diff --git a/CMakeLists.txt b/CMakeLists.txt index cd782408..4eb50c5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) option(MTGODOT_BUILD_EXTENSION "Build the Godot GDExtension (pulls in godot-cpp)" ON) option(MTGODOT_BUILD_TOOLS "Build libgr2 validation tools (gr2dump/gr2fuzz/oracle_diff)" OFF) +option(MTGODOT_BUILD_NET_TOOLS "Build host-only protocol probes without Godot" OFF) # --- shared, cross-platform core (no godot-cpp, no third-party) --- add_subdirectory(libgr2) @@ -46,3 +47,27 @@ if(MTGODOT_BUILD_EXTENSION) endif() add_subdirectory(extension) endif() + +# FreeBSD is the native build target of the archived 40250 server, but it is +# not a supported Godot extension target. Keep the live classic probe +# available as a small host-only build so a FreeBSD jail/VM can compile and run +# it without pulling in godot-cpp or the Darwin/iOS/Android extension. +if(MTGODOT_BUILD_NET_TOOLS AND NOT MTGODOT_BUILD_EXTENSION) + add_subdirectory(extension/third_party) + add_library(mtnet_host STATIC + extension/src/net/secure_cipher.cpp + extension/src/net/net_stream.cpp + extension/src/net/entity_store.cpp + extension/src/net/mark_image.cpp + extension/src/net/classic/classic_stream.cpp + extension/src/net/classic/classic_parser.cpp + extension/src/net/classic/classic_session.cpp + extension/src/net/classic/classic_cipher.cpp + ) + target_include_directories(mtnet_host PUBLIC extension/src/net) + target_link_libraries(mtnet_host PUBLIC mt3p::sodium mt3p::minilzo mt3p::cryptopp) + target_compile_features(mtnet_host PUBLIC cxx_std_20) + + add_executable(net_classic_e2e_host extension/tools/net_classic_e2e.cpp) + target_link_libraries(net_classic_e2e_host PRIVATE mtnet_host) +endif() diff --git a/assets/asset_index.txt b/assets/asset_index.txt index 09abb3a0..a6de68eb 100644 --- a/assets/asset_index.txt +++ b/assets/asset_index.txt @@ -26105,7 +26105,6 @@ Y ymir work/zone/oxevent/ox_01.mdatr Zone/ymir work/zone/oxevent/ox_01.mdatr Y ymir work/zone/oxevent/ox_tile03.dds Zone/ymir work/zone/oxevent/ox_tile03.dds Y ymir work/zone/oxevent/x_flag.gr2 Zone/ymir work/zone/oxevent/x_flag.gr2 Y ymir work/zone/oxevent/x_flag.mdatr Zone/ymir work/zone/oxevent/x_flag.mdatr -R .ds_store .DS_Store R asset_index.txt asset_index.txt R effect/ymir work/effect/affect/3spot.dds Effect/ymir work/effect/affect/3spot.dds R effect/ymir work/effect/affect/damagevalue/critical.mse Effect/ymir work/effect/affect/damagevalue/critical.mse diff --git a/build-android.sh b/build-android.sh index 1c5d48b5..2d970028 100755 --- a/build-android.sh +++ b/build-android.sh @@ -13,7 +13,7 @@ CONFIG="${1:-Debug}" # Debug | Release ABI="${ANDROID_ABI:-arm64-v8a}" API="${ANDROID_PLATFORM:-24}" BUILD_DIR="build-android" -JOBS="${JOBS:-$(sysctl -n hw.ncpu)}" +JOBS="${JOBS:-$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)}" # --- locate the NDK --- NDK="${ANDROID_NDK_ROOT:-${ANDROID_NDK_HOME:-}}" diff --git a/docs/ANDROID-TESTING.md b/docs/ANDROID-TESTING.md new file mode 100644 index 00000000..be80a140 --- /dev/null +++ b/docs/ANDROID-TESTING.md @@ -0,0 +1,393 @@ + +# Android 真机测试指南 + +本文说明如何在 Android 真机上安装 `mtgodot-poc`、生成并导入资源包、验证资源挂载,以及进行 40250 客户端测试。 + +## 1. 当前测试范围与已知前置条件 + +当前 Android 导出目标是 `arm64-v8a`,APK 包名为 `org.internal.mtgodotpoc`,最低 Android SDK 为 24。APK 只包含代码和 Godot 工程资源;Metin2 的 `assets/` 与 `bgm/` 不打进 APK,测试时必须单独导入 `assets.zip`。 + +当前仓库的资源部署存在一个需要特别注意的限制: + +- `export-android.sh --install` 会把资源推到 `/sdcard/Android/data/org.internal.mtgodotpoc/files/assets.zip`。 +- `project/asset_pack.gd` 首先查找 `user://assets.zip`,当前没有显式把上述外部目录加入候选路径。 +- 因此,Debug 真机测试应把外部目录中的压缩包再复制到应用私有 `files/` 目录,确保客户端的 `user://assets.zip` 能命中。 + +另外,40250 classic 网络栈当前由进程环境变量 `MT_PROTOCOL=classic` 选择。Android 通过 Activity 启动 APK 时不能直接继承 Mac 终端的环境变量;如果 APK 尚未增加 Android 侧的协议配置入口或将 classic 设为移动端默认值,则只能完成 APK、资源和 UI 验证,不能据此宣称已经完成真实 40250 登录验收。 + +公会功能按当前项目范围暂缓;龙魂玩法不属于目标 40250 服务器功能,不纳入 Android 验收。 + +## 2. 主机环境 + +以下版本来自当前 Android Gradle 配置和构建脚本: + +| 项目 | 要求 | +|---|---| +| 主机 | macOS,Apple Silicon 构建脚本已按当前机器验证 | +| Godot | `4.7.1.stable`,并安装对应 Android 导出模板 | +| Android SDK | compile/target SDK `36`,Build Tools `36.1.0` | +| Android NDK | `29.0.14206865` | +| Java | Gradle 配置最低 Java 17;当前脚本默认使用 OpenJDK 21 | +| Android 手机 | `arm64-v8a`,建议使用 Vulkan 设备 | +| 磁盘 | 至少预留 APK、资源包和临时构建空间;当前 `assets.zip` 约 2.1–2.2 GB | + +进入仓库并设置环境变量。路径按本机安装位置调整: + +```bash +cd /Users/shenlei/Work/mt/mtgodot-poc + +export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk" +export ANDROID_HOME="$ANDROID_SDK_ROOT" +export ANDROID_NDK_ROOT="$ANDROID_SDK_ROOT/ndk/29.0.14206865" +export JAVA_HOME="/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home" +export GODOT="/opt/homebrew/bin/godot" +export ADB="$ANDROID_SDK_ROOT/platform-tools/adb" +``` + +先确认工具存在: + +```bash +"$GODOT" --version +java -version +"$ADB" version +test -f "$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake" +``` + +如果 Android SDK/NDK 尚未安装,可在 Android Studio 的 SDK Manager 中安装,或使用 `sdkmanager` 安装与上表一致的版本。不要只安装一个较旧 NDK 后直接构建;Gradle 模板要求的 NDK 版本以 `project/android/build/config.gradle` 为准。 + +Godot 还需要安装与 `4.7.1` 完全匹配的 Android 导出模板。可在 Godot 的“编辑器设置 → 导出 → 导出模板”中安装。 + +首次导出前生成 Debug keystore: + +```bash +./gen-debug-keystore.sh +``` + +## 3. 连接 Android 真机 + +在手机上完成以下设置: + +1. 设置 → 关于手机 → 连续点击版本号,开启开发者选项。 +2. 开发者选项中开启“USB 调试”。 +3. USB 连接模式选择“文件传输/MTP”。 +4. 首次连接时,在手机上确认“允许 USB 调试”。 + +在 Mac 上检查设备: + +```bash +"$ADB" kill-server +"$ADB" start-server +"$ADB" devices -l +``` + +期望看到: + +```text +<设备序列号> device +``` + +状态为 `unauthorized` 时,解锁手机并接受 RSA 授权;没有设备时,优先检查 USB 线、USB 模式、开发者选项和手机是否允许该电脑调试。 + +## 4. 生成资源包 + +资源包必须从与 APK 同一份工作树生成。执行: + +```bash +./pack-assets.sh +``` + +该脚本会: + +1. 执行 `bake_asset_index.gd`,生成 `assets/asset_index.txt`。 +2. 将 `assets/` 和 `bgm/` 打成 `build/export/assets.zip`。 +3. 使用 `zip -0` 原样存储,不压缩 `.dds`、`.gr2` 等大型资源。 +4. 排除 `.git`、`.DS_Store` 和 `assets/.gdignore`。 + +检查资源包: + +```bash +ls -lh build/export/assets.zip +unzip -l build/export/assets.zip | rg 'assets/asset_index\.txt|assets/|bgm/' | head -n 20 +``` + +不要手工解压到 APK,也不要把完整 `assets/` 强行放进 `res://`。客户端启动时通过 `ProjectSettings.load_resource_pack()` 挂载 zip,挂载成功后资源以 `res://assets/...` 和 `res://bgm/...` 访问。 + +资源发生变化后必须重新执行 `./pack-assets.sh`。只重新导出 APK 不会更新已经生成的 `assets.zip`。 + +## 5. 构建 APK + +建议先单独构建,不要在第一次测试时直接使用 `--install`: + +```bash +./export-android.sh Debug +``` + +构建成功后应得到: + +```text +build/export/mtgodot-poc.apk +``` + +检查 APK 和 native library: + +```bash +ls -lh build/export/mtgodot-poc.apk +unzip -l build/export/mtgodot-poc.apk | rg 'lib/arm64-v8a/.*\.so' +``` + +应至少包含 `lib/arm64-v8a/` 下的 Godot Android 库和 `libmtgodot` 扩展库。 + +## 6. 安装 APK 并导入资源 + +### 6.1 安装 APK + +```bash +"$ADB" install -r build/export/mtgodot-poc.apk +``` + +`-r` 会保留应用数据。若要完全清理测试数据,可选执行: + +```bash +"$ADB" shell pm clear org.internal.mtgodotpoc +``` + +清理后必须重新导入资源包。 + +### 6.2 先推送到 Android 外部目录 + +```bash +PKG=org.internal.mtgodotpoc +EXT_DIR="/sdcard/Android/data/$PKG/files" + +"$ADB" shell mkdir -p "$EXT_DIR" +"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip" +"$ADB" shell ls -lh "$EXT_DIR/assets.zip" +``` + +### 6.3 Debug 测试复制到 Godot `user://` + +当前 `Debug` APK 可使用 `run-as` 把外部文件复制到应用私有 `files/` 目录: + +```bash +"$ADB" shell run-as "$PKG" sh -c \ + "cp '$EXT_DIR/assets.zip' files/assets.zip" + +"$ADB" shell run-as "$PKG" ls -lh files/assets.zip +``` + +最后一条命令能看到约 2.1–2.2 GB 的文件,才继续启动客户端。这个步骤是当前代码路径下的关键步骤;只执行 `adb push` 到 `/sdcard/Android/data/.../files/`,不能替代它。 + +如果 `run-as` 报告应用不可调试,确认安装的是 `Debug` APK,而不是 Release APK。Release 流程需要先修改资源查找/部署实现,使客户端明确支持外部目录,不能假设 `run-as` 可用。 + +### 6.4 资源更新 + +客户端退出后,只更新资源包时执行: + +```bash +./pack-assets.sh + +"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip" +"$ADB" shell run-as "$PKG" sh -c \ + "cp '$EXT_DIR/assets.zip' files/assets.zip" +``` + +资源挂载只在 `client_main.gd::_ready()` 中执行,因此更新后必须重启客户端,不能只切回前台: + +```bash +"$ADB" shell am force-stop "$PKG" +``` + +## 7. 启动客户端并确认资源挂载 + +清空旧日志后启动: + +```bash +"$ADB" logcat -c +"$ADB" shell am start -n \ + org.internal.mtgodotpoc/com.godot.game.GodotApp +``` + +实时查看日志: + +```bash +"$ADB" logcat -v time -s godot GodotError AndroidRuntime +``` + +资源挂载成功的关键日志是: + +```text +[AssetPack] mounted .../assets.zip +``` + +以下日志表示资源没有被找到或挂载失败: + +```text +[AssetPack] 找不到 assets.zip +[AssetPack] load_resource_pack 失败 +[client] 资源目录不存在 +``` + +启动验收至少包含: + +- 登录界面正常出现,而不是黑屏或立即退出。 +- 登录背景、控件和字体资源正常显示。 +- 选人页能加载职业模型、背景和界面资源。 +- 进入游戏后能看到地图、地形、建筑、树木或角色模型。 +- 日志中没有持续出现资源文件缺失、`FileAccess` 打开失败或 native library 加载失败。 + +可保存截图作为测试证据: + +```bash +mkdir -p build/export/android-evidence +"$ADB" exec-out screencap -p > build/export/android-evidence/launch.png +``` + +## 8. 40250 服务器连接配置 + +### 8.1 手机网络要求 + +手机必须能直接访问认证服/游戏服的 IP 和端口: + +- 手机与局域网测试服连接到同一网络,或服务器开放公网访问。 +- 客户端不能使用 `127.0.0.1` 或 `localhost` 指向 Mac;在手机上它们指向手机自身。 +- 防火墙和 FreeBSD jail 的端口映射必须允许手机来源地址访问。 +- 服务器端口以实际 `CONFIG` 为准,不要照抄示例端口。 + +### 8.2 `serverlist.txt` + +客户端启动时会优先读取 `res://serverlist.txt`;没有该文件时使用 `project/net/serverinfo.gd` 中的内置默认值。真实 40250 测试应在导出前准备 `project/serverlist.txt`,格式为 TSV: + +```text +# 名称\t认证地址\t认证端口\t游戏地址\t游戏端口\t频道列表\t端口步长\t会徽端口 +龙魂40250\t<服务器IP>\t\t<服务器IP>\t\t1,2,3,4\t1\t0 +``` + +例如 40250 仓库脚本中的默认 channel1 端口与当前客户端内置默认值并不相同,必须以目标 FreeBSD 服务器的 `CONFIG` 和实际监听结果为准。 + + + +### 8.3 classic 协议选择限制 + +当前 native 代码仅在进程环境变量满足以下条件时切换 40250 classic 后端: + +```text +MT_PROTOCOL=classic +``` + +在 Mac 上运行 Godot 时可以通过环境变量设置;但 Android APK 是由 Activity 启动的,普通的 `adb shell am start` 不会把 Mac 的环境变量传入 APK。因此,真实 Android 40250 登录测试前必须确认以下任一项已经完成: + +1. Android 版本把 classic 设置为默认网络后端; +2. 客户端增加可持久化的协议配置并在 Android 导出中设为 `classic`;或 +3. Android 测试包提供协议选择入口。 + +不要把下面的命令当作可靠解决方案: + +```bash +adb shell MT_PROTOCOL=classic am start ... +``` + +它设置的是 `am` 命令进程的环境,不等于给已启动的 Android Activity 设置环境变量。 + +## 9. 真机功能验收清单 + +以下项目按实际 40250 测试账号、角色和 NPC 条件逐项记录: + +### 启动与网络 + +- [ ] APK 安装成功,包名为 `org.internal.mtgodotpoc`。 +- [ ] `assets.zip` 已复制到应用私有 `files/`,大小与主机一致。 +- [ ] 日志出现 `[AssetPack] mounted`。 +- [ ] 登录界面资源完整显示。 +- [ ] 服务器/频道检测能得到预期结果。 +- [ ] 认证成功后进入选人页。 +- [ ] 选择角色后进入游戏场景。 + +### 世界与基础操作 + +- [ ] 地图、地形、建筑、树木、角色和纹理正常加载。 +- [ ] 点击地面移动,角色位置与服务器同步。 +- [ ] 普通攻击、目标选择、技能和动作没有异常断线。 +- [ ] 聊天发送与接收正常。 +- [ ] 切换前后台后连接和场景状态符合预期;断线时能看到重连提示。 + +### 已接入的常用功能 + +- [ ] 背包打开、物品使用、丢弃、移动和快捷栏操作。 +- [ ] NPC 对话、脚本选项、输入框和确认框。 +- [ ] 普通商店查看、切换货架和购买。 +- [ ] 私人商店物品选择、定价、开设和撤收。 +- [ ] 交易发起、物品/金币添加、确认和取消。 +- [ ] 仓库密码、存入、取出和物品移动。 +- [ ] 商城物品列表和取出。 +- [ ] 组队邀请、接受、离队、成员状态和治疗入口。 +- [ ] ESC 系统菜单、音量、镜头、雾效和显示设置持久化。 + +### 明确不纳入本轮 + +- 公会相关功能:按当前范围暂缓。 +- 龙魂:目标 40250 服务器没有该功能,不进行功能验收。 +- 真实 FreeBSD + MySQL 全流程验收:需要服务器环境和测试账号,不能用本机离线测试结果替代。 + +## 10. 测试证据保存 + +建议每次测试保留 APK、资源包校验值、设备信息和日志: + +```bash +mkdir -p build/export/android-evidence + +shasum -a 256 build/export/mtgodot-poc.apk \ + build/export/assets.zip \ + > build/export/android-evidence/artifacts.sha256 + +"$ADB" shell getprop ro.product.model \ + > build/export/android-evidence/device-model.txt +"$ADB" shell getprop ro.build.version.release \ + > build/export/android-evidence/android-version.txt +"$ADB" logcat -d -v time -s godot GodotError AndroidRuntime \ + > build/export/android-evidence/logcat.txt +``` + +测试记录至少填写:构建时间、Git commit、APK SHA-256、`assets.zip` SHA-256、手机型号、Android 版本、服务器地址/端口、账号、测试结果和失败日志。 + +## 11. 常见问题 + +| 现象 | 处理 | +|---|---| +| `adb devices` 没有设备 | 开启 USB 调试、接受 RSA、切换 MTP、检查数据线;必要时重新执行 `adb kill-server` / `adb start-server` | +| 状态是 `unauthorized` | 解锁手机并接受“允许 USB 调试”,然后重新执行 `adb devices` | +| APK 安装失败 | 检查设备是否为 arm64;卸载旧包后再安装;查看 `adb install` 的具体错误 | +| `run-as` 报不可调试 | 安装 `Debug` APK;Release APK 不能依赖 `run-as` 导入资源 | +| 日志找不到 `assets.zip` | 确认外部 push 成功,再执行 `run-as ... cp ... files/assets.zip`,然后重启应用 | +| `load_resource_pack 失败` | 检查压缩包完整性、磁盘空间、是否由 `./pack-assets.sh` 生成,以及 zip 内是否存在 `assets/asset_index.txt` | +| 登录连接超时 | 手机不能使用 `localhost`;检查服务器 IP、端口、Wi-Fi/VPN、防火墙和 FreeBSD jail 映射 | +| 登录协议不对或立即断线 | 确认 Android 包实际选择了 `classic`,仅在 Mac 终端设置 `MT_PROTOCOL` 不会自动传入 APK | +| 黑屏或 Vulkan 崩溃 | 保存完整 `logcat`;当前 Android 移动 Vulkan 的 shader/GPU-skin 真机验证仍需在目标设备上进行 | +| 更新资源后画面不变 | 资源包挂载发生在启动阶段,执行 `am force-stop` 后重新启动;必要时清理应用数据并重新导入 | + +## 12. 推荐的最短测试流程 + +首次测试按以下顺序执行: + +```bash +cd /Users/shenlei/Work/mt/mtgodot-poc + +./pack-assets.sh +./export-android.sh Debug + +export ADB="${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}/platform-tools/adb" +PKG=org.internal.mtgodotpoc +EXT_DIR="/sdcard/Android/data/$PKG/files" + +"$ADB" install -r build/export/mtgodot-poc.apk +"$ADB" shell mkdir -p "$EXT_DIR" +"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip" +"$ADB" shell run-as "$PKG" sh -c \ + "cp '$EXT_DIR/assets.zip' files/assets.zip" +"$ADB" shell run-as "$PKG" ls -lh files/assets.zip + +"$ADB" logcat -c +"$ADB" shell am start -n "$PKG/com.godot.game.GodotApp" +"$ADB" logcat -v time -s godot GodotError AndroidRuntime +``` + +只有在看到 `[AssetPack] mounted`、登录界面资源正常、并确认 Android 包使用正确的 40250 classic 后端后,才进入真实服务器功能验收。 diff --git a/docs/CLIENT-40250-PORT.md b/docs/CLIENT-40250-PORT.md new file mode 100644 index 00000000..322f1980 --- /dev/null +++ b/docs/CLIENT-40250-PORT.md @@ -0,0 +1,648 @@ +# 迁移到 40250 服务端 —— 协议差异与移植方案 + +> 目标:网络层从 **m2dev fork 协议** 换成 **40250 经典 Metin2 协议**,连 +> `Work/mt/40250/Server/`。现有 m2dev 那套**保留**为可切换后端(`MT_PROTOCOL=m2dev|classic`), +> Godot 场景 / GDScript / UI / 渲染保持既有接口与布局;为接住 classic 的状态/命令,只做必要的 +> bridge、状态显示和资源映射补充。 +> +> 参考源: +> - 40250 客户端:`/Users/shenlei/Work/mt/40250/ClientVS22/source/` +> (`UserInterface/`、`EterLib/NetStream.{h,cpp}`、`EterBase/cipher.{h,cpp}`) +> - 40250 服务端:`/Users/shenlei/Work/mt/40250/Server/metin2/src/server/` +> (`game/src/packet.h`、`game/src/packet_info.cpp`、`game/src/desc.cpp`(握手/阶段/cipher)、 +> `game/src/input.cpp`(`CInputHandshake` + sequence 校验)、`game/src/input_auth.cpp`、`common/`)。 +> auth 服 = 同一个 game 二进制跑 auth 模式(无独立源码目录);运行时目录 +> `Server/metin2/server/{auth, game99, channel1..4, db}`,各带 `CONFIG`。 +> - m2dev(现有移植的对照):`/Users/shenlei/Work/mt/m2dev-client-src-main/src/UserInterface/` + +> **当前范围调整(2026-09-01)**:本阶段只收口客户端本地协议、状态桥接、UI 首版和离线回归。 +> 真实 FreeBSD + MySQL 40250 服务端的完整登录 / 功能验收暂缓,不作为本阶段交付阻塞;公会相关 +> 功能暂缓。当前目标 40250 服务端不提供龙魂玩法,因此龙魂不纳入本阶段支持范围;代码中的兼容 +> 分支不代表该服务端可用。 + +--- + +## 0. 一句话结论 + +| 层 | 改动 | 量级 | +|---|---|---| +| **网络层** `extension/src/net/` | classic 栈从零写(cipher / 分帧 / 握手 / ~200 结构体 / dispatch),m2dev 栈挪进子目录冻结 | **大**(~2–4 周)| +| `EntityStore` | 拆出 mutation API,两个 parser 共用世界模型 | 中(1–2 天)| +| `M2Client` | 加 `INetSession` seam,方法转发,按 `MT_PROTOCOL` 选后端 | 小(1 天)| +| 渲染 / `formats` / `libgr2` / Godot 场景 / `app_flow` / HUD / UI 窗口 | 保持既有接口;按 40250 复核并补状态、命令和动作资源映射(不重写渲染底座)| 小—中 | +| **前置**:跑起 40250 服务端 | 独立一摊(**FreeBSD** game/auth/db + MySQL + proto 表 + config;见 §7.1;仓库已提供可执行脚本)| 中 | + +--- + +## 1. 封包头 + +### 1.1 宽度与风格 + +| | m2dev fork | 40250 classic | +|---|---|---| +| 头字段 | `uint16_t`(小端),十六进制段(`CG_MOVE = 0x0301`)| **`BYTE`(1 字节)**,十进制(`HEADER_CG_MOVE = 7`)| +| 定义位置 | `wire.h`(我们自己维护)| 客户端 `UserInterface/Packet.h`(L30 起匿名 enum,CG/GC/GG 混一起)**与**服务端 `game/src/packet.h` 手工保持一致 | + +> ⚠️ 客户端 `Packet.h` 的 header enum 有 `#if defined(GAIDEN)` 分支,**40250 客户端构建未定义 +> `GAIDEN`**(`UserInterface.vcxproj` PreprocessorDefinitions 只有 `WIN32;_DEBUG;_WINDOWS;USE_LOD; +> _CRT_SECURE_NO_WARNINGS`)。非 GAIDEN 分支里同一 header 值的名字和服务端不同: +> 服务端 `HEADER_GC_MAIN_CHARACTER=113` ↔ 客户端非 GAIDEN 是 `HEADER_GC_MAIN_CHARACTER2_EMPIRE=113` +> (`HEADER_GC_MAIN_CHARACTER=15` 在客户端指旧包);`SKILL_LEVEL` / `REFINE_INFORMATION` / +> `TARGET_CREATE` 等也有 `_OLD` / `_NEW` / `2_` 后缀错位。**移植时以服务端 `game/src/packet.h` +> 的值 + 名为准**(它就是线上实际值),结构体按「服务端实际 `Packet()` 发的那个」核(见 §4.4)。 + +### 1.2 40250 头表(服务端 `packet.h` 权威值) + +**控制段(保留头,两向都有)** +``` +0xff GC/CG_HANDSHAKE 0xfe CG_PONG / GC_BINDUDP +0xfd CG_CLIENT_VERSION / GC_PHASE 0xfc CG_TIME_SYNC / GC_TIME_SYNC (0xfc 的 GC 侧: 服务端 + packet.h 叫 HEADER_GC_TIME_SYNC,客户端 Packet.h 叫 + HEADER_GC_HANDSHAKE_OK —— 同一字节;CG 侧无 0xfa) +0xfb GC/CG_KEY_AGREEMENT 0xfa GC_KEY_AGREEMENT_COMPLETED +0xf1 CG_CLIENT_VERSION2 +``` +(客户端值:`Packet.h` L162-167 CG、L362-367 GC。GC 0xfc `HEADER_GC_HANDSHAKE_OK` 注释写「252」。) + +**CG(客户端→服务端)** +``` + 1 LOGIN 2 ATTACK 3 CHAT 4 CHARACTER_CREATE 5 CHARACTER_DELETE + 6 CHARACTER_SELECT 7 MOVE 8 SYNC_POSITION 10 ENTERGAME +11 ITEM_USE 12 ITEM_DROP 13 ITEM_MOVE 15 ITEM_PICKUP +16 QUICKSLOT_ADD 17 QUICKSLOT_DEL 18 QUICKSLOT_SWAP 19 WHISPER 20 ITEM_DROP2 +26 ON_CLICK 27 EXCHANGE 28 CHARACTER_POSITION 29 SCRIPT_ANSWER +30 QUEST_INPUT_STRING 31 QUEST_CONFIRM +50 SHOP 51 FLY_TARGETING 52 USE_SKILL 53 ADD_FLY_TARGETING 54 SHOOT 55 MYSHOP +60 ITEM_USE_TO_ITEM 61 TARGET 64 TEXT 65 WARP 66 SCRIPT_BUTTON 67 MESSENGER +69 MALL_CHECKOUT 70 SAFEBOX_CHECKIN 71 SAFEBOX_CHECKOUT +72 PARTY_INVITE 73 PARTY_INVITE_ANSWER 74 PARTY_REMOVE 75 PARTY_SET_STATE 76 PARTY_USE_SKILL +77 SAFEBOX_ITEM_MOVE 78 PARTY_PARAMETER +80 GUILD 81 ANSWER_MAKE_GUILD 82 FISHING 83 ITEM_GIVE 90 EMPIRE 96 REFINE +100 MARK_LOGIN 101 MARK_CRCLIST 102 MARK_UPLOAD 104 MARK_IDXLIST 105 HACK 106 CHANGE_NAME +109 LOGIN2 110 DUNGEON 111 LOGIN3 112 GUILD_SYMBOL_UPLOAD 113 SYMBOL_CRC +114 SCRIPT_SELECT_ITEM 116 LOGIN5_OPENID 202 PASSPOD_ANSWER 203 HS_ACK 204 XTRAP_ACK +205 DRAGON_SOUL_REFINE 206 STATE_CHECKER +``` + +**GC(服务端→客户端)** +``` + 1 CHARACTER_ADD 2 CHARACTER_DEL 3 MOVE 4 CHAT 5 SYNC_POSITION + 6 LOGIN_SUCCESS3(=3格,PLAYER_PER_ACCOUNT3) 7 LOGIN_FAILURE 32 LOGIN_SUCCESS4(=4格) + 8 CHARACTER_CREATE_SUCCESS 9 CREATE_FAILURE 10 DELETE_SUCCESS 11 DELETE_WRONG_SOCIAL_ID +12 ATTACK 13 STUN 14 DEAD 15 MAIN_CHARACTER_OLD +16 CHARACTER_POINTS 17 CHARACTER_POINT_CHANGE 18 CHANGE_SPEED +19 CHARACTER_UPDATE 24 CHARACTER_UPDATE_NEW +20 ITEM_DEL 21 ITEM_SET 22 ITEM_USE 23 ITEM_DROP 25 ITEM_UPDATE +26 ITEM_GROUND_ADD 27 ITEM_GROUND_DEL +28 QUICKSLOT_ADD 29 QUICKSLOT_DEL 30 QUICKSLOT_SWAP 31 ITEM_OWNERSHIP +34 WHISPER 36 MOTION 37 PARTS 38 SHOP 39 SHOP_SIGN +40 DUEL_START 41 PVP 42 EXCHANGE 43 CHARACTER_POSITION 44 PING +45 SCRIPT 46 QUEST_CONFIRM 61 MOUNT 62 OWNERSHIP 63 TARGET 65 WARP +69 ADD_FLY_TARGETING 70 CREATE_FLY 71 FLY_TARGETING 72 SKILL_LEVEL_OLD 76 SKILL_LEVEL +74 MESSENGER 75 GUILD 77 PARTY_INVITE 78 PARTY_ADD 79 PARTY_UPDATE 80 PARTY_REMOVE +81 QUEST_INFO 82 REQUEST_MAKE_GUILD 83 PARTY_PARAMETER +85 SAFEBOX_SET 86 SAFEBOX_DEL 87 SAFEBOX_WRONG_PASSWORD 88 SAFEBOX_SIZE +89 FISHING 90 EMPIRE 91 PARTY_LINK 92 PARTY_UNLINK 95 REFINE_INFORMATION_OLD +99 VIEW_EQUIP 100 MARK_BLOCK 102 MARK_IDXLIST 106 TIME 107 CHANGE_NAME 110 DUNGEON +111 WALK_MODE 112 SKILL_GROUP 113 MAIN_CHARACTER 114 SEPCIAL_EFFECT / (USE_POTION 注释掉) +115 NPC_POSITION 116 MATRIX_CARD 118 LOGIN_KEY 119 REFINE_INFORMATION 121 CHANNEL +122 MALL_OPEN 123 TARGET_UPDATE 124 TARGET_DELETE 125 TARGET_CREATE +126 AFFECT_ADD 127 AFFECT_REMOVE 128 MALL_SET 129 MALL_DEL 130 LAND_LIST +131 LOVER_INFO 132 LOVE_POINT_UPDATE 133 SYMBOL_DATA 134 DIG_MOTION 135 DAMAGE_INFO +136 CHAR_ADDITIONAL_INFO 137 MAIN_CHARACTER3_BGM 138 MAIN_CHARACTER4_BGM_VOL +150 AUTH_SUCCESS 151 PANAMA_PACK 152 HYBRIDCRYPT_KEYS 153 HYBRIDCRYPT_SDB 154 AUTH_SUCCESS_OPENID +200 ROULETTE 202 REQUEST_PASSPOD 203 REQUEST_PASSPOD_FAILED 204 HS_REQUEST 205 XTRAP_CS1_REQUEST +208 SPECIFIC_EFFECT 209 DRAGON_SOUL_REFINE 210 RESPOND_CHANNELSTATUS +``` + +> 逐结构体细节实现期直接看 `game/src/packet.h`(EUC-KR 编码,注释乱码无碍)。 + +--- + +## 2. 分帧(framing) + +### 2.1 m2dev fork +每个包 `[u16 header LE][u16 length LE][payload]`。长度永远显式。无 sequence 字节。 + +### 2.2 40250 classic —— 静态尺寸表 + sequence 字节 + 动态包 + +- **收**:读 1 字节 header → 查尺寸表(`CPacketInfo::Set(header, sizeof(TPacketXxx), name, bSeq)`,见 + `game/src/packet_info.cpp`)→ 读定长 body。 +- **CG 的 sequence 字节**:`bSeq=true` 的包尾部多 1 字节 `BYTE sequence`。服务端 `Set()` 里 + `if (bSeq) element->iSize += sizeof(BYTE)`(尺寸表已含 +1);客户端 `NetStream.cpp` 发包后调 + `SendSequence()`:`m_bUseSequence` 为真时追加 `m_kVec_bSequenceTable[m_iSequence++ % SEQUENCE_TABLE_SIZE]` + (静态表 `s_bSequenceTable[SEQUENCE_TABLE_SIZE]`,`NetStream.cpp` L881)。开关由 Python 调 + `net.SetPacketSequenceMode()`(`PythonNetworkStreamModule.cpp:1601`,对 `rns` 和 + `rkAccountConnector` 都置 true)—— 具体时机在 `root/*.py`(本 dump 没带),实现期抓包定位。 + 服务端逐包校验、错了断线。 +- **`bSeq=true` 覆盖几乎所有 CG 游戏内包**(Login/Move/Attack/Chat/ItemMove/Shop/Party/Quest/Pong/…; + 连 `CG_LOGIN`/`LOGIN2`/`LOGIN3` 和 `CG_TIME_SYNC` 都是 `true`,见 `packet_info.cpp:148-150,137`)。 + `bSeq=false` 的全集(`packet_info.cpp`):`TEXT` `HANDSHAKE` `MARK_LOGIN` `MARK_IDXLIST` `MARK_CRCLIST` + `MARK_UPLOAD` `KEY_AGREEMENT` `GUILD_SYMBOL_UPLOAD` `SYMBOL_CRC` `DRAGON_SOUL_REFINE` `STATE_CHECKER`。 + (`HS_ACK` / `XTRAP_ACK` 在 40250 服务端 `packet_info.cpp:227-228` 是**注释掉的**,根本没登记。) + 客户端只在 `m_bUseSequence` 打开后才真正追加尾字节,未开时即便 `bSeq=true` 也不加。 +- **GC 不带 sequence 字节**。 +- **动态尺寸包**:客户端接收侧靠 `CNetworkPacketHeaderMap`(`CMainPacketHeaderMap` 构造函数, + `PythonNetworkStream.cpp` L29 起)里的 `Set(header, TPacketType(sizeof(TPacketXxx), DYNAMIC_SIZE_PACKET))` + 标记区分;`CheckPacket()` 命中动态项时先 `Peek(TDynamicSizePacketHeader{BYTE header; WORD size;})` + 拿 `size` = 整包字节数,再 `Peek(size)`。发送侧则看结构体自带的长度字段 + (`command_chat` 叫 `WORD length`、`command_whisper` 叫 `WORD wSize`、GC 侧 `packet_*` 叫 `WORD size`,语义相同)。 + **客户端 GC 动态包全集**(`CMainPacketHeaderMap`,其余 GC 全部 `STATIC_SIZE_PACKET`): + `GC_CHAT` `GC_SCRIPT` `GC_SHOP` `GC_GUILD` `GC_MESSENGER` `GC_QUEST_INFO` `GC_DUEL_START` + `GC_SYNC_POSITION` `GC_DUNGEON` `GC_NPC_POSITION` `GC_LAND_LIST` `GC_HYBRIDCRYPT_KEYS` `GC_HYBRIDCRYPT_SDB`。 + **CG 动态包**:只有 `CG_CHAT`(`command_chat`)和 `CG_WHISPER`(`command_whisper`)。 + **易错的静态包**:`GC_MALL_OPEN`/`SET`/`DEL`、`GC_SAFEBOX_SET`、`GC_PARTY_ADD`/`UPDATE`、`GC_WHISPER`、 + `GC_AFFECT_ADD` 都是 `STATIC_SIZE_PACKET`(定长,`sizeof` 取满缓冲)。CG 侧 `CG_MARK_UPLOAD` + (`{BYTE header; DWORD gid; BYTE image[16*12*4];}`)、`CG_SHOP`(`{BYTE header; BYTE subheader;}`)、 + `CG_GUILD`(`{BYTE byHeader; BYTE bySubHeader;}`)也都是定长子头分发,不是动态包。 + +### 2.3 影响 +`net_stream.cpp` 完全重写:新 `classic_stream.cpp` 维护 header→size 表(从 `packet.h` + `packet_info.cpp` +镜像一份到 `wire_classic.h` 的 `static_assert` + 一个 `packet_size(header)` 函数),发 CG 时自动追加 +sequence 字节并推进本地序列表,动态包读 `size` 前缀。 + +--- + +## 3. 加密(cipher) + +### 3.1 m2dev fork +libsodium `crypto_kx`(X25519),一轮:`GC_KEY_CHALLENGE{server_pk, challenge}` → +`CG_KEY_RESPONSE{client_pk, HMAC(challenge, tx_key)}` → `GC_KEY_COMPLETE{AEAD 加密的 session token, nonce}`。 +`crypto_kx_*_session_keys` 出**两把方向密钥** `m_tx_key` / `m_rx_key`(**不是**两向同密钥);激活后每向 +一条 `crypto_stream_xchacha20`(固定方向 nonce:`0x01` S→C、`0x02` C→S)+ 递增字节计数原地 XOR。 +KEY_COMPLETE 的 token 用一次性 `crypto_aead_xchacha20poly1305_ietf`。`secure_cipher.{h,cpp}` +(近乎照搬客户端 `EterBase/SecureCipher`)。 + +### 3.2 40250 classic —— `_IMPROVED_PACKET_ENCRYPTION_`(`EterBase/cipher.{h,cpp}`) + +1. **密钥协商**:Crypto++ `DH2`(Unified DH)——`DH2KeyAgreement` 里 `DH dh_; DH2 dh2_(dh_);`, + 同一组 DH 域参数下各生成「静态 + 临时」两对密钥,`dh2_.Agree(shared_, spriv, epriv, otherPub…)` + 一次得共享密钥 `SecByteBlock shared_`(`cipher.cpp` L123-133, 336, 428-441)。 + 握手时间同步收敛后,流程是**服务端先手**: + 1. 服务端 `DESC::SendKeyAgreement()`(`desc.cpp:726`):`cipher_.Prepare(packet.data, &data_length)` + 生成本端 blob → 发 `HEADER_GC_KEY_AGREEMENT` + `TPacketKeyAgreement{BYTE bHeader; WORD wAgreedLength; WORD wDataLength; BYTE data[MAX_DATA_LEN=256];}` + (定长 261B,客户端 `Packet.h` L2722,客户端把它登记为 `STATIC_SIZE_PACKET`)。 + 2. 客户端 `RecvKeyAgreementPacket()`(`PythonNetworkStreamPhaseHandshake.cpp:208`):`Prepare()` 生成本端 + blob → **`Activate(pkt.wAgreedLength, pkt.data, pkt.wDataLength)` 用服务端的数据**(内部 + `m_cipher.Activate(true, …)`,`Agree()` 得 `SecByteBlock shared_`)→ 再发 `HEADER_CG_KEY_AGREEMENT` + 带自己的 blob。 + 3. 服务端收 `HEADER_CG_KEY_AGREEMENT`(`input.cpp:647`):**先** `SendKeyAgreementCompleted()` + (发 `HEADER_GC_KEY_AGREEMENT_COMPLETED` `TPacketKeyAgreementCompleted{BYTE bHeader; BYTE data[3];}`) + + `ProcessOutput()` 刷 socket,**再** `IsCipherPrepared()` 检查(否则「maybe a Hacker」 + `DelayedDisconnect(5)`)→ `FinishHandshake(wAgreedLength, data, wDataLength)` = `cipher_.Activate(false, …)` + (`desc.cpp:755`)成功则 `g_bAuthServer ? SetPhase(PHASE_AUTH) : SetPhase(PHASE_LOGIN)`(`input.cpp:665-668`), + 失败 `PHASE_CLOSE`。 + 4. 客户端 `RecvKeyAgreementCompletedPacket()` → `ActivateCipher()` = `m_cipher.set_activated(true)`。 + —— `Agree()` 完成到 `set_activated(true)` 之间有一小段窗口:密钥算出但还没开始真正加解密。 + 注意服务端是**先发 COMPLETED 再自己 FinishHandshake/切阶段**(顺序有意如此,帮客户端先进加密态)。 +2. **对称加密**:`SetUp(polarity)`(`cipher.cpp` L205)里 `hint_0 = shared[shared[0] % size]`、 + `hint_1 = shared[shared[1] % size]`,各 `BlockCipherAlgorithm::Pick(hint)` → `selector = hint % + kMaxAlgorithms`(**`kMaxAlgorithms = 14`**,enum 里 `kDefault=0` 占一位)。`selector` 1–13 依次是 + `RC6/MARS/Twofish/Serpent/CAST256/IDEA/3DES(DES_EDE2)/Camellia/SEED/RC5/Blowfish/TEA/SHACAL2`; + `selector == 0`(`kDefault`)或落到 `default:` → `Twofish`(`kAES/Rijndael` 那位是注释掉的)。 + **CTR 模式**(`CTR_Mode::Encryption/Decryption`),key/iv 从 `shared` 切片。两个密码实例按 + `polarity` 决定收/发各用哪个 —— **客户端 polarity = `true`** + (`EterLib/NetStream.cpp:3004` `return m_cipher.Activate(true, agreed_length, buffer, length);`), + 服务端用 `false`。无 padding(CTR 流)。 + `Encrypt/Decrypt` = `SymmetricCipher::ProcessData` 原地。 +3. **`_IMPROVED_PACKET_ENCRYPTION_` 是编译期 `#define`,不是运行时开关**: + - 服务端 `common/service.h:7` `#define _IMPROVED_PACKET_ENCRYPTION_` —— **shipped 40250 服务端默认开**。 + - 客户端 `eterBase/ServiceDefs.h:4` 同样 `#define` —— 也默认开。 + - 关掉走老路:4-DWORD key 的 `TEA_Encrypt`(服务端 `desc.cpp` non-improved 分支 + `GetEncryptionKey()`) + / 客户端 `SetSecurityMode`。**要「明文起步」必须重编服务端**(把 `service.h` 那行注释掉), + 没有 `CONFIG` token 能关(见 §7.2)。有源码,可行。 + - 另有一层 `packet_encode`/`packet_decode`(`desc.cpp:479`)在 cipher 之外,始终生效。 + +### 3.3 影响 +最硬的一块。需要 **Crypto++**(`DH`/`DH2` + `CTR_Mode` 13 个算法)。方案: +- vendored Crypto++(子模块,CMake 跨 macOS/iOS/Android 能编)—— 体积大但省事;或 +- 只挪需要的算法(DH2 + Twofish/RC5/... CTR)—— 工作量大。 +- 版本 **Crypto++ 8.4.0**:服务端 `src/extern/cryptopp_8_4_0.tar.gz`(+ 预编 `src/extern/lib/libcryptopp.a`), + 客户端 `ClientVS22/extern/include/cryptopp/`(`config_ver.h` `CRYPTOPP_VERSION 840`)。移植对齐这个版本。 + +`secure_cipher.cpp` 不动(m2dev 用),新 `classic_cipher.{h,cpp}` 端口 `EterBase/cipher.cpp`。 + +--- + +## 4. 握手 / 阶段流 + +### 4.1 阶段枚举 +服务端 `enum EPhase`(`packet.h:850`):`PHASE_CLOSE=0, HANDSHAKE=1, LOGIN=2, SELECT=3, LOADING=4, +GAME=5, DEAD=6, CLIENT_CONNECTING=7, DBCLIENT=8, P2P=9, AUTH=10, TEEN=11, PASSPOD=12`。 +客户端匿名 enum(`Packet.h:1124`)前 7 个(0–6)一致,尾部是 `DBCLIENT_CONNECTING / DBCLIENT`—— +**只有 0–6 会经 `GC_PHASE` 到达客户端**,`PHASE_AUTH` 等是服务端内部态。 +正常流:CLOSE→HANDSHAKE→(AUTH,仅 `g_bAuthServer`)→LOGIN→SELECT→LOADING→GAME。 +切阶段由 `HEADER_GC_PHASE`(0xfd) `TPacketGCPhase{BYTE header; BYTE phase;}` 驱动(客户端 `RecvPhasePacket()`)。 + +### 4.2 HANDSHAKE +客户端 `PythonNetworkStreamPhaseHandshake.cpp`;**服务端 `desc.cpp` + `input.cpp`(`CInputHandshake`)明文都在**。 + +- `TPacketGCHandshake`(=`TPacketCGHandshake`,同布局):`{BYTE bHeader; DWORD dwHandshake; DWORD dwTime; + LONG lDelta;}`(服务端 `packet.h` `packet_header_handshake`;客户端字段名 `header`)。`bSeq=false` + (`packet_info.cpp:136`)。 +- 连上 → 服务端 `DESC::StartHandshake` → `SendHandshake(get_dword_time(), 0)`,`pack.bHeader = + HEADER_GC_HANDSHAKE`(0xff)(`desc.cpp:637-658`)。 +- 客户端 **HandShake 阶段**收到 `HEADER_GC_HANDSHAKE`(`PythonNetworkStreamPhaseHandshake.cpp` L37-62 内联): + `ELTimer_SetServerMSec(dwTime + lDelta)` → `dwTime += 2*lDelta`、`lDelta = 0` → + **header 不变(仍 0xff)原样回发**,不追加 sequence。 +- 服务端 `CInputProcessor::Handshake`(`input.cpp:195`):先校验 `p->dwHandshake == GetHandshake()` + (不符 `PHASE_CLOSE`)。在 `PHASE_HANDSHAKE` 里调 `HandshakeProcess(dwTime, lDelta, false)` + (`desc.cpp:662`): + - `bias = get_dword_time() - (dwTime + lDelta)`;**`0 ≤ bias ≤ 50` → 收敛**,`m_bHandshaking=false` 返回 true。 + - 否则 `lNewDelta = (dwCurTime - dwTime) / 2`(<0 时用 `(dwCurTime - m_dwHandshakeSentTime)/2`), + `++m_iHandshakeRetry > HANDSHAKE_RETRY_LIMIT` → `PHASE_CLOSE`;否则 `SendHandshake(dwCurTime, lNewDelta)` + 再来一轮。 +- **收敛后**(`input.cpp:207-217`): + - `#ifdef _IMPROVED_PACKET_ENCRYPTION_`(shipped 默认)→ `d->SendKeyAgreement()`,**这里先不切阶段**; + 阶段推进发生在之后收到 `HEADER_CG_KEY_AGREEMENT` 时(`input.cpp:665-668`,`FinishHandshake` 成功后 + `SetPhase(PHASE_AUTH|PHASE_LOGIN)`)。完整密钥协商流程见 §3.2。 + - `#else`(明文/老 TEA)→ 立即 `g_bAuthServer ? SetPhase(PHASE_AUTH) : SetPhase(PHASE_LOGIN)`。 +- **握手期之后的时钟再同步**:SELECT/GAME 里服务端再发 `HEADER_GC_HANDSHAKE`,客户端不在 handshake + phase → `PythonNetworkStreamPhaseSelect.cpp` L96-102 的 `RecvHandshakePacket()`:回发时 header 改成 + `HEADER_CG_TIME_SYNC`(0xfc) 且 `SendSequence()`(`bSeq=true`,`packet_info.cpp:137`)。服务端此路 + `HandshakeProcess(…, true)`(`bInfiniteRetry=true`,`input.cpp:222`),收敛时回发 **1 字节 + `HEADER_GC_TIME_SYNC`(0xfc)**(`desc.cpp:676-679`)→ 客户端 `RecvHandshakeOKPacket()` 读 + `TPacketGCBlank{BYTE header;}` 定终值。 + —— 注意 0xfc 这个值:**客户端叫 `HEADER_GC_HANDSHAKE_OK`,服务端叫 `HEADER_GC_TIME_SYNC`**,同一字节。 +- 期间可能夹 `HEADER_GC_KEY_AGREEMENT` / `_COMPLETED`(见 §3)、`HEADER_GC_BINDUDP`、`HEADER_GC_PING`、 + `HEADER_GC_HYBRIDCRYPT_KEYS` / `_SDB`(动态包)。`CInputHandshake::Analyze`(`input.cpp:276`)还会 + 处理 `HEADER_CG_TEXT`(webadmin `IS_SERVER_UP` 等文本命令)和 header `10`(旧探活忽略)。 + +### 4.3 LOGIN(`PythonNetworkStreamPhaseLogin.cpp`) +- **两条路**: + - `SendLoginPacket` → `HEADER_CG_LOGIN` `TPacketCGLogin{BYTE header, char login[31], char passwd[17]}` + (明文账密,服务端直连模式)。 + - `SendLoginPacketNew` → `HEADER_CG_LOGIN2` `command_login2` `{BYTE header; char name[31]; + DWORD login_key; DWORD adwClientKey[4];}` —— `login_key` 来自**独立 auth 服**(同 game 二进制跑 + auth 模式)先前发的 `HEADER_GC_LOGIN_KEY`(118);`adwClientKey` = 客户端 `extern DWORD g_adwEncryptKey[4]`。 + `SendLoginPacketNew` 还会 `SetSecurityMode(true, g_adwEncryptKey, g_adwDecryptKey)` 起老 TEA 层。 + - `HEADER_CG_LOGIN3` `command_login3` `{header; name[31]; pwd[17]; DWORD adwClientKey[4];}` + (account server 直登 + 客户端 key)。 +- 回:**40250 服务端实际只发 `HEADER_GC_LOGIN_SUCCESS_NEWSLOT`(=**32**)** + (`DESC::SendLoginSuccessPacket` `desc.cpp:925-959`:`p.bHeader = HEADER_GC_LOGIN_SUCCESS_NEWSLOT`, + `Packet(&p, sizeof(TPacketGCLoginSuccess))`)。结构体 `packet_login_success` / + `TPacketGCLoginSuccess`(`packet.h:892`):`{BYTE bHeader; TSimplePlayer players[PLAYER_PER_ACCOUNT=**4**]; + DWORD guild_id[4]; char guild_name[4][GUILD_NAME_MAX_LEN+1=13]; DWORD handle; DWORD random_key;}` + —— 客户端非 GAIDEN 里 header 32 走 `HEADER_GC_LOGIN_SUCCESS4` → `TPacketGCLoginSuccess4`(`[4]`,同布局)。 + `TSimplePlayer`(`common/tables.h:347`,`pack(1)`,**63 字节**)== 客户端 `TSimplePlayerInformation`。 + header **6**(`HEADER_GC_LOGIN_SUCCESS` / 客户端 `_SUCCESS3`,`players[3]`)是旧格式,shipped 40250 不发。 + 失败 `HEADER_GC_LOGIN_FAILURE`(7) `{BYTE header; char szStatus[LOGIN_STATUS_MAX_LEN+1=9];}` + (`LOGIN_FAILURE_* enum`:1 ALREADY / 2 ID_NOT_EXIST / 3 WRONG_PASS / 4 FALSE / 7 FULL)。 + `handle`/`random_key` 供 `CG_MARK_LOGIN` 用(会徽下载)。 +- 频道状态:`HEADER_GC_RESPOND_CHANNELSTATUS`(210)。 +- `GC_PHASE(PHASE_SELECT)` → 选人阶段。 + +### 4.4 SELECT / LOADING / GAME +- SELECT:`CG_CHARACTER_SELECT`(6) `command_player_select` `{BYTE header; BYTE player_index;}` → + `GC_PHASE(PHASE_LOADING)` + **header 113 的「主角包」**。服务端 `char.cpp:1607` 发的是 + `TPacketGCMainCharacter`(服务端 `packet.h` L1043)= + `{BYTE header; DWORD dwVID; WORD wRaceNum; char szName[CHARACTER_NAME_MAX_LEN+1=25]; long lx,ly,lz; + BYTE empire; BYTE skill_group;}` —— 客户端非 GAIDEN 里这个 header 走 `case HEADER_GC_MAIN_CHARACTER2_EMPIRE` + 读 `TPacketGCMainCharacter2_EMPIRE`(同布局)。注意 `wRaceNum` 是种族不是地图号,szName 在坐标**前**, + 尾部是 `empire` + `skill_group` 两个 BYTE。开了 SUPPORT_BGM 时改发 `_BGM`(137) / `_BGM_VOL`(138) 变体 + (多 BGM 名字段)。地图名另经加载流程 → `CG_ENTERGAME`(10) → `GC_PHASE(PHASE_GAME)`。 +- 建/删号:`CG_CHARACTER_CREATE`(4) —— 客户端 `command_player_create` / `TPacketCGCreateCharacter` + `{BYTE header; BYTE index; char name[CHARACTER_NAME_MAX_LEN+1=25]; WORD job; BYTE shape; BYTE CON; + BYTE INT; BYTE STR; BYTE DEX;}`(服务端侧同一包叫 `TPacketCGPlayerCreate`)。 + `CG_CHARACTER_DELETE`(5) `command_player_delete` / `TPacketCGDestroyCharacter` + `{BYTE header; BYTE index; char szPrivateCode[PRIVATE_CODE_LENGTH=8];}`。 + → `GC_CHARACTER_CREATE_SUCCESS`(8) `command_player_create_success` / `TPacketGCPlayerCreateSuccess` + `{BYTE header; BYTE bAccountCharacterSlot; TSimplePlayerInformation kSimplePlayerInfomation;}` + / `_CREATE_FAILURE`(9) / `_DELETE_SUCCESS`(10) `{header, BYTE account_index}` / + `_DELETE_WRONG_SOCIAL_ID`(11)。 + +> 与 m2dev 对照:m2dev 是 `CG_CHARACTER_CREATE=0x0201`;40250 是 `HEADER_CG_CHARACTER_CREATE=4`。 +> create 包里 `job` 两边**都是 `WORD`(u16)**;差异在头值、结构体名、字段序(40250 顺序是 +> name→job→shape→CON/INT/STR/DEX),按 40250 `command_player_create` 重推。**只有摘要结构 +> `TSimplePlayerInformation.byJob` 是 BYTE**(见 §5),别和 create 包的 `WORD job` 混。 + +--- + +## 5. 关键结构体差异(抽样,实现期逐个对 `game/src/packet.h`) + +| 语义 | m2dev fork | 40250 classic | +|---|---|---| +| 包头 | `uint16_t header; uint16_t length;` | `BYTE header;`(动态包再加 `WORD size;`)| +| `TItemPos` | `{u8 window_type; u16 cell;}` | `{BYTE window_type; WORD cell;}`(同布局,但不少老包里 cell 是 `BYTE`,按包看)| +| `TPlayerItemAttribute` | `{u8 bType; i16 sValue;}` (3B) | 同 | +| `TSimplePlayerInformation`(客户端 `Packet.h` L1176)| fork 版 | `{DWORD dwID; char szName[CHARACTER_NAME_MAX_LEN+1=25]; BYTE byJob; BYTE byLevel; DWORD dwPlayMinutes; BYTE byST,byHT,byDX,byIQ; WORD wMainPart; BYTE bChangeName; WORD wHairPart; BYTE bDummy[4]; long x,y; LONG lAddr; WORD wPort; BYTE bySkillGroup;}` —— **摘要里 `byJob` 是 BYTE**(但 `command_player_create.job` 是 `WORD`,别混),名字 25,无 wMapIndex/guild(guild 在 `TPacketGCLoginSuccess3/4` 尾部并列数组)| +| 移动 `CG_MOVE`(`command_move`)| fork | `{BYTE bHeader; BYTE bFunc; BYTE bArg; BYTE bRot; long lX; long lY; DWORD dwTime;}` —— **实测一致** | +| 聊天 | fork `[hdr][len][type][...]` | CG `command_chat{BYTE header; WORD length; BYTE type;}` + `char szChat[]`(`Packet.h` L597);GC `packet_chatting{BYTE header; WORD size; BYTE type; DWORD dwVID; BYTE bEmpire;}` + 文本(L1425)。都是动态包,长度字段一个叫 `length` 一个叫 `size`,语义相同 | +| 商店 | fork `GC_SHOP`(0x0810) sub-header + `SHOP_GC_START_EX` | `HEADER_GC_SHOP`(38) `TPacketGCShop{BYTE header; WORD size; BYTE subheader;}`(动态)。`EPacketShopSubHeaders`(`Packet.h` L1864):`GC_START`=0 … `GC_START_EX`=10、`NOT_ENOUGH_MONEY_EX`=11 —— **子头值与 fork 一致**,商店层大体可搬 | +| 交易 | fork `GC_EXCHANGE` sub-header | `TPacketExchange{BYTE header; BYTE subheader; …}` —— **定长,无 `WORD size`**(不是所有 sub-header 包都是动态包,逐个看)| +| 帮会 / messenger / quest | fork 各自 | `GC_GUILD` / `GC_MESSENGER` / `GC_QUEST_INFO` 是动态包(`[BYTE header][WORD size][...]`,见 §2.2 权威清单),子头在 size 之后。`GC_SCRIPT`(任务对话)也是动态 | +| 龙魂精炼 | 不纳入本阶段 | 目标 40250 服务端不提供该玩法;客户端兼容代码保留但不宣称可用,也不纳入当前验收 | + +`wire.h` ~2000 行结构体按 40250 重写成 `wire_classic.h`。**所有 wire 结构体是 `#pragma pack(1)`** +(客户端 `Packet.h` L435–2813 的 `pack(push)/pack(1)…pack(pop)` 段;文件开头那段 `pack(8)` 是无关的 +Hackshield 传输缓冲,不涉及协议)。 + +--- + +## 6. 双后端架构 + +``` +extension/src/net/ +├─ entity_store.{h,cpp} # 共享世界模型。apply() 拆成: +│ # - 状态 + mutation 方法(spawn_entity / set_vitals / +│ # set_inv_item / party_set / shop_set / ...)—— 协议无关 +│ # - m2dev_parser.cpp : 现有 apply() 挪过来,调 mutation +│ # - classic_parser.cpp: 新写,按 §1/§5 解 40250 包,调同一批 mutation +├─ i_net_session.h # 新接口: +│ connect(host, port) / login(id, pw) / select_char(i) / enter_game() +│ send_move/attack/chat/item_move/use_skill/... (或 send(Intent, args)) +│ pump() → 产出 GC 包 → parser → entity_store +│ 信号源: 让 M2Client 照旧 emit(session 只回调 "有 N 个事件待抽干") +├─ m2dev/ # 现有文件整体挪入, namespace mtnet::m2dev, 不改逻辑 +│ wire.h · secure_cipher.{h,cpp} · net_stream.{h,cpp} · game_client.h · auth_client.h · +│ mark_client.h · mark_image.{h,cpp} · byte_buffer.h · m2dev_parser.cpp(从 entity_store 拆) +│ 实现 INetSession +├─ classic/ # 新, namespace mtnet::classic +│ wire_classic.h · classic_cipher.{h,cpp}(Crypto++ DH2 + CTR)· classic_stream.{h,cpp} +│ (1B 头 + size 表 + sequence 字节 + 动态包)· classic_session.cpp(HANDSHAKE→…→GAME 状态机) +│ · classic_parser.cpp · 实现 INetSession +└─ m2_client.{h,cpp} # 持有 std::unique_ptr; + 构造时按 OS.get_environment("MT_PROTOCOL")(默认 "classic" 或先 "m2dev")选 + m2dev::Session / classic::Session; 所有 game->send_* / dispatch 改成 session-> +``` + +- **CTest**:`net_entity_test` / `net_loopback_test` 现有的绑 m2dev 后端,保持绿。 + classic 侧新增 `net_classic_test`(合成包 + MockServer 走 classic 分帧/cipher)。 +- **GDScript / 场景 / UI / 渲染**:保留原有 `M2Client` 方法和既有信号兼容性;为 40250 + 特有的 classic 回包增加必要 signal/状态桥接和 UI 处理,不改渲染底座。 + +--- + +## 7. 待确认 / 暂缓项 + +1. **【暂缓】跑起 40250 服务端** —— `Server/metin2/src/server/`(顶层 `Makefile` → `libthecore libpoly libgame + liblua libsql libserverkey game db`)。**这套是 FreeBSD-only**:`CC = clang++-devel`、`-m32` + 32 位、`-lmd`、静态链 `/usr/local/lib/mysql/libmysqlclient.a` + 预编 `extern/lib/libcryptopp.a` + + `libIL.a`,`GAMEDIR = /usr/metin2/server/share/bin`(`game/src/Makefile` `SVN_VERSION = 40250`)。 + Linux 上跑要么改 Makefile/补依赖,要么 FreeBSD VM/jail。还要 MySQL(`Server/metin2_mysql_dump` / + `Server/mysql`)、`item_proto`/`mob_proto` 表、运行时 `Server/metin2/server/{game99,auth}` 的 `CONFIG`。 + 本仓库的 `tools/40250/{build_server,setup_mysql,prepare_runtime,start_server,stop_server,run_classic_e2e}.sh` + 已把这一步固化为可执行 runbook;当前 macOS 机器仍没有 FreeBSD/MySQL server。该环境搭建和 + live 结果回填暂不属于本阶段交付,后续恢复公会 / 真服验收时再执行。 +2. **明文起步要重编服务端**:`_IMPROVED_PACKET_ENCRYPTION_` 是 `common/service.h:7` 的编译期 `#define`, + **没有 `CONFIG` token 可关**(`config.cpp` 里只有 `test_server` / `distribution_test_server` / + `g_bAuthServer` 这类,与加密无关)。第一里程碑:注释掉 `service.h` 那行重编 game,客户端同理, + shipped 40250 默认直接走 DH2/CTR;明文只作为需要重编 game 的诊断分支,不是运行配置项。 +3. **auth 服务器是否独立端口**:`g_bAuthServer` 分支决定握手收敛后进 `PHASE_AUTH` 还是直接 `PHASE_LOGIN` + (`input.cpp:207-217`)。auth 服和 game 服可能不同端口(运行时 `server/auth` vs `server/game99`)。 + 决定用 `CG_LOGIN` 还是 `CG_LOGIN2/3` + `GC_LOGIN_KEY`。 +4. **Crypto++ 引入方式**:vendored 子模块 vs 抽子集。对齐服务端的 `cryptopp_8_4_0`。 +5. **sequence 表**:客户端静态表 `s_bSequenceTable[SEQUENCE_TABLE_SIZE=32768]`(`EterLib/NetStream.cpp` + L881;`SendSequence()` L834 循环取值 `m_iSequence % 32768`,`SetPacketSequenceMode(true)` L829 开启)。 + 服务端对应表 `game/src/sequence.cpp` `gc_abSequence[SEQUENCE_MAX_NUM=32768]`;校验在 `input.cpp` + L121-162:`m_pPacketInfo->IsSequence(bHeader)` 时读包尾 1 字节与 `lpDesc->GetSequence()` 比,不符 + → `SetPhase(PHASE_CLOSE)` 断线,符 → `push_seq` + `SetNextSequence()`。 + **两张表必须逐字节一致**,端口时整表 + 开启时机照抄。 +6. **HYBRIDCRYPT**(`GC_HYBRIDCRYPT_KEYS/SDB`, 152/153,动态包)—— 是**加密资源包(EterPack)的密钥下发**: + 客户端 `RecvHybridCryptKeyPacket`/`SDBPacket` → `CEterPackManager::RetrieveHybridCryptPackKeys/PackSDB` + (SDB = Supplementary Data Blocks),让客户端能解密 hybrid 加密的 `.eix/.epk`。**与反外挂无关**。 + 我们的移植走散文件 / 自研 mtpack,不吃官方加密包 → **直接忽略**(收到丢弃即可)。 +7. **root/\*.py + uiscript**:这个 dump 只有 client 源码,没带 `root/` pack。UI 窗口对照 40250 版 + uiscript 是**独立线**,不阻塞协议移植(现有窗口先照跑)。 + +--- + +## 8. 建议推进顺序 + +1. **【暂缓】真服前置**:在 FreeBSD VM/jail 按 `tools/40250/README.md` 起 40250 game+auth+db, + 并用官方客户端或 `net_classic_e2e_host` 登入验证;不作为当前交付门槛。 +2. `INetSession` 接口 + `EntityStore` mutation 拆分 + m2dev 挪入 `net/m2dev/`(现有测试保持绿)。 +3. `classic/classic_stream`:1B 头 + size 表 + sequence + 动态包 + shipped DH2/CTR,打通 + HANDSHAKE→LOGIN→SELECT→GAME 空跑。 +4. `classic_parser`:`GC_LOGIN_SUCCESS` / `GC_MAIN_CHARACTER` / `GC_CHARACTER_ADD` / `GC_MOVE` / + `GC_CHARACTER_POINTS` —— 能进游戏、看见自己和别人动。 +5. `classic_cipher`:Crypto++ DH2 + CTR,接 `KEY_AGREEMENT` 流。 +6. 铺开其余 GC/CG(物品 / 战斗 / 商店 / 组队 / 任务 …),对照 m2dev 已做的功能清单逐个搬; + 公会与龙魂不列入当前阶段。 +7. `MT_PROTOCOL` 切换、`net_classic_test`;真服 e2e 暂缓。 +8. UI 窗口对 40250 uiscript 复核(独立)。 + +> 进度按 `docs/CLIENT-GAP.md` 的功能清单同步,标注 classic/m2dev 各自完成度。 + +### 进度(branch `feat/40250-classic-net`) + +- **前置(step 1)**:40250 FreeBSD 服务端 —— 暂缓(见 §7.1),不阻塞当前本地协议 / UI 交付。 +- **step 3a — wire 层** ✅:`extension/src/net/classic/wire_classic.h`(`namespace mtnet::classic`, + 1B 头 enum 全表,命名跟服务端 `packet.h` + `#pragma pack(1)` 结构体 + `static_assert` + + `packet_size_{cg,gc}(h)`(**整包尺寸含 1B 头、不含 seq 字节** —— 对齐 `CPacketInfo::Set(…, sizeof(…))`)+ + `is_sequence_cg` / `is_dynamic_{cg,gc}`)。覆盖 control / handshake / key-agreement / login(1/2/3) / + login_success(32 主用, 6 legacy) / select / create / delete / main_character(113) / + character_add(1,2) / move(CG,GC) / points / point_change / chat。`TSimplePlayer` = **63 字节**。 + 40250 客户端/服务端实际会用到的结构体已随 parser 补齐;仅 vendor-only 或服务端未登记的包不伪造。 +- **step 3b — sequence 表** ✅:`extension/src/net/classic/sequence_table.h` —— 32768 字节 + `SEQUENCE_TABLE`,逐字节 = `NetStream.cpp:881` `s_bSequenceTable` = 服务端 `sequence.cpp` + `gc_abSequence[]`(脚本校验过)。 +- **step 3c — 分帧层** ✅:`extension/src/net/classic/classic_stream.{h,cpp}`(在 `mtnet` 库里)。 + 非阻塞 TCP + `feed()`/`take_outgoing()` 无 socket 测试路径。base 处理 HANDSHAKE 回显 + (`time += 2*delta`、header 不变、无 seq)、`GC_TIME_SYNC` blank、`GC_PHASE`、`GC_PING→CG_PONG`、 + `BINDUDP`;`set_sequence_mode(true)` 后对 bSeq CG 包追加 `SEQUENCE_TABLE[i++]`;动态包读 + `TDynamicSizePacketHeader.size`。收到 `GC_KEY_AGREEMENT` 后由 `classic_cipher` 完成 DH2/CTR + 协商,并支持完成包与后续密文同一 read 的 pipeline。 + CTest `net.classic_wire` + `net.classic_stream` 绿。 +- **step 2 — `INetSession` seam + `EntityStore` mutation API** ✅(部分): + `extension/src/net/i_net_session.h`(`connect / disconnect / select_char / enter_game / pump / + stage / world`,per-intent `send_*` 随后加)。`EntityStore` 加了协议无关的 + `mut_spawn / mut_spawn_main / mut_despawn / mut_move / mut_set_points / mut_set_point` + (包住原 `touch()` / `start_move()`,m2dev `apply()` 一行没动,`net.entity_store` 仍绿)。 + m2dev 文件的物理挪目录(`net/m2dev/`)延后(纯改名,无功能收益)。 +- **step 4 — `classic_parser` + `classic_session`** ✅: + - `classic/classic_parser.{h,cpp}` —— 40250 GC 包体 → `EntityStore::mut_*`。已接 + `GC_LOGIN_SUCCESS`(32/6) / `GC_LOGIN_FAILURE` / `GC_LOGIN_KEY` / `GC_MAIN_CHARACTER`(113) / + `GC_CHARACTER_ADD`(1) / `GC_CHARACTER_DEL`(2) / `GC_MOVE`(3) / `GC_CHARACTER_POINTS`(16) / + `GC_CHARACTER_POINT_CHANGE`(17,含 `int32_t header` 怪癖) / `GC_CHAT`(4,dynamic)。 + `CharSlot` 列表 + handle/random_key。 + - `classic/classic_session.{h,cpp}`(实现 `INetSession`)—— 驱动 + HANDSHAKE→LOGIN(`CG_LOGIN`, shipped server 的 DH2/CTR)→SELECT→LOADING→GAME。`GC_PHASE(LOGIN)` 时开 sequence mode + 并发登录;`GC_PHASE(SELECT)` 抛 `on_char_list`;`select_char(slot)`→`CG_CHARACTER_SELECT`; + `PHASE_LOADING` 后 1.5s 自动 `CG_ENTERGAME`(可配);`PHASE_GAME`→`on_entered_game`。 + `start_offline()` 测试钩子跳过 socket。 + - CTest `net.classic_session` —— 合成服务端字节走完整流程:握手回显、CG_LOGIN + seq[0]、 + 4 格角色列表、选人 + seq[1]、主角/NPC spawn、自动 ENTERGAME + seq[2]、进游戏、 + GC_MOVE 插值、points/point_change/del。全量 ctest **13/13**。 +- **step 4b — per-intent `send_*`** ✅:`INetSession` + `ClassicSession` 加了 + `send_move`(`bRot = deg/5`)/ `send_attack` / `send_chat`(dynamic:`[hdr][WORD len][type]text\0`, + `len = 4 + strlen + 1`)/ `send_target` / `send_character_position` / `send_click_npc` / + `send_script_answer` / `send_item_use` / `send_item_move` / `send_item_drop`(count>0 走 DROP2)/ + `send_item_pickup` / `send_use_skill`(target 非 0 时先发 `CG_FLY_TARGETING`)。全部 + `Stage::InGame` 门控,走 `classic_stream` 的 seq 追加。`wire_classic.h` 补了对应 CG 结构体 + + `packet_size_cg` 表项。`EntityStore::mut_move` 改收「已解码角度」(m2dev `rot*360/256` vs + classic `rot*5` 两种编码,放到 parser 里转)。`net.classic_session` 扩展验证 + move/attack/target/chat/item_move 的字节布局 + seq[3..6] 连续性 + 非 InGame 拒绝。ctest 13/13。 +- **step 7(前半)— `M2Client` 按 `MT_PROTOCOL` 选后端** ✅:`connect_to_server()` 里 + `OS::get_environment("MT_PROTOCOL") == "classic"` → 建 `ClassicSession` 直连 game host(无独立 + auth 服),`set_stage(GameConnect)`;否则原 `AuthClient`+`GameClient` 路径**一行没动**。 + `_process()` 加 `pump_classic()` 分支(stage→`phase_changed`/`stage_changed`/`char_list`/ + `entered_game` + 复用世界镜像子集:`entity_spawned/despawned/moved/main_set/info` + `chat` + + `vitals_changed` + `points_changed`——即 `classic_parser` 目前产出的那些)。热路径方法 + (`move` / `attack` / `set_target` / `say` / `character_position` / `click_npc` / `script_answer` / + `use_skill` / `move_item` / `use_item` / `drop_item{,_count}` / `pickup_item` / `select_character`) + 加 `if (classic_sess) return classic_sess->send_*(...)` 前置分支。读方法 + (`get_entity` / `get_entities` / `get_main_vid` / `get_points`)经新 `active_world()` 取 + `classic_sess ? &classic_sess->world() : &game->world()`。guild/cube/marks 已接入 classic: + 公会/战争/技能走 `CG_GUILD`,会徽走带当前 handle/random_key 的独立 mark 连接,Cube 走 + 40250 的 `/cube r_info`、`/cube add/delete`、`/cube make` 命令;classic 下原来因 `game == null` + 而 no-op 的 M2Client 分支已消除。仍不伪造 vendor-only HackShield/XTrap 响应和未在 40250 + 源码登记的可选包。 + ctest 13/13,Godot editor import 干净,抽样 GDScript 测试通过,iOS/Android 绿。 +- **step 5 — `classic_cipher`(`_IMPROVED_PACKET_ENCRYPTION_`)** ✅(mac + iOS + Android 全绿): + - **Crypto++ 8.4.0 vendored**:`extension/third_party/cryptopp/`(从 `ClientVS22/extern/include/ + cryptopp` 拷 393 个 `.h/.cpp/.S`,非 submodule)+ 自写 `CMakeLists.txt`(glob `.cpp`,剔除 + test/bench/validat/regtest/adhoc/fips,`CRYPTOPP_DISABLE_ASM/SSSE3/AESNI` 全平台纯 C++)。 + `mt3p::cryptopp`,链进 `mtnet`。mac 编译干净。 + - `classic/classic_cipher.{h,cpp}` —— 近乎照搬 `EterBase/cipher.cpp`:`DH2KeyAgreement` + (RFC 5114 1024-bit MODP + `DH2` 静态+临时密钥对,`prepare()` 生成 `spub||epub` blob,`agree()` + 出 `SecByteBlock shared`)+ `BlockCipherAlgorithm::Pick(hint % 14)` 选块密码(默认 Twofish)+ + `set_up(polarity)` 从 `shared` 切 key/iv 建两个 `CTR_Mode` 实例(`polarity` 决定收发各用哪个)。 + - `classic_stream` 接进去:`GC_KEY_AGREEMENT`(0xFB) → `prepare()` + `activate(polarity, …)` + + 回发 `CG_KEY_AGREEMENT`(明文);`GC_KEY_AGREEMENT_COMPLETED`(0xFA) → `set_activated(true)` + + 立刻解密缓冲区里 server 可能 pipeline 的密文尾巴。激活后 `emit_bytes()` 对所有出站字节 + (含 seq 字节)CTR 加密、`decrypt_appended()` 对每个 recv/feed chunk 解密。`set_polarity(true)` + = 客户端。 + - CTest `net.classic_cipher`(DH2 双端协商 + 加解密对称往返 + CTR 连续性 + 会话隔离)、 + `net.classic_encstream`(`ClassicStream` 全流程:握手 → KEY_AGREEMENT 交换 → COMPLETED → + 加密 GC_PHASE 解出 + 出站 CG_MOVE 服务端能解 + pipelined COMPLETED+密文一个 feed)。 + mac ctest 15/15。 + - **交叉编译**:iOS arm64 ✅、Android arm64 ✅(Android 需把 NDK 的 + `sources/android/cpufeatures/cpu-features.c` 编进 `cryptopp` + 加到 include path —— + `cpu.cpp` 无条件 `#include "cpu-features.h"`;已在 `cryptopp/CMakeLists.txt` 的 `if(ANDROID)` 里处理)。 + `.so` 从 46 MB → 59 MB。Godot editor import 干净,ctest 15/15。 +- **step 4c — `classic_parser` 铺开 GC(items)** ✅:接了 `GC_ITEM_SET`(21) / `GC_ITEM_DEL`(20) / + `GC_ITEM_UPDATE`(25) / `GC_ITEM_GROUND_ADD`(26) / `GC_ITEM_GROUND_DEL`(27)。40250 的 + `TPlayerItemAttribute` 是 3 字节 `pack(1)`(`{BYTE type; short value}`),跟 `EntityStore::Item.attrs` + 的 stride 不同 → parser 里逐元素解包。`EntityStore` 加 `mut_item_set / mut_item_del / + mut_item_update / mut_ground_add / mut_ground_del`(包 `mut_slot()` + `m_inv_changes` / + `m_ground`)。`M2Client`:`get_inventory / get_equipment / get_item / get_ground_items` 改走 + `active_world()`;`pump_classic()` 补 `drain_inv` → `inventory_changed`、`drain_ground` → + `ground_item_added/removed`。`net.classic_session` 扩展验证 item_set/update/del + ground add/del。 + ctest 15/15,iOS/Android 绿。 +- **step 4d — `classic_parser` GC 实体状态簇** ✅:`GC_CHARACTER_UPDATE`(19,装备外观/公会/善恶/骑乘) / + `GC_CHANGE_SPEED`(18) / `GC_CHARACTER_POSITION`(43) / `GC_WALK_MODE`(111) / `GC_STUN`(13) / + `GC_DEAD`(14) / `GC_MOTION`(36) / `GC_TARGET`(63,目标血条 %)。`EntityStore` 加 `mut_char_update / + mut_set_position / mut_change_speed / mut_walk_mode / mut_stun / mut_dead / mut_motion / mut_target` + (包 `m_ents` / `m_motions` / `m_target_*` / `m_mount_changes`)。`pump_classic()` 补 + `drain_motions`→`motion`、`drain_damage`→`damage`、`drain_mount_changes`→`mount_changed`、 + `take_target_dirty`→`target_info`。`get_target()` 走 `active_world()`。`net.classic_session` + 扩展验证。ctest 15/15,iOS/Android 绿。 +- **step 4e — `classic_parser` HUD 簇** ✅:`GC_SKILL_LEVEL`(76,`TPlayerSkill` 6B/条,`time_t` + 32 位) / `GC_QUICKSLOT_ADD/DEL/SWAP`(28/29/30) / `GC_AFFECT_ADD/REMOVE`(126/127,`TPacketAffectElement` + 21B) / `GC_DAMAGE_INFO`(135) / `GC_CHAR_ADDITIONAL_INFO`(136,补 spawn 的 name/parts/level/guild) / + `GC_WHISPER`(34,dynamic —— 客户端 map 登记 STATIC 但 `wSize` 恰在 `TDynamicSizePacketHeader.size` + 偏移,走 dynamic 路径 ok) / `GC_SYNC_POSITION`(5,dynamic)。`EntityStore` 加 `mut_skill_levels / + mut_quickslot_{set,del,swap} / mut_affect_{add,remove} / mut_damage / mut_char_info / + mut_snap_position / mut_chat / mut_whisper`。`GC_CHAT`/`GC_WHISPER` 改走 `EntityStore::m_chat` + 队列(跟 m2dev 一致,`pump_classic` 的 `drain_chat` 统一处理),删掉 parser 的 `on_chat` 回调。 + `pump_classic()` 补 skills/quickslots/affects 的 drain;`get_skills/get_quickslots/get_affects/ + get_skill_group` 走 `active_world()`。ctest 15/15,iOS/Android 绿。 +- **step 4f — `classic_parser` party** ✅:`GC_PARTY_INVITE`(77,`leader_vid`) / `GC_PARTY_ADD`(78) / + `GC_PARTY_UPDATE`(79,role/hp%/affects[7]) / `GC_PARTY_REMOVE`(80) / `GC_PARTY_LINK`(91) / + `GC_PARTY_UNLINK`(92) / `GC_PARTY_PARAMETER`(83,分配模式)。`EntityStore` 加 `mut_party_{invite,add, + update,remove,link,unlink,parameter}`。`pump_classic()` 补 `drain_party_invites`→`party_invite_ask`、 + `party_dirty`→`party_changed`。`get_party` / `get_party_distribute_mode` 走 `active_world()`。 + ctest 15/15,iOS/Android 绿。 +- **step 4g — `classic_parser` NPC shop** ✅:`GC_SHOP`(38,dynamic 子头) —— `START`(0,单货架 + `packet_shop_start{u32 owner_vid; packet_shop_item[40]}`,`packet_shop_item`=43B) / + `START_EX`(10,多货架 `{u32 vid; u8 tab_count} + tab_count×{name[32]; coin_type; item[40]}`) / + `END`(1) / 错误子头(`NOT_ENOUGH_MONEY`/`SOLDOUT`/`INVENTORY_FULL`/`INVALID_POS`)。 + `EntityStore` 加 `mut_shop_open(vid, tabs) / mut_shop_close() / mut_shop_error(code)`。 + `pump_classic()` 补 `shop_dirty`→`shop_opened`/`shop_closed`、`drain_shop_errors`→`shop_error`。 + `is_shop_open` / `get_shop_items` / `get_shop` 走 `active_world()`。ctest 15/15,iOS/Android 绿。 +- **step 4h — `classic_parser` quest / NPC 对话** ✅:`GC_SCRIPT`(45,dynamic,`{skin; u16 src_size; + text}`) / `GC_QUEST_CONFIRM`(46,STATIC 74B) / `GC_QUEST_INFO`(81,dynamic,`{u16 index; u8 flag}` + + flag 驱动 title/clock/counter/icon 串)。`EntityStore` 加 `mut_script / mut_quest_confirm / + mut_quest_info`。`pump_classic()` 补 `drain_scripts`→`script_dialog`、`drain_confirms`→ + `quest_confirm_ask`、`drain_quest_changes`→`quest_info`。`get_quests` 走 `active_world()`。 + ctest 15/15,iOS/Android 绿。至此 `click_npc`→`GC_SCRIPT` 对话闭环。 +- **step 4i — classic P8 social / storage** ✅: + - `GC_MESSENGER` / `CG_MESSENGER`:好友快照、上线/下线与手机状态,以及按 40250 客户端格式发送加好友/删好友。 + - `GC_EXCHANGE` / `CG_EXCHANGE`:交易开始、双方物品/金币/接受状态、结束/错误提示,以及全部客户端操作。 + - `GC_SAFEBOX_*` / `CG_SAFEBOX_*`:仓库开启、资金、物品快照/删除、密码错误、存入/取出/移动。 + - `GC_MALL_*` / `CG_MALL_CHECKOUT`:商城开启、物品快照/删除、取出;均接入 `EntityStore`、 + `M2Client` 读接口、信号和 classic session intent。`net.classic_wire` / `net.classic_session` 覆盖 + 包尺寸、字段布局、序列字节和状态变更;macOS `mtgodot` 构建通过。 +- **step 4j — classic P9 / remaining fixed packets** ✅:补齐 `GC_WARP` 跨频道重连、`GC_TIME` / + `GC_CHANNEL`、NPC/土地/目标标记、恋人、观察者、坐骑/飞行、PVP、`GC_DUEL_START` 对手 VID 列表、装备查看、挖矿/钓鱼、炼化、 + 技能冷却和特殊效果;并消费登录安全包、BGM 主角包、`CHARACTER_ADD2/UPDATE2`。龙魂兼容代码不纳入目标服务端支持声明。 + 不具备 40250 vendor runtime 的 HackShield/XTrap 请求只做定长消费,不伪造响应。 +- **step 4k — Cube + private shop semantics** ✅:classic Cube 使用 40250 `cmd_general.cpp` 的 + `/cube r_info`、`/cube r_info `、`/cube add `、 + `/cube delete `、`/cube make`;UI 提供背包→24 格材料槽的添加/删除。个人摊位收摊 + 使用空 `CG_MYSHOP`,与 40250 `CHARACTER::OpenMyShop()` 的关闭语义一致。 +- **step 4l — UI/uiscript复核** ✅:好友、交易、仓库、商城、NPC 商店、会徽、Cube、炼化和个人摊位 + 窗口均通过既有 M2Client 信号/intent 接入;公会窗口暂缓,龙魂窗口不纳入目标服务端支持范围。Cube UI 的旧“直接按配方 index 制作” + 已改为先装载材料槽再制作,避免把 classic index 当成服务端参数;PVP/决斗状态也会在世界标签中 + 刷新,`MobView.set_display_name()` 对无内置名字节点的真模型提供同样的名字牌回退。 +- **step 4m — 公会完整状态与会徽原生协议** ⏸️ 暂缓:公会在线/离线、公告列表、 + 邀请、战争积分等 GC 子包,并接入 `EntityStore`、`M2Client` 和公会窗口;公告发布/刷新/删除、 + 邀请接受/拒绝都有对应 CG 路径;已有代码保留但公会整体不纳入当前阶段。会徽独立连接也已改为 40250 的单字节头、`bufSize` 分片、CRC、 + 符号包和上传布局;并按原客户端在首个 `GC_HANDSHAKE` 后发送 `CG_MARK_LOGIN` 的时序处理, + 兼容随后是否进入可选 DH2/CTR;`net.classic_mark` 固定了下载与上传的关键字节协议。 +- **step 4n — 握手重试与时钟同步时序** ✅:`PHASE_HANDSHAKE` 中的重试仍回发 + `GC_HANDSHAKE`(0xff),进入 LOGIN/SELECT/GAME 后收到的后续握手才改发带 sequence 的 + `CG_TIME_SYNC`(0xfc);会徽独立连接保持首个握手后的 `CG_MARK_LOGIN` 路径,避免把两种连接的 + 控制包时序混用。`net.classic_stream` 和 `net.classic_mark` 已分别覆盖这两个边界。 +- **step 4o — 好友邀请确认闭环** ✅:40250 的 `GC_CHAT/COMMAND` 命令 + `messenger_auth ` 不再静默丢弃,现会产生 `friend_invite_ask`;好友窗口显示接受/拒绝 + 对话框,并通过 `/messenger_auth y|n ` 回发原生服务端命令。`net.entity_store` 与 + `p8_test.gd` 覆盖邀请入队、弹窗和两种回答;`netbridge_test.gd` 同时校验 P8/P9、会徽和精炼 + API 都实际绑定到 Godot;公会与龙魂不作为当前交付验收项。 +- **step 4p — 40250 命令总线补齐** ✅:`PartyRequest`/`PartyRequestDenied`、`CloseSafebox`/ + `CloseMall`、`ShowMeSafeboxPassword`/`ShowMeMallPassword`、`RefineSuceeded`/`RefineFailed`、 + `OpenPrivateShop`、`MyShopPriceList` 和服务端回传的 `setblockmode` 已从静默 no-op 改为 + `EntityStore` typed event;M2Client 暴露对应 signal,仓库/商城会弹密码框,错误密码会提示, + 精炼结果会回显,个人摊位可由服务端命令打开并使用价格回填,游戏设置会按服务端屏蔽掩码同步。 + `net.entity_store` 覆盖这些命令及仓库关闭状态。 +- **step 4q — 其余有状态的 ServerCommand** ✅:40250 客户端原生处理的 + `ObserverMode`/`ObserverCount`、`StoneDetect`、`StartStaminaConsume`/`StopStaminaConsume`、 + `sms`/`nosms`、`mobile_auth` 和 `combo` 已进入 `EntityStore` 状态及 typed event; + M2Client 提供观战/体力/手机/连击 getter 和对应 signal(体力按服务端下发速率递减,探石保留 + 转换后的角度),因此 classic 不会在这些回包上静默丢状态。`ConsoleEnable`、`BettingMoney`、 + `ObserverTeamInfo` 仍保持 40250 原客户端的无可见副作用语义;不伪造它们不存在的 Godot 功能。 +- **step 4r — GC_MOTION 与表情命令** ✅:`GC_MOTION` 不再只由 M2Client 发出后被场景丢弃, + NetWorld 会驱动本地/远端实体,并按 40250 `CRaceMotionData` 的职业变体选择真实 `.msa`。 + `kiss`、`french_kiss`、`slap`、`clap`、`cheer1/2`、`dance1..6`、`dig_motion` 及其余 + `congratulation/forgive/angry/.../joy` ServerCommand 也映射到同一 motion 流;`gift` 会触发 + 可见通知。40250 源码只提供 `Gift_Show()` 通知入口,没有随命令携带奖励或领取 CG,因此不虚构 + 礼物奖励数据协议。 +- **step 4s — 版本门禁与无阵营账号** ✅:补齐账号未绑定阵营时的 `CG_EMPIRE` 选择入口,并在 + 收到 `GC_MAIN_CHARACTER`、`GC_MAIN_CHARACTER3_BGM` 或 `GC_MAIN_CHARACTER4_BGM_VOL` 后按 + 40250 原客户端时序发送一次 `CG_CLIENT_VERSION`(`1215955205`)及 sequence。服务端 + `input_main.cpp` 会在首次 `CG_MOVE` 前拒绝没有版本上报的连接;classic session 现在覆盖这个 + 门禁,离线测试同时锁定版本字段和序号推进。 +- **step 4t — 强制改名 UI 闭环** ✅:`SimplePlayer.change_name` 已透传到 classic / m2dev + 角色槽位;选人页在该标志存在时按 40250 原版行为拦截“开始”并打开改名窗,发送 + `CG_CHANGE_NAME`,再由 `GC_CHANGE_NAME` 刷新角色名并清除强制改名标志。`AppFlow` 已接通请求、 + 成功和失败回传,`char_create_delete_test.gd` 覆盖短名拒绝、发送参数和成功状态。强制改名的 + 重名 / 非法名错误码与真实服务端验收暂缓。 +- **step 4u — 创建公会 UI 闭环** ⏸️ 暂缓:`GC_REQUEST_MAKE_GUILD` 现在会触发公会窗的创建名称输入, + 按 40250 原版流程校验空名、控制字符和 12 字上限,再调用 `CG_ANSWER_MAKE_GUILD`;发送失败会 + 保留窗口以便重试。已有 `guild_creation_ui_test.gd` 覆盖服务端请求、名称校验和合法名称应答。 + 公会完整页面、服务端敏感词 / 重名错误回包、实际建会状态和权限暂不纳入本阶段。 +- **step 4v — 任务选魔石窗口复核** ✅:确认 `[SELECT_ITEM]` 已从 `QuestDialog` 接到 + `SelectItemUI`,按原 `uiselectitem.RefreshSlot` 过滤魔石和 grade、将选择窗格映射回背包格, + 选择时发送 `CG_SCRIPT_SELECT_ITEM`,关闭时发送 0;`select_item_ui_test.gd` 已覆盖过滤和选择。 + 原版 CJK IME、完整资源视觉及真实脚本业务回包验收暂缓。 +- **step 4w — 队伍角色 / 能量 / 私店招牌复核** ✅:按 40250 `CParty::Update` 修正 + `party_ui.gd` 的角色 6 为 `HASTE`(迅捷),并补齐 `affects[7]` 槽位语义;攻击/坦克/迅捷/辅助/ + 宗师/防御分别按 Leadership 10/20/20/25/35/40 门控,组队治疗按 Leadership 18 门控, + `p8_test.gd` 覆盖低等级禁用路径。Cube 的 `POINT_ENERGY` 已由 HUD 快照显示;`GC_SHOP_SIGN` + 已由 `NetWorld` 提供 `ShopSign` Label3D fallback,`GC_SYMBOL_DATA` 已接会徽下载链路;个人摊位 + 已支持标准 Godot 拖放与点击选取双路径,Cube 已校验 `cube_open(npc)` 前置、配方材料、金币和 + 制作状态。缺失共享 `.sub` 贴图时使用现有 fallback,不阻断窗口逻辑;live FreeBSD + MySQL E2E 暂缓。 +- **step 4x — P8 交互边界与目标服务端范围** ✅:NPC/石头/传送点点选统一进入 + `click_npc`,服务端 `cube_open` 才打开 Cube;商店购买/出售支持数量控件和错误回显,交易栏位按 + 服务端已占用槽位分配并拒绝重复/超限,仓库/商城拒绝满背包或满仓位,密码弹窗可正常确认/取消。 + 40250 目标服务端没有龙魂玩法,`GameScene` 不再创建龙魂入口、不消费其背包右键或快捷键; + `ds_refine` 兼容 API 仍保留。 +- **本机回归结果**:C++/协议 CTest 16/16 通过(包含 `net.loopback_flow`);本次抽样的 + `project/*_test.gd` 共 38 个脚本全部通过;系统设置测试已使用 headless 临时配置并对缺失可选 + 贴图安全降级。当前沙箱禁止 loopback bind,因此 `channel_status_test` 明确跳过本机 mock; + 有网络权限时仍执行完整请求/响应断言,不是 40250 classic 协议失败。 +- **当前收尾项**:协议 / 状态链路、classic UI 交互和离线回归测试已完成;真实 FreeBSD + MySQL + binary E2E 暂缓,公会功能暂缓,龙魂因目标 40250 服务端不提供而排除。`tools/40250/` 的 + build/setup/start/stop/probe 入口保留,待后续恢复真服验收时使用。 diff --git a/docs/CLIENT-GAP.md b/docs/CLIENT-GAP.md index d41befe6..941cc73d 100644 --- a/docs/CLIENT-GAP.md +++ b/docs/CLIENT-GAP.md @@ -8,10 +8,14 @@ > 渲染细节另见 `PARITY-GAP.md`,动画、材质和资产管线另见 `BACKLOG.md`,网络实现另见 > `CLIENT-PORT.md`。 > -> 更新日期:2026-08-31(增量 38) +> 更新日期:2026-09-01(增量 45) > > **状态列图例**:✅ 达到本文末“1:1 完成判据” · 🟡 有首版 / 部分语义 · ⬜ 未实现 · > ❌ 明确不做(超出 m2dev-client 参考范围,除非另立需求)。 + +> **当前 40250 范围调整(增量 45)**:真实 FreeBSD + MySQL 服务端的完整登录 / 功能验收暂缓, +> 不作为本阶段交付门槛;公会相关功能暂缓。当前目标 40250 服务端不提供龙魂玩法,龙魂不纳入本阶段 +> 支持范围,已有兼容代码不代表服务端可用;运行时龙魂入口已禁用,但保留 `ds_refine` 等协议兼容代码。 > > ### 不做清单(❌) > @@ -21,9 +25,38 @@ > - **反作弊(anti-cheat)**:`CG_HACK`(0x0B03) 客户端异常上报,以及桌面外壳的 > `ProcessCRC` / `ProcessScanner` / 内存扫描等。自用客户端不需要,**标注为不做**, > 除非服务端强制校验才回头做最小上报。 +> - **龙魂精炼(当前 40250 目标服务端)**:目标服务端不提供该玩法,本阶段不实现 / 不验收; +> 客户端保留的兼容代码不计入当前支持范围。 > > ### 变更记录 > +> - **2026-09-01 增量 45(P8 交互边界与龙魂运行时范围)**:补齐 NPC 点击路由、Cube NPC +> 前置 / 配方材料 / 金币校验与制作状态、商店购买 / 出售数量和错误反馈、交换重复 / 满槽 / +> 金币边界、仓库 / 商城密码与满包回滚、个人摊位标准 Godot 拖放路径;缺失可选 `.sub` 贴图 +> 安全降级。龙魂入口运行时禁用,公会和真实服务器验收继续按当前范围暂缓。 +> - **2026-09-01 增量 44(交付范围调整)**:真实 FreeBSD + MySQL 完整验收、公会相关功能均 +> 暂缓;当前目标 40250 服务端不提供龙魂玩法,龙魂从本阶段支持范围排除。保留本地协议 / 状态 / UI +> 首版与离线回归结果,后续恢复服务端条件后再单独推进 deferred 项。 +> - **2026-09-01 增量 43(队伍角色 / 能量 / 私店招牌复核)**:对照 40250 服务端 +> `CParty::Update` 修正队伍角色 6 为 `HASTE`(迅捷),补齐 `affects[7]` 的服务端槽位语义, +> 并在 `party_ui.gd` 按 Leadership 10/20/25/35/40 门控攻击/坦克/迅捷/辅助/宗师/防御, +> Leadership 18 门控组队治疗;`p8_test.gd` 覆盖低 Leadership 的禁用路径。Cube HUD 已有 +> `POINT_ENERGY` 快照显示;`GC_SHOP_SIGN` 已解析并在 `NetWorld` 以 `ShopSign` Label3D +> 作为无 `.sub` 资源 fallback,`GC_SYMBOL_DATA` 也已有会徽下载链路。剩余仍是原版资源、真 +> `.sub` 拖放 / 视觉和 Cube NPC 交互;live FreeBSD + MySQL E2E 暂缓。 +> - **2026-09-01 增量 42(选魔石窗口闭环复核)**:确认 `GC_SCRIPT` 的 `[SELECT_ITEM]` 已由 +> `QuestDialog` 转发到 `SelectItemUI`;选择窗按原 `uiselectitem.RefreshSlot` 过滤魔石 / grade、 +> 映射背包格并发送 `CG_SCRIPT_SELECT_ITEM`,关闭发送 0,`select_item_ui_test.gd` 已覆盖。仍需 +> 完整原版资源、图标和 CJK 输入环境下的视觉验收。 +> - **2026-09-01 增量 41(创建公会 UI 闭环)**:`GC_REQUEST_MAKE_GUILD` 触发公会创建窗口, +> 对应 `CG_ANSWER_MAKE_GUILD` 已接入名称输入、12 字上限、空名 / 控制字符校验和发送失败提示; +> 新增 `guild_creation_ui_test.gd` 覆盖请求、校验和合法名称应答。服务端敏感词 / 重名错误及实际建会 +> 状态仍需真服验收。 +> - **2026-09-01 增量 40(强制改名 UI 闭环)**:`SimplePlayer.change_name` 已从 classic / m2dev +> 角色列表透传到 `M2Client.char_list`;选人页按 40250 原版语义,在角色带该标志时点击“开始” +> 弹出改名窗,校验名称后发送 `CG_CHANGE_NAME`,成功的 `GC_CHANGE_NAME` 刷新槽位并清除标志, +> `AppFlow` 接通请求、成功和失败回传,新增 `char_create_delete_test.gd` 回归覆盖。P1 行不再把 +> 改名 UI 列为未实现;仍需真服验证强制改名、重名 / 非法名错误码和服务端状态。 > - **2026-08-31 增量 30(EterGrnLib 对齐复核)**:查代码确认以下已落地,表内相关行同步。 > ① **材质 blend / two-sided 改读 GR2 材质信息**(`metin2_model::decide_blend/decide_two_sided` > 优先 `gr2::MaterialInfo.alpha_blend/two_sided` = `dump_materials` 端口 `Material.cpp:233`, @@ -63,17 +96,18 @@ > - **2026-08-31 增量 37(组队成员信息板 + `CG_PARTY_SET_STATE`)**: > ① **C++**:`wire.h` 加 `CGPartySetState{u16 hdr,u16 len,u32 pid,u8 role,u8 on}`(断言 10) > + `EPartyRole` 枚举(NORMAL 0/LEADER 1/ATTACKER 2/TANKER 3/BUFFER 4/SKILL_MASTER 5/ -> BERSERKER 6/DEFENDER 7);`game_client.send_party_set_state(pid,role,on)`; +> HASTE 6/DEFENDER 7);`game_client.send_party_set_state(pid,role,on)`; > `M2Client.party_set_state(pid,role,on)` + bind;`get_party()` dict 补 `state`(完整角色字节) > 和 `affects[7]`。 > ② **`party_ui.gd`** 从「名字 + 一条 HP」重做成 1:1 迁移 `assets/root/uiparty.py` > `PartyMemberInfoBoard` + `partymemberinfoboard.py` 布局:每员 strip = 角色状态按钮 -> (队长可点 → 弹角色菜单 普通/攻击/坦克/狂战/辅助/宗师/防御 → `party_set_state`;普通 = +> (队长可点 → 弹角色菜单 普通/攻击/坦克/迅捷/辅助/宗师/防御 → `party_set_state`;普通 = > 清当前角色 `on=false`;+ 踢出 → `party_leave` = `SendPartyRemovePacket`)+ 名字(+★队长) > + HP gauge + `affects[7]` 非零 → 附加效果 chip(tooltip 带值,槽位名暂定)。点名字 → > `set_target(vid)`。顶部:EXP 分配开关(`party_set_distribute` 0 不均分 / 1 均分)+ > 组队治疗(`party_use_skill(PARTY_SKILL_HEAL=1, 0)`)。队长判定 = `get_party()` 里本地 -> `get_main_vid()` 那条的 `leader`。角色菜单按党技能等级门控(Tanker≥10…Defender≥40)暂略。 +> `get_main_vid()` 那条的 `leader`。角色菜单按 40250 服务端 Leadership 门控:攻击≥10、坦克/迅捷≥20、 +> 辅助≥25、宗师≥35、防御≥40;治疗要求 Leadership≥18。 > ③ **修 `p8_test` 隐患**:`_init` 原来 `_run()` 未 `await`,`_run` 第一个 `await process_frame` > 之后的所有断言(含增量 34 的 `shop_ex` 多货架)从未真正生效 —— 改成 `await _run()` 后 > 暴露 `shop_ui.refresh()` 的 `queue_free` 延迟 bug(旧 row 当帧未消失 → `get_child_count` @@ -224,6 +258,11 @@ > `get_observers()` 与 `land_areas_changed` / `observer_event` 已接入;小地图现在消费观战者 > 状态并绘制紫色菱形标记。实体、回环、Godot 桥接和 `p9_test.gd` 覆盖。缺失 header 清单由 > 5 项降为 **1 项**(仅剩 `CG_TEXT`,参考端未发现实际发送方)。 +> - **2026-09-01 增量 39(`CG_TEXT` wire 尺寸覆盖)**:按 40250 `TPacketCGText` / +> `CInputHandshake::Analyze` 补齐 `CG_TEXT` 的 1 字节固定前缀和 classic `packet_size_cg()` +> 表项,并加入 wire 回归断言。该包后续文本由服务端按换行特殊解析,仅作为握手阶段管理通道; +> Cube 继续使用已验证的 `CG_CHAT`/`CHAT_TYPE_COMMAND`,不把管理命令暴露为普通游戏 API。 +> 主网络层缺失 header 清单由 1 项降为 0 项。 > - **2026-08-31 增量 19(钓鱼动作消费)**:`NetWorld` 和 `NetPlay` 现在消费 > `fishing_event` 的 START / STOP / REACT / SUCCESS / FAIL 子头,记录方向并尝试驱动远端及 > 本地主角的钓鱼动作;FISH 子头按参考客户端语义保留为鱼获物品事件,不误当作角色 VID。 @@ -272,7 +311,7 @@ > - **2026-08-31 增量 3**:两个 ⬜ 项落地首版 —— **私人商店 / 道具商城** > (`CG_MYSHOP` / `GC_MALL_OPEN|SET|DEL` / `CG_MALL_CHECKOUT` + `private_shop_ui` / > `mall_ui`)、**Cube 제작**(`GC_CHAT/COMMAND` 的 `cube …` 总线 → `CubeState` + -> `cube_ui`)。仍缺能量条、原版拖放 UI 细节。 +> `cube_ui`)。能量值已由 `POINT_ENERGY` 快照接入 HUD;仍缺原版拖放 UI 细节。 > **拍卖行**经核查 m2dev-client 无此系统 → 标注 ❌ 不做(见上「不做清单」)。 > **反作弊**(`CG_HACK` + `ProcessCRC`/`ProcessScanner`)→ 标注 ❌ 不做。 > **「协议覆盖审计」段**改为逐条清单:脚本核对 `wire.h` vs `Packet.h`,主网络层 @@ -291,7 +330,7 @@ ## 结论 `mtgodot-poc` 已经不是早期“只能登录、移动和攻击”的骨架:登录到 PHASE_GAME、基础战斗、 -背包 / 装备、技能 UI、任务、聊天、组队 / 好友、商店 / 交易 / 仓库、公会、精炼、龙魂、 +背包 / 装备、技能 UI、任务、聊天、组队 / 好友、商店 / 交易 / 仓库、精炼, 地图和部分特效都已有可运行首版。 当前的主要差距已从“有没有功能”转为: @@ -313,7 +352,7 @@ - 背包、基础装备换模、地面物品、技能窗口和快捷栏读取; - 聊天、私聊、基础任务对话和任务日志; - 组队、好友、情侣名 / 爱意值状态、NPC 商店、交易、仓库; -- 公会、公会技能、公会战、会徽上 / 下载、精炼、龙魂精炼; +- 公会、公会技能、公会战、会徽上 / 下载、精炼(公会相关验收暂缓); - 地形、建筑、水体、**NPC / 怪物真模型(vnum→npclist.txt→目录)**、小地图、频道、昼夜和天气首版; - GR2 模型 / 动画、换装首版、武器 / 盾挂点、距离 LOD / 淡入、角色接触阴影、 `item_proto` 驱动的球面高光和 `.mse` 粒子首版。 @@ -324,7 +363,7 @@ | 优先级 | 状态 | 模块 | 当前实现 | 需要迁移的原客户端语义 | |---|---|---|---|---| -| P1 | 🟡 | 选人 / 建号 / 删号 / 改名 | `CG_CHARACTER_CREATE`(0x0201) / `CG_CHARACTER_DELETE`(0x0202) / `CG_CHANGE_NAME`(0x010B) / `GC_PLAYER_CREATE_SUCCESS`(0x020C) / `GC_PLAYER_CREATE_FAILURE`(0x020D) / `GC_PLAYER_DELETE_SUCCESS`(0x020E) / `GC_PLAYER_DELETE_WRONG_SOCIAL_ID`(0x020F) / `GC_CHANGE_NAME`(0x010C) 全部有尺寸断言;`GameClient` 发送接口、角色槽位补丁和 `drain_*_events()`;`M2Client` 同名建删改 API、4 个建删结果信号及 `char_name_changed`;`net.loopback_flow` 覆盖建删和改名名称字节 / pid 广播。**真机验证(2026-08-31,`net_e2e MT_E2E_CHARCREATE=1`)**:建号、`GC_PLAYER_CREATE_FAILURE`、`GC_EMPIRE` 已验。选人页有建号 / 删号弹窗与国家国旗 | `CG_CHARACTER_DELETE` 破坏性,真机未验;改名 UI / 改名卡消耗和重复名错误提示未接;建号缺外形 / 发型选择与属性再分配 UI(现发 `shape=0` + 职业基础四维);缺 `SELECT_EMPIRE` 选国界面;原版选人台座、镜头动画、`OnCreateFailure` 完整错误码文案 | +| P1 | 🟡 | 选人 / 建号 / 删号 / 改名 | `CG_CHARACTER_CREATE`(0x0201) / `CG_CHARACTER_DELETE`(0x0202) / `CG_CHANGE_NAME`(0x010B) / `GC_PLAYER_CREATE_SUCCESS`(0x020C) / `GC_PLAYER_CREATE_FAILURE`(0x020D) / `GC_PLAYER_DELETE_SUCCESS`(0x020E) / `GC_PLAYER_DELETE_WRONG_SOCIAL_ID`(0x020F) / `GC_CHANGE_NAME`(0x010C) 全部有尺寸断言;`GameClient` 发送接口、角色槽位补丁和 `drain_*_events()`;`M2Client` 同名建删改 API、4 个建删结果信号及 `char_name_changed`;`net.loopback_flow` 覆盖建删和改名名称字节 / pid 广播。**真机验证(2026-08-31,`net_e2e MT_E2E_CHARCREATE=1`)**:建号、`GC_PLAYER_CREATE_FAILURE`、`GC_EMPIRE` 已验。选人页有建号 / 删号弹窗、强制改名弹窗与国家国旗 | `CG_CHARACTER_DELETE` 破坏性,真机未验;强制改名、重名 / 非法名错误码和服务端状态未真服验收;建号缺外形 / 发型选择与属性再分配 UI(现发 `shape=0` + 职业基础四维);原版选人台座、镜头动画、`OnCreateFailure` 完整错误码文案 | | P0 | 🟡 | 技能施放协议 | `CG_USE_SKILL`、`CG_FLY_TARGETING`、`CG_ADD_FLY_TARGETING` 与 `CG_SHOOT` 已有尺寸断言、原生发送接口和 loopback 字节验证;服务端 `GC_FLY_TARGETING` / `GC_ADD_FLY_TARGETING` 已进入 `EntityStore`,通过 `M2Client.fly_targeting` 暴露,且已补入 `GameClient` 世界分派;`GC_CHANGE_SKILL_GROUP` 会更新 `get_skill_group()` 并使技能快照失效;快捷栏先发 `use_skill(skill_id,target_vid)`,再同步 `CG_MOVE` 技能动作;弓技能会在 `.msa` FLY 事件发送 `CG_SHOOT`。真服单会话已发送 `CG_USE_SKILL` / `CG_FLY_TARGETING` / `CG_ADD_FLY_TARGETING` / `CG_SHOOT`,均无断连 / unknown | 仍需实现范围 / 多目标选择器来自动驱动 `ADD_FLY_TARGETING`;冷却、目标合法性、真实弹道和客户端表现也须按技能类型细分;尚未在真服观察到对应 GC 飞行目标推送 | | P0 | 🟡 | 快捷栏持久化 | 已覆盖 36 槽(4 页 × 9 格)、F1–F4 切页和 1–9 激活;拖放 / 清除 / 交换会分别发送 `CG_QUICKSLOT_ADD/DEL/SWAP`,服务器 `GC_*` 可完整恢复;技能冷却读取对应 `.msk` 的 `CoolTimeFormula` | 仍需补命令 / 表情快捷槽、物品拖放来源、鼠标物品态及原 UI 的完整快捷栏交互;冷却还未叠加原客户端的施法速度与所有特殊技能规则 | | P0 | 🟡 | 物品操作 | 已有移动、使用、丢弃、拾取;Shift 选“来源→目标”发 `ITEM_USE_TO_ITEM`,Ctrl+右键向当前目标 `ITEM_GIVE`,Alt+右键以数量框发 `ITEM_DROP2`;`ITEM_OWNERSHIP` 会实时更新地面名条;`GC_VIEW_EQUIP` 已保存 11 格检查快照并弹出装备查看窗 | 仍需复刻原鼠标物品态、操作确认 / 错误提示、宝石专用规则,以及装备查看窗的原版槽位图标、3D 纸娃娃与交互 | @@ -333,14 +372,15 @@ | P0 | 🟡 | PVP / 决斗 / 阵营 | `GC_PVP` 和 `DUEL_START` 已进入状态层,并以 `pvp_changed` / `duel_started` 信号提供给 Godot;挑战 / 战斗 / 复仇关系会在世界实体上显示标签;实体已有部分 empire / alignment / pk 字段 | 仍需 PK 模式上行、原版名字颜色、可攻击判定、阵营规则和原版目标板 / 决斗 UI | | P1 | 🟡 | Actor 战斗运行时 | 有骨骼动画、基础 combo / 硬直 / 相机抖动;动作切换按 Granny `EaseInCurve(0,0,1,1)` 的 `2w²−w³` 逐骨 crossfade;角色 mesh 支持距离 LOD、15% 迟滞和约 0.18s 新旧 mesh 淡入(`LodGhost` + `lod_fade` uniform);右手武器 / 左手盾按 `weaponComposite[0] = weaponInvWorld[0]·weaponLocal[0]` grip 复合挂 `equip_right_hand`(探针实测 Δ≤0.06 m,非标准米级偏移文件夹断回退);`.msa` motion event 已分派声音、EffectPosition 特效、震屏和屏闪(FLY / WARP 留钩子);玩家 / 怪物强制实时投影并附脚底接触阴影 Decal;实体 `attack_speed` 与本地 `POINT_ATT_SPEED` 已按原版 100 基准影响攻击请求间隔 | 仍需用真实 `.msa` motion duration、武器 / 坐骑规则和服务端合法性校准攻击节奏;另补 combo 取消窗口、精确受击 / 击退、角色碰撞、同步碰撞、武器拖尾、剩余 motion event / 骨骼挂点语义、GPU skin LOD、双持 / 左手武器和目标锁定相机;`03150` 类偏移网格需 per-weapon 偏移数据或修 .gr2 | | P1 | 🟡 | 飞行物与命中特效 | `GC_FLY_TARGETING` / `GC_ADD_FLY_TARGETING` 保存 shooter 的目标队列和 VID / 坐标;`GC_CREATE_FLY` 可消费队列并生成 tween 发光球 | 对齐 `FlyingObjectManager`:真实技能弹道模型、命中时机 / 命中特效、消失条件、声音与 EffectLib 特效 | -| P1 | 🟡 | 任务 / NPC | 支持 `[ENTER]`、`[CLEAR]`、`[NEXT]`、`[DONE]`、基础 `[QUESTION]`、`[INPUT]` 文本框和任务日志;`M2Client.script_select_item()` / `quest_cancel()` 已可发送原协议应答,Escape 会走取消包;真服单会话已发送 `CG_SCRIPT_SELECT_ITEM`(8B) 与 `CG_QUEST_CANCEL`(4B),取消触发 1 条 quest-change 且无断连 / unknown | 补选道具网格、原版 CJK IME / 输入校验、QuestButton、立绘、完整 EventManager 标签、世界箭头和屏幕边缘指示;选道具包本轮未出现脚本业务回包 | +| P1 | 🟡 | 任务 / NPC | 支持 `[ENTER]`、`[CLEAR]`、`[NEXT]`、`[DONE]`、基础 `[QUESTION]`、`[INPUT]`、`[SELECT_ITEM]` 文本流程和任务日志;`SelectItemUI` 按原 `uiselectitem.RefreshSlot` 过滤魔石 / grade、映射背包格并发送 `CG_SCRIPT_SELECT_ITEM`,`quest_cancel()` 发送取消包;真服单会话已发送 `CG_SCRIPT_SELECT_ITEM`(8B) 与 `CG_QUEST_CANCEL`(4B),取消触发 1 条 quest-change 且无断连 / unknown | 补原版 CJK IME / 输入校验、QuestButton、立绘、完整 EventManager 标签、世界箭头和屏幕边缘指示;选道具业务回包与完整资源视觉仍需真服 / 资源环境验收 | | P1 | 🟡 | 商店 / 交易 / 仓库 | 普通 NPC 商店、交易状态和仓库列表已有首版;**`SHOP_GC_START_EX` 多货架已解析(`m_shop_tabs`,`get_shop()`),`shop_ui` 带货架按钮 + `tabIdx*40+slot` 买位置** | 补图标格网格、数量输入、交易回滚提示、仓库密码 / 改密码、完整拖放规则、`coin_type` 非金币货币显示 | -| P1 | 🟡 | 私人商店 / 道具商城 | **首版**:`CG_MYSHOP`(0x0802) `CGMyShopHead`(38) + `MyShopItem`(13)×N 有尺寸断言 + `GameClient::send_open_private_shop` / `send_close_private_shop`(=`SHOP_CG_END`) + loopback 字节级;`GC_MALL_OPEN`(0x0841)/`GC_MALL_SET`(0x0842)/`GC_MALL_DEL`(0x0843) 路由进 `EntityStore`(`m_mall[135]` + `mall_open/size/slot/dirty`),`CG_MALL_CHECKOUT`(0x0840) `CGMallCheckout`(8) 发送;`M2Client` `open/close_private_shop`、`get_mall_items`/`mall_checkout` + `mall_opened`/`mall_changed` 信号;`ui/private_shop_ui.gd`(**已重做成 `PrivateShopBuilder.itemStock` 模型:40 格 grid + 拿起 / 落位 / 逐件价格弹窗 / 点占用格撤下 / 개설按格号排序 + display_pos + 上限 39**)、`ui/mall_ui.gd`(列表 + 取出)。**真机验证(2026-08-31,`net_e2e MT_E2E_MYSHOP=1`)**:`CG_MYSHOP` 38B head + 13B item×1 被真服接受,无断连 / 无 shop error,`SHOP_CG_END` 关店正常。`CG_MALL_CHECKOUT` 送出不断连,但 mall 需点 NPC 才 open。他人开店 `SHOP_GC_START_EX` 多货架已解析(见增量 34)。⬜ `SYMBOL_DATA`/`GC_SHOP_SIGN` 头顶招牌 3D、真 `.sub` 版 `privateshopbuilder.py` uiscript、鼠标真拖放物品态 | +| P1 | 🟡 | 私人商店 / 道具商城 | **首版**:`CG_MYSHOP`(0x0802) `CGMyShopHead`(38) + `MyShopItem`(13)×N 有尺寸断言 + `GameClient::send_open_private_shop` / `send_close_private_shop`(=`SHOP_CG_END`) + loopback 字节级;`GC_MALL_OPEN`(0x0841)/`GC_MALL_SET`(0x0842)/`GC_MALL_DEL`(0x0843) 路由进 `EntityStore`(`m_mall[135]` + `mall_open/size/slot/dirty`),`CG_MALL_CHECKOUT`(0x0840) `CGMallCheckout`(8) 发送;`M2Client` `open/close_private_shop`、`get_mall_items`/`mall_checkout` + `mall_opened`/`mall_changed` 信号;`ui/private_shop_ui.gd`(**已重做成 `PrivateShopBuilder.itemStock` 模型:40 格 grid + 拿起 / 落位 / 逐件价格弹窗 / 点占用格撤下 / 개설按格号排序 + display_pos + 上限 39**)、`ui/mall_ui.gd`(列表 + 取出)。**真机验证(2026-08-31,`net_e2e MT_E2E_MYSHOP=1`)**:`CG_MYSHOP` 38B head + 13B item×1 被真服接受,无断连 / 无 shop error,`SHOP_CG_END` 关店正常。`CG_MALL_CHECKOUT` 送出不断连,但 mall 需点 NPC 才 open。他人开店 `SHOP_GC_START_EX` 多货架已解析(见增量 34)。`GC_SHOP_SIGN` 已在 `NetWorld` 提供 `ShopSign` Label3D fallback,`GC_SYMBOL_DATA` 已接会徽下载;仍缺真 `.sub` 版 `privateshopbuilder.py` uiscript、资源视觉和鼠标真拖放物品态 | | — | ❌ | 拍卖行 / auction house | 不做 | m2dev-client 无此系统(`0x08xx` 段只有 shop/myshop/safebox/mall,全源码 / 协议 / 资产零 `auction` 命中)。需自定义协议 + 服务端支持才能实现,**标注为不做**,除非后续明确提需求 | -| P1 | 🟡 | Cube (제작) / 能量系统 | **首版**:Cube 走 `GC_CHAT`/`CHAT_TYPE_COMMAND` 文本总线(对齐 `ServerCommand()`),`EntityStore::apply_server_command` 解析 `cube open/close/info/success/fail/r_list/m_info`(配方 `v,c` 列表 + `@`/`&`/`|`/`/` 分层材料 + 金币)→ `CubeState` + `drain_cube_events()`;`GameClient::send_cube_make/material_info/result_list`(`/cube make|mInfo|rList`);`M2Client` `get_cube`/`cube_make`/`cube_request_*` + `cube_opened`/`cube_closed`/`cube_changed`/`cube_result` 信号;`ui/cube_ui.gd`(配方列表 + 材料/金币 + 제작)。`net.entity_store` + `net.loopback_flow` 覆盖。真机(2026-08-31)`/cube rList` 送出不断连,但服务器只在玩家站到 cube NPC 前才回应 → `cube open=0`,需 NPC 交互完整验。⬜ 能量条(`POINT_ENERGY` / affect)、原 `uiCube.py` 材料格 3D 图标 / 拖放 / 결과 애니、NPC 前完整验 send 命令字 | -| P1 | 🟡 | 组队 | 邀请、接受、离队;**成员信息板(`party_ui.gd`,1:1 迁移 `uiparty.PartyMemberInfoBoard`):每员角色状态按钮(队长弹菜单 → `CG_PARTY_SET_STATE` 0x0704 分配 攻/坦/狂/辅/宗/防 或踢人)+ 名字(★队长) + HP gauge + `affects[7]` 附加效果 chip;顶部 EXP 分配开关(`party_set_distribute`)+ 组队治疗(`party_use_skill(1,0)`)**;真服单会话 `CG_PARTY_USE_SKILL`(9B) 后仍在线;小地图 / Atlas 绿色队员点 + 队长环 | 补角色菜单按党技能等级门控(Tanker≥10…Defender≥40)、`affects[7]` 精确槽位语义、真版 `.sub` 图标 / 颜色、队伍技能冷却 / 权限、离线颜色语义 | +| P1 | 🟡 | Cube (제작) / 能量系统 | **首版**:Cube 走 `GC_CHAT`/`CHAT_TYPE_COMMAND` 文本总线(对齐 `ServerCommand()`),`EntityStore::apply_server_command` 解析 `cube open/close/info/success/fail/r_list/m_info`(配方 `v,c` 列表 + `@`/`&`/`|`/`/` 分层材料 + 金币)→ `CubeState` + `drain_cube_events()`;`GameClient::send_cube_make/material_info/result_list`(`/cube make|mInfo|rList`);`M2Client` `get_cube`/`cube_make`/`cube_request_*` + `cube_opened`/`cube_closed`/`cube_changed`/`cube_result` 信号;`ui/cube_ui.gd`(配方列表 + 材料/金币 + 제작)。`net.entity_store` + `net.loopback_flow` 覆盖。真机(2026-08-31)`/cube rList` 送出不断连,但服务器只在玩家站到 cube NPC 前才回应 → `cube open=0`,需 NPC 交互完整验。`POINT_ENERGY` 已由 HUD 快照显示;仍缺原 `uiCube.py` 材料格 3D 图标 / 拖放 / 결과 애니、NPC 前完整验 send 命令字 | +| P1 | 🟡 | 组队 | 邀请、接受、离队;**成员信息板(`party_ui.gd`,1:1 迁移 `uiparty.PartyMemberInfoBoard`):每员角色状态按钮(队长弹菜单 → `CG_PARTY_SET_STATE` 0x0704 分配 攻/坦/迅捷/辅/宗/防 或踢人)+ 名字(★队长) + HP gauge + `affects[7]` 附加效果 chip;顶部 EXP 分配开关(`party_set_distribute`)+ 组队治疗(`party_use_skill(1,0)`)**;角色 / 治疗控件已按 40250 服务端 Leadership 规则本地门控(攻击≥10、坦克/迅捷≥20、辅助≥25、宗师≥35、防御≥40,治疗≥18);真服单会话 `CG_PARTY_USE_SKILL`(9B) 后仍在线;小地图 / Atlas 绿色队员点 + 队长环 | 仍需真版 `.sub` 图标 / 颜色、队伍技能冷却 / 权限、离线颜色语义和真实两账号组队验收 | | P1 | 🟡 | 好友 / 情侣 | 好友列表、上线状态和私聊入口已有;`GC_LOVER_INFO`(70B) / `GC_LOVE_POINT_UPDATE`(5B) 已有尺寸断言、`EntityStore::LoverInfo` 状态、`M2Client.get_lover()` / `lover_changed`,`love_ui` 常驻显示伴侣名和 0–100 爱意值;`net.entity_store` 与 `love_ui_test.gd` 覆盖 | 补好友分组和完整 messenger 行为;情侣仍需完整交互 / 状态图标与 affect 表现、断线 / 切图生命周期、原版文案和真服务器端到端验收 | -| P1 | 🟡 | 公会 | 信息、成员、技能、公会战、会徽上 / 下载和部分操作已有首版;`GC_REQUEST_MAKE_GUILD`(0x0731) 已解析并以 `M2Client.guild_make_requested` 通知;`CG_SYMBOL_CRC` / `GC_SYMBOL_DATA` 已支持原始符号文件下载 | 补完整权限 / 等级页、公告与日志、成员管理、创建公会 UI / 应答流程、公会战应答、积分板、领地和公会建筑 | +| P1 | 🟡 | 公会(暂缓) | 信息、成员、技能、公会战、会徽上 / 下载和部分操作已有首版;`GC_REQUEST_MAKE_GUILD`(0x0731) 已解析并以 `M2Client.guild_make_requested` 通知;公会窗已弹出创建名称输入并发送 `CG_ANSWER_MAKE_GUILD`;`CG_SYMBOL_CRC` / `GC_SYMBOL_DATA` 已支持原始符号文件下载 | 本阶段暂缓完整权限 / 等级页、公告与日志、成员管理、公会战应答、积分板、领地和公会建筑;恢复公会范围后再做完整真服验收 | +| — | ❌ | 龙魂精炼 | 当前目标 40250 服务端不提供该玩法;本阶段不纳入支持或验收,已有兼容代码仅保留作协议参考 | 若未来服务端增加该玩法,再另立协议、UI 和验收需求 | | P1 | 🟡 | 世界玩法 | 有 `CG_WARP` 主动请求、`GC_WARP` 同服 / 跨服处理、`CG_FISHING` / `GC_FISHING` 钓鱼方向与状态事件、`NetWorld` / `NetPlay` 钓鱼动作分发、`ChatUI` 鱼获 / 失败日志、`CG_DUNGEON` / `GC_DUNGEON` 副本请求与状态事件、`GC_DIG_MOTION` 挖矿动作广播、`GC_LAND_LIST` 领地状态、`GC_OBSERVER_ADD/REMOVE/MOVE` 观战者状态、频道、时间、NPC marker、天气粒子和 mount_vnum 字段;真服登录洪流已收到并解析 `GC_LAND_LIST`(436B),单会话发送 `CG_FISHING`(5B) 后收到“Please choose a Fishing Pole.”业务拒绝且连接保持;同服 `GC_WARP` 直接挪玩家,跨服 `addr≠0` 由 `M2Client` 复用 login key 直连目标 game server,断点重连也走该快路径 | 补完整钓鱼 UI / 鱼获背包落地、副本计时 / 入口 UI、坐骑真模型 / 骑乘动作 / 移速、地形贴花、DungeonBlock 和地图天气配置;`CG_DUNGEON` / `CG_WARP` 本轮为避免副作用未发送,跨服换图仍需真服端到端验收与场景生命周期清理 | | P1 | 🟡 | 小地图 / Atlas | 可画玩家、实体、NPC、任务标记、观战者紫色菱形和 `GC_LAND_LIST` 领地边框;支持 `set_scale()` / 鼠标滚轮缩放;Atlas 支持底图、地图名称、玩家坐标、拖动和坐标查询 | 补原 minimap / Atlas 贴图细节、提示、队员 / NPC 分类、世界箭头、地图驱动天气配置和原版窗口视觉 | | P1 | 🟡 | EffectLib | `.mse` Particle 已映射到 `GPUParticles3D` | 粒子 `.dds` 目前被程序化径向渐变替代,`.mde` 用 box 占位;需补 EffectMesh、SimpleLight、TexAni、MovingType、骨骼挂点和完整时间轴 | @@ -384,7 +424,7 @@ 故当前总数从 24 降为 22 个 header;增量 7 再补任务选择 / 取消上行,增量 8 补队伍技能上行, 增量 9 补飞行目标广播,增量 10 补技能组切换,增量 11 补角色改名,增量 12 补公会创建请求, 增量 13 补主动传送,增量 14 补挖矿动作,增量 15 补会徽符号下载,增量 16 补钓鱼协议, -增量 17 补副本协议,增量 18 补领地与观战者,当前为 **1 个 header**。 +增量 17 补副本协议,增量 18 补领地与观战者,增量 39 补 `CG_TEXT`,当前为 **0 个 header**。 排除仅命名不同、功能已覆盖的别名(`GC_CHAR_ADDITIONAL_INFO`=`GC_CHAR_ADD_INFO`、 `GC_TARGET`=`GC_TARGET_INFO`、`GC_TARGET_CREATE_NEW`=`GC_TARGET_CREATE`、 @@ -392,13 +432,13 @@ `GC_SEPCIAL_EFFECT`=`GC_SPECIAL_EFFECT`、`GC_REFINE_INFORMATION_NEW`=`GC_REFINE_INFO_NEW`), 以及 `CG_STATE_CHECKER` / `GC_RESPOND_CHANNELSTATUS`(`project/net/channel_status.gd` 单独实现) 和 `CG_HACK`(反作弊,见「不做清单」), -**当前主网络层仍缺 1 个 header**(脚本核对 `wire.h` vs `Packet.h`): +**当前主网络层仍缺 0 个 header**(脚本核对 `wire.h` vs `Packet.h`): ### 账号 / 命令通道 | header | 值 | 说明 | |---|---|---| -| `CG_TEXT` | 0x0011 | 简易命令通道(Cube 现借 `CG_CHAT`/`CHAT_TYPE_COMMAND` 实现,非原路径) | +| `CG_TEXT` | 0x0011 | 已补 classic wire 尺寸表;这是握手阶段的管理命令,固定前缀为 1 字节,后续文本直到换行由服务端特殊解析。Cube 仍借 `CG_CHAT`/`CHAT_TYPE_COMMAND` 实现,不伪造管理命令入口 | ### 已声明但待核(不计入上面 1 个) @@ -407,8 +447,9 @@ 自动触发语义、姿态动作链和服务端位置纠偏回包验收。 - `CG_SCRIPT_SELECT_ITEM`(0x0903) / `CG_QUEST_CANCEL`(0x0906):wire、发送接口和 loopback 字节测试已覆盖;真服单会话已分别发送 8B / 4B,取消触发 1 条 quest-change 且无 - unknown;基础 `[INPUT]` / Escape 取消已接入,仍缺选道具网格、原版输入校验和有脚本时的任务 - 流程验收。 + unknown;基础 `[INPUT]` / `[SELECT_ITEM]` / Escape 取消已接入,选择窗的背包魔石网格、 + grade 过滤和选择回包已由 `select_item_ui_test.gd` 覆盖;仍缺原版输入校验、CJK IME 和有脚本时 + 的真实任务流程验收。 - `CG_PARTY_USE_SKILL`(0x0705):wire、发送接口和 loopback 字节测试已覆盖;真服单会话已发送 9B 且保持在线 / 无 unknown,但无队伍技能业务回包;仍缺冷却 / 权限、UI 入口和有效队伍真服 验收。 @@ -420,10 +461,11 @@ `M2Client.skill_group_changed` 已覆盖;本轮发现并修复 `GameClient` 未分派该 header 的 bug; 仍缺技能组选择 UI、服务端权限和真服推送验收。 - `CG_CHANGE_NAME`(0x010B) / `GC_CHANGE_NAME`(0x010C):wire、角色槽位更新、 - `M2Client.change_name()` 和 `char_name_changed` 已覆盖;仍缺改名 UI、改名卡消耗 / 重名错误 - 文案和真服验收。 -- `GC_REQUEST_MAKE_GUILD`(0x0731):无负载 wire 解析和 `guild_make_requested` 信号已覆盖;仍缺 - 创建公会窗口、名称校验 / 应答和真服验收。 + `M2Client.change_name()` 和 `char_name_changed` 已覆盖;选人页按 `change_name` 标志接入 + 原版“点击开始先改名”流程,并对重名 / 非法名错误码给出状态文案;仍缺真服验收。 +- `GC_REQUEST_MAKE_GUILD`(0x0731):无负载 wire 解析和 `guild_make_requested` 信号已覆盖;公会窗已 + 完成创建窗口、12 字上限、空名 / 控制字符校验和 `CG_ANSWER_MAKE_GUILD` 应答;仍缺服务端敏感词 / + 重名错误回包、实际建会状态和真服验收。 - `CG_SYMBOL_CRC`(0x0723) / `GC_SYMBOL_DATA`(0x0732):16B / 8B wire、`MarkClient` CRC 请求、 变长数据接收和 `M2Client.guild_symbol_ready` 已覆盖;仍缺本地符号缓存失效策略、UI 预览和 真服验收。 @@ -464,7 +506,7 @@ 1. 任务完整标签 / 输入 / 选道具 / 指引; 2. 商店 START_EX、仓库密码、商城、私人商店、Cube(拍卖行 m2dev-client 无,除非另起协议); -3. 组队角色、公会完整页面、情侣完整交互、领地与公会建筑; +3. 组队角色、情侣完整交互、领地与公会建筑;公会完整页面暂缓; 4. 钓鱼、副本、坐骑、观战者和 Atlas。 ### M3:UI 与表现 1:1 @@ -483,7 +525,7 @@ ## 1:1 完成判据 -一个功能只有同时满足以下条件才标记为完成: +一个功能只有同时满足以下条件才标记为完成。当前 40250 阶段对已明确暂缓的真服、公会和龙魂项不作完成承诺: 1. 原客户端涉及的 CG / GC 包和 sub-header 全部覆盖,并有尺寸断言; 2. 数据状态能正确恢复、重连、切图和清理; diff --git a/export-android.sh b/export-android.sh index d510c4c4..bb0b34da 100755 --- a/export-android.sh +++ b/export-android.sh @@ -25,10 +25,15 @@ GODOT="${GODOT:-godot}" ADB="${ADB:-$SDK/platform-tools/adb}" case "$CONFIG" in - Release) MODE="--export-release" ;; - *) MODE="--export-debug" ;; + Release) + MODE="--export-release" + OUT="build/export/mtgodot-poc-release.apk" + ;; + *) + MODE="--export-debug" + OUT="build/export/mtgodot-poc.apk" + ;; esac -OUT="build/export/mtgodot-poc$([ "$CONFIG" = Release ] && echo -release).apk" echo ">> NDK: $ANDROID_NDK_ROOT" echo ">> JDK: $JAVA_HOME" @@ -58,9 +63,17 @@ if [ "$INSTALL" = 1 ]; then echo ">> pushing assets.zip ($(du -h build/export/assets.zip | cut -f1)) -> $DEST" "$ADB" shell mkdir -p /sdcard/Android/data/org.internal.mtgodotpoc/files/ || true "$ADB" push build/export/assets.zip "$DEST" + if [ "$CONFIG" != "Release" ]; then + echo ">> copying assets.zip into the Debug app user:// directory" + # Android 14/15 may deny run-as reading /sdcard even for the app's own + # external files directory. Stream through adb instead. + "$ADB" shell "run-as org.internal.mtgodotpoc sh -c 'cat > files/assets.zip'" \ + < build/export/assets.zip + fi else echo ">> NOTE: no build/export/assets.zip — run ./pack-assets.sh; the world won't render without it" fi - "$ADB" shell am start -n org.internal.mtgodotpoc/com.godot.game.GodotApp + "$ADB" shell am start -W -n org.internal.mtgodotpoc/com.godot.game.GodotAppLauncher \ + -a android.intent.action.MAIN -c android.intent.category.LAUNCHER echo ">> logcat: $ADB logcat -s godot GodotError Godot" fi diff --git a/extension/CMakeLists.txt b/extension/CMakeLists.txt index 6cb36b12..f5def3d8 100644 --- a/extension/CMakeLists.txt +++ b/extension/CMakeLists.txt @@ -20,9 +20,13 @@ add_library(mtnet STATIC src/net/net_stream.cpp src/net/entity_store.cpp src/net/mark_image.cpp + src/net/classic/classic_stream.cpp # MT_PROTOCOL=classic (40250) + src/net/classic/classic_parser.cpp + src/net/classic/classic_session.cpp + src/net/classic/classic_cipher.cpp ) target_include_directories(mtnet PUBLIC src/net) -target_link_libraries(mtnet PUBLIC mt3p::sodium mt3p::minilzo) +target_link_libraries(mtnet PUBLIC mt3p::sodium mt3p::minilzo mt3p::cryptopp) target_compile_features(mtnet PUBLIC cxx_std_20) # --- mtpack: m2dev-fork asset pack reader/writer (libsodium + zstd) --- @@ -60,32 +64,62 @@ if(MT_HOST_BUILD) # real server; dumps entities / points / inventory. Live integration check. add_executable(net_e2e tools/net_e2e.cpp) target_link_libraries(net_e2e PRIVATE mtnet) + + # net_classic_e2e: live 40250 classic handshake -> login -> char select -> PHASE_GAME probe. + add_executable(net_classic_e2e tools/net_classic_e2e.cpp) + target_link_libraries(net_classic_e2e PRIVATE mtnet) endif() if(BUILD_TESTING AND MT_HOST_BUILD) add_executable(net_cipher_test tests/net_cipher_test.cpp) target_link_libraries(net_cipher_test PRIVATE mtnet) - add_test(NAME net.cipher_roundtrip COMMAND net_cipher_test) + add_test(NAME net.cipher_roundtrip COMMAND $) add_executable(net_loopback_test tests/net_loopback_test.cpp) target_link_libraries(net_loopback_test PRIVATE mtnet) - add_test(NAME net.loopback_flow COMMAND net_loopback_test) + add_test(NAME net.loopback_flow COMMAND $) add_executable(net_entity_test tests/net_entity_test.cpp) target_link_libraries(net_entity_test PRIVATE mtnet) - add_test(NAME net.entity_store COMMAND net_entity_test) + add_test(NAME net.entity_store COMMAND $) + + # 40250 "classic" backend (MT_PROTOCOL=classic). + add_executable(net_classic_wire_test tests/net_classic_wire_test.cpp) + target_include_directories(net_classic_wire_test PRIVATE src/net) + target_compile_features(net_classic_wire_test PRIVATE cxx_std_20) + add_test(NAME net.classic_wire COMMAND $) + + add_executable(net_classic_stream_test tests/net_classic_stream_test.cpp) + target_link_libraries(net_classic_stream_test PRIVATE mtnet) + add_test(NAME net.classic_stream COMMAND $) + + add_executable(net_classic_session_test tests/net_classic_session_test.cpp) + target_link_libraries(net_classic_session_test PRIVATE mtnet) + add_test(NAME net.classic_session COMMAND $) + + add_executable(net_classic_cipher_test tests/net_classic_cipher_test.cpp) + target_link_libraries(net_classic_cipher_test PRIVATE mtnet) + add_test(NAME net.classic_cipher COMMAND $) + + add_executable(net_classic_encstream_test tests/net_classic_encstream_test.cpp) + target_link_libraries(net_classic_encstream_test PRIVATE mtnet) + add_test(NAME net.classic_encstream COMMAND $) + + add_executable(net_classic_mark_test tests/net_classic_mark_test.cpp) + target_link_libraries(net_classic_mark_test PRIVATE mtnet) + add_test(NAME net.classic_mark COMMAND $) add_executable(net_mark_test tests/net_mark_test.cpp) target_link_libraries(net_mark_test PRIVATE mtnet mt3p::minilzo) - add_test(NAME net.guild_mark COMMAND net_mark_test) + add_test(NAME net.guild_mark COMMAND $) add_executable(pack_roundtrip_test tests/pack_roundtrip_test.cpp) target_link_libraries(pack_roundtrip_test PRIVATE mtpack) - add_test(NAME pack.roundtrip COMMAND pack_roundtrip_test) + add_test(NAME pack.roundtrip COMMAND $) add_executable(proto_test tests/proto_test.cpp) target_link_libraries(proto_test PRIVATE mtproto) - add_test(NAME proto.item_mob COMMAND proto_test) + add_test(NAME proto.item_mob COMMAND $) if(DEFINED ENV{M2_ASSETS}) set_tests_properties(proto.item_mob PROPERTIES ENVIRONMENT "M2_ASSETS=$ENV{M2_ASSETS}") endif() diff --git a/extension/src/net/classic/classic_cipher.cpp b/extension/src/net/classic/classic_cipher.cpp new file mode 100644 index 00000000..6d4b2eff --- /dev/null +++ b/extension/src/net/classic/classic_cipher.cpp @@ -0,0 +1,323 @@ +// Ported from ClientVS22/source/EterBase/cipher.cpp (Crypto++ 8.4.0). +#include "classic_cipher.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace CryptoPP; + +namespace mtnet::classic { + +namespace { + +// Block cipher algorithm selector abstract base class. +struct BlockCipherAlgorithm { + enum { + kDefault, // to give more chances to default algorithm + kRC6, + kMARS, + kTwofish, + kSerpent, + kCAST256, + kIDEA, + k3DES, // DES-EDE2 + kCamellia, + kSEED, + kRC5, + kBlowfish, + kTEA, + kSHACAL2, + kMaxAlgorithms + }; + + BlockCipherAlgorithm() = default; + virtual ~BlockCipherAlgorithm() = default; + + static BlockCipherAlgorithm *Pick(int hint); + + virtual int GetBlockSize() const = 0; + virtual int GetDefaultKeyLength() const = 0; + + virtual SymmetricCipher *CreateEncoder(const CryptoPP::byte *key, size_t keylen, + const CryptoPP::byte *iv) const = 0; + virtual SymmetricCipher *CreateDecoder(const CryptoPP::byte *key, size_t keylen, + const CryptoPP::byte *iv) const = 0; +}; + +template +struct BlockCipherDetail : public BlockCipherAlgorithm { + int GetBlockSize() const override { return T::BLOCKSIZE; } + int GetDefaultKeyLength() const override { return T::DEFAULT_KEYLENGTH; } + + SymmetricCipher *CreateEncoder(const CryptoPP::byte *key, size_t keylen, + const CryptoPP::byte *iv) const override { + return new typename CTR_Mode::Encryption(key, keylen, iv); + } + SymmetricCipher *CreateDecoder(const CryptoPP::byte *key, size_t keylen, + const CryptoPP::byte *iv) const override { + return new typename CTR_Mode::Decryption(key, keylen, iv); + } +}; + +BlockCipherAlgorithm *BlockCipherAlgorithm::Pick(int hint) { + BlockCipherAlgorithm *detail; + int selector = hint % kMaxAlgorithms; + switch (selector) { + case kRC6: detail = new BlockCipherDetail(); break; + case kMARS: detail = new BlockCipherDetail(); break; + case kTwofish: detail = new BlockCipherDetail(); break; + case kSerpent: detail = new BlockCipherDetail(); break; + case kCAST256: detail = new BlockCipherDetail(); break; + case kIDEA: detail = new BlockCipherDetail(); break; + case k3DES: detail = new BlockCipherDetail(); break; + case kCamellia: detail = new BlockCipherDetail(); break; + case kSEED: detail = new BlockCipherDetail(); break; + case kRC5: detail = new BlockCipherDetail(); break; + case kBlowfish: detail = new BlockCipherDetail(); break; + case kTEA: detail = new BlockCipherDetail(); break; + case kSHACAL2: detail = new BlockCipherDetail(); break; + case kDefault: + default: detail = new BlockCipherDetail(); break; // default algorithm + } + return detail; +} + +} // namespace + +// Key agreement scheme abstract class. +class KeyAgreement { +public: + KeyAgreement() = default; + virtual ~KeyAgreement() = default; + + virtual size_t Prepare(void *buffer, size_t *length) = 0; + virtual bool Agree(size_t agreed_length, const void *buffer, size_t length) = 0; + + const SecByteBlock &shared() const { return shared_; } + +protected: + SecByteBlock shared_; +}; + +namespace { + +// Crypto++ Unified Diffie-Hellman key agreement scheme. +class DH2KeyAgreement : public KeyAgreement { +public: + DH2KeyAgreement() : dh_(), dh2_(dh_) {} + + size_t Prepare(void *buffer, size_t *length) override; + bool Agree(size_t agreed_length, const void *buffer, size_t length) override; + +private: + DH dh_; + DH2 dh2_; + SecByteBlock spriv_key_; + SecByteBlock epriv_key_; +}; + +size_t DH2KeyAgreement::Prepare(void *buffer, size_t *length) { + // RFC 5114, 1024-bit MODP Group with 160-bit Prime Order Subgroup. + Integer p("0xB10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6" + "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" + "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70" + "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" + "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708" + "DF1FB2BC2E4A4371"); + Integer g("0xA4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F" + "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" + "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1" + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24" + "855E6EEB22B3B2E5"); + Integer q("0xF518AA8781A8DF278ABA4E7D64B7CB9D49462353"); + + AutoSeededRandomPool rnd; + + dh_.AccessGroupParameters().Initialize(p, q, g); + if (!dh_.GetGroupParameters().ValidateGroup(rnd, 3)) { + return 0; + } + + p = dh_.GetGroupParameters().GetModulus(); + q = dh_.GetGroupParameters().GetSubgroupOrder(); + g = dh_.GetGroupParameters().GetGenerator(); + + Integer v = ModularExponentiation(g, q, p); + if (v != Integer::One()) { + return 0; + } + + spriv_key_.New(dh2_.StaticPrivateKeyLength()); + epriv_key_.New(dh2_.EphemeralPrivateKeyLength()); + SecByteBlock spub_key(dh2_.StaticPublicKeyLength()); + SecByteBlock epub_key(dh2_.EphemeralPublicKeyLength()); + + dh2_.GenerateStaticKeyPair(rnd, spriv_key_, spub_key); + dh2_.GenerateEphemeralKeyPair(rnd, epriv_key_, epub_key); + + const size_t spub_key_length = spub_key.size(); + const size_t epub_key_length = epub_key.size(); + const size_t data_length = spub_key_length + epub_key_length; + if (*length < data_length) { + return 0; + } + + *length = data_length; + CryptoPP::byte *buf = (CryptoPP::byte *)buffer; + std::memcpy(buf, spub_key.BytePtr(), spub_key_length); + std::memcpy(buf + spub_key_length, epub_key.BytePtr(), epub_key_length); + + return dh2_.AgreedValueLength(); +} + +bool DH2KeyAgreement::Agree(size_t agreed_length, const void *buffer, size_t length) { + if (agreed_length != dh2_.AgreedValueLength()) { + return false; + } + const size_t spub_key_length = dh2_.StaticPublicKeyLength(); + const size_t epub_key_length = dh2_.EphemeralPublicKeyLength(); + if (length != (spub_key_length + epub_key_length)) { + return false; + } + shared_.New(dh2_.AgreedValueLength()); + const CryptoPP::byte *buf = (const CryptoPP::byte *)buffer; + if (!dh2_.Agree(shared_, spriv_key_, epriv_key_, buf, buf + spub_key_length)) { + return false; + } + return true; +} + +} // namespace + +// --------------------------------------------------------------------- ClassicCipher + +ClassicCipher::ClassicCipher() = default; + +ClassicCipher::~ClassicCipher() { + clean_up(); +} + +void ClassicCipher::clean_up() { + delete encoder_; + encoder_ = nullptr; + delete decoder_; + decoder_ = nullptr; + delete key_agreement_; + key_agreement_ = nullptr; + activated_ = false; +} + +void ClassicCipher::encrypt(void *buffer, size_t length) { + if (!activated_ || !encoder_) { + return; + } + encoder_->ProcessData((CryptoPP::byte *)buffer, (const CryptoPP::byte *)buffer, length); +} + +void ClassicCipher::decrypt(void *buffer, size_t length) { + if (!activated_ || !decoder_) { + return; + } + decoder_->ProcessData((CryptoPP::byte *)buffer, (const CryptoPP::byte *)buffer, length); +} + +size_t ClassicCipher::prepare(void *buffer, size_t *length) { + assert(key_agreement_ == nullptr); + key_agreement_ = new DH2KeyAgreement(); + size_t agreed_length = key_agreement_->Prepare(buffer, length); + if (agreed_length == 0) { + delete key_agreement_; + key_agreement_ = nullptr; + } + return agreed_length; +} + +bool ClassicCipher::activate(bool polarity, size_t agreed_length, const void *buffer, + size_t length) { + assert(!activated_); + if (!key_agreement_) { + return false; + } + bool result = false; + if (key_agreement_->Agree(agreed_length, buffer, length)) { + result = set_up(polarity); + } + // NOTE: unlike the upstream Cipher, we keep key_agreement_ alive until here + // only; set_up() reads shared() before we free it below. + delete key_agreement_; + key_agreement_ = nullptr; + return result; +} + +bool ClassicCipher::set_up(bool polarity) { + const SecByteBlock &shared = key_agreement_->shared(); + if (shared.size() < 2) { + return false; + } + + int hint_0 = shared.BytePtr()[*(shared.BytePtr()) % shared.size()]; + int hint_1 = shared.BytePtr()[*(shared.BytePtr() + 1) % shared.size()]; + std::unique_ptr algorithm_0(BlockCipherAlgorithm::Pick(hint_0)); + std::unique_ptr algorithm_1(BlockCipherAlgorithm::Pick(hint_1)); + + const size_t key_length_0 = algorithm_0->GetDefaultKeyLength(); + const size_t iv_length_0 = algorithm_0->GetBlockSize(); + if (shared.size() < key_length_0 || shared.size() < iv_length_0) { + return false; + } + const size_t key_length_1 = algorithm_1->GetDefaultKeyLength(); + const size_t iv_length_1 = algorithm_1->GetBlockSize(); + if (shared.size() < key_length_1 || shared.size() < iv_length_1) { + return false; + } + + SecByteBlock key_0(key_length_0), iv_0(iv_length_0); + SecByteBlock key_1(key_length_1), iv_1(iv_length_1); + + size_t offset; + key_0.Assign(shared, key_length_0); + offset = std::min(key_length_0, shared.size() - key_length_1); + key_1.Assign(shared.BytePtr() + offset, key_length_1); + + offset = shared.size() - iv_length_0; + iv_0.Assign(shared.BytePtr() + offset, iv_length_0); + offset = (offset < iv_length_1 ? 0 : offset - iv_length_1); + iv_1.Assign(shared.BytePtr() + offset, iv_length_1); + + if (polarity) { + encoder_ = algorithm_1->CreateEncoder(key_1, key_1.size(), iv_1); + decoder_ = algorithm_0->CreateDecoder(key_0, key_0.size(), iv_0); + } else { + encoder_ = algorithm_0->CreateEncoder(key_0, key_0.size(), iv_0); + decoder_ = algorithm_1->CreateDecoder(key_1, key_1.size(), iv_1); + } + return encoder_ != nullptr && decoder_ != nullptr; +} + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_cipher.h b/extension/src/net/classic/classic_cipher.h new file mode 100644 index 00000000..2bc81900 --- /dev/null +++ b/extension/src/net/classic/classic_cipher.h @@ -0,0 +1,52 @@ +#pragma once +// ClassicCipher — 40250 _IMPROVED_PACKET_ENCRYPTION_ (docs/CLIENT-40250-PORT.md §3). +// Ported near-verbatim from ClientVS22/source/EterBase/cipher.{h,cpp} +// (Themida / stdafx / logging stripped). Needs Crypto++ 8.4.0 (mt3p::cryptopp). +// +// Prepare(buf,&len) -> generate this end's DH2 public blob (spub||epub), +// returns the agreed-value length (0 = failure). +// Activate(polarity, agreed_len, peer_blob, peer_len) +// -> DH2 Agree() -> derive 2 hint-selected block ciphers in +// CTR mode, wire encoder_/decoder_ per polarity. +// **client polarity = true**, server = false. +// Encrypt/Decrypt(buf,len) in place, no padding (CTR stream). +// activated() flips true only after set_activated(true) (on GC_KEY_AGREEMENT_COMPLETED). + +#include +#include + +namespace CryptoPP { +class SymmetricCipher; +} + +namespace mtnet::classic { + +class KeyAgreement; + +class ClassicCipher { +public: + ClassicCipher(); + ~ClassicCipher(); + + void clean_up(); + + size_t prepare(void *buffer, size_t *length); + bool activate(bool polarity, size_t agreed_length, const void *buffer, size_t length); + + void encrypt(void *buffer, size_t length); + void decrypt(void *buffer, size_t length); + + bool activated() const { return activated_; } + void set_activated(bool value) { activated_ = value; } + bool key_ready() const { return encoder_ != nullptr && decoder_ != nullptr; } + +private: + bool set_up(bool polarity); + + bool activated_ = false; + CryptoPP::SymmetricCipher *encoder_ = nullptr; + CryptoPP::SymmetricCipher *decoder_ = nullptr; + KeyAgreement *key_agreement_ = nullptr; +}; + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_mark_client.h b/extension/src/net/classic/classic_mark_client.h new file mode 100644 index 00000000..31b4a26a --- /dev/null +++ b/extension/src/net/classic/classic_mark_client.h @@ -0,0 +1,297 @@ +#pragma once +// ClassicMarkClient — the 40250 guild-mark side connection. +// +// The side socket shares the classic handshake framing with the game socket. +// The stock mark client sends CG_MARK_LOGIN immediately after the first +// GC_HANDSHAKE; depending on the server build, the mark side can then stay +// plaintext or continue through the optional DH2/CTR exchange. Its mark +// protocol has its own frames: +// CG_MARK_* are raw fixed packets (one-byte header), +// GC_MARK_IDXLIST/GC_MARK_BLOCK are [header][u32 whole-size] packets, and +// GC_SYMBOL_DATA is a normal [header][u16 whole-size] dynamic packet. +// +// Keeping this separate from MarkClient is intentional: MarkClient implements +// the m2dev fork's four-byte frame protocol and those bytes are not accepted by +// a stock 40250 mark server. + +#include "classic_stream.h" +#include "mark_image.h" + +#include +#include +#include +#include +#include +#include + +namespace mtnet::classic { + +class ClassicMarkClient { +public: + enum class Mode { Download, DownloadSymbol, UploadMark, UploadSymbol }; + + ClassicMarkClient(uint32_t handle, uint32_t random_key) : m_handle(handle), m_random_key(random_key) { + // GuildMarkDownloader does not use the normal game-side time-sync + // response; every handshake is answered by its mark login packet. + m_stream.set_time_sync_mode(false); + m_stream.on_server_handshake = [this]() { on_server_handshake(); }; + m_stream.on_cipher_active = [this]() { on_cipher_active(); }; + m_stream.on_phase = [this](uint8_t phase) { on_phase(phase); }; + m_stream.on_packet = [this](uint8_t header, const uint8_t *body, uint32_t len) { + return on_packet(header, body, len); + }; + m_stream.on_raw_packet = [this](uint8_t header, const uint8_t *packet, size_t available) { + return on_raw_packet(header, packet, available); + }; + } + + bool connect(const std::string &host, uint16_t port) { + if (!m_valid) { + return false; + } + return m_stream.connect(host, port); + } + void disconnect() { m_stream.disconnect(); } + void process() { m_stream.process(); } + + ClassicStream::State state() const { return m_stream.state(); } + const std::string &last_error() const { return m_stream.last_error(); } + void set_wire_trace(bool on) { m_stream.set_wire_trace(on); } + + void set_upload_mark(uint32_t guild_id, + const uint32_t px[GUILD_MARK_WIDTH * GUILD_MARK_HEIGHT]) { + m_mode = Mode::UploadMark; + m_up_gid = guild_id; + std::memcpy(m_up_mark, px, sizeof(m_up_mark)); + } + + void set_upload_symbol(uint32_t guild_id, std::vector bytes) { + m_mode = Mode::UploadSymbol; + m_up_gid = guild_id; + m_up_symbol = std::move(bytes); + m_valid = m_up_symbol.size() + sizeof(CGGuildSymbolUpload) <= 0xFFFFu; + } + + void set_download_symbol(uint32_t guild_id, uint32_t crc = 0, uint32_t size = 0) { + m_mode = Mode::DownloadSymbol; + m_symbol_gid = guild_id; + m_symbol_crc = crc; + m_symbol_size = size; + } + + Mode mode() const { return m_mode; } + bool complete() const { return m_complete; } + bool upload_sent() const { return m_upload_sent; } + bool upload_done() const { return m_upload_sent && m_stream.outgoing_pending() == 0; } + const MarkImageSet &marks() const { return m_marks; } + uint32_t symbol_guild_id() const { return m_symbol_gid; } + const std::vector &symbol_data() const { return m_symbol_data; } + + // Socket-free access is useful for protocol tests and alternative transports. + ClassicStream &stream() { return m_stream; } + MarkImageSet &marks() { return m_marks; } + +private: + static constexpr uint32_t kMaxPacket = 8u * 1024 * 1024; + + static uint16_t read_u16(const uint8_t *p) { + return static_cast(p[0] | (static_cast(p[1]) << 8)); + } + static uint32_t read_u32(const uint8_t *p) { + return static_cast(p[0]) | + (static_cast(p[1]) << 8) | + (static_cast(p[2]) << 16) | + (static_cast(p[3]) << 24); + } + static ClassicStream::RawPacketResult raw(ClassicStream::RawPacketStatus status, + size_t bytes = 0) { + return {status, bytes}; + } + + void on_server_handshake() { + CGMarkLogin p{}; + p.header = HDR_CG_MARK_LOGIN; + p.handle = m_handle; + p.random_key = m_random_key; + m_login_sent = m_stream.send_fixed(&p, sizeof(p)); + } + + void on_cipher_active() { + // The stock 40250 mark client logs in immediately after the first + // GC_HANDSHAKE (while still in PHASE_HANDSHAKE). Do not send a second + // login after key agreement: the server has already switched to its + // login input processor and would reject the duplicate header. + if (!m_login_sent) { + on_server_handshake(); + } + } + + void on_phase(uint8_t phase) { + if (phase == PHASE_CLOSE) { + m_complete = true; + return; + } + if (phase != PHASE_LOGIN) { + return; + } + + if (m_mode == Mode::UploadMark) { + m_upload_sent = send_upload_mark(); + m_complete = m_upload_sent; + return; + } + if (m_mode == Mode::UploadSymbol) { + m_upload_sent = send_upload_symbol(); + m_complete = m_upload_sent; + return; + } + if (m_mode == Mode::DownloadSymbol) { + CGSymbolCRC p{}; + p.header = HDR_CG_SYMBOL_CRC; + p.guild_id = m_symbol_gid; + p.crc = m_symbol_crc; + p.size = m_symbol_size; + m_symbol_crc_sent = m_stream.send_fixed(&p, sizeof(p)); + return; + } + if (!m_idx_requested) { + CGMarkIDXList p{HDR_CG_MARK_IDXLIST}; + m_idx_requested = m_stream.send_fixed(&p, sizeof(p)); + } + } + + ClassicStream::RawPacketResult on_raw_packet(uint8_t header, const uint8_t *packet, + size_t available) { + if (header == HDR_GC_MARK_IDXLIST) { + return receive_idxlist(packet, available); + } + if (header == HDR_GC_MARK_BLOCK) { + return receive_block(packet, available); + } + return raw(ClassicStream::RawPacketStatus::NotHandled); + } + + bool on_packet(uint8_t header, const uint8_t *body, uint32_t len) { + // ClassicStream has already consumed [header][u16 size] here. The + // remaining body starts with guild_id and then the raw symbol bytes. + if (header == HDR_GC_SYMBOL_DATA && m_mode == Mode::DownloadSymbol) { + if (len < sizeof(uint32_t)) { + return false; + } + m_symbol_gid = read_u32(body); + m_symbol_data.assign(body + sizeof(uint32_t), body + len); + m_complete = true; + } + return true; + } + + ClassicStream::RawPacketResult receive_idxlist(const uint8_t *packet, size_t available) { + if (available < sizeof(GCMarkIDXList)) { + return raw(ClassicStream::RawPacketStatus::NeedMore); + } + const uint32_t total = read_u32(packet + 1); + const uint16_t count = read_u16(packet + 5); + const size_t expected = sizeof(GCMarkIDXList) + static_cast(count) * 4; + if (total < expected || total > kMaxPacket) { + return raw(ClassicStream::RawPacketStatus::Error); + } + if (available < total) { + return raw(ClassicStream::RawPacketStatus::NeedMore); + } + + m_marks.clear(); + const size_t done = parse_mark_idxlist(packet + sizeof(GCMarkIDXList), + total - sizeof(GCMarkIDXList), count, m_marks); + if (done != count) { + return raw(ClassicStream::RawPacketStatus::Error); + } + m_needed = m_marks.needed_images(); + m_next = 0; + if (m_needed.empty()) { + m_complete = true; + } else { + send_crclist(m_needed[0]); + } + return raw(ClassicStream::RawPacketStatus::Consumed, total); + } + + ClassicStream::RawPacketResult receive_block(const uint8_t *packet, size_t available) { + if (available < sizeof(GCMarkBlock)) { + return raw(ClassicStream::RawPacketStatus::NeedMore); + } + const uint32_t total = read_u32(packet + 1); + const uint8_t img_idx = packet[5]; + const uint32_t count = read_u32(packet + 6); + if (total < sizeof(GCMarkBlock) || total > kMaxPacket) { + return raw(ClassicStream::RawPacketStatus::Error); + } + if (available < total) { + return raw(ClassicStream::RawPacketStatus::NeedMore); + } + + parse_mark_block(packet + sizeof(GCMarkBlock), total - sizeof(GCMarkBlock), img_idx, + count, m_marks); + ++m_next; + if (m_next < m_needed.size()) { + send_crclist(m_needed[m_next]); + } else { + m_complete = true; + } + return raw(ClassicStream::RawPacketStatus::Consumed, total); + } + + void send_crclist(int img_idx) { + CGMarkCRCList p{}; + p.header = HDR_CG_MARK_CRCLIST; + p.img_idx = static_cast(img_idx); + // All-zero CRCs ask the stock server for every block in the image. + m_stream.send_fixed(&p, sizeof(p)); + } + + bool send_upload_mark() { + CGMarkUpload p{}; + p.header = HDR_CG_MARK_UPLOAD; + p.gid = m_up_gid; + std::memcpy(p.image, m_up_mark, sizeof(p.image)); + return m_stream.send_fixed(&p, sizeof(p)); + } + + bool send_upload_symbol() { + if (m_up_symbol.empty() || !m_valid) { + return false; + } + std::vector packet(sizeof(CGGuildSymbolUpload) + m_up_symbol.size()); + CGGuildSymbolUpload head{}; + head.header = HDR_CG_GUILD_SYMBOL_UPLOAD; + head.size = static_cast(packet.size()); + head.guild_id = m_up_gid; + std::memcpy(packet.data(), &head, sizeof(head)); + std::memcpy(packet.data() + sizeof(head), m_up_symbol.data(), m_up_symbol.size()); + return m_stream.send_dynamic(packet.data(), packet.size()); + } + + ClassicStream m_stream; + uint32_t m_handle = 0; + uint32_t m_random_key = 0; + bool m_valid = true; + bool m_login_sent = false; + bool m_idx_requested = false; + bool m_complete = false; + bool m_upload_sent = false; + bool m_symbol_crc_sent = false; + + Mode m_mode = Mode::Download; + uint32_t m_up_gid = 0; + uint32_t m_up_mark[GUILD_MARK_WIDTH * GUILD_MARK_HEIGHT] = {}; + std::vector m_up_symbol; + uint32_t m_symbol_gid = 0; + uint32_t m_symbol_crc = 0; + uint32_t m_symbol_size = 0; + std::vector m_symbol_data; + + MarkImageSet m_marks; + std::vector m_needed; + size_t m_next = 0; +}; + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_parser.cpp b/extension/src/net/classic/classic_parser.cpp new file mode 100644 index 00000000..f697b800 --- /dev/null +++ b/extension/src/net/classic/classic_parser.cpp @@ -0,0 +1,1409 @@ +#include "classic_parser.h" + +#include +#include + +namespace mtnet::classic { + +void ClassicParser::parse_login_success(const SimplePlayer *players, const uint32_t *guild_id, + const char (*guild_name)[GUILD_NAME_MAX_LEN + 1], int n, uint32_t handle, uint32_t rkey) { + m_slots.clear(); + m_slot_count = n; + for (int i = 0; i < n; ++i) { + const SimplePlayer &sp = players[i]; + CharSlot s; + s.id = sp.id; + s.name.assign(sp.name, strnlen(sp.name, sizeof(sp.name))); + s.job = sp.job; + s.level = sp.level; + s.st = sp.st; + s.ht = sp.ht; + s.dx = sp.dx; + s.iq = sp.iq; + s.play_minutes = sp.play_minutes; + s.x = sp.x; + s.y = sp.y; + s.main_part = sp.main_part; + s.hair_part = sp.hair_part; + s.skill_group = sp.skill_group; + s.change_name = sp.change_name != 0; + s.guild_id = guild_id[i]; + s.guild_name.assign(guild_name[i], strnlen(guild_name[i], GUILD_NAME_MAX_LEN + 1)); + m_slots.push_back(std::move(s)); + } + m_handle = handle; + m_random_key = rkey; + m_char_list_ready = true; +} + +bool ClassicParser::on_gc(uint8_t header, const uint8_t *body, uint32_t len) { + switch (header) { + case HDR_GC_LOGIN_SUCCESS_NEWSLOT: { // 32 — what 40250 actually sends + GCLoginSuccess p; + if (!fill(p, header, body, len)) { + return false; + } + parse_login_success(p.players, p.guild_id, p.guild_name, PLAYER_PER_ACCOUNT, p.handle, + p.random_key); + return true; + } + case HDR_GC_LOGIN_SUCCESS: { // 6 — legacy 3-slot + GCLoginSuccess3 p; + if (!fill(p, header, body, len)) { + return false; + } + parse_login_success(p.players, p.guild_id, p.guild_name, PLAYER_PER_ACCOUNT3, p.handle, + p.random_key); + return true; + } + case HDR_GC_LOGIN_FAILURE: { + GCLoginFailure p; + if (!fill(p, header, body, len)) { + return false; + } + m_login_failure.assign(p.status, strnlen(p.status, sizeof(p.status))); + return true; + } + case HDR_GC_AUTH_SUCCESS: + case HDR_GC_AUTH_SUCCESS_OPENID: + case HDR_GC_MATRIX_CARD: + case HDR_GC_RUNUP_MATRIX_QUIZ: + case HDR_GC_REQUEST_PASSPOD: + case HDR_GC_REQUEST_PASSPOD_FAILED: + case HDR_GC_HS_REQUEST: + case HDR_GC_XTRAP_CS1_REQUEST: + case HDR_GC_PANAMA_PACK: + // These packets belong to optional account/anti-cheat integrations. + // Their static sizes are still registered in wire_classic.h so they + // cannot desynchronise the game stream; this client has no matching + // Godot UI or vendor runtime to act on them. + return true; + case HDR_GC_CHARACTER_CREATE_SUCCESS: { + GCPlayerCreateSuccess p; + if (!fill(p, header, body, len)) { + return false; + } + if (p.account_slot < m_slots.size()) { + CharSlot &s = m_slots[p.account_slot]; + s.id = p.player.id; + s.name.assign(p.player.name, strnlen(p.player.name, sizeof(p.player.name))); + s.job = p.player.job; + s.level = p.player.level; + s.st = p.player.st; + s.ht = p.player.ht; + s.dx = p.player.dx; + s.iq = p.player.iq; + s.play_minutes = p.player.play_minutes; + s.x = p.player.x; + s.y = p.player.y; + s.main_part = p.player.main_part; + s.hair_part = p.player.hair_part; + s.skill_group = p.player.skill_group; + s.change_name = p.player.change_name != 0; + } + m_char_events.push_back({CharEvent::CreateOk, p.account_slot, 0}); + return true; + } + case HDR_GC_CREATE_FAILURE: { + GCPlayerCreateFailure p; + if (!fill(p, header, body, len)) { + return false; + } + m_char_events.push_back({CharEvent::CreateFail, -1, p.type}); + return true; + } + case HDR_GC_DELETE_SUCCESS: { + GCPlayerDeleteSuccess p; + if (!fill(p, header, body, len)) { + return false; + } + if (p.account_index < m_slots.size()) { + m_slots[p.account_index] = CharSlot{}; + } + m_char_events.push_back({CharEvent::DeleteOk, p.account_index, 0}); + return true; + } + case HDR_GC_DELETE_WRONG_SOCIAL_ID: + m_char_events.push_back({CharEvent::DeleteFail, -1, 0}); + return true; + case HDR_GC_CHANGE_NAME: { + GCChangeNameNotice p; + if (!fill(p, header, body, len)) { + return false; + } + std::string name(p.name, strnlen(p.name, sizeof(p.name))); + for (auto &s : m_slots) { + if (s.id == p.pid) { + s.name = name; + // GC_CHANGE_NAME is the successful completion of the forced + // rename flow; do not prompt again on the next Start click. + s.change_name = false; + } + } + m_name_events.push_back({p.pid, std::move(name)}); + return true; + } + case HDR_GC_LOGIN_KEY: { + GCLoginKey p; + if (!fill(p, header, body, len)) { + return false; + } + m_login_key = p.login_key; + return true; + } + case HDR_GC_EMPIRE: { + GCEmpire p; + if (!fill(p, header, body, len)) { + return false; + } + m_empire = p.empire; + return true; + } + + case HDR_GC_MAIN_CHARACTER: { // 113 + GCMainCharacter p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_spawn_main(p.vid, p.race, + std::string(p.name, strnlen(p.name, sizeof(p.name))), (float)p.x, (float)p.y, + (float)p.z); + return true; + } + case HDR_GC_MAIN_CHARACTER3_BGM: { + GCMainCharacter3BGM p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_spawn_main(p.vid, p.race, + std::string(p.name, strnlen(p.name, sizeof(p.name))), (float)p.x, (float)p.y, + (float)p.z); + return true; + } + case HDR_GC_MAIN_CHARACTER4_BGM_VOL: { + GCMainCharacter4BGM p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_spawn_main(p.vid, p.race, + std::string(p.name, strnlen(p.name, sizeof(p.name))), (float)p.x, (float)p.y, + (float)p.z); + return true; + } + case HDR_GC_CHARACTER_ADD: { // 1 + GCCharacterAdd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_spawn(p.vid, p.race, p.type, /*name*/ std::string(), (float)p.x, (float)p.y, + (float)p.z, p.angle, p.moving_speed, p.attack_speed); + return true; + } + case HDR_GC_CHARACTER_ADD2: { + GCCharacterAdd2 p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_spawn(p.vid, p.race, p.type, + std::string(p.name, strnlen(p.name, sizeof(p.name))), (float)p.x, (float)p.y, + (float)p.z, p.angle, p.moving_speed, p.attack_speed); + m_world.mut_char_info(p.vid, {}, p.parts, p.empire, (int32_t)p.guild, 0, + p.alignment, p.pk_mode, p.mount_vnum); + return true; + } + case HDR_GC_CHARACTER_DEL: { // 2 + GCCharacterDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_despawn(p.vid); + return true; + } + case HDR_GC_MOVE: { // 3 + GCMove p; + if (!fill(p, header, body, len)) { + return false; + } + // classic wire heading: deg = bRot * 5 (client NetStream Send/Recv Move) + m_world.mut_move(p.vid, (float)p.rot * 5.0f, p.func, (float)p.x, (float)p.y, + p.duration); + return true; + } + case HDR_GC_CHARACTER_POINTS: { // 16 + GCPoints p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_set_points(p.points, POINT_MAX_NUM); + return true; + } + case HDR_GC_CHARACTER_POINT_CHANGE: { // 17 — struct has int32_t header + GCPointChange p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_set_point(p.type, p.value, p.vid); + return true; + } + + case HDR_GC_ITEM_SET: { // 21 + GCItemSet p; + if (!fill(p, header, body, len)) { + return false; + } + mtnet::ItemAttr a[ITEM_ATTRIBUTE_MAX_NUM]; + for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i) { + a[i] = {p.attrs[i].type, p.attrs[i].value}; + } + m_world.mut_item_set(p.cell.window_type, p.cell.cell, p.vnum, p.count, p.flags, + p.anti_flags, p.sockets, a); + return true; + } + case HDR_GC_ITEM_DEL: { // 20 — inventory pos only + GCItemDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_item_del(/*WINDOW_INVENTORY*/ 1, p.pos); + return true; + } + case HDR_GC_ITEM_UPDATE: { // 25 + GCItemUpdate p; + if (!fill(p, header, body, len)) { + return false; + } + mtnet::ItemAttr a[ITEM_ATTRIBUTE_MAX_NUM]; + for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i) { + a[i] = {p.attrs[i].type, p.attrs[i].value}; + } + m_world.mut_item_update(p.cell.window_type, p.cell.cell, p.count, p.sockets, a); + return true; + } + case HDR_GC_ITEM_GROUND_ADD: { // 26 + GCItemGroundAdd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_ground_add(p.vid, p.vnum, (float)p.x, (float)p.y, (float)p.z); + return true; + } + case HDR_GC_ITEM_GROUND_DEL: { // 27 + GCItemGroundDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_ground_del(p.vid); + return true; + } + + case HDR_GC_CHARACTER_UPDATE: + case HDR_GC_CHARACTER_UPDATE2: + case HDR_GC_CHARACTER_UPDATE_NEW: { // 19 / 24 + GCCharacterUpdate p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_char_update(p.vid, p.parts, p.moving_speed, p.attack_speed, + (int32_t)p.guild_id, p.alignment, p.pk_mode, p.mount_vnum); + return true; + } + case HDR_GC_CHARACTER_POSITION: { // 43 + GCCharacterPosition p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_set_position(p.vid, p.position); + return true; + } + case HDR_GC_CHANGE_SPEED: { // 18 + GCChangeSpeed p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_change_speed(p.vid, p.moving_speed); + return true; + } + case HDR_GC_WALK_MODE: { // 111 + GCWalkMode p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_walk_mode(p.vid, p.mode); + return true; + } + case HDR_GC_STUN: { // 13 + GCStun p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_stun(p.vid); + return true; + } + case HDR_GC_DEAD: { // 14 + GCDead p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_dead(p.vid); + return true; + } + case HDR_GC_MOTION: { // 36 + GCMotion p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_motion(p.vid, p.victim_vid, p.motion); + return true; + } + case HDR_GC_TARGET: { // 63 + GCTarget p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_target(p.vid, p.hp_percent); + return true; + } + case HDR_GC_DAMAGE_INFO: { // 135 + GCDamageInfo p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_damage(p.vid, p.flag, p.damage); + return true; + } + case HDR_GC_FISHING: { + GCFishing packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_fishing(packet.subheader, packet.info, packet.dir); + return true; + } + case HDR_GC_CHAR_ADDITIONAL_INFO: { // 136 + GCCharAddInfo p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_char_info(p.vid, std::string(p.name, strnlen(p.name, sizeof(p.name))), + p.parts, p.empire, (int32_t)p.guild_id, (int32_t)p.level, p.alignment, + p.pk_mode, p.mount_vnum); + return true; + } + case HDR_GC_SKILL_LEVEL: { // 76 + GCSkillLevel p; + if (!fill(p, header, body, len)) { + return false; + } + uint8_t level[SKILL_MAX_NUM]; + uint8_t master[SKILL_MAX_NUM]; + for (int i = 0; i < SKILL_MAX_NUM; ++i) { + level[i] = p.skills[i].level; + master[i] = p.skills[i].master_type; + } + m_world.mut_skill_levels(level, master, SKILL_MAX_NUM); + return true; + } + case HDR_GC_SKILL_COOLTIME_END: { + GCSkillCooltimeEnd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_skill_cooldown_end(p.skill); + return true; + } + case HDR_GC_QUICKSLOT_ADD: { // 28 + GCQuickSlotAdd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_quickslot_set(p.pos, p.slot.type, p.slot.position); + return true; + } + case HDR_GC_QUICKSLOT_DEL: { // 29 + GCQuickSlotDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_quickslot_del(p.pos); + return true; + } + case HDR_GC_QUICKSLOT_SWAP: { // 30 + GCQuickSlotSwap p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_quickslot_swap(p.pos, p.pos_to); + return true; + } + case HDR_GC_AFFECT_ADD: { // 126 + GCAffectAdd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_affect_add(p.elem.type, p.elem.point_idx, p.elem.apply_value, p.elem.flag, + p.elem.duration); + return true; + } + case HDR_GC_AFFECT_REMOVE: { // 127 + GCAffectRemove p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_affect_remove(p.type); + return true; + } + case HDR_GC_WHISPER: { // 34 (dynamic) — body = type, name_from[25], text + const size_t name_max = CHARACTER_NAME_MAX_LEN + 1; + if (len < 1u + name_max) { + return true; + } + uint8_t wtype = body[0]; + const char *name = reinterpret_cast(body + 1); + const char *text = reinterpret_cast(body + 1 + name_max); + size_t text_len = len - 1 - name_max; + m_world.mut_whisper(wtype, std::string(name, strnlen(name, name_max)), + std::string(text, strnlen(text, text_len))); + return true; + } + case HDR_GC_SYNC_POSITION: { // 5 (dynamic) — body = N x SyncPosElement + size_t n = len / sizeof(SyncPosElement); + const auto *els = reinterpret_cast(body); + for (size_t i = 0; i < n; ++i) { + m_world.mut_snap_position(els[i].vid, (float)els[i].x, (float)els[i].y); + } + return true; + } + + case HDR_GC_PARTY_INVITE: { // 77 + GCPartyInvite p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_invite(p.leader_vid); + return true; + } + case HDR_GC_PARTY_ADD: { // 78 + GCPartyAdd p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_add(p.pid, std::string(p.name, strnlen(p.name, sizeof(p.name)))); + return true; + } + case HDR_GC_PARTY_UPDATE: { // 79 + GCPartyUpdate p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_update(p.pid, p.role, p.percent_hp, p.affects); + return true; + } + case HDR_GC_PARTY_REMOVE: { // 80 + GCPartyRemove p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_remove(p.pid); + return true; + } + case HDR_GC_PARTY_LINK: { // 91 + GCPartyLink p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_link(p.pid, p.vid); + return true; + } + case HDR_GC_PARTY_UNLINK: { // 92 + GCPartyUnlink p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_unlink(p.pid); + return true; + } + case HDR_GC_PARTY_PARAMETER: { // 83 + GCPartyParameter p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_party_parameter(p.distribute_mode); + return true; + } + + case HDR_GC_MESSENGER: { // 74 (dynamic) — body = subheader + records + if (len < 1) { + return true; + } + const uint8_t sub = body[0]; + const uint8_t *cur = body + 1; + const uint8_t *end = body + len; + auto read_name = [&](uint8_t n) -> std::string { + if (cur + n > end) { + return {}; + } + std::string name(reinterpret_cast(cur), n); + cur += n; + return name; + }; + switch (sub) { + case MESSENGER_GC_LIST: + // LIST is a complete snapshot, so remove friends from a previous + // character/server before applying the records that follow. + m_world.mut_friend_clear(); + while (cur + sizeof(MessengerListEntry) <= end) { + const uint8_t connected = cur[0]; + const uint8_t n = cur[1]; + cur += sizeof(MessengerListEntry); + std::string name = read_name(n); + if (name.size() != n) { + break; + } + m_world.mut_friend_set(name, (connected & 1u) != 0); + m_world.mut_friend_mobile(name, (connected & 2u) != 0); + } + return true; + case MESSENGER_GC_LOGIN: + case MESSENGER_GC_LOGOUT: + if (cur < end) { + const uint8_t n = *cur++; + std::string name = read_name(n); + if (name.size() == n) { + m_world.mut_friend_set(name, sub == MESSENGER_GC_LOGIN); + } + } + return true; + case MESSENGER_GC_MOBILE: + // 40250 sends [state][name_length][name]. The state is + // the mobile-presence flag, not an online/offline transition. + if (cur + 2 <= end) { + const uint8_t state = *cur++; + const uint8_t n = *cur++; + std::string name = read_name(n); + if (name.size() == n) { + m_world.mut_friend_mobile(name, state != 0); + } + } + return true; + default: + // INVITE has no local representation; it is handled by the + // command channel in this 40250 client. + return true; + } + } + + case HDR_GC_EXCHANGE: { // 42 (static) + GCExchange p; + if (!fill(p, header, body, len)) { + return false; + } + const bool self = p.is_me != 0; + switch (p.subheader) { + case EXCHANGE_GC_START: + m_world.mut_exchange_start(p.arg1); + break; + case EXCHANGE_GC_ITEM_ADD: + m_world.mut_exchange_item(self, static_cast(p.arg2.cell), p.arg1, + static_cast(p.arg3)); + break; + case EXCHANGE_GC_ITEM_DEL: + m_world.mut_exchange_item_del(self, static_cast(p.arg1)); + break; + case EXCHANGE_GC_GOLD_ADD: + m_world.mut_exchange_gold(self, static_cast(p.arg1)); + break; + case EXCHANGE_GC_ACCEPT: + m_world.mut_exchange_accept(self, p.arg1 != 0); + break; + case EXCHANGE_GC_END: + m_world.mut_exchange_end(); + break; + case EXCHANGE_GC_ALREADY: + case EXCHANGE_GC_LESS_GOLD: + m_world.mut_exchange_notice(); + break; + default: + break; + } + return true; + } + + case HDR_GC_SAFEBOX_SIZE: { // 88 + GCSafeboxSize p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_safebox_open(p.size); + return true; + } + case HDR_GC_SAFEBOX_MONEY_CHANGE: { // 84 + GCSafeboxMoneyChange p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_safebox_money(p.money); + return true; + } + case HDR_GC_SAFEBOX_SET: { // 85 + GCItemSet p; + if (!fill(p, header, body, len)) { + return false; + } + mtnet::ItemAttr attrs[ITEM_ATTRIBUTE_MAX_NUM] = {}; + for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i) { + attrs[i] = {p.attrs[i].type, p.attrs[i].value}; + } + m_world.mut_safebox_set(p.cell.cell, p.vnum, p.count, p.flags, p.anti_flags, p.sockets, + attrs); + return true; + } + case HDR_GC_SAFEBOX_DEL: { // 86 + GCItemDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_safebox_del(p.pos); + return true; + } + case HDR_GC_SAFEBOX_WRONG_PASSWORD: // 87 + m_world.mut_safebox_wrong_password(); + return true; + + case HDR_GC_MALL_OPEN: { // 122 + GCMallOpen p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_mall_open(p.size); + return true; + } + case HDR_GC_MALL_SET: { // 128 + GCItemSet p; + if (!fill(p, header, body, len)) { + return false; + } + mtnet::ItemAttr attrs[ITEM_ATTRIBUTE_MAX_NUM] = {}; + for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i) { + attrs[i] = {p.attrs[i].type, p.attrs[i].value}; + } + m_world.mut_mall_set(p.cell.cell, p.vnum, p.count, p.flags, p.anti_flags, p.sockets, + attrs); + return true; + } + case HDR_GC_MALL_DEL: { // 129 + GCItemDel p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_mall_del(p.pos); + return true; + } + + case HDR_GC_SCRIPT: { // 45 (dynamic) — body = [skin][u16 src_size][text] + if (len < 3) { + return true; + } + uint8_t skin = body[0]; + const char *txt = reinterpret_cast(body + 3); + size_t txt_len = len - 3; + m_world.mut_script(skin, std::string(txt, strnlen(txt, txt_len))); + return true; + } + case HDR_GC_QUEST_CONFIRM: { // 46 (static) + GCQuestConfirm p; + if (!fill(p, header, body, len)) { + return false; + } + m_world.mut_quest_confirm(std::string(p.msg, strnlen(p.msg, sizeof(p.msg))), p.timeout, + p.request_pid); + return true; + } + case HDR_GC_QUEST_INFO: { // 81 (dynamic) — body = [u16 index][u8 flag][flag-driven...] + if (len < 3) { + return true; + } + uint16_t index; + std::memcpy(&index, body, 2); + uint8_t flag = body[2]; + const uint8_t *cur = body + 3; + const uint8_t *end = body + len; + auto take_str = [&](size_t cap) -> std::string { + size_t n = 0; + while (cur + n < end && cur[n] != 0 && n < cap) { + ++n; + } + std::string s(reinterpret_cast(cur), n); + cur += (cur + n < end) ? n + 1 : n; // skip NUL if present + return s; + }; + auto take_i32 = [&]() -> int32_t { + int32_t v = 0; + if (cur + 4 <= end) { + std::memcpy(&v, cur, 4); + cur += 4; + } + return v; + }; + std::string title, clock_name, counter_name, icon; + int32_t clock_value = 0, counter_value = 0; + if (flag & QUEST_SEND_TITLE) { + title = take_str(28); + } + if (flag & QUEST_SEND_CLOCK_NAME) { + clock_name = take_str(16); + } + if (flag & QUEST_SEND_CLOCK_VALUE) { + clock_value = take_i32(); + } + if (flag & QUEST_SEND_COUNTER_NAME) { + counter_name = take_str(16); + } + if (flag & QUEST_SEND_COUNTER_VALUE) { + counter_value = take_i32(); + } + if (flag & QUEST_SEND_ICON_FILE) { + icon = take_str(24); + } + m_world.mut_quest_info(index, flag, (flag & QUEST_SEND_IS_BEGIN) != 0, title, clock_name, + clock_value, counter_name, counter_value, icon); + return true; + } + + case HDR_GC_SHOP: { // 38 (dynamic) — body = [subheader][sub-specific...] + if (len < 1) { + return true; + } + uint8_t sub = body[0]; + const uint8_t *cur = body + 1; + const uint8_t *end = body + len; + auto read_tab = [&](ShopTab &tab) { + for (int j = 0; j < SHOP_HOST_ITEM_MAX_NUM && + cur + (int)sizeof(ShopItem43) <= end; + ++j) { + ShopItem43 si; + std::memcpy(&si, cur, sizeof(si)); + cur += sizeof(si); + if (si.vnum != 0) { + tab.items.push_back({si.vnum, si.price, si.count, si.display_pos}); + } + } + }; + switch (sub) { + case SHOP_SUB_START: { + if (cur + 4 > end) { + return true; + } + uint32_t vid; + std::memcpy(&vid, cur, 4); + cur += 4; + ShopTab tab; // unnamed -> flat single shelf + read_tab(tab); + m_world.mut_shop_open(vid, {std::move(tab)}); + return true; + } + case SHOP_SUB_START_EX: { + if (cur + 5 > end) { + return true; + } + uint32_t vid; + std::memcpy(&vid, cur, 4); + cur += 4; + uint8_t tab_count = *cur++; + std::vector tabs; + for (uint8_t t = 0; t < tab_count && t < SHOP_TAB_COUNT_MAX; ++t) { + if (cur + (int)sizeof(ShopTabHead32) > end) { + break; + } + ShopTabHead32 th; + std::memcpy(&th, cur, sizeof(th)); + cur += sizeof(th); + ShopTab tab; + tab.name.assign(th.name, strnlen(th.name, SHOP_TAB_NAME_MAX)); + tab.coin_type = th.coin_type; + read_tab(tab); + tabs.push_back(std::move(tab)); + } + m_world.mut_shop_open(vid, tabs); + return true; + } + case SHOP_SUB_END: + m_world.mut_shop_close(); + return true; + case SHOP_SUB_NOT_ENOUGH_MONEY: + case SHOP_SUB_NOT_ENOUGH_MONEY_EX: + m_world.mut_shop_error("NOT_ENOUGH_MONEY"); + return true; + case SHOP_SUB_SOLDOUT: + case SHOP_SUB_SOLD_OUT: + m_world.mut_shop_error("SOLDOUT"); + return true; + case SHOP_SUB_INVENTORY_FULL: + m_world.mut_shop_error("INVENTORY_FULL"); + return true; + case SHOP_SUB_INVALID_POS: + m_world.mut_shop_error("INVALID_POS"); + return true; + case SHOP_SUB_UPDATE_ITEM: { + if (cur + (int)sizeof(ShopUpdateItem) > end) { + return true; + } + ShopUpdateItem update; + std::memcpy(&update, cur, sizeof(update)); + m_world.mut_shop_update_item(update.pos, update.item.vnum, update.item.price, + update.item.count); + return true; + } + case SHOP_SUB_UPDATE_PRICE: { + if (cur + (int)sizeof(ShopUpdatePrice) > end) { + return true; + } + ShopUpdatePrice update; + std::memcpy(&update, cur, sizeof(update)); + m_world.mut_shop_update_price(update.price); + return true; + } + default: + return true; // OK has no state payload + } + } + + case HDR_GC_SHOP_SIGN: { + GCShopSign packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_shop_sign(packet.vid, + std::string(packet.sign, strnlen(packet.sign, sizeof(packet.sign)))); + return true; + } + + case HDR_GC_GUILD: { // dynamic — body = [subheader][sub-specific...] + if (len < 1) { + return true; + } + const uint8_t sub = body[0]; + const uint8_t *cur = body + 1; + const uint8_t *end = body + len; + switch (sub) { + case GUILD_GC_LOGIN: + case GUILD_GC_LOGOUT: + if (cur + 4 <= end) { + uint32_t pid; + std::memcpy(&pid, cur, sizeof(pid)); + m_world.mut_guild_member_online(pid, sub == GUILD_GC_LOGIN); + } + return true; + case GUILD_GC_INFO: { + if (cur + (int)sizeof(GuildInfo35) > end) { + return true; + } + GuildInfo35 info; + std::memcpy(&info, cur, sizeof(info)); + m_world.mut_guild_info(info.member_count, info.max_member_count, info.guild_id, + info.master_pid, info.exp, info.level, + std::string(info.name, strnlen(info.name, sizeof(info.name))), info.gold, + info.has_land != 0); + return true; + } + case GUILD_GC_LIST: { + if ((end - cur) % (int)sizeof(GuildMember38) != 0) { + return true; + } + m_world.mut_guild_clear_members(); + while (cur + (int)sizeof(GuildMember38) <= end) { + GuildMember38 member; + std::memcpy(&member, cur, sizeof(member)); + cur += sizeof(member); + m_world.mut_guild_member(member.pid, member.grade, member.is_general != 0, + member.job, member.level, member.offer, + std::string(member.name, strnlen(member.name, sizeof(member.name)))); + } + return true; + } + case GUILD_GC_GRADE: { + if (cur >= end) { + return true; + } + const uint8_t count = *cur++; + for (uint8_t i = 0; i < count; ++i) { + if (cur + 1 + (int)sizeof(GuildGrade10) > end) { + return true; + } + const uint8_t grade = *cur++; + GuildGrade10 data; + std::memcpy(&data, cur, sizeof(data)); + cur += sizeof(data); + m_world.mut_guild_grade(grade, + std::string(data.name, strnlen(data.name, sizeof(data.name))), data.auth); + } + return true; + } + case GUILD_GC_ADD: { + if (cur + (int)sizeof(GuildMember38) > end) { + return true; + } + GuildMember38 member; + std::memcpy(&member, cur, sizeof(member)); + m_world.mut_guild_member(member.pid, member.grade, member.is_general != 0, + member.job, member.level, member.offer, + std::string(member.name, strnlen(member.name, sizeof(member.name)))); + return true; + } + case GUILD_GC_REMOVE: + if (cur + 4 <= end) { + uint32_t pid; + std::memcpy(&pid, cur, sizeof(pid)); + m_world.mut_guild_remove_member(pid); + } + return true; + case GUILD_GC_GRADE_NAME: + if (cur + 1 + GUILD_GRADE_NAME_MAX_LEN + 1 <= end) { + const uint8_t grade = *cur++; + m_world.mut_guild_grade_name(grade, + std::string(reinterpret_cast(cur), + strnlen(reinterpret_cast(cur), GUILD_GRADE_NAME_MAX_LEN + 1))); + } + return true; + case GUILD_GC_GRADE_AUTH: + if (cur + 2 <= end) { + m_world.mut_guild_grade_auth(cur[0], cur[1]); + } + return true; + case GUILD_GC_CHANGE_EXP: + if (cur + 5 <= end) { + const uint8_t level = *cur++; + uint32_t exp; + std::memcpy(&exp, cur, sizeof(exp)); + m_world.mut_guild_exp(level, exp); + } + return true; + case GUILD_GC_CHANGE_MEMBER_GRADE: + if (cur + 5 <= end) { + uint32_t pid; + std::memcpy(&pid, cur, sizeof(pid)); + m_world.mut_guild_member_grade(pid, cur[4]); + } + return true; + case GUILD_GC_SKILL_INFO: { + if (cur + (int)sizeof(GuildSkill17) > end) { + return true; + } + GuildSkill17 skill; + std::memcpy(&skill, cur, sizeof(skill)); + m_world.mut_guild_skill(skill.skill_point, skill.levels, skill.guild_point, + skill.max_guild_point); + return true; + } + case GUILD_GC_CHANGE_MEMBER_GENERAL: + if (cur + 5 <= end) { + uint32_t pid; + std::memcpy(&pid, cur, sizeof(pid)); + m_world.mut_guild_member_general(pid, cur[4] != 0); + } + return true; + case GUILD_GC_WAR: + if (cur + (int)sizeof(GuildWar10) <= end) { + GuildWar10 war; + std::memcpy(&war, cur, sizeof(war)); + m_world.mut_guild_war(war.self_id, war.opponent_id, war.type, war.state); + } + return true; + case GUILD_GC_GUILD_WAR_LIST: + case GUILD_GC_GUILD_WAR_END_LIST: { + if ((end - cur) % (int)sizeof(GuildWarPair8) != 0) { + return true; + } + std::vector pairs; + while (cur + (int)sizeof(GuildWarPair8) <= end) { + GuildWarPair8 pair; + std::memcpy(&pair, cur, sizeof(pair)); + cur += sizeof(pair); + pairs.push_back({pair.src, pair.dst}); + } + m_world.mut_guild_war_pairs(pairs, sub == GUILD_GC_GUILD_WAR_END_LIST); + return true; + } + case GUILD_GC_WAR_POINT: + if (cur + (int)sizeof(GuildWarPoint12) <= end) { + GuildWarPoint12 point; + std::memcpy(&point, cur, sizeof(point)); + m_world.mut_guild_war_score(point.gain_guild_id, point.opponent_guild_id, + point.point); + } + return true; + case GUILD_GC_COMMENTS: { + if (cur >= end) { + m_world.mut_guild_comments({}); + return true; + } + const uint8_t count = *cur++; + std::vector comments; + comments.reserve(count); + for (uint8_t i = 0; i < count; ++i) { + if (cur + (int)sizeof(GuildComment80) > end) { + break; + } + GuildComment80 packet; + std::memcpy(&packet, cur, sizeof(packet)); + cur += sizeof(packet); + comments.push_back({packet.id, + std::string(packet.name, strnlen(packet.name, sizeof(packet.name))), + std::string(packet.content, strnlen(packet.content, sizeof(packet.content)))}); + } + m_world.mut_guild_comments(comments); + return true; + } + case GUILD_GC_GUILD_INVITE: { + GuildInvite17 packet; + if (cur + (int)sizeof(packet) <= end) { + std::memcpy(&packet, cur, sizeof(packet)); + m_world.mut_guild_invite(packet.guild_id, + std::string(packet.guild_name, + strnlen(packet.guild_name, sizeof(packet.guild_name)))); + } + return true; + } + case GUILD_GC_MONEY_CHANGE: + if (cur + 4 <= end) { + uint32_t gold; + std::memcpy(&gold, cur, sizeof(gold)); + m_world.mut_guild_money(gold); + } + return true; + case GUILD_GC_NAME: + if ((end - cur) % (int)sizeof(GuildName16) != 0) { + return true; + } + while (cur + (int)sizeof(GuildName16) <= end) { + GuildName16 name; + std::memcpy(&name, cur, sizeof(name)); + cur += sizeof(name); + m_world.mut_guild_name(name.id, + std::string(name.name, strnlen(name.name, sizeof(name.name)))); + } + return true; + default: + return true; + } + } + + case HDR_GC_ITEM_USE: { + GCItemUse packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_item_used(packet.vnum); + return true; + } + case HDR_GC_ITEM_OWNERSHIP: { + GCItemOwnership packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_ground_owner(packet.vid, + std::string(packet.owner, strnlen(packet.owner, sizeof(packet.owner)))); + return true; + } + case HDR_GC_OWNERSHIP: { + GCOwnership packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_ground_owner(packet.victim_vid, std::to_string(packet.owner_vid)); + return true; + } + case HDR_GC_MOUNT: { + GCMount packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_mount(packet.vid, packet.mount_vnum); + return true; + } + case HDR_GC_CREATE_FLY: { + GCCreateFly packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_fly(packet.type, packet.start_vid, packet.end_vid); + return true; + } + case HDR_GC_FLY_TARGETING: + case HDR_GC_ADD_FLY_TARGETING: { + GCFlyTargeting packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_fly_target(packet.shooter_vid, packet.target_vid, packet.x, packet.y, + header == HDR_GC_ADD_FLY_TARGETING); + return true; + } + case HDR_GC_PVP: { + GCPvp packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_pvp(packet.src_vid, packet.dst_vid, packet.mode); + return true; + } + case HDR_GC_DUEL_START: { + // TPacketGCDuelStart is [header][u16 whole_size] followed by the + // DWORD VIDs of every opponent in the duel. ClassicStream has + // already consumed the three-byte dynamic prefix, so `body` is the + // packed VID list here. + if (len % sizeof(uint32_t) != 0) { + return false; + } + std::vector opponents; + opponents.reserve(len / sizeof(uint32_t)); + for (uint32_t i = 0; i < len; i += sizeof(uint32_t)) { + uint32_t vid = 0; + std::memcpy(&vid, body + i, sizeof(vid)); + opponents.push_back(vid); + } + m_world.mut_duel_start(opponents.data(), (int)opponents.size()); + return true; + } + case HDR_GC_SPECIAL_EFFECT: { + GCSpecialEffect packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_special_effect(packet.vid, packet.type); + return true; + } + case HDR_GC_SPECIFIC_EFFECT: { + GCSpecificEffect packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_specific_effect(packet.vid, + std::string(packet.effect_file, strnlen(packet.effect_file, sizeof(packet.effect_file)))); + return true; + } + case HDR_GC_SKILL_GROUP: { + GCSkillGroup packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_skill_group(packet.skill_group); + return true; + } + case HDR_GC_SKILL_LEVEL_OLD: { + GCSkillLevelOld packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_skill_levels(packet.levels, nullptr, SKILL_MAX_NUM); + return true; + } + case HDR_GC_OBSERVER_ADD: + case HDR_GC_OBSERVER_MOVE: { + GCObserverMove packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_observer(header == HDR_GC_OBSERVER_ADD ? ObserverEvent::Add : ObserverEvent::Move, + packet.vid, (int32_t)packet.x * 100, (int32_t)packet.y * 100); + return true; + } + case HDR_GC_OBSERVER_REMOVE: { + GCObserverRemove packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_observer(ObserverEvent::Remove, packet.vid, 0, 0); + return true; + } + case HDR_GC_REFINE_INFORMATION_OLD: + case HDR_GC_REFINE_INFORMATION: { + GCRefineInfo packet; + if (!fill(packet, header, body, len)) { + return false; + } + RefineCue::Mat materials[5] = {}; + for (int i = 0; i < 5; ++i) { + materials[i].vnum = packet.materials[i].vnum; + materials[i].count = packet.materials[i].count; + } + m_world.mut_refine(packet.type, packet.pos, packet.src_vnum, packet.result_vnum, + packet.material_count, packet.cost, packet.prob, materials); + return true; + } + case HDR_GC_DRAGON_SOUL_REFINE: { + GCDragonSoulRefine packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_dragon_soul_refine(packet.sub_type, packet.pos.window_type, + packet.pos.cell); + return true; + } + case HDR_GC_WARP: { + GCWarpClassic packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_warp(packet.x, packet.y, packet.addr, packet.port); + return true; + } + case HDR_GC_TIME: { + GCTime packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_server_time(packet.time); + return true; + } + case HDR_GC_CHANNEL: { + GCChannel packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_channel(packet.channel); + return true; + } + case HDR_GC_DUNGEON: { + if (len < sizeof(GCDungeonHead)) { + return true; + } + GCDungeonHead packet; + std::memcpy(&packet, body, sizeof(packet)); + if (packet.subheader == 1 && len >= sizeof(packet) + sizeof(GCDungeonDestination)) { + GCDungeonDestination destination; + std::memcpy(&destination, body + sizeof(packet), sizeof(destination)); + m_world.mut_dungeon(packet.subheader, destination.x, destination.y, true); + } else { + m_world.mut_dungeon(packet.subheader, 0, 0, false); + } + return true; + } + case HDR_GC_NPC_POSITION: { + if (len < sizeof(GCNPCPositionHead)) { + return true; + } + GCNPCPositionHead head; + std::memcpy(&head, body, sizeof(head)); + const uint8_t *cur = body + sizeof(head); + const uint8_t *end = body + len; + std::vector marks; + for (uint16_t i = 0; i < head.count && cur + (int)sizeof(NPCPosition34) <= end; ++i) { + NPCPosition34 entry; + std::memcpy(&entry, cur, sizeof(entry)); + cur += sizeof(entry); + marks.push_back({entry.type, 0, + std::string(entry.name, strnlen(entry.name, sizeof(entry.name))), entry.x, entry.y}); + } + m_world.mut_npc_marks(marks); + return true; + } + case HDR_GC_LAND_LIST: { + const uint8_t *cur = body; + const uint8_t *end = body + len; + if (len % sizeof(LandPacketElement24) != 0) { + return true; + } + std::vector areas; + while (cur + (int)sizeof(LandPacketElement24) <= end) { + LandPacketElement24 entry; + std::memcpy(&entry, cur, sizeof(entry)); + cur += sizeof(entry); + areas.push_back({entry.id, entry.x, entry.y, entry.width, entry.height, entry.guild_id}); + } + m_world.mut_land_areas(areas); + return true; + } + case HDR_GC_TARGET_CREATE: { + GCTargetCreate43 packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_marker_create(packet.id, + std::string(packet.name, strnlen(packet.name, sizeof(packet.name))), packet.vid, + packet.type); + return true; + } + case HDR_GC_TARGET_UPDATE: { + GCTargetUpdate13 packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_marker_update(packet.id, packet.x, packet.y); + return true; + } + case HDR_GC_TARGET_DELETE: { + GCTargetDelete5 packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_marker_delete(packet.id); + return true; + } + case HDR_GC_LOVER_INFO: { + GCLoverInfo packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_lover(std::string(packet.name, strnlen(packet.name, sizeof(packet.name))), + packet.love_point); + return true; + } + case HDR_GC_LOVE_POINT_UPDATE: { + GCLovePointUpdate packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_love_point(packet.love_point); + return true; + } + case HDR_GC_DIG_MOTION: { + GCDigMotion packet; + if (!fill(packet, header, body, len)) { + return false; + } + m_world.mut_dig(packet.vid, packet.target_vid, packet.count); + return true; + } + case HDR_GC_REQUEST_MAKE_GUILD: + ++m_guild_make_requests; + return true; + case HDR_GC_VIEW_EQUIP: { + GCViewEquip packet; + if (!fill(packet, header, body, len)) { + return false; + } + Item items[mtnet::VIEW_EQUIP_WEAR_MAX_NUM] = {}; + for (int i = 0; i < mtnet::VIEW_EQUIP_WEAR_MAX_NUM && i < CLASSIC_WEAR_MAX_NUM; ++i) { + items[i].vnum = packet.equips[i].vnum; + items[i].count = packet.equips[i].count; + std::memcpy(items[i].sockets, packet.equips[i].sockets, sizeof(items[i].sockets)); + for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; ++j) { + items[i].attrs[j] = {packet.equips[i].attrs[j].type, + packet.equips[i].attrs[j].value}; + } + } + m_world.mut_view_equipment(packet.vid, items, mtnet::VIEW_EQUIP_WEAR_MAX_NUM); + return true; + } + + case HDR_GC_CHAT: { // 4 (dynamic) — body = type,vid,empire,text (after [hdr][u16 size]) + if (len < 6) { + return true; // malformed, ignore + } + uint8_t type = body[0]; + uint32_t vid; + std::memcpy(&vid, body + 1, 4); + // body[5] = empire; text follows + const char *txt = reinterpret_cast(body + 6); + m_world.mut_chat(type, vid, std::string(txt, strnlen(txt, len - 6))); + return true; + } + + default: + // not handled yet — harmless, keep going. classic_stream already + // rejected unknown *static* headers via the size table. + return true; + } +} + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_parser.h b/extension/src/net/classic/classic_parser.h new file mode 100644 index 00000000..1399908a --- /dev/null +++ b/extension/src/net/classic/classic_parser.h @@ -0,0 +1,109 @@ +#pragma once +// ClassicParser — 40250 GC packet bodies -> shared world model (EntityStore via +// its protocol-neutral mut_* API) + login/char-list state. +// Counterpart of EntityStore::apply() for MT_PROTOCOL=classic. +// See docs/CLIENT-40250-PORT.md §4 / §5. +// +// `body` is the bytes AFTER the 1-byte header (for dynamic packets: after the +// [header][uint16 size] prefix); `len` its length — i.e. exactly what +// ClassicStream::on_packet delivers. + +#include "wire_classic.h" + +#include "../entity_store.h" + +#include +#include +#include +#include + +namespace mtnet::classic { + +struct CharSlot { + uint32_t id = 0; + std::string name; + uint8_t job = 0; + uint8_t level = 0; + uint8_t st = 0, ht = 0, dx = 0, iq = 0; + uint32_t play_minutes = 0; + int32_t x = 0, y = 0; + uint16_t main_part = 0, hair_part = 0; + uint8_t skill_group = 0; + // Server requires this character to be renamed before entering the game. + bool change_name = false; + uint32_t guild_id = 0; + std::string guild_name; + bool empty() const { return id == 0 && name.empty(); } +}; + +class ClassicParser { +public: + struct CharEvent { + enum Kind { CreateOk, CreateFail, DeleteOk, DeleteFail } kind; + int slot = -1; + int fail_type = 0; + }; + struct NameEvent { + uint32_t pid = 0; + std::string name; + }; + + explicit ClassicParser(EntityStore &world) : m_world(world) {} + + // one GC packet. returns false to abort the connection. + bool on_gc(uint8_t header, const uint8_t *body, uint32_t len); + + // --- login / select state --- + const std::vector &char_slots() const { return m_slots; } + int slot_count() const { return m_slot_count; } // 3 or 4 + uint32_t handle() const { return m_handle; } + uint32_t random_key() const { return m_random_key; } + bool char_list_ready() const { return m_char_list_ready; } + const std::string &login_failure() const { return m_login_failure; } + uint32_t login_key() const { return m_login_key; } // GC_LOGIN_KEY (auth path) + uint8_t empire() const { return m_empire; } + std::vector drain_char_events() { + auto v = std::move(m_char_events); + m_char_events.clear(); + return v; + } + std::vector drain_name_events() { + auto v = std::move(m_name_events); + m_name_events.clear(); + return v; + } + int drain_guild_make_requests() { + int count = m_guild_make_requests; + m_guild_make_requests = 0; + return count; + } + +private: + template + static bool fill(T &t, uint8_t header, const uint8_t *body, uint32_t len) { + if (len + 1u < sizeof(T)) { + return false; + } + t.header = header; + std::memcpy(reinterpret_cast(&t) + 1, body, sizeof(T) - 1); + return true; + } + void parse_login_success(const SimplePlayer *players, const uint32_t *guild_id, + const char (*guild_name)[GUILD_NAME_MAX_LEN + 1], int n, uint32_t handle, + uint32_t rkey); + + EntityStore &m_world; + std::vector m_slots; + int m_slot_count = 0; + uint32_t m_handle = 0; + uint32_t m_random_key = 0; + uint32_t m_login_key = 0; + uint8_t m_empire = 0; + std::vector m_char_events; + std::vector m_name_events; + int m_guild_make_requests = 0; + bool m_char_list_ready = false; + std::string m_login_failure; +}; + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_session.cpp b/extension/src/net/classic/classic_session.cpp new file mode 100644 index 00000000..6042fa86 --- /dev/null +++ b/extension/src/net/classic/classic_session.cpp @@ -0,0 +1,947 @@ +#include "classic_session.h" + +#include +#include +#include + +namespace mtnet::classic { + +ClassicSession::ClassicSession() : m_parser(m_world) { + m_stream.on_phase = [this](uint8_t p) { on_phase(p); }; + m_stream.on_packet = [this](uint8_t h, const uint8_t *b, uint32_t l) { + return on_packet(h, b, l); + }; + m_stream.on_error = [this](const std::string &e) { + m_last_error = e; + set_stage(Stage::Failed); + if (on_error) { + on_error(e); + } + }; + m_stream.on_state_change = [this](ClassicStream::State s) { + if (s == ClassicStream::State::Offline && m_stage != Stage::Failed && + m_stage != Stage::Offline) { + m_last_error = m_stream.last_error().empty() ? "disconnected" : m_stream.last_error(); + set_stage(Stage::Failed); + } else if (s == ClassicStream::State::Online && m_stage == Stage::Connecting) { + // handshake packets flow next; stay in Connecting until GC_PHASE(LOGIN) + } + }; +} + +void ClassicSession::set_stage(Stage s) { + if (m_stage == s) { + return; + } + m_stage = s; + if (on_stage_change) { + on_stage_change(s); + } +} + +void ClassicSession::start_offline(const std::string &id, const std::string &pw) { + m_id = id; + m_pw = pw; + m_login_sent = false; + m_entergame_sent = false; + m_version_sent = false; + m_last_error.clear(); + // During PHASE_HANDSHAKE even retry handshakes must be answered with + // 0xFF. The normal game client switches to CG_TIME_SYNC only after the + // server has advanced into the login/select side of the connection. + m_stream.set_time_sync_mode(false); + set_stage(Stage::Connecting); +} + +bool ClassicSession::connect(const std::string &game_host, uint16_t game_port, + const std::string &id, const std::string &pw) { + start_offline(id, pw); + if (!m_stream.connect(game_host, game_port)) { + m_last_error = m_stream.last_error(); + set_stage(Stage::Failed); + return false; + } + return true; +} + +void ClassicSession::disconnect() { + m_stream.disconnect(); + set_stage(Stage::Offline); +} + +void ClassicSession::pump() { + m_stream.process(); + // auto CG_ENTERGAME a beat into PHASE_LOADING (the m2dev client waits ~1.5s; + // sending it too early makes the server drop us mid spawn-burst). + if (m_stage == Stage::Loading && !m_entergame_sent && m_entergame_delay > 0 && + m_now - m_loading_since >= m_entergame_delay) { + enter_game(); + } + m_world.tick(); +} + +void ClassicSession::send_login() { + if (m_login_sent) { + return; + } + // docs §2.2: the client turns sequence mode on around here; CG_LOGIN is a + // bSeq packet and the server expects the trailing byte from packet #1. + m_stream.set_sequence_mode(true); + + CGLogin p{}; + p.header = HDR_CG_LOGIN; + std::strncpy(p.login, m_id.c_str(), sizeof(p.login) - 1); + std::strncpy(p.passwd, m_pw.c_str(), sizeof(p.passwd) - 1); + m_stream.send_fixed(&p, sizeof(p)); + m_login_sent = true; +} + +bool ClassicSession::create_character(int slot, const std::string &name, int job, int shape, + int con, int intel, int str, int dex) { + if (m_stage != Stage::CharSelect || slot < 0 || slot >= m_parser.slot_count() || + name.empty() || name.size() > CHARACTER_NAME_MAX_LEN) { + return false; + } + CGPlayerCreate p{}; + p.header = HDR_CG_CHARACTER_CREATE; + p.index = static_cast(slot); + std::memcpy(p.name, name.data(), name.size()); + p.job = static_cast(job); + p.shape = static_cast(shape); + p.con = static_cast(con); + p.intel = static_cast(intel); + p.str = static_cast(str); + p.dex = static_cast(dex); + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::delete_character(int slot, const std::string &private_code) { + if (m_stage != Stage::CharSelect || slot < 0 || slot >= m_parser.slot_count() || + private_code.size() > PRIVATE_CODE_LENGTH) { + return false; + } + CGPlayerDelete p{}; + p.header = HDR_CG_CHARACTER_DELETE; + p.index = static_cast(slot); + std::memcpy(p.private_code, private_code.data(), private_code.size()); + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::change_name(int slot, const std::string &name) { + if (m_stage != Stage::CharSelect || slot < 0 || slot >= m_parser.slot_count() || + name.empty() || name.size() > CHARACTER_NAME_MAX_LEN) { + return false; + } + CGChangeName p{}; + p.header = HDR_CG_CHANGE_NAME; + p.index = static_cast(slot); + std::memcpy(p.name, name.data(), name.size()); + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_empire(uint8_t empire) { + if (m_stage != Stage::CharSelect) { + return false; + } + CGEmpire p{HDR_CG_EMPIRE, empire}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_client_version() { + if (m_version_sent) { + return true; + } + CGClientVersion p{}; + // The stock 40250 game client sends the version report immediately after + // receiving the main-character packet and advances the normal CG sequence. + p.header = HDR_CG_CLIENT_VERSION; + std::strncpy(p.filename, "metin2.bin", sizeof(p.filename) - 1); + std::strncpy(p.timestamp, "1215955205", sizeof(p.timestamp) - 1); + if (!m_stream.send_fixed(&p, sizeof(p))) { + return false; + } + m_version_sent = true; + return true; +} + +void ClassicSession::on_phase(uint8_t phase) { + if (phase == PHASE_LOGIN || phase == PHASE_SELECT || phase == PHASE_LOADING || + phase == PHASE_GAME || phase == PHASE_DEAD) { + m_stream.set_time_sync_mode(true); + } + switch (phase) { + case PHASE_LOGIN: + set_stage(Stage::LoggingIn); + send_login(); + break; + case PHASE_SELECT: + set_stage(Stage::CharSelect); + if (m_parser.char_list_ready() && on_char_list) { + on_char_list(m_parser.char_slots()); + } + break; + case PHASE_LOADING: + set_stage(Stage::Loading); + m_loading_since = m_now; + m_entergame_sent = false; + break; + case PHASE_GAME: + set_stage(Stage::InGame); + if (on_entered_game) { + on_entered_game(); + } + break; + case PHASE_CLOSE: + m_last_error = m_last_error.empty() ? "server closed phase" : m_last_error; + set_stage(Stage::Failed); + break; + default: + break; + } +} + +bool ClassicSession::on_packet(uint8_t header, const uint8_t *body, uint32_t len) { + if (!m_parser.on_gc(header, body, len)) { + m_last_error = "parse error on GC header " + std::to_string(header); + return false; + } + if ((header == HDR_GC_MAIN_CHARACTER || header == HDR_GC_MAIN_CHARACTER3_BGM || + header == HDR_GC_MAIN_CHARACTER4_BGM_VOL) && !send_client_version()) { + m_last_error = "failed to send client version"; + return false; + } + if (!m_parser.login_failure().empty() && m_stage == Stage::LoggingIn) { + m_last_error = "login failed: " + m_parser.login_failure(); + set_stage(Stage::Failed); + return false; + } + return true; +} + +bool ClassicSession::select_char(int slot) { + // Caller-side misuse: return false but don't poison m_last_error, which is + // reserved for transport/protocol failures ("is the connection healthy"). + if (m_stage != Stage::CharSelect) { + return false; + } + if (slot < 0 || slot >= m_parser.slot_count()) { + return false; + } + CGPlayerSelect p{}; + p.header = HDR_CG_CHARACTER_SELECT; + p.player_index = static_cast(slot); + m_stream.send_fixed(&p, sizeof(p)); + return true; +} + +bool ClassicSession::enter_game() { + if (m_entergame_sent) { + return true; + } + CGEnterGame p{}; + p.header = HDR_CG_ENTERGAME; + m_stream.send_fixed(&p, sizeof(p)); + m_entergame_sent = true; + return true; +} + +// --- in-game intents --------------------------------------------------------- + +bool ClassicSession::send_move(uint8_t func, uint8_t arg, float rot_deg, int32_t x, int32_t y, + uint32_t time_ms) { + if (m_stage != Stage::InGame) { + return false; + } + CGMove p{}; + p.header = HDR_CG_MOVE; + p.func = func; + p.arg = arg; + p.rot = static_cast(rot_deg / 5.0f); // classic wire: bRot = deg/5 + p.x = x; + p.y = y; + p.time = time_ms ? time_ms : m_now; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_attack(uint8_t type, uint32_t victim_vid) { + if (m_stage != Stage::InGame) { + return false; + } + CGAttack p{}; + p.header = HDR_CG_ATTACK; + p.type = type; + p.victim_vid = victim_vid; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_chat(uint8_t type, const std::string &text) { + if (m_stage != Stage::InGame || text.empty() || text.size() >= 512) { + return false; + } + // wire: [header][WORD length][BYTE type][text\0]; length = 4 + strlen + 1 + const uint16_t len = static_cast(sizeof(CGChatHead) + text.size() + 1); + std::vector buf(len, 0); + CGChatHead h{}; + h.header = HDR_CG_CHAT; + h.length = len; + h.type = type; + std::memcpy(buf.data(), &h, sizeof(h)); + std::memcpy(buf.data() + sizeof(h), text.data(), text.size()); + // buf[len-1] stays 0 (the trailing NUL) + return m_stream.send_dynamic(buf.data(), buf.size()); +} + +bool ClassicSession::send_target(uint32_t vid) { + if (m_stage != Stage::InGame) { + return false; + } + CGTarget p{HDR_CG_TARGET, vid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_character_position(uint8_t position) { + if (m_stage != Stage::InGame) { + return false; + } + CGPosition p{HDR_CG_CHARACTER_POSITION, position}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_click_npc(uint32_t vid) { + if (m_stage != Stage::InGame) { + return false; + } + CGOnClick p{HDR_CG_ON_CLICK, vid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_script_answer(uint8_t answer) { + if (m_stage != Stage::InGame) { + return false; + } + CGScriptAnswer p{HDR_CG_SCRIPT_ANSWER, answer}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_use(uint8_t window, uint16_t cell) { + if (m_stage != Stage::InGame) { + return false; + } + CGItemUse p{}; + p.header = HDR_CG_ITEM_USE; + p.pos = {window, cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_move(uint8_t window, uint16_t cell, uint8_t to_window, + uint16_t to_cell, uint8_t count) { + if (m_stage != Stage::InGame) { + return false; + } + CGItemMove p{}; + p.header = HDR_CG_ITEM_MOVE; + p.pos = {window, cell}; + p.change_pos = {to_window, to_cell}; + p.num = count; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_drop(uint8_t window, uint16_t cell, uint32_t gold, uint8_t count) { + if (m_stage != Stage::InGame) { + return false; + } + if (count > 0) { + CGItemDrop2 p{}; + p.header = HDR_CG_ITEM_DROP2; + p.pos = {window, cell}; + p.gold = gold; + p.count = count; + return m_stream.send_fixed(&p, sizeof(p)); + } + CGItemDrop p{}; + p.header = HDR_CG_ITEM_DROP; + p.pos = {window, cell}; + p.gold = gold; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_pickup(uint32_t ground_vid) { + if (m_stage != Stage::InGame) { + return false; + } + CGItemPickup p{HDR_CG_ITEM_PICKUP, ground_vid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_use_skill(uint32_t skill_vnum, uint32_t target_vid) { + if (m_stage != Stage::InGame) { + return false; + } + if (target_vid) { + CGFlyTargeting ft{}; + ft.header = HDR_CG_FLY_TARGETING; + ft.target_vid = target_vid; + m_stream.send_fixed(&ft, sizeof(ft)); + } + CGUseSkill p{}; + p.header = HDR_CG_USE_SKILL; + p.vnum = skill_vnum; + p.target_vid = target_vid; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_use_to_item(uint8_t window, uint16_t cell, uint8_t target_window, + uint16_t target_cell) { + if (m_stage != Stage::InGame) { + return false; + } + CGItemUseToItem p{}; + p.header = HDR_CG_ITEM_USE_TO_ITEM; + p.pos = {window, cell}; + p.target_pos = {target_window, target_cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_item_give(uint32_t target_vid, uint8_t window, uint16_t cell, + uint8_t count) { + if (m_stage != Stage::InGame || target_vid == 0 || count == 0) { + return false; + } + CGGiveItem p{}; + p.header = HDR_CG_ITEM_GIVE; + p.target_vid = target_vid; + p.pos = {window, cell}; + p.count = count; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_request_warp() { + if (m_stage != Stage::InGame) { + return false; + } + CGWarp p{HDR_CG_WARP}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_fishing(uint8_t rot) { + if (m_stage != Stage::InGame) { + return false; + } + CGFishing p{HDR_CG_FISHING, rot}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_dungeon() { + if (m_stage != Stage::InGame) { + return false; + } + CGWarp p{HDR_CG_DUNGEON}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_sync_positions(const std::vector &positions) { + if (m_stage != Stage::InGame || positions.empty() || positions.size() > 16) { + return false; + } + const size_t total = sizeof(DynHead) + positions.size() * sizeof(SyncPosElement); + if (total > 0xffffu) { + return false; + } + std::vector buf(total, 0); + DynHead head{HDR_CG_SYNC_POSITION, static_cast(total)}; + std::memcpy(buf.data(), &head, sizeof(head)); + std::memcpy(buf.data() + sizeof(head), positions.data(), + positions.size() * sizeof(SyncPosElement)); + return m_stream.send_fixed(buf.data(), buf.size()); +} + +bool ClassicSession::send_whisper(const std::string &to, const std::string &text) { + if (m_stage != Stage::InGame || to.empty() || to.size() > CHARACTER_NAME_MAX_LEN || + text.empty() || text.size() >= 512) { + return false; + } + const size_t total = sizeof(CGWhisper) + text.size() + 1; + if (total > 0xffffu) { + return false; + } + std::vector buf(total, 0); + CGWhisper p{}; + p.header = HDR_CG_WHISPER; + p.size = static_cast(total); + std::memcpy(p.name_to, to.data(), to.size()); + std::memcpy(buf.data(), &p, sizeof(p)); + std::memcpy(buf.data() + sizeof(p), text.data(), text.size()); + return m_stream.send_dynamic(buf.data(), buf.size()); +} + +bool ClassicSession::send_shoot(uint8_t type) { + if (m_stage != Stage::InGame) { + return false; + } + CGShoot p{HDR_CG_SHOOT, type}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_add_fly_targeting(uint32_t target_vid, int32_t x, int32_t y) { + if (m_stage != Stage::InGame) { + return false; + } + CGFlyTargeting p{HDR_CG_ADD_FLY_TARGETING, target_vid, x, y}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quickslot_add(uint8_t pos, uint8_t type, uint8_t ref) { + if (m_stage != Stage::InGame || pos >= QUICKSLOT_MAX_NUM) { + return false; + } + CGQuickSlotAdd p{HDR_CG_QUICKSLOT_ADD, pos, type, ref}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quickslot_del(uint8_t pos) { + if (m_stage != Stage::InGame || pos >= QUICKSLOT_MAX_NUM) { + return false; + } + CGQuickSlotDel p{HDR_CG_QUICKSLOT_DEL, pos}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quickslot_swap(uint8_t pos, uint8_t pos_to) { + if (m_stage != Stage::InGame || pos >= QUICKSLOT_MAX_NUM || pos_to >= QUICKSLOT_MAX_NUM) { + return false; + } + CGQuickSlotSwap p{HDR_CG_QUICKSLOT_SWAP, pos, pos_to}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_script_button(uint32_t index) { + if (m_stage != Stage::InGame) { + return false; + } + CGScriptButton p{HDR_CG_SCRIPT_BUTTON, index}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_script_select_item(uint32_t selection) { + if (m_stage != Stage::InGame) { + return false; + } + CGScriptSelectItem p{HDR_CG_SCRIPT_SELECT_ITEM, selection}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quest_input(const std::string &text) { + if (m_stage != Stage::InGame || text.size() > 64) { + return false; + } + CGQuestInput p{}; + p.header = HDR_CG_QUEST_INPUT_STRING; + std::memcpy(p.msg, text.data(), text.size()); + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quest_confirm(bool yes, uint32_t request_pid) { + if (m_stage != Stage::InGame) { + return false; + } + CGQuestConfirm p{HDR_CG_QUEST_CONFIRM, static_cast(yes ? 1 : 0), request_pid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_quest_cancel() { + // The classic protocol has no separate CG_QUEST_CANCEL header. The stock + // client closes a script by answering 255 (the same sentinel exposed by + // script_answer()) and the server routes it through ScriptAnswer. + return send_script_answer(255); +} + +bool ClassicSession::send_party_invite(uint32_t vid) { + if (m_stage != Stage::InGame || vid == 0) return false; + CGPartyInvite p{HDR_CG_PARTY_INVITE, vid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_party_answer(uint32_t leader_vid, bool accept) { + if (m_stage != Stage::InGame || leader_vid == 0) return false; + CGPartyInviteAnswer p{HDR_CG_PARTY_INVITE_ANSWER, leader_vid, + static_cast(accept ? 1 : 0)}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_party_remove(uint32_t pid) { + if (m_stage != Stage::InGame || pid == 0) return false; + CGPartyRemove p{HDR_CG_PARTY_REMOVE, pid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_party_set_state(uint32_t pid, uint8_t role, bool on) { + if (m_stage != Stage::InGame || pid == 0) return false; + CGPartySetState p{HDR_CG_PARTY_SET_STATE, pid, role, static_cast(on ? 1 : 0)}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_party_use_skill(uint8_t skill_index, uint32_t vid) { + if (m_stage != Stage::InGame) return false; + CGPartyUseSkill p{HDR_CG_PARTY_USE_SKILL, skill_index, vid}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_party_parameter(uint8_t mode) { + if (m_stage != Stage::InGame) return false; + CGPartyParameter p{HDR_CG_PARTY_PARAMETER, mode}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_shop_buy(uint8_t pos, uint8_t count) { + if (m_stage != Stage::InGame) return false; + uint8_t buf[sizeof(CGShop) + sizeof(CGShopBuy)] = {}; + CGShop head{HDR_CG_SHOP, SHOP_CG_BUY}; + CGShopBuy body{count, pos}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &body, sizeof(body)); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_shop_sell(uint8_t pos, uint8_t count) { + if (m_stage != Stage::InGame) return false; + if (count == 0) { + uint8_t buf[sizeof(CGShop) + sizeof(CGShopSell)] = {}; + CGShop head{HDR_CG_SHOP, SHOP_CG_SELL}; + CGShopSell body{pos}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &body, sizeof(body)); + return m_stream.send_fixed(buf, sizeof(buf)); + } + uint8_t buf[sizeof(CGShop) + sizeof(CGShopSell2)] = {}; + CGShop head{HDR_CG_SHOP, SHOP_CG_SELL2}; + CGShopSell2 body{pos, count}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &body, sizeof(body)); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_shop_close() { + if (m_stage != Stage::InGame) return false; + CGShop p{HDR_CG_SHOP, SHOP_CG_END}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_private_shop(const std::string &sign, + const std::vector &items) { + if (m_stage != Stage::InGame || sign.size() > SHOP_TAB_NAME_MAX) return false; + const size_t n = std::min(items.size(), static_cast(39)); + const size_t total = sizeof(CGMyShopHead) + n * sizeof(CGMyShopItem); + std::vector buf(total, 0); + CGMyShopHead head{}; + head.header = HDR_CG_MYSHOP; + std::memcpy(head.sign, sign.data(), sign.size()); + head.count = static_cast(n); + std::memcpy(buf.data(), &head, sizeof(head)); + if (n > 0) { + std::memcpy(buf.data() + sizeof(head), items.data(), n * sizeof(CGMyShopItem)); + } + return m_stream.send_fixed(buf.data(), buf.size()); +} + +bool ClassicSession::send_cube_make(int result_index) { + // 40250's command handler ignores a recipe index: an argument means + // "make all" while no argument makes one recipe from the currently loaded + // cube slots. Never send the index through as it would unexpectedly craft + // repeatedly and consume every matching material. + (void)result_index; + return send_chat(0, "/cube make"); +} + +bool ClassicSession::send_cube_result_list(int npc_vnum) { + (void)npc_vnum; // 40250 derives the active NPC from the selected cube context. + return send_chat(0, "/cube r_info"); +} + +bool ClassicSession::send_cube_materials(int start_index, int count) { + if (start_index < 0 || count < 1 || start_index > 255 || count > 255) return false; + return send_chat(0, "/cube r_info " + std::to_string(start_index) + " " + + std::to_string(count)); +} + +bool ClassicSession::send_cube_open() { + return send_chat(0, "/cube open"); +} + +bool ClassicSession::send_cube_close() { + return send_chat(0, "/cube close"); +} + +bool ClassicSession::send_cube_list() { + return send_chat(0, "/cube list"); +} + +bool ClassicSession::send_cube_add_item(int cube_index, int inventory_index) { + if (cube_index < 0 || cube_index >= 24 || inventory_index < 0 || inventory_index > 255) { + return false; + } + return send_chat(0, "/cube add " + std::to_string(cube_index) + " " + + std::to_string(inventory_index)); +} + +bool ClassicSession::send_cube_delete_item(int cube_index) { + if (cube_index < 0 || cube_index >= 24) return false; + return send_chat(0, "/cube delete " + std::to_string(cube_index)); +} + +bool ClassicSession::send_guild_sub(uint8_t subheader) { + if (m_stage != Stage::InGame) return false; + CGGuild p{HDR_CG_GUILD, subheader}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_guild_u32(uint8_t subheader, uint32_t value) { + if (m_stage != Stage::InGame) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(value)] = {}; + CGGuild head{HDR_CG_GUILD, subheader}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &value, sizeof(value)); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_i32(uint8_t subheader, int32_t value) { + if (m_stage != Stage::InGame) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(value)] = {}; + CGGuild head{HDR_CG_GUILD, subheader}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &value, sizeof(value)); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_grade_name(uint8_t grade, const std::string &name) { + if (m_stage != Stage::InGame || grade == 0 || grade >= 16 || name.empty() || + name.size() > GUILD_GRADE_NAME_MAX_LEN) return false; + uint8_t buf[sizeof(CGGuild) + 1 + GUILD_GRADE_NAME_MAX_LEN + 1] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_CHANGE_GRADE_NAME}; + std::memcpy(buf, &head, sizeof(head)); + buf[sizeof(head)] = grade; + std::memcpy(buf + sizeof(head) + 1, name.data(), name.size()); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_grade_authority(uint8_t grade, uint8_t authority) { + if (m_stage != Stage::InGame || grade == 0 || grade >= 16) return false; + uint8_t buf[sizeof(CGGuild) + 2] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_CHANGE_GRADE_AUTHORITY}; + std::memcpy(buf, &head, sizeof(head)); + buf[sizeof(head)] = grade; + buf[sizeof(head) + 1] = authority; + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_member_grade(uint32_t pid, uint8_t grade) { + if (m_stage != Stage::InGame || pid == 0 || grade == 0 || grade >= 16) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(pid) + 1] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_CHANGE_MEMBER_GRADE}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &pid, sizeof(pid)); + buf[sizeof(head) + sizeof(pid)] = grade; + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_member_general(uint32_t pid, bool enabled) { + if (m_stage != Stage::InGame || pid == 0) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(pid) + 1] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_CHANGE_MEMBER_GENERAL}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &pid, sizeof(pid)); + buf[sizeof(head) + sizeof(pid)] = enabled ? 1 : 0; + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_comment(const std::string &text) { + if (m_stage != Stage::InGame || text.empty() || + text.size() + 1 > GUILD_COMMENT_MAX_LEN) return false; + std::vector buf(sizeof(CGGuild) + 1 + text.size() + 1, 0); + CGGuild head{HDR_CG_GUILD, GUILD_CG_POST_COMMENT}; + std::memcpy(buf.data(), &head, sizeof(head)); + buf[sizeof(head)] = static_cast(text.size() + 1); + if (!text.empty()) { + std::memcpy(buf.data() + sizeof(head) + 1, text.data(), text.size()); + } + return m_stream.send_fixed(buf.data(), buf.size()); +} + +bool ClassicSession::send_guild_invite_answer(uint32_t guild_id, bool accept) { + if (m_stage != Stage::InGame) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(guild_id) + 1] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_GUILD_INVITE_ANSWER}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &guild_id, sizeof(guild_id)); + buf[sizeof(head) + sizeof(guild_id)] = accept ? 1 : 0; + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_guild_answer_make(const std::string &name) { + if (m_stage != Stage::InGame || name.empty() || name.size() > GUILD_NAME_MAX_LEN) return false; + CGAnswerMakeGuild p{}; + p.header = HDR_CG_ANSWER_MAKE_GUILD; + std::memcpy(p.guild_name, name.data(), name.size()); + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_guild_skill(uint32_t skill_vnum, uint32_t target_pid) { + if (m_stage != Stage::InGame) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(CGGuildUseSkill)] = {}; + CGGuild head{HDR_CG_GUILD, GUILD_CG_USE_SKILL}; + CGGuildUseSkill body{skill_vnum, target_pid}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &body, sizeof(body)); + return m_stream.send_fixed(buf, sizeof(buf)); +} + +bool ClassicSession::send_refine(uint8_t pos, uint8_t type) { + if (m_stage != Stage::InGame) return false; + CGRefine p{HDR_CG_REFINE, pos, type}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_dragon_soul_refine(uint8_t subheader, const ItemPos *grid, size_t count) { + if (m_stage != Stage::InGame || !grid || count > DS_REFINE_GRID_MAX_NUM) return false; + CGDragonSoulRefine p{}; + p.header = HDR_CG_DRAGON_SOUL_REFINE; + p.subheader = subheader; + std::memcpy(p.grid, grid, count * sizeof(ItemPos)); + return m_stream.send_fixed(&p, sizeof(p)); +} + +namespace { +bool valid_character_name(const std::string &name) { + return !name.empty() && name.size() < CHARACTER_NAME_MAX_LEN; +} +} + +bool ClassicSession::send_friend_add(const std::string &name) { + if (m_stage != Stage::InGame || !valid_character_name(name)) { + return false; + } + // Messenger's extra payload is not length-prefixed: the server consumes a + // fixed CHARACTER_NAME_MAX_LEN byte buffer after the two-byte base header. + std::vector buf(sizeof(CGMessenger) + CHARACTER_NAME_MAX_LEN, 0); + CGMessenger p{HDR_CG_MESSENGER, MESSENGER_CG_ADD_BY_NAME}; + std::memcpy(buf.data(), &p, sizeof(p)); + std::memcpy(buf.data() + sizeof(p), name.data(), name.size()); + return m_stream.send_fixed(buf.data(), buf.size()); +} + +bool ClassicSession::send_friend_remove(const std::string &name) { + if (m_stage != Stage::InGame || !valid_character_name(name)) { + return false; + } + std::vector buf(sizeof(CGMessenger) + CHARACTER_NAME_MAX_LEN, 0); + CGMessenger p{HDR_CG_MESSENGER, MESSENGER_CG_REMOVE}; + std::memcpy(buf.data(), &p, sizeof(p)); + std::memcpy(buf.data() + sizeof(p), name.data(), name.size()); + return m_stream.send_fixed(buf.data(), buf.size()); +} + +bool ClassicSession::send_exchange_start(uint32_t partner_vid) { + if (m_stage != Stage::InGame) { + return false; + } + CGExchange p{}; + p.header = HDR_CG_EXCHANGE; + p.subheader = EXCHANGE_CG_START; + p.arg1 = partner_vid; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_exchange_item_add(uint8_t inv_window, uint16_t inv_cell, + uint8_t display_pos) { + if (m_stage != Stage::InGame) { + return false; + } + CGExchange p{}; + p.header = HDR_CG_EXCHANGE; + p.subheader = EXCHANGE_CG_ITEM_ADD; + p.arg2 = display_pos; + p.pos = {inv_window, inv_cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_exchange_gold(uint32_t gold) { + if (m_stage != Stage::InGame) { + return false; + } + CGExchange p{}; + p.header = HDR_CG_EXCHANGE; + p.subheader = EXCHANGE_CG_GOLD_ADD; + p.arg1 = gold; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_exchange_accept() { + if (m_stage != Stage::InGame) { + return false; + } + CGExchange p{}; + p.header = HDR_CG_EXCHANGE; + p.subheader = EXCHANGE_CG_ACCEPT; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_exchange_cancel() { + if (m_stage != Stage::InGame) { + return false; + } + CGExchange p{}; + p.header = HDR_CG_EXCHANGE; + p.subheader = EXCHANGE_CG_CANCEL; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_safebox_checkin(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) { + if (m_stage != Stage::InGame) { + return false; + } + CGSafeboxCheckin p{}; + p.header = HDR_CG_SAFEBOX_CHECKIN; + p.safe_pos = safe_pos; + p.item_pos = {inv_window, inv_cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_safebox_checkout(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) { + if (m_stage != Stage::InGame) { + return false; + } + CGSafeboxCheckout p{}; + p.header = HDR_CG_SAFEBOX_CHECKOUT; + p.safe_pos = safe_pos; + p.item_pos = {inv_window, inv_cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_safebox_move(uint16_t from_cell, uint16_t to_cell, uint8_t count) { + if (m_stage != Stage::InGame) { + return false; + } + CGItemMove p{}; + p.header = HDR_CG_SAFEBOX_ITEM_MOVE; + // The stock 40250 client sends inventory-window positions; the active + // safebox context tells the server these positions refer to the safebox. + p.pos = {WINDOW_INVENTORY, from_cell}; + p.change_pos = {WINDOW_INVENTORY, to_cell}; + p.num = count; + return m_stream.send_fixed(&p, sizeof(p)); +} + +bool ClassicSession::send_mall_checkout(uint8_t mall_pos, uint8_t inv_window, + uint16_t inv_cell) { + if (m_stage != Stage::InGame) { + return false; + } + CGMallCheckout p{}; + p.header = HDR_CG_MALL_CHECKOUT; + p.mall_pos = mall_pos; + p.item_pos = {inv_window, inv_cell}; + return m_stream.send_fixed(&p, sizeof(p)); +} + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_session.h b/extension/src/net/classic/classic_session.h new file mode 100644 index 00000000..4d1fd8b6 --- /dev/null +++ b/extension/src/net/classic/classic_session.h @@ -0,0 +1,169 @@ +#pragma once +// ClassicSession — MT_PROTOCOL=classic: drives ClassicStream through +// HANDSHAKE -> LOGIN -> SELECT -> LOADING -> GAME and parses GC packets into a +// shared EntityStore. See docs/CLIENT-40250-PORT.md §4 / §8. +// +// The stock 40250 server uses _IMPROVED_PACKET_ENCRYPTION_; ClassicStream +// negotiates that DH2 + CTR session before the first login packet. + +#include "classic_parser.h" +#include "classic_stream.h" +#include "wire_classic.h" + +#include "../entity_store.h" +#include "../i_net_session.h" + +#include +#include +#include +#include + +namespace mtnet::classic { + +class ClassicSession : public mtnet::INetSession { +public: + ClassicSession(); + + // --- INetSession --- + bool connect(const std::string &game_host, uint16_t game_port, const std::string &id, + const std::string &pw) override; + void disconnect() override; + bool select_char(int slot) override; + bool enter_game() override; + bool create_character(int slot, const std::string &name, int job, int shape, + int con, int intel, int str, int dex); + bool delete_character(int slot, const std::string &private_code); + bool change_name(int slot, const std::string &name); + bool send_empire(uint8_t empire); + void pump() override; + Stage stage() const override { return m_stage; } + const std::string &last_error() const override { return m_last_error; } + EntityStore &world() override { return m_world; } + + bool send_move(uint8_t func, uint8_t arg, float rot_deg, int32_t x, int32_t y, + uint32_t time_ms = 0) override; + bool send_attack(uint8_t type, uint32_t victim_vid) override; + bool send_chat(uint8_t type, const std::string &text) override; + bool send_target(uint32_t vid) override; + bool send_character_position(uint8_t position) override; + bool send_click_npc(uint32_t vid) override; + bool send_script_answer(uint8_t answer) override; + bool send_item_use(uint8_t window, uint16_t cell) override; + bool send_item_move(uint8_t window, uint16_t cell, uint8_t to_window, uint16_t to_cell, + uint8_t count) override; + bool send_item_drop(uint8_t window, uint16_t cell, uint32_t gold, uint8_t count) override; + bool send_item_pickup(uint32_t ground_vid) override; + bool send_use_skill(uint32_t skill_vnum, uint32_t target_vid) override; + bool send_item_use_to_item(uint8_t window, uint16_t cell, uint8_t target_window, + uint16_t target_cell); + bool send_item_give(uint32_t target_vid, uint8_t window, uint16_t cell, uint8_t count); + bool send_request_warp(); + bool send_fishing(uint8_t rot); + bool send_dungeon(); + bool send_sync_positions(const std::vector &positions); + bool send_whisper(const std::string &to, const std::string &text); + bool send_shoot(uint8_t type); + bool send_add_fly_targeting(uint32_t target_vid, int32_t x, int32_t y); + bool send_quickslot_add(uint8_t pos, uint8_t type, uint8_t ref); + bool send_quickslot_del(uint8_t pos); + bool send_quickslot_swap(uint8_t pos, uint8_t pos_to); + bool send_script_button(uint32_t index); + bool send_script_select_item(uint32_t selection); + bool send_quest_input(const std::string &text); + bool send_quest_confirm(bool yes, uint32_t request_pid); + bool send_quest_cancel(); + bool send_party_invite(uint32_t vid); + bool send_party_answer(uint32_t leader_vid, bool accept); + bool send_party_remove(uint32_t pid); + bool send_party_set_state(uint32_t pid, uint8_t role, bool on); + bool send_party_use_skill(uint8_t skill_index, uint32_t vid); + bool send_party_parameter(uint8_t mode); + bool send_shop_buy(uint8_t pos, uint8_t count); + bool send_shop_sell(uint8_t pos, uint8_t count); + bool send_shop_close(); + bool send_private_shop(const std::string &sign, const std::vector &items); + bool send_cube_make(int result_index); + bool send_cube_result_list(int npc_vnum); + bool send_cube_materials(int start_index, int count); + bool send_cube_open(); + bool send_cube_close(); + bool send_cube_list(); + bool send_cube_add_item(int cube_index, int inventory_index); + bool send_cube_delete_item(int cube_index); + bool send_guild_sub(uint8_t subheader); + bool send_guild_u32(uint8_t subheader, uint32_t value); + bool send_guild_i32(uint8_t subheader, int32_t value); + bool send_guild_grade_name(uint8_t grade, const std::string &name); + bool send_guild_grade_authority(uint8_t grade, uint8_t authority); + bool send_guild_member_grade(uint32_t pid, uint8_t grade); + bool send_guild_member_general(uint32_t pid, bool enabled); + bool send_guild_comment(const std::string &text); + bool send_guild_invite_answer(uint32_t guild_id, bool accept); + bool send_guild_answer_make(const std::string &name); + bool send_guild_skill(uint32_t skill_vnum, uint32_t target_pid); + bool send_refine(uint8_t pos, uint8_t type); + bool send_dragon_soul_refine(uint8_t subheader, const ItemPos *grid, size_t count); + bool send_friend_add(const std::string &name) override; + bool send_friend_remove(const std::string &name) override; + bool send_exchange_start(uint32_t partner_vid) override; + bool send_exchange_item_add(uint8_t inv_window, uint16_t inv_cell, + uint8_t display_pos) override; + bool send_exchange_gold(uint32_t gold) override; + bool send_exchange_accept() override; + bool send_exchange_cancel() override; + bool send_safebox_checkin(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) override; + bool send_safebox_checkout(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) override; + bool send_safebox_move(uint16_t from_cell, uint16_t to_cell, uint8_t count) override; + bool send_mall_checkout(uint8_t mall_pos, uint8_t inv_window, + uint16_t inv_cell) override; + + // --- callbacks --- + std::function &)> on_char_list; + std::function on_entered_game; + std::function on_stage_change; + std::function on_error; + + // Set up creds + state WITHOUT opening a socket — feed the stream by hand via + // stream().feed()/take_outgoing(). Used by the offline flow test and any + // non-TCP transport. connect() == start_offline() + m_stream.connect(). + void start_offline(const std::string &id, const std::string &pw); + + // --- accessors --- + const std::vector &char_slots() const { return m_parser.char_slots(); } + ClassicStream &stream() { return m_stream; } // for tests / trace + ClassicParser &parser() { return m_parser; } + uint32_t now_ms() const { return m_now; } + void set_now(uint32_t ms) { + m_now = ms; + m_world.set_now(ms); + } + // auto-send CG_ENTERGAME this many ms after entering PHASE_LOADING (0 = never, + // caller drives enter_game()). Default mirrors the m2dev client's ~1.5s. + void set_auto_entergame_delay(uint32_t ms) { m_entergame_delay = ms; } + void set_wire_trace(bool on) { m_stream.set_wire_trace(on); } + +private: + void set_stage(Stage s); + void on_phase(uint8_t phase); + bool on_packet(uint8_t header, const uint8_t *body, uint32_t len); + void send_login(); + bool send_client_version(); + + EntityStore m_world; + ClassicStream m_stream; + ClassicParser m_parser; + + Stage m_stage = Stage::Offline; + std::string m_last_error; + std::string m_id, m_pw; + uint32_t m_now = 0; + uint32_t m_loading_since = 0; + uint32_t m_entergame_delay = 1500; + bool m_entergame_sent = false; + bool m_login_sent = false; + bool m_version_sent = false; +}; + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_stream.cpp b/extension/src/net/classic/classic_stream.cpp new file mode 100644 index 00000000..da5489e7 --- /dev/null +++ b/extension/src/net/classic/classic_stream.cpp @@ -0,0 +1,499 @@ +#include "classic_stream.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mtnet::classic { + +namespace { +constexpr size_t RECV_CHUNK = 32 * 1024; + +uint32_t now_ms() { + using namespace std::chrono; + return static_cast( + duration_cast(steady_clock::now().time_since_epoch()).count()); +} + +void set_nonblocking(int fd) { + int fl = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, fl | O_NONBLOCK); +} +} // namespace + +ClassicStream::~ClassicStream() { + disconnect(); +} + +void ClassicStream::set_state(State s) { + if (m_state == s) { + return; + } + m_state = s; + if (on_state_change) { + on_state_change(s); + } +} + +// --------------------------------------------------------------------- socket +bool ClassicStream::connect(const std::string &host, uint16_t port) { + disconnect(); + + addrinfo hints{}; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + addrinfo *res = nullptr; + char portbuf[8]; + std::snprintf(portbuf, sizeof(portbuf), "%u", port); + if (getaddrinfo(host.c_str(), portbuf, &hints, &res) != 0 || !res) { + m_last_error = "getaddrinfo(" + host + ") failed"; + return false; + } + + m_sock = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (m_sock < 0) { + m_last_error = std::string("socket: ") + std::strerror(errno); + freeaddrinfo(res); + return false; + } + set_nonblocking(m_sock); + int one = 1; + setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); + + int rc = ::connect(m_sock, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + if (rc == 0) { + set_state(State::Online); + } else if (errno == EINPROGRESS || errno == EWOULDBLOCK) { + set_state(State::Connecting); + } else { + m_last_error = std::string("connect: ") + std::strerror(errno); + ::close(m_sock); + m_sock = -1; + return false; + } + return true; +} + +void ClassicStream::disconnect() { + if (m_sock >= 0) { + ::close(m_sock); + m_sock = -1; + } + m_recv.clear(); + m_send.clear(); + m_seq_idx = 0; + m_seq_on = false; + m_handshake_seen = false; + m_cipher.clean_up(); + set_state(State::Offline); +} + +void ClassicStream::decrypt_appended(size_t n) { + if (n == 0 || !m_cipher.activated()) { + return; + } + // the n bytes just written sit at the tail of the unread region + m_cipher.decrypt(m_recv.mutable_unread() + (m_recv.readable() - n), n); +} + +bool ClassicStream::recv_into_buffer() { + uint8_t *dst = m_recv.reserve_write(RECV_CHUNK); + ssize_t n = ::recv(m_sock, dst, RECV_CHUNK, 0); + if (n > 0) { + m_recv.commit_write(static_cast(n), RECV_CHUNK); + decrypt_appended(static_cast(n)); + return true; + } + m_recv.commit_write(0, RECV_CHUNK); + if (n == 0) { + m_last_error = "peer closed"; + return false; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return true; + } + m_last_error = std::string("recv: ") + std::strerror(errno); + return false; +} + +bool ClassicStream::flush_send() { + while (m_send.readable() > 0) { + ssize_t n = ::send(m_sock, m_send.read_ptr(), m_send.readable(), 0); + if (n > 0) { + m_send.discard(static_cast(n)); + continue; + } + if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + break; + } + m_last_error = std::string("send: ") + std::strerror(errno); + return false; + } + return true; +} + +void ClassicStream::process() { + if (m_sock < 0) { + return; + } + if (m_state == State::Connecting) { + int err = 0; + socklen_t len = sizeof(err); + if (getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0 || err != 0) { + m_last_error = "connect failed"; + disconnect(); + return; + } + set_state(State::Online); + } + if (!recv_into_buffer()) { + disconnect(); + return; + } + dispatch(); + if (m_sock >= 0 && !flush_send()) { + disconnect(); + } +} + +// ----------------------------------------------------------------- framing core +void ClassicStream::feed(const void *data, size_t n) { + m_recv.write(data, n); + decrypt_appended(n); + dispatch(); +} + +void ClassicStream::emit_bytes(const void *p, size_t n) { + if (!m_cipher.activated()) { + m_send.write(p, n); + return; + } + // CTR stream: encrypt in call order; the encoder keeps its counter across calls. + std::string tmp(static_cast(p), n); + m_cipher.encrypt(tmp.data(), n); + m_send.write(tmp.data(), n); +} + +size_t ClassicStream::take_outgoing(void *dst, size_t cap) { + size_t n = m_send.readable() < cap ? m_send.readable() : cap; + if (n) { + std::memcpy(dst, m_send.read_ptr(), n); + m_send.discard(n); + } + return n; +} + +void ClassicStream::append_sequence_if_needed(uint8_t header) { + if (!m_seq_on || !is_sequence_cg(header)) { + return; + } + uint8_t seq = SEQUENCE_TABLE[m_seq_idx]; + m_seq_idx = (m_seq_idx + 1) % SEQUENCE_TABLE_SIZE; + emit_bytes(&seq, 1); +} + +bool ClassicStream::send_fixed(const void *struct_bytes, size_t n) { + if (n == 0) { + return false; + } + uint8_t header = *static_cast(struct_bytes); + emit_bytes(struct_bytes, n); + append_sequence_if_needed(header); + if (m_trace) { + std::fprintf(stderr, "[classic] send hdr=%u n=%zu seq=%d\n", header, n, + (m_seq_on && is_sequence_cg(header))); + } + return true; +} + +bool ClassicStream::send_dynamic(const void *bytes, size_t n) { + if (n < sizeof(DynHead)) { + return false; + } + uint8_t header = *static_cast(bytes); + emit_bytes(bytes, n); + append_sequence_if_needed(header); + return true; +} + +// ----------------------------------------------------------------- dispatch +bool ClassicStream::handle_control(uint8_t header, bool &consumed) { + consumed = false; + switch (header) { + case HDR_HANDSHAKE: { + Handshake hs{}; + if (!m_recv.peek(&hs, sizeof(hs))) { + return true; // need more + } + m_recv.discard(sizeof(hs)); + consumed = true; + // mirror EterLib/PythonNetworkStreamPhaseHandshake.cpp + desc.cpp: + m_server_time_base = hs.time + static_cast(hs.delta); + m_client_time_base = now_ms(); + hs.time = hs.time + 2u * static_cast(hs.delta); + hs.delta = 0; + const bool initial = !m_handshake_seen; + m_handshake_seen = true; + if (!initial && m_time_sync_mode) { + // PythonNetworkStreamPhaseHandShake.cpp uses 0xFF only for the + // first handshake. Select/Game phase resyncs are sent as the + // same struct with header 0xFC and the next sequence byte. + hs.header = HDR_CG_TIME_SYNC; + send_fixed(&hs, sizeof(hs)); + } else { + // Initial handshake (and the mark side's repeated login + // handshake) stays 0xFF and has no sequence byte. + emit_bytes(&hs, sizeof(hs)); + } + if (on_server_handshake) { + on_server_handshake(); + } + if (m_trace) { + std::fprintf(stderr, "[classic] handshake echo time=%u\n", hs.time); + } + return true; + } + case HDR_GC_TIME_SYNC: { // 0xFC — 1-byte "handshake ok" blank (re-sync path) + Blank b{}; + if (!m_recv.peek(&b, sizeof(b))) { + return true; + } + m_recv.discard(sizeof(b)); + consumed = true; + if (on_handshake_ok) { + on_handshake_ok(); + } + return true; + } + case HDR_GC_PHASE: { + Phase_ p{}; + if (!m_recv.peek(&p, sizeof(p))) { + return true; + } + m_recv.discard(sizeof(p)); + consumed = true; + if (m_trace) { + std::fprintf(stderr, "[classic] phase -> %u\n", p.phase); + } + if (on_phase) { + on_phase(p.phase); + } + return true; + } + case HDR_GC_PING: { + Blank b{}; + if (!m_recv.peek(&b, sizeof(b))) { + return true; + } + m_recv.discard(sizeof(b)); + consumed = true; + uint8_t pong = HDR_CG_PONG; // 0xFE + send_fixed(&pong, 1); // CG_PONG is bSeq=true (sizeof(BYTE)+seq) + return true; + } + case HDR_GC_BINDUDP: { + BindUDP u{}; + if (!m_recv.peek(&u, sizeof(u))) { + return true; + } + m_recv.discard(sizeof(u)); + consumed = true; + return true; // UDP not used + } + case HDR_KEY_AGREEMENT: { // 0xFB — GC_KEY_AGREEMENT (server's DH2 blob) + if (m_recv.readable() < sizeof(KeyAgreement)) { + return true; // need the whole 261-byte packet (consumed stays false) + } + consumed = true; + return handle_key_agreement(); + } + case HDR_GC_KEY_AGREEMENT_COMPLETED: { // 0xFA + KeyAgreementCompleted kac{}; + if (!m_recv.peek(&kac, sizeof(kac))) { + return true; + } + m_recv.discard(sizeof(kac)); + consumed = true; + m_cipher.set_activated(true); + // the server may have pipelined encrypted bytes right behind this; + // decrypt whatever's already buffered before we dispatch it. + if (m_recv.readable() > 0) { + m_cipher.decrypt(m_recv.mutable_unread(), m_recv.readable()); + } + if (m_trace) { + std::fprintf(stderr, "[classic] cipher activated\n"); + } + if (on_cipher_active) { + on_cipher_active(); + } + return true; + } + default: + return true; // not a control header + } +} + +bool ClassicStream::handle_key_agreement() { + KeyAgreement pkt{}; + if (!m_recv.peek(&pkt, sizeof(pkt))) { + return true; // need the whole 261-byte packet + } + m_recv.discard(sizeof(pkt)); + + // generate our own DH2 public blob + KeyAgreement out{}; + out.header = HDR_KEY_AGREEMENT; // CG_KEY_AGREEMENT (same 0xFB) + size_t data_len = sizeof(out.data); + size_t agreed = m_cipher.prepare(out.data, &data_len); + if (agreed == 0) { + m_last_error = "classic cipher: DH2 Prepare failed"; + if (on_error) { + on_error(m_last_error); + } + return false; + } + out.agreed_length = static_cast(agreed); + out.data_length = static_cast(data_len); + + // derive keys from the peer's blob (does NOT flip activated_ yet) + if (!m_cipher.activate(m_polarity, pkt.agreed_length, pkt.data, pkt.data_length)) { + m_last_error = "classic cipher: DH2 Agree/SetUp failed"; + if (on_error) { + on_error(m_last_error); + } + return false; + } + + // reply with our blob — still plaintext (peer activates on its own COMPLETED) + emit_bytes(&out, sizeof(out)); + if (m_trace) { + std::fprintf(stderr, "[classic] key agreement: replied, keys ready\n"); + } + return true; +} + +void ClassicStream::dispatch() { + for (;;) { + if (m_recv.readable() == 0) { + return; + } + uint8_t header = *m_recv.read_ptr(); + + // zero padding between packets (cipher block alignment on the m2dev side; + // harmless to skip here too). + if (header == 0) { + m_recv.discard(1); + continue; + } + + bool consumed = false; + if (!handle_control(header, consumed)) { + if (on_error && m_last_error.empty()) { + on_error("dispatch aborted"); + } + disconnect(); + return; + } + if (consumed) { + continue; + } + // control handler said "need more bytes" for a control header it owns? + if (header == HDR_HANDSHAKE || header == HDR_GC_TIME_SYNC || header == HDR_GC_PHASE || + header == HDR_GC_PING || header == HDR_GC_BINDUDP || header == HDR_KEY_AGREEMENT || + header == HDR_GC_KEY_AGREEMENT_COMPLETED) { + return; // wait for the rest of this control packet + } + + // Some side connections share the classic cipher/control handshake but + // have their own packet framing. Give that connection a chance before + // the normal GC static/dynamic table is consulted. + if (on_raw_packet) { + RawPacketResult raw = on_raw_packet(header, m_recv.read_ptr(), m_recv.readable()); + switch (raw.status) { + case RawPacketStatus::NeedMore: + return; + case RawPacketStatus::Consumed: + if (raw.bytes == 0 || raw.bytes > m_recv.readable()) { + m_last_error = "raw packet consumed invalid byte count"; + if (on_error) { + on_error(m_last_error); + } + disconnect(); + return; + } + m_recv.discard(raw.bytes); + continue; + case RawPacketStatus::Error: + m_last_error = "raw packet framing error"; + if (on_error) { + on_error(m_last_error); + } + disconnect(); + return; + case RawPacketStatus::NotHandled: + break; + } + } + + // --- dynamic-size GC packet --- + if (is_dynamic_gc(header)) { + DynHead dh{}; + if (!m_recv.peek(&dh, sizeof(dh))) { + return; + } + if (dh.size < sizeof(DynHead)) { + m_last_error = "dynamic packet size underflow"; + if (on_error) { + on_error(m_last_error); + } + disconnect(); + return; + } + if (m_recv.readable() < dh.size) { + return; // whole packet not here yet + } + m_recv.discard(sizeof(DynHead)); + uint32_t body_len = dh.size - sizeof(DynHead); + const uint8_t *body = m_recv.read_ptr(); + bool ok = !on_packet || on_packet(header, body, body_len); + m_recv.discard(body_len); + if (!ok) { + disconnect(); + return; + } + continue; + } + + // --- static-size GC packet --- (packet_size_gc = FULL size incl. header) + int total = packet_size_gc(header); + if (total <= 0) { + m_last_error = "unknown/unsupported GC header " + std::to_string(header); + if (on_error) { + on_error(m_last_error); + } + disconnect(); + return; + } + if (m_recv.readable() < static_cast(total)) { + return; + } + const uint8_t *p = m_recv.read_ptr(); + bool ok = !on_packet || on_packet(header, p + 1, static_cast(total - 1)); + m_recv.discard(static_cast(total)); + if (!ok) { + disconnect(); + return; + } + } +} + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/classic_stream.h b/extension/src/net/classic/classic_stream.h new file mode 100644 index 00000000..108638a1 --- /dev/null +++ b/extension/src/net/classic/classic_stream.h @@ -0,0 +1,132 @@ +#pragma once +// ClassicStream — 40250 "classic" Metin2 framing over non-blocking TCP. +// The `MT_PROTOCOL=classic` counterpart of mtnet::NetStream (m2dev fork). +// See docs/CLIENT-40250-PORT.md §2 (framing) / §4 (handshake / phase). +// +// 1-byte header -> static size table (wire_classic.h) OR dynamic `uint16 size`. +// CG game packets append a trailing sequence byte once sequence mode is on. +// Control packets (HANDSHAKE / TIME_SYNC / PHASE / PING / BINDUDP) are handled +// here; everything else goes to on_packet(header, body, len). +// +// Encryption (Crypto++ DH2 + CTR, docs §3) is negotiated in the stream before +// phase/login packets are dispatched. +// +// Testability: feed()/take_outgoing() drive the framing synchronously with no +// socket; connect()/process() add the real POSIX I/O on top. + +#include "classic_cipher.h" +#include "sequence_table.h" +#include "wire_classic.h" + +#include "../byte_buffer.h" + +#include +#include +#include + +namespace mtnet::classic { + +class ClassicStream { +public: + enum class State { Offline, Connecting, Online }; + enum class RawPacketStatus { NotHandled, NeedMore, Consumed, Error }; + struct RawPacketResult { + RawPacketStatus status = RawPacketStatus::NotHandled; + size_t bytes = 0; + }; + + ClassicStream() = default; + ~ClassicStream(); + + // --- callbacks (set before connect/feed) --- + std::function on_state_change; + // Fired after the initial GC_HANDSHAKE has been consumed and echoed. The + // 40250 guild-mark side sends CG_MARK_LOGIN at this point, before the + // normal game-side key agreement/phase transition. + std::function on_server_handshake; + std::function on_phase; // GC_PHASE + std::function on_handshake_ok; // time sync converged + std::function on_cipher_active; // GC_KEY_AGREEMENT_COMPLETED + // A non-control packet is fully buffered. `body` covers the bytes AFTER the + // header byte (for dynamic packets: after the header+size prefix), `len` its + // length. Return false to abort the connection. + std::function on_packet; + // Optional protocol-specific framing hook. The 40250 mark side uses a + // one-byte header followed by a u32 whole-packet size for GC_MARK_* packets, + // instead of the normal static/dynamic game packet map. + // Return the exact number of bytes consumed when status == Consumed. + std::function + on_raw_packet; + std::function on_error; + + // --- real socket lifecycle --- + bool connect(const std::string &host, uint16_t port); + void disconnect(); + void process(); // one recv() + dispatch + one send() flush + State state() const { return m_state; } + bool is_online() const { return m_state == State::Online; } + const std::string &last_error() const { return m_last_error; } + + // --- socket-free framing (tests / alternative transports) --- + void feed(const void *data, size_t n); // append inbound bytes, run dispatch + size_t take_outgoing(void *dst, size_t cap); + size_t outgoing_pending() const { return m_send.readable(); } + + // --- sending --- + // `struct_bytes[0]` must already be the header byte; frames the body and + // appends the sequence byte when sequence mode is on and the header is bSeq. + bool send_fixed(const void *struct_bytes, size_t n); + // Caller supplies the full dynamic packet incl. [header][uint16 size][...]. + bool send_dynamic(const void *bytes, size_t n); + + // docs §2.2: turn on once the client would call net.SetPacketSequenceMode() + // (LOGIN phase onward). Off during pure HANDSHAKE. + void set_sequence_mode(bool on) { m_seq_on = on; } + bool sequence_mode() const { return m_seq_on; } + uint32_t sequence_index() const { return m_seq_idx; } + + // The normal game connection changes later GC_HANDSHAKE packets into + // CG_TIME_SYNC. The guild-mark connection is a special case: the stock + // downloader keeps answering with CG_MARK_LOGIN, so it leaves this off. + void set_time_sync_mode(bool on) { m_time_sync_mode = on; } + + void set_wire_trace(bool on) { m_trace = on; } + + // _IMPROVED_PACKET_ENCRYPTION_ (docs §3). Client polarity = true. + bool cipher_active() const { return m_cipher.activated(); } + void set_polarity(bool client) { m_polarity = client; } + +private: + void set_state(State s); + bool recv_into_buffer(); + bool flush_send(); + void dispatch(); // consume complete packets from m_recv + bool handle_control(uint8_t header, bool &consumed); + // append + (if the cipher is live) encrypt bytes into the send buffer. + void emit_bytes(const void *p, size_t n); + void append_sequence_if_needed(uint8_t header); + bool handle_key_agreement(); + void decrypt_appended(size_t n); // decrypt the last n bytes just written to m_recv + + int m_sock = -1; + State m_state = State::Offline; + std::string m_last_error; + + ByteBuffer m_recv; + ByteBuffer m_send; + + ClassicCipher m_cipher; + bool m_polarity = true; // client + + bool m_seq_on = false; + uint32_t m_seq_idx = 0; + bool m_handshake_seen = false; + bool m_time_sync_mode = false; + bool m_trace = false; + + // server clock offset from the last handshake exchange (informational). + uint32_t m_server_time_base = 0; + uint32_t m_client_time_base = 0; +}; + +} // namespace mtnet::classic diff --git a/extension/src/net/classic/sequence_table.h b/extension/src/net/classic/sequence_table.h new file mode 100644 index 00000000..87253050 --- /dev/null +++ b/extension/src/net/classic/sequence_table.h @@ -0,0 +1,2062 @@ +#pragma once +// 40250 client sequence table — verbatim copy of EterLib/NetStream.cpp:881 +// s_bSequenceTable[SEQUENCE_TABLE_SIZE]. Must match the server's gc_abSequence[] +// (game/src/sequence.cpp) byte-for-byte (docs/CLIENT-40250-PORT.md §7.5). +// Generated — do not hand-edit. +#include +#include +namespace mtnet::classic { +inline constexpr size_t SEQUENCE_TABLE_SIZE = 32768; +inline constexpr uint8_t SEQUENCE_TABLE[SEQUENCE_TABLE_SIZE] = { +0xaf,0xca,0x8a,0xcf,0x48,0xa7,0x54,0xc7,0xd7,0xdf,0x1,0x25,0x72,0xf7,0x6f,0x84, +0xbc,0x37,0x46,0xe3,0x24,0xda,0xa1,0xc8,0xee,0x36,0x7c,0x33,0x2f,0x98,0x76,0x5e, +0xe2,0x1,0x2e,0xab,0x29,0x3,0xf2,0x1,0xe2,0xf3,0xa5,0x56,0x6b,0x15,0x5a,0xa7, +0xcc,0x21,0x8b,0x70,0xfb,0xac,0x3a,0x6b,0xe3,0x36,0x9e,0x92,0x4e,0x16,0xf1,0x31, +0x96,0x9f,0x5c,0x3f,0xa2,0x50,0xbf,0x6,0xc3,0x66,0xdb,0x30,0xfa,0xb5,0xd7,0x47, +0xd6,0xe3,0xb8,0x53,0x90,0x72,0xbe,0xf3,0xa8,0xdc,0x7,0x76,0x72,0x78,0xa7,0xa, +0x18,0x84,0xc8,0x3b,0xd4,0x89,0x41,0x18,0xef,0x9c,0x48,0x6a,0x52,0xa0,0xb2,0xa9, +0x4,0xea,0x7c,0x94,0xdc,0x3b,0x9,0x85,0x97,0x10,0x7b,0xb,0x88,0x23,0x94,0x20, +0x27,0x5d,0xda,0xfb,0xe6,0x1c,0x15,0x56,0x38,0xdc,0xc1,0xb,0xfc,0xf3,0xb4,0x1, +0xde,0x31,0x16,0xbb,0xeb,0x9e,0xc0,0x83,0x2e,0x3c,0xe,0x36,0xde,0xa2,0x56,0x86, +0x80,0x32,0x82,0xe6,0xcd,0x17,0x3e,0x86,0x74,0x7f,0x91,0xf0,0x73,0x46,0xf2,0xd1, +0xf6,0x88,0xd,0x62,0x27,0x4d,0x65,0x55,0x9,0x74,0xb,0x67,0x96,0x61,0xed,0x17, +0x13,0xf0,0xfe,0xe1,0x87,0xbc,0xe7,0xfb,0x3c,0x79,0x6d,0xaf,0x3f,0x60,0x1,0x36, +0x68,0xe,0x18,0xf,0x5b,0x7d,0xe3,0x64,0x71,0xee,0xcb,0x9,0xcf,0x3a,0x9f,0xe3, +0x2b,0x1e,0x45,0xb2,0xda,0x2d,0x2f,0x96,0xa6,0x9c,0x46,0xe5,0x7c,0xc6,0x9b,0xe4, +0xd4,0xb3,0x73,0xaf,0xb0,0x57,0x93,0x23,0x46,0xdf,0xab,0x16,0x1a,0x4b,0x79,0x45, +0x6a,0xbe,0xf7,0xc4,0xeb,0xa6,0x5c,0x12,0x43,0x22,0x77,0xbf,0xe9,0x92,0x24,0x3e, +0x46,0x97,0xee,0x77,0xee,0x82,0x9a,0xb4,0x62,0xc5,0x4b,0xfb,0x11,0xc4,0x41,0xfa, +0x84,0xb9,0x40,0xef,0x60,0x9c,0x82,0xa4,0x3e,0xf9,0x64,0xa7,0x8d,0x89,0xe6,0x53, +0xa0,0x55,0x4a,0x90,0x57,0x64,0x45,0x3a,0x2a,0x90,0x36,0x3c,0xd5,0x78,0xb6,0xd9, +0x32,0xf6,0x49,0x12,0x13,0xcb,0xb6,0xd1,0x46,0x9b,0x79,0x53,0xa4,0xdf,0x26,0x45, +0xb4,0x71,0x55,0xd,0xd5,0x9b,0x47,0x80,0xab,0x7d,0x3c,0x81,0x75,0xf2,0xda,0x27, +0x6a,0x25,0x3a,0x7d,0xf0,0xf0,0xce,0xb6,0xc,0x49,0xa,0xb0,0xa8,0xb0,0x76,0x5e, +0x22,0xcb,0x6b,0x77,0xe6,0x32,0x77,0x13,0x2f,0xb3,0x94,0xa5,0xa7,0xef,0x4c,0x12, +0x15,0x86,0xf,0x85,0xf7,0xde,0x3d,0x83,0xa7,0x47,0x35,0x50,0x77,0x2b,0xae,0x99, +0xf6,0x99,0x91,0xde,0xcb,0x9,0xf1,0x7b,0xbd,0x6,0x21,0xe4,0xf5,0x6d,0xf6,0x8a, +0x74,0x85,0x11,0xeb,0x64,0x4e,0x6f,0xc,0x15,0xa4,0xdc,0x8d,0x4f,0xb,0xa6,0x47, +0xa5,0xb7,0xa5,0xf0,0x41,0x17,0x6c,0xfe,0x9c,0xd,0x63,0x93,0x7b,0xd9,0x9d,0x6f, +0x5f,0xae,0x5b,0x44,0xfc,0xca,0xcf,0x13,0xef,0xac,0x20,0x3f,0xb8,0xc6,0x6,0xdd, +0xfe,0xab,0xce,0x40,0x42,0x3c,0x3f,0xdf,0x49,0x22,0xf2,0x44,0xfb,0x90,0xb3,0xda, +0x40,0x8e,0x1f,0x3d,0xd9,0xef,0xcf,0xc9,0x1c,0xef,0x88,0xd4,0x37,0x8f,0xb2,0x36, +0xba,0x82,0xf5,0xfd,0x3e,0xb4,0xdd,0x7,0xd6,0xd0,0x4c,0xd2,0x61,0x7f,0xad,0xa1, +0xf,0x4d,0x5f,0xe8,0x3d,0x2f,0x32,0x59,0x9f,0xba,0xae,0x56,0xc9,0x61,0xc,0x85, +0x63,0x2,0x3,0x21,0xb6,0xe0,0x29,0xd,0xb1,0xf4,0xdf,0x92,0x74,0xd,0xb4,0x3, +0x5a,0x14,0x6b,0x17,0xc2,0x1d,0xf0,0xe1,0x58,0x9f,0x38,0x22,0x80,0xc3,0xa7,0x64, +0x45,0xaa,0x85,0xfb,0xb,0x2e,0x88,0x3c,0x23,0x68,0xcf,0x18,0xf5,0x84,0x1b,0xcf, +0x18,0x7,0xe7,0xda,0x24,0xd8,0xbd,0x7c,0xf7,0xf5,0x1f,0xf7,0x3a,0x46,0x5c,0x7f, +0x71,0x62,0xfb,0x7c,0x90,0x84,0xb9,0x34,0x6d,0x9,0x4c,0x63,0xd,0xe6,0xb2,0x25, +0x6d,0x1a,0x0,0x12,0x72,0x3d,0xe,0x6a,0xb3,0x2d,0x63,0xed,0x74,0x3f,0x6d,0xe5, +0xa1,0x69,0xe1,0xb2,0x6e,0x1b,0xe6,0xdb,0x24,0x33,0xbe,0xb0,0x99,0x71,0xd5,0x8, +0x8c,0x56,0x1a,0xfe,0x93,0x28,0xe9,0x47,0x56,0xcc,0xb4,0x4a,0xc,0x23,0xaf,0xae, +0xc,0x91,0xe0,0x7a,0xad,0xc7,0xd5,0x51,0x7a,0x94,0x82,0x14,0x86,0x58,0x9b,0x13, +0x2e,0xb5,0x91,0x42,0x5e,0xfa,0x9,0x34,0xc7,0xbe,0x7e,0xd4,0xe1,0x2e,0x3,0x6d, +0x3f,0xe3,0x68,0x6c,0x2b,0x3e,0xbe,0xa5,0xd3,0x41,0x39,0x5a,0x19,0xd5,0xec,0xc7, +0xb,0xfd,0xa,0x69,0xf9,0x92,0x9d,0xc1,0x51,0x9b,0x16,0xb2,0x49,0x98,0x21,0x9, +0x7c,0x89,0x75,0xa7,0xc7,0x34,0xcc,0x1b,0xf4,0x7,0xf4,0x8e,0xdc,0xe1,0x56,0xe7, +0x60,0xdf,0xd1,0x5a,0x72,0xee,0x9b,0x44,0xb,0x32,0xf6,0x54,0xca,0x18,0x5d,0xc7, +0x21,0x53,0xee,0x69,0x7,0xbc,0x4,0xfc,0x43,0xf9,0xb,0x9f,0x5b,0xe0,0x7,0xbb, +0x40,0xd8,0x16,0xb2,0x48,0x32,0xf6,0x53,0x64,0x6e,0x27,0xae,0x6,0x5,0x76,0x28, +0x58,0xe5,0x11,0x5f,0x22,0x15,0xdb,0x65,0x8e,0xe6,0x5,0xea,0xc7,0x8b,0xa6,0x8, +0x65,0x3d,0x3b,0xad,0x6f,0xb1,0x80,0x53,0x20,0xa7,0x2,0x27,0xac,0xf8,0xce,0x5, +0xde,0x5f,0xe4,0x80,0xf3,0xc0,0xe5,0x83,0xa8,0x6a,0x6e,0xef,0xf5,0x94,0x78,0xda, +0xd1,0x33,0x8,0xc0,0xe4,0x88,0x14,0x85,0xb0,0x96,0x2c,0x5d,0x8f,0xfa,0xe2,0xed, +0xd9,0xc7,0x6e,0xcd,0x8,0x54,0x51,0x30,0x3e,0x3f,0x21,0xb3,0xd4,0x19,0x8f,0x26, +0x4c,0x17,0x67,0xb0,0xa0,0x7b,0x36,0xd0,0x12,0x62,0x2e,0x21,0xdc,0x90,0xf,0xb6, +0x58,0x7d,0x85,0xe0,0x51,0x56,0x11,0x8f,0x96,0x32,0xc3,0xea,0xca,0xd2,0x90,0x96, +0xe9,0xf7,0x48,0xa,0xf3,0xfd,0xda,0x6,0x61,0x89,0xa7,0xbd,0x1a,0xb6,0xf4,0xf2, +0x35,0x7a,0xd3,0x6,0x50,0xe4,0x16,0xe6,0x97,0xd9,0x51,0xe1,0xac,0xe2,0x79,0x16, +0xda,0xc1,0x21,0xce,0xbf,0x7b,0x55,0xa0,0x5,0xfc,0xde,0x9f,0x33,0xd3,0x92,0xe7, +0xcd,0xe5,0xee,0x1e,0x4a,0x5,0x6,0x61,0x5e,0xd6,0x44,0xb,0xb9,0xbd,0xa0,0x15, +0xfe,0xc1,0x63,0xbe,0xbd,0xb8,0xdf,0x42,0x35,0xbe,0xe1,0xe8,0x92,0xf3,0xd0,0x60, +0x59,0x3f,0x7e,0xa4,0x44,0x4,0x6,0x22,0xdb,0x4a,0x2d,0x15,0x87,0xce,0x2a,0x86, +0x10,0x8e,0xc5,0x4d,0xc6,0xa5,0x90,0x7c,0x64,0xf1,0x65,0x76,0xe6,0xb5,0x56,0x40, +0xf5,0x54,0xe4,0xb9,0xd8,0x6b,0xdc,0x34,0x35,0x89,0x49,0xbd,0xd7,0xf3,0xc3,0x68, +0x2,0x89,0xb5,0xc8,0x2f,0x46,0xc4,0x13,0xb8,0xa9,0x9,0x9f,0x60,0x5f,0x5f,0xd5, +0x34,0x45,0xf,0xd,0x30,0xeb,0x41,0x65,0x76,0x8a,0xa2,0xcd,0xfd,0x67,0x36,0x0, +0xf0,0x6c,0x49,0xa0,0x32,0xe,0x33,0xea,0x38,0x3d,0x8a,0x18,0x1c,0xea,0xed,0x50, +0xaf,0xfc,0x5d,0xdf,0x69,0x9e,0xc4,0x5f,0xa9,0xe7,0x2d,0xa7,0x4f,0x64,0xa8,0xbf, +0x50,0xf1,0xdf,0x82,0x7f,0x14,0x6e,0xb7,0xd0,0xf8,0xcf,0xec,0x63,0x3d,0xbd,0x13, +0xba,0x1b,0x72,0x24,0x3a,0xb7,0x83,0xe3,0x9f,0x30,0xb,0x6e,0x94,0x33,0xad,0x64, +0xa4,0x8e,0xe7,0x25,0x22,0x56,0x5c,0x72,0x4f,0xac,0xde,0xb3,0x69,0x9c,0x46,0x24, +0xb8,0x39,0x48,0x72,0xf0,0x4b,0xd5,0x10,0x7c,0xe0,0x7e,0x90,0x15,0x2c,0xf5,0xb9, +0x3a,0xdd,0x5e,0xdb,0x34,0x3b,0x4e,0x3,0xe7,0x2e,0x36,0x51,0xca,0x7d,0x76,0x3, +0x36,0x3e,0xf4,0x27,0x8a,0xca,0x37,0x7,0x2c,0x35,0x17,0xc0,0xe0,0xd,0x7a,0x1c, +0xea,0x59,0xf7,0x9e,0x94,0xc6,0xa2,0x7c,0x74,0xd8,0x4d,0x3f,0xd5,0x43,0xc2,0xc, +0x82,0x37,0xb2,0x8c,0x3,0x69,0x13,0x2f,0x9e,0x2a,0xef,0x80,0xb7,0xe9,0x1c,0x22, +0xc2,0x93,0xc1,0x57,0x5a,0x64,0x53,0xce,0xbc,0xa1,0x8e,0x13,0x64,0xd0,0x9e,0x66, +0x8,0x52,0x72,0xb,0xbb,0x85,0xb9,0xda,0x30,0x29,0x5b,0xe7,0x93,0xf6,0xa,0x56, +0x8a,0x4b,0x2e,0x65,0x2f,0x81,0x34,0xec,0xa2,0x42,0x0,0x8,0x13,0x1e,0xed,0x9b, +0x70,0x61,0x26,0xac,0xe6,0x60,0x87,0x96,0x89,0x62,0xfd,0x9c,0xd8,0x88,0xf3,0x63, +0xd3,0xa1,0xc8,0x4,0x23,0x7d,0x70,0x46,0x3f,0xef,0xcd,0xd2,0xe,0xbb,0x6e,0x7f, +0x1d,0x94,0xab,0x84,0xf4,0xb2,0x1b,0xfe,0x94,0x99,0x9b,0x6d,0x22,0xf,0xd0,0xf5, +0xb0,0x1a,0x79,0x54,0x17,0x69,0x9a,0x56,0x59,0x68,0x29,0x68,0x24,0x97,0x67,0xc1, +0xac,0x92,0x46,0xa1,0x45,0x61,0xa0,0xd9,0xfa,0xbc,0x47,0x9c,0xcb,0x97,0x13,0xfc, +0x31,0xc,0x51,0x48,0x76,0x6b,0x1f,0xcf,0xd3,0xc7,0x38,0x77,0xdf,0x1f,0x39,0x8c, +0xb1,0xfe,0xad,0xf6,0x61,0xce,0x50,0xdb,0x8b,0x17,0xf8,0xd6,0x2f,0xc,0xd3,0x60, +0x18,0xa4,0x29,0x8e,0x10,0xc7,0xde,0x63,0x8f,0x96,0xdb,0x6f,0xb6,0x94,0x7b,0xe7, +0x94,0x2a,0x5f,0x75,0xf8,0xaf,0xd0,0x4,0xc7,0xc9,0xda,0x76,0x55,0xaf,0xd6,0xed, +0x54,0x7f,0x7c,0x65,0x47,0x5b,0xc8,0xd7,0xf2,0x24,0xc6,0x29,0xb9,0xc2,0x11,0xcd, +0xec,0x70,0x43,0x65,0xa0,0x93,0x69,0xe7,0xdd,0xc3,0x5e,0x33,0x73,0xb4,0x21,0x48, +0x35,0x1e,0xad,0x7c,0xf8,0xf5,0xd3,0x6b,0x9a,0x9b,0x94,0xd3,0x5e,0x26,0xa1,0xca, +0x96,0x64,0xaf,0xb6,0xf7,0x98,0x9e,0xd5,0x5c,0x7c,0x89,0x50,0x32,0xaa,0x98,0x67, +0x48,0x46,0xe3,0x42,0xbb,0xb8,0xad,0x56,0xd3,0x43,0x2a,0xb1,0xe8,0x4b,0xfb,0x7f, +0xaf,0xab,0xb6,0x28,0xc3,0xd4,0x7d,0x9f,0x52,0x7,0xef,0x4,0x32,0x88,0xea,0x7a, +0x4e,0xce,0xbc,0xb,0x7,0xea,0xe0,0x5a,0xad,0x8b,0xc,0x96,0x56,0x87,0x95,0x7, +0xb2,0x4c,0xae,0x76,0xa1,0x2c,0x17,0x73,0xb3,0x7,0x77,0xe5,0x10,0x62,0xdf,0x5e, +0xb0,0x1d,0xe8,0x38,0x8,0x4a,0x92,0xb5,0xd5,0x1f,0xcb,0x2c,0xa6,0x61,0xb2,0x5a, +0x2e,0x61,0x50,0xcf,0xe,0x67,0x43,0xc1,0xee,0xba,0x27,0xfe,0x9c,0x7,0x5d,0x4d, +0x24,0xc6,0x5,0x2c,0x11,0x98,0x61,0xe6,0x37,0x2d,0x92,0xdd,0xf,0xc5,0x38,0x3d, +0xa6,0x89,0xd,0xb4,0x70,0xcf,0xf5,0x5f,0x8a,0x1d,0xdd,0xa6,0x25,0x3c,0x73,0xc8, +0x3,0x79,0x75,0x14,0x91,0x56,0x7a,0xc8,0x84,0x8c,0xa6,0x13,0x52,0x5f,0x50,0xf9, +0x68,0xdc,0x2e,0x58,0xac,0x25,0x38,0xb6,0xc1,0x16,0x5d,0x66,0x52,0x50,0x30,0xd4, +0xc9,0xa5,0x68,0x5b,0xfb,0x62,0xa3,0x0,0xef,0x4b,0x13,0x42,0x2a,0xe2,0xbb,0x12, +0xbf,0xea,0x6a,0x6c,0x10,0xa2,0xa2,0xd1,0xb9,0x0,0x39,0x8b,0x51,0xe8,0xe0,0x9a, +0xe,0x49,0x76,0xa,0xac,0x1a,0x8a,0x1c,0x65,0x1d,0x5e,0xf,0x1,0x1b,0x21,0x40, +0x85,0xc,0x2d,0x95,0xae,0xcf,0xe6,0xe7,0x50,0x9f,0x74,0xa1,0x88,0x55,0xbb,0x96, +0x1e,0x32,0x21,0x4a,0x4d,0x2b,0x66,0x32,0x48,0xc5,0x42,0xc8,0x60,0xe2,0x89,0xe5, +0xee,0xb6,0xfa,0x1e,0x6,0x61,0x6,0x56,0x2,0xf9,0x77,0xa,0xce,0x34,0xa1,0xed, +0x66,0x42,0x38,0xb3,0x6d,0x9f,0xe6,0xb5,0xe4,0xa8,0xfe,0xc4,0x8b,0x88,0x2a,0xfa, +0xbe,0x25,0x19,0xc4,0x6,0x9e,0x9b,0x8,0x99,0x13,0x13,0xe7,0x47,0x34,0xd5,0xae, +0x76,0x8e,0x62,0xe3,0xad,0xc8,0x19,0x92,0x71,0x97,0x57,0xfd,0x9f,0x81,0xf8,0x5e, +0x26,0x91,0xa3,0x2c,0x30,0x3f,0xb4,0x49,0xd1,0x47,0x32,0x1a,0x7b,0x87,0x48,0x71, +0x16,0x2a,0x55,0xc3,0xf3,0xed,0xd5,0x65,0x6,0xac,0xe2,0xa5,0xad,0x5b,0x84,0xd3, +0x6c,0x28,0x80,0x1d,0xe6,0x35,0x66,0xb8,0x7c,0x18,0xd2,0x77,0xa0,0x9a,0xe8,0x36, +0xc5,0xbd,0x7a,0xb9,0x2b,0x50,0x9e,0x31,0x7d,0x2,0xd7,0x2b,0xdc,0x5c,0x7f,0x4a, +0x4,0x0,0x67,0xea,0xb4,0x4d,0x23,0xb0,0x66,0x76,0x28,0x7,0x11,0x90,0xbc,0xd6, +0x4e,0x37,0x10,0x79,0x8,0xaf,0x2b,0x85,0x31,0x3,0xb0,0xe,0xde,0x30,0xd7,0x62, +0xaf,0xbe,0xcc,0xe3,0xd,0xef,0x14,0x73,0x66,0xbb,0xf9,0xf7,0x4c,0xb6,0xce,0x1a, +0xee,0xdf,0x94,0x76,0xf,0xbf,0xfb,0xbf,0x42,0xac,0xcd,0xa0,0x5d,0x26,0x3,0x8c, +0xe4,0xcf,0xf0,0xf1,0xbf,0x5,0xe4,0xa6,0xc1,0x5e,0x9e,0xe,0x16,0xec,0xa8,0x84, +0xcc,0x3d,0xfa,0x5b,0x7c,0x76,0x1b,0x3e,0x23,0x69,0xde,0x0,0x8f,0xe1,0xd,0xf3, +0xb1,0xfd,0x66,0xf0,0x82,0x4b,0x97,0x44,0x2a,0xb5,0xd2,0x40,0xa3,0x7b,0x44,0x70, +0x38,0xbe,0x4c,0x34,0x35,0xe6,0x72,0xd7,0x50,0xd0,0xd8,0x5f,0xb2,0x65,0xd3,0xe3, +0xe2,0x3a,0xd4,0x65,0x5,0xec,0x2a,0x2f,0xa2,0xfc,0xee,0x46,0xf7,0x33,0x37,0xaf, +0x71,0x3,0xe3,0xa6,0xe9,0xd5,0x7f,0x3b,0xa6,0xd7,0x1a,0x59,0xbc,0xed,0x3d,0x9f, +0xa7,0x91,0x5,0xad,0x7e,0x2f,0x5c,0xa1,0xab,0x4c,0x67,0xa3,0xfe,0x9e,0x53,0x71, +0xa1,0xb6,0x97,0x8c,0x8c,0x17,0x47,0x33,0x6e,0xe0,0xc,0x2b,0x4f,0x49,0xca,0xf6, +0x5b,0x50,0x24,0x59,0x7f,0x81,0xfa,0xab,0x4d,0xe2,0xce,0xcb,0x81,0xa2,0xbc,0xa3, +0x59,0x55,0xaf,0xe6,0xeb,0xf6,0x99,0xda,0xd7,0xa6,0x6,0xa6,0x6f,0x51,0x9e,0xca, +0xa1,0xc2,0xa4,0xa0,0xc3,0x1f,0xcb,0x11,0x2,0x9b,0xdd,0x84,0x3e,0x9a,0xa7,0x17, +0x6f,0x57,0xfd,0x5c,0x4e,0x18,0x37,0xa5,0xbe,0xbc,0x4d,0x2e,0x8d,0x6b,0x79,0xae, +0x2e,0x1e,0x50,0xf2,0x3d,0x9b,0x83,0xbf,0x37,0xe0,0x44,0xf4,0xfb,0x6b,0xd,0x6b, +0xc2,0x8a,0x47,0x90,0xa2,0xfd,0x36,0x61,0xbb,0x3,0x90,0x49,0x6e,0xa,0x78,0x1d, +0xa7,0xc8,0x8f,0x64,0xe3,0x13,0x24,0x1c,0x74,0xe7,0x90,0x70,0x53,0x9d,0x5b,0x16, +0x29,0xa3,0xa6,0xcb,0xa1,0x5d,0xad,0xdc,0xdf,0xbd,0xa6,0x4f,0x47,0x1f,0xeb,0xee, +0x67,0xfa,0x53,0x4b,0xe,0xf7,0xe6,0x2,0xdf,0x78,0x72,0x34,0x95,0x4e,0x4a,0xbe, +0xf1,0x71,0xb,0x13,0xce,0xb8,0x70,0xae,0xf5,0x96,0x7d,0x3d,0xb5,0xe8,0x2c,0x9c, +0xe3,0xfe,0x67,0x72,0xf6,0xce,0x74,0xd7,0x47,0x67,0x8b,0x5c,0xb5,0x55,0x1c,0x27, +0xc6,0xa6,0x3a,0x15,0xde,0x2a,0x44,0xd4,0xc0,0x41,0x12,0xf5,0x2b,0xbd,0x92,0x8e, +0xbc,0x7a,0x1,0x34,0x49,0xf5,0x8b,0x10,0xdc,0x17,0x6c,0x92,0xeb,0x88,0xb9,0xb3, +0x2f,0x73,0x48,0x8d,0x9e,0x8c,0x62,0xde,0x4e,0x74,0xd5,0x79,0xb1,0x68,0x8,0x6f, +0xe2,0x89,0x23,0x2c,0xfe,0x2e,0x3c,0xdb,0xc4,0x29,0xed,0xb0,0xb1,0xa7,0xe3,0x61, +0x9a,0x2d,0xee,0xb8,0x39,0xd1,0x98,0x87,0x46,0xed,0x80,0xf8,0x56,0x9,0xe7,0xb9, +0x12,0x8a,0x65,0x11,0xb8,0x22,0xec,0x7d,0x4b,0xda,0xad,0x7c,0x2,0x92,0x5d,0x1c, +0x3f,0x4d,0xd5,0xf7,0x1f,0xed,0x80,0xe4,0xdb,0x80,0x5d,0xb1,0x89,0xc4,0xea,0x9b, +0x4f,0x51,0x2c,0x87,0xf2,0x19,0x84,0xbd,0x73,0x33,0x3a,0x75,0x45,0x98,0x12,0x84, +0x65,0x67,0x7c,0x4,0xd4,0x7c,0xe8,0xb0,0xfd,0xc6,0xe1,0x87,0x8b,0x4d,0xa3,0x5b, +0x1e,0xcf,0x62,0x11,0x69,0xe7,0xce,0x5c,0x1b,0x88,0x52,0x60,0x21,0x64,0x64,0x86, +0xcb,0xe0,0xa,0xa0,0x5e,0xf3,0xd0,0xdb,0x3a,0x32,0xe2,0x45,0x7f,0x86,0xa0,0x9d, +0xd6,0x4,0x2e,0xbf,0x6b,0xfc,0x1c,0x86,0x86,0x6e,0x66,0x27,0xd2,0xca,0x2e,0x1e, +0x2b,0x38,0x3e,0x89,0xab,0xf,0xe4,0x65,0xc1,0xc8,0xab,0x41,0x4f,0x4c,0x5f,0xa5, +0xcf,0x8d,0xe4,0x3b,0xb,0x2,0x41,0x11,0x70,0xa7,0x38,0xc3,0xf1,0xe5,0x61,0x1e, +0x1f,0xa0,0x27,0x4a,0x2f,0xd,0xb0,0xf0,0xd5,0x5c,0xb2,0xa4,0x28,0x12,0xca,0xf8, +0x1f,0xaf,0xb3,0x2a,0xb1,0xf5,0x3b,0xa2,0x1d,0xf3,0xe5,0x8f,0xd9,0x47,0xad,0x78, +0x67,0x54,0xc3,0x97,0xe0,0xf3,0x8,0x36,0x50,0x3a,0x5b,0xf7,0xcb,0xa5,0x70,0xeb, +0x55,0x25,0x16,0x87,0x9a,0xd1,0xa9,0xb7,0xc5,0xf,0x47,0x9f,0xd5,0x74,0x98,0x3e, +0x49,0xdb,0x55,0xa9,0xcf,0xdc,0x60,0x9f,0x18,0xbb,0x97,0xe3,0x61,0x9,0x4f,0x36, +0xad,0xe5,0x3d,0x48,0xb7,0xe6,0x7f,0xfc,0xf5,0x47,0x1c,0x4c,0x3b,0xb4,0x8a,0x84, +0x90,0x5f,0xae,0x60,0x3c,0xf,0x0,0xd3,0xca,0x18,0x38,0xab,0x21,0x87,0xe1,0x4e, +0x6d,0x20,0x96,0x25,0x86,0x95,0xa1,0xfc,0xdc,0xbe,0x49,0x19,0x73,0x53,0x1d,0x5, +0xb2,0xcb,0xe4,0x6e,0xda,0x65,0x43,0x25,0x7d,0x7b,0x50,0x1e,0x3,0x33,0x6c,0xf0, +0xd2,0x82,0x95,0xd8,0x18,0x38,0xd5,0xf5,0xf6,0x1f,0x8e,0x6a,0xf1,0x2b,0xee,0xa4, +0xf7,0xd4,0x14,0x52,0x3a,0xd6,0xf7,0xb7,0x52,0x48,0xd5,0xd4,0xfa,0xc1,0xc5,0xcd, +0x44,0x5c,0x27,0x5c,0x94,0xfc,0xd1,0x8b,0x9c,0xdf,0x75,0x8e,0xc,0x65,0xb3,0x83, +0x3a,0xc7,0x55,0xf3,0x1e,0x4d,0x2b,0x70,0x16,0x80,0x45,0x11,0x42,0x8b,0x5f,0x6, +0xe7,0x86,0x62,0xfb,0x83,0xb4,0x7,0x9f,0x94,0x7c,0x2f,0x20,0xe1,0xe2,0xa3,0x9b, +0x2a,0xf9,0xf,0x48,0xc6,0x3a,0x38,0xdc,0x3a,0xfc,0xee,0x7c,0x88,0x4e,0x82,0xef, +0x54,0x65,0xeb,0xd7,0x99,0x72,0xf7,0x2e,0xef,0x27,0x4f,0x51,0x89,0x72,0x6d,0xb3, +0xeb,0x7c,0x7b,0xb3,0x37,0xb3,0x90,0x71,0xb0,0xfe,0xee,0xb9,0xcc,0xf0,0xa9,0x21, +0xd5,0x16,0x79,0x6f,0x88,0x71,0x1e,0xf7,0x18,0xec,0x4a,0xa1,0x5f,0xb7,0xd4,0x4c, +0xb3,0xcf,0x7f,0xea,0x83,0x8f,0x5d,0xb3,0x8f,0xcb,0xec,0x5c,0x3c,0x97,0xfd,0x13, +0x2d,0x77,0x82,0xb5,0x68,0xa0,0x2e,0x80,0xd,0x78,0xa1,0x6d,0xaf,0xf5,0x39,0x63, +0xc5,0xb8,0x4f,0xc8,0xc7,0x2c,0xfb,0x57,0xf7,0xe9,0x34,0x34,0x1,0x32,0xc6,0x2e, +0x29,0x4a,0x63,0x91,0x6a,0x91,0x91,0x78,0xa,0x33,0x65,0xb9,0xa8,0x1e,0x9d,0x6e, +0x56,0x6c,0xb6,0x1e,0x98,0xb2,0x76,0x10,0x9c,0x2a,0xc3,0x9d,0xdb,0x8b,0x4b,0x5, +0x55,0xaf,0x16,0x3f,0x41,0xa7,0x37,0xcb,0x5a,0x9c,0x5,0x3,0x3a,0xa2,0x71,0x90, +0xf,0xa7,0xaf,0x27,0x5a,0x26,0x37,0x77,0xcf,0xfb,0x94,0xab,0x87,0xe0,0xb0,0x5c, +0x10,0xc6,0x9b,0x51,0xed,0xd3,0x1d,0x48,0xef,0x23,0x4b,0x2b,0xc5,0x3c,0xbb,0x55, +0xe3,0x6b,0x7c,0xbd,0x11,0x34,0x35,0xe0,0x30,0x4a,0x8c,0x37,0xaa,0xbc,0x93,0xba, +0x3,0xae,0xc,0xf0,0x82,0xa9,0x39,0xf2,0xcc,0x84,0x1e,0x12,0x40,0x59,0xe6,0x24, +0x45,0x64,0x62,0x56,0x18,0x97,0xb7,0x48,0x61,0xc3,0xfe,0xc,0x81,0x12,0xc6,0x84, +0xc0,0xd3,0x76,0xc3,0x7d,0x2f,0xb6,0xc9,0x34,0x54,0xdb,0x74,0x2d,0xc3,0x19,0x72, +0xa7,0x7b,0x49,0xbf,0x92,0x80,0x87,0xf4,0x44,0x6,0x1,0x45,0x18,0xc8,0xca,0xd8, +0x1c,0xc0,0x1c,0x19,0x6f,0x52,0xe2,0xa3,0x26,0x3e,0x98,0x54,0x81,0x31,0x46,0xa8, +0xac,0x8f,0xe7,0xbe,0x10,0xee,0xb3,0xd4,0xf4,0x35,0x1a,0xd,0x7d,0x64,0x66,0x19, +0xa4,0x82,0x32,0x15,0xd5,0x94,0x38,0x7b,0x52,0xd0,0xcf,0x54,0x2,0x17,0x7c,0x2e, +0x26,0x65,0xed,0xb6,0x54,0x21,0x8b,0xc9,0xd5,0xa5,0xd6,0x53,0xb,0xbc,0xeb,0xaf, +0xbf,0x1e,0x44,0x15,0x32,0x7d,0x90,0x5,0xcd,0x61,0x59,0x50,0xf7,0xd5,0x7e,0x9d, +0xba,0xeb,0x54,0x8f,0x8d,0xdf,0x59,0x63,0x6,0xaf,0x37,0x11,0xec,0x23,0x40,0xac, +0xc1,0x85,0x41,0x73,0x82,0xd1,0x78,0x50,0xb2,0x51,0xa0,0x2a,0xa7,0x9f,0xc8,0x62, +0xb,0x1d,0x71,0x18,0x7d,0x4a,0xfb,0x83,0x7a,0x33,0x14,0x67,0xd5,0x54,0x93,0x97, +0x59,0xd4,0xc,0xdb,0x26,0x4,0xac,0xd9,0x56,0xcc,0x4,0xfd,0x6c,0xcc,0xdf,0xf7, +0x6a,0x52,0x10,0xe7,0x1c,0x8b,0xea,0x96,0xbe,0xfe,0x7d,0x95,0x53,0x90,0xac,0x2d, +0x65,0x38,0x88,0xc,0x3d,0x35,0xe5,0x13,0x3,0x69,0x90,0xee,0x37,0x70,0x66,0x21, +0x42,0xf6,0x9,0xde,0x82,0xf3,0x75,0xc1,0x72,0x73,0xd6,0xc5,0x4,0x83,0x72,0xe9, +0x3c,0xfb,0xf5,0xf8,0xb0,0x5b,0xc,0xb3,0xc4,0x1c,0x23,0x7b,0x8c,0x89,0x9c,0x4f, +0x0,0x25,0x2e,0x83,0x98,0x23,0x45,0xb,0x16,0x1c,0x51,0x9a,0x1f,0xc3,0x84,0x5b, +0x3f,0xf9,0xd3,0xf0,0x55,0x5f,0x24,0x99,0x7b,0x47,0x16,0x9,0x51,0x32,0xd7,0x51, +0x58,0x85,0x54,0x70,0x28,0x19,0x7c,0x3f,0x35,0x4d,0xd9,0xd4,0x90,0xdd,0xaf,0xd0, +0xd7,0x84,0x41,0xac,0xe3,0x65,0x46,0x60,0x2d,0x5c,0xe8,0x7e,0x8f,0x40,0x4f,0x67, +0xc5,0x24,0xd7,0xed,0x3d,0xd3,0x2d,0xf2,0x21,0x86,0x47,0x32,0x64,0xf6,0x82,0x3c, +0xfa,0xc3,0x68,0xdf,0x29,0xaf,0xbf,0xd5,0x8b,0x28,0xd3,0x9a,0x68,0xa3,0x81,0xad, +0xc7,0x5a,0x9b,0x84,0xad,0x49,0x77,0x4f,0x4f,0xbe,0x81,0xb4,0x36,0x4,0x70,0x31, +0xc7,0xd9,0x90,0x70,0x9,0x50,0x47,0x14,0x78,0x1b,0xaf,0x60,0x3e,0x31,0xe,0x6, +0xb,0x2a,0x8b,0x39,0xf2,0x82,0x88,0x42,0xc1,0xa,0xf6,0xf7,0x8d,0xe7,0xa8,0x55, +0xc1,0x3a,0x45,0x4a,0x8a,0xc,0x5e,0x83,0xa7,0xe,0xe3,0xe5,0xbf,0x72,0xec,0x4a, +0x9c,0xf7,0x83,0xf,0x7a,0x8b,0x51,0x3c,0x95,0xc8,0xb3,0x23,0x30,0x5d,0xf7,0xf1, +0x97,0xbd,0x3c,0xa1,0xc9,0x1a,0xa4,0x71,0x29,0x9,0xd7,0x68,0x7b,0x44,0x32,0x97, +0x3c,0x36,0xa6,0x36,0xc1,0x77,0xf2,0xd7,0xbf,0xa6,0x7a,0xef,0x83,0xf2,0x61,0x9a, +0xb0,0x1d,0xbc,0x7a,0x38,0x61,0x6c,0xe0,0x6a,0xc3,0xc8,0x65,0x8,0xfa,0x7c,0x44, +0x31,0xa2,0xf9,0x73,0x1b,0xec,0x4b,0x5a,0x14,0x45,0x4b,0x97,0x38,0x2c,0xb2,0xe8, +0x4a,0x6f,0xe3,0x82,0xd0,0xcf,0xe2,0xbb,0x93,0xab,0xa0,0x1b,0xa6,0x1e,0xde,0x58, +0xc0,0xd8,0xcb,0x5b,0xc6,0x96,0xb6,0xda,0xdb,0x81,0xf1,0x94,0xad,0x24,0x7d,0xf7, +0x93,0xe0,0xf9,0xe4,0xb0,0xdc,0xa0,0xc3,0x88,0x41,0xde,0xaf,0xde,0xbd,0x8,0xa0, +0x97,0x53,0xfb,0xdd,0xe9,0x32,0x38,0x45,0xb3,0x2a,0xd9,0x62,0x4f,0xd7,0xd9,0x62, +0xb8,0xd4,0x47,0x6a,0xb1,0x67,0xad,0xba,0x29,0x8d,0x6a,0x8,0x4b,0x72,0x28,0xe2, +0x45,0x25,0xc0,0x2f,0x57,0xf8,0xf3,0xc,0xa3,0x4e,0xed,0x72,0x26,0xc7,0xd4,0xde, +0x1c,0x9c,0xc8,0x4e,0x4,0x77,0x9,0xac,0x5,0x73,0xb5,0xcf,0x65,0x5d,0x33,0xaa, +0x82,0x73,0x59,0x5a,0xec,0xcc,0xe5,0x90,0x1b,0xd3,0x82,0xc0,0x1b,0xd6,0x20,0x38, +0x73,0xe8,0x86,0xf7,0xdf,0xf,0xa4,0x64,0x2,0xd9,0xb4,0xe6,0x38,0xe7,0x91,0x3a, +0x5b,0x6a,0x14,0x48,0xb6,0xf9,0x58,0xd2,0x4d,0xda,0x93,0xe8,0x32,0xb3,0x21,0xa5, +0x1d,0x27,0x1d,0x7c,0xb5,0x42,0x61,0xb7,0x1c,0x16,0x9e,0xd3,0xfd,0xaf,0x8e,0x59, +0x1a,0xa2,0x22,0xd0,0x1d,0x7a,0x23,0x6a,0xd5,0x37,0x53,0x8,0x6a,0xf3,0xad,0x7, +0x9a,0x4b,0x84,0x50,0x8d,0xe5,0x8,0x29,0xfb,0x26,0x7d,0xf9,0xd5,0xc,0xd2,0x6f, +0x2e,0xf4,0xc0,0x4b,0xef,0x63,0xb6,0xc5,0x9a,0x89,0xcd,0x6,0xfd,0xfa,0x8c,0x98, +0xc5,0x11,0x69,0x53,0x76,0xf0,0x7d,0x72,0x18,0xfa,0xeb,0x6d,0x86,0x3f,0xdd,0xb4, +0xb3,0x1e,0x1,0xa3,0x81,0x37,0xe8,0x1d,0x40,0x36,0xa2,0x3e,0xb1,0xae,0x57,0x77, +0xc0,0x40,0xcb,0x37,0x31,0xc8,0x2a,0xc8,0x43,0x95,0x37,0xc9,0xd4,0x94,0xfd,0x89, +0xb2,0x7e,0xac,0x34,0x35,0x96,0xd0,0x76,0xcc,0xf2,0x34,0x7e,0xa2,0xb,0xf6,0xe2, +0x4b,0x42,0x99,0xfc,0xb,0xc3,0xc5,0xcd,0xd9,0xfc,0x97,0xae,0x91,0x15,0xb7,0x44, +0x94,0xe4,0xf8,0x49,0x7b,0x49,0xbf,0xc7,0x3d,0x74,0x47,0x5f,0xfe,0xbd,0xc1,0x4b, +0x0,0x5b,0x48,0x8a,0x9f,0xe,0x58,0x79,0x8b,0x6f,0xa7,0x1d,0x4,0xdf,0xe1,0x18, +0xc4,0x5a,0x62,0xbf,0xa3,0xa1,0x87,0x60,0x16,0x4e,0x3f,0x16,0xc,0x1,0xe0,0x8b, +0x5d,0xa8,0x16,0xfc,0xb6,0xed,0xf5,0xc1,0xdc,0x1d,0xdf,0xe1,0xfc,0x41,0xf9,0x41, +0x9b,0x5c,0x1,0x3f,0xfe,0x89,0x20,0x94,0xd7,0x5f,0x2a,0x64,0x61,0x8a,0xef,0xbe, +0x33,0x86,0x3b,0x6a,0xf3,0xb0,0x2c,0xd1,0xcd,0x8b,0xb3,0x4b,0xcc,0x2d,0x8c,0xe7, +0x8a,0x8e,0x28,0x9,0x97,0x48,0x1d,0xee,0x27,0xc7,0x53,0x88,0x52,0xc3,0xc6,0x6, +0xc9,0x2,0x70,0xbd,0x32,0x1c,0x8f,0x1,0xa8,0xc2,0x4c,0xf4,0xf0,0x58,0xdd,0xfa, +0x66,0x85,0x83,0xfd,0x4d,0xa0,0x6d,0x74,0xe7,0x40,0xfd,0xba,0x4,0xc4,0xc0,0xcd, +0x47,0xb0,0xc,0x79,0x4c,0x9b,0xf9,0xf4,0xde,0xc5,0x6a,0xcf,0x1f,0x48,0xca,0x5, +0xcd,0x4e,0x83,0x1b,0x6e,0xf0,0xf,0x57,0x31,0xd,0x12,0xb5,0x52,0x52,0x83,0x19, +0x82,0xf,0x12,0xce,0xab,0xd,0x44,0x8a,0x52,0xae,0xd9,0xf0,0xf6,0x24,0xf6,0x44, +0x72,0x7a,0xde,0x60,0x6b,0xed,0x37,0x1c,0x7b,0xc8,0xd1,0x4d,0x1b,0xd5,0xe5,0x1d, +0xe4,0xf7,0xec,0x10,0x84,0x31,0x1a,0xd7,0x5f,0xf3,0xc8,0xd5,0x97,0x3f,0x1a,0xa, +0xb9,0x78,0xea,0x25,0xe5,0x22,0xc1,0x61,0xeb,0x93,0x2e,0x86,0x69,0x14,0xa4,0xce, +0xd,0x91,0xde,0x11,0x42,0xf9,0xe8,0x21,0x6d,0x32,0xf6,0x6,0x71,0x90,0x8f,0xab, +0x9,0x7a,0x50,0xee,0x1d,0x12,0xd0,0x9,0xa6,0x7e,0x8f,0x8f,0x93,0xb3,0x5e,0x20, +0x45,0x3e,0x31,0x7,0xb7,0x9a,0x28,0xa4,0x4c,0x1f,0xaa,0x3d,0x2f,0xba,0xe8,0x38, +0xb4,0x3a,0xa7,0xd1,0x4c,0xf7,0x5a,0xf2,0xf5,0x6a,0x3,0x89,0x1e,0x61,0x29,0xe3, +0x1f,0x5b,0xea,0x56,0x75,0x93,0xfb,0xc1,0x32,0x26,0xfe,0x62,0xe0,0xe8,0x1a,0x16, +0xa2,0x41,0xe7,0xee,0xb8,0xc2,0x62,0xaf,0x2d,0x65,0x39,0xca,0x46,0xe2,0xae,0xe5, +0xbd,0x1a,0x3c,0x33,0xad,0x38,0x74,0x5f,0x5f,0xf2,0xc1,0xbf,0x5b,0xdc,0xd5,0xfd, +0x9d,0x3e,0xed,0x57,0x1,0xcf,0x7,0xad,0xb4,0xbf,0x78,0x7a,0xa2,0xa7,0x60,0x60, +0xc1,0x9d,0x93,0xee,0xd5,0x87,0x4e,0xb4,0x7b,0x90,0xf4,0xd6,0x6d,0xca,0xd5,0x8a, +0x88,0x43,0xe1,0x9,0x92,0xe8,0xb6,0x47,0x29,0xaf,0xc1,0xcb,0x57,0x23,0x2d,0x19, +0x40,0x40,0x87,0x95,0x48,0xd5,0x4b,0xc3,0x66,0xbf,0x9a,0x53,0xa,0xef,0xde,0x93, +0xb2,0x40,0x9c,0x45,0xa9,0xd3,0xc,0xd2,0x83,0x4e,0x9e,0xda,0x71,0x4b,0xf3,0x31, +0xc,0xfa,0xc6,0x54,0xd0,0x91,0x97,0xb7,0x51,0x32,0x8a,0x5c,0xa2,0x69,0x6f,0x55, +0x2a,0x8b,0x9b,0xd3,0x5f,0xa7,0xa6,0xe2,0xf5,0xc4,0xbd,0xe6,0x90,0x31,0x18,0x1c, +0x2c,0x5f,0xef,0x7d,0xf0,0x87,0x35,0xc2,0xb9,0xbf,0x9e,0xdb,0xa9,0xe,0x32,0xd3, +0x99,0xcd,0xa7,0xf9,0xf4,0xcd,0xdc,0x6b,0x12,0x1b,0xd1,0x22,0x4c,0x6a,0x3e,0xf8, +0xc9,0x2e,0x76,0x3a,0xb5,0x2b,0xfc,0xef,0xea,0x9b,0xcb,0x14,0x29,0x7d,0xe7,0xc3, +0xca,0xf,0x3d,0xc0,0x5c,0x99,0xab,0xee,0xb4,0x7d,0x11,0x81,0x67,0x50,0x7a,0xb0, +0xfd,0x70,0xeb,0x34,0x9b,0x68,0xa3,0x6,0x5,0xee,0x1b,0x2e,0x6d,0x82,0x71,0x38, +0x92,0x2e,0x78,0x6e,0xc8,0x24,0x5d,0xfc,0x22,0x6f,0xfd,0x89,0x3f,0xf7,0xba,0xbc, +0xe7,0xa6,0xf0,0x83,0xf,0x94,0x8a,0x93,0x84,0x25,0x42,0x71,0xa7,0x33,0xa9,0xb9, +0x62,0x23,0x29,0xaa,0x47,0x86,0x27,0xe8,0x75,0xa5,0xf2,0x34,0x9d,0xad,0xf1,0x86, +0x54,0xe2,0x89,0xe2,0xf7,0x93,0xf6,0xfb,0xb8,0x39,0x6d,0x61,0x6c,0x17,0x9a,0x4e, +0x3a,0xc3,0xf8,0x2,0xca,0xa0,0xea,0xbf,0x46,0xdd,0xf4,0xe3,0xb,0xe6,0xe9,0xde, +0x49,0xf3,0xc2,0x41,0x87,0x39,0x3d,0x41,0xf1,0x2a,0x22,0x5e,0x42,0x3c,0x2d,0xfb, +0x1,0xa5,0xfd,0x4b,0x46,0x69,0x8a,0xc,0xc6,0x7f,0x70,0xd2,0xe5,0x5a,0xb1,0xaf, +0xcd,0xf3,0x70,0x56,0xac,0x2e,0x17,0x9e,0x58,0xb8,0x7d,0x9a,0xf4,0xaa,0x97,0x75, +0xcf,0x15,0x40,0x17,0xfd,0xcb,0x23,0xc5,0xca,0x13,0x18,0x31,0xed,0x49,0xe0,0xbb, +0xbd,0x51,0x12,0x6a,0x7f,0x29,0xa,0xd8,0x61,0x87,0xf2,0x57,0xb1,0xa,0x4c,0x81, +0x9f,0x8d,0x18,0x9d,0xd8,0xbb,0x63,0xa3,0xce,0xfa,0xd4,0xbc,0x45,0x35,0x79,0x82, +0x87,0x8b,0xec,0x86,0x35,0xf6,0xde,0x96,0xfd,0xd2,0x6d,0xaf,0x5c,0xba,0x32,0xfb, +0xc7,0x4a,0x9a,0xa0,0x6,0x7d,0xc3,0xd5,0xf8,0x19,0x92,0x3e,0xcd,0x8b,0xc0,0xd4, +0x18,0x2d,0x5c,0xcc,0x25,0xba,0x63,0xa2,0x8d,0x51,0x53,0x6a,0x8b,0x5,0x66,0x53, +0x4f,0x80,0x73,0xd5,0xfe,0xb6,0x2b,0xf7,0x4f,0x3d,0xb5,0x1e,0xc9,0xf5,0xf2,0x61, +0x23,0xce,0x2e,0xc7,0x8a,0x11,0xea,0x97,0x62,0x3e,0x2,0x6d,0xc2,0xe8,0x40,0x91, +0x69,0x33,0x67,0xe7,0xea,0x92,0x5f,0xb9,0x50,0x15,0xd7,0x1a,0x8a,0x4b,0x7b,0x2e, +0x1a,0xa9,0x75,0x24,0x3a,0x60,0xbc,0x1d,0x1e,0x3e,0x8a,0xe0,0x27,0xcb,0x73,0x91, +0xfe,0x5a,0xf8,0x69,0xed,0x59,0x24,0xbd,0x6e,0x7b,0xd7,0x79,0x46,0xd2,0xa7,0x61, +0xfb,0x1d,0x5,0x36,0x7e,0x41,0x53,0x1c,0x80,0xde,0xfd,0xa7,0x2a,0xf0,0xb8,0xa8, +0x4b,0xb2,0x13,0xb8,0xc,0xb6,0x76,0xf9,0x32,0x4e,0x73,0xf8,0x21,0x9a,0x5a,0x1d, +0x38,0xde,0xd3,0x36,0x21,0x27,0x52,0xa1,0x85,0x50,0xc8,0x2f,0x41,0x2,0xd8,0xd, +0x34,0xeb,0xc5,0xbf,0x22,0x3d,0x39,0xd3,0xb,0x2d,0xcc,0xac,0xc7,0xa6,0xc9,0x0, +0x86,0x1d,0xb5,0x27,0xc4,0x9,0xc8,0x4a,0xd8,0x11,0x7a,0x9a,0x92,0xd2,0xa7,0x46, +0x3e,0x6d,0x6,0x60,0xaa,0x40,0x34,0x36,0xec,0x81,0xe2,0x34,0x28,0x2c,0xb4,0xae, +0x4a,0x6a,0x55,0xf,0x73,0x1e,0xd8,0x4d,0xaf,0xd2,0xe7,0xc1,0xa5,0xf,0x9,0xe3, +0x7c,0xf,0x44,0xa7,0xce,0xf8,0xdd,0x3b,0x7a,0xc0,0x70,0xa2,0x6c,0x25,0xd1,0xb6, +0x8f,0x27,0x45,0x4,0xc5,0x1f,0xd0,0xf4,0xf1,0x38,0xb6,0x18,0x47,0x3f,0xfb,0xc3, +0x4f,0xc0,0xea,0x9d,0x39,0x48,0xd9,0xb3,0x9,0xc9,0xd5,0xf5,0xee,0x27,0xac,0xfd, +0xce,0xf2,0x81,0x14,0x91,0x52,0x88,0x3,0xa,0x3f,0x1b,0x51,0x7f,0x97,0x95,0x4e, +0xd7,0x80,0x6b,0x11,0xc9,0xc4,0x44,0x52,0x8e,0x99,0x48,0xfc,0x41,0x75,0xfb,0x10, +0xe7,0x7d,0xa3,0x79,0x50,0x2c,0xfb,0x5a,0xea,0x97,0x2c,0xe9,0xae,0xc1,0xb7,0x86, +0xc1,0x24,0x17,0xb,0x68,0xda,0xdd,0xf7,0x74,0xa5,0x74,0xb5,0x1b,0x70,0x45,0x82, +0x6e,0xe8,0x7b,0xbe,0x15,0x78,0x19,0x80,0x8f,0xc4,0x6a,0x3e,0x86,0xa2,0xc4,0xc8, +0xc6,0x5b,0xd3,0xae,0x36,0x31,0x26,0xaa,0xd7,0x9b,0xe0,0x72,0xc,0x26,0x75,0x7a, +0x10,0xf0,0xb8,0xa4,0xe8,0x52,0x25,0x78,0x17,0x10,0xb6,0x1e,0xb2,0xfa,0xe6,0xf8, +0x56,0x3a,0x27,0x8c,0x6c,0x4e,0xb7,0xc3,0xe9,0x98,0xb5,0x75,0xbe,0x2b,0x70,0x4e, +0x1d,0x29,0xf3,0x6,0x7b,0x98,0x7f,0x13,0x28,0x36,0x31,0x5a,0x32,0x97,0xd2,0x8, +0xd1,0xfa,0x95,0xbd,0xc8,0xcc,0x81,0xb2,0x65,0x38,0x28,0x24,0x63,0x18,0xf2,0x0, +0x42,0x66,0x7,0x3d,0x7e,0x6,0xcf,0xa7,0xbb,0x1,0x81,0x6d,0x98,0xd4,0x76,0xea, +0x4f,0x8b,0xa8,0x18,0x58,0x2b,0xca,0xbd,0xe2,0x72,0x61,0xc5,0x8b,0x54,0xc6,0x4d, +0x3a,0xcd,0x8a,0xb9,0x53,0x5b,0xe0,0xf,0xdb,0xe1,0x7d,0xf4,0xb6,0x73,0xdf,0x6, +0xfe,0x88,0x1e,0x57,0xb3,0x68,0x94,0x16,0xdb,0xf5,0xdc,0x67,0xca,0xa3,0x34,0x5, +0xf0,0xbe,0x3e,0x44,0x99,0x1f,0xd2,0xf5,0x2,0x50,0xea,0x38,0xc3,0xca,0x3f,0xc2, +0xd2,0x5d,0x99,0x87,0xc6,0x2e,0x9d,0x22,0xa4,0xf9,0x9,0x6f,0x9d,0x3d,0xf3,0x8e, +0x7b,0x33,0x52,0x95,0xd1,0x26,0x8b,0xd3,0x76,0xf5,0x8c,0xba,0xc0,0xcb,0xfc,0x93, +0xa8,0x97,0x9a,0xee,0x45,0xb8,0x11,0xe9,0xb2,0x99,0xd8,0xd0,0xd6,0xcd,0x5f,0x53, +0x80,0x32,0x68,0x52,0x58,0xf3,0xa6,0x4e,0xe9,0x33,0x9,0x2a,0x7e,0x86,0x3d,0x27, +0x9d,0x58,0x96,0xe2,0x90,0x27,0x4d,0xc2,0xc1,0xa5,0x93,0x98,0xf2,0x73,0x6b,0x73, +0xa5,0xd3,0x46,0xfd,0x47,0x6c,0x4c,0xb0,0x1f,0xd5,0x5a,0x9d,0xdb,0x18,0x44,0x79, +0x70,0xda,0xdb,0x80,0x82,0x29,0x43,0x44,0xcf,0xd7,0x5c,0xc2,0x4b,0xc8,0xb6,0xf0, +0x1c,0x7c,0x6e,0xe3,0xe8,0x3a,0x94,0x8,0x8f,0x6f,0x25,0x6b,0x87,0xe8,0xe4,0x77, +0x44,0x41,0xf7,0xc6,0x6a,0x3b,0xb,0xb9,0x92,0x67,0xfc,0x5d,0xaf,0x33,0xcd,0x4c, +0xaf,0x3c,0x30,0x18,0x77,0x44,0x9f,0x7,0xb3,0xc4,0xf2,0xba,0x2d,0xd7,0x32,0x71, +0x19,0xa9,0x38,0x4,0x65,0x43,0x3d,0xf7,0x2b,0xb9,0xd5,0xda,0xec,0xa3,0x27,0x1c, +0xe0,0xd6,0x34,0xd7,0x1c,0x53,0x5e,0x4f,0x97,0x51,0xb,0xc5,0xa9,0xbc,0x37,0x42, +0xe6,0xef,0xc5,0x4c,0x33,0x4,0xc3,0xdd,0x3d,0x99,0x39,0xaa,0x3e,0xdf,0xc6,0x9e, +0xb7,0x7b,0x76,0x53,0xce,0x54,0xa2,0x67,0xa6,0x2d,0x2d,0xcf,0x6a,0xe3,0x12,0x51, +0xd3,0xd8,0x1d,0x87,0x5c,0x60,0x65,0x99,0x7a,0x1e,0x44,0xb8,0xfe,0x8b,0xd6,0xb6, +0x7,0xcc,0xa,0x55,0x21,0x2c,0xbc,0x47,0xd9,0x69,0x17,0x44,0xcd,0xa9,0x15,0xa1, +0x2,0x32,0x29,0xdd,0x92,0xf,0x77,0xd,0x2d,0x3c,0x45,0x2c,0x47,0x9b,0x62,0x4e, +0x68,0xeb,0x23,0xa,0x98,0xe0,0x51,0x72,0xc9,0xe8,0xb6,0x97,0x12,0xcb,0xb9,0x14, +0x7d,0x62,0xf1,0x8f,0xf0,0xe8,0x1d,0x9e,0xa4,0x62,0x4a,0xeb,0x7e,0xad,0xb9,0xe6, +0x19,0xdd,0xf0,0xb1,0xbe,0xc2,0xa3,0x8,0x2b,0x5a,0x20,0x3d,0xa5,0x59,0xd0,0xa2, +0xbb,0x42,0x33,0xad,0x2b,0x50,0x4c,0xd0,0x32,0x96,0x3c,0xb0,0xc3,0xf6,0x18,0xdd, +0xd4,0x88,0xf,0x13,0x4b,0xb3,0x1b,0xf5,0x8d,0xba,0xb2,0xb3,0x14,0x83,0x56,0xd0, +0xc5,0x9,0xfd,0x71,0xd8,0xc9,0xc1,0x8b,0x60,0xfd,0x3c,0xa4,0xf4,0xd3,0x2,0xc9, +0x5d,0x11,0xdc,0x28,0x44,0x78,0x1f,0xd2,0x33,0xd1,0x6,0x48,0xd5,0x5c,0x98,0x9b, +0xe5,0x16,0x8c,0x3e,0xdf,0x4e,0xc9,0xbf,0x4d,0x86,0x64,0x42,0x5a,0x66,0xd,0xb7, +0xf7,0x69,0x60,0x3c,0xe1,0x7f,0xf,0x16,0xd0,0x15,0xdd,0xa6,0xf1,0x76,0xc2,0x57, +0x8c,0x4f,0x95,0xeb,0x9e,0xdf,0xab,0xeb,0x66,0x11,0xad,0xc0,0xf6,0xba,0xf8,0xee, +0xa4,0x59,0x2c,0x86,0x58,0xba,0x9c,0x29,0x50,0xf9,0x50,0xc1,0xef,0x13,0x19,0xfb, +0xe1,0x2e,0xe7,0x80,0xe,0x94,0xeb,0x74,0x25,0x1a,0xb5,0x1c,0x54,0x2e,0x8b,0xf8, +0x7,0xb7,0x80,0x5f,0xf1,0x9c,0x8,0x42,0x97,0x58,0x83,0x7,0xea,0x9c,0x4,0xcd, +0x4b,0xeb,0xcd,0x59,0x0,0x3a,0x4e,0xa4,0x54,0x83,0x41,0xa8,0xb1,0xcc,0x22,0xb8, +0x4,0xa2,0x18,0xf5,0x3f,0x9f,0xb8,0x56,0xf8,0x3c,0x5e,0xe3,0x59,0xe1,0x31,0xa4, +0x4d,0x7f,0x7d,0x4e,0xb9,0xcb,0x72,0x8d,0x4f,0xb3,0xb5,0x80,0x80,0xd7,0x39,0x84, +0x7a,0xd0,0xfa,0x3a,0x71,0x33,0x10,0xe9,0x6f,0xed,0x4d,0x48,0xcf,0x7f,0x6c,0x1e, +0x7e,0xea,0xeb,0x38,0x36,0x5e,0x45,0x6,0x13,0xfa,0x86,0x13,0xd3,0x40,0x18,0xcd, +0x90,0x13,0x8,0x81,0x46,0x19,0x6b,0x35,0x7,0x39,0xfd,0x57,0x38,0x6a,0x75,0xb6, +0xd4,0x61,0xee,0xc,0x3f,0x34,0x12,0xd1,0xae,0x18,0xe5,0x82,0x58,0xfd,0x51,0xe9, +0x90,0xd8,0xea,0x56,0x71,0xd6,0xb,0xf8,0x10,0x88,0x50,0x48,0xf3,0x45,0xfe,0xc8, +0xa6,0x6d,0x54,0x65,0x21,0xe5,0x38,0xcf,0xfe,0x9d,0xd2,0x57,0x1b,0x24,0xc0,0xab, +0x7c,0x2c,0x81,0xee,0x3,0xc,0xe7,0x13,0x95,0xb7,0x5b,0x89,0xfc,0xd9,0xd1,0x23, +0xc6,0xa6,0x88,0xe7,0x8c,0xc0,0x37,0xb,0xdd,0xa,0x63,0xf8,0xad,0xa3,0x24,0x2b, +0xcf,0xa5,0x1a,0xd2,0x32,0x81,0x65,0xc7,0x39,0x40,0xd0,0x36,0x1a,0x22,0x59,0xe0, +0xc8,0xe1,0x48,0xd5,0x23,0x80,0xe0,0x80,0x8a,0xc3,0x7a,0xb8,0xe7,0x9e,0xe3,0x37, +0xc4,0xfd,0x8a,0xf6,0x7f,0xef,0x3e,0x38,0x31,0xf,0x6e,0xca,0x31,0xc7,0x2c,0x7a, +0x29,0x74,0x50,0xcb,0xf4,0xb0,0x4d,0x0,0x75,0x47,0x38,0x5d,0x65,0x1c,0x14,0x2a, +0x99,0x9e,0xa0,0x19,0x8f,0xde,0xd0,0x40,0x6d,0x3f,0xb,0x9f,0x86,0x37,0x99,0x2f, +0x2c,0xe9,0x7b,0xa0,0x1a,0xc8,0x20,0x8f,0x8f,0x58,0x6c,0xf4,0x74,0x1,0x9f,0xe, +0x9f,0xbf,0xa6,0xae,0x9f,0x77,0xee,0xd,0xb6,0x7a,0x2c,0xbc,0x31,0xc5,0xec,0x5d, +0x2f,0x68,0xfe,0x4a,0xb0,0x1f,0x59,0x40,0x78,0x46,0xb4,0xec,0x47,0x54,0x7b,0x66, +0x94,0x22,0x16,0x34,0x9a,0x5,0xc0,0xd0,0xfe,0x6d,0xe,0x31,0x33,0xfa,0x8e,0xe2, +0xe2,0x8d,0xac,0x93,0x2d,0x85,0x53,0xa5,0x4b,0x8,0x12,0x12,0xdc,0x8d,0x79,0xf0, +0xb0,0x8f,0xa4,0xca,0x14,0x65,0x1b,0x14,0x52,0x29,0xc4,0x86,0xa3,0x53,0xe8,0x86, +0x61,0x95,0x99,0x8e,0x9a,0xec,0xb3,0xe6,0x75,0xc5,0xf8,0xd1,0x54,0xf1,0xc2,0x84, +0x1,0x67,0xce,0x16,0x4c,0x69,0xa9,0x9f,0x93,0x6e,0xa5,0xb6,0x41,0x8e,0x3e,0x22, +0xa3,0xd7,0xb0,0xbd,0x45,0xe3,0xa4,0xba,0xaa,0x1e,0xc,0x7e,0x8f,0xce,0x3,0x91, +0xb5,0x51,0xa7,0x2,0xba,0xd0,0x21,0xcd,0xbe,0xc6,0x5,0x0,0xd4,0x43,0x23,0x78, +0x9a,0x53,0x37,0x5f,0x38,0x5b,0x99,0x62,0xf8,0xa5,0xe0,0x89,0xf3,0x63,0x1b,0xa9, +0xb4,0x42,0x2c,0xee,0x13,0x4d,0x3d,0xd1,0x15,0x42,0x51,0xe9,0x5,0x74,0xe2,0x9f, +0x48,0x99,0x7f,0x0,0x74,0x19,0x62,0x6e,0xbf,0x43,0x77,0x33,0x26,0x92,0x5d,0xda, +0x54,0x89,0x49,0x67,0x56,0x86,0xb8,0xea,0x48,0xa,0x55,0x4d,0xfe,0x38,0x6d,0xc6, +0x51,0xec,0xc6,0xc5,0x6,0x29,0xb3,0x45,0xeb,0x2b,0x79,0x12,0x3d,0xd6,0x6c,0x91, +0x60,0xb5,0x78,0x36,0xbc,0x31,0x22,0x5,0xbb,0x77,0x53,0x3a,0x2f,0x40,0x1,0x0, +0x2d,0xc7,0xc5,0x33,0x70,0xf9,0x79,0x5c,0xa4,0xf2,0x6e,0x62,0x49,0x5a,0x73,0x29, +0x10,0xec,0x5f,0x4c,0x9d,0x1,0xd1,0xd8,0x78,0x25,0x13,0x27,0xe4,0x93,0x27,0x12, +0x5b,0x6d,0xc4,0x4b,0x67,0x3e,0xa7,0x8b,0xb0,0x95,0xed,0x79,0xef,0x62,0xa2,0x80, +0xce,0x3,0x4c,0xeb,0x4,0x1e,0x45,0xfc,0xc2,0xd7,0x24,0xa7,0x6c,0xcb,0xb9,0x47, +0x39,0x7f,0x93,0x20,0x3d,0xba,0xab,0x6e,0x51,0x1a,0xe7,0xc0,0xfb,0xb,0xc0,0xca, +0xe,0xe,0x36,0x91,0x2c,0xfa,0xe,0x6f,0xd3,0xb2,0x17,0xbf,0x7e,0x51,0x7,0x37, +0x50,0x9a,0x57,0x8d,0x56,0x3,0x7b,0x27,0x1d,0x64,0xe7,0x19,0x6f,0x29,0x63,0xfc, +0xb6,0x1a,0xe,0xe2,0x94,0x9c,0xd1,0x68,0x4f,0xe9,0x28,0x4d,0x3b,0x30,0x84,0xb, +0x4a,0xdb,0x98,0x20,0x5e,0x94,0x47,0xfb,0xf8,0xaf,0x94,0xe7,0xd8,0x78,0x64,0x8f, +0x12,0xf1,0xf1,0xa6,0x8e,0xc4,0x8f,0xdd,0x2e,0xb7,0x2b,0xe8,0x67,0x2f,0xf3,0x32, +0x8a,0xc,0x52,0xe9,0xa0,0x9a,0x65,0x99,0x4a,0xf9,0x1,0xa2,0xf1,0xe4,0xb1,0x4, +0xd7,0xa3,0x2b,0x66,0xe7,0xba,0xc4,0x16,0xf1,0x6f,0x7e,0xd9,0x9f,0x72,0xc,0x2a, +0x7f,0x5e,0x93,0x20,0x78,0xf8,0x3a,0x42,0x73,0xba,0xe4,0xe4,0xa0,0x96,0x69,0xf7, +0xba,0x94,0xdd,0xa2,0x4f,0xa2,0x39,0x41,0x92,0xb7,0x1b,0x32,0x2b,0xa6,0xdb,0x2a, +0x6,0xef,0xc9,0xfd,0x68,0x4,0x41,0x5b,0x3f,0xa5,0x41,0x5f,0x3d,0xaa,0x57,0x77, +0xbe,0x35,0x1a,0xe,0x58,0xd2,0xce,0xea,0x8b,0x6a,0x9c,0x36,0x11,0xf7,0xdf,0x96, +0xe7,0xa9,0x95,0x51,0x2e,0xd6,0xac,0x6d,0xfb,0x6d,0xcc,0xb8,0x97,0x24,0x30,0x56, +0xd8,0xca,0xe3,0x31,0x9d,0xb3,0x9b,0xa8,0x1e,0x38,0x5e,0xae,0xb0,0x3e,0x46,0x98, +0xe8,0xdb,0x69,0x17,0x32,0x96,0x4,0x2e,0x4,0xd0,0x67,0x1c,0x74,0x97,0x72,0xcc, +0x62,0x57,0x7e,0x80,0x8a,0x1a,0x29,0x28,0xd2,0x88,0xd6,0x83,0xc6,0x1d,0x9b,0x2f, +0x78,0x6,0xc5,0x2a,0x9c,0xc9,0xd8,0x20,0x1a,0x40,0x3c,0xe,0xd7,0x2f,0xdb,0xba, +0x6,0x5a,0x3b,0x10,0x74,0x64,0x38,0xc6,0x6c,0x8e,0xc9,0xb3,0xac,0x66,0x62,0xa4, +0xeb,0x29,0x4f,0x88,0x72,0x28,0x28,0xd,0xe7,0xe4,0x1b,0xbf,0x14,0x76,0xf9,0x99, +0xd0,0x35,0xa9,0xc5,0x1a,0x61,0x8c,0x6,0xef,0xd6,0xb9,0x1c,0x3d,0x9c,0xc1,0x29, +0xc5,0x11,0x31,0xb7,0xb8,0xd8,0x44,0xa0,0xbd,0xdf,0xdf,0x51,0x56,0xda,0xea,0x28, +0x8f,0x14,0xed,0xa9,0xf4,0xf9,0x30,0xe5,0x50,0xe9,0x2,0x8d,0x6,0x43,0x36,0xcb, +0x54,0xe6,0x4,0x8c,0xc0,0xc7,0x2d,0xfd,0xa7,0xe,0x50,0xfe,0xe8,0xba,0xa6,0xf7, +0x4f,0x14,0x22,0x44,0x8d,0x52,0x2a,0xde,0xbb,0xac,0xeb,0xc2,0xef,0x23,0xe,0x45, +0x89,0x91,0x51,0x4a,0x5a,0x7f,0x49,0x81,0x8d,0x19,0x0,0xf5,0x53,0xa6,0x6d,0xa2, +0x3a,0x8f,0xe7,0xc8,0xe1,0x91,0x27,0x9e,0x3e,0x13,0xe0,0x2f,0xb5,0xee,0xf3,0x40, +0x81,0x45,0xa,0x5b,0xc4,0xd2,0xdc,0xd1,0xeb,0x5d,0x47,0x40,0x83,0xb5,0x62,0xbe, +0x45,0xc9,0x7,0xa7,0x5c,0x2e,0xc5,0x9a,0xc0,0xa6,0x49,0x77,0x15,0x3d,0xb7,0x96, +0x3,0xc1,0x71,0x47,0x15,0xce,0x1a,0x1,0x2c,0xe0,0xc0,0xaf,0x96,0xa3,0xed,0x5c, +0x6d,0x74,0x83,0xc9,0xa2,0x49,0xe4,0x64,0xef,0xad,0x5b,0x5,0xeb,0x13,0x1c,0x6e, +0x54,0xd,0xb5,0x69,0xdb,0x4f,0xea,0x87,0x31,0x2b,0xb7,0x47,0xce,0x25,0x23,0xbc, +0x9a,0xa6,0x6,0x3d,0xef,0xea,0x21,0x5f,0x99,0x7c,0xe4,0x5,0xf,0x80,0x73,0x64, +0x8d,0x29,0x4d,0xe9,0x79,0xb7,0xf0,0x2a,0xe3,0x28,0x71,0x32,0x4e,0x95,0xee,0xe8, +0xbb,0x75,0xa5,0xac,0x60,0x47,0x8b,0x79,0xc3,0x70,0x7e,0x53,0xf0,0x71,0x37,0xfe, +0x1b,0x84,0x68,0x14,0xbc,0x59,0x3e,0x20,0x82,0xaf,0x52,0x50,0xc4,0xc1,0x39,0x81, +0x37,0xde,0xad,0x17,0x26,0x39,0x11,0x6a,0x2a,0xf,0x3d,0x9a,0x81,0x74,0x19,0x1c, +0x78,0x81,0x30,0x35,0x5b,0x6e,0x55,0x5d,0x9d,0x28,0xad,0xe2,0x69,0x66,0xe3,0x20, +0xc4,0x91,0xb6,0x6b,0x4a,0xc7,0xd5,0xf3,0xd7,0x13,0xf,0xd8,0x7,0x28,0xf4,0x7f, +0xaa,0x25,0x35,0x85,0x93,0x8a,0x62,0xb0,0x32,0x8f,0x93,0x1b,0xf5,0x77,0x3b,0xba, +0x88,0xf2,0x26,0x53,0x3a,0x7b,0xc6,0x12,0xe,0xd5,0xea,0x15,0xfe,0xdf,0x15,0x29, +0x5,0x4a,0x2e,0x18,0x54,0x90,0xc9,0x87,0x20,0xdc,0xa2,0x16,0xd4,0x5e,0x50,0x5d, +0xd0,0xf6,0x30,0xb,0x72,0xf7,0x1e,0x1,0xcd,0x88,0x16,0x4c,0x69,0xaa,0x75,0xed, +0xf4,0xa3,0x86,0x4a,0xb3,0xcf,0xd1,0xd3,0xac,0xf3,0x69,0x81,0xd1,0x3a,0x5f,0xa2, +0x31,0xf,0xae,0x23,0x7,0x4c,0x24,0x55,0xd4,0xba,0xa1,0xbd,0x65,0x97,0x2c,0x5b, +0xba,0xb2,0x25,0x6f,0x2,0xf6,0x43,0xae,0x6a,0x2d,0xb0,0xbc,0x67,0x8f,0x5f,0x98, +0x9e,0x8d,0x3b,0x26,0x59,0x60,0xfa,0xae,0x9a,0x1c,0x6c,0x7f,0xb3,0x18,0xda,0x6f, +0x4a,0x0,0x5e,0x4c,0x76,0x21,0x7b,0x61,0x4e,0x2c,0x1e,0x35,0xbb,0xfc,0x4d,0xd9, +0x8b,0x89,0x0,0xe4,0x69,0xfa,0x93,0x4,0x18,0x80,0x83,0x4b,0x18,0xde,0x3a,0x63, +0x5e,0x98,0xaf,0x55,0xba,0x2b,0xb6,0x88,0xd6,0xd4,0xbe,0x12,0x51,0xc,0xec,0xdc, +0x95,0x6c,0x42,0x7e,0xe7,0x55,0x82,0x0,0xd5,0x86,0xca,0x6e,0xe4,0x6,0xd1,0x43, +0x1e,0x1,0x98,0xd8,0xac,0xce,0xe1,0x3,0x23,0xa0,0x16,0x75,0x2c,0x82,0x52,0xc2, +0xee,0x94,0x41,0xd6,0x6a,0x44,0x56,0xbf,0x4a,0x22,0x2e,0x2f,0xa7,0x0,0x72,0xc5, +0x81,0x8b,0x1f,0x2e,0x5a,0x1,0x31,0x7e,0xa1,0xc6,0xf3,0xcd,0x49,0xc5,0x10,0xb8, +0xda,0xd1,0x8f,0x45,0x16,0x66,0x5,0xdf,0x8,0x34,0xf,0xaf,0xb3,0x1,0x75,0x35, +0x8c,0x94,0xe2,0x67,0x95,0x15,0x65,0xb6,0xdb,0x59,0x5,0xa5,0x9e,0x15,0x5e,0x79, +0x66,0x6d,0x3e,0x7c,0xd3,0x44,0xdb,0xdb,0xf7,0xea,0x8b,0x2b,0x6c,0x81,0x61,0xf8, +0x16,0xc3,0xdf,0x2c,0xd8,0x45,0xe2,0x35,0x1e,0xe7,0x5a,0xbd,0x7d,0xb8,0x37,0xe3, +0x26,0xf5,0xe0,0x7a,0x3a,0xbc,0x56,0xb1,0xa8,0x62,0xdc,0x15,0xe3,0xbd,0x8d,0x79, +0x82,0xed,0xa5,0xda,0x33,0x89,0x8f,0x52,0xf0,0xe9,0x10,0x6e,0xa2,0xc6,0x53,0x49, +0xbc,0x34,0xc3,0x76,0xf0,0x99,0xa7,0x19,0x7b,0x85,0xad,0xde,0xc2,0xbb,0x59,0xc4, +0xa9,0xfe,0xa0,0x5c,0x8,0xaf,0xae,0xf9,0x9a,0x3e,0x68,0xbc,0x6,0x3b,0x6,0x42, +0x6f,0x49,0x39,0xe0,0x63,0xe0,0x79,0xde,0xe5,0x28,0xbe,0x29,0x63,0x97,0xed,0xd, +0x16,0xe,0x69,0x1f,0xbe,0x98,0x98,0xd8,0xd6,0x80,0x95,0x5c,0xbc,0x1c,0x1f,0xab, +0xe4,0x58,0x8c,0x48,0xb8,0x7,0x28,0x1f,0xae,0x66,0x48,0x12,0xfd,0x36,0x9e,0x14, +0xc4,0x87,0xb2,0x83,0x20,0x4b,0x5c,0x77,0xcc,0x71,0x53,0x9,0x8d,0x72,0xb4,0x73, +0x4a,0xc1,0x3b,0x83,0x48,0x63,0xa2,0xf6,0x49,0x6a,0x88,0xc6,0x20,0xa6,0x5b,0xe4, +0x2e,0xe,0x68,0xce,0xd9,0x44,0x46,0x26,0xb6,0x19,0x2f,0x44,0xc,0x63,0x37,0x56, +0xa4,0x73,0x59,0xec,0x56,0x7b,0x63,0x20,0xe5,0x6b,0xe6,0x7,0x12,0x42,0xeb,0x41, +0xd0,0xd4,0x8f,0x2a,0x98,0xd5,0x50,0x4f,0x6e,0xfe,0x14,0x7a,0xe1,0xca,0x51,0x87, +0x3e,0xaa,0xf3,0x15,0x27,0xd7,0x35,0x8c,0xc2,0x9b,0x93,0xd5,0x5e,0x0,0x96,0x2f, +0x54,0x26,0x59,0xec,0x7b,0x29,0xbc,0xe9,0x28,0x50,0x65,0x89,0x1b,0x36,0x90,0xd9, +0xe0,0x85,0xee,0x87,0xdc,0x24,0x15,0x9f,0x3f,0x28,0xf4,0x9d,0xa7,0x8b,0xcc,0xfb, +0x31,0xa5,0x69,0xac,0xce,0x26,0x17,0x76,0xf5,0xfb,0x1,0x11,0x32,0x91,0xea,0x13, +0x96,0xd9,0x1b,0xf2,0x7d,0xaf,0x93,0xbd,0xd7,0x8,0x5b,0x0,0x14,0xa8,0x7b,0x45, +0xcd,0xe4,0x72,0x1d,0x8a,0x9,0x93,0x80,0x5,0x14,0x92,0x37,0x26,0xfc,0xc9,0x3c, +0x57,0x64,0x30,0xd4,0x14,0x43,0x12,0x6c,0x4b,0xed,0x6c,0x5f,0x16,0xe7,0x25,0xe3, +0x4d,0x17,0x80,0xd7,0x20,0x15,0xd8,0x25,0xa8,0xea,0xdb,0x4e,0xe7,0xa5,0x8b,0x3f, +0xb,0xbb,0x94,0x9e,0x7e,0x26,0xb,0xc9,0x93,0x77,0xa9,0xa9,0xdf,0x4e,0xe,0x2d, +0x65,0x8e,0x84,0x85,0x23,0x5d,0x2a,0x4c,0x48,0x6,0x9a,0x31,0x2b,0x26,0xef,0xb5, +0x61,0x84,0x55,0xdf,0x2b,0x60,0x2a,0xbe,0x58,0x53,0xe8,0x38,0xa1,0x76,0xe4,0x86, +0x84,0x69,0xc,0x28,0xc7,0xb5,0x74,0x10,0xbb,0xf,0xc0,0xe6,0xb5,0xb1,0x9d,0x96, +0xb5,0xf2,0x77,0x60,0xd2,0x21,0x20,0xaa,0x74,0x88,0x62,0x16,0xfe,0x47,0x9c,0x3, +0xb1,0x28,0x2b,0xf8,0xdd,0x9f,0x88,0x19,0x2f,0xc9,0x7f,0x64,0xfa,0x9c,0xfa,0x30, +0xf,0x72,0x91,0xe2,0x93,0xb1,0x8d,0x87,0xb9,0x70,0x1d,0xb8,0xb7,0x39,0xbb,0xe8, +0x61,0x67,0x61,0xbe,0x7,0xea,0x57,0xb5,0x34,0xd7,0x1a,0x2f,0x74,0x16,0x5f,0x84, +0x8,0xf0,0xe6,0x1c,0x22,0xf3,0xa3,0xdb,0x64,0xc1,0x14,0x1d,0x7a,0xd0,0x85,0xdc, +0x38,0xe7,0x1b,0xbe,0x52,0x73,0x75,0x86,0xca,0xf,0xb5,0x3f,0xa4,0x15,0xc3,0xad, +0x86,0x2a,0x49,0xa8,0x1f,0xec,0x85,0x83,0x2e,0x99,0xa0,0xa9,0xe9,0xa6,0x6,0xa1, +0x8e,0xa0,0x61,0xe0,0x14,0x56,0xe6,0xde,0xe4,0x9c,0x9e,0x8a,0x31,0xe1,0xb7,0xb7, +0xd,0x1,0xe0,0x2c,0x6d,0x66,0xaf,0x1c,0x7f,0xd0,0x45,0x6a,0xf6,0x4b,0xc,0x85, +0x6b,0xec,0xe5,0x0,0xc2,0x4c,0x5e,0x28,0xe8,0xfc,0xb2,0x99,0xdf,0x6a,0xd1,0x6c, +0xea,0xb2,0x18,0x58,0x98,0x47,0x74,0x18,0x97,0xb9,0x2,0x8e,0x84,0x8e,0x14,0xf0, +0xfa,0x79,0xf0,0xbe,0xc5,0x4f,0xe6,0x2e,0xcc,0x19,0x48,0x2c,0x3,0x1a,0x98,0xed, +0x4c,0x30,0x46,0x64,0x77,0x3b,0x7c,0x10,0xf4,0xfe,0x9e,0xf9,0x8d,0x33,0x6a,0x88, +0x2c,0x5b,0xc6,0x72,0x2a,0x2d,0xa0,0xf6,0xc5,0x68,0xa2,0xc8,0x82,0x3b,0xb6,0x4e, +0xea,0xfd,0xb2,0x63,0x39,0xaf,0x73,0xad,0xae,0x91,0x27,0xbb,0x44,0x91,0xc3,0x71, +0x6c,0xb,0xe3,0x17,0x38,0x4,0xe,0xfe,0x6d,0x31,0xc7,0x6f,0xeb,0xfe,0xbe,0xd7, +0x7c,0xf0,0x3b,0x35,0x20,0x2e,0xe2,0xce,0xbf,0x8a,0xa,0x5,0x1c,0xce,0xf5,0x9, +0xd9,0x59,0x20,0x91,0x5d,0xad,0x10,0xca,0xde,0x58,0xba,0xcb,0x57,0xf8,0xa3,0xd3, +0xe9,0xde,0x9,0xb,0x8c,0x6b,0x59,0xcb,0xf5,0xe3,0x50,0x92,0xb2,0x46,0x9b,0xc, +0x9f,0xbb,0x9d,0x7d,0xe8,0x2e,0x48,0xc8,0x86,0x82,0x94,0xdd,0x7b,0xb7,0x31,0xe5, +0x16,0xb9,0x70,0xa2,0x25,0x49,0x6e,0x9b,0x2d,0xbf,0xad,0x5f,0x85,0xc8,0x6b,0x26, +0x4,0x89,0xa3,0xec,0xb7,0x6b,0xb5,0xbd,0xee,0xc9,0x1b,0xe9,0x81,0x4c,0xcf,0x97, +0x6,0x40,0xb9,0xaa,0x8a,0x29,0xc5,0x37,0x68,0x73,0x97,0xed,0x3c,0x3,0x93,0x40, +0xc,0xb6,0xad,0x43,0xa2,0x63,0x1,0x11,0x2e,0x1c,0xfa,0x2f,0xe7,0x4b,0x47,0xed, +0x8b,0x1,0x19,0x95,0xa9,0xde,0xcd,0x91,0xd2,0xe4,0x80,0x8e,0xe7,0x93,0x4f,0x74, +0x4b,0xfc,0xb7,0x6d,0xdf,0x39,0x7e,0x8d,0xd4,0xf8,0xbd,0xbd,0x44,0x84,0x2b,0x50, +0x85,0xc3,0xe5,0xaf,0xa3,0x33,0x41,0xf5,0x18,0x41,0x84,0x80,0xd5,0x53,0x74,0xa0, +0x50,0xab,0xe,0x31,0x64,0x8c,0xbe,0x3a,0x85,0xfb,0x77,0x4a,0x80,0x22,0x9a,0x86, +0xe6,0x0,0x36,0xa,0xb3,0x77,0x0,0xcb,0xb9,0x4,0xcb,0xf,0x58,0xbf,0xaf,0xa8, +0x6c,0xbd,0x59,0xd0,0xc9,0x98,0xb,0xce,0x94,0x2,0x19,0x95,0x25,0x33,0x1c,0xc, +0x34,0x52,0x95,0xe7,0x49,0x95,0x33,0x82,0x19,0x7f,0x91,0x71,0x3f,0x41,0x9a,0xab, +0x7e,0x73,0xfc,0xc7,0xc,0x87,0x17,0x21,0x8a,0x30,0xb6,0x2f,0xe3,0x52,0x3b,0x18, +0xa4,0xd0,0x7f,0x6d,0xe5,0x32,0xf0,0x7e,0xb1,0x2,0xf0,0xf1,0xc3,0xb,0x1d,0xc1, +0x7e,0x99,0x8a,0xb,0x22,0xa1,0x2c,0x2c,0x51,0x62,0x5b,0x35,0xb4,0x96,0xcc,0xd8, +0xe6,0x4c,0x46,0x4c,0x7f,0xb6,0xca,0xb0,0x39,0x3b,0x22,0xfc,0xc5,0xbf,0x3e,0xc4, +0x59,0x48,0xcf,0x7b,0xe9,0x7b,0xa7,0xbb,0xdd,0x82,0x70,0x92,0x19,0x3e,0xea,0x7f, +0xa,0xb0,0x4b,0x9,0x68,0x17,0x3a,0x21,0xd1,0x5c,0x9d,0x98,0x1c,0xdb,0x5d,0xf5, +0x25,0xac,0xf0,0x8e,0x28,0x19,0x4a,0x85,0x9b,0xbb,0x18,0x35,0x79,0x82,0xb4,0x3, +0x33,0x80,0xd,0x1b,0x17,0x47,0x3c,0xe8,0x23,0xd9,0x1,0xbf,0xb6,0xdd,0xb5,0x5b, +0x8a,0xa6,0xe9,0xb2,0x3f,0xb4,0x38,0xdb,0xef,0xcf,0x11,0x69,0x52,0x45,0x6c,0x6, +0xc5,0xf8,0x21,0xdc,0x40,0x5e,0x46,0x64,0xb7,0x47,0x24,0xed,0x26,0x59,0x49,0xb0, +0x7f,0x34,0xe3,0xbf,0xe8,0x9b,0x9b,0xd8,0xeb,0x2c,0xc1,0x3e,0x71,0xad,0xc3,0xb7, +0xa7,0xe5,0x94,0xe7,0xc3,0xda,0xcb,0x7b,0xa2,0x6f,0x6a,0xc8,0x48,0xb3,0xf8,0xc8, +0x67,0x5c,0x88,0xcf,0xf8,0x24,0x28,0xe4,0xcf,0xe9,0xa2,0x41,0x98,0x67,0xf8,0x40, +0xcc,0xe,0xa7,0x90,0x68,0xf3,0xc,0xb,0xe2,0x76,0x53,0xab,0xaa,0x4d,0x74,0x12, +0xa9,0x7c,0xe2,0x22,0xa0,0xb,0x7,0xef,0x75,0x2a,0x31,0xe,0x91,0xaa,0xcd,0x5e, +0xb8,0xf4,0xee,0x21,0x68,0x7a,0x2d,0x4c,0xf1,0x80,0xf7,0x9c,0x4d,0xeb,0x2e,0x77, +0x68,0x11,0x99,0x88,0x9c,0x21,0x78,0x12,0x4b,0xa9,0x9f,0x5c,0x54,0x6d,0xba,0x8c, +0xe1,0x29,0xae,0x4b,0xa3,0xdb,0x17,0x15,0xdb,0x8e,0x31,0x2a,0x7a,0x60,0x21,0xe2, +0x71,0xba,0xea,0x8d,0xdb,0x63,0x9f,0xa6,0x8c,0x3f,0x3,0x61,0x2c,0x3d,0xed,0x8e, +0x66,0x9c,0xd9,0x8a,0xf7,0xf0,0x9f,0xd4,0x7f,0xd1,0x7e,0x79,0x32,0x9f,0x5c,0x23, +0xd9,0x47,0xb1,0x36,0x2a,0xd0,0xdc,0xb6,0x90,0xe0,0x18,0x3c,0x1e,0x86,0xca,0x5, +0x23,0xa4,0x8f,0x9b,0x15,0xae,0xef,0x14,0x0,0x6e,0x8d,0x32,0x8d,0x69,0xd5,0xe6, +0x30,0x87,0x1d,0x5a,0x58,0x7a,0x91,0x68,0xda,0x29,0xa5,0x78,0xaf,0x70,0xfc,0x53, +0x95,0x8c,0xee,0x2a,0xbb,0xde,0x3f,0xbb,0xcc,0x4c,0x6e,0xd9,0xb6,0x44,0x40,0x66, +0x4b,0x5e,0x41,0x23,0x58,0x52,0x8c,0xb2,0x7b,0x32,0x2b,0xab,0xa2,0x29,0x7e,0xb7, +0x35,0xec,0xe2,0xf0,0x4b,0x22,0x2d,0x18,0xed,0x9b,0x71,0x24,0xdf,0xb1,0x8b,0x2b, +0x8f,0xcc,0xcd,0x67,0x1f,0x5a,0x1a,0x1a,0x8c,0x46,0x45,0xaf,0xee,0xc3,0x67,0x24, +0xb0,0xc9,0x95,0xfb,0x6b,0xc2,0x93,0x5a,0x5e,0x84,0x7e,0xbd,0x37,0xa,0x68,0x46, +0x56,0x36,0xae,0xf4,0x91,0xc8,0x8f,0x9d,0x8e,0xd4,0xcc,0xfc,0x19,0xb4,0x22,0xc9, +0x7e,0x37,0x46,0xea,0x79,0x59,0xc4,0x57,0xde,0x43,0x15,0x95,0xcd,0xfc,0x5b,0x24, +0x33,0xa,0x1a,0x44,0x53,0x29,0x62,0x61,0xfd,0xae,0x5f,0x17,0x63,0x1,0x61,0x62, +0xb7,0x27,0xcc,0x31,0x80,0x91,0x88,0xde,0xd4,0x1d,0x74,0xa2,0x1a,0xd0,0x47,0xcc, +0x5a,0xe0,0x91,0x2d,0xa,0x73,0x8f,0x8,0x22,0x6e,0x9f,0x86,0x6f,0x1,0x68,0x27, +0x28,0x35,0xd7,0x28,0xc6,0xdf,0x8,0x1b,0xfc,0xfb,0x3e,0x96,0xcc,0x85,0xe2,0xa7, +0xe5,0x74,0xd4,0xef,0xe7,0x64,0x77,0x8a,0xd2,0x17,0x90,0xc1,0x97,0xf8,0xe8,0x3f, +0xad,0x40,0x68,0xf3,0x20,0xef,0xf,0x1d,0xeb,0xcc,0x33,0x39,0xd1,0x17,0xe0,0xb7, +0xb,0xb5,0xa7,0x73,0x1b,0x9f,0xfd,0x6d,0x36,0x8e,0x30,0xce,0x87,0x98,0x8d,0x35, +0xd9,0xf5,0x29,0xf9,0x65,0xb7,0x97,0x52,0x85,0x4a,0x8b,0xd6,0x61,0x6c,0x8f,0xec, +0xa1,0xb6,0x60,0xbc,0x56,0x5e,0xaa,0x8d,0xec,0xda,0xdb,0xf3,0xf2,0x69,0xa8,0xcc, +0xdf,0x51,0x47,0x45,0x9,0x5e,0x97,0xe,0xa8,0xa2,0xe5,0x8a,0x8e,0xf4,0x77,0x31, +0xab,0xd7,0x6d,0x82,0x36,0x18,0x8f,0xa2,0x72,0x6b,0x96,0x66,0xd4,0x3f,0xb2,0x34, +0x90,0x79,0x7a,0x19,0xd7,0x91,0xa7,0x1,0x35,0x8d,0x8b,0x43,0x2,0x3,0x74,0xad, +0xda,0x62,0x30,0x90,0xf9,0xbf,0x33,0xec,0xaa,0xc9,0xd2,0x0,0x88,0x85,0x34,0x98, +0x7f,0x2e,0x31,0x57,0xc0,0xd8,0xd7,0x75,0xe5,0x63,0xb8,0xe7,0x66,0xad,0x16,0xc0, +0x8f,0x46,0x51,0x89,0x86,0x84,0x76,0x31,0xcd,0x49,0x31,0x56,0x4f,0xe5,0x6e,0xce, +0x14,0xa0,0xa5,0x54,0xf8,0x7e,0xc9,0xdf,0xe1,0x3,0xc7,0xc8,0x30,0xdd,0x89,0xbf, +0xa4,0xdb,0x49,0xaa,0xdf,0x40,0xdb,0xae,0x89,0x8d,0x84,0x58,0x73,0x73,0x27,0x7, +0x14,0xcd,0x5c,0xd,0xcb,0x26,0x6c,0xad,0xa8,0x35,0xf5,0xd8,0x92,0x80,0x98,0xb6, +0xdb,0x62,0x61,0xbb,0xa2,0xbd,0xe9,0xab,0x4b,0x6f,0x5,0x3e,0xe2,0x2c,0x45,0x76, +0x79,0x21,0x83,0xc4,0xc7,0xf0,0xf2,0x70,0xa5,0xe8,0x4a,0xb7,0x69,0x62,0xee,0x45, +0xc4,0x50,0x81,0xe6,0x8d,0x6b,0x93,0xd8,0x5a,0x18,0x96,0x3d,0xc3,0x5c,0x33,0x3e, +0x7d,0x37,0x3,0x45,0xa7,0xf5,0xb6,0x4d,0x5f,0x80,0x84,0xc8,0xe2,0xf2,0x8e,0x28, +0x44,0x8f,0x8e,0xd1,0xfa,0x22,0x2b,0x56,0xb9,0xc1,0x13,0x7e,0x1e,0xc6,0xbc,0x1c, +0xfd,0x3f,0x61,0xa5,0xb5,0x18,0x72,0x15,0x18,0x76,0x5d,0xfb,0x6a,0x6b,0xa3,0xae, +0xfa,0x32,0x0,0x76,0xd4,0xaa,0x4c,0x8e,0xec,0xde,0xd,0x8a,0xa5,0x49,0xa6,0xa3, +0x9,0x9,0x49,0xbe,0xa0,0x3b,0x53,0xb9,0xb2,0x30,0x35,0x1d,0x9c,0xd8,0x4b,0x17, +0x8a,0xca,0xd,0x5f,0x76,0x59,0x6e,0xe2,0x39,0x7b,0x6d,0x5e,0xc5,0x15,0x82,0xce, +0x9d,0xcb,0xd,0x3e,0x87,0xdf,0x77,0x3a,0x10,0xac,0xd6,0x2c,0x5,0x22,0x44,0x90, +0xec,0x51,0x6f,0xe2,0x2b,0xdd,0x45,0xe3,0xd9,0xb3,0x42,0x1f,0x48,0xc4,0xed,0xe5, +0x11,0x7a,0xa3,0x18,0x5a,0x1c,0x52,0x6a,0x48,0x29,0x17,0xcd,0xca,0x5b,0xdd,0x37, +0x2c,0x4d,0x9a,0xd6,0xab,0xdf,0xba,0x85,0x93,0x7d,0xa4,0xdb,0xc1,0x12,0x41,0x52, +0x8c,0xe5,0x6a,0x66,0x81,0xbc,0x50,0xc9,0x65,0x67,0x17,0xaf,0x42,0xf4,0xe7,0xee, +0x43,0x2,0xc5,0x6e,0xe1,0x1,0xf3,0xf5,0x7e,0x18,0x51,0xbf,0x2a,0x93,0x13,0x36, +0xf8,0x7d,0x1c,0x7a,0xba,0x6c,0xc3,0x9f,0xd4,0xdb,0x50,0x96,0xd0,0xb7,0x85,0x93, +0xb9,0x4c,0x2,0x9b,0xcc,0x75,0x91,0x4b,0xd,0xe3,0x8a,0x37,0xf6,0x9d,0xec,0xef, +0x1c,0x9,0x6a,0xd6,0xf5,0xad,0x76,0x4a,0x89,0x46,0xe0,0xda,0xfd,0xe6,0xed,0xb7, +0xb2,0x70,0xd3,0x7f,0xe5,0x65,0x4a,0x73,0xc8,0xd4,0xaa,0x3f,0x73,0x18,0x2f,0xf, +0xa0,0x19,0xe5,0x96,0xc7,0xdb,0xe0,0xd0,0x23,0x42,0x2b,0xa0,0x29,0x1a,0x59,0xdb, +0x8a,0x2d,0xda,0xef,0x12,0x25,0x63,0x5b,0xf9,0x8e,0x9a,0xec,0x26,0x4a,0xfb,0xc6, +0xe2,0x61,0xdd,0x2a,0xbd,0x3e,0x7b,0xe0,0x0,0xa6,0x1,0xa8,0x40,0x5a,0x84,0x4a, +0x7,0xde,0xba,0x99,0x4,0x9d,0xf4,0x7e,0xab,0xf,0xea,0xd1,0xd8,0xe7,0x19,0xbc, +0xc8,0x76,0xe6,0x86,0xb4,0x62,0xe6,0xb5,0x89,0xe8,0x5e,0xc9,0x43,0x63,0x94,0xca, +0xc1,0x4f,0x64,0xc6,0xec,0xd8,0xc4,0x99,0xe7,0xaf,0xea,0xc1,0x17,0x4,0xfd,0x60, +0xf9,0xe4,0xe6,0xaf,0xc7,0xce,0xe4,0x51,0x37,0xc2,0x9a,0xf9,0xa5,0x2f,0xc4,0x68, +0x7e,0x29,0xae,0xeb,0x2,0xf2,0x5,0x6a,0x22,0xef,0xab,0xb9,0x74,0xa9,0x1a,0x6e, +0xe,0x1,0x9d,0xd5,0x4f,0x2,0xa6,0x86,0x45,0x42,0x81,0xea,0xf0,0x46,0xd2,0xef, +0xef,0x1,0x5b,0x71,0xf3,0x60,0x5b,0x17,0xcf,0x7,0xd0,0x44,0x30,0xea,0x33,0x3f, +0x6b,0x50,0x94,0xbb,0x53,0x3c,0x42,0x98,0xfd,0x43,0x3,0x6e,0xa,0xd6,0x5e,0xf9, +0xd7,0xb9,0xea,0x4c,0x99,0x47,0xe2,0x6a,0xcd,0x33,0x2e,0xfe,0x9d,0x61,0xbd,0x9, +0x32,0x52,0x44,0x85,0xe,0x87,0x1e,0x8b,0x4a,0xa0,0xfa,0x54,0x77,0xd8,0xcd,0xcf, +0x13,0xb9,0x9b,0xac,0x80,0x7e,0x96,0xcd,0x31,0xc5,0x4c,0xce,0xa6,0xa,0x57,0xd8, +0x5d,0x9c,0xdd,0xea,0xa3,0x7b,0x77,0xed,0x1d,0xf1,0x43,0x14,0xca,0x11,0xe3,0x5d, +0x4a,0xfe,0xb,0x4a,0xfc,0x21,0x19,0x2e,0x66,0x65,0xfc,0xe,0x70,0x55,0x66,0x4d, +0xf1,0xc4,0x38,0x95,0x40,0x2f,0x3,0x5d,0x21,0x46,0x72,0x6c,0xd7,0xd5,0xc9,0x22, +0xd5,0x54,0x6d,0xd2,0x76,0x6,0x81,0xdc,0x6b,0xfd,0x6a,0x5b,0x53,0x51,0x28,0xc4, +0x16,0xe0,0xd9,0x56,0x10,0xdd,0x34,0xb1,0xa3,0xa6,0x1e,0x7b,0xfb,0xe7,0x9e,0x51, +0x3d,0x8b,0xa4,0x33,0x11,0x26,0x10,0x7c,0x24,0xfa,0x58,0xf7,0x4c,0x80,0x3c,0xe1, +0x61,0x96,0x38,0xf1,0x74,0x6c,0xa3,0x97,0x92,0xc1,0x14,0xf,0x29,0x32,0x60,0xe5, +0x3d,0x84,0x98,0x4e,0xaa,0x29,0x4a,0x4f,0x24,0xa2,0xc6,0xef,0xa3,0x3,0xd1,0x5, +0x99,0xa,0x76,0x8d,0xf6,0x1a,0x26,0x9,0x5b,0x3a,0x97,0x5,0xeb,0xf8,0xea,0x29, +0x7d,0x4,0x77,0xa8,0x2d,0x41,0x77,0x51,0xe4,0x3e,0x41,0x88,0x41,0x92,0xd,0xdb, +0x1c,0x84,0xe8,0x13,0x1e,0xf,0x9c,0x7a,0xc8,0x34,0xfe,0xb4,0xac,0x69,0x5d,0xaa, +0x6d,0x54,0xd2,0x9a,0x96,0x4a,0xeb,0x7b,0x88,0xac,0x83,0x49,0x3f,0x10,0x25,0x5c, +0x14,0x8e,0xee,0x33,0x9d,0xb,0x2d,0xe6,0x40,0x2c,0x1b,0x6c,0x95,0x79,0x17,0x4, +0x4d,0xe9,0x9e,0xe3,0x34,0xb,0xde,0x3c,0x37,0xe1,0x86,0xf6,0xf2,0x2b,0xd2,0x7, +0xb9,0xc1,0x3a,0xd7,0xcd,0xe6,0xbe,0x8d,0x13,0x59,0xf9,0x29,0xd2,0x91,0xac,0xa0, +0x7b,0x4b,0x84,0x30,0xd5,0xe3,0xeb,0xe,0xc5,0x72,0x84,0xb8,0x9e,0x57,0x40,0xd7, +0x98,0xf9,0xaf,0xe5,0xe1,0xed,0x73,0x74,0xc7,0xed,0x9d,0x9a,0x7f,0x4a,0xba,0x7a, +0x16,0x40,0x2a,0xeb,0x24,0x17,0x79,0x69,0x9,0x7d,0x23,0x27,0xd4,0x63,0x0,0x6e, +0xdc,0x2f,0x54,0xbe,0x9d,0x48,0x34,0x65,0x36,0x51,0x7f,0x35,0x9c,0x3b,0x2f,0x32, +0xfa,0xd9,0x9d,0x9e,0x70,0x18,0x8,0x79,0x15,0xaa,0xa1,0xea,0x8d,0xa1,0x59,0x6b, +0x50,0x2d,0x2a,0xed,0x75,0xdd,0x53,0x2b,0x30,0x53,0xdf,0xcc,0x8e,0x10,0xfe,0x89, +0x69,0x9c,0x28,0xd9,0x34,0xaf,0x53,0x4a,0x5b,0x74,0xb4,0xe8,0x95,0x8d,0x54,0xe6, +0xba,0x7f,0x54,0xb0,0xdc,0xa8,0xdb,0xd,0x7b,0xbc,0xd9,0xa,0x4c,0x58,0x13,0x35, +0x75,0xba,0xf,0x29,0x6a,0xe1,0xf2,0xc5,0x57,0xa7,0xaf,0xec,0x35,0x4,0xd3,0x70, +0x3,0x29,0x21,0x60,0x51,0x7c,0x6d,0xcc,0xb8,0xc7,0x56,0x84,0x20,0x69,0xb9,0x15, +0x24,0x48,0x3f,0x8e,0x2b,0xb1,0xd4,0x82,0x5a,0x84,0xee,0xf,0x8,0xc3,0xfe,0x8b, +0x6c,0x9f,0xeb,0x3d,0x1d,0x59,0x89,0x55,0x21,0xdf,0x5a,0xc1,0x49,0x14,0x56,0xec, +0xdc,0x15,0xfa,0x8,0xc7,0xcf,0xa,0x22,0x54,0x78,0xb0,0xdc,0xbb,0xb0,0x68,0x28, +0xcf,0xd3,0xe4,0x6c,0x2d,0x6e,0xc2,0xce,0x4e,0x1d,0x10,0x17,0xb0,0xe5,0x4,0xd, +0xfb,0x0,0x15,0xc3,0x4f,0x9e,0x65,0xa4,0x18,0x95,0x1,0xd3,0xc5,0x69,0x7c,0x96, +0x3d,0x61,0x3,0xe9,0xd0,0x45,0x38,0x9e,0xe1,0xc7,0xb6,0x13,0xae,0xba,0x20,0x2a, +0x3a,0x36,0xed,0x8a,0x54,0xd2,0xae,0xeb,0x68,0xaf,0xc0,0xae,0x98,0xbc,0x45,0x55, +0x1e,0xc7,0xbe,0x6e,0xe,0x77,0xe,0xef,0x3f,0xc4,0x3,0x6d,0xfe,0x24,0x97,0xb9, +0xd9,0x5,0xc3,0xad,0x57,0x72,0x9a,0xc0,0xa1,0xda,0xee,0x3a,0x97,0x34,0xf,0x35, +0xfb,0xcd,0xa4,0x89,0x45,0x32,0xf9,0x5,0xf6,0x7c,0x72,0x75,0x20,0x8a,0x2f,0x79, +0x8f,0xf2,0x28,0xe7,0xe4,0xc2,0x28,0x86,0x1d,0x17,0x40,0xb4,0xca,0x4f,0x69,0x46, +0x1e,0xe,0x50,0x63,0x40,0x4a,0x68,0xb6,0xc6,0x5b,0x2d,0xe7,0xe5,0xdb,0x61,0xf4, +0xcf,0x9,0xdc,0xb4,0x4b,0x84,0xbb,0x68,0x1b,0xfb,0x9c,0x65,0x4c,0x7,0xac,0x6a, +0x15,0xfc,0x4d,0xd5,0xc6,0xb6,0xc,0x8d,0x91,0xb8,0xf4,0x77,0x95,0xd6,0x6c,0xe4, +0xdf,0xc9,0x19,0xab,0xcd,0xd4,0x14,0xe9,0xd1,0xb1,0x4f,0x1e,0xb8,0x7b,0x8,0x4d, +0x78,0x55,0xa2,0x3f,0x8b,0xaf,0x4d,0x1d,0xe7,0xc1,0x14,0x7d,0x98,0x81,0x62,0xf8, +0xca,0x7c,0x24,0x98,0x51,0x38,0x2,0xa2,0x69,0x52,0x40,0x22,0x4d,0x48,0xef,0xc6, +0x9e,0x92,0x85,0xa9,0xc1,0xd2,0xc7,0xaa,0x15,0xdb,0xa7,0xad,0xdc,0xb,0x26,0xa7, +0x7,0x4a,0xc0,0xd7,0x3,0xc2,0x7b,0x6c,0x94,0xbb,0xf,0xe2,0x84,0xfe,0x29,0x23, +0x11,0xae,0xcc,0x53,0x2,0x14,0x7d,0x17,0x70,0x25,0x44,0x4d,0xaf,0xea,0x75,0x36, +0xb4,0xb5,0xf,0xb7,0x78,0xa,0xa4,0x8d,0x45,0xb3,0x70,0xc9,0xb2,0x99,0x6c,0x43, +0xc7,0xb9,0x96,0xc9,0x4d,0x14,0x60,0xbd,0xb9,0x25,0x8b,0x69,0x10,0x80,0x20,0x44, +0x36,0x2f,0xfc,0x2e,0xb8,0xa1,0xbb,0xfd,0xd4,0xab,0x48,0x7,0x45,0x34,0x4a,0x8d, +0xed,0x61,0xd6,0xbb,0xf4,0x38,0x79,0xae,0xdc,0x84,0x98,0xec,0x5,0xb8,0x31,0x3b, +0x67,0xad,0xe9,0x20,0xce,0xa5,0x9d,0xa3,0x52,0x65,0xaa,0x17,0x9a,0xf5,0xa4,0x8, +0xd6,0xfb,0x43,0xcb,0x34,0xbd,0x7b,0x11,0xc1,0x93,0x7d,0xc7,0x4c,0x2e,0x82,0x33, +0x5c,0x6c,0x53,0x2b,0x13,0x70,0x4f,0xe4,0x56,0xf9,0xfb,0x70,0x6f,0x21,0xf7,0x46, +0x1d,0x3c,0x13,0xd0,0x79,0xe,0x61,0x3b,0xa1,0x5e,0x3,0x6d,0x8c,0x86,0xa0,0xe8, +0x72,0xf3,0x94,0x5,0xe3,0xe3,0xe9,0x3a,0x5d,0x66,0x2a,0xcd,0x7,0x23,0x93,0xa3, +0x5f,0xa6,0x74,0xd8,0x34,0x55,0x14,0xd5,0xb3,0x18,0x43,0xbf,0x1e,0xe3,0x29,0x90, +0x57,0xbd,0x96,0xbb,0x21,0x0,0x75,0x7e,0x66,0xa0,0x4c,0xec,0xc3,0xe0,0x90,0x23, +0x7,0x84,0x7b,0xbb,0xd9,0x8f,0x11,0x8d,0x27,0x55,0xcd,0xc4,0xb8,0xf6,0x56,0x90, +0xb4,0x6c,0x4c,0x55,0xeb,0x41,0xd3,0xd2,0xe1,0x21,0xbf,0xa5,0x81,0x51,0x48,0x8, +0xd5,0xc3,0x43,0xb0,0xd3,0x55,0xbd,0xfa,0xaa,0x8b,0xc0,0xe2,0x2,0x96,0xf2,0x36, +0x82,0xbe,0x8b,0x6e,0x1,0x60,0x41,0x62,0x1,0x2,0x9,0x2,0xd2,0xd0,0x89,0xa8, +0x15,0xcd,0xd8,0xe8,0x23,0x17,0x63,0x4d,0x22,0xa3,0xaf,0x25,0xb9,0xa3,0x5b,0xbb, +0x62,0xe7,0x2b,0xe2,0x48,0xeb,0x46,0xc8,0x6d,0xce,0xca,0x40,0x9f,0x54,0x69,0x34, +0xa1,0xc1,0x9c,0xc4,0xd8,0x80,0x12,0xfb,0x24,0xc2,0xa0,0x5e,0xe5,0xfb,0x1a,0x48, +0xe3,0xc4,0x2c,0xab,0x31,0xf1,0xf3,0x9e,0xc0,0x3e,0x5f,0xdf,0x93,0xc8,0x15,0xb4, +0xa,0xb1,0x7a,0xe3,0x32,0x8c,0x5f,0xd6,0xce,0x0,0xb4,0xb4,0x7b,0x4e,0x7d,0xdf, +0x14,0x29,0xb,0x45,0x1b,0x0,0x63,0xdb,0x3e,0xc2,0xbb,0x51,0x8b,0x50,0x7,0x16, +0x82,0x81,0x79,0xb4,0x8d,0xd8,0xb,0xdc,0x58,0x3f,0x11,0x53,0x8e,0x8e,0x33,0xa2, +0xb7,0xbe,0x67,0x52,0xbe,0xca,0xad,0x7c,0x8e,0xe9,0x4e,0x99,0x3a,0x55,0xaf,0xbc, +0x56,0x29,0xf1,0x63,0x81,0x7c,0xbf,0x59,0xbc,0xd1,0x2d,0x4b,0xdf,0x60,0x6d,0x98, +0x9e,0xd4,0x6a,0x5d,0x1f,0x19,0x5a,0x2d,0x3,0xa8,0xc7,0x3d,0xfd,0xf6,0x7a,0xd3, +0xa0,0x6c,0xb6,0xa1,0xe8,0x77,0x7b,0xa5,0xc8,0xa8,0x70,0xa8,0x88,0xdd,0xc0,0x28, +0xb2,0x2c,0x5,0x52,0x45,0x5f,0x7f,0x48,0x87,0xc6,0x5,0x85,0x3e,0x7f,0xd8,0xde, +0x6b,0x90,0x0,0xd4,0x87,0xfa,0x7a,0x50,0x23,0xeb,0xf8,0xac,0xc9,0x3a,0x54,0xfc, +0x66,0xd8,0x4f,0x2b,0x39,0xce,0xf2,0xc0,0x96,0xf7,0xc6,0x54,0xf7,0x1f,0x33,0x63, +0x2f,0xb2,0x38,0x36,0xae,0x33,0x86,0xd1,0x9e,0x0,0xfd,0xe7,0x3a,0xd1,0xe4,0x20, +0xab,0xb3,0x4b,0x64,0x3,0x3e,0x25,0x19,0xb5,0x6b,0x6d,0xad,0xb,0x20,0x91,0x3a, +0xd2,0xc9,0x71,0x1,0x7c,0x77,0xd3,0x1b,0xf6,0x51,0x4,0xb0,0x24,0x68,0xd0,0xcf, +0x1d,0x9b,0x34,0x20,0xd9,0xd8,0xb8,0x10,0xc4,0x26,0xbd,0xcf,0x46,0x4f,0x89,0x19, +0x99,0x7a,0x9a,0x16,0x72,0xed,0x32,0x69,0x3f,0xb5,0x1b,0x63,0x1e,0x6b,0xb2,0xba, +0x8,0xe6,0xda,0x61,0x40,0x93,0x71,0x5,0x39,0xaf,0x54,0x7f,0x7e,0x5d,0x19,0x18, +0xd8,0xb3,0xae,0x4b,0xa1,0x60,0x34,0xe0,0x16,0x4f,0xc4,0x34,0x3b,0x77,0xef,0x43, +0xde,0x4a,0x24,0x1f,0x5e,0x16,0xa3,0x97,0xc5,0x77,0x97,0x44,0xd4,0xb0,0xdc,0xad, +0xe3,0x8b,0x78,0x85,0xeb,0xad,0xe5,0x2,0x7c,0x2a,0xb5,0xb7,0x22,0x25,0x7a,0x1, +0xef,0x9f,0x9f,0x4e,0xb5,0xc2,0x65,0x7b,0x3a,0x7c,0x3f,0xf,0xac,0x1c,0x3d,0x90, +0x27,0x35,0x95,0x92,0xe2,0xfb,0x94,0x60,0x26,0xca,0x97,0xc7,0x6f,0x13,0x48,0x5f, +0x32,0x67,0x2d,0xe7,0x2a,0x13,0xe2,0xe3,0x8f,0xa1,0xf3,0x3d,0x3e,0xb0,0xcd,0x65, +0xe5,0xe3,0xf8,0x49,0xdf,0xd,0x29,0x85,0x57,0xc0,0x4e,0xc7,0x53,0x96,0x27,0x85, +0x7e,0xd4,0x6d,0xa8,0xe7,0xcf,0x8d,0xf6,0x72,0x1,0x34,0xb0,0xb1,0x82,0x95,0x17, +0xe5,0xe,0x60,0xc5,0x1c,0x89,0xca,0x73,0xca,0x98,0xba,0x1e,0xaf,0xe2,0xa4,0x2e, +0x37,0x91,0xd6,0x1f,0x62,0xe3,0x95,0x54,0xe4,0xca,0x84,0x16,0xcc,0x1a,0xad,0xb2, +0x29,0xe,0xf7,0xc4,0x18,0xc2,0xb7,0xe2,0x5c,0x73,0x1,0x8b,0xd5,0x25,0xb9,0xd, +0xb7,0x90,0xab,0x99,0xf4,0x41,0xed,0xd9,0x8b,0x72,0x70,0xd7,0xc,0x1e,0x8a,0xb4, +0xab,0x2,0x79,0x43,0x45,0x32,0x26,0xa1,0xa5,0xa7,0x2d,0xfa,0x4c,0x66,0x8,0x4, +0xf6,0x33,0x1d,0xeb,0xf3,0xb,0x46,0x80,0xfc,0x36,0x58,0x89,0x54,0x63,0x3e,0x7f, +0xe4,0xb8,0xc3,0x2a,0x6a,0x69,0xcb,0x8f,0x90,0x78,0x8a,0xdd,0xde,0x12,0x61,0x56, +0x45,0x7f,0xc1,0x39,0xa,0x87,0x39,0x87,0xbd,0x12,0x11,0x91,0xf4,0x4f,0x12,0xd9, +0x87,0x55,0x5,0x71,0x3e,0x50,0x1,0xcf,0x49,0xb,0x2d,0xa7,0x1d,0x8e,0x7d,0xe1, +0x8d,0x40,0x9b,0x18,0xc7,0xd4,0x9f,0x6,0x66,0x30,0x97,0x5b,0xfe,0x29,0xb5,0x87, +0xfd,0xba,0x78,0x3d,0x8a,0x7a,0x8c,0xd3,0x85,0xb9,0xfb,0x23,0xc7,0x79,0x5,0xd5, +0xb9,0xa0,0xed,0x2,0xf5,0xd,0x8,0xdb,0x3d,0x1f,0xb7,0x3c,0x49,0x6d,0x43,0x47, +0xa7,0xbc,0x84,0x32,0xb6,0x90,0x86,0xbb,0x4a,0x82,0xde,0x92,0xfb,0xe4,0x68,0x36, +0x5,0xd5,0xb7,0x7a,0xe2,0xbf,0x57,0x9f,0xde,0xf,0xdb,0xa7,0xfb,0x9f,0xef,0xa3, +0xdb,0xf3,0x55,0x92,0x85,0xdb,0x4e,0x4f,0xdd,0xad,0x61,0x5a,0x12,0xc9,0x90,0x17, +0x9f,0x48,0x92,0x82,0x87,0x69,0x22,0xe5,0x78,0x7e,0x8e,0x74,0x9d,0xfd,0x97,0xf8, +0x71,0xec,0xb,0xf6,0x49,0xd8,0xc6,0xa6,0x86,0x28,0x1,0x98,0x72,0x11,0xb0,0x91, +0xd8,0xc2,0x15,0x60,0x2c,0xb6,0xc6,0x24,0xb4,0xd4,0x18,0xd1,0xd2,0xaf,0xca,0x44, +0x1c,0xd5,0xbb,0x65,0xaf,0x2,0xd,0xb5,0x2a,0xe,0x4f,0x1c,0x9f,0x7f,0xae,0x78, +0xc1,0x43,0x59,0xed,0x79,0x20,0x91,0x2f,0xf4,0xa9,0x80,0x47,0x59,0x4c,0x8b,0x75, +0xa1,0x47,0x5b,0xd0,0x49,0x68,0x87,0xf3,0xf5,0xd6,0x10,0x15,0x56,0x3e,0x8e,0x18, +0x81,0xe7,0x85,0xfb,0x87,0x96,0xaa,0xfb,0x40,0x2b,0x43,0x19,0x77,0x4e,0xe,0x99, +0x16,0x69,0x6a,0x5f,0x51,0xf1,0xd2,0xc7,0x48,0x63,0xdc,0x1e,0xa1,0xea,0xb5,0x24, +0x52,0x3b,0x9f,0x59,0x51,0x4a,0x55,0x91,0x75,0x18,0xaa,0x6d,0x67,0x39,0x7,0xfc, +0x22,0x71,0xdb,0x74,0xe3,0xaf,0xbb,0x2c,0x92,0x18,0x4b,0x34,0x4,0x80,0xd7,0x56, +0x3c,0x77,0xb0,0x8d,0xc1,0x85,0x20,0xb7,0x1e,0x4a,0x25,0x5,0x83,0xab,0x2,0xa6, +0x9c,0xdd,0x9a,0x80,0x8d,0x56,0x2d,0x20,0xed,0xf7,0xd4,0xf1,0x78,0x2c,0xc8,0xb4, +0xa4,0xf8,0x43,0xe5,0xfd,0x63,0x9d,0x1c,0x2d,0x42,0x21,0xb1,0xed,0xa2,0xd7,0x8b, +0x81,0xf1,0x8b,0x8e,0xc7,0xb8,0x2f,0xb5,0xb0,0x83,0xa8,0x2a,0xaf,0xf0,0x5e,0x54, +0x69,0xa1,0x3b,0x67,0x84,0x58,0x4,0xb2,0x9b,0xa4,0xe3,0x89,0x48,0xbb,0x94,0xc9, +0x2d,0x21,0xd7,0xf4,0xd9,0x7,0xaa,0xb,0x8a,0xd2,0xb4,0x3b,0xc3,0x13,0xf,0x2d, +0x35,0xc9,0x95,0xb9,0x23,0x19,0xeb,0x3e,0xbd,0xcf,0xc7,0x6,0xb,0x5d,0x4f,0x38, +0xfd,0x28,0x2d,0xd7,0x2f,0xd8,0x62,0x3a,0xab,0x17,0xf4,0xef,0xaa,0x4,0x1d,0xdf, +0xce,0x32,0x19,0x71,0x4b,0x6,0xaf,0xa,0x55,0xf6,0x8f,0x61,0xd3,0xdf,0x19,0xd1, +0x8,0xc6,0x2a,0xb6,0x9f,0xc,0x70,0xca,0x24,0x65,0xba,0x4e,0xe9,0x58,0xad,0x38, +0xa,0x46,0xa9,0xd5,0xcb,0xd8,0x5f,0x22,0xcf,0xee,0x3,0x24,0xce,0x1c,0xf5,0x56, +0xe2,0x9f,0xe,0x2,0xac,0x7e,0x4d,0x50,0x64,0x8,0x9e,0x4e,0xdf,0xcb,0x86,0x6a, +0x12,0xaf,0x40,0xde,0x88,0x1f,0x1,0x58,0x8d,0x83,0x7c,0xdc,0x9f,0xf2,0x33,0x3, +0x92,0xc0,0x84,0x3f,0xbf,0xd1,0x8f,0x24,0x5a,0xad,0xf1,0x3a,0x79,0x78,0x24,0xc, +0xa7,0xe3,0xea,0x30,0x3,0x6b,0x8,0x11,0xee,0x5,0xed,0xe,0xf7,0x21,0x90,0xa, +0x62,0x16,0xc9,0x22,0x67,0xd8,0xc5,0xc1,0x7,0xb7,0x7c,0x0,0xaf,0xa0,0xc,0x57, +0x5,0x76,0x7,0x8,0x61,0xf,0x19,0xcf,0x14,0x86,0x5e,0x8b,0xa8,0xee,0x16,0xb, +0x84,0x5f,0xac,0xec,0x38,0x72,0x2e,0x3f,0xa9,0xaa,0x40,0x59,0xcb,0xcb,0x30,0xd0, +0x43,0x37,0x58,0x24,0xc5,0x72,0xf4,0xda,0xf8,0x53,0xe5,0x21,0xc1,0x7b,0xab,0xc6, +0xda,0x58,0x33,0x14,0x4a,0x61,0xd2,0xf3,0xd,0x92,0xcc,0x58,0x5f,0x7c,0x29,0x22, +0xb3,0x81,0xc5,0xf9,0x73,0xba,0xd4,0xec,0x8d,0x3a,0x8d,0x50,0xb6,0x3a,0x96,0x91, +0x12,0xc9,0x25,0x5d,0x2b,0xf8,0xd0,0xb7,0x8b,0x1e,0x8f,0x6a,0x9a,0xb8,0xc,0xce, +0xba,0xd2,0xc8,0x2e,0xd,0x1d,0x9a,0x9b,0x57,0x29,0x6b,0x8d,0x63,0x2,0x20,0xf4, +0x4b,0x45,0x52,0x76,0xbd,0xa3,0xae,0xc9,0xc1,0x3e,0xb3,0x5c,0x77,0xc0,0x2b,0x32, +0x13,0x73,0xdf,0x20,0x90,0x7b,0xbb,0x68,0xa4,0xa6,0xf5,0x87,0x28,0x95,0x7c,0x73, +0xdb,0x4f,0x6a,0x19,0xf2,0x98,0xe2,0x34,0x56,0x97,0x90,0xcd,0xd7,0x3c,0x7f,0xea, +0xaf,0x60,0x8a,0xc0,0xdb,0xc6,0x29,0x0,0x6d,0x1f,0x7,0x96,0xb5,0x83,0x89,0x11, +0x52,0xf3,0xa9,0xc4,0x8c,0xd,0xf8,0xe3,0x24,0xa,0xb1,0xfb,0x46,0xb1,0x66,0x75, +0x12,0xf0,0xb5,0x6d,0xb7,0xde,0x6d,0xa5,0x7e,0x74,0xbb,0xb3,0x77,0x45,0x44,0xca, +0x3a,0xed,0xf,0xc6,0xfa,0x9,0x2a,0x1f,0x92,0x5c,0x9a,0xd8,0xe,0x1,0xcd,0x20, +0x72,0x4,0xd,0xa9,0xe2,0x7a,0x4f,0xe0,0x6e,0xb,0x14,0x65,0xd0,0x58,0xaf,0xb, +0xc6,0xbf,0x51,0xc1,0x48,0x7c,0x61,0xda,0x58,0x7b,0x33,0x66,0xfc,0x1,0x6,0x6f, +0x84,0x13,0x19,0x68,0xd,0xe8,0xc8,0xfa,0x73,0xdd,0x60,0x44,0x36,0x11,0xce,0x7c, +0x50,0x21,0xbe,0x98,0x1d,0x20,0x73,0xf4,0x1b,0xa6,0x5b,0x18,0x27,0xe0,0x87,0xac, +0x73,0x21,0x94,0x0,0x89,0x5d,0xfa,0xfc,0xba,0xda,0xc1,0x71,0x6b,0x90,0xed,0xbb, +0x31,0xac,0x54,0xcd,0x4c,0x47,0xc2,0x68,0xed,0x1e,0x80,0x95,0x7e,0x88,0x42,0xf1, +0x29,0x56,0x71,0xb2,0x33,0xeb,0x2f,0xee,0xc7,0xf0,0x60,0x33,0x82,0xcd,0x6f,0xb3, +0x7b,0x43,0x82,0xc7,0x8b,0x45,0xaf,0xf8,0xe3,0xb0,0x8e,0xe1,0xb8,0x50,0x54,0xe1, +0xa6,0xc5,0x14,0x5a,0xb2,0x43,0x49,0xf9,0x35,0x29,0xac,0xb7,0xf6,0x1c,0xea,0x72, +0x60,0xec,0xba,0x6b,0xb2,0xe9,0x64,0x16,0x9a,0xf3,0xf7,0xd2,0xc3,0x4c,0xb4,0x6b, +0x92,0xc8,0xc5,0xc4,0x8c,0x8e,0xbe,0xc1,0xb7,0xea,0xf8,0x2e,0x8,0xe3,0x21,0xe7, +0x51,0x5b,0x53,0x4,0x45,0xb7,0x99,0x60,0x2b,0x91,0x33,0xef,0x5e,0x68,0xda,0x70, +0xb0,0x20,0x35,0x3d,0x2e,0xf3,0x7e,0xe5,0xde,0x77,0x93,0x66,0xdb,0xb4,0xcd,0x2d, +0x10,0xa0,0xb0,0xd5,0xd8,0x4a,0x36,0x4,0x5b,0xe8,0x73,0x39,0xd0,0x4e,0xa9,0x82, +0xed,0xde,0x3f,0x1c,0x52,0xbe,0x81,0xb1,0xb5,0x16,0x18,0x91,0xca,0x66,0x3e,0xdb, +0x7,0xee,0x31,0xdf,0xb8,0x67,0x64,0x94,0xcf,0xd7,0xcd,0xa1,0xa6,0x78,0xa3,0x14, +0x57,0x62,0x31,0xaa,0x21,0xb2,0x5c,0x57,0x48,0xf3,0xe8,0x14,0xd9,0x28,0x6f,0xe1, +0x96,0xa0,0x41,0xcf,0x87,0xa5,0x64,0x57,0xfd,0x32,0x78,0xa4,0xaa,0x1c,0xb8,0x3, +0x7f,0x69,0x2d,0x20,0x9c,0x89,0x77,0xe4,0xfc,0x61,0xf8,0xd7,0x9,0xe7,0x39,0x1f, +0x88,0x7a,0xee,0x8f,0xa0,0x53,0xe7,0x1e,0x6,0x60,0x42,0xb0,0xfc,0x7a,0x33,0x7c, +0xe4,0x60,0x9c,0x81,0x69,0x94,0xe5,0x67,0xf5,0xdf,0xbe,0x7e,0x47,0x77,0x9d,0x50, +0xf1,0xd,0xdf,0x12,0xdf,0x47,0x30,0xe5,0xa8,0x72,0x97,0x25,0xed,0xca,0xa1,0x52, +0x2c,0xbd,0x53,0x15,0x52,0x39,0xfb,0xc7,0x19,0xba,0xc5,0xe0,0x32,0xe3,0x31,0xa4, +0xf0,0x90,0x36,0xd0,0xd8,0x67,0xb7,0x1,0x59,0x4f,0x26,0xc6,0x99,0x47,0x19,0x45, +0x5,0x6c,0x5b,0xd7,0xa6,0x57,0x1f,0x3f,0x92,0xe5,0x20,0xc4,0xc9,0xd0,0xe8,0xba, +0x62,0x20,0xb,0x3b,0x7,0xc2,0x3c,0x60,0x91,0xe1,0x28,0x2c,0x29,0xc0,0xf0,0xad, +0x2e,0x4c,0x85,0x54,0x24,0xa5,0x93,0xb6,0xb,0x34,0x7b,0xd4,0x84,0xe4,0xf,0xe6, +0x5,0x1a,0xa1,0xc,0x5d,0x5d,0xeb,0xee,0x3f,0x14,0x9a,0x68,0x55,0x8c,0x96,0x3, +0x58,0x1c,0x57,0x7c,0x41,0x6a,0x33,0xcb,0x1e,0x2f,0x20,0xa3,0x14,0x2f,0x8a,0x19, +0xc9,0x2d,0xa4,0xa6,0x8a,0x90,0x15,0x4a,0x25,0xb0,0x32,0x7a,0xbc,0xc8,0x7d,0x15, +0x65,0x54,0x12,0xa6,0xbe,0x45,0x73,0xdd,0x74,0x13,0x1,0x8,0x43,0x8b,0xa0,0x8c, +0x38,0x45,0xb2,0x43,0xd6,0xc7,0x8d,0xfb,0xf7,0xbf,0xf5,0xb4,0x9,0xf2,0x4a,0x6e, +0x47,0x5c,0x94,0x6,0x21,0x87,0x63,0x16,0x9b,0x64,0x1e,0x5e,0x70,0xbf,0x6a,0xa8, +0x84,0x1d,0x6b,0x5b,0xe4,0xf8,0xd6,0x5d,0x39,0x4c,0x91,0x42,0x3f,0xdb,0x30,0x86, +0xb7,0xc4,0xd,0x59,0x4d,0xef,0x6f,0xe8,0xd4,0xd,0xc6,0x45,0x4c,0x31,0x6d,0xd1, +0x4e,0xd9,0xac,0xb2,0x52,0x4,0x8f,0x8b,0x50,0x22,0x4d,0x10,0x7d,0x7d,0x16,0x36, +0xc2,0x23,0xf,0x8f,0x93,0x7e,0x78,0x68,0xb,0xbe,0xad,0x58,0xef,0x9a,0x2a,0xbd, +0x74,0x56,0xef,0xc7,0x5a,0x80,0xd2,0x2b,0xa2,0xa0,0x3b,0x20,0x9d,0x51,0xd5,0xdf, +0xf4,0xe4,0x6f,0x88,0xe2,0x67,0x70,0xee,0x26,0x1e,0xc6,0x16,0x38,0xf0,0x53,0xad, +0xc6,0x44,0xf4,0xa1,0xc4,0x47,0xcc,0xe6,0x67,0x87,0x86,0x6,0x58,0x5d,0xe5,0xcc, +0xc1,0x56,0xd4,0x25,0xbd,0x45,0x93,0x64,0x63,0x5a,0x7a,0x1c,0xca,0x4e,0xc9,0x91, +0x92,0x3e,0x33,0xd6,0x5,0x7f,0xbd,0x6d,0x7,0x44,0xf2,0xdf,0x21,0x58,0xac,0xe3, +0x2e,0x82,0x88,0x6c,0xc7,0x1c,0xd0,0xab,0xf5,0xca,0xc7,0xc0,0x19,0x11,0xd1,0xab, +0x4f,0x6,0x2,0xd3,0x5,0xbf,0x41,0x8c,0x5,0x34,0x6c,0x26,0xd,0x19,0x89,0x3b, +0x1b,0x91,0xa7,0x63,0xad,0xf7,0xf,0x23,0xc3,0x56,0xe3,0x5c,0x67,0xb6,0x88,0x36, +0x3c,0x8a,0xa,0x41,0x4b,0xcb,0xcd,0xcf,0x7f,0xb9,0xf5,0x8c,0x53,0x0,0xc8,0x6e, +0x91,0xef,0xd1,0xbf,0xe8,0x60,0xe2,0x2c,0xb6,0xc7,0x88,0x9d,0xfd,0x11,0x53,0xb9, +0x9c,0xdd,0x7a,0xe7,0xa9,0xc8,0xb7,0x29,0x82,0x2d,0x36,0xd5,0xac,0xfe,0xc4,0x3f, +0x6e,0x16,0xfe,0xd6,0x77,0x61,0x3,0xad,0xa8,0x8c,0xcb,0x26,0x1d,0x1f,0xdf,0xb9, +0xfc,0x5b,0x21,0xa6,0xa3,0x58,0x50,0x26,0x6,0x86,0x7c,0xb2,0x5,0x41,0xf1,0xf2, +0xd6,0x70,0xca,0x4e,0xd2,0x4d,0x7c,0xfa,0x59,0x48,0x22,0x77,0xe6,0x2,0x31,0xe4, +0xdc,0xd2,0xb,0x80,0x2b,0x5b,0x27,0x31,0x61,0xa3,0xe4,0x66,0x64,0x56,0x5a,0x3b, +0x47,0xa4,0xa,0x1a,0xf1,0x86,0x94,0x4c,0x4e,0xb6,0xc3,0x35,0x39,0x74,0x1a,0x16, +0xc6,0xa5,0x17,0x72,0x80,0x3e,0x23,0xe2,0x61,0x87,0xc8,0x45,0xde,0xa2,0x80,0x26, +0x47,0xa,0xbf,0x3a,0x10,0x54,0x6,0x5e,0xc,0x49,0x94,0x45,0x3d,0x2e,0xda,0x5, +0x53,0x71,0x77,0xd4,0x2f,0x9a,0xb7,0x90,0x23,0x80,0x55,0x81,0x24,0x56,0xa7,0xea, +0x60,0xe6,0xa4,0x71,0xba,0xaa,0x4f,0x46,0xf3,0x63,0x8b,0x32,0x12,0xe6,0xb6,0x65, +0x58,0x2e,0x3a,0x8,0x48,0xf1,0x98,0x6b,0xf2,0x6e,0x6c,0x96,0xc4,0x93,0x81,0x25, +0x7a,0x27,0x16,0x36,0x51,0x66,0x7c,0x46,0xc9,0x88,0xf7,0xdb,0xee,0xae,0xc1,0xc6, +0x5c,0xfb,0xce,0xa4,0x6e,0xe7,0x90,0x61,0x56,0xfc,0x77,0x1b,0x91,0x78,0xbf,0x8b, +0x9f,0x56,0x41,0x71,0xbc,0x3e,0x37,0x6,0xc6,0x2f,0x62,0x35,0x5d,0x24,0xfb,0x39, +0x9f,0xcb,0xdd,0xe,0x33,0xed,0xee,0x89,0x6b,0x66,0x24,0xfc,0xdf,0x63,0x8,0xfe, +0xb9,0x4a,0x70,0xf5,0x88,0xa7,0xfc,0xce,0x56,0xde,0x4,0x33,0x3,0x7f,0x6c,0xa2, +0x4b,0xca,0x31,0xfd,0xb8,0x20,0x87,0x24,0x7,0x2b,0xa0,0x66,0x8f,0xa9,0xe4,0xc8, +0x73,0x56,0xbf,0xfb,0x7d,0xbc,0x4a,0x54,0x1b,0x4e,0x87,0x9d,0xcd,0x74,0xbf,0x99, +0x3f,0xf0,0x97,0xf7,0x91,0x9f,0x9c,0x98,0x4a,0x3d,0xfe,0x59,0x66,0x63,0x23,0xd9, +0x39,0xe2,0x55,0xb7,0x1f,0x9f,0x8b,0x3a,0x6d,0x92,0xd7,0x3c,0x7,0x97,0x55,0xc5, +0x89,0x6c,0x3e,0x1b,0x8b,0xda,0x33,0xd6,0x97,0xb1,0x30,0xfe,0x15,0x53,0x58,0x4f, +0x36,0xae,0x86,0xd4,0xcd,0x91,0xf,0x3c,0x24,0x66,0xf7,0xab,0xfe,0x4d,0x71,0x8, +0x39,0xaf,0xa2,0xc5,0xa,0x55,0x9c,0xa2,0x7,0x4c,0x21,0x9b,0x20,0xf8,0xea,0x56, +0xa7,0xf0,0x2c,0x76,0x82,0xba,0x32,0x27,0x22,0x2a,0xd2,0xa0,0xf6,0x44,0x28,0x30, +0x74,0xca,0xf5,0xfd,0x20,0x12,0xa0,0xa6,0xde,0x41,0x42,0xfe,0x3b,0xad,0xd4,0x62, +0x1e,0x80,0x58,0xa1,0x3c,0x8a,0x48,0xdd,0xb4,0x1b,0x7e,0xab,0xde,0xa6,0x5c,0x53, +0xf0,0xd1,0x52,0x90,0xe4,0x72,0x37,0x43,0x34,0xf8,0x42,0xee,0x26,0x17,0x51,0x45, +0x98,0xaa,0x66,0x54,0x35,0xae,0x32,0x6a,0x49,0x30,0x95,0x28,0xd6,0xf1,0xfb,0x47, +0xc4,0xcd,0xd7,0x29,0xbf,0x8e,0x6c,0xf3,0x7,0x2e,0x62,0xad,0x45,0xb4,0xf2,0xdd, +0xde,0xd8,0x32,0x93,0x7,0xe3,0xfd,0xcf,0x14,0x14,0xf7,0x6a,0x6,0x73,0xb1,0x4a, +0x41,0x9,0xf2,0x81,0x97,0xde,0xf4,0x1f,0xd,0x58,0xcc,0x53,0xd,0x3f,0xb0,0x6b, +0x97,0x63,0xfe,0x1e,0x47,0x7d,0xed,0x5c,0x91,0x65,0xc6,0x17,0xd9,0xf8,0xe1,0x9a, +0x2,0xd4,0x9b,0x1a,0xb4,0x91,0x39,0xc1,0xe9,0x85,0x94,0x76,0x44,0x46,0xe1,0xdb, +0x29,0x60,0xf9,0x70,0xdd,0x67,0x4c,0xee,0xcc,0x14,0x7,0x26,0xd,0xe8,0x41,0x8e, +0x3d,0xdc,0xa8,0x71,0xed,0x61,0xb3,0xd7,0xe6,0x48,0xcd,0x2b,0xe,0x2f,0x86,0x37, +0x90,0x0,0xa8,0x6e,0x67,0x74,0x5e,0xb4,0x88,0xe4,0x5a,0x15,0x4d,0x9b,0xa4,0x8a, +0xf8,0xcc,0x7c,0xe6,0x2f,0x30,0x3f,0x95,0x78,0xd,0xc1,0x7,0x3d,0xc7,0x3e,0x4d, +0xc8,0x66,0xbb,0xaf,0xdb,0x99,0x64,0xe3,0xfd,0xbf,0x79,0x4b,0xda,0x1e,0x56,0x53, +0xea,0xd2,0x3b,0x99,0x3,0xf9,0x30,0xfa,0x86,0x71,0x2,0xc3,0x39,0xc0,0x90,0x81, +0xa6,0xcc,0x32,0x2,0x66,0x16,0x66,0x65,0x55,0xdf,0x30,0x31,0x7d,0x86,0x4,0xe7, +0x59,0xbe,0x82,0xdb,0xb8,0x32,0xd7,0x40,0xa3,0x59,0x83,0x5c,0x99,0x15,0xde,0xc0, +0xe1,0x90,0x42,0xc7,0xa6,0x28,0xac,0xfc,0x8,0xdd,0xad,0x5,0xe3,0xb1,0xed,0xbd, +0x71,0xef,0x99,0xa9,0xa1,0xf0,0x69,0x45,0xca,0xed,0x21,0xe3,0x82,0x0,0x24,0x64, +0x90,0xe6,0xab,0x38,0xf,0x59,0xb4,0x97,0xb6,0x62,0x9c,0x9a,0x14,0xa,0xd7,0x5, +0xf9,0x72,0xaf,0x9b,0xe2,0x19,0x60,0xad,0x86,0x82,0x12,0x9,0x2,0x36,0xec,0x13, +0x1d,0x19,0xca,0x2d,0xf1,0x7f,0x44,0xa8,0xe1,0xe0,0xc2,0x75,0xeb,0x9b,0xfa,0x65, +0x8d,0xaa,0x81,0x70,0x43,0xe1,0x9e,0x4a,0xe3,0xb0,0xd2,0x66,0x66,0x40,0x79,0x84, +0x59,0x44,0x31,0x4b,0x43,0x75,0x73,0x25,0xd5,0x36,0x1a,0xc1,0x51,0x15,0xa7,0xde, +0x3f,0x29,0x50,0x3,0x8a,0xee,0x4d,0x6f,0x1f,0x9f,0x55,0x85,0xdf,0xce,0x89,0xb8, +0x92,0x3a,0x83,0xd5,0x2f,0xf6,0x7a,0x6,0xad,0x94,0x47,0xfe,0xaa,0xee,0xde,0xe9, +0x18,0xae,0x6c,0x23,0x1d,0x39,0x12,0x3c,0xd9,0x67,0xc1,0x39,0x36,0x4c,0x72,0xc8, +0x6,0xf5,0x1e,0x36,0x6d,0x98,0x3c,0x9a,0x2d,0x83,0x99,0x57,0xf2,0xf7,0xc1,0x8a, +0x26,0x2e,0xad,0x43,0x68,0xbf,0x7f,0xc1,0x27,0xc1,0x7a,0xdc,0x8d,0xec,0x25,0x93, +0x63,0x43,0xc9,0x50,0x5b,0x85,0xea,0x89,0xa,0x84,0xe0,0x7c,0xfc,0x22,0x7,0x23, +0x51,0xb5,0xe6,0x39,0xf4,0x66,0xfa,0x9c,0xa7,0xf4,0xf8,0x35,0x62,0x1f,0xc9,0xc5, +0xe1,0x93,0x16,0x3e,0x1a,0x1,0x47,0xa3,0x5,0xa7,0x9f,0x81,0xca,0xa6,0x25,0x1c, +0xdb,0xc,0xd4,0x51,0xf1,0x4f,0xed,0x9a,0x44,0xe6,0x4f,0xa6,0x85,0x19,0x6c,0xe7, +0x2d,0x2,0x26,0xc6,0x82,0x6d,0xe9,0x8,0x15,0x89,0x89,0x5f,0xaf,0xae,0x7b,0x8c, +0x3a,0x50,0xdd,0x2d,0x1f,0x4b,0x47,0x64,0xb1,0x96,0xb,0x38,0x30,0xf7,0x9f,0x5d, +0x79,0xc5,0xa3,0x7c,0xb2,0x8d,0x84,0x47,0x96,0xe,0xa7,0x46,0x3d,0xa2,0xd2,0xf6, +0x73,0x30,0x24,0x92,0x7b,0xea,0x76,0xad,0x82,0x82,0x65,0x32,0xf9,0x5,0x8f,0xf2, +0x4a,0xb2,0x6f,0xfc,0xbf,0xf3,0xc3,0x56,0x82,0xea,0x9c,0x3f,0x8e,0xef,0x36,0x81, +0x9f,0xda,0x14,0x9b,0xc5,0x8b,0x49,0xc7,0x8d,0xae,0xf9,0x7,0xb3,0x9,0x79,0x7d, +0xbb,0xe9,0x7a,0x7b,0x5d,0xbd,0x51,0xdf,0xa9,0x6e,0x9e,0xb7,0x5e,0xd5,0xb8,0x7d, +0xb0,0x4c,0x19,0xf5,0xd7,0x62,0xbe,0xe4,0x90,0x38,0x6b,0xc3,0x42,0xe5,0x41,0x7d, +0x4f,0x3b,0x79,0xac,0xf9,0xca,0xd,0x23,0x39,0x2b,0x5a,0x17,0x1,0x13,0x95,0x31, +0x5f,0xae,0x28,0xb7,0x91,0x66,0x1c,0x22,0x9e,0x88,0x66,0x60,0xed,0xa7,0xde,0xbc, +0x63,0x58,0xe8,0xdc,0xa2,0xf5,0x0,0xdc,0x22,0xd9,0xf3,0xa2,0xec,0x89,0x54,0xcb, +0xb8,0x7c,0x83,0x4a,0x62,0xa0,0xeb,0x80,0xa8,0x52,0xe1,0x16,0x7a,0x40,0xd2,0x5d, +0x18,0xbb,0x3a,0x3a,0x32,0xb9,0x17,0xd3,0x93,0x8b,0x76,0x0,0x94,0xca,0xcb,0x4d, +0xc6,0x50,0x17,0xa8,0x70,0x4,0x2a,0x98,0xd5,0x8b,0xae,0xcf,0x4b,0x1,0xac,0x63, +0xbc,0xe6,0x9d,0x6e,0xa0,0x35,0x42,0xb3,0x40,0x39,0xb3,0xd4,0x83,0x80,0x23,0x4b, +0x50,0xb9,0x73,0x40,0x3d,0x9d,0xd8,0x93,0x29,0x7,0x63,0x74,0x8,0x90,0x57,0x44, +0x77,0x75,0xb3,0x98,0x2a,0xf5,0x4c,0x6a,0x2f,0x1,0x3f,0x33,0x1,0xe1,0xfd,0x51, +0x1c,0x71,0x11,0x59,0x10,0xe9,0xec,0xb8,0xf0,0xd0,0xad,0xf8,0x61,0x84,0x3d,0x58, +0xf9,0xf0,0xf0,0xa3,0x67,0x3e,0xe,0x16,0xbe,0xcd,0x49,0x3f,0x2f,0x47,0x90,0x4b, +0x39,0xa1,0x25,0x49,0xb,0x12,0x81,0xfb,0x62,0x2f,0x74,0x43,0xb4,0x31,0x9c,0x2e, +0xa2,0x8d,0xd2,0x89,0x4b,0x60,0x9f,0x89,0x2e,0x69,0xc8,0xdd,0xb0,0xd8,0xa8,0x69, +0xf9,0xcd,0xb2,0x5,0x60,0x35,0x80,0xc2,0xe3,0x74,0x86,0x18,0xa6,0x23,0x47,0xc8, +0x30,0x1a,0x52,0xfb,0x7a,0x71,0x85,0x29,0xda,0x4f,0x86,0xc,0xa7,0x2f,0x75,0xa2, +0xfd,0xa8,0x27,0x5e,0x5d,0xa8,0xa0,0x41,0x9c,0x27,0x5a,0xc2,0x4a,0xa1,0x8b,0xfa, +0x3b,0x5d,0xf6,0x35,0xcf,0x7c,0xdd,0xaa,0x4b,0x64,0xb6,0xf3,0x94,0xac,0x16,0x12, +0x55,0x3d,0x70,0xb2,0xe5,0x90,0xf3,0x3,0xb8,0xcd,0xc5,0x82,0xee,0x52,0xfc,0x2a, +0xaf,0xf3,0xdf,0xfe,0xf0,0xbd,0xaa,0x3c,0xa2,0xe0,0xaf,0xb6,0x8d,0xc5,0xc8,0xe2, +0x4,0xb8,0x15,0x69,0x49,0x89,0x6c,0x81,0x57,0x33,0x84,0x47,0x5,0x81,0xf0,0x34, +0x76,0x50,0x34,0x67,0x8e,0x5e,0x23,0x31,0x3f,0xd3,0xe7,0x4d,0x99,0xb0,0x30,0x9d, +0x69,0xc5,0x87,0x32,0x4f,0xf3,0xb4,0xa6,0xa6,0x39,0x6d,0x2b,0xba,0xde,0x60,0xb0, +0x2f,0x14,0x18,0xbd,0x72,0x3c,0x6e,0xb1,0x8f,0x56,0x7e,0x29,0x86,0x2f,0x47,0x6f, +0xf4,0xce,0xa2,0x44,0x42,0xd6,0xea,0x69,0x8f,0xd8,0x94,0x4a,0xb7,0x74,0x7b,0x66, +0x88,0x13,0x25,0xfa,0xce,0x93,0x2d,0x5e,0x6a,0xab,0x8,0x70,0xda,0x4f,0x60,0x4f, +0x9d,0x82,0x93,0x5f,0x59,0xfe,0xc8,0xe8,0xd7,0xdd,0xb2,0xf,0x52,0xad,0x75,0xdb, +0xc1,0x9a,0x56,0x90,0xae,0x83,0xef,0x98,0xaf,0xf7,0x88,0xa,0xc6,0xe8,0x5a,0x64, +0x6b,0x6d,0x43,0x44,0x6c,0xd,0x2d,0x44,0x6a,0x60,0x53,0xbc,0xe,0x49,0x18,0xcf, +0xe3,0x6f,0xe0,0x12,0x72,0xd0,0x2a,0xa1,0x48,0xb3,0xac,0xf,0x1c,0x86,0xf2,0x88, +0xf3,0x36,0xcc,0xe0,0xc2,0x7a,0x25,0x2d,0xda,0xf8,0x6a,0x68,0xc1,0x82,0xb8,0xa5, +0x71,0x99,0x38,0xe4,0xe9,0xe1,0x6,0x32,0x95,0xb2,0xc0,0xb2,0xb8,0xb3,0xba,0x2d, +0x69,0x87,0xe,0x2d,0x2,0xb2,0xd9,0x5c,0x2b,0xc3,0x45,0xec,0x47,0x7d,0x13,0xb8, +0x17,0xca,0x1d,0x80,0xac,0x24,0xb2,0xc2,0x56,0x73,0xf4,0x8f,0xa6,0xaf,0xbc,0x10, +0xb6,0x4a,0xbc,0x39,0xfc,0x17,0x95,0x29,0xda,0x5a,0x95,0x22,0xd7,0xa8,0x5b,0x6e, +0x73,0xf7,0xee,0xa0,0x9b,0x21,0x63,0xf2,0x14,0x58,0x2,0xba,0x87,0xbe,0x4b,0x3e, +0x9,0x87,0x77,0x85,0x9e,0x8d,0x2e,0x7a,0xe7,0xc4,0x1c,0x40,0xec,0xf6,0xae,0xe0, +0x6f,0x9e,0x81,0xb,0xbf,0x64,0x7d,0x54,0xbc,0x7f,0xf,0xc3,0x3e,0xd9,0x2,0xc6, +0x62,0x7a,0x4d,0x1,0x8,0x7b,0xfa,0x6f,0xbf,0x97,0xaf,0xad,0xe,0x5f,0x8e,0x7d, +0x7d,0x10,0x89,0xbc,0xf3,0x7,0x11,0x30,0x87,0xa0,0xf3,0x45,0x7a,0xf5,0x8c,0x5c, +0xef,0xd9,0xdd,0x77,0xd4,0xd8,0xe7,0x95,0xef,0x97,0x43,0xfe,0x76,0x51,0x7c,0xf3, +0x61,0x6,0x31,0xd4,0x8d,0x42,0x5,0x94,0xe2,0xf8,0xd9,0xdd,0xee,0x66,0x3a,0x5f, +0xbf,0x18,0xd6,0x95,0x71,0xbe,0xaa,0x61,0xd6,0x6d,0x60,0x4d,0xbe,0x5d,0xc1,0x9f, +0xe2,0x72,0x74,0x70,0xb4,0x79,0x5,0x18,0x72,0x5f,0x75,0xe0,0x45,0xaf,0x40,0x6, +0x48,0x18,0x1b,0xb9,0xd6,0x45,0x9a,0x2d,0xb2,0x7b,0xfa,0x71,0xd8,0xbc,0x11,0xbb, +0xae,0x85,0xac,0x63,0xfe,0xb1,0xfa,0xf0,0x90,0x70,0xd1,0xd6,0xa0,0x13,0x5c,0x68, +0xaa,0xf6,0x22,0x1,0x3c,0x3c,0x2f,0xee,0xb7,0x2a,0xdf,0x90,0x66,0xf0,0xcc,0x15, +0x76,0x79,0xf7,0xf4,0xaa,0x73,0xe5,0x3c,0x63,0x37,0x92,0x4,0x4a,0x6e,0x6c,0x74, +0xe4,0xe,0x76,0x21,0xca,0xa5,0x8f,0x82,0x4f,0x6f,0x93,0xb5,0xdf,0x60,0x4a,0xd5, +0xd9,0x42,0xca,0x84,0xb5,0x30,0x40,0x1a,0x67,0xd2,0x9d,0x32,0xc0,0x8a,0xa6,0xa5, +0x18,0x1d,0x46,0xe2,0x42,0x55,0xe5,0x91,0xc4,0x79,0xc6,0x24,0xd9,0x11,0xf9,0xb3, +0xd3,0xc4,0xb7,0x89,0xf4,0xf8,0x23,0x5d,0x4b,0xc1,0xf,0x8c,0xcb,0xb5,0xb1,0xe3, +0xd3,0xf8,0xc7,0x95,0x4e,0xad,0x28,0x93,0xa6,0x6e,0xb7,0x80,0x80,0x32,0xb3,0x54, +0xf6,0xea,0x5d,0x6c,0xe3,0x81,0x49,0xaf,0xc2,0x58,0xbb,0x8e,0xe,0x6d,0xf1,0x61, +0x66,0xb9,0xf7,0x35,0xe6,0x9f,0x48,0x8d,0x8d,0x0,0x8d,0xe,0xb1,0xc0,0xe1,0xa9, +0xac,0xbf,0x95,0x10,0xc0,0x5e,0xbf,0x3,0xb6,0xfa,0x91,0x44,0x69,0x83,0x26,0xcf, +0xbd,0x9d,0x84,0x24,0x3d,0xcc,0x32,0x4a,0x4d,0x3f,0xd8,0xfe,0x1,0xba,0x28,0xad, +0xf9,0xbd,0xbd,0xba,0x1c,0xfd,0x3d,0x52,0xf8,0xce,0x17,0x62,0xd2,0x3d,0xb2,0x10, +0xda,0x37,0xb3,0x97,0x5,0x65,0xe1,0x52,0xa5,0xba,0x51,0x26,0xf5,0x7a,0xd3,0x6f, +0xb7,0x11,0x2b,0x54,0x8e,0x68,0xa6,0x8,0xb7,0xbd,0xe9,0xa,0x7a,0x1c,0x99,0x55, +0x54,0x4d,0xec,0xd8,0x33,0x4f,0xaa,0xd8,0x89,0x7b,0xfe,0x7f,0x75,0x52,0xef,0x2e, +0xe2,0x9a,0x82,0xf1,0x82,0xa8,0xf9,0xb9,0xe6,0x63,0x43,0x61,0x80,0xdc,0x37,0xd4, +0xaa,0xa3,0x2d,0xdd,0xf2,0xd7,0xb6,0x7d,0x53,0x35,0x7c,0xc9,0x7,0x6c,0x77,0x69, +0x86,0x79,0x5b,0xa,0xa1,0xd4,0x43,0x88,0x39,0x87,0x6a,0xb9,0x64,0x21,0xe,0xf, +0xc4,0x3b,0x6c,0xb8,0x92,0x23,0xb5,0x65,0xd7,0x32,0xae,0x5e,0x1f,0x26,0xc8,0x25, +0x1f,0xa3,0x2f,0xc1,0x79,0xf2,0xc9,0xb2,0x7a,0xb3,0xeb,0x5e,0xd4,0xf9,0xed,0x9a, +0xb4,0x5a,0xd2,0xc6,0xfd,0x88,0x2c,0x55,0x3a,0xdb,0xb4,0xd8,0x81,0xfc,0xfe,0xa1, +0xa0,0xad,0x63,0x1a,0xa0,0xac,0x4c,0x9a,0x61,0x38,0xf9,0x36,0xb1,0x67,0xd0,0xe5, +0xc1,0xa3,0xac,0xbf,0xab,0x59,0x16,0x66,0x35,0xca,0x3f,0xb6,0x47,0xbd,0x58,0xe7, +0x6c,0x3b,0x3,0x8c,0xe8,0xce,0x28,0x4a,0x8,0xa1,0x0,0x39,0x9,0x51,0x9f,0x4a, +0x74,0x4c,0xb,0x21,0xa5,0xa0,0x7,0x5a,0xea,0xc5,0x91,0x32,0x84,0x69,0x1a,0x70, +0xa5,0x9c,0xfc,0xe,0x6c,0xa4,0xd7,0x74,0xc5,0xd7,0x2d,0x4e,0x29,0xcc,0x99,0x9e, +0x99,0xa4,0x3f,0xbe,0xc4,0xc5,0x1a,0xaf,0x8b,0xab,0xe1,0x10,0x15,0xfb,0x0,0x3a, +0x99,0x7d,0xc7,0x6,0x22,0x9f,0xf9,0xe8,0xf7,0xa6,0xb6,0xa0,0x74,0x50,0x3f,0xe, +0x74,0xfd,0xcc,0x39,0xc3,0x66,0xe8,0x50,0x91,0xca,0xdf,0x27,0x47,0x60,0x61,0xe0, +0xdd,0x2a,0x66,0x0,0x49,0xdf,0x68,0x41,0x86,0x20,0xe2,0xfa,0x70,0xa1,0x88,0x65, +0xa0,0xd5,0x9e,0xe3,0x3c,0x88,0xb3,0xce,0x53,0x94,0xf5,0x1a,0xf4,0xd6,0xfa,0x52, +0x80,0xe0,0x52,0xca,0xc0,0x3b,0x8b,0x48,0xda,0x6e,0xc2,0xca,0x90,0x4c,0x30,0xb0, +0xa1,0xcf,0x94,0xdd,0x58,0x49,0x2c,0x2b,0x5d,0x22,0x46,0xd1,0x79,0xc0,0x24,0xf9, +0xa2,0xf5,0xc4,0xe2,0x31,0xd0,0xaa,0xc,0xbe,0x6e,0x57,0x4f,0x3a,0x87,0x0,0x5b, +0x57,0x15,0x39,0x2f,0x5e,0x66,0x5b,0x3b,0x8,0xa1,0x8c,0x81,0x62,0xb0,0x7c,0x84, +0xa6,0xc0,0xe7,0x58,0x11,0x92,0xe3,0xd0,0x80,0x3b,0x20,0x3a,0x43,0xa0,0x95,0x9a, +0x35,0x4f,0xca,0x13,0xb5,0x26,0x4e,0xbd,0x47,0xda,0xbf,0x29,0xb,0xbb,0x2e,0x31, +0xfb,0x16,0x89,0xe,0xa8,0xed,0xde,0xa9,0xa8,0x7e,0xe3,0xeb,0x9e,0xf9,0x87,0xd3, +0x49,0xd1,0xe6,0xfe,0x77,0xb4,0x3c,0x3e,0x8f,0x7b,0x67,0x1a,0x37,0x15,0x4c,0x34, +0x2b,0x55,0x42,0x54,0x43,0xa0,0x7d,0xec,0x1f,0xe0,0x58,0xbe,0xda,0x5f,0x12,0x24, +0x31,0xf9,0xa2,0x28,0x2e,0x5f,0x66,0x3e,0x5a,0x4e,0x58,0x92,0x63,0xa4,0x46,0xf, +0x7a,0x8,0xe2,0xbd,0xa8,0x60,0x2a,0x47,0x41,0x83,0x85,0x1d,0x62,0x98,0xc0,0x14, +0x12,0xe3,0x3c,0x40,0xc2,0x23,0xfd,0x1d,0x71,0x57,0x2f,0x54,0x7b,0x75,0xe2,0xf5, +0x7d,0xc5,0x34,0xa5,0x26,0x5e,0xed,0xe7,0x61,0x73,0x84,0xc4,0x8b,0xc4,0xd8,0x1d, +0xa8,0x94,0x5e,0x6b,0xb7,0x5c,0x9,0xa8,0x33,0x38,0xfd,0xaf,0xae,0xe0,0x25,0xab, +0x27,0x59,0xd1,0xcc,0x38,0xbf,0xb4,0x99,0xb2,0xb8,0xdd,0xbe,0x7e,0x36,0xdb,0xa6, +0xcb,0xb9,0x92,0x3,0x96,0x9b,0xac,0xc9,0xd3,0x2a,0xf8,0x2,0x8a,0x1f,0xae,0xb1, +0xf7,0x0,0xfe,0x30,0xbf,0x33,0xca,0xf1,0xec,0x28,0x30,0xea,0xde,0xd,0x91,0x2a, +0x46,0x24,0x2d,0xdc,0xbf,0x59,0x27,0x14,0x83,0x9f,0x16,0x8e,0x3e,0x44,0xbf,0x37, +0x44,0xbe,0x67,0x83,0xf2,0xb1,0x76,0x5f,0x5a,0xa6,0x4a,0x39,0x33,0xdb,0x63,0x7a, +0x1,0x90,0xd6,0x40,0x6a,0xfd,0x54,0xed,0x9e,0x6b,0x7c,0x5c,0xaf,0x3d,0x93,0x74, +0x7b,0x7b,0xf7,0x6e,0xac,0xed,0x4d,0x7,0x95,0x97,0xbf,0x48,0x74,0x23,0xc2,0xf4, +0x34,0x9a,0xb4,0x9e,0x18,0xa,0xc,0x36,0xf4,0x9,0x93,0xa4,0xc5,0xa6,0x98,0x41, +0xa1,0x91,0x30,0x4f,0x7f,0x7d,0xd5,0x94,0x95,0x96,0xdd,0x89,0xb9,0x20,0x7e,0x6d, +0x3a,0x33,0xc,0x53,0xbc,0x98,0x9,0xb1,0xa1,0x1c,0xd6,0x67,0xc3,0x6f,0x28,0x65, +0x1,0xd7,0x34,0x1,0x56,0xb,0x95,0x6b,0xa1,0xf2,0xf4,0xda,0x93,0xf2,0x49,0xcd, +0x26,0xd4,0xa0,0x63,0xec,0xaa,0x15,0x8e,0xc6,0xeb,0x75,0xa,0xdb,0x1e,0xef,0xdc, +0xf5,0x24,0x5d,0xcb,0xae,0x73,0x37,0xcf,0x66,0x2c,0xab,0xf9,0x1f,0x74,0x48,0xc5, +0xc8,0xe8,0xa8,0xb6,0x93,0xbd,0xc4,0xda,0x2a,0xba,0xe4,0x6,0xd8,0xd4,0x62,0x4e, +0xf9,0x40,0x1b,0x28,0xb3,0xd1,0xf8,0x99,0x7e,0x24,0x94,0x9d,0x18,0x5c,0xe2,0xe0, +0x45,0xb,0x17,0x59,0xc9,0x5c,0x34,0x73,0x17,0x19,0xf8,0x6f,0xee,0x5b,0xbd,0x68, +0x1b,0xd8,0x90,0xce,0xab,0x9,0x69,0xa9,0x2d,0x7d,0xc6,0x45,0xd9,0xaa,0xa6,0x1f, +0xb5,0x3d,0x78,0xfe,0x99,0xac,0xf1,0x30,0x46,0xea,0x9f,0xb4,0xc6,0x5e,0x1d,0xe1, +0xb6,0x2d,0xb1,0xe1,0xb6,0x9a,0x8b,0xe3,0x18,0x53,0xa9,0xf1,0x7d,0xcf,0x90,0xb2, +0xd,0xa,0xb2,0x27,0x36,0x24,0x57,0x7c,0x10,0xf7,0xb0,0xd6,0xd5,0xcd,0x38,0x8c, +0x7b,0x69,0x6f,0x32,0x4,0xfa,0x95,0x1c,0xcd,0xbe,0x8d,0x4b,0x8e,0x1f,0xfe,0x1c, +0xa8,0xb1,0x43,0x5e,0x55,0x1a,0x5b,0x65,0x91,0xc,0xbb,0x67,0x5a,0x74,0xf4,0xd5, +0xdd,0xe3,0x87,0xe2,0x5e,0x9c,0x7e,0x2d,0x5c,0x8c,0x78,0x6a,0xab,0x77,0x6,0xd3, +0xa8,0x49,0x32,0xfe,0xe3,0x8d,0xe3,0x75,0x9a,0xa0,0x5d,0xf4,0x15,0xd1,0x4a,0x72, +0xb5,0x51,0xd4,0x93,0xed,0x54,0xc0,0xc9,0xe0,0xb9,0xb4,0xc,0xb0,0xba,0x5f,0x5a, +0x84,0x91,0xd8,0x68,0x9f,0xbc,0x5d,0x3a,0xdc,0xba,0xae,0x71,0x8c,0xf8,0x64,0xc1, +0xc9,0x39,0x56,0x37,0x8d,0x96,0x81,0xed,0x50,0x36,0x79,0x2,0x70,0xd8,0xdb,0xf4, +0x6b,0x34,0xdc,0xb,0xf0,0xba,0xc4,0x4e,0x75,0x73,0x3f,0x82,0xeb,0xa3,0xc3,0xb5, +0xdd,0x99,0xec,0xea,0x31,0x6e,0xd9,0x1,0x24,0x53,0x82,0x95,0xac,0xdd,0xa,0x18, +0x12,0xe7,0xa2,0x83,0xa2,0x67,0x51,0x97,0x5a,0x90,0x99,0x46,0xb4,0xdd,0xfb,0x92, +0x77,0x68,0x7d,0x28,0xd7,0xd6,0xa9,0xfb,0xaa,0xab,0x11,0x57,0x8a,0x1c,0xee,0x1c, +0x83,0x11,0x9f,0x26,0x78,0xf0,0x3d,0x52,0x2,0x57,0x98,0xb6,0x35,0x14,0xc8,0xac, +0xfb,0xc5,0x55,0xd3,0x9d,0xfe,0x50,0xc7,0xaa,0x61,0x9e,0xb4,0xfc,0xd,0xd1,0x80, +0x1e,0xf0,0x26,0x16,0xe2,0xe3,0x68,0x64,0x3b,0x80,0x1b,0xef,0x14,0x63,0x9c,0x10, +0x29,0x71,0x64,0x46,0xef,0x34,0x8d,0x1b,0x15,0x2c,0xcf,0x13,0xb8,0x21,0x93,0xd6, +0x13,0x3a,0x6c,0x75,0x1e,0xd4,0xd9,0x59,0xd4,0x74,0x49,0x68,0xd7,0x65,0xf8,0x1, +0x57,0x5d,0xc7,0x47,0x11,0x55,0x62,0x26,0x82,0x33,0xb8,0x3b,0x54,0xcc,0x92,0xe6, +0x7,0xfe,0x5c,0x25,0x54,0x36,0xfd,0xa8,0x2a,0xc6,0x12,0x2,0xab,0xb,0x83,0x3, +0xe7,0x4b,0x4b,0xf8,0xa0,0xad,0x9e,0xa2,0x60,0x58,0x5e,0x35,0xa4,0xf0,0x1c,0xab, +0x6f,0x79,0x50,0xc3,0x2f,0xcd,0x6d,0x5a,0x94,0xfe,0xdb,0x40,0xa,0x5f,0x44,0x71, +0x2a,0xf,0x6a,0xcb,0x3c,0x88,0x6e,0x9d,0x60,0xcc,0x52,0x5,0x3d,0x6e,0x30,0xad, +0x67,0x80,0xf0,0x17,0xcd,0x5e,0xf0,0x62,0x5d,0xcc,0x23,0xe6,0xac,0xe6,0x58,0xd6, +0xf5,0x42,0xa2,0x32,0x4b,0x91,0x4f,0xab,0xdd,0xa1,0x31,0x9b,0x90,0x61,0x49,0x77, +0x62,0x3a,0x8e,0x30,0x19,0xfe,0x13,0xf5,0xcc,0x36,0x5d,0x79,0x1d,0xb5,0x50,0x13, +0x78,0x73,0xc4,0xc3,0x84,0x94,0xee,0x62,0x36,0x20,0xfd,0x46,0x2,0xc6,0xbe,0x64, +0x2,0xcc,0x14,0x9a,0x4c,0x27,0x90,0x19,0x5d,0xed,0x12,0xf9,0x24,0xe1,0x8c,0x1c, +0xd4,0x52,0x5f,0x59,0xe6,0x4e,0xbc,0x9c,0xee,0x3a,0xe3,0xf0,0x2,0x22,0xd4,0x83, +0x6e,0xe8,0x9d,0xba,0x90,0x2e,0x53,0x6d,0x9c,0xe4,0x68,0x40,0xc7,0xf4,0x5c,0x9c, +0xc6,0xbb,0xf6,0xad,0x89,0x33,0xca,0x78,0x6d,0x2e,0x69,0xee,0xcf,0x3e,0xf1,0x3e, +0xa7,0x8f,0x79,0x38,0x3e,0x4c,0xa5,0xda,0x32,0xe,0x1b,0xf9,0x83,0xf6,0x16,0x4a, +0xb2,0xd,0x78,0xbb,0xbf,0x43,0x35,0xad,0x71,0x9e,0x1c,0x41,0x5d,0xf,0xfe,0x84, +0x9e,0xf7,0x3c,0x5c,0x45,0xe1,0x37,0x77,0x70,0xd1,0xf0,0x73,0x48,0x7,0xbd,0x7a, +0x94,0x36,0x37,0xd3,0xf8,0x6c,0x81,0x6a,0x8a,0x9e,0xab,0x67,0xad,0x2b,0xeb,0xcb, +0x23,0x28,0x29,0x68,0x8a,0xdf,0x5f,0x7a,0x32,0x50,0xed,0x7a,0xd7,0x2b,0xf5,0xeb, +0xe1,0x2d,0xbf,0xda,0x19,0x42,0x46,0xa3,0x60,0x71,0xc,0x8d,0x9c,0x77,0x59,0x40, +0x20,0x2,0xa8,0x2a,0x62,0x88,0x24,0x94,0xd8,0x91,0x8e,0x30,0xbc,0x4,0x1c,0x1e, +0x31,0xdc,0xf9,0xc9,0x9e,0xbf,0x6e,0xfe,0xb0,0xf9,0x8c,0xcd,0xf0,0x65,0xe,0x90, +0xe7,0x36,0xba,0x4a,0xbe,0xde,0x5e,0x18,0xef,0xec,0x48,0x2d,0x71,0xe4,0x4b,0x22, +0xc1,0xc4,0xec,0xdf,0x84,0x5b,0xde,0xb5,0xd4,0x6b,0x83,0xc5,0x50,0x91,0x57,0x38, +0xc7,0x91,0x2,0x87,0xf0,0x60,0x9f,0xe0,0xcd,0x67,0xe,0x3f,0x4c,0xd9,0x61,0x8d, +0x9e,0x4e,0x6d,0xa3,0x29,0x4c,0x59,0x7d,0x37,0xdc,0xc3,0x88,0xed,0x1b,0xc0,0x35, +0x2c,0x43,0x3c,0x1d,0xa3,0xdb,0x7e,0xf0,0xc3,0xc,0xaf,0x10,0xe5,0x12,0x9e,0x5, +0xdf,0xc,0xa8,0x89,0x59,0x81,0x7,0x10,0xdd,0xca,0x98,0xcb,0x65,0xd9,0x80,0x12, +0x1d,0xbd,0xae,0x40,0x99,0x2d,0x32,0xdc,0xb9,0xe1,0xed,0x1f,0x73,0x8c,0x24,0xd3, +0x18,0x4c,0xdc,0xf0,0xcd,0xe3,0x2,0xab,0x2f,0x9a,0xf6,0x14,0xf3,0x78,0x26,0x90, +0x36,0x55,0xd1,0x4f,0x2,0x83,0x2d,0xbb,0xe4,0x1b,0xdb,0xd8,0x27,0x7f,0x2c,0x3f, +0xcc,0x9,0x31,0x9a,0x6c,0xb2,0xc6,0x9b,0xcc,0xbd,0x30,0xc1,0x36,0xd5,0x52,0x6c, +0x2b,0xa3,0xbc,0x2e,0xa6,0x69,0x69,0x8c,0x84,0xc4,0xe4,0xab,0x45,0x11,0x6a,0x91, +0x1a,0x1b,0x2c,0x86,0xcd,0xf2,0xa2,0x9b,0x31,0x52,0xdc,0x67,0x28,0xae,0x54,0xd3, +0xd2,0x90,0x81,0x79,0xf9,0xea,0x85,0x7e,0xb0,0x6a,0xa9,0x75,0xfa,0x93,0x7,0x15, +0xaf,0xb2,0x1c,0xfc,0x26,0x3e,0x18,0x57,0x90,0xf4,0x3e,0x38,0x24,0x92,0x8b,0xf6, +0xa2,0xd,0x70,0x9c,0x78,0xf6,0x9a,0xa8,0xe0,0xc3,0x1e,0xdc,0xd7,0xa4,0x71,0x7, +0x57,0x8d,0x4,0x7d,0x4b,0x1d,0x54,0x5b,0x91,0x93,0x94,0xb5,0xa5,0x20,0x2c,0xc8, +0xad,0x9d,0x65,0x26,0x14,0x80,0xce,0x74,0xc3,0xec,0x51,0x9b,0x11,0xc3,0xa2,0x68, +0xd0,0x27,0x66,0x9c,0xc3,0xba,0xf7,0x55,0xcd,0xc,0x8b,0xf3,0x2d,0xb7,0xbc,0x5a, +0xd4,0xa1,0x80,0x68,0x22,0x4f,0xdd,0x66,0xbb,0x2f,0x2,0xcc,0x72,0x25,0xb4,0xc3, +0x4c,0x1b,0x60,0x8f,0xd6,0x58,0x64,0x24,0x65,0xef,0x18,0x12,0x28,0xd4,0x6c,0xfc, +0x77,0x6c,0x66,0x19,0x3b,0xc3,0x7f,0xf6,0xf2,0x2,0x43,0xe5,0xa6,0xf7,0x29,0xf2, +0x14,0x89,0x2,0x6a,0x61,0x66,0xe,0x46,0xd6,0x27,0xd7,0xfe,0xfb,0xc3,0x7b,0xf2, +0x30,0x61,0x8c,0x6b,0x25,0x8b,0xe1,0x98,0x8d,0x25,0xfd,0x34,0x9d,0x27,0xa6,0xb1, +0x30,0xa8,0x9b,0x91,0x8f,0xa9,0x58,0x66,0x50,0x30,0x65,0xcc,0xf4,0x60,0xbf,0x25, +0xc2,0xcb,0x11,0xe7,0x58,0xf2,0x0,0xe5,0x98,0xfd,0x9a,0x36,0x25,0xc0,0x67,0x55, +0xe9,0x3,0x67,0x79,0x2c,0xbf,0xdf,0xfc,0xef,0xc4,0xc9,0xe4,0x25,0x9,0x8a,0xe7, +0xd5,0x1b,0x50,0x2e,0xe,0xcf,0x93,0xa6,0xce,0xad,0x5c,0x73,0x6f,0xc3,0xc9,0xd8, +0x46,0xb0,0x52,0x73,0x70,0xb1,0x70,0xdf,0xf5,0xb9,0xc5,0x1b,0xc2,0xcf,0x83,0x98, +0x6a,0x53,0x46,0x78,0x23,0xda,0x9f,0x71,0x8,0xfb,0xe5,0x77,0xc0,0x2f,0xcf,0x7, +0xdf,0xa1,0xf9,0xcf,0x53,0xe9,0xaf,0x49,0xa3,0xf4,0xe4,0x67,0xc4,0x68,0x7f,0xae, +0x3b,0xc6,0x28,0xdd,0x21,0x47,0x50,0x29,0xc2,0x36,0x21,0x3,0xe4,0xf0,0xb,0xc4, +0x93,0x84,0x14,0x66,0xee,0xc3,0x30,0x92,0xb9,0x15,0x79,0xfd,0xfc,0xf9,0xad,0xb7, +0x40,0x55,0x95,0x61,0x9c,0xe5,0xa,0xde,0x9b,0x2b,0xe2,0x80,0x9c,0x6d,0xc4,0xaf, +0xf1,0xd8,0x95,0xe0,0x9d,0xc5,0xf3,0xd6,0x5a,0x6d,0xd4,0x57,0xe6,0x2,0x8e,0x27, +0x57,0x25,0x8,0x73,0xb,0x13,0x53,0x27,0xbd,0x36,0xa7,0xd9,0x23,0xec,0x89,0x15, +0xc5,0x9f,0x76,0xe2,0x65,0xe9,0x39,0xc0,0xd6,0x8e,0x97,0xbe,0x90,0x27,0x65,0xe8, +0xcb,0x6e,0xdb,0x56,0x1,0xae,0x7d,0xbe,0x64,0xa5,0x19,0x87,0x92,0xa2,0x1d,0xd7, +0x42,0x13,0x3b,0x28,0xfc,0x74,0x68,0xd3,0x3,0x0,0x92,0x14,0xa6,0xf8,0x7c,0x72, +0xe6,0x58,0x49,0xe7,0x8,0xc6,0x26,0x6c,0xeb,0x3f,0xf4,0x7e,0x62,0x91,0xd6,0xa4, +0xa4,0x91,0x4c,0xa1,0x6,0xb4,0xf4,0x89,0x35,0x88,0x9d,0x5b,0x1,0x1a,0xce,0x67, +0xf1,0x18,0x4f,0x79,0x5e,0x75,0x66,0x4b,0xb5,0xda,0x49,0x18,0x6c,0x9f,0x3c,0x11, +0x31,0x89,0xb2,0xb7,0xbd,0x27,0xc0,0xf2,0xaf,0x5e,0xce,0x30,0xf7,0x9d,0x97,0x69, +0x35,0x66,0xe3,0x13,0xdc,0x4a,0xdd,0x12,0x25,0x28,0x2a,0x91,0xc7,0xe5,0x22,0xf9, +0xee,0x54,0x31,0xad,0x7b,0xf1,0x20,0xab,0xcf,0xee,0x5b,0xc7,0xc,0xf3,0xb0,0xc0, +0x5a,0x14,0x54,0xb6,0x5e,0x32,0xc8,0x3,0xd9,0x72,0x14,0xa2,0x59,0x36,0x1c,0x48, +0xa,0xcc,0x75,0x86,0xbe,0x16,0x32,0x8e,0x84,0x8d,0xd5,0x91,0x1,0x86,0xd1,0xdb, +0x9b,0x26,0x12,0x79,0xd8,0xdb,0xfc,0xb2,0xcd,0x11,0xd4,0xa6,0xc7,0xf0,0xef,0x51, +0xbd,0xe4,0xd7,0xfb,0xfa,0x89,0x8a,0x0,0x97,0x60,0x11,0x98,0x67,0xe2,0xf3,0x82, +0x89,0x7,0xfb,0x62,0x62,0x78,0x94,0xaf,0x8a,0x6a,0x57,0xd1,0xda,0xc6,0x23,0x19, +0xab,0x7b,0x15,0x27,0x5,0x20,0x27,0x1c,0x0,0x38,0xb5,0x67,0x9a,0x29,0xe9,0xa3, +0xaf,0x66,0x6,0x91,0xde,0x9b,0x42,0xe8,0x85,0x99,0x3a,0x60,0x60,0x5e,0x79,0x8b, +0x59,0xf,0x32,0xdd,0x2f,0xd8,0xfa,0x2f,0x90,0x30,0x97,0x2c,0x59,0x1,0xcf,0xa, +0xe6,0x56,0x1b,0x46,0x71,0x5d,0x2f,0xf6,0xf6,0x6a,0xd6,0xd6,0x48,0xd0,0xe2,0x21, +0xdf,0x15,0xfe,0xf,0xee,0xf9,0x3e,0xfe,0x2a,0x55,0x2b,0x84,0xd6,0x7b,0xe,0xbd, +0x51,0x29,0x4,0x42,0x7,0xb3,0xb8,0x7d,0x9d,0x8f,0x55,0x65,0x60,0xb7,0x86,0x40, +0xcc,0x85,0xce,0x3b,0x80,0x8d,0x3b,0xaa,0xe2,0xe5,0xae,0x39,0xe0,0x3c,0xf7,0x32, +0xe5,0x7b,0x74,0xec,0x2f,0x2d,0x6a,0x4c,0x3d,0x3f,0xb1,0x9d,0xf6,0x38,0x5e,0x44, +0xbe,0x2d,0x7f,0xbe,0xba,0x3a,0xe8,0x1e,0x21,0x98,0x57,0x2,0x54,0xce,0xb4,0x3a, +0xca,0xa8,0x27,0xf9,0xd6,0x12,0xc6,0x14,0x51,0x78,0x31,0x49,0xb1,0xf,0xd,0xef, +0xbc,0x8c,0x2e,0x77,0xc7,0x17,0x15,0x68,0x2f,0xec,0xe9,0x84,0xbb,0x9e,0x3e,0x86, +0x48,0xe5,0x1,0x9e,0x77,0x47,0x32,0xc8,0xbf,0xe2,0x91,0xf0,0xf2,0x9e,0x60,0xaf, +0xab,0x8e,0xa6,0xf2,0x26,0xbc,0x5b,0x55,0x29,0xc4,0x59,0x64,0xe3,0x18,0x6b,0x2c, +0xfd,0x6c,0x4a,0x75,0xb3,0xfb,0xbd,0xf2,0xde,0x50,0xe4,0xd1,0x6e,0xc4,0x1,0x1a, +0x54,0xa8,0x8c,0x7a,0xe4,0xe7,0x4f,0x8d,0x2d,0xa9,0xf1,0x11,0x41,0x5d,0xbc,0x3f, +0x49,0x7,0x34,0x7c,0x3,0x71,0x70,0x61,0x41,0xd4,0xb3,0xb0,0x99,0xb4,0x4a,0x6d, +0xdc,0xd7,0x67,0x41,0x3f,0xb7,0xce,0x6c,0xe0,0xc1,0x7d,0xa1,0x1f,0xb9,0xe0,0x69, +0xc0,0x94,0xe5,0x43,0x6,0x56,0x25,0x48,0xaa,0xd8,0x78,0xc4,0x8d,0xc2,0x32,0xea, +0x1a,0x1a,0x2c,0x5a,0xd1,0xfb,0xc6,0x32,0xbd,0xc4,0xd3,0xdc,0x7e,0x34,0xc5,0xbf, +0x48,0xac,0x82,0xcd,0x82,0xa7,0x95,0x2e,0x80,0xe,0xf2,0x8e,0x51,0xa4,0xf8,0x6b, +0xbe,0x25,0xc5,0x10,0x21,0xd,0xc1,0x5e,0xd1,0x15,0xbb,0xcf,0xc8,0x81,0x8f,0x11, +0xad,0x92,0xdf,0x31,0x3a,0xf4,0xde,0x3b,0x4,0x51,0x49,0x55,0x75,0x42,0xc0,0x35, +0x67,0x7,0xc4,0x9,0x14,0x87,0xe6,0x65,0x1c,0xa2,0x35,0xe5,0xa4,0x45,0x76,0x52, +0xd7,0xd5,0x3,0x12,0xcb,0x61,0xcc,0xcf,0xb2,0x16,0xa4,0x29,0x58,0xe4,0xdd,0x40, +0xeb,0x22,0xc8,0x0,0xa9,0xaf,0x65,0x46,0xd2,0x1b,0x2c,0xf6,0x60,0xa2,0x49,0x38, +0x79,0xcc,0x4a,0x45,0x2e,0x18,0x94,0x61,0xad,0x39,0xa,0x7,0x1e,0xe7,0xc6,0x8a, +0xa,0xf,0x8a,0x34,0x3e,0x70,0x7a,0x11,0x8b,0x26,0x87,0x6b,0x48,0xd1,0xa3,0xc1, +0x1e,0xed,0x86,0x4c,0x85,0x9a,0x2d,0x34,0xd3,0x37,0xba,0x72,0x1f,0x1,0xfc,0xa9, +0x10,0x7,0x5d,0x4e,0xf6,0x57,0xdf,0x2,0x7d,0x67,0x6d,0x45,0xb8,0x11,0x8,0xd6, +0x7f,0xe,0xa3,0x84,0xa9,0xd0,0x38,0xfc,0x9,0xf2,0xee,0xa7,0xf3,0x6b,0xd0,0x83, +0xf2,0x2e,0xd2,0xe9,0x85,0x32,0x6c,0x82,0x99,0xd9,0xc8,0xd2,0x6b,0x50,0xa9,0x6a, +0xdd,0xcc,0xee,0x7,0x9e,0x28,0x5,0x27,0x9a,0x73,0x4e,0xf,0xdf,0x20,0x92,0xd2, +0x4e,0xe4,0x3c,0x54,0x17,0xa8,0x56,0x31,0x3,0x9e,0x4,0xed,0x6e,0x2d,0x58,0x4d, +0x7a,0xc6,0x54,0x98,0x6e,0xd8,0xbf,0xa,0x4d,0xe,0x98,0x2d,0xad,0xaa,0x7f,0xfc, +0x90,0xbb,0xd0,0x27,0xe4,0x27,0x58,0x67,0x46,0xdb,0x55,0xb4,0x89,0x2d,0x81,0x4, +0xf3,0xd6,0x9c,0xe2,0x2f,0xdb,0xec,0x7c,0x69,0x5,0x29,0x18,0xaf,0xa8,0x94,0xbf, +0xe4,0x65,0xe7,0xc9,0xc,0xbf,0x31,0xd1,0x1c,0x6,0x87,0xa5,0x33,0x9,0x29,0xa6, +0x5f,0x45,0x89,0x8f,0x21,0xf5,0xc,0xa,0xfa,0xb5,0x22,0x2b,0x5e,0x36,0xea,0xc2, +0x9b,0x52,0x8c,0x28,0x13,0x3d,0xf9,0xae,0x43,0x1,0xd3,0xf5,0xb,0xfc,0x9d,0xe9, +0x42,0x27,0x79,0xe2,0x1e,0x6,0x6c,0x98,0xbb,0xf,0xc3,0x99,0x45,0xaf,0x5d,0x61, +0x81,0x69,0x9,0x94,0x27,0x3,0xc2,0x6a,0x5,0x96,0xe0,0x8f,0x93,0x7e,0xf8,0x55, +0xa5,0x73,0xb7,0x43,0xf8,0x25,0xdc,0x34,0xb3,0x20,0x4d,0xf8,0xcf,0x2a,0x5a,0x52, +0x94,0x63,0x66,0xbb,0xe6,0xa9,0xa5,0x6b,0x40,0x86,0x7a,0x54,0x84,0x73,0xa9,0xaa, +0x66,0xe1,0xed,0xde,0x86,0x4a,0x13,0x3a,0x6b,0x61,0x33,0xba,0xb,0xe,0x8c,0x9f, +0xf0,0x73,0xda,0x57,0x1d,0x1,0xc2,0x5d,0x7,0xbc,0xb1,0x8c,0x31,0xdb,0x37,0x17, +0x3d,0xa4,0xf6,0xc3,0x6f,0x89,0x7d,0x5a,0x6a,0x30,0x15,0x76,0x3e,0x22,0x16,0xaf, +0x95,0x71,0x86,0xb2,0x72,0xc9,0x8f,0x79,0x86,0xc1,0x85,0x37,0x1d,0x3c,0x4f,0x5a, +0xe1,0xc5,0x9d,0xd0,0x4f,0x1b,0x2b,0xba,0x4b,0xbf,0x31,0xa,0xe1,0xc6,0x39,0xf6, +0xb7,0xbf,0x29,0x2a,0x89,0xb9,0x24,0x90,0xfa,0xa9,0xc7,0x18,0xe6,0x96,0xf1,0x48, +0xdb,0xf,0x98,0x2c,0xa9,0xc3,0x66,0xf4,0x83,0x17,0x7e,0xe5,0x5d,0xb7,0xdc,0x16, +0xf7,0x7,0x40,0x1,0x40,0xe3,0x91,0x3b,0x8e,0xd9,0xd2,0xf4,0xef,0x44,0x3d,0xcc, +0x53,0xd5,0x78,0x7c,0x19,0x5e,0x71,0x1c,0x75,0x70,0x2,0xd2,0xa7,0x5f,0xe8,0x9f, +0x66,0xa9,0x21,0xa6,0x8d,0x32,0x61,0x9b,0xc,0x34,0x90,0x7c,0xf7,0x4d,0xc8,0xca, +0xa2,0x41,0x47,0xbb,0x9f,0x38,0x58,0x15,0xa8,0x5a,0x67,0x51,0x39,0xd0,0x70,0x9f, +0x7a,0x91,0xc5,0x87,0xc4,0x27,0x24,0x50,0xda,0xb4,0xcc,0xd2,0x82,0x95,0x9d,0x25, +0x56,0xe4,0x61,0xf5,0x1e,0xb9,0x8a,0x46,0x93,0x72,0x97,0xcd,0x43,0x88,0xec,0xbd, +0x1a,0xb3,0xc4,0x5e,0xda,0xe8,0x2f,0xb6,0x1e,0x7b,0x9,0x20,0x91,0xa7,0x45,0xe7, +0xc,0x26,0x5e,0xa9,0x5f,0x68,0xf0,0x73,0xda,0x8,0xc0,0x9d,0x90,0xad,0x5b,0x2b, +0xe0,0xa0,0x9,0x3c,0x89,0x38,0x72,0x27,0xb4,0x7b,0x47,0x46,0xa2,0xd,0xad,0xaf, +0x33,0xc,0xd8,0x13,0xf4,0xc9,0x86,0xcf,0xd2,0x47,0x6e,0xe2,0x74,0x49,0xe,0xd5, +0xe9,0x97,0x12,0xf3,0xcf,0x84,0x1b,0x4,0x0,0xe2,0xc9,0xa3,0xef,0x78,0xd2,0x23, +0x4,0xab,0x36,0xf8,0xf5,0x3c,0x49,0x48,0x3,0x37,0x2b,0x78,0x0,0xb9,0xcd,0x6a, +0x51,0xdf,0x5e,0xa0,0x64,0xf8,0xa5,0xe3,0xdb,0x6f,0x7,0xcb,0x67,0xd9,0x6f,0x6c, +0x6,0xa5,0xe4,0xfb,0x62,0x2e,0x44,0x65,0xe4,0xee,0x5d,0xe5,0xa8,0x2b,0x50,0xf9, +0xb,0x2e,0x1b,0xee,0x27,0xc0,0x53,0x4,0xaf,0x5a,0x4f,0x18,0xb4,0xbe,0x4,0xba, +0xe4,0xe8,0x36,0x47,0x97,0x7a,0xac,0xfb,0xe8,0x8a,0xe1,0x92,0xb5,0xb1,0xc,0x41, +0xdf,0x27,0x30,0x8,0xe7,0x83,0x8b,0x18,0x5e,0xda,0x30,0x13,0x9a,0xb3,0x4d,0x7f, +0x1c,0x83,0x46,0xb3,0x7d,0x72,0x30,0x66,0xfc,0x12,0x78,0xb3,0x44,0x85,0xf4,0x24, +0xac,0xa4,0x2c,0x15,0xa8,0xb7,0x2d,0x7,0x13,0xdc,0x1a,0xad,0x90,0xe6,0xac,0x2c, +0x6a,0xf2,0xe0,0x67,0x65,0x90,0xcd,0x63,0x22,0x47,0x96,0x66,0x4c,0xb,0x8b,0x78, +0x2f,0x37,0x8d,0xd7,0xef,0x3a,0x5e,0x82,0x96,0xf7,0x30,0xa6,0xde,0xdc,0xd3,0x49, +0x4f,0x34,0x30,0x34,0xc4,0xfe,0x97,0xe6,0xc5,0xad,0x4e,0x91,0xb8,0x59,0xa,0xe8, +0x90,0x18,0x40,0x0,0x52,0x9f,0x82,0x69,0x97,0xb2,0x10,0x77,0xf,0xe3,0x40,0xdd, +0x97,0x71,0x13,0x5c,0xef,0x2a,0xc3,0x35,0xd8,0x91,0xc6,0x11,0xea,0xd0,0xf9,0x7b, +0xe8,0x3b,0xfb,0xbb,0x5a,0x7e,0x25,0xf1,0xb1,0xb4,0x69,0xc0,0x99,0x2a,0x1f,0xb0, +0x9b,0x32,0xe,0x8b,0x5c,0x51,0x40,0xb4,0xe2,0x7,0xc6,0xcd,0xd7,0xc0,0xc8,0x41, +0x7b,0xc4,0xfc,0xd5,0xc3,0xa1,0x48,0x75,0x56,0x31,0xb5,0xef,0x5b,0xd4,0x21,0xf6, +0x86,0x2f,0x2,0xe3,0x0,0x42,0x98,0xe2,0xc8,0x5f,0x30,0xa1,0xa0,0x78,0x62,0x9b, +0xbd,0x5f,0xf1,0x81,0x1,0x3a,0xf6,0x57,0xea,0xac,0xc7,0x47,0x2,0xe8,0xbd,0x88, +0x97,0x40,0xeb,0x17,0x2,0x85,0xf9,0xcb,0x64,0xa9,0xec,0x84,0xa1,0x4f,0x21,0x5f, +0x2e,0x13,0xe0,0x2f,0xcc,0x57,0x6,0xb7,0x84,0x4d,0x7e,0x86,0x36,0x3d,0x8e,0x4d, +0xfc,0x7b,0x64,0xfe,0x1,0xdd,0xca,0xe4,0x7,0x37,0x6a,0xa9,0x86,0x8b,0x9,0xb4, +0x1e,0x6a,0x63,0x6a,0x41,0xe9,0xa1,0xc5,0x37,0x21,0xcb,0xed,0xdd,0x5b,0x3b,0xda, +0xd6,0x20,0x59,0xd7,0x7d,0xa4,0x3c,0x85,0xdb,0xa6,0x2f,0xe2,0xb1,0xb7,0x97,0x4f, +0x22,0x7b,0xb9,0x64,0x65,0x5c,0xa9,0x1c,0xfc,0x76,0xa,0x5a,0xd1,0x46,0x35,0xa8, +0xe5,0x8e,0x0,0x63,0x33,0x3c,0xe8,0x8f,0x63,0x97,0x72,0x15,0x50,0x89,0x65,0xf1, +0x5,0x9e,0xd5,0xe9,0xfa,0x80,0x7,0x77,0xf6,0x11,0xd1,0x48,0xd6,0x86,0x70,0x3c, +0x95,0x70,0xa0,0xc8,0x2c,0x9,0xd7,0x8f,0x21,0x4a,0x25,0x71,0xd4,0x8a,0xe2,0x59, +0x29,0xb9,0x44,0xa4,0x3a,0xca,0x9b,0xb0,0x5b,0x6e,0x78,0xb2,0x74,0xe8,0xee,0xa, +0x59,0xf,0x53,0x5,0x98,0x2b,0x95,0xb9,0x76,0xba,0x2b,0x4b,0xc4,0xe,0x24,0x6d, +0x47,0x68,0x91,0x81,0xb2,0x2e,0xb1,0xf,0x1c,0x2a,0xc1,0x90,0x13,0x30,0x9b,0xeb, +0x40,0x6e,0xf1,0xd8,0x99,0x7,0x12,0x10,0x41,0xbc,0xda,0x6,0x4a,0x0,0x73,0x92, +0xe7,0x6,0x93,0x1b,0xb3,0xc5,0x2a,0xcf,0xef,0x6b,0xdf,0x83,0x1b,0x7b,0xee,0x5b, +0xe9,0xe0,0xb3,0x4,0x67,0x45,0x93,0xa8,0x2,0xee,0x2e,0x4d,0x6e,0xa2,0x5f,0xd5, +0x28,0xf2,0xf0,0x5b,0xb8,0x9a,0x2b,0x29,0x85,0xb,0x2c,0xa1,0x7,0x1b,0xfc,0x70, +0xfc,0x31,0xf3,0x64,0x76,0x88,0x8d,0xf8,0x77,0xbb,0x46,0x65,0xdd,0xa5,0x3b,0x85, +0x18,0x2d,0xe0,0x51,0x47,0x8b,0x7a,0xcd,0x17,0xa6,0x6f,0x1e,0xc1,0x6c,0xe,0x3e, +0x1d,0x3,0x23,0x14,0xb,0xb0,0xd,0x2,0xeb,0x53,0x67,0xca,0x78,0xa2,0x50,0x10, +0x4f,0xb1,0x61,0x97,0x3d,0xdb,0x65,0x54,0x2,0xd4,0xf1,0x44,0xc0,0x80,0x82,0x5e, +0x83,0x25,0x72,0xe,0xd5,0x7f,0x10,0xc2,0x52,0xf6,0xd,0xca,0x99,0x5d,0xda,0x69, +0xf,0xbc,0x80,0xcc,0x98,0xe5,0x21,0x1b,0x3a,0x93,0x5f,0x7a,0x14,0xe1,0xd8,0x17, +0x8,0x4b,0x25,0x5d,0x4a,0xb4,0x9f,0x9c,0xab,0xac,0xe6,0xc4,0x8a,0x42,0x2e,0x19, +0xfe,0xae,0xe5,0x17,0x14,0x87,0x32,0xcd,0x1b,0x91,0x49,0x2f,0xf3,0x22,0x46,0x7b, +0xed,0xea,0x58,0xb7,0x9f,0xf8,0xd4,0xca,0x25,0xbb,0x8f,0xaf,0x7d,0x3e,0xc9,0xfb, +0xec,0x2f,0x14,0x81,0xb6,0xc5,0x4f,0xd1,0xd7,0x98,0x80,0x4b,0x3b,0x46,0x46,0xa8, +0xb0,0x9e,0x60,0x50,0x97,0xb4,0x9a,0xbd,0xf0,0x2b,0xec,0x6e,0x69,0x36,0xea,0xd5, +0x66,0x7e,0xd6,0x1d,0xc3,0x27,0x6f,0x9b,0x3f,0x6f,0x66,0x7a,0x36,0xac,0xa2,0xe6, +0x4c,0x83,0xb7,0xe3,0x38,0x52,0x21,0x29,0xfc,0xf,0x18,0xe5,0x45,0x3,0xbc,0x2b, +0x1,0x13,0xc8,0xc4,0x3a,0x38,0x61,0x7a,0x27,0x47,0x74,0x5d,0xf4,0x97,0x45,0x41, +0x1b,0xfc,0xa4,0xd2,0xce,0x46,0xfc,0xcc,0xd4,0x94,0xb2,0x1a,0x17,0xee,0x46,0x18, +0x3,0xf,0xdc,0x3d,0xc6,0xbd,0x37,0x6d,0x6,0x2c,0xcb,0x7a,0xc3,0x90,0x3b,0xde, +0xd,0x5f,0xb1,0xdb,0xa5,0x2e,0xa8,0x7a,0x42,0xdb,0x15,0x59,0xca,0x5b,0xf0,0xcd, +0xe9,0x4e,0x8b,0x30,0xc,0x42,0x9d,0x91,0x6e,0xe8,0x8b,0x32,0xf8,0xc6,0x90,0x6, +0x27,0xc2,0x62,0x4c,0xf0,0x8a,0xc7,0xb3,0x66,0xdc,0xd,0xb1,0xb7,0x7e,0x7f,0x21, +0xcc,0x8a,0xd0,0x58,0xcd,0xed,0x6a,0x3c,0xd7,0xf5,0xee,0x50,0x3d,0x7f,0x57,0xe3, +0x42,0x39,0x30,0xb3,0xc3,0xf7,0x67,0xaa,0x54,0xf3,0x5c,0x8b,0x72,0x5b,0xac,0xbe, +0xe6,0x7d,0x18,0x34,0x6c,0x82,0xef,0xc3,0xf7,0xde,0x14,0x35,0x5f,0xea,0x19,0xa1, +0x24,0xc9,0xd4,0x68,0xc1,0x3c,0x13,0x96,0x31,0x6f,0x22,0x23,0x4a,0x4f,0xe2,0xb0, +0xcc,0x7a,0xe4,0xb8,0x7c,0xd5,0xfb,0x74,0xb4,0x11,0x2a,0x14,0x7b,0xc2,0x36,0x20, +0x8c,0xb,0x88,0xce,0xc7,0x9b,0x65,0x78,0x8a,0x7,0x9b,0xd4,0x56,0xfd,0x86,0x24, +0x78,0xea,0x5c,0x74,0xc0,0x59,0x69,0xf5,0xe9,0x13,0x89,0xe4,0xd5,0xbf,0x5,0xe2, +0x4b,0x8d,0xb1,0x13,0x29,0x96,0x8b,0x33,0x9d,0xa6,0x9,0xf4,0xa5,0xf,0x98,0x9d, +0xf9,0xf4,0x92,0x3b,0xcd,0xfb,0x31,0x37,0xf,0xba,0x1d,0x64,0xfa,0x22,0x47,0xc5, +0xb0,0x78,0xd8,0x59,0x8e,0xe3,0xd,0xac,0xa,0x16,0xa1,0x2f,0xa4,0xb9,0x4d,0x1e, +0x2e,0xdf,0x59,0xfc,0xdb,0xa,0xb3,0x6a,0xc5,0xd0,0xce,0x40,0xf3,0x96,0x6,0x24, +0x8e,0x5e,0xfc,0x1e,0xc1,0xa,0xca,0xcb,0x9f,0xeb,0xfb,0xc3,0xa5,0x49,0xe2,0x53, +0x29,0xbb,0xcf,0x84,0xc6,0x84,0xee,0xc,0x55,0x3d,0x4c,0xc8,0x53,0x52,0x6c,0xe2, +0x30,0x6a,0x80,0xf1,0xf3,0xca,0xbd,0x94,0x36,0xb9,0x58,0x5b,0x82,0xba,0xae,0x2b, +0x77,0x7f,0xaf,0x3e,0x4,0x1e,0x4a,0xd8,0x5c,0x16,0xa2,0x2f,0x68,0x8e,0x91,0x98, +0xf8,0x12,0xa,0x6d,0x5c,0xc7,0x2,0x92,0x2,0xd9,0xed,0x84,0x95,0x1d,0xb0,0x8c, +0x9c,0xdf,0xca,0x20,0xfe,0x94,0xf8,0xda,0xaa,0x1b,0x89,0x92,0xaa,0x1c,0xaa,0x23, +0x2e,0xb4,0x90,0xb,0xfb,0x12,0x9d,0xfd,0xec,0xc,0x3,0x2,0xa8,0x33,0xe,0x45, +0x13,0xd8,0xe4,0x91,0xec,0xdd,0xeb,0x97,0x79,0x76,0xa9,0x24,0x92,0x54,0x47,0xc0, +0x88,0xd8,0x4b,0x84,0xea,0x69,0x83,0x57,0x75,0x86,0xd8,0x9d,0xb9,0xe6,0x62,0x4c, +0x3f,0x47,0xde,0xab,0xa4,0xca,0xc2,0x1e,0x41,0x6c,0x42,0x53,0xc0,0xa,0x94,0x49, +0x62,0xdf,0xce,0x4d,0x49,0xd1,0x25,0x3e,0xd7,0x7d,0xdb,0x11,0xe4,0x3e,0x5d,0xa3, +0x85,0xbb,0x50,0xaa,0x7,0x13,0xc8,0xc7,0x80,0x8b,0x1c,0xc0,0x95,0xb0,0x8a,0xf7, +0x90,0xd8,0xc4,0xda,0x2a,0x69,0x19,0x2,0x67,0x75,0x13,0x4c,0xb3,0xef,0x6f,0xb9, +0x2c,0xbf,0x64,0x33,0x53,0x2d,0xfa,0x53,0x38,0x17,0x93,0xcd,0x47,0x1e,0x45,0xd8, +0x76,0x8a,0x33,0xa0,0xf3,0xcb,0xa2,0x5b,0x41,0x35,0x27,0xf5,0xa5,0x97,0xaf,0xd1, +0xd6,0x93,0x5,0x2a,0xc0,0x7f,0xfc,0x79,0x17,0x91,0x47,0x5e,0xaf,0xd,0x37,0x27, +0x97,0xe9,0x47,0xb,0xb6,0xea,0x67,0xf7,0x9f,0xe,0x6d,0x45,0x25,0x9c,0x17,0xfc, +0x30,0x9b,0xa6,0x71,0x1c,0xa4,0xea,0x33,0xb5,0xb1,0x11,0x65,0xbe,0xc8,0xc,0x56, +0xb2,0xd3,0x62,0x69,0x3e,0x49,0xe1,0xdd,0xd6,0x4f,0xa3,0xfc,0x6c,0xba,0xf9,0x9c, +0xd6,0x20,0x8d,0xf2,0x44,0x78,0xa5,0xf9,0x2b,0xb6,0x60,0x69,0x7f,0xeb,0x40,0x33, +0x3f,0x22,0x1c,0x7d,0x6b,0x7d,0x5c,0xc1,0x4d,0x0,0xbe,0xb9,0x3a,0x38,0xd5,0x11, +0x59,0x64,0x83,0x9d,0xdc,0x29,0x98,0x87,0x60,0x78,0x71,0xdf,0xe3,0xb1,0x92,0x24, +0xd3,0x2f,0xa1,0xbe,0x2c,0xfd,0x80,0x79,0x7d,0x40,0xb2,0xb8,0x78,0x89,0x49,0x51, +0xed,0xcd,0xef,0x4a,0x76,0x88,0x52,0xd6,0x80,0xc3,0x37,0x64,0x75,0xc9,0x88,0xc8, +0x78,0x2b,0x87,0xa5,0xa8,0x87,0x9e,0xa6,0x47,0x52,0x5f,0x40,0x5b,0x28,0x91,0x49, +0xf5,0x1,0x13,0x6d,0x9,0xe4,0x44,0x89,0xa8,0xfa,0xee,0x9d,0xc5,0xf6,0x66,0xbd, +0xa1,0x6d,0x63,0xca,0x75,0x82,0x71,0xbc,0xd4,0x50,0xfc,0x30,0x78,0xf,0xf8,0xee, +0x10,0x8b,0x5c,0x1a,0x71,0x20,0x23,0x99,0x1c,0x12,0xb7,0x61,0x89,0x1e,0x9e,0xaa, +0xc,0x82,0x75,0x81,0x5,0x66,0xbd,0xd9,0xb6,0x3b,0xa,0xaf,0x4a,0x82,0x9e,0xd9, +0xe,0x7a,0x73,0xfe,0x1a,0x97,0x99,0xb5,0x29,0x51,0x17,0xb2,0xee,0x36,0xdd,0x7a, +0xb8,0x53,0x7b,0xbd,0xba,0x3a,0x97,0xf0,0x75,0x21,0xa0,0x3f,0xa3,0x3f,0x98,0x31, +0xb9,0xd,0x31,0x54,0xa4,0x4a,0xa,0xcd,0x9b,0xa1,0x1,0xa,0xd7,0xde,0x85,0x90, +0xb1,0x1,0x4e,0x6c,0xba,0x65,0x5e,0x30,0x86,0x7e,0xee,0xa9,0xbe,0x88,0x5a,0xf7, +0x95,0x8b,0x4c,0xb9,0x55,0xd6,0x7,0xf0,0x78,0x8,0xfb,0x50,0x66,0x1,0xe0,0x19, +0x2,0xae,0x5,0x3d,0x14,0xe2,0xec,0x1a,0x62,0xdc,0x43,0xa0,0xe4,0x1d,0x18,0xf9, +0x29,0xe4,0xb3,0x7e,0xbb,0xba,0x70,0x34,0x43,0xeb,0x84,0xa9,0x6c,0xe4,0x42,0xed, +0x13,0xc7,0x2b,0xa6,0xaa,0x19,0x40,0x8c,0xf5,0x3,0xac,0x5a,0x20,0xc5,0x54,0x49, +0xaa,0x8,0xc8,0xe5,0xc2,0xb8,0x1a,0x6,0x24,0x1e,0x30,0x90,0x82,0x72,0x7e,0x95, +0x3a,0xaa,0xbb,0x65,0xc3,0xfb,0x71,0x39,0xfe,0x1f,0x93,0x1f,0xe4,0xe7,0xe8,0xf, +0xef,0xb1,0xf4,0x32,0x6a,0x8e,0xb8,0xe,0xac,0x68,0x9e,0xae,0xda,0x1d,0x44,0x95, +0xc7,0x7f,0x7a,0xb,0x7b,0xeb,0x44,0x7a,0xb,0x57,0x19,0x6f,0x3f,0x2,0xfd,0xae, +0x33,0x72,0xe1,0x1d,0x1,0x1a,0x2b,0x2d,0x82,0xc9,0xdb,0xdc,0xe7,0x9f,0xf1,0x2f, +0x1f,0x6c,0x3b,0x9a,0xd8,0xfe,0x94,0x63,0x57,0x2e,0xd3,0x16,0x30,0x51,0xc5,0x64, +0xc4,0x27,0x81,0xc5,0x41,0x2d,0xf3,0x43,0xf6,0x4f,0x20,0x5e,0xef,0x92,0x8e,0xf, +0x7e,0x49,0x2a,0x57,0xc7,0xbe,0x3b,0x1f,0x6c,0x8e,0xb5,0x9d,0xdf,0x7b,0x81,0xa4, +0x22,0x82,0x6b,0xe2,0xaf,0xde,0x26,0xa7,0x2e,0xc5,0x85,0x9d,0x58,0x14,0xad,0xd7, +0xdc,0x57,0xae,0xa5,0x95,0xe9,0x44,0x3,0x78,0xf9,0xa0,0x59,0xf4,0xa1,0x7d,0x17, +0xa3,0x68,0xf9,0x54,0x47,0x9f,0x7b,0xf5,0x66,0x1,0x93,0x3e,0x95,0xc0,0x95,0xf1, +0x97,0x45,0x17,0x2e,0xae,0x5c,0x31,0x28,0xd5,0x51,0x1,0x4b,0x72,0x7e,0xe1,0x16, +0xe7,0xdc,0x6a,0xae,0xfb,0x65,0x24,0xe1,0xe6,0x38,0x21,0x7c,0xf8,0xb6,0x6e,0x11, +0xfb,0x86,0x3f,0xab,0x62,0xef,0x53,0xb7,0xc0,0x54,0x3,0x33,0x52,0xe5,0x49,0xb9, +0x42,0x34,0x69,0xbd,0x19,0x8d,0xa0,0x0,0xc5,0xc1,0x7c,0x3f,0x78,0x6b,0x50,0xf4, +0x71,0xf,0x20,0x53,0xfe,0x73,0xb,0xbf,0x47,0x8e,0xf2,0x99,0xf3,0xbb,0x54,0xb5, +0x6f,0x3d,0x73,0x89,0xca,0x14,0x89,0x11,0x55,0x86,0x50,0xce,0x71,0x20,0x43,0x62, +0x2f,0x63,0xb5,0x2e,0x56,0x40,0x6d,0x9d,0xce,0x60,0xb6,0x42,0x9b,0xb,0xf7,0xc, +0xc7,0xeb,0x15,0x93,0x0,0x9e,0x24,0xd5,0xa4,0xf3,0xa4,0x95,0x14,0x67,0xf7,0xc2, +0xca,0xad,0x70,0xa0,0x6e,0xdd,0x3e,0x3d,0xbd,0xf4,0x0,0x59,0x80,0xf7,0xe4,0x48, +0x63,0xf9,0x5b,0x64,0x19,0x7f,0xb9,0x3d,0xf2,0xdd,0xd3,0x7,0x45,0xcb,0x49,0x8f, +0xf9,0xb9,0x30,0x68,0x97,0xed,0x25,0x55,0xe2,0xa4,0x2f,0xe2,0x9d,0x14,0xab,0x1, +0x8e,0x7,0xe4,0x27,0x7,0x9e,0x64,0xf9,0x7c,0xb7,0x81,0x41,0x4,0xca,0xd0,0xfd, +0x85,0x80,0xe5,0x9c,0x6e,0x8a,0xf2,0xd1,0x30,0x22,0xb4,0x4d,0xb5,0x60,0xcd,0xc3, +0xe7,0x33,0xea,0x6e,0x51,0x50,0x68,0x4e,0x8,0x69,0x8f,0xc,0xb4,0xe0,0x89,0x3a, +0x61,0xee,0xd6,0xd0,0xf9,0x49,0xa2,0xa9,0xea,0xd6,0xf6,0x21,0x38,0x44,0xe4,0x9f, +0x77,0xd0,0xe,0x49,0x21,0xf5,0x97,0xa8,0x60,0xa6,0x35,0x94,0x7,0x3e,0xce,0x69, +0xad,0x25,0xb9,0xa7,0xee,0x5c,0x51,0xd9,0x33,0xc7,0xfa,0xea,0xc,0xe0,0xa,0x4, +0x31,0x18,0xcc,0xd1,0x8e,0xe3,0x7a,0x6e,0x8a,0x2f,0x3,0x12,0xed,0x51,0x7b,0x9b, +0xf5,0x35,0x43,0xe4,0x11,0x14,0x3f,0x44,0xdb,0xb9,0xaf,0x67,0x1a,0xb9,0xea,0x4b, +0x52,0xb7,0x1d,0xe0,0x9b,0x18,0xce,0xa6,0x47,0xd1,0xb8,0xb4,0xa2,0xb3,0x50,0x98, +0x68,0x13,0x7e,0x79,0x27,0xbd,0x3d,0x82,0xf6,0x6c,0xea,0x12,0x27,0x55,0x5d,0xf8, +0xe,0x7b,0x59,0x29,0x13,0x28,0x4f,0x5a,0x79,0x87,0x10,0x1c,0xba,0xdf,0xb4,0x23, +0xf3,0xb2,0x9c,0x1b,0xef,0x5a,0x1e,0xe7,0xc6,0x88,0xf9,0x6d,0xdd,0x57,0x66,0x6b, +0x52,0xbf,0x95,0x65,0x67,0x64,0x40,0xe0,0x6c,0xcf,0x7c,0x27,0xaf,0xb1,0x4b,0x23, +0x64,0x67,0xbe,0xd4,0xc1,0xdc,0xbc,0x89,0x65,0x36,0xf6,0x43,0xd,0xdd,0xaf,0x60, +0x1d,0xc4,0x45,0x85,0xa8,0x5,0xe5,0x15,0xd4,0x63,0x3d,0x5,0x94,0x88,0x28,0x78, +0xef,0xe6,0x4d,0x32,0x43,0x89,0x3b,0xa8,0xbf,0xb1,0x6c,0xcd,0x8f,0x1c,0xad,0xad, +0x60,0xf2,0xb2,0x9,0xf8,0x98,0x9e,0x4d,0x7b,0xdb,0x52,0x8f,0xe3,0xfa,0x9,0x53, +0x61,0x56,0x85,0xa5,0xe0,0x40,0x4e,0xa0,0xf2,0xba,0xed,0x2,0x56,0x9b,0x2f,0x36, +0xf,0xe1,0xbf,0x87,0xfa,0x5e,0x54,0xf5,0x3a,0x27,0x86,0x9d,0xa1,0x8f,0xf0,0x3, +0xe5,0xf6,0xa8,0x46,0xb6,0x77,0x67,0xa9,0x32,0x55,0x2c,0x9,0x71,0x5b,0x3f,0x0, +0xbd,0xfe,0x7,0xb8,0xdc,0xda,0xae,0x96,0x2,0xb4,0x34,0xa3,0x44,0xa5,0xa7,0xaa, +0x9c,0xcf,0x70,0x53,0x47,0xd7,0x7d,0xf9,0xad,0xa9,0x82,0x9e,0x84,0xc1,0x9e,0x42, +0x41,0x25,0xfa,0x1e,0x0,0x2a,0xb5,0x82,0xde,0x69,0x26,0x24,0xf,0x4d,0x4e,0x2b, +0x9d,0xbe,0xfe,0x64,0x97,0xfb,0xdd,0xc4,0xa5,0x60,0x63,0xa9,0xa2,0x81,0xec,0xe3, +0xa6,0xe7,0x81,0x26,0x91,0xb6,0xa8,0x71,0x21,0x4f,0x15,0x30,0x1c,0x63,0xdb,0xb9, +0xa1,0xda,0x9e,0xb8,0xd6,0x7c,0x7d,0xfb,0xdd,0x60,0xa5,0x80,0xe1,0x92,0xe3,0x8, +0xfa,0xe4,0xae,0x8c,0x9c,0x57,0x7d,0x3d,0x26,0x92,0xec,0xc2,0x75,0xc8,0xfb,0x18, +0x23,0x9a,0x50,0x79,0x18,0x4e,0xf4,0xf5,0xae,0x1b,0xf5,0x91,0x2d,0x59,0x19,0x28, +0x3e,0xc7,0x35,0x5a,0x9f,0xb2,0x97,0x45,0xc5,0x85,0x8,0x3b,0xcd,0x5,0xd2,0xf1, +0x9f,0x24,0xea,0xb7,0xf1,0xe0,0x2d,0xa0,0xfb,0xa2,0xb1,0x29,0xfb,0xcb,0xd1,0xba, +0x13,0x86,0x15,0xb2,0x39,0xad,0x78,0x7e,0xb2,0x80,0xba,0x80,0x5,0xd,0xf1,0xa5, +0xb0,0xdd,0xdc,0xa2,0x3e,0x8a,0x44,0xb9,0x2d,0x75,0xe2,0x2a,0x41,0x34,0xe4,0xd4, +0xba,0x79,0x7,0x74,0xa6,0x7f,0xf2,0x59,0x80,0x2d,0x5a,0x85,0xba,0xcb,0xaa,0xea, +0x29,0x8,0x8e,0x67,0x92,0x52,0xa0,0xbf,0xc7,0x4,0x69,0x89,0x38,0xcd,0x5e,0x73, +0x48,0xe4,0x67,0xee,0x65,0x5a,0xc8,0x65,0x8,0xa2,0xea,0x42,0x6e,0x16,0x2d,0x18, +0x1e,0x3b,0xfe,0xb0,0x8d,0xa0,0xef,0xd5,0xa4,0x5a,0xde,0x5c,0x28,0xbc,0xcf,0xef, +0xa1,0x37,0x5f,0x86,0x12,0x28,0xeb,0x99,0xca,0xd7,0xdb,0xb8,0xed,0x88,0xd0,0x8b, +0xc4,0x50,0x3c,0x52,0xf0,0x2c,0xa7,0x15,0x6,0x86,0x71,0x2f,0x43,0xc1,0x9e,0x65, +0xf8,0xfd,0xeb,0x8a,0x26,0xd8,0x24,0x70,0x30,0x7f,0xa9,0x9d,0x88,0xf9,0x29,0x4d, +0x4a,0xe4,0x1f,0xba,0x90,0xc7,0xcf,0x97,0xcd,0x42,0x46,0x91,0x4,0xe4,0xf6,0x7c, +0xe3,0x62,0x8,0x89,0xba,0xab,0x7a,0x6a,0xab,0x24,0x87,0x34,0x1e,0x30,0x1,0xe8, +0x15,0x20,0xa3,0xa6,0x67,0x74,0xbd,0x36,0x36,0x4,0x47,0xb9,0x68,0x3e,0x36,0x4c, +0x20,0xbd,0x56,0xdb,0xe9,0xd0,0xc5,0x15,0xf4,0x4e,0xc8,0x92,0x7e,0xc9,0x7b,0x94, +0xe9,0x9f,0xba,0x52,0x14,0x78,0x8,0xc9,0xfb,0x4f,0x83,0x64,0xd,0x39,0x31,0x2d, +0x77,0x7,0x88,0xe0,0xd7,0x4f,0xf5,0x4c,0x9d,0x3e,0x5e,0x9b,0x8,0xda,0x30,0xf1, +0xf9,0x6a,0xc3,0xe,0x62,0xcb,0x57,0xdd,0x9a,0x5a,0x43,0xa7,0x93,0xf3,0x55,0x8a, +0xfa,0x5d,0xea,0x52,0x2c,0xe0,0x9e,0xc9,0x1f,0xfc,0xe5,0xa6,0x57,0x16,0x19,0x51, +0x1,0xdc,0xde,0x63,0x29,0x36,0x42,0xc3,0x10,0x5,0xeb,0x24,0x78,0x41,0xae,0x73, +0x1e,0x9a,0xc5,0x4b,0xfa,0xe3,0x94,0x9a,0xe0,0x7a,0x41,0xb8,0x11,0x5a,0xa,0x12, +0xb7,0x69,0xf4,0xe0,0x1f,0xb6,0x24,0x30,0x3b,0x10,0x54,0xb3,0xd0,0x82,0x27,0x6f, +0x9c,0x6c,0xba,0x98,0x50,0x4f,0xb2,0xb1,0x4a,0x73,0x6a,0x5b,0x4e,0xf3,0xec,0x6, +0x5d,0xe1,0x66,0x7d,0x19,0xa,0x2d,0x54,0x9a,0x1,0x9,0x6b,0x83,0xaf,0xda,0x21, +0x9c,0x15,0x39,0xec,0xe4,0x6b,0x1e,0x2f,0x5e,0x88,0x8a,0xac,0x7d,0x77,0x32,0x5a, +0xd8,0x18,0x57,0xf1,0x23,0x84,0x47,0xbd,0x5,0xcf,0xa8,0x89,0x7f,0x4,0x2a,0x1c, +0x19,0xe2,0x89,0xfd,0x4e,0xa7,0x2d,0x2c,0xb0,0x37,0xd9,0xad,0xae,0x8b,0x8,0x88, +0xa4,0xdf,0x7a,0x47,0xe3,0x41,0x5,0xe9,0x11,0x2d,0xf2,0x11,0xb0,0x1d,0xac,0xca, +0x7f,0x36,0x48,0x4d,0x5e,0xf5,0x79,0xf,0xac,0x53,0xbc,0xdb,0x5f,0x44,0xe3,0x4, +0x24,0xdd,0xca,0x88,0x20,0x4f,0x72,0x31,0x7c,0x65,0xc1,0x2e,0x2,0x6f,0x78,0x81, +0xa5,0x40,0xce,0x83,0xb5,0xc7,0x92,0x63,0x9b,0xce,0x3f,0xfa,0x14,0x23,0x7e,0xb7, +0x1,0x49,0xbf,0xa0,0x98,0x32,0xd2,0x15,0x17,0x14,0xc2,0x98,0x83,0xba,0x99,0xa9, +0xfb,0xe7,0x2d,0xb1,0xb0,0xc0,0x94,0x4c,0x8f,0x53,0x47,0x23,0x76,0x45,0x5b,0xf7, +0x8e,0x1b,0x98,0x27,0xcd,0xea,0xbb,0x64,0x0,0x7f,0xfd,0x83,0x3a,0x17,0x2d,0xb5, +0x0,0x5b,0xe7,0xb0,0x9b,0x7c,0x7c,0xaa,0xd0,0x43,0x4e,0xc6,0x88,0xa9,0x3e,0x17, +0x44,0xd7,0xbd,0x91,0xc2,0x79,0xf6,0x42,0xf8,0x74,0x46,0xb3,0xb,0x73,0x69,0xb, +0x4e,0xd0,0x3b,0x69,0xcd,0x37,0x15,0x1e,0x7a,0x63,0xe4,0x82,0x8c,0x24,0x19,0x50, +0x7b,0xd6,0xe2,0xbd,0x51,0x59,0x1,0x4a,0x4d,0x47,0x7d,0x58,0x3a,0x67,0xe3,0x9, +0x38,0x1f,0x72,0x6,0x57,0x87,0x24,0x51,0x6a,0x89,0x54,0x76,0x2d,0x6d,0x47,0xa8, +0x45,0xa9,0x66,0x96,0x3,0x67,0x60,0xcf,0x2e,0xde,0xa7,0x69,0x46,0x8b,0xf1,0xfd, +0x2b,0x64,0x84,0x2,0x6c,0xa8,0x53,0x56,0xb1,0xa7,0xcd,0xde,0x16,0x15,0x87,0xda, +0xbe,0x6e,0x71,0x41,0xd5,0xd1,0x90,0x84,0x30,0x38,0xed,0x76,0xc4,0xdf,0xf4,0x6f, +0xc3,0x79,0x71,0x30,0xa1,0x44,0x87,0x54,0xec,0xd4,0x33,0x82,0x69,0x3b,0x5d,0xa7, +0xa9,0x4e,0x68,0xfe,0x20,0xf8,0x83,0x51,0xb0,0xf0,0x47,0xf4,0x50,0x3c,0x64,0x15, +0x35,0xd5,0xc4,0xd7,0x1b,0xcb,0x2c,0x87,0xa0,0xde,0x89,0x89,0x1a,0xe6,0x31,0x43, +0xb4,0x99,0x43,0xd4,0x12,0xc6,0xa5,0xc3,0x38,0x6d,0xb8,0x88,0x29,0x1e,0x9d,0x5f, +0x73,0xe2,0x37,0x8e,0xae,0xe2,0x95,0x50,0xc1,0x1f,0xd9,0x5c,0x85,0x8b,0x9f,0x3a, +0xa4,0xe2,0x10,0xb7,0x2a,0x35,0x7b,0x62,0xa2,0xb3,0x6a,0xcc,0xd1,0x88,0x2c,0xc5, +0x6b,0xe2,0x54,0x1a,0xc5,0xea,0xe9,0x87,0xa,0x44,0xe3,0x10,0xcf,0x84,0x4a,0x74, +0xe6,0xd9,0xab,0x11,0x10,0x27,0xf2,0x32,0x5b,0x5e,0xfe,0xac,0xe6,0xaa,0x72,0x52, +0xd,0xc7,0xeb,0xd2,0x32,0xd6,0xda,0xbb,0x1b,0xbe,0xcb,0x6a,0xc2,0x96,0x5e,0x2a, +0x70,0xb,0xba,0x0,0xb1,0xae,0x33,0xd,0x8c,0xb1,0xba,0xf2,0x5d,0xac,0xc4,0x6a, +0xf3,0xb0,0xbd,0x26,0x7,0x98,0x62,0x22,0xd6,0xad,0xc,0x1a,0x44,0x6b,0x44,0x35, +0xf5,0x7e,0x35,0xa7,0xac,0x68,0x35,0x39,0x1b,0x6f,0x2c,0xf7,0x1c,0x70,0xe1,0x11, +0x22,0x9f,0xb6,0x29,0xb7,0x98,0xcb,0x8f,0x47,0xd7,0x29,0xb,0xc2,0x6d,0x40,0xb8, +0x6b,0x76,0xe0,0x19,0x5e,0x16,0x52,0xf8,0x85,0xfe,0xf0,0x21,0x6f,0x53,0x32,0x11, +0x72,0x69,0x3b,0x2b,0x2,0x7,0x3a,0x49,0x5e,0x63,0x55,0xa1,0x50,0x15,0x5a,0xbb, +0x8b,0x3b,0xd4,0x6a,0xd0,0xa7,0x63,0xd5,0x26,0xd4,0xf7,0x15,0x28,0x2a,0x27,0x9a, +0x93,0xe1,0x45,0x16,0x68,0xfe,0x5f,0x46,0x62,0x34,0xe7,0x32,0x4a,0xc2,0xee,0x55, +0xfd,0x43,0xbf,0x4f,0x6a,0x24,0x25,0x10,0xf8,0x1d,0x26,0xa0,0xc7,0xcc,0xba,0xda, +0x2e,0x1,0xf0,0x96,0x0,0x51,0x5c,0xe2,0x5,0x45,0x15,0x4f,0x8,0x83,0xa5,0x85, +0x47,0xe4,0xd4,0xb1,0x9,0xfa,0xc2,0x81,0x97,0x68,0x22,0x5f,0xb4,0x5d,0x3b,0xe2, +0xdd,0x2c,0xf8,0x5d,0xfc,0x55,0x40,0x3,0x9a,0xd5,0xd1,0x22,0xd8,0xf6,0xa8,0x20, +0xdc,0xfc,0x52,0x65,0x77,0x15,0xe7,0x10,0xfc,0x89,0x6f,0xb1,0xe6,0xaa,0x94,0xc4, +0x57,0x8d,0x23,0xd3,0x62,0xe2,0x56,0xfd,0xb8,0x29,0x9f,0x12,0x9f,0xc7,0x32,0x7c, +0xc5,0x84,0xe2,0x3d,0x19,0x4a,0x4d,0x16,0xd3,0xbd,0x47,0xbb,0xe7,0xdb,0x0,0xbe, +0xe8,0xa2,0x93,0xcb,0x86,0x69,0x49,0xbe,0x92,0xe8,0xd0,0x33,0xb1,0x83,0x2f,0x77, +0x87,0x91,0x34,0xa1,0xdb,0x82,0x37,0xb0,0xbf,0xfe,0xeb,0x27,0x5a,0x6b,0xe6,0x44, +0xf,0xf9,0x10,0x15,0x63,0x59,0xd3,0x76,0xc1,0x25,0x29,0x73,0xa8,0xd7,0x6a,0x30, +0x6a,0x9f,0x51,0x46,0xa1,0x9,0x76,0x61,0x8,0xe1,0x88,0x62,0x4e,0xee,0x26,0xdc, +0x68,0xb5,0xf1,0xcc,0x8e,0x45,0xc2,0x51,0xe9,0xeb,0xc4,0x92,0xc3,0xaf,0x43,0xad, +0x4f,0x14,0xf4,0xf0,0x9c,0xea,0xd1,0xa4,0x4d,0xd9,0x87,0x1b,0xc9,0xad,0xf7,0x32, +0x64,0x69,0x7e,0xf2,0x2e,0x41,0xc3,0x19,0x2d,0x9,0x2b,0x71,0xb8,0xed,0x1f,0x87, +0x3,0x93,0xf7,0x9f,0xfe,0xc9,0xc4,0x4c,0xa3,0x4c,0x67,0x6d,0xf9,0xde,0x20,0xdd, +0x48,0x9e,0x51,0xf5,0xe0,0x15,0xf,0x8d,0x1e,0x3b,0x7e,0x56,0x29,0x1e,0xdd,0xab, +0xb1,0xd5,0x4c,0xb0,0x1f,0x90,0x7c,0xc3,0xdc,0xe3,0xb0,0x56,0x42,0x50,0xb4,0xa, +0xef,0x6,0x1,0x50,0x9a,0x10,0x5d,0xb9,0xca,0xdc,0x10,0xf4,0xfa,0x6e,0xa0,0x2c, +0xc3,0x6c,0x5d,0xe3,0x7c,0xd9,0xa7,0x59,0x3e,0xd7,0x30,0x80,0x29,0x64,0x8b,0x98, +0x6a,0xc,0x68,0x84,0x1c,0xc5,0xbd,0x67,0x22,0x4e,0x5c,0x9c,0xbc,0x7c,0xc9,0x80, +0x69,0xa6,0x64,0xe5,0x80,0x8b,0xbf,0x3e,0xe3,0x6f,0xbf,0x8c,0xd3,0xca,0x25,0xbd, +0xd6,0xd,0x42,0x72,0xd2,0x80,0xd9,0x75,0xce,0xb5,0x12,0xb,0xb2,0x5b,0x8b,0x9b, +0x2,0x70,0x81,0x3,0x7b,0xc0,0x41,0x5f,0xaf,0x80,0x6b,0x83,0xca,0x90,0xc0,0x21, +0x1d,0x83,0x14,0xf0,0x4,0x6d,0xe5,0x52,0x24,0xf7,0x5d,0x56,0x54,0x68,0xf1,0xd5, +0xd8,0xf2,0xd8,0xd4,0x34,0x9a,0x34,0xe3,0x9a,0xa0,0xe7,0x66,0xb0,0xa8,0x7,0x4e, +0xab,0x1b,0x3f,0xaf,0x89,0x25,0x2,0x2d,0x9c,0xde,0x83,0x70,0x48,0xf4,0x47,0x21, +0xe7,0x9f,0xf5,0x1c,0xb9,0xaa,0x1,0x55,0xca,0x68,0x3b,0xfa,0x11,0x42,0x49,0xbd, +0x5e,0x8,0xec,0xe7,0xac,0x6f,0x15,0x4a,0x4e,0x18,0xba,0x96,0xd,0x81,0x38,0xf4, +0xa1,0xad,0x91,0x5b,0x58,0x12,0xb0,0xa2,0x7a,0xeb,0x9e,0x8b,0xae,0x67,0xc8,0xd, +0x70,0x36,0x74,0x1d,0xa5,0x89,0xe6,0x73,0xa1,0xa2,0xb,0x2e,0xa3,0xc2,0x23,0x45, +0x70,0x34,0xa1,0xc9,0x46,0xd1,0xeb,0xc0,0x3e,0x8a,0xcc,0xec,0x72,0x15,0x79,0xe2, +0x4b,0xed,0x7f,0x70,0x77,0x67,0xe4,0x98,0x89,0x6f,0x46,0x2d,0x32,0x69,0xf2,0xa2, +0x9e,0x14,0xeb,0xe4,0xe5,0xd8,0x26,0x24,0xe2,0xf2,0x90,0x55,0x8,0xa,0x38,0xd3, +0xf7,0x38,0x44,0xee,0x9f,0x29,0x7,0xa8,0x18,0x4d,0x55,0x4a,0x37,0x48,0xed,0x55, +0x5c,0xd9,0xb9,0xc2,0x32,0xdf,0xe6,0x16,0x52,0xf7,0x6b,0xda,0x2,0x24,0xae,0x7a, +0xdb,0xf2,0xe8,0x7b,0x9c,0xf0,0xa3,0xb4,0xbd,0xf8,0x7f,0xf4,0x42,0x6d,0xc9,0x1e, +0xc6,0x84,0xe0,0xf9,0xe3,0x48,0x8f,0x37,0x40,0x7a,0x12,0xc1,0x1e,0x40,0xbb,0xf9, +0xb2,0xa5,0xf4,0x4f,0x16,0x98,0x84,0xd3,0x12,0x4,0x49,0xd3,0xf0,0x13,0xf1,0x37, +0x97,0x53,0xb0,0x7c,0x1b,0x40,0x33,0xda,0x3b,0x45,0x9c,0x59,0x5,0xd8,0xd3,0xb7, +0x7e,0x48,0x87,0x94,0xe1,0xc,0xe7,0x73,0x8f,0x31,0x47,0x0,0xc4,0xb8,0xb6,0x5c, +0x8b,0x68,0x58,0xa6,0x28,0xb,0x81,0x63,0x50,0x9e,0x3d,0x55,0x77,0x11,0x8d,0x75, +0x59,0x15,0x89,0xba,0xa0,0x71,0xad,0xaf,0x23,0xf4,0xaf,0xe7,0x2e,0x66,0xc3,0xb9, +0x4e,0x9c,0x61,0x77,0xa7,0x62,0xda,0x78,0x1,0x97,0x4d,0xf7,0xa8,0xda,0x6d,0x82, +0xef,0xf6,0xbc,0x90,0xe8,0x6b,0x40,0x8b,0x60,0x6f,0x73,0xe,0x56,0xb6,0xc8,0xa4, +0x53,0xa9,0x9b,0xfb,0xc,0xf6,0x74,0x8d,0x8e,0xc1,0x85,0x38,0x1d,0x73,0x3a,0xd, +0xe9,0xf6,0x1e,0xd2,0x62,0x5e,0x5e,0x43,0x4e,0x51,0x51,0xa4,0x9,0x99,0xc8,0x5c, +0x43,0x65,0xd7,0xcf,0x5c,0xcb,0xdc,0xea,0xe,0x62,0xa2,0x2b,0xd5,0xdc,0x38,0xc0, +0x54,0xd5,0x13,0xb6,0x35,0xf1,0xf9,0x3,0x43,0xcb,0xa7,0xcb,0x65,0xef,0xa8,0x29, +0xd4,0x80,0x78,0x31,0xcc,0x55,0x9c,0xda,0xb7,0xbe,0x6,0xe,0x1c,0xbd,0x4e,0x70, +0x94,0xe0,0xa6,0x49,0xd2,0x21,0x4c,0x96,0xec,0x73,0x62,0x52,0x63,0x8a,0xfa,0xb8, +0xc,0x73,0xe9,0xd8,0xc8,0x6,0x33,0x1,0xc5,0x39,0x8e,0x61,0x76,0x5c,0xd1,0x8a, +0x3d,0x78,0xd3,0x90,0x99,0x9f,0xa6,0x6,0x13,0x9,0xd8,0xf6,0x14,0xd3,0xaf,0x9f, +0x48,0x19,0xf7,0x90,0x9f,0x2b,0x11,0xe4,0xe3,0x9f,0x46,0x5a,0xfb,0x97,0x65,0xb9, +0x10,0x39,0xc9,0x2a,0xd9,0x70,0x30,0x6c,0xf8,0x88,0xe2,0xd,0x5d,0x92,0xac,0x25, +0x2c,0xa4,0x35,0xcb,0xcf,0x47,0xb0,0xb3,0x66,0xf6,0x8e,0x63,0x8e,0xf3,0x9c,0x1e, +0xac,0x66,0xc7,0x6,0xd6,0x78,0x73,0xcf,0x1,0x56,0x5d,0xdd,0x69,0xa,0x3,0x95, +0xaf,0xb8,0xe0,0xfe,0x0,0x91,0x33,0x66,0x8,0xc1,0x49,0x16,0x35,0x65,0x34,0x61, +0x4b,0x7c,0x68,0x22,0xf4,0x5b,0x72,0x75,0x31,0x4f,0x54,0x1a,0x59,0xd6,0xaf,0x88, +0x8f,0x10,0x88,0xf,0xa1,0xbb,0xf5,0x29,0xfc,0xbe,0x3f,0xb1,0xa4,0xf3,0x13,0xef, +0x70,0x7b,0x92,0xe4,0x56,0x5,0xd9,0x88,0x54,0xad,0xa2,0x2d,0x85,0xd2,0xb6,0x94, +0xe2,0x3f,0x24,0x5,0x7a,0x99,0xad,0x77,0x58,0xed,0x29,0xfc,0x61,0x3c,0xed,0x51, +0x38,0x80,0xb5,0x8e,0x5,0x8f,0x96,0xd8,0x3e,0xb9,0x6,0x43,0x8c,0x3c,0xd7,0xee, +0x7b,0x7b,0x73,0x75,0x15,0x22,0xec,0x6e,0x8f,0x95,0xea,0xf0,0x52,0x58,0x42,0x8a, +0x58,0xf7,0x98,0x5d,0x87,0x30,0xb5,0x45,0x69,0x3c,0x88,0xf5,0x78,0xe0,0x64,0x74, +0x5c,0xd8,0xe9,0x72,0x7a,0x57,0x60,0xa,0xec,0xca,0xfa,0x3f,0x24,0xbc,0xc9,0xfb, +0xb4,0xe2,0x5a,0xbb,0x92,0x8f,0x81,0xfb,0xcb,0xa,0x71,0x45,0xea,0xd5,0x39,0x48, +0x2e,0x23,0x3a,0x28,0x7a,0x1a,0x32,0x68,0xe4,0xac,0x27,0x88,0x69,0xf1,0x85,0x9d, +0x54,0x5f,0xd9,0xe6,0xee,0x5b,0xe2,0x3b,0x65,0xd3,0x80,0xd0,0xa9,0x39,0x98,0x58, +0x5c,0xd2,0x80,0x57,0x6c,0x33,0xbf,0x51,0x5f,0xe6,0x5a,0x49,0x58,0xdf,0xe6,0xac, +0x3f,0x40,0x13,0xad,0x1b,0x75,0xe8,0x1,0x49,0xe8,0xd1,0xf3,0x22,0x6a,0xcb,0xfe, +0xbc,0xcb,0x56,0xa8,0x7e,0x16,0xf9,0xde,0x7c,0xd3,0x28,0x55,0xb3,0x8e,0x81,0x72, +0xcf,0x95,0x21,0x6a,0xb,0x89,0x6b,0x55,0xf2,0x3d,0xc8,0x15,0x27,0x94,0x14,0x63, +0xdf,0xe9,0xc,0x5f,0x7f,0x86,0x3e,0xfc,0x5a,0xe5,0xd1,0xf,0x74,0x53,0x1,0xc3, +0x68,0xa1,0x2f,0x74,0x2c,0x9a,0x49,0x1f,0x58,0x12,0xb3,0x7f,0x26,0x48,0x63,0x85, +0x32,0x6f,0xe4,0xb2,0xf5,0xa2,0x2f,0xd0,0x88,0x1,0xdf,0x7d,0xd3,0x60,0x41,0x3d, +0x3,0xef,0xb1,0x2f,0x8b,0x7a,0xcd,0x63,0x8c,0x1,0xe2,0x32,0x49,0x46,0xb7,0x7c, +0x36,0x9d,0xae,0x2c,0xbf,0x5d,0x7c,0x49,0x5e,0xdb,0xc6,0xb1,0x3d,0x87,0xee,0x40, +0x78,0x20,0xee,0x83,0x9a,0x3c,0xe6,0xa6,0x3d,0xc9,0xd8,0x87,0x90,0x11,0x83,0xc6, +0x2e,0xb1,0x72,0xed,0xf,0xef,0x37,0xec,0xcb,0x7d,0x9e,0x88,0x6,0x8e,0xc8,0x7e, +0xae,0x37,0x2,0xc9,0x73,0xe8,0x70,0x31,0x32,0xc9,0xb8,0x42,0xda,0xbb,0x88,0x9, +0x6d,0x7b,0xf6,0x7c,0xea,0xae,0x69,0x36,0x2c,0x8,0xbf,0x32,0x16,0x8,0xb0,0x45, +0x40,0x32,0xf,0x33,0x9a,0xfe,0x64,0xcd,0x48,0x9c,0x8f,0x23,0x58,0x19,0xab,0x45, +0x14,0x23,0xc1,0xfe,0xd1,0xaa,0x35,0x7d,0x33,0x74,0xb0,0xc8,0x7d,0xe0,0xe,0x3d, +0x93,0x9c,0x70,0x2e,0x1c,0x55,0x7b,0x64,0xf1,0xc,0x8,0xca,0xa4,0xb3,0x10,0xb8, +0x56,0x52,0x37,0xa7,0xfc,0xeb,0x26,0xaf,0x61,0x56,0x79,0x5e,0xb6,0x7,0x9b,0x4a, +0xa4,0x8b,0x79,0xc0,0xe0,0xf4,0xa4,0x53,0x80,0xac,0x1e,0x25,0xe0,0x2e,0x5d,0x37, +0x0,0x14,0xdf,0x7d,0x1,0x85,0x2d,0xe1,0xdb,0x26,0x40,0x92,0x2e,0x5b,0x5d,0xd2, +0xe6,0xd6,0x13,0x48,0x4b,0xb7,0x1b,0xcc,0x65,0x39,0x71,0x46,0xe6,0x4f,0xfc,0xe7, +0x63,0xdc,0x65,0xe3,0x62,0x92,0xc5,0xbd,0x39,0x85,0x51,0x67,0xe0,0xae,0xb9,0x48, +0x5,0xcc,0x10,0xcf,0x4,0x2b,0x9c,0x69,0x64,0x8e,0x2f,0xca,0x5d,0x2d,0xb2,0x40, +0x89,0x18,0x25,0x6c,0x2b,0x6a,0x2a,0x64,0xf0,0xfa,0x4b,0x51,0x29,0x5,0x19,0xad, +0xd1,0x29,0x7e,0xd5,0xd3,0x9a,0xbf,0xb7,0x29,0x6e,0x83,0x6,0x1b,0x36,0x47,0x25, +0xce,0xeb,0x91,0x79,0x56,0xbb,0x5d,0xc6,0x37,0xa8,0x98,0x60,0xad,0xb1,0xf,0xfe, +0x5b,0x8d,0x54,0x2f,0xa7,0x93,0xe7,0xd1,0x3,0x6b,0xd7,0x9d,0x21,0x9e,0xc2,0x6f, +0x8a,0x54,0x68,0xe1,0x90,0xc5,0x28,0x47,0xed,0xc0,0x27,0x1b,0x73,0xb5,0x1a,0x4e, +0xc2,0xee,0x7d,0x6b,0x82,0xe4,0x3d,0x5,0xcf,0x94,0xa3,0x71,0x34,0xe5,0xe0,0x3e, +0x3b,0xc9,0x20,0x4b,0xf,0xc8,0x12,0xfd,0x89,0x39,0x19,0x7c,0xef,0xb3,0x4a,0xb2, +0xa2,0xc8,0x1e,0x25,0x2d,0xda,0x2b,0xfd,0x70,0x4e,0x6f,0x24,0x34,0xcf,0x62,0xee, +0x99,0x3,0xb9,0x29,0xcb,0xcb,0x27,0xd4,0x6,0xbf,0xd1,0xf5,0x73,0x1c,0x28,0x95, +0x64,0x47,0x3b,0x92,0x22,0x66,0x90,0x92,0x34,0x7f,0x36,0x68,0x4f,0x99,0xd7,0x69, +0x1c,0x91,0x92,0x67,0x5e,0x39,0xbb,0xe3,0xf8,0x8d,0x59,0xec,0x2a,0x81,0x82,0x8e, +0xc8,0xbd,0x21,0xeb,0xa3,0x31,0xfd,0xd7,0xb0,0xb4,0xc0,0x1,0xcd,0x98,0xe9,0xe9, +0xa9,0xfb,0x51,0x8,0x35,0x8c,0xeb,0x2e,0x1b,0xc4,0x9a,0x45,0x47,0x9d,0xd3,0x10, +0x5b,0x75,0x7b,0x7f,0xa6,0x7a,0xd6,0x58,0xae,0x17,0xd8,0x7c,0xaf,0x42,0x66,0x5a, +0x3e,0x37,0xe1,0x73,0xc3,0x4e,0x21,0x5e,0x13,0xbc,0xa3,0x5a,0x5a,0xf7,0xea,0x35, +0x6d,0x66,0x34,0x93,0x60,0xc,0xeb,0xf,0x23,0x44,0x8b,0x53,0x86,0x71,0x2d,0xc4, +0xa8,0xf,0xb7,0xec,0xdc,0xd9,0x4b,0xf0,0x16,0xef,0xca,0xef,0x67,0xb5,0xa4,0xd4, +0x9c,0xd9,0x68,0xfc,0x65,0xd4,0xd,0x8,0x19,0x18,0x5b,0x20,0x8a,0x88,0xe4,0xb2, +0x18,0x9d,0x9f,0x74,0xf6,0xeb,0xe4,0xd,0x5b,0xb0,0x7c,0xc2,0xe5,0x21,0x17,0x82, +0xfa,0xfe,0x0,0x60,0xd3,0x8c,0x69,0x6d,0xa4,0x44,0x8d,0x2f,0x4d,0xf1,0xe2,0xe4, +0xf,0x2,0x59,0x6,0xed,0x3f,0x92,0x49,0x6f,0xf,0x8b,0x55,0x31,0xa2,0x58,0xab, +0x22,0x58,0xd,0xf5,0xe4,0xf5,0xe2,0x89,0x3a,0xef,0x39,0x7,0xe2,0x9b,0xeb,0x71, +0x9d,0x46,0x78,0xc,0x5,0x8a,0xd4,0x74,0x9a,0x61,0xc9,0xcb,0x83,0x22,0x77,0xa5, +0x7a,0x4,0x1c,0x5f,0x79,0xfe,0x69,0x34,0x6f,0x22,0x3b,0x52,0xbd,0x28,0x43,0xda, +0xed,0xbb,0xe6,0xf2,0x47,0xbc,0x67,0x61,0x9d,0xb0,0x2d,0x21,0xd3,0x24,0xc7,0xcd, +0xa8,0x63,0xad,0x22,0x62,0x17,0x56,0x51,0xb8,0x12,0x23,0x76,0xb9,0x67,0x51,0xa7, +0x23,0xb8,0x1a,0xe9,0xf4,0x1,0x4b,0x92,0xb1,0xf7,0x33,0x5,0x9c,0x7a,0x53,0x45, +0xdd,0x1,0xe6,0xc0,0x97,0x3e,0x12,0x50,0xcf,0x36,0x46,0x89,0x9d,0x17,0xb0,0x40, +0xcf,0xca,0xaa,0x44,0x4b,0xf5,0xd6,0xfc,0x6e,0x8a,0x82,0xb,0x5,0xd5,0x50,0x63, +0xd6,0x37,0x24,0xed,0xf4,0xb5,0x3e,0x44,0x6b,0x84,0xcd,0x9,0x9b,0xfd,0xc9,0xeb, +0x48,0x74,0x30,0x93,0xe9,0x87,0x91,0x58,0x12,0x93,0xe2,0x96,0x69,0xb2,0xf9,0xbf, +0x6a,0x9d,0xad,0xde,0x54,0xeb,0x24,0x3f,0xef,0xf1,0x49,0xb,0xf0,0x92,0xf6,0x39, +0x7,0x28,0x4d,0x70,0x2f,0x5e,0x49,0xc0,0xf1,0x2c,0x57,0x5b,0xdf,0xd1,0x1b,0x4a, +0xee,0xc8,0x29,0xc2,0x34,0xcc,0x3,0xa3,0xbf,0x4c,0xae,0x30,0x5e,0xa6,0xe8,0xe4, +0x4e,0x36,0x55,0xfc,0x94,0x9e,0xbd,0x86,0xcb,0x15,0x61,0x2b,0x66,0x7c,0xf4,0x56, +0xc4,0x9d,0x19,0x78,0x6b,0x1c,0x1c,0xaa,0xe7,0xcb,0xda,0x46,0xf1,0x43,0x2b,0x40, +0xf9,0x1,0x3d,0x8e,0x1f,0x7a,0x95,0x6a,0x8f,0xf6,0x95,0x76,0xf3,0xa,0xcc,0x38, +0xa8,0x65,0xb1,0x14,0x82,0xcd,0x3e,0xe9,0x19,0x19,0xb0,0xb,0xdb,0x5b,0xca,0xd5, +0x5c,0x87,0xe4,0x7c,0x2,0x7a,0x66,0x12,0xf0,0xfc,0x88,0xe4,0x7,0xd4,0x1e,0x2f, +0x3a,0x4f,0xc2,0x3c,0x9c,0x1,0xa6,0xb6,0x99,0x57,0xc1,0x76,0x32,0xd,0xcb,0xf, +0x94,0xb0,0xb,0x17,0x2b,0x71,0xa8,0x1d,0x6e,0x31,0x81,0xf5,0x85,0x1f,0xa4,0x3f, +0x6e,0x68,0xfb,0xc,0x69,0xa2,0xc2,0x83,0x79,0x4,0xf9,0xab,0x90,0x45,0xba,0xa5, +0xf6,0x45,0xbc,0x22,0xb7,0x65,0xbe,0x26,0x16,0xc0,0x9b,0x1b,0xdf,0x41,0x5a,0x4f, +0x29,0x56,0xda,0x92,0x78,0x9d,0x95,0x71,0x21,0x8f,0x9d,0xb2,0x55,0xd7,0xd7,0x4c, +0x1e,0x14,0xed,0xd5,0x79,0x2d,0x7b,0xf,0xed,0x18,0x2a,0xcd,0xd8,0x4,0x1d,0x2, +0xda,0xf7,0x14,0x53,0x15,0xaa,0x45,0xb6,0xb9,0xe2,0xe8,0xf,0x3a,0xc0,0x5b,0x58, +0xd4,0xc9,0x2e,0xcd,0xf6,0xaa,0x5c,0xe4,0x42,0x6,0xb2,0x9a,0xa,0x50,0x9c,0xe4, +0xc7,0xb0,0xb8,0x5d,0x5b,0x7d,0x14,0x95,0x60,0xfc,0xa4,0x9a,0x3d,0x80,0x73,0x91, +0x4a,0xa1,0xde,0x41,0xcb,0x3b,0x26,0x8d,0xc0,0xd8,0x28,0xca,0xa8,0x44,0x30,0x71, +0xf5,0x68,0xce,0xd0,0xe5,0x62,0x66,0xc5,0xde,0x8b,0xdf,0x1c,0xc,0x53,0x2d,0x56, +0x75,0xc,0x97,0xc0,0xc6,0x3d,0x4f,0x87,0x16,0xf6,0xd1,0x3f,0x3c,0x2,0xb0,0x32, +0x6a,0xfe,0x82,0xcf,0x61,0x69,0x95,0x40,0xf4,0x76,0xdb,0x1,0x49,0x9,0x57,0xbe, +0x94,0x6e,0x80,0x5b,0xab,0xcf,0x62,0x41,0x46,0x34,0x80,0x82,0xb6,0xb0,0xb4,0xa0, +0xaf,0xb7,0x71,0x90,0x21,0x86,0x50,0x16,0xfc,0x2c,0x96,0x47,0x35,0x6d,0x85,0x49, +0xdb,0x6,0xa4,0x7,0x55,0x86,0x48,0x9c,0xbb,0x49,0x1f,0x72,0xf9,0x54,0x13,0x2a, +0xc,0x4,0xba,0xac,0x8b,0x8b,0x42,0x8,0xb7,0xd8,0xce,0x6d,0x46,0x55,0xb6,0xa1, +0xda,0xdb,0xa8,0x31,0x62,0x70,0x4d,0x9d,0xb9,0xeb,0x10,0x34,0x40,0xa3,0x5e,0xcb, +0x27,0x98,0xf7,0xb2,0x24,0x3a,0xbb,0x5c,0x92,0x8a,0xc9,0x58,0x5f,0x0,0xf9,0x3b, +0xdb,0x22,0x6c,0xbe,0x93,0x39,0x5c,0xcc,0x25,0xec,0x1,0xe5,0x90,0xde,0x31,0x37, +0xf7,0x2a,0xea,0x9b,0xe3,0x26,0xf7,0xf6,0xb0,0x41,0x4f,0x11,0xc1,0x4a,0xcb,0x9d, +0xeb,0x38,0xdb,0xfe,0xf0,0x39,0x4c,0x16,0x26,0x4d,0x7b,0x36,0xac,0x2d,0x6d,0x24, +0xd6,0xd7,0x3f,0xba,0xfd,0xb7,0xb1,0x2f,0xf8,0x81,0xbf,0xba,0x4b,0x8b,0xd8,0x37, +0x43,0xb4,0x37,0x34,0x6d,0x83,0xc9,0x93,0x50,0x46,0x49,0x7c,0x73,0xb7,0x20,0x4a, +0x8f,0x60,0x84,0xe,0x18,0xb6,0x3d,0x11,0x38,0xfc,0x4c,0x83,0x8,0xa4,0x3a,0x4b, +0xd8,0xf0,0x7f,0x47,0xf3,0xc8,0xda,0x45,0x8e,0x25,0x41,0x81,0x5c,0x62,0x4b,0x6b, +0xc2,0xd0,0x79,0xda,0x7,0x36,0x6b,0x3f,0xb2,0x37,0x42,0xba,0x5b,0x7c,0x85,0x35, +0x6e,0x84,0x7c,0x62,0x4e,0xd6,0x27,0xdc,0x7b,0x69,0x5f,0xd7,0x4b,0xaa,0xc3,0x8d, +0xfa,0xbc,0xe7,0x2,0xf3,0xd2,0xc0,0x26,0xb,0x3,0x61,0x66,0x80,0xe6,0x1b,0xee, +0x6c,0x97,0xd0,0xba,0x6f,0xf8,0x17,0x6a,0xe1,0xf5,0x43,0x2d,0xa1,0x7,0x3a,0x1c, +0x43,0x22,0x1f,0x37,0xf4,0x5f,0xdd,0x7f,0x63,0x3f,0x66,0xe3,0x26,0x81,0x52,0x92, +0x99,0x23,0xcc,0x88,0x9b,0xe4,0xf2,0x7d,0xda,0xb5,0x2a,0xfb,0xbc,0x64,0x19,0x80, +0x6,0xb7,0xb7,0xfb,0x17,0x15,0xfa,0x7a,0x54,0xe0,0xdd,0x7b,0x63,0xaf,0x8d,0x7c, +0x53,0x5b,0x5,0xee,0x40,0xf7,0xec,0x9a,0xae,0x17,0x17,0xea,0xfb,0x30,0x6b,0x2, +0x67,0xa3,0x7d,0x7e,0x38,0x79,0x79,0x8d,0x5a,0xd6,0x9,0x3d,0x7,0x96,0xb9,0xd9, +0x71,0x3e,0x48,0x31,0xb6,0x35,0x4c,0x65,0xcc,0x63,0xcf,0xc8,0x93,0xbb,0x4a,0xfa, +0xde,0xc8,0xf8,0x17,0xc1,0xf1,0x24,0x9b,0x49,0x2d,0x59,0x50,0x44,0x92,0x2a,0x35, +0xd1,0x72,0x67,0x88,0x28,0xb3,0x6d,0x74,0x17,0xbc,0xbc,0x2a,0xf7,0x7,0xa4,0x56, +0x4f,0x1d,0x6e,0x90,0x10,0x12,0xac,0x59,0xbf,0x6,0xa9,0x83,0x98,0x53,0xb8,0xe9, +0x45,0x9f,0x72,0x6d,0x53,0x5f,0xe1,0xe9,0x9c,0x1e,0x93,0x94,0x26,0x38,0xeb,0xf4, +0x56,0xd9,0x86,0xe5,0xeb,0x33,0x3f,0xab,0xb8,0x68,0x2f,0xd0,0xbb,0xe8,0xbb,0x80, +0x88,0xad,0x6e,0x5c,0xe,0x50,0xc5,0x2a,0xee,0x5a,0xbe,0x15,0x12,0xaa,0xa,0xe7, +0x4,0x10,0xcd,0xf0,0xc2,0xd,0x1c,0x7b,0x75,0x4c,0x4d,0xb0,0xb4,0x88,0x32,0xbc, +0x36,0xa0,0x19,0xc3,0x70,0x5f,0xed,0x5f,0x39,0x2d,0xf3,0x4b,0xd7,0x7e,0x34,0x5c, +0xe,0x2,0x4d,0xd1,0x10,0x69,0xcc,0x5,0x35,0x99,0x36,0xe9,0xa1,0xe7,0xa7,0xd8, +0x8,0x40,0x1c,0x78,0x9f,0xb,0x58,0xd8,0x38,0xcb,0xa4,0x8f,0x4a,0xd8,0x6b,0xd8, +0xda,0xb8,0xaa,0x6a,0xa2,0xf6,0xef,0x57,0x11,0xa5,0x42,0xb2,0x8d,0x69,0x8b,0x95, +0xa9,0x28,0x8d,0xc9,0xb2,0x65,0x22,0x6a,0x32,0xc6,0x79,0xfb,0x1f,0xe5,0xd4,0x7a, +0x1e,0xfe,0xe4,0xc0,0x76,0x54,0x19,0x87,0xf9,0xda,0x3a,0x87,0x44,0x46,0x9c,0x6d, +0xed,0x2b,0x37,0xa0,0x90,0xd9,0xb,0x42,0x20,0x84,0x3f,0x40,0x6a,0x93,0xba,0x89, +0x93,0x1f,0xc9,0xa,0x74,0x62,0x11,0xed,0xbc,0xca,0xf5,0x1,0x90,0x92,0xee,0x7e, +0x3d,0xa5,0x1f,0xce,0x7f,0x2a,0x11,0xa0,0x2f,0xcf,0xe0,0x19,0x64,0x1b,0xa2,0xf7, +0x3a,0xec,0x81,0xae,0xce,0x92,0x1d,0x8c,0xdc,0x13,0xd,0x6e,0x25,0xfb,0xec,0x63, +0xa2,0xd,0xb1,0xa1,0xb6,0xc2,0x42,0x65,0x93,0xa2,0x7f,0x77,0xbd,0xa1,0x6f,0x78, +0xe,0x70,0xa6,0xdd,0x82,0xc3,0x6a,0x5f,0x56,0x77,0xcd,0x7c,0xf3,0x3b,0xdf,0x96, +0xc7,0x91,0x38,0x7e,0xd3,0xfa,0x64,0xe6,0x1d,0xe3,0x5e,0x5b,0x85,0x4d,0xd3,0x94, +0x3d,0x7a,0xf1,0xbf,0xbe,0x5c,0x9f,0x15,0x53,0xec,0x11,0x47,0x28,0xf0,0x5d,0x6f, +0x2,0x96,0xee,0x56,0x11,0xd2,0xbc,0xad,0xb6,0x9b,0x88,0xbb,0xe8,0x5c,0xcf,0xa6, +0x57,0xc1,0xe5,0x95,0x9d,0x85,0xaa,0xf1,0xf2,0xbc,0xb8,0x9a,0x2d,0x17,0xb,0xaf, +0x2d,0x79,0x85,0xbd,0x4c,0x42,0x6b,0x82,0xdd,0xf4,0x3e,0x47,0xd0,0x8e,0xed,0xa7, +0x50,0xd3,0x3d,0x6e,0xd9,0xe8,0xdf,0xcc,0x25,0x98,0xe6,0xd1,0xaf,0xf1,0x1,0x5c, +0x6b,0x6,0x1a,0x37,0x49,0x86,0xb9,0xa6,0xfa,0xf8,0x6d,0xcb,0x87,0x5b,0x74,0x57, +0xaf,0xb1,0xc5,0x9,0x1a,0xa5,0xd5,0xbe,0xbe,0xbc,0x11,0x6e,0x2f,0x91,0x4b,0x9a, +0x98,0x65,0xd2,0x61,0x6b,0x8c,0x8,0x66,0x5,0x76,0xb2,0xc,0x51,0xa6,0x64,0x80, +0x58,0xa9,0x89,0xf2,0xcf,0xde,0x31,0x8e,0x9c,0xc1,0x7c,0x4b,0x54,0xc7,0x65,0x6c, +0x2e,0xb7,0xcd,0x19,0x45,0x55,0x80,0xc9,0xcb,0xb2,0xd6,0x9d,0x59,0xba,0x1e,0x31, +0x64,0xa8,0xa3,0x34,0x87,0xd5,0x42,0xa3,0x17,0xbf,0xee,0x6b,0x7,0x55,0x57,0xb4, +0xd,0x25,0xce,0xd1,0x7b,0x4f,0x1c,0xc6,0x81,0xf2,0x64,0xda,0x2d,0x3,0xc,0x91, +0xab,0xb0,0x46,0x33,0x6,0x8,0x57,0x1d,0x47,0x46,0x9,0x4f,0x1b,0x60,0x4,0xa8, +0x86,0xd2,0xf9,0x81,0xa1,0x16,0xc7,0x23,0x9,0xac,0xfd,0xb5,0xaf,0x8a,0xc7,0x5b, +0x3b,0x8d,0xe,0x41,0x95,0xe4,0xdd,0xdd,0x2c,0xe6,0x2d,0xc6,0x48,0xb0,0xee,0x4e, +0x4,0xe9,0x4f,0xa5,0x0,0x17,0x49,0x89,0xc3,0xc6,0x3f,0xf2,0x51,0x7,0xcd,0xc, +0x94,0xdc,0xcc,0xaa,0x41,0xab,0x88,0xec,0x92,0x35,0xb4,0xda,0x65,0xa3,0xa8,0x69, +0x8d,0xf7,0x8f,0xe,0x10,0xd8,0x97,0x53,0x1f,0xd6,0x47,0x71,0x5e,0x15,0xfc,0x72, +0x71,0x4a,0x1d,0x33,0xf5,0xa5,0x20,0x8,0x5a,0xd4,0x63,0xc0,0xf8,0xc,0xa9,0x6, +0x5,0x39,0x14,0x94,0x12,0xab,0x67,0x32,0x3,0xae,0x23,0x61,0x44,0x9f,0xd3,0x35, +0xe9,0x71,0x68,0x5f,0x17,0x89,0xe7,0xf1,0xdd,0x4b,0x32,0x56,0xd6,0xdb,0x5d,0xdb, +0x16,0x71,0xef,0xa7,0x9d,0x58,0x59,0xa0,0x86,0xfb,0x81,0x4a,0x9c,0x55,0x0,0x6, +0x46,0xe7,0xe5,0x5e,0xf0,0xcd,0xcf,0xcf,0x19,0x81,0x26,0xef,0x5d,0x83,0x4c,0xf2, +0x75,0xbb,0x9b,0x13,0x14,0x74,0xb3,0x1b,0x71,0xb4,0x65,0x8d,0x89,0xe4,0x13,0xd0, +0xcd,0xf8,0xae,0xbe,0xc6,0x7e,0x8e,0x5f,0x0,0x35,0xcf,0xdc,0x38,0x9b,0xd0,0x2d, +0x57,0xeb,0x40,0xeb,0x60,0x73,0x7,0xd1,0x28,0xeb,0xde,0xb2,0xd1,0xf2,0x83,0x9f, +0xeb,0xb1,0xdd,0x33,0x30,0xec,0x92,0xaf,0x22,0xe1,0x8c,0xd9,0x7d,0xdc,0x8,0xd5, +0xc8,0xc7,0xc1,0xa9,0xbb,0x48,0x7b,0xe3,0x34,0xda,0x16,0x85,0xcd,0x19,0xa4,0x39, +0xca,0x83,0x6c,0x7a,0x70,0x7f,0x2a,0x12,0x61,0x37,0xeb,0xdf,0x14,0x73,0x35,0x5d, +0x3c,0xf6,0x7,0xf7,0xbe,0x2,0x5b,0x72,0xdc,0xf1,0xf8,0x2a,0xb,0x1d,0x64,0xd6, +0xa0,0xd0,0xd0,0x11,0x50,0xfb,0x23,0x32,0xb2,0x8f,0x12,0x46,0x3,0x47,0xa3,0xbe, +0xbd,0x2a,0x36,0x7c,0x2d,0x12,0x6e,0x89,0x4,0xe6,0xb4,0xf,0x5,0x98,0x65,0xa5, +0x69,0x37,0x37,0x3a,0xb2,0xd9,0x6c,0x65,0xe8,0xfd,0xab,0xec,0xc4,0xcf,0x2b,0x82, +0xf9,0xe1,0x7e,0xa6,0xf3,0x6c,0xb0,0xf7,0x54,0xe4,0x7,0x59,0x7d,0xec,0x7e,0x66, +0x24,0x35,0xa0,0x56,0x10,0x8c,0x3b,0xf8,0xa,0x66,0x65,0xce,0x36,0x11,0xd0,0xb0, +0xf2,0xce,0xd6,0xe6,0x3c,0x87,0xde,0x10,0x6c,0x65,0x69,0x69,0x52,0x67,0xd0,0xf5, +0x9d,0xf0,0xcb,0xad,0x7e,0x7,0x26,0x8,0x6e,0x8c,0x57,0xa4,0x9d,0xa7,0xd4,0x10, +0x77,0x2c,0xf6,0x33,0xb3,0x55,0x43,0xa0,0xba,0x2c,0x89,0x8d,0x93,0x5a,0x83,0x31, +0x4c,0xcf,0x5e,0x4a,0xd6,0x85,0x52,0x45,0x91,0x29,0x6a,0xae,0xd1,0x3f,0xbe,0x49, +0xea,0xb5,0xfb,0x9f,0xb,0x3f,0xbf,0x45,0x6b,0x49,0xd2,0x7e,0x24,0xd6,0x30,0x70, +0xa6,0x8e,0x3a,0x7d,0x93,0x8c,0x43,0xa4,0xb6,0xad,0x53,0x88,0x6c,0x12,0x51,0x58, +0x47,0x4d,0x77,0xd1,0xc,0xb6,0x18,0xf6,0x7f,0xea,0x75,0xa3,0x41,0xa5,0x93,0xe7, +0xb4,0xcd,0xe5,0x48,0xda,0x29,0xed,0x91,0x56,0xc0,0x99,0x42,0xd3,0x6a,0x9a,0x9a, +0xb7,0x91,0x6d,0x43,0x48,0x85,0x3a,0xc8,0xef,0x2f,0xeb,0xb1,0xd5,0x80,0x19,0xa, +0x4e,0x7e,0xd1,0x29,0x27,0x3f,0x3a,0x7d,0x1,0x53,0xc0,0x54,0xbd,0xda,0xee,0xf4, +0x6d,0xdb,0x38,0x35,0xe0,0xf1,0x7d,0x51,0x22,0x6a,0x3,0x77,0x6a,0x1c,0x1,0x38, +0x9b,0xd2,0x62,0xc2,0x13,0x1c,0xc0,0x93,0x70,0x1,0xe7,0xad,0xdb,0x56,0xa3,0xc8, +0x33,0x5b,0x7e,0x14,0xcd,0xfb,0xe4,0xef,0xe5,0xe7,0xe6,0x50,0x84,0xe7,0x89,0x9f, +0xba,0x6b,0xe1,0x4d,0x87,0xa2,0xe0,0x77,0xa3,0x48,0x26,0x0,0x9f,0x49,0x48,0x52, +0x24,0xc6,0x66,0xf1,0xc3,0xcb,0x61,0xa9,0xb3,0x48,0x7a,0xb7,0xaf,0x4,0x57,0x6b, +0x6f,0x3a,0x38,0x76,0x5c,0x1a,0xee,0x80,0x62,0x94,0x80,0x81,0xdd,0xc8,0xd3,0x81, +0x10,0xba,0x74,0x53,0x86,0xd5,0xfc,0x3a,0x9e,0xf6,0x72,0x4e,0xfa,0xc9,0x39,0xe9, +0x83,0xf1,0x61,0xe0,0x8b,0xcf,0x61,0xed,0x64,0xe1,0xef,0xc1,0x2a,0xc3,0x43,0xb9, +0xfd,0x37,0xd,0x84,0x8d,0xb,0x3f,0x2c,0x2,0xb1,0xf9,0x7d,0x7b,0xb3,0x67,0x7f, +0xa5,0x48,0x60,0x31,0x18,0xc1,0x9e,0xfb,0x23,0x8e,0xbd,0xcc,0xd2,0x81,0x87,0xd0, +0xb8,0x94,0x56,0x46,0x1f,0x95,0x72,0xa1,0xc6,0xec,0x1f,0xc1,0xa0,0x6,0x41,0x46, +0x4f,0xa1,0x77,0xe6,0xe2,0x16,0xe3,0x6,0x25,0xa1,0xd3,0xf7,0x23,0xda,0x48,0xdc, +0x6f,0x9e,0xa2,0xf,0xb3,0x16,0xb0,0xf9,0x82,0x4f,0xbc,0x23,0x55,0xfd,0x69,0x24, +0x20,0x60,0xc,0x3,0xf5,0x6f,0x89,0x1b,0x11,0xdc,0x92,0xb4,0xb7,0xdb,0x11,0xa6, +0xf9,0xb3,0xb5,0xae,0x49,0x66,0xa8,0xcb,0xb5,0xe4,0xee,0x8b,0xe3,0xd7,0xaf,0x83, +0x38,0x3b,0x86,0xae,0xaa,0x8f,0xc9,0x3c,0x6c,0xdc,0x70,0x24,0xb8,0x81,0xcb,0xb2, +0xb4,0x1,0xe0,0xfe,0x68,0x8a,0x4a,0x9d,0xee,0xb9,0xa8,0xd2,0x91,0xd8,0xd5,0x4a, +0x14,0xdc,0xf8,0x3f,0x6c,0x42,0x7b,0xd9,0x1f,0x6b,0x7d,0xd7,0xec,0xc8,0xb,0x21, +0xca,0xeb,0x20,0xb2,0xf5,0xea,0xcf,0xe5,0xa4,0x79,0x38,0xb5,0x52,0xf,0x7f,0xe5, +0x6b,0xf7,0x25,0xd7,0x3b,0x20,0x31,0xd9,0x8b,0xaf,0x32,0xf7,0xf7,0x3d,0x1a,0x42, +0xa8,0xb9,0xf4,0x9f,0xa4,0x45,0x5,0xc8,0xbe,0x3d,0xfe,0x90,0xcb,0x7e,0x76,0x37, +0xf6,0x1c,0x8f,0xb1,0x3c,0xc0,0x8b,0x48,0x70,0xbd,0xbf,0xe8,0x7a,0xd9,0x2b,0x24, +0x94,0xa0,0x43,0xb8,0xe5,0x48,0x2,0xa4,0x5,0x1,0xb4,0x51,0xfe,0x2b,0x8,0xf5, +0x47,0x97,0xa7,0x4,0x59,0xb3,0xcb,0x49,0xf0,0x8b,0x32,0x6c,0x66,0xdd,0x10,0x7a, +0x7e,0xd2,0xb2,0x64,0x9a,0xb4,0x88,0x9f,0x35,0x3d,0x70,0xb4,0xe7,0x79,0xaa,0x30, +0x90,0xd2,0xb3,0xe9,0x6,0xfe,0xb3,0xf6,0x8a,0x65,0xe2,0x70,0x43,0xf2,0x6a,0xc1, +0xc5,0x1e,0xa5,0x60,0x52,0x2e,0x80,0x8,0xea,0x70,0xbc,0xd3,0x69,0xe6,0x83,0xfa, +0x39,0xb6,0x64,0x3f,0xb5,0x18,0x37,0x40,0x7e,0x1a,0x31,0x41,0x8d,0x9b,0x4,0x53, +0x39,0x29,0x34,0x8c,0xd7,0x34,0x14,0xc2,0x24,0xd0,0x96,0x8e,0xb7,0x99,0x89,0x71, +0x50,0xed,0xb0,0x6,0x86,0xe7,0xc6,0x84,0x82,0xf7,0xc5,0x10,0x13,0x49,0xe2,0x4d, +0x73,0x17,0x59,0x4b,0xca,0x6d,0xe,0xef,0xbd,0x25,0x7e,0xf4,0x3e,0x87,0x66,0x8f, +0xf4,0x18,0x15,0x7b,0x7f,0x5b,0x0,0x2,0xd2,0xc6,0x12,0xe6,0x8f,0x75,0xb3,0x3, +0xc,0xd,0x4e,0xd7,0xf9,0xdc,0x47,0xb7,0x81,0x45,0xac,0xbf,0xcc,0x93,0xce,0x41, +0xab,0x64,0xbd,0x2b,0x3f,0x3d,0xad,0x13,0x83,0x3f,0x79,0x14,0xb4,0x2d,0x17,0xc1, +0x3a,0xe5,0x19,0xb3,0x42,0x60,0xea,0x43,0xa5,0x17,0x82,0xf1,0xaa,0xd1,0x33,0xd5, +0x36,0x70,0x2,0x75,0x2e,0x2f,0x8,0xb1,0x6e,0x81,0x45,0xa3,0xae,0xdc,0x65,0x68, +0xc2,0x7e,0x9b,0x84,0x5e,0x86,0xc7,0x4,0x9e,0x4a,0x75,0x49,0x1c,0xa8,0x20,0xd1, +0x99,0xa1,0xc7,0xc7,0xd0,0xcf,0xf8,0xbe,0xd1,0x3f,0x62,0x0,0x1c,0x47,0x69,0x5e, +0xc5,0x5,0x62,0x24,0x8c,0x2a,0xa7,0xaa,0xf3,0x9c,0xf3,0x90,0xc5,0x93,0x62,0x5f, +0xb4,0x2a,0xa6,0x5,0x7a,0x9f,0xc4,0xcb,0xde,0xa6,0xcb,0x7a,0xee,0x35,0x58,0x34, +0xba,0xba,0xd8,0xc6,0xe4,0x0,0x71,0x59,0x9d,0xe4,0xe9,0x63,0xf8,0x4c,0xc2,0xad, +0xf6,0x69,0x33,0xf0,0x88,0x77,0xbc,0x68,0x1e,0x88,0x62,0x8c,0x3e,0xbb,0xc1,0xf8, +0x76,0x1a,0xbf,0xdb,0x1a,0xb0,0x35,0xb7,0x15,0x1f,0x1b,0xe,0xea,0x5d,0x3c,0x61, +0xc6,0x6f,0x52,0x50,0xe6,0xf,0x38,0x5,0x18,0x9a,0x12,0x56,0x56,0xd3,0x4f,0x4d, +0xed,0x8e,0x29,0x87,0x3f,0xdd,0x40,0xd3,0x7c,0x5b,0xe2,0x67,0xb9,0x9e,0x49,0x0, +0xe,0x9b,0xcf,0xf4,0x2b,0x8,0x79,0x43,0x23,0x8b,0x99,0xf8,0xde,0xe8,0xc5,0x4c, +0xf6,0xee,0xd4,0xb5,0x4c,0x94,0x89,0xc8,0xef,0xeb,0xb0,0x29,0x8a,0xf9,0xa9,0x98, +0x15,0x79,0xd,0x40,0x2,0x87,0x3,0xa4,0x92,0x9c,0x9d,0xf1,0x5,0x64,0x3e,0xfb, +0xd2,0x92,0xb1,0x20,0x27,0xbb,0x68,0x97,0xa7,0x98,0xc0,0x33,0x92,0xe9,0x4b,0x28, +0x64,0x59,0x68,0xe5,0x60,0xeb,0x8a,0xf2,0x88,0xa7,0xe4,0x8e,0xc,0xa3,0xa,0x5f, +0xb5,0x3c,0xfe,0xdd,0xf7,0xe6,0x75,0x1f,0x80,0xb5,0xd1,0x13,0xa0,0x1e,0xba,0x84, +0x77,0xa3,0x6a,0xd7,0x8f,0xf4,0x4a,0x18,0x9c,0x30,0x26,0x29,0x53,0xb0,0x8,0x9, +0xec,0x86,0x66,0x64,0x6d,0xdb,0x3,0xed,0x12,0xd5,0x81,0x32,0xf3,0x3c,0xb6,0xea, +0xdf,0xa0,0xc2,0x6f,0x95,0x8c,0x8,0xb1,0x3c,0x2e,0x5a,0x8f,0x5e,0xe1,0x99,0xca, +0x68,0x7f,0x2f,0xd6,0xdb,0x33,0xc4,0xed,0x9,0x46,0x9f,0x7c,0x83,0x56,0x67,0x63, +0x76,0xa9,0x53,0xc,0x36,0x5b,0x3d,0x73,0x9,0x18,0x3,0x68,0xf9,0x1c,0x33,0xe2, +0x9c,0xe2,0xb9,0x78,0x95,0x7e,0xe5,0x1e,0x45,0x85,0x9a,0x48,0x5b,0x2,0xab,0xd1, +0xab,0x7e,0x5d,0x61,0xd9,0x1a,0xd4,0xe3,0x32,0x58,0xcb,0xac,0x74,0xfe,0x8f,0x90, +0xe1,0x49,0x88,0xf6,0x47,0x6e,0x15,0x8c,0x73,0xaf,0xd4,0xce,0x31,0x1,0xa0,0x5c, +0x7f,0x7d,0xbe,0xd9,0x98,0x93,0x3d,0x4a,0xeb,0x9,0xf6,0xe0,0x87,0x86,0xf0,0xe9, +0x4f,0x7a,0xe0,0x17,0x68,0xf6,0x23,0xdc,0xa6,0xf8,0xab,0x58,0x79,0xcc,0xb4,0x78, +0xc9,0x73,0xd1,0x62,0x87,0xf,0xad,0xf2,0x97,0x24,0x53,0x20,0xab,0x45,0xa,0x7a, +0xbf,0xea,0x91,0xa7,0x61,0xb5,0x84,0x88,0x2e,0xb0,0xe0,0x27,0x7d,0x95,0x1f,0x47, +0x89,0xf1,0x2a,0x90,0x1,0x57,0x83,0x99,0x7b,0x57,0x39,0xa6,0x9c,0x43,0x22,0xdb, +0xad,0x33,0x83,0x10,0xe8,0x88,0x98,0x96,0x39,0xf8,0x3d,0x36,0x8e,0x5d,0x7d,0x97, +0x4f,0x27,0x28,0xcf,0x7e,0x2c,0xe8,0xfa,0x83,0x22,0xa1,0x9f,0x65,0x43,0xfa,0x93, +0x77,0xfd,0x23,0xdf,0x86,0x3b,0xf6,0xbf,0x34,0x34,0xf5,0xc2,0x91,0xf3,0x5b,0x60, +0x9a,0x3,0x31,0x1a,0x2f,0x1a,0x94,0x32,0x3d,0x36,0x51,0x22,0xf9,0x4c,0x35,0x71, +0xca,0x58,0xd0,0x51,0x93,0xc7,0x91,0xc7,0xfc,0x7,0xb,0xe,0x7a,0xe5,0x6f,0x16, +0x68,0xa0,0x30,0x18,0x3a,0xc4,0x4a,0xf6,0x7a,0x1c,0x1a,0x74,0xe7,0xce,0x65,0xb2, +0x28,0x37,0x84,0x3b,0x7e,0x95,0x83,0xfa,0x9c,0x8e,0xa,0x18,0xf3,0x79,0xad,0x5c, +0x99,0x5d,0x74,0xd3,0x22,0x3f,0xcb,0x1c,0x5b,0x65,0x11,0x43,0x34,0xf5,0x76,0x5c, +0xac,0xfa,0x18,0x2c,0x90,0x9b,0x27,0xac,0xa9,0xb0,0x44,0x1d,0x2a,0xf1,0xf8,0xc3, +0x4f,0x6e,0x98,0xf0,0x2d,0xe3,0x8d,0x8,0x49,0x9e,0x4b,0x7d,0x94,0x41,0x5a,0xc1, +0x3c,0x72,0xed,0x4c,0xe,0x94,0xf9,0x37,0x46,0x3e,0x54,0x70,0xb0,0x4d,0xb4,0x7f, +0x3b,0xcc,0x71,0xe7,0xb0,0xfe,0xef,0xf9,0x1d,0xbb,0x77,0x31,0xfc,0xd1,0xf2,0xb9, +0xc3,0x60,0x6,0x51,0xf5,0x7f,0x88,0xbb,0x3e,0x5c,0xab,0xee,0x2a,0x60,0x6e,0xe4, +0xac,0x5f,0xcd,0x5d,0xdd,0x3d,0x57,0x7a,0x78,0x4f,0xac,0x76,0xa0,0x1f,0x30,0x65, +0x0,0xb5,0xb6,0x75,0x36,0xbf,0x31,0x74,0x1c,0xdc,0x63,0xc5,0xbd,0x51,0xab,0x6a, +0xb1,0xf8,0x48,0xf,0xb5,0x9f,0x8a,0x2f,0x6e,0xb6,0xa5,0x10,0x55,0x55,0x75,0x55, +0xb,0xab,0xca,0xc0,0x6b,0x7b,0x35,0x8,0xd8,0x18,0x4d,0x96,0x6a,0xf8,0x80,0x9b, +0x71,0xc8,0xaa,0x28,0xe8,0xb4,0xd6,0x57,0xea,0xfb,0xe6,0x41,0x51,0xdb,0x16,0xdb, +0x88,0x61,0x9d,0x73,0xdc,0x52,0x7b,0x35,0x6b,0xc9,0x4b,0xd5,0x42,0xcc,0xf0,0x34, +0x15,0x1b,0xdb,0xfd,0xd0,0xb2,0xd5,0x3b,0xae,0xbc,0x7c,0x0,0x19,0x13,0x5b,0xa1, +0x74,0x78,0x15,0xd0,0xcb,0x11,0x7,0x37,0x5a,0x52,0x8c,0x1c,0x9e,0x7d,0x50,0xb4, +0x98,0x2c,0x32,0xe8,0xde,0x87,0x25,0x8d,0xc4,0x21,0xd,0xdd,0xb3,0xe8,0x7f,0x28, +0x61,0x14,0x79,0xac,0xa4,0x80,0x63,0x7e,0x52,0xef,0x9b,0xf1,0xec,0xeb,0x26,0x86, +0x98,0x58,0xee,0xf6,0xe0,0x93,0x5,0x25,0xb5,0x12,0x3,0x69,0x7a,0x2,0x12,0x5c, +0x16,0x8b,0x9,0x3b,0x8b,0x6d,0xb9,0xdd,0xdc,0x55,0x4f,0xca,0xc1,0x75,0x51,0x5a, +0x4e,0xbf,0xd0,0xae,0x54,0xd5,0xd3,0x89,0x68,0xd6,0xf2,0xe2,0xd8,0x84,0x3f,0x6e, +0x8f,0x49,0xa9,0x1b,0x36,0x64,0x79,0x13,0x39,0x48,0xdd,0xfa,0xbe,0xae,0xd4,0x8c, +0x6f,0xa6,0x3b,0xc3,0x7c,0xf,0x4d,0xe4,0x65,0xbf,0x48,0xbd,0xc4,0x87,0x2c,0x54, +0x50,0x56,0xef,0x86,0xba,0xe8,0x9a,0xf3,0x31,0xf7,0x6f,0x6f,0xa7,0x44,0xfb,0x17, +0x6a,0xb6,0xda,0x67,0xc5,0xa7,0xcb,0xaa,0x67,0x14,0x68,0xab,0x9c,0x95,0x1,0x6c, +0xeb,0xf0,0xf3,0x26,0x59,0xe,0x99,0x8a,0x6,0x9,0x7a,0xad,0xcd,0x76,0xc4,0xb7, +0x2e,0x1f,0x9e,0x73,0x46,0x6b,0x1f,0x2e,0xfe,0x7,0xd9,0x1b,0x1c,0xda,0x88,0x87, +0x4b,0x7c,0xad,0x24,0x8a,0xc7,0xaf,0x90,0x50,0x2a,0xbe,0x1e,0x20,0x3,0x56,0xcd, +0x23,0xf4,0x42,0xe8,0xdf,0xe0,0x17,0xdf,0x67,0x71,0x7a,0x84,0xcb,0x3,0xc,0x18, +0xfe,0x3a,0x3c,0x89,0x2,0x6b,0x9a,0x52,0x15,0x59,0xf0,0x36,0xdb,0xc6,0x4,0xfe, +0xbb,0xc5,0x68,0x1c,0x26,0xfe,0x7b,0x8e,0x70,0xf5,0x13,0x3d,0xf9,0x1f,0xd4,0xf8, +0xd8,0x90,0x3,0xda,0xfc,0x1d,0xad,0x12,0xf5,0x9e,0xc7,0xd1,0x65,0xcc,0x51,0xa0, +0x12,0xb9,0xbc,0x39,0xb8,0xb7,0xc7,0x2a,0xae,0xda,0xe6,0x28,0x79,0xbb,0xa0,0x53, +0x4c,0xa3,0xad,0x49,0x40,0x5b,0xdb,0x36,0x79,0xa3,0x88,0xde,0xef,0xd9,0x0,0x3, +0x13,0x3c,0xbb,0xcb,0xf4,0x83,0x75,0x23,0xdd,0x5c,0x4b,0x57,0x18,0xeb,0x2a,0xe4, +0x10,0x58,0x2e,0x50,0xb3,0x89,0x7,0x2e,0xad,0x8f,0x8c,0x1d,0xe8,0xc,0x9f,0xfb, +0x49,0x5b,0x47,0xbd,0xde,0xbd,0xe0,0xbc,0x99,0x2c,0x94,0x32,0x97,0x3e,0x17,0xa7, +0x96,0xc4,0x78,0xca,0x4f,0xfe,0x78,0x7c,0xe,0x84,0x99,0xf6,0x91,0x3a,0xf2,0x5a, +0x95,0xb9,0x18,0xf4,0x77,0xf8,0xb1,0x91,0xa4,0xc5,0xc3,0x3c,0x84,0x5a,0x64,0x1b, +0x1f,0x5c,0x65,0xed,0xda,0xdd,0xe9,0xe8,0x63,0x84,0x5f,0x74,0xbe,0xd1,0xce,0xd3, +0x8b,0xe6,0xc8,0x4,0x5f,0xfa,0x15,0x4,0x40,0x58,0xbf,0xc4,0xb2,0xa3,0xe0,0x51, +0x0,0xc5,0xbf,0xda,0xa4,0xa9,0x43,0x87,0x2e,0xa2,0xfb,0x6c,0x74,0xca,0xc0,0x1, +0x31,0x89,0x84,0x90,0x4,0x99,0x14,0x45,0xf1,0x53,0x89,0x24,0xf7,0xe9,0x75,0xf7, +0xb0,0x35,0x53,0x55,0xdf,0x96,0x5c,0x8d,0x3a,0x58,0xfa,0x2e,0xa2,0xbb,0x2f,0x53, +0xc4,0xb3,0x63,0x49,0xcc,0x77,0xe,0x3e,0xca,0x97,0x62,0xc2,0x82,0xd8,0x3b,0x33, +0xe,0xe,0x8,0x6d,0xa4,0x64,0xfb,0x5e,0x3c,0x76,0xd,0x5e,0xb1,0x3c,0xb1,0xf5, +0x70,0x15,0x3f,0x3d,0xc,0x4d,0xfb,0x56,0xe5,0x5e,0x99,0x68,0x37,0xd4,0x1b,0xc5, +0xe2,0xa2,0xb2,0x7,0x7,0x2e,0xe5,0xc2,0xa4,0xf2,0x21,0xd5,0xae,0xd2,0xcc,0x1f, +0x67,0x8b,0xdc,0x73,0xd9,0xd8,0xc9,0x3f,0x37,0x63,0xa7,0xee,0xb7,0x42,0x34,0x1a, +0xe4,0xe6,0xa1,0x6b,0x16,0x87,0x2e,0x3a,0xf9,0x4f,0x90,0xa8,0xa1,0xdc,0xc8,0x9, +0x68,0x25,0xfb,0x42,0xfd,0xc5,0x81,0xb4,0xa9,0xa8,0x23,0xe0,0x6a,0x57,0xfb,0xce, +0xbe,0x1d,0x3a,0x54,0xa4,0xe7,0xe,0x9e,0x37,0x9e,0x47,0x58,0x7b,0x8f,0xe0,0xe4, +0xb4,0xdc,0xa6,0x32,0x23,0xa8,0x67,0xcc,0xd0,0x8a,0x2d,0x3c,0x62,0xa8,0xb,0x21, +0xc5,0xc5,0x75,0xe9,0xad,0x83,0x88,0x65,0x23,0x50,0xbd,0x1e,0x5f,0x9f,0x82,0x15, +0x7c,0xa9,0xc6,0x1f,0x52,0x2e,0x6b,0x23,0x39,0x99,0xde,0x9b,0x42,0xea,0x3c,0x88, +0xb0,0xb1,0x72,0x5e,0xb4,0x7b,0x43,0x57,0xcb,0x2,0x76,0x2b,0x21,0x78,0xbf,0x1d, +0x22,0x7,0x3d,0x74,0xb4,0xa8,0x18,0xed,0x42,0xf6,0x9,0x5,0xe1,0x45,0x8d,0x12, +0xf6,0x0,0xf0,0xac,0x7b,0x34,0x4,0xc6,0xb5,0xf9,0x72,0xd6,0x73,0xb1,0xf4,0x95, +0xb8,0x32,0x8a,0x6e,0x5a,0xa2,0xdb,0x1d,0x19,0xe5,0xa1,0x7b,0x2b,0x2f,0x8d,0xa2, +0xae,0x7e,0x4f,0xaa,0x33,0xd2,0xf0,0xe8,0x4d,0x63,0xc0,0xc0,0x95,0x35,0xd5,0x4e, +0xe6,0xdf,0x3c,0x41,0x2,0x19,0xdd,0x1c,0xfe,0x7f,0x97,0xa9,0xae,0x25,0x4c,0xdd, +0x24,0x1b,0x8,0xd6,0xee,0xf8,0xbf,0xbb,0xdc,0x0,0xfb,0x72,0x35,0x51,0x40,0x9b, +0x32,0x7d,0xdd,0x34,0x16,0xbb,0x50,0x94,0xbb,0x67,0x3e,0xe9,0xd,0x8b,0xc7,0x31, +0xa6,0x4f,0x87,0x15,0xc8,0x47,0x50,0x25,0xc7,0x4c,0x17,0x7c,0x9e,0x57,0x19,0xd0, +0x54,0x76,0x84,0xe9,0xb1,0x55,0x7e,0x6d,0xbc,0xbd,0x58,0xc9,0xc8,0x9f,0x7a,0x6f, +0xef,0x2,0x5,0xb8,0xc9,0x55,0xdd,0x91,0xa2,0xf4,0xe,0xc0,0xcb,0xa6,0x11,0xa0, +0x1d,0x95,0x8a,0xcf,0xea,0xa,0x3d,0x28,0xc7,0x15,0xf1,0x10,0xb5,0x6d,0xfe,0xa5, +0xee,0x4,0xdd,0xb8,0xd9,0x3b,0xc9,0xfb,0x30,0x58,0xbc,0x7b,0xfe,0xcd,0x1c,0x9c, +0xe2,0xa7,0x6c,0xce,0xb1,0x29,0xf6,0xf8,0x3f,0x68,0x9,0x74,0x55,0x87,0x1a,0x45, +0x8c,0x77,0x7d,0xe5,0xb2,0xc7,0xe1,0x62,0x9f,0x1e,0xdd,0x9e,0xeb,0xfa,0xba,0x4e, +0x22,0x27,0x1d,0x53,0xd0,0x93,0xcb,0x10,0x7c,0x54,0x4,0xd1,0xdb,0x1e,0x96,0x68, +0x15,0x15,0xcd,0xc7,0x5c,0xaf,0xa9,0xfb,0x4d,0x87,0x1a,0xb8,0x2,0xd5,0x8,0xa3, +0x7c,0x25,0xf6,0x4d,0x39,0xc2,0xdc,0xb5,0x17,0xe0,0x7,0xf3,0x7e,0x9e,0xdb,0x93, +0x33,0xaa,0xda,0x8f,0xd9,0x84,0xb,0x28,0x8c,0x25,0xe0,0x8e,0xfa,0xe8,0xb2,0x78, +0x8e,0xa9,0x45,0x47,0xec,0x23,0xfc,0x4,0x83,0x83,0x77,0x3,0x22,0x54,0x96,0x55, +0x7e,0xf1,0x64,0x58,0x76,0x6f,0x0,0x3,0x95,0xe1,0x12,0x10,0x4a,0xc4,0x8,0xd8, +0x6e,0x4e,0x20,0x5b,0x71,0x9c,0xdf,0x74,0x21,0x57,0x77,0xc2,0x2b,0x8e,0x19,0xa9, +0x80,0xfc,0x82,0xf6,0x6d,0x82,0xfa,0x82,0xe3,0xd,0x92,0x2f,0x51,0x9b,0x87,0xbf, +0x69,0xa8,0x9b,0x5a,0xc4,0x7b,0xce,0x65,0x52,0x47,0x29,0x7e,0xd5,0xc1,0xa7,0x56, +0xbe,0xa9,0xcc,0xab,0x2d,0x47,0x2e,0x90,0xd3,0x41,0xbf,0x25,0x5c,0x48,0x65,0xc5, +0x70,0x1,0x20,0xb4,0xfb,0xee,0x1b,0xcd,0x36,0xc3,0x4c,0x8b,0x85,0x74,0x61,0xc3, +0x1e,0x2f,0x70,0xca,0xf5,0x1e,0x5c,0xca,0x5f,0x9b,0x6f,0xbb,0x63,0xd4,0x81,0xd3, +0x55,0xa1,0x9,0x51,0x11,0x24,0x20,0x47,0xe7,0xeb,0x53,0xec,0xdf,0xb4,0x30,0xfe, +0x63,0xa0,0x49,0x5a,0x3f,0xa5,0x25,0x9e,0xc1,0x94,0xda,0x25,0xe9,0xdb,0x79,0x3f, +0xfd,0x82,0x11,0xf,0xa6,0xb0,0xd5,0xe,0x9c,0x29,0x7a,0xfc,0xde,0xaa,0xfb,0xc1, +0xcb,0xc4,0x1c,0xb,0x6b,0xc0,0xa9,0xac,0xd5,0x4,0xd1,0xbf,0xe0,0x4b,0x7e,0xde, +0x4d,0x8f,0x6d,0xf3,0x40,0x43,0x81,0x5d,0xec,0x7b,0x5a,0xcb,0x27,0xd5,0xd,0xf2, +0x9a,0x2a,0x7d,0x85,0x6a,0xa6,0x32,0xbf,0xab,0x84,0xfe,0xc,0x4f,0x7e,0x6a,0x9d, +0x8d,0xd7,0x11,0xce,0x9a,0x13,0xab,0x87,0x8e,0x6,0xd2,0x35,0x5b,0xe0,0x28,0xf5, +0x8a,0x25,0xfb,0xf4,0xcc,0x2e,0xb5,0x78,0x32,0xb4,0x84,0x82,0xb2,0x6e,0x20,0x41, +0x46,0x31,0x8f,0xe0,0xc3,0x3b,0x69,0x53,0xc0,0x3c,0x88,0x1c,0x1d,0x31,0x91,0xa7, +0x56,0x8d,0x1d,0x23,0x3c,0x52,0x1b,0x6e,0x7,0x1f,0x70,0x3a,0x8d,0x10,0x7b,0x53, +0x42,0xb,0x35,0x6,0xc5,0x1e,0xd8,0x86,0xd9,0x62,0x22,0xf7,0x13,0x33,0x1f,0x69, +0x41,0xbb,0xd,0x7d,0xe,0x28,0x6b,0x95,0xc7,0x5c,0xcf,0x55,0x6c,0x4b,0xa9,0x2e, +0xd5,0x5e,0xb4,0x9b,0x7c,0x8d,0xa1,0x56,0x6f,0xc3,0xcd,0x82,0x76,0x6d,0xec,0xb7, +0xa8,0x79,0xb4,0xb7,0x21,0xa0,0x4d,0xe8,0xfc,0x9c,0xbe,0x69,0x67,0xe7,0x98,0x3d, +0x46,0x4d,0x58,0x42,0xda,0xf9,0x18,0xca,0x3d,0x66,0x4d,0x33,0x53,0xb9,0xeb,0xfb, +0x33,0xa0,0xb3,0x55,0xc0,0x80,0xbd,0xbd,0x1d,0x7c,0x28,0x4,0xe3,0x40,0x41,0x2a, +0xd,0x19,0xeb,0x67,0x92,0x84,0x32,0xcf,0xea,0x80,0x4,0x3e,0xb9,0x6f,0x3a,0xed, +0x8f,0x6e,0xc2,0x51,0x6e,0x0,0x8e,0x8c,0x7d,0x36,0x10,0xe0,0x76,0xd1,0xc,0x83, +0xea,0x77,0xeb,0x7e,0xfb,0x1e,0xcd,0x66,0x1e,0x51,0x24,0xd8,0xc0,0xde,0x46,0x51, +0x4d,0x88,0x22,0xbb,0x88,0xb0,0xc7,0x85,0xe7,0xd8,0x67,0x5e,0x2a,0xf2,0x62,0x15, +0x6a,0xcd,0x13,0xe6,0x6b,0xe1,0xcc,0x8a,0x33,0xf1,0xe2,0x74,0xd0,0xa8,0xc5,0x9d, +0x31,0x67,0x59,0x39,0x18,0xa1,0xbf,0x0,0xf9,0xa6,0xde,0x24,0x99,0x41,0xb8,0x83, +0x8e,0xcc,0xe9,0xf9,0xae,0xb7,0x84,0x61,0x29,0xe6,0xd5,0xf9,0x8f,0x1b,0x97,0x40, +0x82,0x70,0x7a,0x1b,0x91,0xb9,0x1b,0x8b,0x60,0x79,0xaf,0xf9,0xba,0x69,0xfc,0x49, +0xb5,0xe7,0xc3,0x64,0x1f,0xc7,0x45,0x48,0xaf,0x9b,0x42,0xbe,0xb6,0x59,0x0,0xb9, +0x49,0xf9,0xd4,0xdb,0xb3,0x6f,0x67,0x14,0xe9,0x97,0x8d,0x24,0x80,0x8a,0xed,0x36, +0xf1,0xb1,0x1a,0x11,0x79,0x5f,0x59,0xa8,0xfa,0x1b,0x68,0x32,0x74,0xe7,0x6b,0xbe, +0x61,0x40,0x9a,0x15,0x2f,0x81,0xa8,0x19,0x19,0x36,0xbd,0x99,0xc0,0xab,0xcf,0x33, +0xdc,0xe9,0x44,0x56,0xc9,0x9e,0x7f,0x44,0xb9,0x67,0x76,0xae,0xce,0x61,0x6d,0x30, +0x21,0x87,0x45,0x51,0x88,0xed,0xe9,0xa2,0xa3,0xa7,0xbb,0xe3,0xd2,0xc,0x17,0xaf, +0x75,0x5c,0x86,0x3f,0xfa,0x85,0x4,0x34,0xec,0xf9,0xe2,0xbb,0x5c,0xcf,0x6b,0x7d, +0xd6,0xb0,0x4e,0x60,0x1e,0x39,0x82,0x41,0x60,0xbd,0x25,0x34,0xc9,0x3d,0x63,0x40, +0x99,0xe9,0xfe,0x14,0xee,0x3,0xc7,0xdb,0x7d,0x2b,0x17,0xd9,0xfa,0x82,0xd6,0x52, +0xb2,0x26,0x32,0x50,0xde,0x34,0x91,0x3f,0xf1,0xb7,0xf2,0x3c,0xf4,0x57,0xfb,0xe, +0xc0,0xfa,0x22,0xb0,0x7e,0x69,0xc,0xfb,0x94,0x24,0x55,0x10,0x26,0x2c,0x62,0xd9, +0x52,0x14,0xa9,0x31,0x48,0x3c,0xf0,0xb9,0xf3,0xe3,0xf5,0x68,0xba,0xf1,0x76,0xfb, +0x6d,0x18,0xac,0x6b,0x81,0x38,0xe6,0x96,0xdb,0x3c,0xa6,0x3,0x68,0x88,0x5c,0x3b, +0x9c,0x6,0xeb,0x64,0x42,0xdc,0x9d,0xb5,0x41,0x94,0x1e,0xfb,0x6,0x14,0xf7,0xf2, +0xab,0x24,0x5e,0xad,0x5d,0xc4,0x44,0x39,0x1,0x6a,0xbb,0xe9,0xf2,0x18,0xa4,0xf, +0x1f,0x90,0xf2,0xe0,0xed,0x90,0x97,0x2f,0xa4,0x35,0x2b,0x2b,0xc9,0xa3,0x1e,0x75, +0x47,0xfc,0xa2,0x24,0x41,0x66,0x5e,0xc2,0xd0,0x99,0xac,0xc3,0xb2,0xd0,0x52,0x51, +0x61,0x45,0x32,0xce,0x56,0x49,0xfd,0x7a,0x7f,0xa9,0xa5,0xc8,0x4d,0x44,0xbd,0x14, +0xc0,0x61,0x39,0x81,0xc7,0x17,0x44,0x99,0xb0,0x70,0xdc,0xe2,0x41,0xaf,0x34,0x23, +0xf4,0xe6,0xf1,0xca,0x30,0x70,0x46,0x2f,0x1a,0x6b,0xf7,0xe6,0x2f,0xb6,0xfa,0x6f, +0x18,0x34,0xf1,0x5f,0x4b,0x36,0x78,0xfc,0xa7,0xd5,0xdf,0x68,0x85,0x94,0x8b,0xf9, +0x7b,0xfd,0xc5,0x2b,0x6e,0x8b,0x5b,0x8,0x76,0xd2,0xee,0x26,0x89,0x69,0x95,0x21, +0x9e,0x7,0x1,0x69,0xbd,0x79,0xe5,0x65,0x4f,0x46,0x4d,0x54,0xda,0x59,0x4f,0xd5, +0x57,0x94,0x1,0x45,0x9f,0xdb,0x4d,0x16,0xaf,0xbb,0x3c,0xb8,0x25,0x52,0xda,0xc3, +0xd8,0x5b,0x2e,0x96,0x54,0x14,0x7b,0xa4,0x5a,0xc9,0x78,0xb4,0x23,0xc7,0x8a,0xf9, +0xdb,0xc,0x3f,0x7b,0xe7,0xc,0x12,0x97,0xc7,0xcd,0xd0,0xec,0x20,0x2b,0x31,0xf9, +0x86,0x5f,0x90,0xda,0xf2,0x8c,0xfe,0xcd,0x56,0x78,0x82,0xf8,0xbf,0x8d,0xf2,0x9c, +0x99,0xb1,0x97,0x81,0xbd,0xa9,0x99,0x5,0x78,0x6a,0xf1,0x18,0x95,0x23,0x12,0x9b, +0x2,0x23,0x76,0xf5,0xaf,0x76,0x43,0x85,0x6e,0xc5,0x7e,0x2e,0x53,0xf0,0x4a,0xec, +0xa2,0xe2,0xee,0xdf,0xc,0x8,0xe4,0x84,0x72,0x56,0x9d,0x87,0xf9,0x2f,0x23,0xfb, +0xd1,0x99,0x71,0x1,0x8f,0xb4,0x86,0xfd,0xfa,0x84,0xac,0x4e,0x75,0x76,0xbb,0x97, +0x59,0x2a,0x77,0xe5,0x32,0xdb,0x6a,0xa4,0xb2,0x87,0xab,0xac,0x37,0xce,0xa8,0x88, +0xe7,0x9a,0x8a,0x78,0x4f,0x90,0xf5,0x4a,0x16,0xa2,0x19,0xb,0x1a,0x54,0xa3,0xf2, +0x7e,0x9a,0xd8,0xb0,0xf6,0xc3,0x55,0xa9,0x4b,0x1,0x56,0x2,0x4f,0x7e,0x8b,0x37, +0x19,0x16,0xaf,0xe8,0x26,0x26,0xb2,0xbb,0xc8,0xcb,0xc7,0x62,0x20,0xea,0x56,0x1e, +0x5,0xae,0xce,0xfb,0x72,0x24,0x25,0x3e,0xa4,0xfa,0x40,0x73,0x7a,0x4b,0xab,0x13, +0xe0,0xda,0x7b,0x8,0x1,0x2f,0xc3,0x4a,0x7a,0x8b,0xac,0x1b,0xf5,0x3,0x39,0xfb, +0x32,0x9,0xf7,0xa4,0xac,0x1e,0x62,0xd1,0x98,0x23,0x45,0x13,0x6e,0x70,0xa6,0x50, +0x4c,0x22,0xd7,0x4d,0xd0,0x9b,0x97,0x4c,0xa7,0xc4,0xe6,0x9d,0x47,0x20,0x19,0x79, +0xa8,0x12,0x1f,0xd5,0xaf,0x1,0xa7,0x48,0x24,0x6c,0xdb,0x93,0xdd,0x2,0x63,0x2a, +0x24,0x3b,0xf6,0xf5,0x56,0xf,0xc1,0xfd,0xd3,0xa8,0x1c,0x1b,0x48,0x35,0x15,0x71, +0xc6,0x34,0x47,0xf5,0xb4,0x6e,0xbe,0xd9,0xda,0x9a,0xec,0x38,0x9c,0xcf,0xe1,0x40, +0xb,0xd9,0xb5,0xe0,0x68,0xf6,0xdf,0xbb,0x9f,0x7b,0x56,0x68,0xb0,0x6b,0xd9,0xf7, +0x1f,0xa0,0xed,0xd4,0xf,0xac,0x2e,0xe9,0xc6,0x1b,0xa2,0xe2,0xea,0x84,0x24,0x75, +0xdd,0x59,0x56,0x46,0x51,0xb5,0x81,0x70,0x31,0x58,0xd8,0x62,0xc3,0x32,0xd9,0x63, +0xd2,0xc7,0x38,0xe1,0xf4,0xe5,0x4c,0x3b,0x1,0xee,0x1f,0x6b,0x73,0xc2,0x60,0xd1, +0x1c,0xb6,0x97,0x6d,0xec,0x1a,0x5e,0x1e,0x72,0x37,0x0,0xb5,0xe9,0xd9,0x19,0xbc, +0x22,0xd0,0x1f,0x96,0x36,0xea,0xd1,0x37,0xd9,0xf0,0x22,0xcc,0x33,0x82,0x9e,0x50, +0xb9,0xb6,0x3d,0xa6,0xd0,0x9b,0x44,0xc2,0x53,0x45,0xf7,0x3d,0x9e,0x91,0x79,0x40, +0xe1,0x98,0xd6,0x19,0x83,0x29,0x50,0xdc,0x99,0xf2,0x2a,0xcd,0x75,0x48,0x9d,0x2f, +0xfe,0xda,0xd5,0x4f,0xf6,0x9a,0x91,0xc9,0x5f,0x8a,0x86,0xfd,0x1c,0x0,0xbe,0xfd, +0x19,0x15,0x17,0x9c,0x3e,0xe7,0xf9,0xd8,0x5a,0x24,0xa6,0x4f,0xeb,0x44,0x7f,0xeb, +0x9e,0xd4,0x3b,0x15,0x6f,0xcd,0xde,0xce,0xd7,0x65,0x4d,0xf3,0xe5,0x8b,0x71,0xfe, +0x20,0x9,0x1b,0x5f,0x70,0x94,0xb7,0xca,0xb8,0xdd,0x99,0xa5,0xa1,0x19,0x11,0xbf, +0x6e,0xcb,0xd5,0x5d,0x99,0x34,0xac,0xf0,0x1a,0x79,0x64,0x0,0x84,0xd6,0x7e,0xa4, +0x5f,0x99,0x4,0x4f,0x2f,0x3b,0x99,0x67,0x98,0x33,0x8c,0x3a,0xcc,0x9d,0xfa,0x3b, +0xe9,0x50,0x18,0x83,0x84,0x44,0xf4,0x9e,0xbd,0x59,0x1e,0x42,0x30,0x9c,0xe7,0xf, +0x37,0x6b,0x5e,0xe5,0x27,0xf7,0xcc,0xbf,0xab,0x5a,0xfa,0x78,0x77,0x75,0x33,0x61, +0xc5,0x4b,0x65,0xc9,0x90,0x5a,0xe8,0xcd,0xb3,0x7,0x90,0x64,0xa4,0xf7,0xf2,0x5b, +0xe2,0x52,0xc0,0xa,0xc9,0x8d,0xca,0x75,0x67,0x45,0xed,0x5f,0x3a,0x21,0x40,0x7f, +0xec,0x25,0x49,0xfc,0xfe,0xb1,0xca,0x33,0xb9,0x5b,0x97,0xdd,0xd2,0xa,0x39,0xb6, +0xdb,0xf9,0xc0,0xa6,0x7,0xb,0x9b,0x6f,0xcf,0xa,0x4e,0x89,0xaa,0x8e,0x9,0x97, +0xb4,0xd2,0x14,0xb3,0x84,0xdf,0x66,0x3e,0xba,0xfd,0x9b,0x8e,0x88,0xd4,0x45,0x64, +0x4e,0x85,0xb,0x56,0x11,0x27,0x45,0x60,0x31,0x13,0xea,0xdb,0xa1,0xf3,0xf3,0xd5, +0x46,0x8,0xa,0xcb,0x67,0x70,0x89,0xa2,0xee,0x26,0x31,0x77,0x7a,0xf5,0xdb,0xc9, +0xfa,0x67,0x9f,0x8b,0x8e,0x64,0xec,0x3f,0x77,0xd7,0x9a,0x19,0x4b,0xe,0x6f,0x92, +0x96,0x79,0xdd,0xfd,0x69,0xe6,0x20,0x58,0x8c,0x51,0x4f,0x8,0xc6,0x2c,0x51,0x42, +0x13,0x70,0xcd,0xa1,0xd4,0xba,0x60,0xcb,0x12,0xfa,0x64,0x5e,0xa,0xd3,0x70,0xa0, +0xcc,0xcd,0x1e,0x37,0xb4,0x3f,0xf,0xc1,0x10,0x5f,0x49,0x57,0xb,0x1a,0x99,0x1e, +0x8a,0xe6,0x3f,0xde,0x22,0x9f,0xaa,0x34,0x9a,0xf,0x12,0x24,0x63,0x82,0xc4,0x30, +0xcf,0x63,0xe6,0x5,0xa2,0x76,0xc6,0xb2,0xd5,0x10,0xa,0x60,0x2a,0x23,0xfd,0x34, +0xb,0x3d,0x13,0x2d,0x5c,0xbd,0x61,0x76,0x4c,0xf3,0x9b,0xaf,0xf5,0xdf,0x60,0xc6, +0x43,0x47,0xcb,0xe5,0x3d,0x92,0x99,0x13,0x22,0x23,0xf2,0x4c,0x47,0xf0,0x80,0xd1, +0xad,0x13,0xfe,0xa,0xd0,0xdf,0x81,0x9c,0xd3,0x1d,0x4d,0xca,0xfc,0xad,0x11,0xc0, +0x74,0xdc,0xa6,0xb2,0xee,0xbf,0x45,0x11,0xe3,0xb8,0xdc,0xaa,0xa9,0xdc,0x7c,0x58, +0xef,0xfa,0xe1,0x40,0xda,0x63,0xdc,0x2f,0x0,0xa9,0x79,0x7d,0xd6,0x8a,0x3e,0xcb, +0xe6,0xe4,0x7e,0xd5,0x25,0x43,0x66,0x88,0xfb,0x43,0x33,0x26,0x20,0x2f,0xfd,0x8f, +0xa9,0xdf,0xcf,0x4,0x44,0x2c,0x33,0x44,0xd6,0x2c,0xc1,0x2d,0x36,0x7f,0xf8,0x1d, +0xe4,0xf6,0x72,0xa,0x3b,0xd8,0x92,0xb6,0x9b,0x45,0xdc,0x3b,0xf3,0xda,0xca,0x9d, +0xbb,0x1a,0xa1,0x7f,0xc6,0x55,0x43,0x9d,0x1,0x85,0x4a,0x38,0x5,0x44,0xd4,0xe9, +0x3b,0x48,0x73,0xf5,0xa0,0x6,0xad,0x3d,0xca,0x8a,0xf7,0xbe,0xe5,0xc3,0xdb,0x21, +0x5d,0xfd,0xa0,0x24,0xd2,0xe3,0x41,0xd3,0x69,0x8c,0x8b,0xee,0x50,0x61,0xd8,0x8b, +0x29,0x4d,0x82,0xc9,0xd2,0x30,0x86,0x9e,0x3a,0x7f,0xdc,0x9f,0xc2,0x39,0xc0,0x9f, +0x37,0xe0,0x44,0xa,0xc5,0x85,0x5d,0xae,0x91,0xe9,0x9d,0xe1,0x4b,0xf6,0x6e,0xf3, +0xc3,0x70,0xbd,0x96,0x20,0xc4,0xb4,0x5a,0xc3,0x12,0x7a,0x6,0x4b,0x3b,0xa5,0x2, +0x1d,0xe9,0x8b,0x62,0xef,0xe8,0x11,0x81,0xd2,0x2f,0xe3,0x9d,0x26,0xd1,0x91,0xe9, +0x42,0xcf,0x0,0x62,0x94,0xb5,0x3c,0xd7,0x47,0xb6,0xdd,0x92,0x72,0x3,0x14,0x8f, +0xed,0x9f,0x71,0x5d,0x88,0x2,0x5e,0xdb,0x31,0x42,0x79,0xd6,0x14,0xc,0x40,0xd5, +0xdb,0x41,0xb7,0xef,0x76,0xf4,0xc7,0xbd,0x2b,0x25,0xcf,0x9d,0x28,0xe3,0xac,0x95, +0x3,0x1e,0xf2,0x8b,0x21,0x52,0x67,0xd1,0x94,0x61,0x29,0x29,0x6d,0x69,0xfe,0xc8, +0x2a,0xb7,0x38,0x20,0x2c,0x7f,0x5d,0x57,0xa4,0xac,0xf5,0xcc,0x90,0x22,0x63,0x93, +0x41,0x56,0x9f,0x62,0x28,0x86,0xb3,0xbd,0xe7,0xdc,0x66,0xd4,0x47,0xe4,0x9d,0xf0, +0x1c,0xd5,0x12,0x48,0x55,0xee,0x20,0x79,0x9c,0x16,0x47,0xac,0xb7,0x2a,0xc0,0xf8, +0x0,0x60,0xda,0x29,0x66,0x8f,0x66,0x4f,0x6c,0x4c,0x24,0x33,0x31,0xc2,0xa4,0x4e, +0x18,0x36,0x96,0xed,0x25,0xb6,0xe6,0xc1,0x4c,0xad,0x6f,0x5,0xd7,0x30,0x7d,0x58, +0x10,0x59,0x1,0x76,0x68,0xe6,0xc5,0x54,0x33,0x6a,0x8,0x64,0xac,0xac,0x32,0x44, +0xe2,0x49,0x32,0x87,0x7f,0x99,0x4a,0x4c,0x47,0x39,0xd0,0x9f,0xe8,0x4e,0xf7,0xf8, +0x27,0xf8,0xee,0x8f,0x5f,0x35,0x64,0x92,0x9f,0x6c,0x76,0x4c,0x98,0x29,0x10,0xfa, +0x72,0xc2,0x82,0xf1,0x5c,0xcc,0x3e,0xa3,0x85,0x8e,0x43,0x6e,0xdd,0xba,0xe6,0x84, +0xb3,0xd6,0x15,0x92,0x8b,0xf8,0xa4,0x2b,0x65,0x1c,0xf6,0x7d,0x45,0x7,0x78,0x37, +0x49,0xfa,0x29,0xa5,0x48,0xe7,0x4a,0xcd,0x76,0xd,0xbc,0xd3,0xc8,0xa3,0x59,0xfb, +0xf9,0xed,0x8f,0x85,0xe6,0x34,0x30,0xcb,0xcf,0xa6,0x49,0x94,0x2e,0x41,0xcb,0x77, +0x3c,0x75,0x9d,0x4,0x5d,0xe7,0x52,0x53,0x74,0xf,0x28,0x3d,0x32,0x1,0x3a,0xac, +0xee,0x49,0xb1,0xd5,0xfc,0xe2,0x21,0xcd,0x9,0x6a,0x62,0xb6,0x2b,0x2f,0xae,0xe6, +0x24,0x4c,0xeb,0x81,0xb3,0x3e,0x54,0x28,0xcc,0xfb,0xe5,0xfe,0xfc,0x9f,0xab,0xeb, +0xe8,0xdd,0x41,0xe5,0xc0,0x62,0xb3,0x49,0x4c,0x96,0x80,0x77,0x45,0x2f,0x5f,0x69, +0x7b,0xca,0x6a,0xae,0x9,0xbe,0xd6,0x55,0xbb,0xbc,0xd3,0x38,0xdb,0x0,0x25,0xc4, +0xdd,0x66,0x2b,0x1e,0x49,0x5e,0x67,0x95,0xf4,0xe7,0x8d,0xb9,0x17,0xec,0x23,0x12, +0xb7,0x8d,0xc0,0x40,0xcc,0x18,0x95,0x8,0x54,0x69,0x40,0x31,0x69,0x65,0x75,0x47, +0x4c,0xa0,0x65,0x95,0x0,0x4d,0xaa,0x74,0xb4,0x38,0x2f,0x4c,0xa4,0x52,0x5e,0x5c, +0x60,0x9f,0x1c,0xac,0x37,0x31,0xb4,0x8b,0x9b,0xf4,0x3c,0x84,0xda,0xb2,0x4c,0xa6, +0x53,0x31,0xbb,0x53,0x7e,0x66,0x48,0xb3,0x1f,0x77,0x0,0xc3,0x49,0xdd,0xa0,0xa9, +0xfc,0xbc,0x56,0x34,0xee,0x8a,0x40,0xa,0x0,0x7c,0xe,0xda,0x2f,0x5a,0x1,0x83, +0x8c,0xbc,0x56,0x8a,0xa2,0x9e,0x3e,0xc1,0x95,0xbd,0x86,0xdf,0x9c,0xa6,0x9,0x19, +0xe2,0xdf,0x4e,0x51,0x6a,0x8e,0x5b,0x6a,0xb,0xe9,0xc4,0x3b,0x44,0xc5,0x3e,0x50, +0x82,0x94,0x5b,0x26,0xb3,0x99,0x67,0x49,0xd7,0x6d,0xa8,0x74,0x14,0xb2,0xd,0x77, +0x92,0x5b,0xc8,0xfc,0x69,0xa4,0xe7,0x75,0x8e,0xac,0x30,0xd2,0x73,0x6e,0xa3,0x75, +0x82,0xfe,0x1b,0x36,0x98,0x83,0x0,0xef,0x70,0xa8,0xe3,0x85,0x5b,0xf1,0xfc,0x6d, +0x4d,0x45,0xea,0xb7,0xe9,0xd2,0xac,0x78,0x7f,0xdc,0xcb,0x72,0xca,0x6f,0x68,0xcc, +0x6e,0x83,0x4,0x86,0x86,0x83,0x77,0xf7,0x2c,0x5b,0xfc,0x8,0x4d,0x79,0x75,0x9b, +0xbe,0x60,0xd2,0x29,0xb2,0x7f,0xa1,0xb2,0xdb,0x6d,0x25,0xa6,0xdc,0x8d,0x73,0xca, +0x91,0xf6,0x52,0x97,0xf9,0xc9,0xf,0xa6,0x25,0x8b,0x2e,0x73,0x5,0x23,0x8e,0x44, +0x4,0x61,0xec,0xb6,0x60,0x8e,0x69,0xbb,0x7c,0xf,0x62,0xd8,0x9c,0x55,0xa4,0xad, +0xcc,0xf6,0xc5,0x46,0xc0,0xd4,0xec,0xe5,0x61,0x1b,0xd8,0xe5,0x3f,0x67,0x2a,0x43, +0x48,0x17,0x79,0xa8,0x26,0xe3,0x64,0x22,0xf2,0x46,0xfa,0xf,0x1c,0x1f,0x3d,0x68, +0x16,0x3,0xae,0xd6,0xd7,0x1c,0x3d,0x39,0xb6,0x16,0x20,0xf5,0xfd,0xc9,0xb8,0x46, +0x61,0x33,0x6f,0x7,0x17,0x53,0x29,0x89,0x1a,0xa3,0x98,0x36,0xc3,0xd5,0x1e,0xd9, +0xd8,0x4c,0x31,0x31,0x68,0xed,0x6a,0x20,0x83,0xa,0x95,0x81,0x54,0x4f,0x48,0x35, +0x2,0xb7,0x3c,0x19,0x8a,0xe4,0x22,0xa4,0x88,0xba,0x5a,0xcb,0x11,0x78,0xa6,0x69, +0xc5,0x57,0x9a,0xad,0xc4,0x85,0xcd,0x48,0xf,0xe3,0x4a,0x63,0x33,0x92,0x18,0x35, +0xc9,0x54,0xcd,0x54,0xb8,0xef,0x79,0x42,0x2a,0xd3,0xe,0x3b,0x4d,0x34,0x25,0x13, +0xb,0xbf,0x40,0xcf,0xc4,0xf,0x19,0xd4,0xf2,0x63,0xb7,0xa5,0x75,0xd0,0x5a,0xbe, +0xa4,0x28,0x13,0x5e,0x97,0x8c,0xa0,0xc1,0x61,0x2e,0x7d,0x2e,0xe2,0xa2,0xc0,0xed, +0x62,0x1,0x3e,0xa7,0x8f,0xd6,0x7c,0x82,0x3a,0xb3,0xa7,0x2f,0x84,0x2,0xed,0x2a, +0x2a,0x80,0x88,0x41,0x8d,0xa8,0x4,0x6e,0x56,0x81,0x9c,0xb8,0x24,0xdc,0x27,0x6, +0xdd,0x65,0xad,0x6e,0x3c,0xa9,0x70,0xf5,0x5e,0x19,0xa4,0xe2,0x9a,0x92,0x8c,0x45, +0x92,0x94,0x86,0x20,0x3d,0x8a,0xe,0x14,0xc,0xaa,0xcc,0xaf,0x87,0xf3,0xb6,0xe5, +0x59,0xe3,0xd3,0x15,0x8e,0x44,0xb,0x6c,0xdc,0x2f,0xce,0x78,0xc1,0x5c,0xbd,0x55, +0xf0,0x44,0xf4,0xae,0x4f,0x4,0xc2,0xda,0x2e,0x8f,0x8b,0x36,0x4,0xc1,0x1c,0xdc, +0xa5,0xef,0xf2,0xb3,0xb3,0x7d,0x20,0x91,0xad,0xef,0x89,0xee,0xcb,0x47,0xc3,0xbc, +0xb,0xb9,0x6b,0xd9,0x3d,0xad,0xb5,0x6b,0x3e,0xc0,0xa1,0xc1,0x82,0x3d,0x9e,0xa7, +0xac,0x91,0xdb,0xe0,0x8f,0x7b,0x72,0x3d,0xea,0x7b,0xab,0xb6,0x42,0x70,0xf3,0x4d, +0x2a,0x5f,0x28,0x67,0x8d,0x5d,0x52,0x4b,0x1e,0x74,0xd,0xa0,0xb1,0xab,0xc7,0xde, +0xbd,0xa3,0xbf,0x4d,0x20,0xb1,0xa,0xb,0xac,0xb5,0x42,0xee,0x26,0x36,0xbb,0x50, +0x15,0xe3,0x37,0xa2,0xc0,0x8a,0xed,0xde,0xfe,0xfa,0x7f,0x30,0xa7,0xc7,0x8e,0x65, +0x6b,0xcd,0x32,0xb,0xfe,0x3c,0x96,0xab,0xf1,0xd8,0x9a,0x19,0xf,0x57,0xe8,0x24, +0xba,0x21,0x47,0x7c,0x2b,0x35,0x5b,0xa9,0xb0,0x5b,0xd9,0xd7,0x23,0xe8,0x3d,0xe, +0xb6,0xee,0x1a,0xb6,0x2b,0xb0,0x62,0x1d,0x9,0x7d,0xb5,0x18,0xd4,0x1f,0xbb,0xf, +0xbf,0x82,0xb,0xea,0xb8,0x67,0x94,0xe8,0x42,0xed,0xc0,0xe4,0xd6,0x7d,0xf2,0x8e, +0x6c,0x8c,0xc4,0x97,0xbc,0xa6,0x34,0xc5,0x24,0x6a,0x5d,0x78,0x89,0x99,0x88,0x49, +0x1c,0x93,0xb3,0x54,0x7a,0x48,0x3d,0x3c,0xb5,0xfd,0x21,0xd,0x7b,0x94,0x1b,0x67, +0x21,0xdf,0x7e,0x5e,0x86,0xb3,0x24,0xab,0x9d,0x82,0xa3,0x27,0x9b,0x2c,0xef,0xb7, +0x40,0xa3,0xd,0x3a,0xeb,0xc9,0xf6,0x21,0xc8,0x18,0x2e,0xc3,0x2c,0x49,0xab,0xcd, +0x29,0x2a,0x2c,0x30,0x5d,0x50,0xdb,0xfa,0x52,0xfe,0x22,0xed,0x2c,0x12,0x26,0xeb, +0xb5,0x33,0xa5,0x21,0xfc,0x9c,0xc2,0x45,0x35,0xf0,0x89,0x61,0x3b,0x35,0x2f,0xe3, +0xde,0x5b,0x14,0x3d,0x2c,0x6f,0x38,0xfd,0x6f,0xda,0xec,0x1b,0x6c,0x13,0x86,0xa2, +0xc5,0xab,0x43,0x42,0xc8,0x6,0x8,0xfd,0x77,0x91,0xde,0x32,0x46,0x8e,0x16,0x25, +0xe9,0xaa,0xe1,0x95,0x99,0x1b,0x94,0x88,0x75,0x81,0x23,0xe1,0x14,0x29,0x4,0x59, +0xd5,0x48,0x9b,0x9e,0x4e,0x23,0x1c,0xc5,0xb4,0xfa,0xf7,0x7a,0x89,0x8e,0x20,0xf3, +0xb8,0x2,0x89,0x52,0x9c,0x9d,0x5b,0x12,0x9e,0x7e,0x74,0xb2,0x28,0x78,0x8b,0xfd, +0x40,0x28,0x1c,0x8f,0x4b,0xb7,0xd4,0x80,0xb2,0x4d,0x7a,0xbc,0x5b,0x9a,0x30,0x14, +0x1d,0xb9,0xe5,0xb9,0xd7,0x41,0x4c,0x76,0x40,0x40,0x2a,0x68,0x38,0xb5,0xe5,0x79, +0x5d,0x81,0x88,0x29,0x39,0xdc,0x29,0x6b,0x2a,0xa3,0x28,0x5,0xbe,0x58,0x98,0xdb, +0x92,0x7f,0x15,0x6a,0x40,0xe0,0xe0,0x80,0x21,0x8a,0x68,0xd9,0xc0,0xcd,0x53,0x9d, +0x4f,0xdb,0xc6,0x88,0xb8,0xef,0xf4,0x63,0x14,0x9c,0x68,0xd2,0xf5,0x2,0x2e,0x8, +0x1,0xc2,0xf1,0x41,0xa4,0xd2,0x42,0x45,0xdd,0x2a,0x1f,0x9e,0xf8,0xf1,0x3c,0x48, +0xcd,0x83,0x51,0x7,0xf2,0x46,0xe9,0x86,0xe2,0x52,0x59,0x58,0xd3,0x7,0x60,0x54, +0xca,0x52,0x16,0xee,0xa5,0x58,0xb3,0x83,0x2,0x53,0xa1,0xfa,0x45,0x5d,0xc3,0x93, +0x60,0x15,0x9a,0x54,0x5b,0x4,0xda,0xbd,0x56,0xb4,0x17,0xaa,0x3b,0x77,0x7e,0x6, +0x4a,0x94,0x74,0x6f,0x6c,0xa8,0xf2,0x6f,0xfb,0x14,0x6a,0xc0,0xf0,0xad,0x54,0x52, +0xc2,0x6e,0x26,0x1e,0x72,0x80,0xdc,0x49,0x35,0x73,0x73,0xf0,0x6a,0xf1,0xf6,0xb4, +0x87,0xeb,0x24,0x73,0x94,0x96,0xe2,0x10,0x2a,0xcd,0xd0,0x1c,0x7b,0x26,0xed,0x3f, +0x14,0x14,0xdc,0x87,0x94,0x39,0xd0,0x4a,0xac,0xc3,0x3b,0x97,0xb5,0xb1,0x4c,0xbc, +0x1d,0xf0,0x31,0xb1,0x87,0x93,0xc1,0x32,0x61,0x13,0x4e,0x5d,0x39,0x3c,0x1c,0x4d, +0xcf,0xf8,0x54,0x64,0xb2,0xa4,0x2e,0xde,0x68,0x69,0x76,0x9e,0x9b,0xc3,0x5b,0xb8, +0x34,0xc,0xea,0x3b,0xa0,0x2c,0x6d,0x81,0x3f,0x3b,0xde,0xf7,0x77,0x7a,0xc5,0x47, +0x74,0x1a,0x2c,0x27,0xbf,0xd9,0x85,0xa7,0x44,0xfc,0x46,0x5f,0x40,0x22,0x97,0x74, +0xad,0x82,0xaf,0xcd,0x2f,0x9d,0x50,0xed,0xd8,0xae,0xe6,0x51,0x2a,0xac,0x18,0x1e, +0xc6,0xc3,0xc4,0x6,0x9e,0x4a,0x2e,0x62,0x47,0x74,0xc1,0x87,0x16,0xd8,0x7b,0xc4, +0xdb,0x2c,0x12,0xb,0x49,0x62,0xf8,0x22,0x91,0x5f,0xf2,0x3b,0xc,0xc,0xd8,0x53, +0x4f,0x9d,0xd8,0xed,0x67,0x7,0xcf,0xaf,0xfb,0x11,0xb6,0x12,0xea,0x33,0x56,0xc6, +0xde,0x69,0x51,0x28,0x4b,0xc9,0xc9,0x5c,0x2a,0xbd,0x17,0xb5,0x49,0xef,0x9,0x98, +0x8d,0x62,0x7,0xf5,0x69,0x56,0x25,0xe4,0x68,0x5b,0x77,0xd2,0xe,0xcd,0x99,0xec, +0xb6,0x6a,0x94,0x82,0x34,0xde,0x5e,0xdd,0x9c,0x76,0x94,0xe5,0x66,0x1d,0xfd,0xf4, +0x7f,0x84,0x6a,0xe9,0xdb,0xf,0xce,0x44,0x6a,0x46,0x17,0x79,0x94,0x30,0xe5,0xca, +0x1a,0xfa,0x4d,0xcd,0xd9,0xac,0xac,0x76,0xa2,0x41,0xdb,0x9,0x5e,0x59,0x7d,0xde, +0xde,0x67,0x48,0xba,0x76,0x96,0x7e,0xe1,0xdd,0x15,0x5b,0xf1,0x45,0xc0,0xbc,0xde, +0xbb,0x8a,0xac,0x15,0xb6,0x59,0xb,0x59,0x1a,0xe6,0x62,0x79,0x41,0x60,0xd7,0x9f, +0xc7,0x20,0xd9,0x3f,0xb6,0x58,0xa0,0x14,0x6d,0x7b,0x6,0x32,0x3c,0x43,0x11,0x78, +0xcd,0x3d,0x8d,0x4,0x97,0x99,0x5d,0xb1,0x0,0x3f,0xaa,0x41,0x9f,0x82,0x60,0x68, +0x22,0x3a,0x27,0x59,0x92,0xc7,0x6d,0x7f,0x43,0xf3,0x31,0xfe,0xb6,0xc1,0x77,0x4, +0x0,0x6,0x8,0x97,0x9f,0xe4,0xc8,0x9f,0x24,0xf3,0x61,0x44,0xf5,0x41,0x2c,0x19, +0x7c,0xd2,0xf1,0x8e,0x9a,0xde,0x8e,0x5d,0xd2,0xbf,0x5c,0x9,0x82,0xd4,0xd,0x82, +0x5a,0x94,0x99,0x79,0x79,0xe1,0x19,0x1e,0xd5,0xf9,0xe1,0xcc,0x3c,0xe,0x65,0xb8, +0xe0,0x57,0xc6,0xfa,0x36,0x55,0xd7,0x89,0x16,0x34,0x12,0x18,0x88,0x20,0x1a,0x62, +0x34,0xb3,0xdb,0x2e,0x15,0xf5,0x4c,0x6b,0x6f,0xad,0x38,0xab,0xbb,0x1d,0xe3,0x1c, +0xf3,0xab,0x96,0xa9,0x1,0x6e,0x33,0x96,0x22,0xc5,0xae,0x2b,0x65,0xc8,0x8d,0x99, +0xfb,0x6a,0xc7,0x12,0xdf,0x93,0xfc,0x4f,0x41,0x35,0xfb,0x7c,0xd1,0x5f,0x18,0xc5, +0xb,0xae,0x6f,0x8c,0x9c,0x23,0xa2,0xbf,0xe8,0x52,0x6a,0x4e,0x9a,0xf7,0x67,0x97, +0xe1,0x30,0x29,0xc1,0x43,0x26,0x12,0x85,0xda,0x8d,0x2,0xac,0xec,0x1b,0xf1,0x78, +0x49,0xe0,0x84,0xe6,0x4,0x27,0x26,0x6c,0x79,0x90,0x3a,0x15,0x8,0xa2,0x2c,0xea, +0x52,0x55,0xac,0x95,0xfa,0x3e,0x9a,0xd5,0xcb,0x9d,0x2,0x39,0x38,0x73,0x31,0x1, +0x54,0xb5,0xe7,0xd8,0xdc,0x8d,0xc4,0xd6,0x9d,0x0,0x6b,0x26,0x22,0x97,0x11,0x74, +0x6c,0x3d,0xa,0x67,0xfb,0xa5,0xbc,0x47,0xc2,0xbe,0x80,0x7a,0xb1,0xb1,0x7b,0x6, +0x67,0xe3,0xde,0xc4,0x71,0xa4,0x9b,0x8f,0x24,0x7,0xb5,0x46,0x1e,0x46,0xba,0x8a, +0x83,0x44,0x71,0x7f,0x69,0x2e,0xc7,0xab,0x6c,0xc7,0x26,0x1e,0xf9,0x22,0x24,0xe0, +0x6,0x83,0xa5,0x77,0xa7,0xc0,0x7,0xcb,0xc7,0x3c,0x91,0xe5,0x82,0xcb,0xef,0x7, +0x10,0x61,0x6,0xf9,0x8f,0x4d,0xa5,0xfb,0x95,0x4c,0x99,0x8f,0x6e,0xbe,0x70,0x74, +0xc1,0x17,0x6b,0x69,0xd7,0xf2,0xb4,0x20,0x2f,0xc5,0x85,0xb2,0x91,0x76,0x39,0xa1, +0xd7,0xbe,0x1b,0xe7,0x8c,0x41,0x63,0x22,0x8d,0xfd,0xb1,0x7b,0x3c,0x22,0xef,0xfd, +0xb8,0xda,0xe6,0x11,0xcd,0x1b,0x31,0xfd,0xe0,0xb6,0x30,0x72,0xac,0xe8,0x93,0x5, +0xa7,0x2f,0xec,0x34,0x70,0xcf,0x56,0xfd,0xcd,0x87,0x79,0x89,0x2a,0xe8,0x7,0xe2, +0xc3,0xed,0xf3,0x12,0x88,0xa4,0x10,0x69,0xdb,0xbf,0x5b,0x88,0xa8,0x6f,0x8d,0xcf, +0x9e,0xf9,0x5,0xf,0xca,0xda,0x8c,0x18,0xe2,0x85,0xa2,0xd,0x6e,0xa9,0xef,0xb1, +0x18,0x64,0xc3,0xa0,0x88,0x53,0x8a,0x64,0x13,0x65,0xed,0x3b,0xd4,0xfa,0xc,0x73, +0xf5,0x90,0x2,0x40,0xea,0x8e,0x58,0xcd,0x14,0x7a,0xda,0x2,0xa4,0x4b,0xb4,0xbc, +0x2f,0x78,0xdc,0xb7,0xcc,0x67,0x1d,0x5f,0x4d,0x8a,0x9b,0x22,0x5,0x27,0x16,0x7a, +0xb7,0x18,0xba,0x22,0xa7,0x93,0xf0,0x3b,0x8d,0x4b,0x3e,0x32,0x96,0xf2,0xee,0x45, +0x6b,0xcc,0xfd,0xb7,0xb3,0x9a,0x18,0x1,0x25,0x33,0xa3,0x2a,0x5a,0xb9,0xa5,0x91, +0xd1,0xdf,0xb3,0xf8,0xf2,0x24,0x35,0x81,0x70,0xf2,0xb3,0x86,0xe5,0xa3,0xcc,0xd0, +0xef,0xca,0x89,0x23,0x65,0x21,0xa4,0xa,0xd3,0x48,0xb3,0xad,0x2,0xd8,0xbe,0x53, +0xb9,0x72,0xcc,0xac,0x17,0x2,0xad,0x87,0xf4,0x62,0xe,0x5a,0x85,0xda,0x2b,0xf4, +0x25,0x34,0x18,0xa,0xd4,0xbc,0x14,0xa8,0x84,0xc8,0xd5,0x86,0xa1,0x94,0x5a,0xda, +0x87,0x27,0x8,0x9e,0xa8,0xb5,0xa5,0x1d,0x18,0xb3,0xf6,0x1d,0xf,0x22,0x12,0x34, +0xd6,0xaa,0x3f,0xab,0xe6,0xd2,0xd4,0x6c,0x1b,0x2a,0x72,0xbd,0xbf,0xcc,0x18,0xc6, +0x73,0x20,0xe4,0x9b,0xd6,0x8a,0xb8,0x6e,0xbd,0xaf,0xc,0xcc,0x52,0x1e,0x81,0xa8, +0xc8,0x40,0x54,0xb0,0x13,0xa8,0x9c,0xae,0x53,0xf,0x6c,0x92,0x5c,0x84,0x59,0xcf, +0x25,0x3e,0x6c,0x7b,0xc8,0xa4,0xe9,0x86,0xd4,0xf5,0xd3,0x27,0x94,0xd4,0xcf,0xdc, +0x15,0xa3,0xd,0xa7,0xcc,0xa9,0x56,0x20,0xb9,0x42,0x32,0x16,0x47,0x8b,0x65,0x6c, +0xc9,0xd1,0xe7,0x12,0xf6,0x51,0x18,0xcb,0xc7,0x6b,0x72,0xdb,0x40,0xc1,0xb8,0xd4, +0xe4,0xc6,0xfc,0xb1,0x70,0x53,0x51,0xa9,0x16,0x83,0x3f,0xdc,0x8e,0xa5,0x49,0xd7, +0xf6,0xb0,0xe9,0xed,0x81,0x82,0x39,0xc8,0xed,0xab,0xa4,0xae,0xec,0x5e,0x83,0xd2, +0xa4,0x80,0x4,0x15,0x54,0xd5,0x3f,0x6a,0xd8,0x7e,0xc6,0x68,0xa3,0x10,0xbf,0x9b, +0x40,0x2a,0x9,0x41,0xac,0x43,0xb,0x1a,0x6e,0xaf,0xc8,0x5c,0x8d,0x4d,0xae,0x32, +0x4d,0xb2,0xc7,0xa1,0x8,0x7,0x8b,0xe1,0x5,0x52,0xc9,0xa9,0xe1,0x89,0x45,0xa1, +0xb3,0xcd,0xe3,0xdf,0x11,0x6e,0xfa,0x0,0x9d,0xc3,0x5c,0x2c,0x90,0xb,0x5e,0xde, +0x3d,0xa5,0x0,0x46,0xac,0x8c,0xa7,0x32,0x5e,0x71,0xdb,0xc0,0xfa,0xa0,0x62,0x2f, +0xed,0xc5,0xf,0x0,0x34,0xa,0x0,0xd2,0x4e,0xdb,0x7e,0x5e,0x66,0xdc,0x3d,0xa3, +0x3,0xbd,0x69,0x2f,0x4a,0x11,0x61,0x28,0x82,0xbc,0xe8,0xfd,0xdc,0xcb,0x2d,0xcb, +0x91,0xbb,0x4b,0x46,0xc6,0x4b,0x98,0x94,0xa6,0x17,0xf2,0xd,0x73,0x31,0x30,0x76, +0xee,0x1a,0xa6,0xb8,0x2b,0x8,0x60,0x2e,0x45,0x4a,0xab,0x22,0x95,0x58,0xed,0x27, +0x14,0x39,0x6d,0x5a,0x4,0x85,0xee,0xaa,0x9c,0xe2,0x37,0x11,0x93,0xe7,0x87,0x2, +0x2,0x2e,0x3a,0xac,0xb6,0x9a,0x5a,0xfb,0x64,0x85,0x9d,0xf9,0xdd,0x8c,0xa1,0xf2, +0x45,0x8e,0xcc,0xc9,0x15,0xbc,0xf3,0xb1,0x1f,0x2c,0x42,0xb2,0x93,0xca,0x34,0x95, +0x78,0x6e,0xc1,0xae,0x88,0x1d,0x2a,0x6d,0x22,0xc8,0xe6,0x1,0xd4,0x88,0x73,0x99, +0x97,0x40,0x63,0x2c,0x7c,0x58,0x5d,0x9b,0x4,0xa0,0x4e,0x97,0xea,0x82,0xac,0xe2, +0x70,0x6e,0x92,0x79,0xb,0xbc,0xe6,0x2e,0x85,0xcd,0xae,0xd9,0xd6,0x22,0x74,0xed, +0xe1,0xd7,0x1a,0x5f,0xaf,0x77,0xfa,0xb3,0x97,0xc9,0xca,0x2,0xcb,0x77,0xe5,0xbc, +0x66,0x78,0x36,0x71,0xb4,0x1d,0x1f,0xba,0xea,0x4d,0x94,0x41,0xee,0x88,0x2f,0xd1, +0x61,0xc8,0xb0,0x90,0xc0,0x2b,0x45,0x58,0xf4,0x8f,0x5b,0x41,0x8,0xc0,0xfd,0x6e, +0x39,0x34,0x5f,0x6d,0x51,0xfe,0x28,0xbb,0x4c,0x3d,0x7d,0x3c,0xc5,0xac,0xe,0xa6, +0xf5,0xbe,0x38,0xb6,0x69,0xfc,0x8e,0x5f,0x8c,0xe9,0xa0,0x14,0x2a,0x1e,0x82,0x63, +0x52,0x62,0x51,0x23,0x61,0x79,0x5e,0xad,0x36,0x5b,0xe9,0xfc,0x9,0x77,0x23,0x7e, +0xb5,0x5b,0x35,0x20,0xd7,0xc3,0x7f,0x65,0x2e,0x9f,0x79,0x58,0x3d,0x7c,0x3c,0xf, +0xde,0x8d,0x32,0x40,0x86,0x10,0x6d,0xbd,0x6c,0x58,0x3a,0xf4,0xcf,0x5d,0x73,0x6, +0xb9,0x28,0x26,0x91,0xeb,0x25,0x76,0x1a,0x44,0x70,0x73,0x81,0xec,0xaf,0x90,0x4b, +0xbc,0x42,0xb,0x43,0xd1,0x78,0x1,0xbd,0xd0,0x3b,0x32,0x21,0x19,0xa5,0x27,0xd2, +0xcd,0xcc,0xe3,0x3a,0xf1,0xda,0x54,0x36,0x4b,0x47,0x37,0xb7,0x76,0xc7,0x3,0x33, +0x89,0x8d,0xf6,0x5b,0x6,0x77,0x99,0x57,0x33,0xcb,0xf7,0x4c,0x72,0x1f,0x9e,0xbf, +0x6b,0x2,0x79,0x5d,0xdc,0x4e,0x13,0xa7,0x95,0x4a,0x5f,0x8c,0x91,0xe1,0x3f,0x9a, +0x6f,0x36,0xf5,0xf5,0xae,0xf,0x4d,0xe1,0xdb,0x45,0x2e,0xcd,0xe3,0x4c,0x8d,0x4f, +0x4e,0x87,0x2c,0x2c,0xd5,0x3f,0xd3,0xea,0x9,0xb3,0x77,0x9a,0x15,0xb7,0x35,0x5, +0x6d,0xaa,0xfa,0x9b,0xba,0x48,0x7d,0x96,0x8d,0x2b,0xe3,0xf0,0x77,0x71,0x40,0xc6, +0x78,0x6c,0x72,0x4e,0x2b,0xc5,0x3a,0x34,0xf8,0x31,0xce,0xf,0x68,0x83,0x14,0xd6, +0xad,0x8e,0x72,0xe7,0xd6,0x70,0xfd,0xe3,0x9b,0xe1,0xd4,0x93,0xd3,0x94,0xd9,0x4c, +0x1,0x4c,0x9b,0xab,0x91,0x55,0xdf,0x8b,0x6,0x2e,0x9a,0x6f,0xb1,0x2e,0x46,0xde, +0xbc,0x38,0xc7,0x13,0x28,0xc5,0x76,0x44,0x28,0x4b,0xd7,0xfb,0x5f,0x31,0x48,0xdf, +0x7d,0x63,0x8b,0xf,0x38,0x6b,0x1a,0x3f,0x99,0x34,0xae,0xca,0x62,0x74,0xa9,0x9e, +0x2c,0xf0,0x31,0x55,0xb7,0xa7,0x99,0xdf,0xf2,0xf0,0x5b,0xd1,0x22,0x23,0xb1,0x9f, +0x87,0x3d,0x2e,0x3f,0xa8,0x49,0x7e,0x42,0xfc,0xac,0x8c,0x60,0xa0,0x37,0x7e,0xcd, +0x28,0xb0,0x23,0x5f,0x58,0x3c,0xbe,0xcb,0x2d,0x1a,0x9d,0x4f,0x3e,0x50,0x6e,0x45, +0x8d,0x9c,0x84,0xb6,0x65,0x83,0x78,0x63,0x30,0x6,0x43,0x51,0x3d,0x41,0x1f,0xe4, +0xf1,0xc1,0x45,0xca,0xfd,0x83,0x96,0x2b,0x9e,0xb3,0x7a,0x5c,0x83,0xe8,0x21,0x91, +0x5,0xa5,0x48,0xea,0xa8,0x40,0x4e,0x59,0x46,0x11,0xaa,0x3,0x52,0x49,0xe8,0xc4, +0xb,0xad,0x8f,0x9,0x31,0xa5,0x34,0x4f,0xd8,0x2e,0xab,0x5d,0x96,0xcc,0x6e,0x9b, +0xf2,0xb6,0x86,0x1b,0x76,0x54,0x74,0xbd,0xe4,0x9e,0xc0,0xb7,0xe7,0x29,0x7c,0xf2, +0xd6,0x8b,0xfb,0x9,0x31,0xaf,0xd7,0x89,0xdd,0x84,0xe6,0xf3,0xd0,0xd4,0x90,0x43, +0xb,0x96,0x5f,0x82,0x6b,0xd3,0x40,0x50,0xf2,0x80,0x8,0xda,0x2a,0x84,0xce,0x1, +0x8f,0x4a,0x89,0xc0,0x7a,0x62,0xca,0xd7,0x66,0x31,0xcc,0x37,0x7,0x5d,0xfa,0x12, +0x73,0x5a,0x94,0xde,0xad,0x54,0x30,0xa0,0x55,0xb7,0x7c,0x7f,0x3d,0xca,0x0,0xcc, +0x94,0x8a,0xe,0xf,0x6c,0xd8,0xe7,0x52,0x89,0xb4,0x9,0x90,0x91,0x4,0xa3,0x5, +0x5e,0xb7,0xe4,0xd,0xd,0x94,0x2d,0xe1,0x4c,0xa9,0x61,0x9,0xf3,0x61,0x56,0x89, +0x6b,0xe3,0x18,0xd7,0x3c,0x0,0xa9,0xc5,0x34,0xb3,0x57,0xc5,0xb7,0x7a,0x4b,0x96, +0x32,0xaf,0xa3,0xbe,0xc3,0xd0,0xa0,0x10,0xfa,0x81,0x99,0x6e,0xe3,0xef,0x77,0xce, +0xd3,0x90,0x27,0x10,0x90,0xd0,0x55,0xc5,0x84,0x2c,0xb,0xbc,0xa6,0xd5,0x53,0x59, +0x85,0xf6,0x97,0x49,0x47,0xb8,0xd9,0xc1,0x3a,0x73,0xb0,0x9d,0x63,0x28,0x6d,0xb6, +0xb8,0x94,0x46,0xc9,0x65,0x9b,0x8f,0x6a,0xc8,0x1a,0x27,0xee,0xf0,0x7a,0xc7,0xf5, +0xf0,0x60,0xbf,0x38,0x19,0x99,0x7a,0xd2,0xd,0xaa,0x71,0xef,0xd2,0x5e,0x26,0x8c, +0xf2,0x6c,0x56,0xd7,0x87,0x65,0x42,0xcf,0xfe,0x69,0xbf,0x6f,0xe3,0x87,0x66,0xd4, +0x67,0x26,0x8d,0x0,0x3f,0x87,0xd3,0x4c,0x32,0xc4,0xbb,0x5,0x23,0xe1,0x11,0x16, +0x4e,0xe6,0x6d,0x55,0xcb,0xb0,0x26,0xcb,0x1a,0x65,0x3b,0x7e,0x6c,0x21,0xd2,0xd4, +0xc6,0x60,0xd4,0x6,0x67,0x28,0xd1,0x99,0xec,0x8d,0x1f,0x10,0x6f,0xaf,0xa5,0x3d, +0x97,0x14,0x93,0x63,0xc4,0x39,0xae,0x5e,0x9e,0x6a,0xdc,0x8a,0x8b,0xb0,0xde,0xd2, +0x90,0xb4,0xd8,0xf8,0xdc,0xab,0x12,0xca,0x39,0xb0,0xda,0x29,0x61,0x81,0x66,0xf8, +0x15,0x79,0x5c,0xd9,0x32,0x8b,0xb7,0x50,0xf5,0x15,0xdb,0x81,0x45,0xba,0x54,0xd5, +0xee,0xad,0x4e,0xcc,0x59,0xe0,0x17,0x12,0x91,0x71,0xba,0xf2,0x72,0xa1,0xeb,0x87, +0x1b,0xc8,0xe0,0xcd,0x54,0x99,0x1e,0x4a,0xae,0xf9,0x4b,0xf3,0x35,0x20,0x49,0x24, +0xcd,0x98,0x70,0xa6,0xf8,0x87,0x38,0x8a,0x79,0xf3,0x7e,0xeb,0x95,0xe9,0xf3,0x30, +0x32,0xd4,0xfd,0x6,0xed,0x9c,0x50,0x9c,0x96,0x1c,0x10,0xcb,0xbb,0x5a,0xf0,0x9, +0x72,0xe0,0xaf,0xea,0x69,0xe7,0x75,0xe2,0x5b,0x73,0x4e,0x70,0x5e,0x42,0xa1,0x90, +0x97,0x1f,0x97,0x85,0xbb,0x67,0xa2,0xd2,0x3,0xb2,0x1e,0xbe,0x8c,0x8e,0x47,0x7e, +0x70,0xf6,0x69,0xd9,0x5f,0x5f,0x3c,0x3a,0xd2,0x8a,0xab,0xb0,0x4d,0xcc,0x42,0xe4, +0xeb,0x59,0x6a,0x28,0x40,0xd,0xfa,0xc3,0x40,0x19,0x2,0xcc,0x28,0x4a,0xcb,0x98, +0xc0,0x35,0x72,0x20,0x94,0x2e,0xda,0xe7,0xb8,0x86,0x98,0x85,0x53,0x5a,0x6a,0xbe, +0xb3,0xd5,0x66,0x74,0x62,0xe0,0xb7,0xa2,0x7a,0xb9,0xef,0xa2,0x83,0xbb,0x3b,0x45, +0x70,0x2d,0xe4,0x85,0x5b,0xbf,0x6d,0x93,0xc5,0x6,0x1a,0x19,0x61,0x84,0x58,0x94, +0xd9,0xbe,0x88,0xbc,0xa0,0x40,0x5f,0x1b,0x7a,0xce,0xbd,0xfd,0xa,0x78,0x43,0xfa, +0xa5,0xa8,0x80,0x80,0x68,0x6d,0x14,0x2f,0xf2,0xad,0xc7,0xd3,0x33,0x9f,0xe8,0x8c, +0x5f,0x71,0x49,0x7f,0x32,0x29,0x1a,0x2c,0xf7,0x57,0x2a,0x82,0xcf,0xed,0x7d,0xf4, +0x96,0x7d,0x75,0x7e,0xea,0x9,0x2d,0x5d,0xb7,0x75,0x32,0x6a,0x15,0x1b,0xf6,0xf3, +0xc,0xc0,0xf2,0xbd,0xe9,0x8c,0xe9,0x61,0xe3,0x15,0x63,0x33,0x82,0xe0,0xa7,0x98, +0x5e,0x1d,0x96,0xc8,0x27,0xc4,0x27,0x5e,0xb9,0x59,0xc8,0x4e,0xf3,0x3f,0x43,0x7f, +0x0,0xb5,0x3e,0x69,0x43,0x28,0xcb,0xa6,0xbc,0xae,0xda,0x3f,0x90,0x82,0xd7,0x6e, +0x20,0xee,0x38,0xc6,0xb3,0xde,0x25,0xec,0xb7,0xed,0x3b,0xab,0x2d,0xfd,0x2b,0xad, +0xb4,0x69,0x17,0x77,0x12,0x62,0x1e,0xce,0x12,0x78,0x8e,0x22,0xfb,0xe5,0x90,0x9b, +0xd4,0x48,0x62,0x88,0x27,0x87,0xf4,0xde,0xf4,0x31,0xa,0xa1,0x2f,0x36,0x4f,0x63, +0x1f,0x67,0xda,0x31,0x49,0xf9,0x80,0xda,0x72,0xf,0xfc,0xed,0xf4,0x8e,0x89,0xca, +0xd6,0xeb,0xd2,0xfe,0xf2,0xc8,0x5d,0xe7,0x79,0x68,0x8a,0xa8,0x9e,0xd9,0xd,0x3d, +0xc0,0xe7,0xee,0x8a,0x61,0x6f,0x65,0xd4,0xfd,0x63,0x42,0xf2,0xf1,0xcc,0x3d,0x48, +0x38,0x90,0xc6,0x2c,0xd8,0x25,0x14,0x52,0x8d,0x1e,0x7a,0xab,0x78,0x7,0xe8,0x39, +0x6f,0x57,0xc3,0xd0,0x46,0xa9,0x25,0x44,0xd,0x68,0xb7,0x7e,0xb4,0xf4,0xc6,0xec, +0x5,0x8e,0x19,0xdd,0x33,0xad,0xaf,0xc0,0xcb,0x2b,0x6c,0x44,0x32,0xd4,0xfd,0xa1, +0x2d,0x41,0xf2,0x73,0xea,0x18,0x38,0xf7,0x0,0xef,0x76,0xb4,0x64,0xbd,0xa2,0x6a, +0xcb,0xbb,0xc7,0xfe,0xe8,0x78,0xbf,0xb5,0xa3,0xab,0x79,0x55,0x0,0x77,0x77,0x2d, +0xb9,0x6a,0x21,0xa4,0x2,0xd8,0x1d,0x3,0xc8,0x13,0xb7,0x2d,0x50,0x5a,0x17,0x1c, +0x96,0xdf,0x1b,0x7f,0xd7,0x5a,0xb4,0xfa,0x85,0x2f,0x50,0x86,0x26,0xc7,0x33,0xdf, +0xb1,0x54,0x5,0xb4,0x2d,0xa1,0xb7,0x75,0xb4,0xee,0x23,0x6,0xc9,0xb9,0xa1,0x60, +0x19,0x3d,0x5f,0xf0,0x97,0x94,0xeb,0x1e,0x43,0xbc,0xa4,0x69,0x4,0xd7,0xc9,0xb6, +0xac,0xce,0xea,0x59,0xef,0xa2,0x4f,0x24,0x91,0x72,0x2a,0xda,0x2c,0x4c,0xba,0x46, +0x89,0x1b,0xb6,0xa0,0x2f,0xa3,0xbe,0x72,0xdf,0xe2,0xdb,0xe3,0x3b,0x25,0x1a,0x67, +0x73,0x5,0xc0,0x63,0x27,0x10,0x88,0x39,0x2,0x32,0x14,0x2f,0x7e,0xcf,0xf4,0x87, +0x6a,0xab,0x29,0x99,0xce,0x67,0x8b,0x2e,0x4b,0xe6,0x92,0x6,0xd,0xac,0x6d,0x80, +0x32,0x2e,0xe4,0xd8,0xbe,0xec,0x12,0x40,0x1f,0x27,0x6f,0x1e,0x76,0xe3,0xa5,0xe0, +0x10,0x4e,0xf9,0x5e,0xb6,0x85,0x8d,0x2,0x6c,0x20,0x87,0x79,0x4c,0xf4,0x7a,0xfd, +0xa2,0xde,0xd7,0x61,0xcb,0xe9,0xa2,0x6a,0x90,0x91,0x8,0x7,0xf5,0x2e,0x67,0x6, +0x7c,0xe0,0x64,0x33,0x66,0x71,0xb4,0x53,0x91,0x3c,0x4c,0x5e,0x31,0xc6,0x5c,0xd4, +0xa5,0x34,0xb5,0xf0,0x1f,0xd7,0x5c,0x2f,0xe9,0x64,0xb6,0xdf,0x92,0x1e,0x65,0x10, +0x0,0x49,0xc2,0xe5,0xbb,0x78,0x39,0xcc,0x34,0x86,0x2b,0xe5,0xcc,0x88,0x3a,0x73, +0xbc,0x6f,0x64,0x5b,0x48,0x40,0x8b,0xb1,0xa5,0x42,0x11,0xb7,0xdf,0xf5,0x47,0x5f, +0x3f,0xb,0xc5,0x7a,0x3,0xfe,0x48,0xb6,0x5,0xf2,0x9c,0x52,0x7b,0xd6,0xc5,0xb8, +0x47,0xa9,0x14,0xf,0x6a,0x1f,0x40,0x8f,0xe0,0x51,0x47,0xc1,0x47,0xf,0xa0,0x6, +0x99,0x66,0x81,0x9c,0xe5,0xc9,0xd2,0x6a,0xbc,0x70,0xbc,0xb8,0xc6,0x2,0x71,0x8d, +0x2c,0x5,0x1c,0x96,0x25,0x5c,0x26,0x6,0xad,0xec,0x47,0x74,0xfb,0xe8,0x7b,0x95, +0xce,0xfc,0xb1,0x34,0x46,0x5,0x9f,0x82,0x75,0xdb,0xba,0xbb,0xde,0x2c,0xc9,0x8a, +0xb1,0xe5,0x21,0xd6,0xc2,0xc6,0x5c,0xef,0x33,0xa4,0x65,0xaf,0xd,0x60,0xc4,0x5b, +0x5d,0xf6,0x90,0x23,0xfb,0x30,0x25,0xf0,0xc,0xe0,0xac,0x6a,0x8c,0xf5,0xf4,0x3e, +0x5c,0x16,0x94,0x1f,0x5c,0xf1,0xf,0x90,0x16,0xf3,0xbf,0xa2,0x54,0x84,0xfd,0x31, +0x7b,0x8e,0xd3,0x77,0x3e,0xf9,0x68,0x4b,0x5a,0x95,0xb5,0x66,0x8b,0x2b,0x25,0x67, +0xc0,0xb9,0x86,0x1e,0x2b,0x16,0x2e,0xc0,0xa,0xed,0x63,0xde,0x72,0xe1,0x8f,0x6e, +0x70,0x64,0xe5,0xaf,0xdd,0xce,0x7a,0x38,0xe3,0xaf,0x1e,0xee,0xda,0x43,0x57,0x9c, +0x7d,0xdd,0x3a,0xa8,0x73,0xe7,0xe9,0xfd,0xd5,0x4d,0x5c,0xc7,0xae,0xeb,0x36,0x20, +0x50,0x9c,0x4f,0x2e,0xea,0x49,0xe5,0xce,0xf8,0x5,0xbd,0x54,0xc7,0x15,0x70,0x45, +0x73,0x2a,0x6e,0x66,0x12,0x58,0x64,0xe7,0x25,0xc0,0x2f,0xd4,0x2d,0xe5,0xf4,0x7d, +0x2,0xc3,0x2c,0xec,0xd,0x91,0x3b,0x85,0x16,0xf8,0x59,0xde,0x8e,0x49,0x24,0x81, + +}; +static_assert(sizeof(SEQUENCE_TABLE) == SEQUENCE_TABLE_SIZE); +} // namespace mtnet::classic diff --git a/extension/src/net/classic/wire_classic.h b/extension/src/net/classic/wire_classic.h new file mode 100644 index 00000000..1df268d0 --- /dev/null +++ b/extension/src/net/classic/wire_classic.h @@ -0,0 +1,1444 @@ +#pragma once +// 40250 "classic" Metin2 wire format — the switchable `MT_PROTOCOL=classic` +// backend (see docs/CLIENT-40250-PORT.md). This is NOT the m2dev fork protocol +// (that stays in ../wire.h). +// +// Framing (docs §2.2): +// recv: read 1 byte header -> look up static size (packet_size) -> read body. +// dynamic-size packets carry a `uint16 size` right after the header. +// send: most CG game packets append 1 trailing `uint8 sequence` byte once +// sequence mode is on (is_sequence()). +// +// Values + struct layouts verified against the 40250 sources: +// Server/metin2/src/server/game/src/packet.h (header enum, EPhase, wire structs) +// Server/metin2/src/server/game/src/packet_info.cpp (CG size table + bSeq flags) +// Server/metin2/src/server/common/{tables.h,length.h} +// ClientVS22/source/UserInterface/{Packet.h,PythonNetworkStream.cpp} (GC size/dynamic map) +// ClientVS22/source/EterBase/cipher.{h,cpp} +// +// The 40250 client Packet.h header enum is #if defined(GAIDEN)-gated and the +// shipped client build does NOT define GAIDEN; where client/server names differ +// for the same value we follow the SERVER packet.h name (it is the wire value). + +#include +#include + +namespace mtnet::classic { + +// ------------------------------------------------------------------ constants +inline constexpr int CHARACTER_NAME_MAX_LEN = 24; // common/length.h -> name[25] +inline constexpr int GUILD_NAME_MAX_LEN = 12; // -> guild_name[13] +inline constexpr int GUILD_GRADE_NAME_MAX_LEN = 8; +inline constexpr int GUILD_COMMENT_MAX_LEN = 50; +inline constexpr int GUILD_SKILL_MAX_NUM = 12; +inline constexpr int PLAYER_PER_ACCOUNT = 4; // common/length.h +inline constexpr int PLAYER_PER_ACCOUNT3 = 3; // legacy GC_LOGIN_SUCCESS (hdr 6) +inline constexpr int ID_MAX_NUM = 30; // Packet.h -> login[31] +inline constexpr int PASS_MAX_NUM = 16; // -> passwd[17] +inline constexpr int PRIVATE_CODE_LENGTH = 8; +inline constexpr int POINT_MAX_NUM = 255; // common/length.h:58 +inline constexpr int CHR_EQUIPPART_NUM = 4; // ARMOR/WEAPON/HEAD/HAIR +inline constexpr int LOGIN_STATUS_MAX_LEN = 8; // -> szStatus[9] +inline constexpr int KEY_AGREEMENT_MAX_DATA_LEN = 256; +inline constexpr int ITEM_SOCKET_MAX_NUM = 3; // common/item_length.h +inline constexpr int ITEM_ATTRIBUTE_MAX_NUM = 7; +inline constexpr int SKILL_MAX_NUM = 255; // common/length.h +inline constexpr int QUICKSLOT_MAX_NUM = 36; +inline constexpr int SHOP_HOST_ITEM_MAX_NUM = 40; +inline constexpr int SHOP_TAB_NAME_MAX = 32; +inline constexpr int SHOP_SIGN_MAX_LEN = 32; +inline constexpr int SHOP_TAB_COUNT_MAX = 3; +inline constexpr int GUILD_MARK_WIDTH = 16; +inline constexpr int GUILD_MARK_HEIGHT = 12; +inline constexpr int MARK_BLOCK_TOTAL_COUNT = 80; + +// EPacketShopSubHeaders (client Packet.h L1864) +enum : uint8_t { + SHOP_SUB_START = 0, + SHOP_SUB_END = 1, + SHOP_SUB_UPDATE_ITEM = 2, + SHOP_SUB_UPDATE_PRICE = 3, + SHOP_SUB_OK = 4, + SHOP_SUB_NOT_ENOUGH_MONEY = 5, + SHOP_SUB_SOLDOUT = 6, + SHOP_SUB_INVENTORY_FULL = 7, + SHOP_SUB_INVALID_POS = 8, + SHOP_SUB_SOLD_OUT = 9, + SHOP_SUB_START_EX = 10, + SHOP_SUB_NOT_ENOUGH_MONEY_EX = 11, +}; + +// ------------------------------------------------------------------ EPhase +// Server enum EPhase (packet.h:850). Only 0..6 reach the client via GC_PHASE. +enum Phase : uint8_t { + PHASE_CLOSE = 0, + PHASE_HANDSHAKE = 1, + PHASE_LOGIN = 2, + PHASE_SELECT = 3, + PHASE_LOADING = 4, + PHASE_GAME = 5, + PHASE_DEAD = 6, + PHASE_CLIENT_CONNECTING = 7, + PHASE_DBCLIENT = 8, + PHASE_P2P = 9, + PHASE_AUTH = 10, + PHASE_TEEN = 11, + PHASE_PASSPOD = 12, +}; + +// ------------------------------------------------------------------ headers +// Control plane (two-directional). Decimal values shown for the 0xF- block. +enum : uint8_t { + HDR_HANDSHAKE = 0xFF, // GC + CG + HDR_GC_BINDUDP = 0xFE, + HDR_CG_PONG = 0xFE, + HDR_GC_PHASE = 0xFD, + HDR_CG_CLIENT_VERSION = 0xFD, + HDR_GC_TIME_SYNC = 0xFC, // client name: HEADER_GC_HANDSHAKE_OK + HDR_CG_TIME_SYNC = 0xFC, + HDR_KEY_AGREEMENT = 0xFB, // GC + CG + HDR_GC_KEY_AGREEMENT_COMPLETED = 0xFA, + HDR_CG_CLIENT_VERSION2 = 0xF1, +}; + +// CG (client -> server). Server packet.h. +enum : uint8_t { + HDR_CG_LOGIN = 1, + HDR_CG_ATTACK = 2, + HDR_CG_CHAT = 3, + HDR_CG_CHARACTER_CREATE = 4, + HDR_CG_CHARACTER_DELETE = 5, + HDR_CG_CHARACTER_SELECT = 6, + HDR_CG_MOVE = 7, + HDR_CG_SYNC_POSITION = 8, + HDR_CG_ENTERGAME = 10, + HDR_CG_ITEM_USE = 11, + HDR_CG_ITEM_DROP = 12, + HDR_CG_ITEM_MOVE = 13, + HDR_CG_ITEM_PICKUP = 15, + HDR_CG_QUICKSLOT_ADD = 16, + HDR_CG_QUICKSLOT_DEL = 17, + HDR_CG_QUICKSLOT_SWAP = 18, + HDR_CG_WHISPER = 19, + HDR_CG_ITEM_DROP2 = 20, + HDR_CG_ON_CLICK = 26, + HDR_CG_EXCHANGE = 27, + HDR_CG_CHARACTER_POSITION = 28, + HDR_CG_SCRIPT_ANSWER = 29, + HDR_CG_QUEST_INPUT_STRING = 30, + HDR_CG_QUEST_CONFIRM = 31, + HDR_CG_SHOP = 50, + HDR_CG_FLY_TARGETING = 51, + HDR_CG_USE_SKILL = 52, + HDR_CG_ADD_FLY_TARGETING = 53, + HDR_CG_SHOOT = 54, + HDR_CG_MYSHOP = 55, + HDR_CG_ITEM_USE_TO_ITEM = 60, + HDR_CG_TARGET = 61, + HDR_CG_TEXT = 64, + HDR_CG_WARP = 65, + HDR_CG_SCRIPT_BUTTON = 66, + HDR_CG_MESSENGER = 67, + HDR_CG_MALL_CHECKOUT = 69, + HDR_CG_SAFEBOX_CHECKIN = 70, + HDR_CG_SAFEBOX_CHECKOUT = 71, + HDR_CG_PARTY_INVITE = 72, + HDR_CG_PARTY_INVITE_ANSWER = 73, + HDR_CG_PARTY_REMOVE = 74, + HDR_CG_PARTY_SET_STATE = 75, + HDR_CG_PARTY_USE_SKILL = 76, + HDR_CG_SAFEBOX_ITEM_MOVE = 77, + HDR_CG_PARTY_PARAMETER = 78, + HDR_CG_GUILD = 80, + HDR_CG_ANSWER_MAKE_GUILD = 81, + HDR_CG_FISHING = 82, + HDR_CG_ITEM_GIVE = 83, + HDR_CG_EMPIRE = 90, + HDR_CG_REFINE = 96, + HDR_CG_MARK_LOGIN = 100, + HDR_CG_MARK_CRCLIST = 101, + HDR_CG_MARK_UPLOAD = 102, + HDR_CG_MARK_IDXLIST = 104, + HDR_CG_HACK = 105, + HDR_CG_CHANGE_NAME = 106, + HDR_CG_LOGIN2 = 109, + HDR_CG_DUNGEON = 110, + HDR_CG_LOGIN3 = 111, + HDR_CG_GUILD_SYMBOL_UPLOAD = 112, + HDR_CG_SYMBOL_CRC = 113, + HDR_CG_SCRIPT_SELECT_ITEM = 114, + HDR_CG_LOGIN5_OPENID = 116, + HDR_CG_PASSPOD_ANSWER = 202, + HDR_CG_HS_ACK = 203, + HDR_CG_XTRAP_ACK = 204, + HDR_CG_DRAGON_SOUL_REFINE = 205, + HDR_CG_STATE_CHECKER = 206, +}; + +// GC (server -> client). Server packet.h (wire authority). +enum : uint8_t { + HDR_GC_CHARACTER_ADD = 1, + HDR_GC_CHARACTER_DEL = 2, + HDR_GC_MOVE = 3, + HDR_GC_CHAT = 4, + HDR_GC_SYNC_POSITION = 5, + HDR_GC_LOGIN_SUCCESS = 6, // client: LOGIN_SUCCESS3 (players[3]); legacy + HDR_GC_LOGIN_FAILURE = 7, + HDR_GC_CHARACTER_CREATE_SUCCESS = 8, + HDR_GC_CREATE_FAILURE = 9, + HDR_GC_DELETE_SUCCESS = 10, + HDR_GC_DELETE_WRONG_SOCIAL_ID = 11, + HDR_GC_ATTACK = 12, + HDR_GC_STUN = 13, + HDR_GC_DEAD = 14, + HDR_GC_MAIN_CHARACTER_OLD = 15, + HDR_GC_CHARACTER_POINTS = 16, + HDR_GC_CHARACTER_POINT_CHANGE = 17, + HDR_GC_CHANGE_SPEED = 18, + HDR_GC_CHARACTER_UPDATE = 19, + HDR_GC_ITEM_DEL = 20, + HDR_GC_ITEM_SET = 21, + HDR_GC_ITEM_USE = 22, + HDR_GC_ITEM_DROP = 23, + HDR_GC_CHARACTER_UPDATE_NEW = 24, + HDR_GC_ITEM_UPDATE = 25, + HDR_GC_ITEM_GROUND_ADD = 26, + HDR_GC_ITEM_GROUND_DEL = 27, + HDR_GC_QUICKSLOT_ADD = 28, + HDR_GC_QUICKSLOT_DEL = 29, + HDR_GC_QUICKSLOT_SWAP = 30, + HDR_GC_ITEM_OWNERSHIP = 31, + HDR_GC_LOGIN_SUCCESS_NEWSLOT = 32, // client: LOGIN_SUCCESS4 (players[4]) — what 40250 sends + HDR_GC_WHISPER = 34, + HDR_GC_MOTION = 36, + HDR_GC_PARTS = 37, + HDR_GC_SHOP = 38, // dynamic + HDR_GC_SHOP_SIGN = 39, + HDR_GC_DUEL_START = 40, // dynamic + HDR_GC_PVP = 41, + HDR_GC_EXCHANGE = 42, + HDR_GC_CHARACTER_POSITION = 43, + HDR_GC_PING = 44, + HDR_GC_SCRIPT = 45, // dynamic + HDR_GC_QUEST_CONFIRM = 46, + HDR_GC_MOUNT = 61, + HDR_GC_OWNERSHIP = 62, + HDR_GC_TARGET = 63, + HDR_GC_WARP = 65, + HDR_GC_ADD_FLY_TARGETING = 69, + HDR_GC_CREATE_FLY = 70, + HDR_GC_FLY_TARGETING = 71, + HDR_GC_SKILL_LEVEL_OLD = 72, + HDR_GC_SKILL_COOLTIME_END = 73, + HDR_GC_MESSENGER = 74, // dynamic + HDR_GC_GUILD = 75, // dynamic + HDR_GC_SKILL_LEVEL = 76, + HDR_GC_PARTY_INVITE = 77, + HDR_GC_PARTY_ADD = 78, + HDR_GC_PARTY_UPDATE = 79, + HDR_GC_PARTY_REMOVE = 80, + HDR_GC_QUEST_INFO = 81, // dynamic + HDR_GC_REQUEST_MAKE_GUILD = 82, + HDR_GC_PARTY_PARAMETER = 83, + HDR_GC_SAFEBOX_MONEY_CHANGE = 84, + HDR_GC_SAFEBOX_SET = 85, + HDR_GC_SAFEBOX_DEL = 86, + HDR_GC_SAFEBOX_WRONG_PASSWORD = 87, + HDR_GC_SAFEBOX_SIZE = 88, + HDR_GC_FISHING = 89, + HDR_GC_EMPIRE = 90, + HDR_GC_PARTY_LINK = 91, + HDR_GC_PARTY_UNLINK = 92, + HDR_GC_REFINE_INFORMATION_OLD = 95, + HDR_GC_OBSERVER_ADD = 96, + HDR_GC_OBSERVER_REMOVE = 97, + HDR_GC_OBSERVER_MOVE = 98, + HDR_GC_VIEW_EQUIP = 99, + HDR_GC_MARK_BLOCK = 100, + HDR_GC_MARK_IDXLIST = 102, + HDR_GC_TIME = 106, + HDR_GC_CHANGE_NAME = 107, + HDR_GC_DUNGEON = 110, // dynamic + HDR_GC_WALK_MODE = 111, + HDR_GC_SKILL_GROUP = 112, + HDR_GC_MAIN_CHARACTER = 113, // client non-GAIDEN: MAIN_CHARACTER2_EMPIRE + HDR_GC_SPECIAL_EFFECT = 114, // sic "SEPCIAL" in source + HDR_GC_NPC_POSITION = 115, // dynamic + HDR_GC_MATRIX_CARD = 116, + HDR_GC_CHARACTER_UPDATE2 = 117, + HDR_GC_LOGIN_KEY = 118, + HDR_GC_REFINE_INFORMATION = 119, + HDR_GC_CHARACTER_ADD2 = 120, + HDR_GC_CHANNEL = 121, + HDR_GC_MALL_OPEN = 122, + HDR_GC_TARGET_UPDATE = 123, + HDR_GC_TARGET_DELETE = 124, + HDR_GC_TARGET_CREATE = 125, + HDR_GC_AFFECT_ADD = 126, + HDR_GC_AFFECT_REMOVE = 127, + HDR_GC_MALL_SET = 128, + HDR_GC_MALL_DEL = 129, + HDR_GC_LAND_LIST = 130, // dynamic + HDR_GC_LOVER_INFO = 131, + HDR_GC_LOVE_POINT_UPDATE = 132, + HDR_GC_SYMBOL_DATA = 133, + HDR_GC_DIG_MOTION = 134, + HDR_GC_DAMAGE_INFO = 135, + HDR_GC_CHAR_ADDITIONAL_INFO = 136, + HDR_GC_MAIN_CHARACTER3_BGM = 137, + HDR_GC_MAIN_CHARACTER4_BGM_VOL = 138, + HDR_GC_AUTH_SUCCESS = 150, + HDR_GC_PANAMA_PACK = 151, + HDR_GC_HYBRIDCRYPT_KEYS = 152, // dynamic — EterPack key delivery, ignore + HDR_GC_HYBRIDCRYPT_SDB = 153, // dynamic + HDR_GC_AUTH_SUCCESS_OPENID = 154, + HDR_GC_RUNUP_MATRIX_QUIZ = 201, + HDR_GC_REQUEST_PASSPOD = 202, + HDR_GC_REQUEST_PASSPOD_FAILED = 203, + HDR_GC_HS_REQUEST = 204, + HDR_GC_XTRAP_CS1_REQUEST = 205, + HDR_GC_SPECIFIC_EFFECT = 208, + HDR_GC_DRAGON_SOUL_REFINE = 209, + HDR_GC_RESPOND_CHANNELSTATUS = 210, +}; + +// ------------------------------------------------------------------ structs +#pragma pack(push, 1) + +struct ItemPos { // TItemPos (GameType.h, pack(1)) + uint8_t window_type; + uint16_t cell; +}; +static_assert(sizeof(ItemPos) == 3); + +struct SimplePlayer { // TSimplePlayer (common/tables.h) == client TSimplePlayerInformation + uint32_t id; + char name[CHARACTER_NAME_MAX_LEN + 1]; + uint8_t job; // BYTE (create packet's `job` is WORD; this summary field is BYTE) + uint8_t level; + uint32_t play_minutes; + uint8_t st, ht, dx, iq; + uint16_t main_part; + uint8_t change_name; + uint16_t hair_part; + uint8_t dummy[4]; + int32_t x, y; + int32_t addr; + uint16_t port; + uint8_t skill_group; +}; +// 4 + 25 + 1 + 1 + 4 + 4 + 2 + 1 + 2 + 4 + 8 + 4 + 2 + 1 +static_assert(sizeof(SimplePlayer) == 63); + +// --- control / handshake --- +struct Blank { uint8_t header; }; +static_assert(sizeof(Blank) == 1); + +struct DynHead { uint8_t header; uint16_t size; }; // TDynamicSizePacketHeader +static_assert(sizeof(DynHead) == 3); + +struct Handshake { // packet_handshake (GC == CG) + uint8_t header; + uint32_t handshake; + uint32_t time; + int32_t delta; +}; +static_assert(sizeof(Handshake) == 13); + +struct Phase_ { uint8_t header; uint8_t phase; }; // packet_phase +static_assert(sizeof(Phase_) == 2); + +struct BindUDP { uint8_t header; uint32_t addr; uint16_t port; }; +static_assert(sizeof(BindUDP) == 7); + +// TPacketCGText is the handshake/admin command base. The server's +// CInputHandshake::Analyze() consumes bytes after this one-byte header up to +// and including the first newline, so the size table describes only this +// fixed prefix. +struct CGText { uint8_t header; }; +static_assert(sizeof(CGText) == 1); + +struct KeyAgreement { // TPacketKeyAgreement — fixed 261B, registered STATIC + uint8_t header; + uint16_t agreed_length; + uint16_t data_length; + uint8_t data[KEY_AGREEMENT_MAX_DATA_LEN]; +}; +static_assert(sizeof(KeyAgreement) == 261); + +struct KeyAgreementCompleted { uint8_t header; uint8_t data[3]; }; +static_assert(sizeof(KeyAgreementCompleted) == 4); + +// --- login --- +struct CGLogin { uint8_t header; char login[ID_MAX_NUM + 1]; char passwd[PASS_MAX_NUM + 1]; }; +static_assert(sizeof(CGLogin) == 1 + 31 + 17); + +struct CGLogin2 { uint8_t header; char login[ID_MAX_NUM + 1]; uint32_t login_key; uint32_t client_key[4]; }; +static_assert(sizeof(CGLogin2) == 1 + 31 + 4 + 16); + +struct CGLogin3 { uint8_t header; char login[ID_MAX_NUM + 1]; char passwd[PASS_MAX_NUM + 1]; uint32_t client_key[4]; }; +static_assert(sizeof(CGLogin3) == 1 + 31 + 17 + 16); + +struct GCLoginKey { uint8_t header; uint32_t login_key; }; +static_assert(sizeof(GCLoginKey) == 5); + +template +struct GCLoginSuccessT { // packet_login_success — 40250 sends the NEWSLOT (N=4) form + uint8_t header; + SimplePlayer players[N]; + uint32_t guild_id[N]; + char guild_name[N][GUILD_NAME_MAX_LEN + 1]; + uint32_t handle; + uint32_t random_key; +}; +using GCLoginSuccess = GCLoginSuccessT; // header 32 +using GCLoginSuccess3 = GCLoginSuccessT; // header 6 (legacy) +// 1 + 63*N + 4*N + 13*N + 4 + 4 +static_assert(sizeof(GCLoginSuccess) == 1 + 63 * 4 + 4 * 4 + 13 * 4 + 4 + 4); // 329 +static_assert(sizeof(GCLoginSuccess3) == 1 + 63 * 3 + 4 * 3 + 13 * 3 + 4 + 4); // 249 + +struct GCLoginFailure { uint8_t header; char status[LOGIN_STATUS_MAX_LEN + 1]; }; +static_assert(sizeof(GCLoginFailure) == 10); +struct GCEmpire { uint8_t header; uint8_t empire; }; + +// Account/security packets are not part of the Godot login flow, but the +// stock 40250 header map treats them as static. Keep their exact sizes so a +// deployment which enables one can still drain the stream safely. +struct GCAuthSuccess { uint8_t header; uint32_t login_key; uint8_t result; }; +struct GCAuthSuccessOpenID { + uint8_t header; + uint32_t login_key; + uint8_t result; + char login[ID_MAX_NUM + 1]; +}; +struct GCMatrixCard { uint8_t header; uint32_t rows; uint32_t cols; }; +struct GCRunupMatrixQuiz { uint8_t header; char quiz[8 + 1]; }; +struct GCRequestPasspod { uint8_t header; }; +struct GCPasspodFailed { uint8_t header; char message[128 + 1]; }; +struct GCXTrapRequest { uint8_t header; uint8_t packet_data[128]; }; +// Optional Panama package IV delivery. It is not needed by the Godot asset +// loader, but it is sent by a stock server when panama.lst is configured. +struct GCPanamaPack { uint8_t header; char pack_name[256]; uint8_t iv[32]; }; +// FreeBSD's game build wraps AHNHS_TRANS_BUFFER in #pragma pack(1): +// byte[400] + uint16 length, followed by the one-byte packet header. +struct GCHSRequest { uint8_t header; uint8_t buffer[400]; uint16_t length; }; +static_assert(sizeof(GCAuthSuccess) == 6 && sizeof(GCAuthSuccessOpenID) == 37 && + sizeof(GCMatrixCard) == 9 && sizeof(GCRunupMatrixQuiz) == 10 && + sizeof(GCRequestPasspod) == 1 && sizeof(GCPasspodFailed) == 130 && + sizeof(GCXTrapRequest) == 129 && sizeof(GCPanamaPack) == 289 && + sizeof(GCHSRequest) == 403); +static_assert(sizeof(GCEmpire) == 2); + +// --- select / create / delete --- +struct CGPlayerSelect { uint8_t header; uint8_t player_index; }; +static_assert(sizeof(CGPlayerSelect) == 2); + +struct CGPlayerCreate { // command_player_create — note `job` is WORD here + uint8_t header; + uint8_t index; + char name[CHARACTER_NAME_MAX_LEN + 1]; + uint16_t job; + uint8_t shape; + uint8_t con, intel, str, dex; +}; +static_assert(sizeof(CGPlayerCreate) == 1 + 1 + 25 + 2 + 1 + 4); + +struct CGPlayerDelete { uint8_t header; uint8_t index; char private_code[PRIVATE_CODE_LENGTH]; }; +static_assert(sizeof(CGPlayerDelete) == 10); + +struct CGChangeName { + uint8_t header; + uint8_t index; + char name[CHARACTER_NAME_MAX_LEN + 1]; +}; +static_assert(sizeof(CGChangeName) == 27); + +struct CGEmpire { uint8_t header; uint8_t empire; }; +static_assert(sizeof(CGEmpire) == 2); + +// CG_CLIENT_VERSION / CG_CLIENT_VERSION2 — TPacketCGClientVersion. The +// 40250 server records this before accepting game-phase movement; omitting it +// causes the server to close the connection on the first CG_MOVE. +struct CGClientVersion { + uint8_t header; + char filename[33]; + char timestamp[33]; +}; +static_assert(sizeof(CGClientVersion) == 67); + +struct GCPlayerCreateSuccess { uint8_t header; uint8_t account_slot; SimplePlayer player; }; +static_assert(sizeof(GCPlayerCreateSuccess) == 2 + 63); +struct GCPlayerCreateFailure { uint8_t header; uint8_t type; }; +struct GCChangeNameNotice { uint8_t header; uint32_t pid; char name[CHARACTER_NAME_MAX_LEN + 1]; }; +static_assert(sizeof(GCPlayerCreateFailure) == 2 && sizeof(GCChangeNameNotice) == 30); + +struct GCPlayerDeleteSuccess { uint8_t header; uint8_t account_index; }; +static_assert(sizeof(GCPlayerDeleteSuccess) == 2); + +struct CGEnterGame { uint8_t header; }; +static_assert(sizeof(CGEnterGame) == 1); + +// --- independent guild-mark connection --- +// The mark server uses the same classic DH2/CTR control handshake, but its +// mark packets are not in the normal game length map. These fixed packet +// layouts are copied from ClientVS22/UserInterface/Packet.h. +struct CGMarkLogin { uint8_t header; uint32_t handle; uint32_t random_key; }; +struct CGMarkIDXList { uint8_t header; }; +struct CGMarkCRCList { uint8_t header; uint8_t img_idx; uint32_t crclist[MARK_BLOCK_TOTAL_COUNT]; }; +struct CGMarkUpload { + uint8_t header; + uint32_t gid; + uint8_t image[GUILD_MARK_WIDTH * GUILD_MARK_HEIGHT * 4]; +}; +struct CGGuildSymbolUpload { uint8_t header; uint16_t size; uint32_t guild_id; }; +struct CGSymbolCRC { uint8_t header; uint32_t guild_id; uint32_t crc; uint32_t size; }; +struct GCMarkIDXList { uint8_t header; uint32_t buf_size; uint16_t count; }; +struct GCMarkBlock { uint8_t header; uint32_t buf_size; uint8_t img_idx; uint32_t count; }; +struct GCSymbolData { uint8_t header; uint16_t size; uint32_t guild_id; }; +static_assert(sizeof(CGMarkLogin) == 9 && sizeof(CGMarkIDXList) == 1 && + sizeof(CGMarkCRCList) == 322 && sizeof(CGMarkUpload) == 773 && + sizeof(CGGuildSymbolUpload) == 7 && sizeof(CGSymbolCRC) == 13 && + sizeof(GCMarkIDXList) == 7 && sizeof(GCMarkBlock) == 10 && + sizeof(GCSymbolData) == 7); + +// --- main character (header 113) --- +struct GCMainCharacter { // packet.h:1043 (== client TPacketGCMainCharacter2_EMPIRE) + uint8_t header; + uint32_t vid; + uint16_t race; + char name[CHARACTER_NAME_MAX_LEN + 1]; + int32_t x, y, z; + uint8_t empire; + uint8_t skill_group; +}; +static_assert(sizeof(GCMainCharacter) == 1 + 4 + 2 + 25 + 12 + 1 + 1); + +// SUPPORT_BGM variants emitted by CHARACTER::MainCharacterPacket when the +// map has a configured background track. The BGM field is not needed by the +// Godot world model, but it must be part of the frame so the next GC packet is +// not mistaken for the tail of this one. +struct GCMainCharacter3BGM { + uint8_t header; + uint32_t vid; + uint16_t race; + char name[CHARACTER_NAME_MAX_LEN + 1]; + char bgm_name[24 + 1]; + int32_t x, y, z; + uint8_t empire; + uint8_t skill_group; +}; +struct GCMainCharacter4BGM { + uint8_t header; + uint32_t vid; + uint16_t race; + char name[CHARACTER_NAME_MAX_LEN + 1]; + char bgm_name[24 + 1]; + float bgm_volume; + int32_t x, y, z; + uint8_t empire; + uint8_t skill_group; +}; +static_assert(sizeof(GCMainCharacter3BGM) == 71 && sizeof(GCMainCharacter4BGM) == 75); + +// --- spawn / despawn / move --- +struct GCCharacterAdd { // packet_add_char (server) — no name/parts + uint8_t header; + uint32_t vid; + float angle; + int32_t x, y, z; + uint8_t type; + uint16_t race; + uint8_t moving_speed; + uint8_t attack_speed; + uint8_t state_flag; + uint32_t affect_flag[2]; +}; +static_assert(sizeof(GCCharacterAdd) == 1 + 4 + 4 + 12 + 1 + 2 + 1 + 1 + 1 + 8); + +struct GCCharacterAdd2 { // packet_add_char2 — name + parts + guild + uint8_t header; + uint32_t vid; + char name[CHARACTER_NAME_MAX_LEN + 1]; + float angle; + int32_t x, y, z; + uint8_t type; + uint16_t race; + uint16_t parts[CHR_EQUIPPART_NUM]; + uint8_t moving_speed; + uint8_t attack_speed; + uint8_t state_flag; + uint32_t affect_flag[2]; + uint8_t empire; + uint32_t guild; + int16_t alignment; + uint8_t pk_mode; + uint32_t mount_vnum; +}; +static_assert(sizeof(GCCharacterAdd2) == + 1 + 4 + 25 + 4 + 12 + 1 + 2 + 8 + 1 + 1 + 1 + 8 + 1 + 4 + 2 + 1 + 4); + +struct GCCharacterDel { uint8_t header; uint32_t vid; }; +static_assert(sizeof(GCCharacterDel) == 5); + +struct CGMove { // command_move + uint8_t header; + uint8_t func; + uint8_t arg; + uint8_t rot; + int32_t x, y; + uint32_t time; +}; +static_assert(sizeof(CGMove) == 4 + 8 + 4); + +struct GCMove { // packet_move (server) — adds vid + duration + uint8_t header; + uint8_t func; + uint8_t arg; + uint8_t rot; + uint32_t vid; + int32_t x, y; + uint32_t time; + uint32_t duration; +}; +static_assert(sizeof(GCMove) == 4 + 4 + 8 + 4 + 4); + +// --- points --- +struct GCPoints { uint8_t header; int32_t points[POINT_MAX_NUM]; }; +static_assert(sizeof(GCPoints) == 1 + 255 * 4); + +struct GCPointChange { // packet_point_change — NOTE: `int header` (4 bytes) in the source + int32_t header; // wire: byte 0 = real header, bytes 1..3 = junk from the int + uint32_t vid; + uint8_t type; + int32_t amount; + int32_t value; +}; +static_assert(sizeof(GCPointChange) == 4 + 4 + 1 + 4 + 4); + +// --- CG in-game intents --- +struct CGAttack { // command_attack + uint8_t header; + uint8_t type; + uint32_t victim_vid; + uint8_t crc_proc; + uint8_t crc_file; +}; +static_assert(sizeof(CGAttack) == 8); + +struct CGTarget { uint8_t header; uint32_t vid; }; // command_target +static_assert(sizeof(CGTarget) == 5); +struct CGOnClick { uint8_t header; uint32_t vid; }; // command_on_click +static_assert(sizeof(CGOnClick) == 5); +struct CGPosition { uint8_t header; uint8_t position; }; // command_position +static_assert(sizeof(CGPosition) == 2); +struct CGScriptAnswer { uint8_t header; uint8_t answer; }; +static_assert(sizeof(CGScriptAnswer) == 2); + +struct CGItemUse { uint8_t header; ItemPos pos; }; // command_item_use +static_assert(sizeof(CGItemUse) == 4); +struct CGItemMove { uint8_t header; ItemPos pos; ItemPos change_pos; uint8_t num; }; +static_assert(sizeof(CGItemMove) == 8); +struct CGItemDrop { uint8_t header; ItemPos pos; uint32_t gold; }; // command_item_drop +static_assert(sizeof(CGItemDrop) == 8); +struct CGItemDrop2 { uint8_t header; ItemPos pos; uint32_t gold; uint8_t count; }; +static_assert(sizeof(CGItemDrop2) == 9); +struct CGItemPickup { uint8_t header; uint32_t vid; }; // command_item_pickup +static_assert(sizeof(CGItemPickup) == 5); +struct CGUseSkill { uint8_t header; uint32_t vnum; uint32_t target_vid; }; +static_assert(sizeof(CGUseSkill) == 9); +struct CGFlyTargeting { uint8_t header; uint32_t target_vid; int32_t x, y; }; +static_assert(sizeof(CGFlyTargeting) == 13); +struct CGShoot { uint8_t header; uint8_t type; }; +static_assert(sizeof(CGShoot) == 2); +struct CGWarp { uint8_t header; }; +static_assert(sizeof(CGWarp) == 1); +struct CGFishing { uint8_t header; uint8_t dir; }; +static_assert(sizeof(CGFishing) == 2); +struct CGItemUseToItem { uint8_t header; ItemPos pos; ItemPos target_pos; }; +static_assert(sizeof(CGItemUseToItem) == 7); +struct CGGiveItem { uint8_t header; uint32_t target_vid; ItemPos pos; uint8_t count; }; +static_assert(sizeof(CGGiveItem) == 9); +struct CGQuickSlotAdd { uint8_t header; uint8_t pos; uint8_t type; uint8_t position; }; +struct CGQuickSlotDel { uint8_t header; uint8_t pos; }; +struct CGQuickSlotSwap { uint8_t header; uint8_t pos; uint8_t pos_to; }; +static_assert(sizeof(CGQuickSlotAdd) == 4 && sizeof(CGQuickSlotDel) == 2 && + sizeof(CGQuickSlotSwap) == 3); + +// --- P8 social / exchange / storage intents ------------------------------- +enum : uint8_t { + EXCHANGE_CG_START = 0, + EXCHANGE_CG_ITEM_ADD = 1, + EXCHANGE_CG_ITEM_DEL = 2, + EXCHANGE_CG_GOLD_ADD = 3, + EXCHANGE_CG_ACCEPT = 4, + EXCHANGE_CG_CANCEL = 5, + + MESSENGER_CG_ADD_BY_VID = 0, + MESSENGER_CG_ADD_BY_NAME = 1, + MESSENGER_CG_REMOVE = 2, +}; + +struct CGExchange { + uint8_t header; + uint8_t subheader; + uint32_t arg1; + uint8_t arg2; + ItemPos pos; +}; +static_assert(sizeof(CGExchange) == 10); + +struct CGMessenger { uint8_t header; uint8_t subheader; }; +static_assert(sizeof(CGMessenger) == 2); + +struct CGSafeboxCheckout { + uint8_t header; + uint8_t safe_pos; + ItemPos item_pos; +}; +struct CGSafeboxCheckin { + uint8_t header; + uint8_t safe_pos; + ItemPos item_pos; +}; +struct CGMallCheckout { + uint8_t header; + uint8_t mall_pos; + ItemPos item_pos; +}; +static_assert(sizeof(CGSafeboxCheckout) == 5 && sizeof(CGSafeboxCheckin) == 5 && + sizeof(CGMallCheckout) == 5); + +enum : uint8_t { + SHOP_CG_END = 0, + SHOP_CG_BUY = 1, + SHOP_CG_SELL = 2, + SHOP_CG_SELL2 = 3, +}; +struct CGShop { uint8_t header; uint8_t subheader; }; +struct CGShopBuy { uint8_t count; uint8_t pos; }; +struct CGShopSell { uint8_t pos; }; +struct CGShopSell2 { uint8_t pos; uint8_t count; }; +static_assert(sizeof(CGShop) == 2 && sizeof(CGShopBuy) == 2 && sizeof(CGShopSell) == 1 && + sizeof(CGShopSell2) == 2); + +struct CGScriptButton { uint8_t header; uint32_t index; }; +struct CGQuestInput { uint8_t header; char msg[64 + 1]; }; +struct CGQuestConfirm { uint8_t header; uint8_t answer; uint32_t request_pid; }; +struct CGScriptSelectItem { uint8_t header; uint32_t selection; }; +static_assert(sizeof(CGScriptButton) == 5 && sizeof(CGQuestInput) == 66 && + sizeof(CGQuestConfirm) == 6 && sizeof(CGScriptSelectItem) == 5); + +struct CGPartyInvite { uint8_t header; uint32_t vid; }; +struct CGPartyInviteAnswer { uint8_t header; uint32_t leader_vid; uint8_t accept; }; +struct CGPartyRemove { uint8_t header; uint32_t pid; }; +struct CGPartySetState { uint8_t header; uint32_t pid; uint8_t role; uint8_t flag; }; +struct CGPartyUseSkill { uint8_t header; uint8_t skill_index; uint32_t vid; }; +struct CGPartyParameter { uint8_t header; uint8_t distribute_mode; }; +static_assert(sizeof(CGPartyInvite) == 5 && sizeof(CGPartyInviteAnswer) == 6 && + sizeof(CGPartyRemove) == 5 && sizeof(CGPartySetState) == 7 && + sizeof(CGPartyUseSkill) == 6 && sizeof(CGPartyParameter) == 2); + +enum : uint8_t { + GUILD_CG_ADD_MEMBER = 0, + GUILD_CG_REMOVE_MEMBER = 1, + GUILD_CG_CHANGE_GRADE_NAME = 2, + GUILD_CG_CHANGE_GRADE_AUTHORITY = 3, + GUILD_CG_OFFER = 4, + GUILD_CG_POST_COMMENT = 5, + GUILD_CG_DELETE_COMMENT = 6, + GUILD_CG_REFRESH_COMMENT = 7, + GUILD_CG_CHANGE_MEMBER_GRADE = 8, + GUILD_CG_USE_SKILL = 9, + GUILD_CG_CHANGE_MEMBER_GENERAL = 10, + GUILD_CG_GUILD_INVITE_ANSWER = 11, + GUILD_CG_CHARGE_GSP = 12, + GUILD_CG_DEPOSIT_MONEY = 13, + GUILD_CG_WITHDRAW_MONEY = 14, +}; +struct CGGuild { uint8_t header; uint8_t subheader; }; +struct CGAnswerMakeGuild { uint8_t header; char guild_name[GUILD_NAME_MAX_LEN + 1]; }; +struct CGGuildUseSkill { uint32_t vnum; uint32_t target_pid; }; +static_assert(sizeof(CGGuild) == 2 && sizeof(CGAnswerMakeGuild) == 14 && + sizeof(CGGuildUseSkill) == 8); + +struct CGMyShopHead { + uint8_t header; + char sign[SHOP_TAB_NAME_MAX + 1]; + uint8_t count; +}; +// TShopItemTable is defined by the common table header. The fields used by +// the classic server are kept here in wire order; socket/attribute payloads +// are copied by ClassicSession without depending on the fork's wire.h types. +struct CGMyShopItem { + uint32_t vnum; + uint8_t count; + ItemPos pos; + uint32_t price; + uint8_t display_pos; +}; +static_assert(sizeof(CGMyShopItem) == 13); + +struct CGRefine { uint8_t header; uint8_t pos; uint8_t type; }; +static_assert(sizeof(CGRefine) == 3); + +inline constexpr int DS_REFINE_GRID_MAX_NUM = 15; +struct CGDragonSoulRefine { + uint8_t header; + uint8_t subheader; + ItemPos grid[DS_REFINE_GRID_MAX_NUM]; +}; +static_assert(sizeof(CGDragonSoulRefine) == 47); + +// --- GC entity state --- +struct GCCharacterUpdate { // packet_update_char (header 19) + uint8_t header; + uint32_t vid; + uint16_t parts[CHR_EQUIPPART_NUM]; + uint8_t moving_speed; + uint8_t attack_speed; + uint8_t state_flag; + uint32_t affect_flag[2]; + uint32_t guild_id; + int16_t alignment; + uint8_t pk_mode; + uint32_t mount_vnum; +}; +static_assert(sizeof(GCCharacterUpdate) == 1 + 4 + 8 + 1 + 1 + 1 + 8 + 4 + 2 + 1 + 4); // 35 + +struct GCStun { uint8_t header; uint32_t vid; }; // header 13 +struct GCDead { uint8_t header; uint32_t vid; }; // header 14 +static_assert(sizeof(GCStun) == 5 && sizeof(GCDead) == 5); + +struct GCMotion { uint8_t header; uint32_t vid; uint32_t victim_vid; uint16_t motion; }; // 36 +static_assert(sizeof(GCMotion) == 11); + +struct GCCharacterPosition { uint8_t header; uint32_t vid; uint8_t position; }; // header 43 +static_assert(sizeof(GCCharacterPosition) == 6); + +struct GCChangeSpeed { uint8_t header; uint32_t vid; uint16_t moving_speed; }; // header 18 +static_assert(sizeof(GCChangeSpeed) == 7); + +struct GCWalkMode { uint8_t header; uint32_t vid; uint8_t mode; }; // header 111 +static_assert(sizeof(GCWalkMode) == 6); + +struct GCTarget { uint8_t header; uint32_t vid; uint8_t hp_percent; }; // header 63 +static_assert(sizeof(GCTarget) == 6); + +struct GCDamageInfo { uint8_t header; uint32_t vid; uint8_t flag; int32_t damage; }; // header 135 +static_assert(sizeof(GCDamageInfo) == 10); + +struct ItemAttr3 { uint8_t type; int16_t value; }; // TPlayerItemAttribute (pack(1) = 3B) +static_assert(sizeof(ItemAttr3) == 3); + +struct GCAttack { uint8_t header; uint32_t vid; uint32_t victim_vid; uint8_t type; }; +struct GCItemUse { uint8_t header; ItemPos cell; uint32_t ch_vid; uint32_t victim_vid; uint32_t vnum; }; +struct GCItemOwnership { uint8_t header; uint32_t vid; char owner[CHARACTER_NAME_MAX_LEN + 1]; }; +struct GCOwnership { uint8_t header; uint32_t owner_vid; uint32_t victim_vid; }; +struct GCMount { + uint8_t header; + uint32_t vid; + uint32_t mount_vnum; + uint8_t pos; + int32_t x, y; +}; +struct GCCreateFly { uint8_t header; uint8_t type; uint32_t start_vid; uint32_t end_vid; }; +struct GCFlyTargeting { + uint8_t header; + uint32_t shooter_vid; + uint32_t target_vid; + int32_t x, y; +}; +struct GCPvp { uint8_t header; uint32_t src_vid; uint32_t dst_vid; uint8_t mode; }; +struct GCDuelStart { uint8_t header; uint16_t size; }; +struct GCShopSign { uint8_t header; uint32_t vid; char sign[SHOP_SIGN_MAX_LEN + 1]; }; +struct GCSkillGroup { uint8_t header; uint8_t skill_group; }; +struct GCSpecialEffect { uint8_t header; uint8_t type; uint32_t vid; }; +struct GCSpecificEffect { uint8_t header; uint32_t vid; char effect_file[128]; }; +struct GCSkillLevelOld { uint8_t header; uint8_t levels[SKILL_MAX_NUM]; }; +struct GCSkillCooltimeEnd { uint8_t header; uint8_t skill; }; +struct GCFishing { uint8_t header; uint8_t subheader; uint32_t info; uint8_t dir; }; +struct GCObserverAdd { uint8_t header; uint32_t vid; uint16_t x, y; }; +struct GCObserverMove { uint8_t header; uint32_t vid; uint16_t x, y; }; +struct GCObserverRemove { uint8_t header; uint32_t vid; }; +// TPacketGCWarp in the 40250 server/client packet.h is a packed static packet +// with no dynamic length field (BYTE + LONG x 3 + WORD). +struct GCWarpClassic { uint8_t header; int32_t x, y, addr; uint16_t port; }; +static_assert(sizeof(GCWarpClassic) == 15); +struct GCTime { uint8_t header; int32_t time; }; +struct GCChannel { uint8_t header; uint8_t channel; }; +struct GCDungeonHead { uint8_t subheader; }; +struct GCDungeonDestination { int32_t x, y; }; +struct GCNPCPositionHead { uint16_t count; }; +struct NPCPosition34 { + uint8_t type; + char name[CHARACTER_NAME_MAX_LEN + 1]; + int32_t x, y; +}; +struct LandPacketElement24 { + uint32_t id; + int32_t x, y; + int32_t width, height; + uint32_t guild_id; +}; +struct GCTargetCreate43 { + uint8_t header; + int32_t id; + char name[32 + 1]; + uint32_t vid; + uint8_t type; +}; +struct GCTargetUpdate13 { uint8_t header; int32_t id; int32_t x, y; }; +struct GCTargetDelete5 { uint8_t header; int32_t id; }; +struct GCLoverInfo { uint8_t header; char name[CHARACTER_NAME_MAX_LEN + 1]; uint8_t love_point; }; +struct GCLovePointUpdate { uint8_t header; uint8_t love_point; }; +struct GCDigMotion { uint8_t header; uint32_t vid; uint32_t target_vid; uint8_t count; }; +struct EquipmentItem38 { + uint32_t vnum; + uint8_t count; + int32_t sockets[ITEM_SOCKET_MAX_NUM]; + ItemAttr3 attrs[ITEM_ATTRIBUTE_MAX_NUM]; +}; +inline constexpr int CLASSIC_WEAR_MAX_NUM = 32; // server common/length.h +struct GCViewEquip { + uint8_t header; + uint32_t vid; + EquipmentItem38 equips[CLASSIC_WEAR_MAX_NUM]; +}; +struct GCChangeName { uint8_t header; uint32_t pid; char name[CHARACTER_NAME_MAX_LEN + 1]; }; +struct GCRefineMaterial { uint32_t vnum; int32_t count; }; +struct GCRefineInfo { + uint8_t header; + uint8_t type; + uint8_t pos; + uint32_t src_vnum; + uint32_t result_vnum; + uint8_t material_count; + int32_t cost; + int32_t prob; + GCRefineMaterial materials[5]; +}; +struct GCDragonSoulRefine { + uint8_t header; + uint8_t sub_type; + ItemPos pos; +}; +static_assert(sizeof(GCAttack) == 10 && sizeof(GCItemUse) == 16 && + sizeof(GCItemOwnership) == 30 && sizeof(GCOwnership) == 9 && sizeof(GCMount) == 18 && + sizeof(GCCreateFly) == 10 && sizeof(GCFlyTargeting) == 17 && + sizeof(GCPvp) == 10 && sizeof(GCDuelStart) == 3 && sizeof(GCShopSign) == 38 && + sizeof(GCSkillGroup) == 2 && sizeof(GCSpecialEffect) == 6 && sizeof(GCSpecificEffect) == 133 && + sizeof(GCSkillLevelOld) == 256 && sizeof(GCSkillCooltimeEnd) == 2 && + sizeof(GCFishing) == 7 && + sizeof(GCObserverAdd) == 9 && sizeof(GCObserverMove) == 9 && + sizeof(GCObserverRemove) == 5 && sizeof(GCTime) == 5 && sizeof(GCChannel) == 2 && + sizeof(GCDungeonHead) == 1 && sizeof(GCNPCPositionHead) == 2 && + sizeof(NPCPosition34) == 34 && sizeof(LandPacketElement24) == 24 && + sizeof(GCTargetCreate43) == 43 && sizeof(GCTargetUpdate13) == 13 && + sizeof(GCTargetDelete5) == 5 && sizeof(GCLoverInfo) == 27 && + sizeof(GCLovePointUpdate) == 2 && sizeof(GCDigMotion) == 10 && + sizeof(EquipmentItem38) == 38 && sizeof(GCViewEquip) == 1221 && + sizeof(GCChangeName) == 30 && sizeof(GCRefineMaterial) == 8 && + sizeof(GCRefineInfo) == 60 && sizeof(GCDragonSoulRefine) == 5); + +// packet_char_additional_info (header 136) — fills a spawned entity's name/parts/... +struct GCCharAddInfo { + uint8_t header; + uint32_t vid; + char name[CHARACTER_NAME_MAX_LEN + 1]; + uint16_t parts[CHR_EQUIPPART_NUM]; + uint8_t empire; + uint32_t guild_id; + uint32_t level; + int16_t alignment; + uint8_t pk_mode; + uint32_t mount_vnum; +}; +static_assert(sizeof(GCCharAddInfo) == 1 + 4 + 25 + 8 + 1 + 4 + 4 + 2 + 1 + 4); // 54 + +// --- GC skills / quickslots --- +struct PlayerSkill3 { // TPlayerSkill (common/tables.h) — time_t is 32-bit on the -m32 server + uint8_t master_type; + uint8_t level; + uint32_t next_read; +}; +static_assert(sizeof(PlayerSkill3) == 6); + +struct GCSkillLevel { uint8_t header; PlayerSkill3 skills[SKILL_MAX_NUM]; }; // header 76 +static_assert(sizeof(GCSkillLevel) == 1 + 255 * 6); // 1531 + +struct QuickSlot2 { uint8_t type; uint8_t position; }; // TQuickSlot / TQuickslot +struct GCQuickSlotAdd { uint8_t header; uint8_t pos; QuickSlot2 slot; }; // header 28 +struct GCQuickSlotDel { uint8_t header; uint8_t pos; }; // header 29 +struct GCQuickSlotSwap { uint8_t header; uint8_t pos; uint8_t pos_to; }; // header 30 +static_assert(sizeof(GCQuickSlotAdd) == 4 && sizeof(GCQuickSlotDel) == 2 && + sizeof(GCQuickSlotSwap) == 3); + +// --- GC affects --- +struct AffectElement { // TPacketAffectElement (client Packet.h L2555) + uint32_t type; + uint8_t point_idx; + int32_t apply_value; + uint32_t flag; + int32_t duration; + int32_t sp_cost; +}; +static_assert(sizeof(AffectElement) == 21); +struct GCAffectAdd { uint8_t header; AffectElement elem; }; // header 126 +struct GCAffectRemove { uint8_t header; uint32_t type; uint8_t apply_on; }; // header 127 +static_assert(sizeof(GCAffectAdd) == 22 && sizeof(GCAffectRemove) == 6); + +// --- GC dynamic: whisper / sync-position --- +struct GCWhisperHead { // packet_whisper (header 34) — + text + uint8_t header; + uint16_t size; + uint8_t type; + char name_from[CHARACTER_NAME_MAX_LEN + 1]; +}; +static_assert(sizeof(GCWhisperHead) == 1 + 2 + 1 + 25); // 29 + +struct SyncPosElement { uint32_t vid; int32_t x, y; }; +static_assert(sizeof(SyncPosElement) == 12); + +// --- GC quest / script --- +struct GCScriptHead { uint8_t header; uint16_t size; uint8_t skin; uint16_t src_size; }; // 45 dyn +static_assert(sizeof(GCScriptHead) == 6); +struct GCQuestConfirm { // packet_quest_confirm (header 46, STATIC) + uint8_t header; + char msg[64 + 1]; + int32_t timeout; + uint32_t request_pid; +}; +static_assert(sizeof(GCQuestConfirm) == 1 + 65 + 4 + 4); // 74 +// GC_QUEST_INFO (81, dynamic): after [header][u16 size] -> [u16 index][u8 flag][flag-driven...] +enum : uint8_t { + QUEST_SEND_IS_BEGIN = 1 << 0, + QUEST_SEND_TITLE = 1 << 1, + QUEST_SEND_CLOCK_NAME = 1 << 2, + QUEST_SEND_CLOCK_VALUE = 1 << 3, + QUEST_SEND_COUNTER_NAME = 1 << 4, + QUEST_SEND_COUNTER_VALUE = 1 << 5, + QUEST_SEND_ICON_FILE = 1 << 6, +}; + +// --- GC party --- +inline constexpr int PARTY_AFFECT_SLOT_MAX_NUM = 7; +struct GCPartyInvite { uint8_t header; uint32_t leader_vid; }; // header 77 +struct GCPartyAdd { uint8_t header; uint32_t pid; char name[CHARACTER_NAME_MAX_LEN + 1]; }; // 78 +struct GCPartyUpdate { // header 79 + uint8_t header; + uint32_t pid; + uint8_t role; + uint8_t percent_hp; + int16_t affects[PARTY_AFFECT_SLOT_MAX_NUM]; +}; +struct GCPartyRemove { uint8_t header; uint32_t pid; }; // header 80 +struct GCPartyLink { uint8_t header; uint32_t pid; uint32_t vid; }; // header 91 +struct GCPartyUnlink { uint8_t header; uint32_t pid; uint32_t vid; }; // header 92 +struct GCPartyParameter { uint8_t header; uint8_t distribute_mode; }; // header 83 +static_assert(sizeof(GCPartyInvite) == 5 && sizeof(GCPartyAdd) == 30 && + sizeof(GCPartyUpdate) == 21 && sizeof(GCPartyRemove) == 5 && sizeof(GCPartyLink) == 9 && + sizeof(GCPartyParameter) == 2); + +// --- GC items --- +enum : uint8_t { + EXCHANGE_GC_START = 0, + EXCHANGE_GC_ITEM_ADD = 1, + EXCHANGE_GC_ITEM_DEL = 2, + EXCHANGE_GC_GOLD_ADD = 3, + EXCHANGE_GC_ACCEPT = 4, + EXCHANGE_GC_END = 5, + EXCHANGE_GC_ALREADY = 6, + EXCHANGE_GC_LESS_GOLD = 7, + + MESSENGER_GC_LIST = 0, + MESSENGER_GC_LOGIN = 1, + MESSENGER_GC_LOGOUT = 2, + MESSENGER_GC_INVITE = 3, + MESSENGER_GC_MOBILE = 4, +}; + +struct GCExchange { + uint8_t header; + uint8_t subheader; + uint8_t is_me; + uint32_t arg1; + ItemPos arg2; + uint32_t arg3; + int32_t sockets[ITEM_SOCKET_MAX_NUM]; + ItemAttr3 attrs[ITEM_ATTRIBUTE_MAX_NUM]; +}; +static_assert(sizeof(GCExchange) == 47); + +struct GCItemSet { // packet_item_set (server packet.h:1134, header 21) + uint8_t header; + ItemPos cell; + uint32_t vnum; + uint8_t count; + uint32_t flags; + uint32_t anti_flags; + uint8_t highlight; // bool on the wire + int32_t sockets[ITEM_SOCKET_MAX_NUM]; + ItemAttr3 attrs[ITEM_ATTRIBUTE_MAX_NUM]; +}; +static_assert(sizeof(GCItemSet) == 1 + 3 + 4 + 1 + 4 + 4 + 1 + 12 + 21); // 51 + +struct GCItemDel { uint8_t header; uint8_t pos; }; // header 20 — inventory pos only +static_assert(sizeof(GCItemDel) == 2); + +// GC_MESSENGER is dynamic: after [header][u16 size], body starts with the +// subheader and then the subheader-specific records below. +struct GCMessengerHead { uint8_t header; uint16_t size; uint8_t subheader; }; +struct MessengerListEntry { uint8_t connected; uint8_t length; }; +struct MessengerNameLength { uint8_t length; }; +static_assert(sizeof(GCMessengerHead) == 4 && sizeof(MessengerListEntry) == 2 && + sizeof(MessengerNameLength) == 1); + +struct GCSafeboxSize { uint8_t header; uint8_t size; }; +struct GCSafeboxMoneyChange { uint8_t header; int32_t money; }; +struct GCMallOpen { uint8_t header; uint8_t size; }; +static_assert(sizeof(GCSafeboxSize) == 2 && sizeof(GCSafeboxMoneyChange) == 5 && + sizeof(GCMallOpen) == 2); + +struct GCItemUpdate { // packet_item_update (header 25) + uint8_t header; + ItemPos cell; + uint8_t count; + int32_t sockets[ITEM_SOCKET_MAX_NUM]; + ItemAttr3 attrs[ITEM_ATTRIBUTE_MAX_NUM]; +}; +static_assert(sizeof(GCItemUpdate) == 1 + 3 + 1 + 12 + 21); // 38 + +struct GCItemGroundAdd { // packet_item_ground_add (header 26) + uint8_t header; + int32_t x, y, z; + uint32_t vid; + uint32_t vnum; +}; +static_assert(sizeof(GCItemGroundAdd) == 1 + 12 + 4 + 4); // 21 + +struct GCItemGroundDel { uint8_t header; uint32_t vid; }; // header 27 +static_assert(sizeof(GCItemGroundDel) == 5); + +// --- GC shop (dynamic, sub-header after [header][u16 size]) --- +struct ShopItem43 { // packet_shop_item + uint32_t vnum; + uint32_t price; + uint8_t count; + uint8_t display_pos; + int32_t sockets[ITEM_SOCKET_MAX_NUM]; + ItemAttr3 attrs[ITEM_ATTRIBUTE_MAX_NUM]; +}; +static_assert(sizeof(ShopItem43) == 4 + 4 + 1 + 1 + 12 + 21); // 43 +struct ShopTabHead32 { char name[SHOP_TAB_NAME_MAX]; uint8_t coin_type; }; +static_assert(sizeof(ShopTabHead32) == 33); +struct ShopUpdateItem { uint8_t pos; ShopItem43 item; }; +struct ShopUpdatePrice { int32_t price; }; +static_assert(sizeof(ShopUpdateItem) == 44 && sizeof(ShopUpdatePrice) == 4); + +// --- GC guild (dynamic, [header][u16 size][subheader]...) --- +struct GuildMember38 { + uint32_t pid; + uint8_t grade; + uint8_t is_general; + uint8_t job; + uint8_t level; + uint32_t offer; + uint8_t name_flag; + char name[CHARACTER_NAME_MAX_LEN + 1]; +}; +struct GuildInfo35 { + uint16_t member_count; + uint16_t max_member_count; + uint32_t guild_id; + uint32_t master_pid; + uint32_t exp; + uint8_t level; + char name[GUILD_NAME_MAX_LEN + 1]; + uint32_t gold; + uint8_t has_land; +}; +struct GuildGrade10 { char name[GUILD_GRADE_NAME_MAX_LEN + 1]; uint8_t auth; }; +struct GuildWar10 { uint32_t self_id; uint32_t opponent_id; uint8_t type; uint8_t state; }; +struct GuildWarPoint12 { uint32_t gain_guild_id; uint32_t opponent_guild_id; int32_t point; }; +struct GuildWarPair8 { uint32_t src; uint32_t dst; }; +struct GuildName16 { uint32_t id; char name[GUILD_NAME_MAX_LEN]; }; +struct GuildSkill17 { + uint8_t skill_point; + uint8_t levels[GUILD_SKILL_MAX_NUM]; + uint16_t guild_point; + uint16_t max_guild_point; +}; +struct GuildComment80 { + uint32_t id; + char name[CHARACTER_NAME_MAX_LEN + 1]; + char content[GUILD_COMMENT_MAX_LEN + 1]; +}; +struct GuildInvite17 { + uint32_t guild_id; + char guild_name[GUILD_NAME_MAX_LEN + 1]; +}; +static_assert(sizeof(GuildMember38) == 38 && sizeof(GuildInfo35) == 35 && + sizeof(GuildGrade10) == 10 && sizeof(GuildWar10) == 10 && + sizeof(GuildWarPoint12) == 12 && sizeof(GuildWarPair8) == 8 && + sizeof(GuildName16) == 16 && sizeof(GuildSkill17) == 17 && + sizeof(GuildComment80) == 80 && sizeof(GuildInvite17) == 17); + +// --- chat (dynamic) --- +struct CGChatHead { uint8_t header; uint16_t length; uint8_t type; }; // + char szChat[] +static_assert(sizeof(CGChatHead) == 4); +struct CGWhisper { uint8_t header; uint16_t size; char name_to[CHARACTER_NAME_MAX_LEN + 1]; }; +static_assert(sizeof(CGWhisper) == 28); + +struct GCChatHead { // packet_chatting — + text + uint8_t header; + uint16_t size; + uint8_t type; + uint32_t vid; + uint8_t empire; +}; +static_assert(sizeof(GCChatHead) == 9); + +#pragma pack(pop) + +// ------------------------------------------------------------------ size table +// FULL on-wire size of a static-size packet — the 1-byte header INCLUDED, any +// trailing sequence byte EXCLUDED (add 1 when is_sequence_cg()). Matches +// packet_info.cpp's `CPacketInfo::Set(header, sizeof(TPacketXxx), ...)` (CG) and +// CMainPacketHeaderMap's `sizeof(...)` (GC). Returns 0 for "unknown / dynamic" — +// callers must check is_dynamic_*() first. Grows as classic_parser lands packets. +constexpr int packet_size_cg(uint8_t h) { + switch (h) { + case HDR_HANDSHAKE: return sizeof(Handshake); + case HDR_CG_TIME_SYNC: return sizeof(Handshake); + case HDR_CG_PONG: return 1; + case HDR_CG_TEXT: return sizeof(CGText); + case HDR_KEY_AGREEMENT: return sizeof(KeyAgreement); + case HDR_CG_LOGIN: return sizeof(CGLogin); + case HDR_CG_LOGIN2: return sizeof(CGLogin2); + case HDR_CG_LOGIN3: return sizeof(CGLogin3); + case HDR_CG_CHARACTER_SELECT: return sizeof(CGPlayerSelect); + case HDR_CG_CHARACTER_CREATE: return sizeof(CGPlayerCreate); + case HDR_CG_CHARACTER_DELETE: return sizeof(CGPlayerDelete); + case HDR_CG_CHANGE_NAME: return sizeof(CGChangeName); + case HDR_CG_EMPIRE: return sizeof(CGEmpire); + case HDR_CG_CLIENT_VERSION: + case HDR_CG_CLIENT_VERSION2: return sizeof(CGClientVersion); + case HDR_CG_ENTERGAME: return sizeof(CGEnterGame); + case HDR_CG_MOVE: return sizeof(CGMove); + case HDR_CG_ATTACK: return sizeof(CGAttack); + case HDR_CG_TARGET: return sizeof(CGTarget); + case HDR_CG_ON_CLICK: return sizeof(CGOnClick); + case HDR_CG_CHARACTER_POSITION: return sizeof(CGPosition); + case HDR_CG_SCRIPT_ANSWER: return sizeof(CGScriptAnswer); + case HDR_CG_SCRIPT_BUTTON: return sizeof(CGScriptButton); + case HDR_CG_SCRIPT_SELECT_ITEM: return sizeof(CGScriptSelectItem); + case HDR_CG_QUEST_INPUT_STRING: return sizeof(CGQuestInput); + case HDR_CG_QUEST_CONFIRM: return sizeof(CGQuestConfirm); + case HDR_CG_ITEM_USE: return sizeof(CGItemUse); + case HDR_CG_ITEM_MOVE: return sizeof(CGItemMove); + case HDR_CG_ITEM_DROP: return sizeof(CGItemDrop); + case HDR_CG_ITEM_DROP2: return sizeof(CGItemDrop2); + case HDR_CG_ITEM_PICKUP: return sizeof(CGItemPickup); + case HDR_CG_ITEM_USE_TO_ITEM: return sizeof(CGItemUseToItem); + case HDR_CG_ITEM_GIVE: return sizeof(CGGiveItem); + case HDR_CG_QUICKSLOT_ADD: return sizeof(CGQuickSlotAdd); + case HDR_CG_QUICKSLOT_DEL: return sizeof(CGQuickSlotDel); + case HDR_CG_QUICKSLOT_SWAP: return sizeof(CGQuickSlotSwap); + case HDR_CG_USE_SKILL: return sizeof(CGUseSkill); + case HDR_CG_FLY_TARGETING: return sizeof(CGFlyTargeting); + case HDR_CG_ADD_FLY_TARGETING: return sizeof(CGFlyTargeting); + case HDR_CG_SHOOT: return sizeof(CGShoot); + case HDR_CG_WARP: return sizeof(CGWarp); + case HDR_CG_FISHING: return sizeof(CGFishing); + case HDR_CG_SYNC_POSITION: return sizeof(DynHead); + case HDR_CG_WHISPER: return sizeof(CGWhisper); + case HDR_CG_PARTY_INVITE: return sizeof(CGPartyInvite); + case HDR_CG_PARTY_INVITE_ANSWER: return sizeof(CGPartyInviteAnswer); + case HDR_CG_PARTY_REMOVE: return sizeof(CGPartyRemove); + case HDR_CG_PARTY_SET_STATE: return sizeof(CGPartySetState); + case HDR_CG_PARTY_USE_SKILL: return sizeof(CGPartyUseSkill); + case HDR_CG_PARTY_PARAMETER: return sizeof(CGPartyParameter); + case HDR_CG_GUILD: return sizeof(CGGuild); + case HDR_CG_ANSWER_MAKE_GUILD: return sizeof(CGAnswerMakeGuild); + case HDR_CG_MYSHOP: return sizeof(CGMyShopHead); + case HDR_CG_REFINE: return sizeof(CGRefine); + case HDR_CG_DRAGON_SOUL_REFINE: return sizeof(CGDragonSoulRefine); + case HDR_CG_SHOP: return sizeof(CGShop); + case HDR_CG_EXCHANGE: return sizeof(CGExchange); + case HDR_CG_MESSENGER: return sizeof(CGMessenger); + case HDR_CG_MALL_CHECKOUT: return sizeof(CGMallCheckout); + case HDR_CG_SAFEBOX_CHECKIN: return sizeof(CGSafeboxCheckin); + case HDR_CG_SAFEBOX_CHECKOUT: return sizeof(CGSafeboxCheckout); + case HDR_CG_SAFEBOX_ITEM_MOVE: return sizeof(CGItemMove); + case HDR_CG_STATE_CHECKER: return 1; + default: return 0; + } +} + +constexpr int packet_size_gc(uint8_t h) { + switch (h) { + case HDR_HANDSHAKE: return sizeof(Handshake); + case HDR_GC_TIME_SYNC: return sizeof(Blank); + case HDR_GC_PHASE: return sizeof(Phase_); + case HDR_GC_BINDUDP: return sizeof(BindUDP); + case HDR_GC_PING: return sizeof(Blank); + case HDR_KEY_AGREEMENT: return sizeof(KeyAgreement); + case HDR_GC_KEY_AGREEMENT_COMPLETED: return sizeof(KeyAgreementCompleted); + case HDR_GC_LOGIN_SUCCESS: return sizeof(GCLoginSuccess3); + case HDR_GC_LOGIN_SUCCESS_NEWSLOT: return sizeof(GCLoginSuccess); + case HDR_GC_LOGIN_FAILURE: return sizeof(GCLoginFailure); + case HDR_GC_AUTH_SUCCESS: return sizeof(GCAuthSuccess); + case HDR_GC_AUTH_SUCCESS_OPENID: return sizeof(GCAuthSuccessOpenID); + case HDR_GC_MATRIX_CARD: return sizeof(GCMatrixCard); + case HDR_GC_RUNUP_MATRIX_QUIZ: return sizeof(GCRunupMatrixQuiz); + case HDR_GC_REQUEST_PASSPOD: return sizeof(GCRequestPasspod); + case HDR_GC_REQUEST_PASSPOD_FAILED: return sizeof(GCPasspodFailed); + case HDR_GC_HS_REQUEST: return sizeof(GCHSRequest); + case HDR_GC_XTRAP_CS1_REQUEST: return sizeof(GCXTrapRequest); + case HDR_GC_PANAMA_PACK: return sizeof(GCPanamaPack); + case HDR_GC_EMPIRE: return sizeof(GCEmpire); + case HDR_GC_LOGIN_KEY: return sizeof(GCLoginKey); + case HDR_GC_CHARACTER_CREATE_SUCCESS: return sizeof(GCPlayerCreateSuccess); + case HDR_GC_CREATE_FAILURE: return sizeof(GCPlayerCreateFailure); + case HDR_GC_DELETE_SUCCESS: return sizeof(GCPlayerDeleteSuccess); + case HDR_GC_DELETE_WRONG_SOCIAL_ID: return sizeof(Blank); + case HDR_GC_MAIN_CHARACTER: return sizeof(GCMainCharacter); + case HDR_GC_MAIN_CHARACTER3_BGM: return sizeof(GCMainCharacter3BGM); + case HDR_GC_MAIN_CHARACTER4_BGM_VOL: return sizeof(GCMainCharacter4BGM); + case HDR_GC_CHARACTER_ADD: return sizeof(GCCharacterAdd); + case HDR_GC_CHARACTER_ADD2: return sizeof(GCCharacterAdd2); + case HDR_GC_CHARACTER_UPDATE_NEW: return sizeof(GCCharacterUpdate); + case HDR_GC_CHARACTER_UPDATE2: return sizeof(GCCharacterUpdate); + case HDR_GC_CHARACTER_DEL: return sizeof(GCCharacterDel); + case HDR_GC_CHANGE_NAME: return sizeof(GCChangeNameNotice); + case HDR_GC_ATTACK: return sizeof(GCAttack); + case HDR_GC_MOVE: return sizeof(GCMove); + case HDR_GC_CHARACTER_POINTS: return sizeof(GCPoints); + case HDR_GC_CHARACTER_POINT_CHANGE: return sizeof(GCPointChange); + case HDR_GC_ITEM_SET: return sizeof(GCItemSet); + case HDR_GC_ITEM_DEL: return sizeof(GCItemDel); + case HDR_GC_ITEM_USE: return sizeof(GCItemUse); + case HDR_GC_ITEM_UPDATE: return sizeof(GCItemUpdate); + case HDR_GC_ITEM_GROUND_ADD: return sizeof(GCItemGroundAdd); + case HDR_GC_ITEM_GROUND_DEL: return sizeof(GCItemGroundDel); + case HDR_GC_ITEM_OWNERSHIP: return sizeof(GCItemOwnership); + case HDR_GC_OWNERSHIP: return sizeof(GCOwnership); + case HDR_GC_CHARACTER_UPDATE: return sizeof(GCCharacterUpdate); + case HDR_GC_STUN: return sizeof(GCStun); + case HDR_GC_DEAD: return sizeof(GCDead); + case HDR_GC_MOTION: return sizeof(GCMotion); + case HDR_GC_CHARACTER_POSITION: return sizeof(GCCharacterPosition); + case HDR_GC_CHANGE_SPEED: return sizeof(GCChangeSpeed); + case HDR_GC_WALK_MODE: return sizeof(GCWalkMode); + case HDR_GC_TARGET: return sizeof(GCTarget); + case HDR_GC_DAMAGE_INFO: return sizeof(GCDamageInfo); + case HDR_GC_CHAR_ADDITIONAL_INFO: return sizeof(GCCharAddInfo); + case HDR_GC_SKILL_LEVEL: return sizeof(GCSkillLevel); + case HDR_GC_SKILL_COOLTIME_END: return sizeof(GCSkillCooltimeEnd); + case HDR_GC_QUICKSLOT_ADD: return sizeof(GCQuickSlotAdd); + case HDR_GC_QUICKSLOT_DEL: return sizeof(GCQuickSlotDel); + case HDR_GC_QUICKSLOT_SWAP: return sizeof(GCQuickSlotSwap); + case HDR_GC_AFFECT_ADD: return sizeof(GCAffectAdd); + case HDR_GC_AFFECT_REMOVE: return sizeof(GCAffectRemove); + case HDR_GC_EXCHANGE: return sizeof(GCExchange); + case HDR_GC_PVP: return sizeof(GCPvp); + case HDR_GC_MOUNT: return sizeof(GCMount); + case HDR_GC_CREATE_FLY: return sizeof(GCCreateFly); + case HDR_GC_FLY_TARGETING: return sizeof(GCFlyTargeting); + case HDR_GC_ADD_FLY_TARGETING: return sizeof(GCFlyTargeting); + case HDR_GC_SHOP_SIGN: return sizeof(GCShopSign); + case HDR_GC_SKILL_LEVEL_OLD: return sizeof(GCSkillLevelOld); + case HDR_GC_SKILL_GROUP: return sizeof(GCSkillGroup); + case HDR_GC_SPECIAL_EFFECT: return sizeof(GCSpecialEffect); + case HDR_GC_SPECIFIC_EFFECT: return sizeof(GCSpecificEffect); + case HDR_GC_OBSERVER_ADD: return sizeof(GCObserverAdd); + case HDR_GC_OBSERVER_REMOVE: return sizeof(GCObserverRemove); + case HDR_GC_OBSERVER_MOVE: return sizeof(GCObserverMove); + case HDR_GC_PARTY_INVITE: return sizeof(GCPartyInvite); + case HDR_GC_PARTY_ADD: return sizeof(GCPartyAdd); + case HDR_GC_PARTY_UPDATE: return sizeof(GCPartyUpdate); + case HDR_GC_PARTY_REMOVE: return sizeof(GCPartyRemove); + case HDR_GC_PARTY_LINK: return sizeof(GCPartyLink); + case HDR_GC_PARTY_UNLINK: return sizeof(GCPartyUnlink); + case HDR_GC_PARTY_PARAMETER: return sizeof(GCPartyParameter); + case HDR_GC_SAFEBOX_MONEY_CHANGE: return sizeof(GCSafeboxMoneyChange); + case HDR_GC_SAFEBOX_SET: return sizeof(GCItemSet); + case HDR_GC_SAFEBOX_DEL: return sizeof(GCItemDel); + case HDR_GC_SAFEBOX_WRONG_PASSWORD: return sizeof(Blank); + case HDR_GC_SAFEBOX_SIZE: return sizeof(GCSafeboxSize); + case HDR_GC_FISHING: return sizeof(GCFishing); + case HDR_GC_REQUEST_MAKE_GUILD: return sizeof(Blank); + case HDR_GC_MALL_OPEN: return sizeof(GCMallOpen); + case HDR_GC_MALL_SET: return sizeof(GCItemSet); + case HDR_GC_MALL_DEL: return sizeof(GCItemDel); + case HDR_GC_TIME: return sizeof(GCTime); + case HDR_GC_CHANNEL: return sizeof(GCChannel); + case HDR_GC_WARP: return sizeof(GCWarpClassic); + case HDR_GC_TARGET_UPDATE: return sizeof(GCTargetUpdate13); + case HDR_GC_TARGET_DELETE: return sizeof(GCTargetDelete5); + case HDR_GC_TARGET_CREATE: return sizeof(GCTargetCreate43); + case HDR_GC_LOVER_INFO: return sizeof(GCLoverInfo); + case HDR_GC_LOVE_POINT_UPDATE: return sizeof(GCLovePointUpdate); + case HDR_GC_DIG_MOTION: return sizeof(GCDigMotion); + case HDR_GC_VIEW_EQUIP: return sizeof(GCViewEquip); + case HDR_GC_REFINE_INFORMATION_OLD: + case HDR_GC_REFINE_INFORMATION: return sizeof(GCRefineInfo); + case HDR_GC_DRAGON_SOUL_REFINE: return sizeof(GCDragonSoulRefine); + case HDR_GC_QUEST_CONFIRM: return sizeof(GCQuestConfirm); + default: return 0; + } +} + +// docs §2.2: CG packets flagged bSeq=true carry a trailing sequence byte once +// sequence mode is enabled. bSeq=false set: TEXT, HANDSHAKE, MARK_*, KEY_AGREEMENT, +// GUILD_SYMBOL_UPLOAD, SYMBOL_CRC, DRAGON_SOUL_REFINE, STATE_CHECKER. +constexpr bool is_sequence_cg(uint8_t h) { + switch (h) { + case HDR_CG_TEXT: + case HDR_HANDSHAKE: + case HDR_CG_MARK_LOGIN: + case HDR_CG_MARK_IDXLIST: + case HDR_CG_MARK_CRCLIST: + case HDR_CG_MARK_UPLOAD: + case HDR_KEY_AGREEMENT: + case HDR_CG_GUILD_SYMBOL_UPLOAD: + case HDR_CG_SYMBOL_CRC: + case HDR_CG_DRAGON_SOUL_REFINE: + case HDR_CG_STATE_CHECKER: + return false; + default: + return true; // every other registered CG packet + } +} + +// docs §2.2: client CMainPacketHeaderMap DYNAMIC_SIZE_PACKET set (GC) + the two +// CG packets whose struct carries its own length word. +constexpr bool is_dynamic_gc(uint8_t h) { + switch (h) { + case HDR_GC_CHAT: + case HDR_GC_SCRIPT: + case HDR_GC_SHOP: + case HDR_GC_GUILD: + case HDR_GC_MESSENGER: + case HDR_GC_QUEST_INFO: + case HDR_GC_DUEL_START: + case HDR_GC_SYNC_POSITION: + // client CMainPacketHeaderMap registers GC_WHISPER STATIC, but its + // `packet_whisper.wSize` sits exactly where TDynamicSizePacketHeader.size + // does, so the dynamic path frames it correctly (the handler reads the + // text tail itself anyway). + case HDR_GC_WHISPER: + case HDR_GC_DUNGEON: + case HDR_GC_NPC_POSITION: + case HDR_GC_LAND_LIST: + case HDR_GC_SYMBOL_DATA: + case HDR_GC_HYBRIDCRYPT_KEYS: + case HDR_GC_HYBRIDCRYPT_SDB: + return true; + default: + return false; + } +} +constexpr bool is_dynamic_cg(uint8_t h) { return h == HDR_CG_CHAT || h == HDR_CG_WHISPER; } + +} // namespace mtnet::classic diff --git a/extension/src/net/entity_store.cpp b/extension/src/net/entity_store.cpp index c8615ae8..39d926f6 100644 --- a/extension/src/net/entity_store.cpp +++ b/extension/src/net/entity_store.cpp @@ -5,6 +5,32 @@ namespace mtnet { +namespace { + +// CRaceMotionData::EName values from the 40250 client. These are kept here +// instead of inventing a second protocol enum: GC_MOTION and ServerCommand +// both ultimately feed CInstanceBase::PushOnceMotion/ActEmotion. +constexpr uint16_t MOTION_CLAP = 305; +constexpr uint16_t MOTION_CHEERS_1 = 306; +constexpr uint16_t MOTION_CHEERS_2 = 307; +constexpr uint16_t MOTION_KISS_START = 308; +constexpr uint16_t MOTION_FRENCH_KISS_START = 312; +constexpr uint16_t MOTION_SLAP_HIT_START = 316; +constexpr uint16_t MOTION_SLAP_HURT_START = 320; +constexpr uint16_t MOTION_DIG = 324; +constexpr uint16_t MOTION_DANCE_1 = 325; +constexpr uint16_t MOTION_CONGRATULATION = 341; +constexpr uint16_t MOTION_FORGIVE = 342; +constexpr uint16_t MOTION_ANGRY = 343; +constexpr uint16_t MOTION_ATTRACTIVE = 344; +constexpr uint16_t MOTION_SAD = 345; +constexpr uint16_t MOTION_SHY = 346; +constexpr uint16_t MOTION_CHEERUP = 347; +constexpr uint16_t MOTION_BANTER = 348; +constexpr uint16_t MOTION_JOY = 349; + +} // namespace + Entity &EntityStore::touch(uint32_t vid, bool &created) { auto it = m_ents.find(vid); created = (it == m_ents.end()); @@ -44,6 +70,1110 @@ void EntityStore::start_move(Entity &e, float tx, float ty, uint32_t start_ms, u } } +// --- protocol-neutral mutation API (m2dev apply() + classic parser share it) --- + +void EntityStore::mut_spawn(uint32_t vid, uint16_t race, uint8_t ch_type, const std::string &name, + float x, float y, float z, float angle, uint16_t moving_speed, uint8_t attack_speed) { + bool created; + Entity &e = touch(vid, created); + e.race = race; + e.ch_type = ch_type; + if (!name.empty()) { + e.name = name; + } + e.x = x; + e.y = y; + e.z = z; + e.angle = angle; + e.moving_speed = moving_speed; + e.attack_speed = attack_speed; + e.moving = false; + m_changes.push_back({ChangeKind::Spawn, vid}); +} + +void EntityStore::mut_spawn_main(uint32_t vid, uint16_t race, const std::string &name, float x, + float y, float z) { + bool created; + Entity &e = touch(vid, created); + e.race = race; + if (!name.empty()) { + e.name = name; + } + e.x = x; + e.y = y; + e.z = z; + e.is_main = true; + e.moving = false; + m_main_vid = vid; + m_changes.push_back({created ? ChangeKind::Spawn : ChangeKind::MainSet, vid}); + if (!created) { + m_changes.push_back({ChangeKind::MainSet, vid}); + } +} + +void EntityStore::mut_despawn(uint32_t vid) { + if (m_ents.erase(vid)) { + m_changes.push_back({ChangeKind::Despawn, vid}); + } + if (vid == m_main_vid) { + m_main_vid = 0; + } +} + +void EntityStore::mut_move(uint32_t vid, float angle_deg, uint8_t func, float tx, float ty, + uint32_t dur_ms) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + Entity &e = it->second; + e.angle = angle_deg; + start_move(e, tx, ty, m_now, dur_ms, func); + m_changes.push_back({ChangeKind::Move, vid}); +} + +void EntityStore::mut_set_points(const int32_t *pts, int n) { + if (n > 256) { + n = 256; + } + std::memcpy(m_points.v, pts, sizeof(int32_t) * (size_t)n); + m_current_stamina = (uint32_t)std::max(0, m_points.stamina()); + m_stamina_current_f = (float)m_current_stamina; + m_points_dirty = true; + if (m_main_vid) { + auto it = m_ents.find(m_main_vid); + if (it != m_ents.end()) { + Entity &e = it->second; + e.hp = m_points.hp(); + e.max_hp = m_points.max_hp(); + e.sp = m_points.sp(); + e.max_sp = m_points.max_sp(); + e.level = m_points.level(); + const int32_t atk = m_points.v[POINT_ATT_SPEED]; + e.attack_speed = (uint8_t)(atk > 0 && atk < 256 ? atk : 0); + e.dead = e.dead && e.hp <= 0; + mark_vitals(m_main_vid); + } + } +} + +void EntityStore::mut_set_point(uint8_t type, int32_t value, uint32_t vid) { + if (vid == m_main_vid) { + m_points.v[type] = value; + if (type == POINT_STAMINA) { + m_current_stamina = (uint32_t)std::max(0, value); + m_stamina_current_f = (float)m_current_stamina; + } + m_points_dirty = true; + } + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + Entity &e = it->second; + switch (type) { + case POINT_HP: e.hp = value; break; + case POINT_MAX_HP: e.max_hp = value; break; + case POINT_SP: e.sp = value; break; + case POINT_MAX_SP: e.max_sp = value; break; + case POINT_LEVEL: e.level = value; break; + case POINT_ATT_SPEED: + e.attack_speed = (uint8_t)(value > 0 && value < 256 ? value : 0); + break; + default: return; + } + mark_vitals(vid); +} + +void EntityStore::mut_item_set(uint8_t window, uint16_t cell, uint32_t vnum, uint8_t count, + uint32_t flags, uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs) { + Item *slot = mut_slot(window, cell); + if (!slot) { + return; + } + slot->vnum = vnum; + slot->count = count; + slot->flags = flags; + slot->anti_flags = anti_flags; + for (int i = 0; i < ITEM_SOCKET_SLOT_MAX_NUM; ++i) { + slot->sockets[i] = sockets ? sockets[i] : 0; + } + for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i) { + slot->attrs[i] = attrs ? attrs[i] : ItemAttr{}; + } + m_inv_changes.push_back({window, cell}); +} + +void EntityStore::mut_item_del(uint8_t window, uint16_t cell) { + Item *slot = mut_slot(window, cell); + if (!slot) { + return; + } + *slot = Item{}; + m_inv_changes.push_back({window, cell}); +} + +void EntityStore::mut_item_update(uint8_t window, uint16_t cell, uint8_t count, + const int32_t *sockets, const ItemAttr *attrs) { + Item *slot = mut_slot(window, cell); + if (!slot || slot->empty()) { + return; + } + slot->count = count; + for (int i = 0; i < ITEM_SOCKET_SLOT_MAX_NUM; ++i) { + slot->sockets[i] = sockets ? sockets[i] : 0; + } + for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i) { + slot->attrs[i] = attrs ? attrs[i] : ItemAttr{}; + } + m_inv_changes.push_back({window, cell}); +} + +void EntityStore::mut_ground_add(uint32_t vid, uint32_t vnum, float x, float y, float z) { + GroundItem g; + g.vid = vid; + g.vnum = vnum; + g.x = x; + g.y = y; + g.z = z; + m_ground[vid] = g; + m_ground_changes.push_back({vid, true}); +} + +void EntityStore::mut_ground_del(uint32_t vid) { + if (m_ground.erase(vid)) { + m_ground_changes.push_back({vid, false}); + } +} + +void EntityStore::mut_ground_owner(uint32_t vid, const std::string &owner) { + auto it = m_ground.find(vid); + if (it == m_ground.end()) { + return; + } + it->second.owner = owner; + m_ground_changes.push_back({vid, true}); +} + +void EntityStore::mut_item_used(uint32_t vnum) { + m_item_events.push_back({ItemEvent::Use, vnum, 0, {}}); +} + +void EntityStore::mut_item_picked(uint32_t vnum, uint8_t count, const std::string &from) { + ItemEvent event; + event.kind = ItemEvent::Get; + event.vnum = vnum; + event.count = count; + event.from = from; + m_item_events.push_back(std::move(event)); +} + +void EntityStore::mut_char_update(uint32_t vid, const uint16_t *parts, uint8_t moving_speed, + uint8_t attack_speed, int32_t guild_id, int16_t alignment, uint8_t pk_mode, + uint32_t mount_vnum) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + Entity &e = it->second; + bool changed = false; + if (parts && std::memcmp(e.parts, parts, sizeof(e.parts)) != 0) { + std::memcpy(e.parts, parts, sizeof(e.parts)); + changed = true; + } + if (e.moving_speed != moving_speed || e.attack_speed != attack_speed) { + e.moving_speed = moving_speed; + e.attack_speed = attack_speed; + changed = true; + } + e.guild = guild_id; + e.alignment = alignment; + e.pk_mode = pk_mode; + if (e.mount_vnum != mount_vnum) { + e.mount_vnum = mount_vnum; + m_mount_changes.push_back(vid); + } + if (changed) { + m_changes.push_back({ChangeKind::Info, vid}); + } +} + +void EntityStore::mut_set_position(uint32_t vid, uint8_t position) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + it->second.position = position; + m_changes.push_back({ChangeKind::Info, vid}); +} + +void EntityStore::mut_snap_position(uint32_t vid, float x, float y) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + Entity &e = it->second; + e.x = e.sx = e.tx = x; + e.y = e.sy = e.ty = y; + e.moving = false; + m_changes.push_back({ChangeKind::Move, vid}); +} + +void EntityStore::mut_change_speed(uint32_t vid, uint16_t moving_speed) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + it->second.moving_speed = moving_speed; + m_changes.push_back({ChangeKind::Info, vid}); +} + +void EntityStore::mut_walk_mode(uint32_t vid, uint8_t mode) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + it->second.walk_mode = mode; + m_changes.push_back({ChangeKind::Info, vid}); +} + +void EntityStore::mut_stun(uint32_t vid) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + it->second.stunned = true; + mark_vitals(vid); +} + +void EntityStore::mut_dead(uint32_t vid) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + return; + } + Entity &e = it->second; + e.dead = true; + e.moving = false; + e.func = FUNC_WAIT; + if (e.hp > 0) { + e.hp = 0; + } + mark_vitals(vid); +} + +void EntityStore::mut_motion(uint32_t vid, uint32_t victim_vid, uint16_t motion) { + m_motions.push_back({vid, victim_vid, motion}); +} + +void EntityStore::mut_target(uint32_t vid, uint8_t hp_pct) { + m_target_vid = vid; + m_target_hp_pct = hp_pct; + m_target_dirty = true; +} + +void EntityStore::mut_damage(uint32_t vid, uint8_t flag, int32_t amount) { + m_damage.push_back({vid, flag, amount}); +} + +void EntityStore::mut_mount(uint32_t vid, uint32_t mount_vnum) { + bool created = false; + Entity &e = touch(vid, created); + e.mount_vnum = mount_vnum; + m_mount_changes.push_back(vid); + if (!created) { + m_changes.push_back({ChangeKind::Info, vid}); + } +} + +void EntityStore::mut_fly(uint8_t type, uint32_t start_vid, uint32_t end_vid) { + m_fly_cues.push_back({type, start_vid, end_vid}); +} + +void EntityStore::mut_fly_target(uint32_t shooter_vid, uint32_t target_vid, int32_t x, int32_t y, + bool append) { + m_fly_target_cues.push_back({shooter_vid, target_vid, x, y, append}); +} + +void EntityStore::mut_dig(uint32_t vid, uint32_t target_vid, uint8_t count) { + m_dig_motions.push_back({vid, target_vid, count}); +} + +void EntityStore::mut_special_effect(uint32_t vid, int32_t special) { + EffectCue cue; + cue.vid = vid; + cue.special = special; + m_effect_cues.push_back(std::move(cue)); +} + +void EntityStore::mut_specific_effect(uint32_t vid, const std::string &file) { + EffectCue cue; + cue.vid = vid; + cue.file = file; + m_effect_cues.push_back(std::move(cue)); +} + +void EntityStore::mut_skill_cooldown_end(uint8_t skill) { + m_cooldown_ends.push_back((int)skill); +} + +void EntityStore::mut_pvp(uint32_t src_vid, uint32_t dst_vid, uint8_t mode) { + const uint32_t lo = src_vid < dst_vid ? src_vid : dst_vid; + const uint32_t hi = src_vid < dst_vid ? dst_vid : src_vid; + const uint64_t key = (uint64_t(lo) << 32) | hi; + PvpRelation relation{src_vid, dst_vid, mode}; + if (mode == 0) { + m_pvp.erase(key); + } else { + m_pvp[key] = relation; + } + m_pvp_changes.push_back(relation); +} + +void EntityStore::mut_duel_start() { + mut_duel_start(nullptr, 0); +} + +void EntityStore::mut_duel_start(const uint32_t *opponents, int count) { + m_duel_opponents.clear(); + if (opponents && count > 0) { + m_duel_opponents.assign(opponents, opponents + count); + } + m_duel_cannot_attack = m_duel_opponents.empty(); + m_duel_started = true; +} + +void EntityStore::mut_view_equipment(uint32_t vid, const Item *items, int n) { + if (!items || n < 0) { + return; + } + ViewedEquipment view; + view.vid = vid; + for (int i = 0; i < VIEW_EQUIP_WEAR_MAX_NUM && i < n; ++i) { + view.items[i] = items[i]; + } + m_view_equipment[vid] = view; + m_view_equipment_changes.push_back(vid); +} + +void EntityStore::mut_char_info(uint32_t vid, const std::string &name, const uint16_t *parts, + uint8_t empire, int32_t guild_id, int32_t level, int16_t alignment, uint8_t pk_mode, + uint32_t mount_vnum) { + bool created; + Entity &e = touch(vid, created); + if (!name.empty()) { + e.name = name; + } + if (parts) { + std::memcpy(e.parts, parts, sizeof(e.parts)); + } + e.level = level; + e.guild = guild_id; + e.alignment = alignment; + e.pk_mode = pk_mode; + if (e.mount_vnum != mount_vnum) { + e.mount_vnum = mount_vnum; + m_mount_changes.push_back(vid); + } + (void)empire; + if (!created) { + m_changes.push_back({ChangeKind::Info, vid}); + } +} + +void EntityStore::mut_shop_sign(uint32_t vid, const std::string &sign) { + auto it = m_ents.find(vid); + if (it == m_ents.end()) { + // A non-empty sign can legally race the character-add packet during a + // shop broadcast. Keep it instead of silently dropping the server state; + // the later character-add packet fills in the rest of this entity. + if (sign.empty()) { + return; + } + bool created = false; + Entity &e = touch(vid, created); + e.shop_sign = sign; + m_changes.push_back({ChangeKind::Spawn, vid}); + return; + } + if (it->second.shop_sign == sign) { + return; + } + it->second.shop_sign = sign; + m_changes.push_back({ChangeKind::Info, vid}); +} + +void EntityStore::mut_skill_levels(const uint8_t *level, const uint8_t *master, int n) { + if (n > SKILL_MAX_NUM) { + n = SKILL_MAX_NUM; + } + for (int i = 0; i < n; ++i) { + m_skills[i] = level[i]; + m_skill_master[i] = master ? master[i] : 0; + } + m_skills_dirty = true; +} + +void EntityStore::mut_skill_group(uint8_t group) { + m_skill_group = group; + m_skill_group_dirty = true; +} + +void EntityStore::mut_quickslot_set(uint8_t pos, uint8_t type, uint8_t position) { + if (pos >= QUICKSLOT_MAX_NUM) { + return; + } + m_quickslots[pos] = {type, position}; + m_quickslots_dirty = true; +} + +void EntityStore::mut_quickslot_del(uint8_t pos) { + if (pos >= QUICKSLOT_MAX_NUM) { + return; + } + m_quickslots[pos] = QuickSlot{}; + m_quickslots_dirty = true; +} + +void EntityStore::mut_quickslot_swap(uint8_t pos, uint8_t pos_to) { + if (pos >= QUICKSLOT_MAX_NUM || pos_to >= QUICKSLOT_MAX_NUM) { + return; + } + std::swap(m_quickslots[pos], m_quickslots[pos_to]); + m_quickslots_dirty = true; +} + +void EntityStore::mut_affect_add(uint32_t type, uint8_t point_idx, int32_t value, uint32_t flag, + int32_t duration) { + Affect a; + a.type = type; + a.point_idx = point_idx; + a.value = value; + a.flag = flag; + a.duration = duration; + m_affects[type] = a; + m_affect_changes.push_back({type, true}); +} + +void EntityStore::mut_affect_remove(uint32_t type) { + m_affects.erase(type); + m_affect_changes.push_back({type, false}); +} + +void EntityStore::mut_chat(uint8_t type, uint32_t vid, const std::string &text) { + if (type == CHAT_TYPE_COMMAND) { + apply_server_command(text); + return; + } + ChatMsg m; + m.type = type; + m.vid = vid; + m.text = text; + m_chat.push_back(std::move(m)); +} + +void EntityStore::mut_whisper(uint8_t sub, const std::string &from, const std::string &text) { + ChatMsg m; + m.type = CHAT_TYPE_WHISPER; + m.sub = sub; + m.from = from; + m.text = text; + m_chat.push_back(std::move(m)); +} + +void EntityStore::mut_shop_open(uint32_t vid, const std::vector &tabs) { + m_shop_vid = vid; + m_shop_tabs.clear(); + m_shop_items.clear(); + m_shop_selling_price = 0; + if (tabs.size() == 1 && tabs[0].name.empty()) { + m_shop_items = tabs[0].items; // flat single-shelf shop + } else { + m_shop_tabs = tabs; + if (!m_shop_tabs.empty()) { + m_shop_items = m_shop_tabs[0].items; + } + } + m_shop_open = true; + m_shop_dirty = true; +} + +void EntityStore::mut_shop_update_item(uint8_t pos, uint32_t vnum, uint32_t price, uint8_t count) { + if (!m_shop_open || pos >= SHOP_HOST_ITEM_MAX_NUM) { + return; + } + auto update = [&](std::vector &items) { + for (size_t i = 0; i < items.size(); ++i) { + if (items[i].pos != pos) { + continue; + } + if (vnum == 0) { + items.erase(items.begin() + (long)i); + } else { + items[i] = {vnum, price, count, pos}; + } + return; + } + if (vnum != 0) { + items.push_back({vnum, price, count, pos}); + } + }; + update(m_shop_items); + if (!m_shop_tabs.empty()) { + update(m_shop_tabs[0].items); + } + m_shop_dirty = true; +} + +void EntityStore::mut_shop_update_price(int32_t price) { + m_shop_selling_price = price; + m_shop_dirty = true; +} + +void EntityStore::mut_shop_close() { + m_shop_open = false; + m_shop_vid = 0; + m_shop_items.clear(); + m_shop_tabs.clear(); + m_shop_selling_price = 0; + m_shop_dirty = true; +} + +void EntityStore::mut_shop_error(const std::string &code) { + m_shop_errors.push_back(code); +} + +void EntityStore::mut_script(uint8_t skin, const std::string &text) { + ScriptCue c; + c.skin = skin; + c.text = text; + m_scripts.push_back(std::move(c)); +} + +void EntityStore::mut_quest_confirm(const std::string &msg, int32_t timeout, uint32_t request_pid) { + ConfirmCue c; + c.msg = msg; + c.timeout = timeout; + c.request_pid = request_pid; + m_confirms.push_back(std::move(c)); +} + +void EntityStore::mut_quest_info(uint16_t index, uint8_t flag, bool begin, const std::string &title, + const std::string &clock_name, int32_t clock_value, const std::string &counter_name, + int32_t counter_value, const std::string &icon) { + QuestInfo &q = m_quests[index]; + q.index = index; + q.flag = flag; + q.begin = begin; + if (!title.empty()) { + q.title = title; + } + if (!clock_name.empty()) { + q.clock_name = clock_name; + } + if (flag & (1 << 3)) { + q.clock_value = clock_value; + } + if (!counter_name.empty()) { + q.counter_name = counter_name; + } + if (flag & (1 << 5)) { + q.counter_value = counter_value; + } + if (!icon.empty()) { + q.icon = icon; + } + m_quest_changes.push_back(index); +} + +void EntityStore::mut_warp(int32_t x, int32_t y, int32_t addr, uint16_t port) { + m_warps.push_back({x, y, addr, port}); +} + +void EntityStore::mut_server_time(int64_t time) { + m_server_time = time; + m_time_dirty = true; +} + +void EntityStore::mut_channel(uint8_t channel) { + m_channel = channel; + m_channel_dirty = true; +} + +void EntityStore::mut_npc_marks(const std::vector &marks) { + m_npc_marks = marks; + m_npc_marks_dirty = true; +} + +void EntityStore::mut_land_areas(const std::vector &areas) { + m_land_areas = areas; + m_land_dirty = true; +} + +void EntityStore::mut_marker_create(int32_t id, const std::string &name, uint32_t vid, + uint8_t type) { + WorldMarker &marker = m_markers[id]; + marker.id = id; + marker.name = name; + marker.vid = vid; + marker.type = type; + m_markers_dirty = true; +} + +void EntityStore::mut_marker_update(int32_t id, int32_t x, int32_t y) { + auto it = m_markers.find(id); + if (it != m_markers.end()) { + it->second.x = x; + it->second.y = y; + m_markers_dirty = true; + } +} + +void EntityStore::mut_marker_delete(int32_t id) { + if (m_markers.erase(id) > 0) { + m_markers_dirty = true; + } +} + +void EntityStore::mut_observer(ObserverEvent::Kind kind, uint32_t vid, int32_t x, int32_t y) { + if (kind == ObserverEvent::Remove) { + if (m_observers.erase(vid) > 0) { + m_observer_events.push_back({kind, vid, 0, 0}); + } + return; + } + const bool existed = m_observers.find(vid) != m_observers.end(); + m_observers[vid] = {vid, x, y}; + m_observer_events.push_back({kind == ObserverEvent::Add && !existed + ? ObserverEvent::Add : ObserverEvent::Move, vid, x, y}); +} + +void EntityStore::mut_lover(const std::string &name, uint8_t love_point) { + m_lover.name = name; + m_lover.love_point = love_point; + m_lover.valid = !name.empty(); + m_lover_dirty = true; +} + +void EntityStore::mut_love_point(uint8_t love_point) { + m_lover.love_point = love_point; + m_lover_dirty = true; +} + +void EntityStore::mut_fishing(uint8_t subheader, uint32_t info, uint8_t dir) { + m_fishing_events.push_back({subheader, info, dir}); +} + +void EntityStore::mut_dungeon(uint8_t subheader, int32_t x, int32_t y, bool has_destination) { + m_dungeon_events.push_back({subheader, x, y, has_destination}); +} + +void EntityStore::mut_party_invite(uint32_t leader) { + m_party_invites.push_back(leader); +} + +void EntityStore::mut_party_add(uint32_t pid, const std::string &name) { + PartyMember &m = m_party[pid]; + m.pid = pid; + m.name = name; + m_party_dirty = true; +} + +void EntityStore::mut_party_update(uint32_t pid, uint8_t role, uint8_t hp_pct, + const int16_t *affects) { + auto it = m_party.find(pid); + if (it == m_party.end()) { + return; + } + it->second.state = role; + it->second.hp_pct = hp_pct; + for (int i = 0; i < PARTY_AFFECT_SLOT_MAX_NUM; ++i) { + it->second.affects[i] = affects ? affects[i] : 0; + } + m_party_dirty = true; +} + +void EntityStore::mut_party_remove(uint32_t pid) { + if (m_party.erase(pid)) { + m_party_dirty = true; + } +} + +void EntityStore::mut_party_link(uint32_t pid, uint32_t vid) { + auto it = m_party.find(pid); + if (it != m_party.end()) { + it->second.vid = vid; + m_party_dirty = true; + } +} + +void EntityStore::mut_party_unlink(uint32_t pid) { + auto it = m_party.find(pid); + if (it != m_party.end()) { + it->second.vid = 0; + m_party_dirty = true; + } +} + +void EntityStore::mut_party_parameter(uint8_t distribute_mode) { + m_party_mode = distribute_mode; + m_party_dirty = true; +} + +void EntityStore::mut_friend_set(const std::string &name, bool online) { + if (name.empty()) { + return; + } + Friend &f = m_friends[name]; + f.name = name; + f.online = online; + m_friends_dirty = true; +} + +void EntityStore::mut_friend_mobile(const std::string &name, bool mobile) { + if (name.empty()) { + return; + } + Friend &f = m_friends[name]; + f.name = name; + f.mobile = mobile; + m_friends_dirty = true; +} + +void EntityStore::mut_friend_remove(const std::string &name) { + if (name.empty()) { + return; + } + m_friends.erase(name); + m_friends_dirty = true; +} + +void EntityStore::mut_friend_clear() { + m_friends.clear(); + m_friends_dirty = true; +} + +void EntityStore::mut_friend_invite(const std::string &name) { + if (!name.empty()) { + m_friend_invites.push_back(name); + } +} + +void EntityStore::mut_guild_info(uint16_t member_count, uint16_t max_member_count, uint32_t id, + uint32_t master_pid, uint32_t exp, uint8_t level, const std::string &name, + uint32_t gold, bool has_land) { + m_guild.in_guild = id != 0; + m_guild.id = id; + m_guild.master_pid = master_pid; + m_guild.exp = exp; + m_guild.level = level; + m_guild.name = name; + m_guild.gold = gold; + m_guild.member_count = member_count; + m_guild.max_member_count = max_member_count; + m_guild.has_land = has_land; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_clear_members() { + if (!m_guild_members.empty()) { + m_guild_members.clear(); + } + m_guild_dirty = true; +} + +void EntityStore::mut_guild_member(uint32_t pid, uint8_t grade, bool is_general, uint8_t job, + uint8_t level, uint32_t offer, const std::string &name) { + GuildMember &m = m_guild_members[pid]; + m.pid = pid; + m.grade = grade; + m.is_general = is_general; + m.job = job; + m.level = level; + m.offer = offer; + if (!name.empty()) { + m.name = name; + } + m_guild_dirty = true; +} + +void EntityStore::mut_guild_member_online(uint32_t pid, bool online) { + auto it = m_guild_members.find(pid); + if (it != m_guild_members.end() && it->second.online != online) { + it->second.online = online; + m_guild_dirty = true; + } +} + +void EntityStore::mut_guild_remove_member(uint32_t pid) { + if (m_guild_members.erase(pid)) { + m_guild_dirty = true; + } +} + +void EntityStore::mut_guild_grade(uint8_t grade, const std::string &name, uint8_t auth) { + if (grade >= 16) { + return; + } + m_guild_grades[grade].name = name; + m_guild_grades[grade].auth = auth; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_grade_name(uint8_t grade, const std::string &name) { + if (grade >= 16) { + return; + } + m_guild_grades[grade].name = name; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_grade_auth(uint8_t grade, uint8_t auth) { + if (grade >= 16) { + return; + } + m_guild_grades[grade].auth = auth; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_member_grade(uint32_t pid, uint8_t grade) { + auto it = m_guild_members.find(pid); + if (it != m_guild_members.end()) { + it->second.grade = grade; + m_guild_dirty = true; + } +} + +void EntityStore::mut_guild_member_general(uint32_t pid, bool is_general) { + auto it = m_guild_members.find(pid); + if (it != m_guild_members.end()) { + it->second.is_general = is_general; + m_guild_dirty = true; + } +} + +void EntityStore::mut_guild_exp(uint8_t level, uint32_t exp) { + m_guild.level = level; + m_guild.exp = exp; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_money(uint32_t gold) { + m_guild.gold = gold; + m_guild_dirty = true; +} + +void EntityStore::mut_guild_skill(uint8_t skill_point, const uint8_t *levels, uint16_t guild_point, + uint16_t max_guild_point) { + m_guild_skill.valid = true; + m_guild_skill.skill_point = skill_point; + if (levels) { + std::memcpy(m_guild_skill.levels, levels, GUILD_SKILL_MAX_NUM); + } else { + std::memset(m_guild_skill.levels, 0, GUILD_SKILL_MAX_NUM); + } + m_guild_skill.guild_point = guild_point; + m_guild_skill.max_guild_point = max_guild_point; + m_guild_skill_dirty = true; +} + +void EntityStore::mut_guild_war(uint32_t self_id, uint32_t opponent_id, uint8_t type, + uint8_t state) { + (void)self_id; + m_guild_war.opp_guild_id = opponent_id; + m_guild_war.type = type; + m_guild_war.state = state; + m_guild_war_events.push_back(m_guild_war); + m_guild_war_dirty = true; +} + +void EntityStore::mut_guild_war_pairs(const std::vector &pairs, bool remove) { + for (const auto &pair : pairs) { + if (remove) { + for (size_t i = 0; i < m_guild_wars.size();) { + if (m_guild_wars[i].src == pair.src && m_guild_wars[i].dst == pair.dst) { + m_guild_wars.erase(m_guild_wars.begin() + (long)i); + } else { + ++i; + } + } + } else { + bool found = false; + for (const auto &existing : m_guild_wars) { + if (existing.src == pair.src && existing.dst == pair.dst) { + found = true; + break; + } + } + if (!found) { + m_guild_wars.push_back(pair); + } + } + } + m_guild_war_dirty = true; +} + +void EntityStore::mut_guild_war_score(uint32_t gain_guild_id, uint32_t opponent_guild_id, + int32_t point) { + m_guild_war_scores.push_back({gain_guild_id, opponent_guild_id, point}); + m_guild_war_dirty = true; +} + +void EntityStore::mut_guild_name(uint32_t id, const std::string &name) { + m_guild_names[id] = name; + if (id == m_guild.id) { + m_guild.name = name; + m_guild_dirty = true; + } + m_guild_war_dirty = true; +} + +void EntityStore::mut_guild_comments(const std::vector &comments) { + m_guild_comments = comments; + m_guild_comments_dirty = true; +} + +void EntityStore::mut_guild_invite(uint32_t guild_id, const std::string &guild_name) { + m_guild_invites.push_back({guild_id, guild_name}); +} + +void EntityStore::mut_exchange_start(uint32_t partner_vid) { + m_exchange = ExchangeState{}; + m_exchange.active = true; + m_exchange.partner_vid = partner_vid; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_item(bool self, uint8_t slot, uint32_t vnum, uint8_t count) { + if (slot >= 12) { + return; + } + ExchangeSlot &item = self ? m_exchange.self_items[slot] : m_exchange.peer_items[slot]; + item.vnum = vnum; + item.count = count; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_item_del(bool self, uint8_t slot) { + if (slot >= 12) { + return; + } + (self ? m_exchange.self_items[slot] : m_exchange.peer_items[slot]) = ExchangeSlot{}; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_gold(bool self, int64_t gold) { + (self ? m_exchange.self_gold : m_exchange.peer_gold) = gold; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_accept(bool self, bool accepted) { + (self ? m_exchange.self_accept : m_exchange.peer_accept) = accepted; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_end() { + m_exchange = ExchangeState{}; + m_exchange_dirty = true; +} + +void EntityStore::mut_exchange_notice() { + m_exchange_dirty = true; +} + +void EntityStore::mut_safebox_open(int size) { + for (Item &item : m_safebox) { + item = Item{}; + } + m_safebox_open = true; + m_safebox_size = size; + m_safebox_dirty = true; +} + +void EntityStore::mut_safebox_money(int64_t money) { + m_safebox_gold = money; + m_safebox_dirty = true; +} + +void EntityStore::mut_safebox_set(uint16_t cell, uint32_t vnum, uint8_t count, uint32_t flags, + uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs) { + if (cell >= SAFEBOX_MAX_NUM) { + return; + } + Item &item = m_safebox[cell]; + item = Item{}; + item.vnum = vnum; + item.count = count; + item.flags = flags; + item.anti_flags = anti_flags; + for (int i = 0; i < ITEM_SOCKET_SLOT_MAX_NUM; ++i) { + item.sockets[i] = sockets ? sockets[i] : 0; + } + for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i) { + item.attrs[i] = attrs ? attrs[i] : ItemAttr{}; + } + m_safebox_dirty = true; +} + +void EntityStore::mut_safebox_del(uint16_t cell) { + if (cell >= SAFEBOX_MAX_NUM) { + return; + } + m_safebox[cell] = Item{}; + m_safebox_dirty = true; +} + +void EntityStore::mut_safebox_wrong_password() { + m_safebox_dirty = true; + m_server_commands.push_back({ServerCommandEvent::SafeboxWrongPassword, 0, 0}); +} + +void EntityStore::mut_safebox_close() { + m_safebox_open = false; + m_safebox_dirty = true; +} + +void EntityStore::mut_mall_open(int size) { + for (Item &item : m_mall) { + item = Item{}; + } + m_mall_open = true; + m_mall_size = size; + m_mall_dirty = true; +} + +void EntityStore::mut_mall_set(uint16_t cell, uint32_t vnum, uint8_t count, uint32_t flags, + uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs) { + if (cell >= MALL_MAX_NUM) { + return; + } + Item &item = m_mall[cell]; + item = Item{}; + item.vnum = vnum; + item.count = count; + item.flags = flags; + item.anti_flags = anti_flags; + for (int i = 0; i < ITEM_SOCKET_SLOT_MAX_NUM; ++i) { + item.sockets[i] = sockets ? sockets[i] : 0; + } + for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i) { + item.attrs[i] = attrs ? attrs[i] : ItemAttr{}; + } + m_mall_dirty = true; +} + +void EntityStore::mut_mall_del(uint16_t cell) { + if (cell >= MALL_MAX_NUM) { + return; + } + m_mall[cell] = Item{}; + m_mall_dirty = true; +} + +void EntityStore::mut_mall_close() { + m_mall_open = false; + m_mall_dirty = true; +} + void EntityStore::apply(uint16_t header, const void *body, uint16_t len) { switch (header) { case GC_MAIN_CHARACTER: { @@ -504,6 +1634,8 @@ void EntityStore::apply(uint16_t header, const void *body, uint16_t len) { GCPlayerPoints p; std::memcpy(&p, body, sizeof(p)); std::memcpy(m_points.v, p.points, sizeof(p.points)); + m_current_stamina = (uint32_t)std::max(0, m_points.stamina()); + m_stamina_current_f = (float)m_current_stamina; m_points_dirty = true; // mirror the vitals onto the main entity so get(main_vid) is complete if (m_main_vid) { @@ -531,6 +1663,10 @@ void EntityStore::apply(uint16_t header, const void *body, uint16_t len) { std::memcpy(&p, body, sizeof(p)); if (p.vid == m_main_vid) { m_points.v[p.type] = p.value; // p.type is uint8_t -> always in [0,255] + if (p.type == POINT_STAMINA) { + m_current_stamina = (uint32_t)std::max(0, p.value); + m_stamina_current_f = (float)m_current_stamina; + } m_points_dirty = true; } auto it = m_ents.find(p.vid); @@ -1569,6 +2705,26 @@ void EntityStore::apply(uint16_t header, const void *body, uint16_t len) { } } +void EntityStore::mut_refine(uint8_t type, uint8_t pos, uint32_t src_vnum, uint32_t result_vnum, + uint8_t material_count, int32_t cost, int32_t prob, const RefineCue::Mat *materials) { + RefineCue cue; + cue.type = type; + cue.pos = pos; + cue.src_vnum = src_vnum; + cue.result_vnum = result_vnum; + cue.material_count = material_count > 5 ? 5 : material_count; + cue.cost = cost; + cue.prob = prob; + if (materials) { + std::memcpy(cue.materials, materials, sizeof(cue.materials)); + } + m_refine_cues.push_back(cue); +} + +void EntityStore::mut_dragon_soul_refine(uint8_t sub_type, uint8_t window, uint16_t cell) { + m_ds_cues.push_back({sub_type, window, cell}); +} + Item *EntityStore::mut_slot(uint8_t window, uint16_t cell) { const auto equip_index = [](uint16_t c) -> int { if (c >= EQUIPMENT_SLOT_START && c < EQUIPMENT_SLOT_START + WEAR_MAX_NUM) @@ -1690,12 +2846,194 @@ std::vector split_ch(const std::string &s, char d) { } // namespace // Mirrors CPythonNetworkStream::ServerCommand() — the GC_CHAT/COMMAND text bus. -// First version: the "cube" family (제작 UI). Other verbs are ignored for now. +// Commands that change a visible or actionable client state are converted to +// typed events; cosmetic/vendor-only commands remain safely consumed. void EntityStore::apply_server_command(const std::string &line) { std::vector tok = split_ws(line); if (tok.empty()) { return; } + auto single_emotion = [this](const std::vector &args, uint16_t motion) { + if (args.size() >= 2) { + m_motions.push_back({(uint32_t)std::strtoul(args[1].c_str(), nullptr, 10), 0, motion}); + } + }; + auto dual_emotion = [this](const std::vector &args, uint16_t motion1, + uint16_t motion2) { + if (args.size() < 3) { + return; + } + const uint32_t first = (uint32_t)std::strtoul(args[1].c_str(), nullptr, 10); + const uint32_t second = (uint32_t)std::strtoul(args[2].c_str(), nullptr, 10); + m_motions.push_back({first, second, motion1}); + m_motions.push_back({second, first, motion2}); + }; + if (tok[0] == "PartyRequestDenied") { + m_server_commands.push_back({ServerCommandEvent::PartyRequestDenied, 0, 0}); + return; + } + if (tok[0] == "PartyRequest" && tok.size() >= 2) { + mut_party_invite((uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10)); + return; + } + if (tok[0] == "CloseSafebox") { + mut_safebox_close(); + return; + } + if (tok[0] == "CloseMall") { + mut_mall_close(); + return; + } + if (tok[0] == "ShowMeSafeboxPassword") { + m_server_commands.push_back({ServerCommandEvent::SafeboxPasswordRequired, 0, 0}); + return; + } + if (tok[0] == "ShowMeMallPassword") { + m_server_commands.push_back({ServerCommandEvent::MallPasswordRequired, 0, 0}); + return; + } + if (tok[0] == "RefineSuceeded") { + m_server_commands.push_back({ServerCommandEvent::RefineSucceeded, 0, 0}); + return; + } + if (tok[0] == "RefineFailed") { + m_server_commands.push_back({ServerCommandEvent::RefineFailed, 0, 0}); + return; + } + if (tok[0] == "OpenPrivateShop") { + m_server_commands.push_back({ServerCommandEvent::PrivateShopOpenRequested, 0, 0}); + return; + } + if (tok[0] == "MyShopPriceList" && tok.size() >= 3) { + m_server_commands.push_back({ServerCommandEvent::MyShopPrice, + (uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10), + (uint32_t)std::strtoul(tok[2].c_str(), nullptr, 10)}); + return; + } + if (tok[0] == "setblockmode" && tok.size() >= 2) { + m_server_commands.push_back({ServerCommandEvent::BlockModeChanged, + (uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10), 0}); + return; + } + if (tok[0] == "ObserverMode" && tok.size() >= 2) { + m_observer_mode = std::strtoul(tok[1].c_str(), nullptr, 10) != 0; + m_server_commands.push_back({ServerCommandEvent::ObserverModeChanged, + m_observer_mode ? 1u : 0u, 0}); + return; + } + if (tok[0] == "ObserverCount" && tok.size() >= 2) { + m_observer_count = (int)std::strtol(tok[1].c_str(), nullptr, 10); + if (m_observer_count < 0) m_observer_count = 0; + m_server_commands.push_back({ServerCommandEvent::ObserverCountChanged, + (uint32_t)m_observer_count, 0}); + return; + } + if (tok[0] == "StoneDetect" && tok.size() >= 4) { + const uint32_t vid = (uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10); + const uint32_t distance = (uint32_t)std::strtoul(tok[2].c_str(), nullptr, 10); + const float raw_angle = std::strtof(tok[3].c_str(), nullptr); + float angle = std::fmod(540.0f - raw_angle, 360.0f); + if (angle < 0.0f) angle += 360.0f; + m_server_commands.push_back({ServerCommandEvent::StoneDetected, vid, distance, angle}); + return; + } + if (tok[0] == "StartStaminaConsume" && tok.size() >= 3) { + m_stamina_consuming = true; + m_stamina_per_sec = (uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10); + m_current_stamina = (uint32_t)std::strtoul(tok[2].c_str(), nullptr, 10); + m_stamina_current_f = (float)m_current_stamina; + m_stamina_last_ms = m_now; + m_points.v[POINT_STAMINA] = (int32_t)m_current_stamina; + m_points_dirty = true; + m_server_commands.push_back({ServerCommandEvent::StaminaStarted, + m_stamina_per_sec, m_current_stamina}); + return; + } + if (tok[0] == "StopStaminaConsume" && tok.size() >= 2) { + m_stamina_consuming = false; + m_stamina_per_sec = 0; + m_current_stamina = (uint32_t)std::strtoul(tok[1].c_str(), nullptr, 10); + m_stamina_current_f = (float)m_current_stamina; + m_stamina_last_ms = m_now; + m_points.v[POINT_STAMINA] = (int32_t)m_current_stamina; + m_points_dirty = true; + m_server_commands.push_back({ServerCommandEvent::StaminaStopped, 0, m_current_stamina}); + return; + } + if (tok[0] == "sms" || tok[0] == "nosms") { + m_mobile_flag = tok[0] == "sms"; + m_server_commands.push_back({ServerCommandEvent::MobileFlagChanged, + m_mobile_flag ? 1u : 0u, 0}); + return; + } + if (tok[0] == "mobile_auth") { + m_server_commands.push_back({ServerCommandEvent::MobileAuthRequired, 0, 0}); + return; + } + if (tok[0] == "combo" && tok.size() >= 2) { + m_combo_skill_flag = std::strtol(tok[1].c_str(), nullptr, 10) != 0; + m_server_commands.push_back({ServerCommandEvent::ComboChanged, + m_combo_skill_flag ? 1u : 0u, 0}); + return; + } + if (tok[0] == "messenger_auth" && tok.size() >= 2) { + mut_friend_invite(tok[1]); + return; + } + if (tok[0] == "gift") { + m_server_commands.push_back({ServerCommandEvent::GiftAvailable, 0, 0}); + return; + } + // The 40250 client maps these commands to the same CRaceMotionData IDs + // used by GC_MOTION. Queueing them in the shared motion stream preserves + // ordering and lets the Godot scene play the real PC action assets. + if (tok[0] == "french_kiss") { + dual_emotion(tok, MOTION_FRENCH_KISS_START, MOTION_FRENCH_KISS_START); + return; + } + if (tok[0] == "kiss") { + dual_emotion(tok, MOTION_KISS_START, MOTION_KISS_START); + return; + } + if (tok[0] == "slap") { + dual_emotion(tok, MOTION_SLAP_HURT_START, MOTION_SLAP_HIT_START); + return; + } + if (tok[0] == "clap") { + single_emotion(tok, MOTION_CLAP); + return; + } + if (tok[0] == "cheer1") { + single_emotion(tok, MOTION_CHEERS_1); + return; + } + if (tok[0] == "cheer2") { + single_emotion(tok, MOTION_CHEERS_2); + return; + } + if (tok[0] == "dig_motion") { + single_emotion(tok, MOTION_DIG); + return; + } + if (tok[0] == "dance1" || tok[0] == "dance2" || tok[0] == "dance3" + || tok[0] == "dance4" || tok[0] == "dance5" || tok[0] == "dance6") { + single_emotion(tok, (uint16_t)(MOTION_DANCE_1 + (tok[0][5] - '1'))); + return; + } + if (tok[0] == "congratulation" || tok[0] == "forgive" || tok[0] == "angry" + || tok[0] == "attractive" || tok[0] == "sad" || tok[0] == "shy" + || tok[0] == "cheerup" || tok[0] == "banter" || tok[0] == "joy") { + const uint16_t motion = tok[0] == "congratulation" ? MOTION_CONGRATULATION + : tok[0] == "forgive" ? MOTION_FORGIVE + : tok[0] == "angry" ? MOTION_ANGRY + : tok[0] == "attractive" ? MOTION_ATTRACTIVE + : tok[0] == "sad" ? MOTION_SAD + : tok[0] == "shy" ? MOTION_SHY + : tok[0] == "cheerup" ? MOTION_CHEERUP + : tok[0] == "banter" ? MOTION_BANTER : MOTION_JOY; + single_emotion(tok, motion); + return; + } if (tok[0] != "cube" || tok.size() < 2) { return; } @@ -1797,6 +3135,18 @@ std::vector EntityStore::pvp_relations() const { } void EntityStore::tick() { + if (m_stamina_consuming && m_stamina_per_sec > 0 && m_now > m_stamina_last_ms) { + const uint32_t elapsed_ms = m_now - m_stamina_last_ms; + m_stamina_last_ms = m_now; + m_stamina_current_f = std::max(0.0f, + m_stamina_current_f - (float)elapsed_ms * (float)m_stamina_per_sec / 1000.0f); + const uint32_t current = (uint32_t)m_stamina_current_f; + if (current != m_current_stamina) { + m_current_stamina = current; + m_points.v[POINT_STAMINA] = (int32_t)current; + m_points_dirty = true; + } + } for (auto &kv : m_ents) { Entity &e = kv.second; if (!e.moving) { diff --git a/extension/src/net/entity_store.h b/extension/src/net/entity_store.h index 4584f40c..de736f5b 100644 --- a/extension/src/net/entity_store.h +++ b/extension/src/net/entity_store.h @@ -32,6 +32,7 @@ struct Entity { uint16_t race = 0; uint8_t ch_type = 0; // CHRTYPE: 0 PC, 1 NPC, 2 MONSTER, 3 STONE, 4 WARP, ... std::string name; + std::string shop_sign; // GC_SHOP_SIGN; empty when the private shop is closed uint16_t parts[CHR_EQUIPPART_NUM] = {0, 0, 0, 0}; bool is_main = false; @@ -230,6 +231,7 @@ struct PartyMember { struct Friend { std::string name; bool online = false; + bool mobile = false; // 40250 GC_MESSENGER_MOBILE / connected-state bit }; // --- P8 NPC shop (GC_SHOP) ---------------------------------------------------- @@ -269,11 +271,21 @@ struct GuildMember { uint32_t pid = 0; uint8_t grade = 0; bool is_general = false; + bool online = false; uint8_t job = 0; uint8_t level = 0; uint32_t offer = 0; std::string name; }; +struct GuildComment { + uint32_t id = 0; + std::string name; + std::string content; +}; +struct GuildInvite { + uint32_t guild_id = 0; + std::string guild_name; +}; struct GuildGrade { std::string name; uint8_t auth = 0; @@ -333,6 +345,37 @@ struct RefineCue { uint8_t material_count = 0; }; +// One stateful line from the 40250 GC_CHAT/COMMAND bus. The original client +// routes these through CPythonNetworkStream::ServerCommand(); keeping them as +// typed events lets the Godot bridge expose the same behaviour without making +// the parser depend on UI code. +struct ServerCommandEvent { + enum Kind { + PartyRequestDenied, + SafeboxPasswordRequired, + SafeboxWrongPassword, + MallPasswordRequired, + RefineSucceeded, + RefineFailed, + PrivateShopOpenRequested, + MyShopPrice, + BlockModeChanged, + ObserverModeChanged, + ObserverCountChanged, + StoneDetected, + StaminaStarted, + StaminaStopped, + MobileFlagChanged, + MobileAuthRequired, + ComboChanged, + GiftAvailable, + }; + Kind kind = PartyRequestDenied; + uint32_t value = 0; // item vnum / price, depending on kind + uint32_t value2 = 0; + float value3 = 0.0f; // StoneDetect angle, in degrees after legacy conversion +}; + // An item lying in the world (GC_ITEM_GROUND_ADD). struct GroundItem { uint32_t vid = 0; @@ -381,6 +424,8 @@ struct PlayerPoints { int32_t max_hp() const { return v[POINT_MAX_HP]; } int32_t sp() const { return v[POINT_SP]; } int32_t max_sp() const { return v[POINT_MAX_SP]; } + int32_t stamina() const { return v[POINT_STAMINA]; } + int32_t max_stamina() const { return v[POINT_MAX_STAMINA]; } int32_t level() const { return v[POINT_LEVEL]; } int32_t exp() const { return v[POINT_EXP]; } int32_t next_exp() const { return v[POINT_NEXT_EXP]; } @@ -408,8 +453,158 @@ public: // Feed one complete game-phase packet. `body` points at the packet start // (header/length included); `len` == that length. Unknown headers ignored. + // This is the m2dev-fork parser; the 40250 "classic" backend calls the + // protocol-neutral mutation API below instead (docs/CLIENT-40250-PORT.md §6). void apply(uint16_t header, const void *body, uint16_t len); + // --- protocol-neutral mutation API --------------------------------------- + // Both the m2dev apply() path and mtnet::classic::ClassicParser drive the + // same world model through these. Positions are server cm; `rot256` is the + // legacy 0..255 heading; `func` mirrors FUNC_*. + void mut_spawn(uint32_t vid, uint16_t race, uint8_t ch_type, const std::string &name, + float x, float y, float z, float angle, uint16_t moving_speed = 0, + uint8_t attack_speed = 0); + void mut_spawn_main(uint32_t vid, uint16_t race, const std::string &name, float x, float y, + float z); + void mut_despawn(uint32_t vid); + // angle_deg is the already-decoded compass heading (m2dev: rot*360/256; + // classic: rot*5 — the two wire encodings differ, so decode at the parser). + void mut_move(uint32_t vid, float angle_deg, uint8_t func, float tx, float ty, + uint32_t dur_ms); + // Full stat block (index = POINT_*). `n` <= 256. + void mut_set_points(const int32_t *pts, int n); + // One stat delta (GC_CHARACTER_POINT_CHANGE equivalent). + void mut_set_point(uint8_t type, int32_t value, uint32_t vid); + + // --- items --- window: 1=inventory, 2=equipment, 5=dragon-soul, 7=belt. + // `sockets` is ITEM_SOCKET_SLOT_MAX_NUM ints; `attrs` is + // ITEM_ATTRIBUTE_SLOT_MAX_NUM ItemAttr (pass nullptr to leave them zero). + void mut_item_set(uint8_t window, uint16_t cell, uint32_t vnum, uint8_t count, uint32_t flags, + uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs); + void mut_item_del(uint8_t window, uint16_t cell); + void mut_item_update(uint8_t window, uint16_t cell, uint8_t count, const int32_t *sockets, + const ItemAttr *attrs); + void mut_ground_add(uint32_t vid, uint32_t vnum, float x, float y, float z); + void mut_ground_del(uint32_t vid); + void mut_ground_owner(uint32_t vid, const std::string &owner); + void mut_item_used(uint32_t vnum); + void mut_item_picked(uint32_t vnum, uint8_t count, const std::string &from); + + // --- entity state (all no-op if vid unknown) --- + // `parts` is CHR_EQUIPPART_NUM u16 (nullptr = leave unchanged). + void mut_char_update(uint32_t vid, const uint16_t *parts, uint8_t moving_speed, + uint8_t attack_speed, int32_t guild_id, int16_t alignment, uint8_t pk_mode, + uint32_t mount_vnum); + void mut_set_position(uint32_t vid, uint8_t position); + // snap an entity to (x,y) with no interpolation (GC_SYNC_POSITION). + void mut_snap_position(uint32_t vid, float x, float y); + void mut_change_speed(uint32_t vid, uint16_t moving_speed); + void mut_walk_mode(uint32_t vid, uint8_t mode); + void mut_stun(uint32_t vid); + void mut_dead(uint32_t vid); + void mut_motion(uint32_t vid, uint32_t victim_vid, uint16_t motion); + void mut_target(uint32_t vid, uint8_t hp_pct); + void mut_damage(uint32_t vid, uint8_t flag, int32_t amount); + void mut_mount(uint32_t vid, uint32_t mount_vnum); + void mut_fly(uint8_t type, uint32_t start_vid, uint32_t end_vid); + void mut_fly_target(uint32_t shooter_vid, uint32_t target_vid, int32_t x, int32_t y, + bool append); + void mut_dig(uint32_t vid, uint32_t target_vid, uint8_t count); + void mut_special_effect(uint32_t vid, int32_t special); + void mut_specific_effect(uint32_t vid, const std::string &file); + void mut_pvp(uint32_t src_vid, uint32_t dst_vid, uint8_t mode); + void mut_duel_start(); + void mut_duel_start(const uint32_t *opponents, int count); + void mut_view_equipment(uint32_t vid, const Item *items, int n); + // GC_CHAR_ADDITIONAL_INFO — fills a spawned entity's name/parts/level/guild. + void mut_char_info(uint32_t vid, const std::string &name, const uint16_t *parts, + uint8_t empire, int32_t guild_id, int32_t level, int16_t alignment, uint8_t pk_mode, + uint32_t mount_vnum); + // GC_SHOP_SIGN — the sign belongs to the entity that owns the private shop. + void mut_shop_sign(uint32_t vid, const std::string &sign); + + // --- local-player skills / quickslots / affects --- + // `level` / `master` are SKILL_MAX_NUM bytes (master may be nullptr). + void mut_skill_levels(const uint8_t *level, const uint8_t *master, int n); + void mut_skill_group(uint8_t group); + void mut_skill_cooldown_end(uint8_t skill); + void mut_quickslot_set(uint8_t pos, uint8_t type, uint8_t position); + void mut_quickslot_del(uint8_t pos); + void mut_quickslot_swap(uint8_t pos, uint8_t pos_to); + void mut_affect_add(uint32_t type, uint8_t point_idx, int32_t value, uint32_t flag, + int32_t duration); + void mut_affect_remove(uint32_t type); + + // --- chat --- (GC_CHAT with type==CHAT_TYPE_COMMAND routes to apply_server_command) + void mut_chat(uint8_t type, uint32_t vid, const std::string &text); + void mut_whisper(uint8_t sub, const std::string &from, const std::string &text); + + // --- NPC shop (GC_SHOP) --- a single-shelf shop is one unnamed tab. + void mut_shop_open(uint32_t vid, const std::vector &tabs); + void mut_shop_update_item(uint8_t pos, uint32_t vnum, uint32_t price, uint8_t count); + void mut_shop_update_price(int32_t price); + void mut_shop_close(); + void mut_shop_error(const std::string &code); + + // --- quest / NPC dialog --- + void mut_script(uint8_t skin, const std::string &text); // GC_SCRIPT + void mut_quest_confirm(const std::string &msg, int32_t timeout, uint32_t request_pid); + void mut_quest_info(uint16_t index, uint8_t flag, bool begin, const std::string &title, + const std::string &clock_name, int32_t clock_value, const std::string &counter_name, + int32_t counter_value, const std::string &icon); + + // --- P9 world systems --- + void mut_warp(int32_t x, int32_t y, int32_t addr, uint16_t port); + void mut_server_time(int64_t time); + void mut_channel(uint8_t channel); + void mut_npc_marks(const std::vector &marks); + void mut_land_areas(const std::vector &areas); + void mut_marker_create(int32_t id, const std::string &name, uint32_t vid, uint8_t type); + void mut_marker_update(int32_t id, int32_t x, int32_t y); + void mut_marker_delete(int32_t id); + void mut_observer(ObserverEvent::Kind kind, uint32_t vid, int32_t x, int32_t y); + void mut_lover(const std::string &name, uint8_t love_point); + void mut_love_point(uint8_t love_point); + void mut_fishing(uint8_t subheader, uint32_t info, uint8_t dir); + void mut_dungeon(uint8_t subheader, int32_t x, int32_t y, bool has_destination); + + // --- party (GC_PARTY_*) --- `affects` is PARTY_AFFECT_SLOT_MAX_NUM int16 (may be nullptr). + void mut_party_invite(uint32_t leader); + void mut_party_add(uint32_t pid, const std::string &name); + void mut_party_update(uint32_t pid, uint8_t role, uint8_t hp_pct, const int16_t *affects); + void mut_party_remove(uint32_t pid); + void mut_party_link(uint32_t pid, uint32_t vid); + void mut_party_unlink(uint32_t pid); + void mut_party_parameter(uint8_t distribute_mode); + + // --- messenger / exchange / storage ------------------------------------- + void mut_friend_set(const std::string &name, bool online); + void mut_friend_mobile(const std::string &name, bool mobile); + void mut_friend_remove(const std::string &name); + void mut_friend_clear(); + // Server command `messenger_auth ` asks the local player to approve + // or deny a pending friend request. + void mut_friend_invite(const std::string &name); + void mut_exchange_start(uint32_t partner_vid); + void mut_exchange_item(bool self, uint8_t slot, uint32_t vnum, uint8_t count); + void mut_exchange_item_del(bool self, uint8_t slot); + void mut_exchange_gold(bool self, int64_t gold); + void mut_exchange_accept(bool self, bool accepted); + void mut_exchange_end(); + void mut_exchange_notice(); // server-side ALREADY / LESS_GOLD notice + void mut_safebox_open(int size); + void mut_safebox_money(int64_t money); + void mut_safebox_set(uint16_t cell, uint32_t vnum, uint8_t count, uint32_t flags, + uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs); + void mut_safebox_del(uint16_t cell); + void mut_safebox_wrong_password(); + void mut_safebox_close(); + void mut_mall_open(int size); + void mut_mall_set(uint16_t cell, uint32_t vnum, uint8_t count, uint32_t flags, + uint32_t anti_flags, const int32_t *sockets, const ItemAttr *attrs); + void mut_mall_del(uint16_t cell); + void mut_mall_close(); + // Advance interpolation of moving entities to m_now. void tick(); @@ -522,10 +717,16 @@ public: return v; } bool friends_dirty() { bool d = m_friends_dirty; m_friends_dirty = false; return d; } + std::vector drain_friend_invites() { + auto v = std::move(m_friend_invites); + m_friend_invites.clear(); + return v; + } // --- P8 NPC shop --- bool shop_open() const { return m_shop_open; } uint32_t shop_vid() const { return m_shop_vid; } + int32_t shop_selling_price() const { return m_shop_selling_price; } const std::vector &shop_items() const { return m_shop_items; } // SHOP_GC_START_EX shelves; empty for a plain SHOP_GC_START shop (use shop_items()). const std::vector &shop_tabs() const { return m_shop_tabs; } @@ -588,6 +789,29 @@ public: CubeResultEntry cube_last_success() const { return m_cube_last_success; } // --- guild --- + void mut_guild_info(uint16_t member_count, uint16_t max_member_count, uint32_t id, + uint32_t master_pid, uint32_t exp, uint8_t level, const std::string &name, + uint32_t gold, bool has_land); + void mut_guild_clear_members(); + void mut_guild_member(uint32_t pid, uint8_t grade, bool is_general, uint8_t job, + uint8_t level, uint32_t offer, const std::string &name); + void mut_guild_member_online(uint32_t pid, bool online); + void mut_guild_remove_member(uint32_t pid); + void mut_guild_grade(uint8_t grade, const std::string &name, uint8_t auth); + void mut_guild_grade_name(uint8_t grade, const std::string &name); + void mut_guild_grade_auth(uint8_t grade, uint8_t auth); + void mut_guild_member_grade(uint32_t pid, uint8_t grade); + void mut_guild_member_general(uint32_t pid, bool is_general); + void mut_guild_exp(uint8_t level, uint32_t exp); + void mut_guild_money(uint32_t gold); + void mut_guild_skill(uint8_t skill_point, const uint8_t *levels, uint16_t guild_point, + uint16_t max_guild_point); + void mut_guild_war(uint32_t self_id, uint32_t opponent_id, uint8_t type, uint8_t state); + void mut_guild_war_pairs(const std::vector &pairs, bool remove); + void mut_guild_war_score(uint32_t gain_guild_id, uint32_t opponent_guild_id, int32_t point); + void mut_guild_name(uint32_t id, const std::string &name); + void mut_guild_comments(const std::vector &comments); + void mut_guild_invite(uint32_t guild_id, const std::string &guild_name); const GuildState &guild() const { return m_guild; } std::vector guild_members() const { std::vector v; @@ -602,6 +826,17 @@ public: return (i >= 0 && i < 16) ? m_guild_grades[i] : kEmpty; } bool guild_dirty() { bool d = m_guild_dirty; m_guild_dirty = false; return d; } + const std::vector &guild_comments() const { return m_guild_comments; } + bool guild_comments_dirty() { + bool d = m_guild_comments_dirty; + m_guild_comments_dirty = false; + return d; + } + std::vector drain_guild_invites() { + auto v = std::move(m_guild_invites); + m_guild_invites.clear(); + return v; + } // --- guild war / guild skill --- const GuildSkillState &guild_skill() const { return m_guild_skill; } @@ -637,6 +872,10 @@ public: m_ds_cues.clear(); return v; } + void mut_refine(uint8_t type, uint8_t pos, uint32_t src_vnum, uint32_t result_vnum, + uint8_t material_count, int32_t cost, int32_t prob, + const RefineCue::Mat *materials); + void mut_dragon_soul_refine(uint8_t sub_type, uint8_t window, uint16_t cell); const Item &dragon_soul_slot(int cell) const; // --- P9 world systems --- @@ -703,12 +942,21 @@ public: return v; } std::vector pvp_relations() const; + const std::vector &duel_opponents() const { return m_duel_opponents; } + bool duel_cannot_attack() const { return m_duel_cannot_attack; } bool take_duel_started() { bool started = m_duel_started; m_duel_started = false; return started; } const LoverInfo &lover() const { return m_lover; } + bool observer_mode() const { return m_observer_mode; } + int observer_count() const { return m_observer_count; } + bool mobile_flag() const { return m_mobile_flag; } + bool combo_skill_flag() const { return m_combo_skill_flag; } + bool stamina_consuming() const { return m_stamina_consuming; } + uint32_t stamina_per_sec() const { return m_stamina_per_sec; } + uint32_t current_stamina() const { return m_current_stamina; } bool take_lover_dirty() { bool dirty = m_lover_dirty; m_lover_dirty = false; @@ -725,6 +973,11 @@ public: m_chat.clear(); return v; } + std::vector drain_server_commands() { + auto v = std::move(m_server_commands); + m_server_commands.clear(); + return v; + } // vids whose hp/sp/level/dead/stunned changed since last drain (deduped). std::vector drain_vitals() { auto v = std::move(m_vitals); @@ -855,9 +1108,20 @@ private: std::vector m_item_events; std::unordered_map m_pvp; std::vector m_pvp_changes; + std::vector m_duel_opponents; bool m_duel_started = false; + bool m_duel_cannot_attack = false; LoverInfo m_lover; bool m_lover_dirty = false; + bool m_observer_mode = false; + int m_observer_count = 0; + bool m_mobile_flag = false; + bool m_combo_skill_flag = false; + bool m_stamina_consuming = false; + uint32_t m_stamina_per_sec = 0; + uint32_t m_current_stamina = 0; + float m_stamina_current_f = 0.0f; + uint32_t m_stamina_last_ms = 0; // P8 social / shop / storage std::unordered_map m_party; @@ -866,11 +1130,13 @@ private: std::vector m_party_invites; std::unordered_map m_friends; bool m_friends_dirty = false; + std::vector m_friend_invites; bool m_shop_open = false; uint32_t m_shop_vid = 0; std::vector m_shop_items; // == m_shop_tabs[0].items when tabs present std::vector m_shop_tabs; bool m_shop_dirty = false; + int32_t m_shop_selling_price = 0; std::vector m_shop_errors; ExchangeState m_exchange; bool m_exchange_dirty = false; @@ -888,6 +1154,7 @@ private: CubeState m_cube; std::vector m_cube_events; CubeResultEntry m_cube_last_success; + std::vector m_server_commands; void apply_server_command(const std::string &line); // P9 world systems @@ -905,8 +1172,11 @@ private: // guild / refine GuildState m_guild; std::unordered_map m_guild_members; + std::vector m_guild_comments; + std::vector m_guild_invites; GuildGrade m_guild_grades[16]; bool m_guild_dirty = false; + bool m_guild_comments_dirty = false; GuildSkillState m_guild_skill; bool m_guild_skill_dirty = false; GuildWarStatus m_guild_war; diff --git a/extension/src/net/game_client.h b/extension/src/net/game_client.h index ed1e54ba..1c9c4004 100644 --- a/extension/src/net/game_client.h +++ b/extension/src/net/game_client.h @@ -37,6 +37,7 @@ public: uint32_t play_minutes = 0; int st = 0, ht = 0, dx = 0, iq = 0; int main_part = 0, hair_part = 0; + bool change_name = false; }; static void fill_slot_stats(CharSlot &c, const SimplePlayerInfo &s) { @@ -47,6 +48,7 @@ public: c.iq = s.iq; c.main_part = s.main_part; c.hair_part = s.hair_part; + c.change_name = s.change_name != 0; } // guild-mark side connection auth (from GC_LOGIN_SUCCESS3/4). @@ -582,6 +584,70 @@ public: std::memcpy(buf + sizeof(head), &arg, 4); return send_packet(buf, sizeof(buf)); } + bool send_guild_sub_i32(uint8_t subheader, int32_t arg) { + uint8_t buf[sizeof(CGGuild) + sizeof(arg)]; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), subheader}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &arg, sizeof(arg)); + return send_packet(buf, sizeof(buf)); + } + bool send_guild_grade_name(uint8_t grade, const std::string &name) { + if (grade == 0 || grade >= 16 || name.empty() || name.size() > GUILD_GRADE_NAME_MAX_LEN) { + return false; + } + uint8_t buf[sizeof(CGGuild) + 1 + GUILD_GRADE_NAME_MAX_LEN + 1] = {}; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), GUILD_CG_CHANGE_GRADE_NAME}; + std::memcpy(buf, &head, sizeof(head)); + buf[sizeof(head)] = grade; + std::memcpy(buf + sizeof(head) + 1, name.data(), name.size()); + return send_packet(buf, sizeof(buf)); + } + bool send_guild_grade_authority(uint8_t grade, uint8_t authority) { + if (grade == 0 || grade >= 16) return false; + uint8_t buf[sizeof(CGGuild) + 2]; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), GUILD_CG_CHANGE_GRADE_AUTHORITY}; + std::memcpy(buf, &head, sizeof(head)); + buf[sizeof(head)] = grade; + buf[sizeof(head) + 1] = authority; + return send_packet(buf, sizeof(buf)); + } + bool send_guild_member_grade(uint32_t pid, uint8_t grade) { + if (pid == 0 || grade == 0 || grade >= 16) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(pid) + 1]; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), GUILD_CG_CHANGE_MEMBER_GRADE}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &pid, sizeof(pid)); + buf[sizeof(head) + sizeof(pid)] = grade; + return send_packet(buf, sizeof(buf)); + } + bool send_guild_member_general(uint32_t pid, bool enabled) { + if (pid == 0) return false; + uint8_t buf[sizeof(CGGuild) + sizeof(pid) + 1]; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), GUILD_CG_CHANGE_MEMBER_GENERAL}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &pid, sizeof(pid)); + buf[sizeof(head) + sizeof(pid)] = enabled ? 1 : 0; + return send_packet(buf, sizeof(buf)); + } + bool send_guild_comment(const std::string &text) { + if (text.empty() || text.size() + 1 > 50) return false; + std::vector buf(sizeof(CGGuild) + 1 + text.size() + 1, 0); + CGGuild head{CG_GUILD, (uint16_t)buf.size(), GUILD_CG_POST_COMMENT}; + std::memcpy(buf.data(), &head, sizeof(head)); + buf[sizeof(head)] = static_cast(text.size() + 1); + if (!text.empty()) { + std::memcpy(buf.data() + sizeof(head) + 1, text.data(), text.size()); + } + return send_packet(buf.data(), buf.size()); + } + bool send_guild_invite_answer(uint32_t guild_id, bool accept) { + uint8_t buf[sizeof(CGGuild) + 4 + 1]; + CGGuild head{CG_GUILD, (uint16_t)sizeof(buf), GUILD_CG_INVITE_ANSWER}; + std::memcpy(buf, &head, sizeof(head)); + std::memcpy(buf + sizeof(head), &guild_id, sizeof(guild_id)); + buf[sizeof(head) + sizeof(guild_id)] = accept ? 1 : 0; + return send_packet(buf, sizeof(buf)); + } // GUILD_CG_USE_SKILL: sub-header + {u32 skill_vnum, u32 target_vid}. bool send_guild_use_skill(uint32_t skill_vnum, uint32_t target_vid) { uint8_t buf[sizeof(CGGuild) + 8]; @@ -744,6 +810,7 @@ protected: for (auto &slot : m_chars) { if (slot.id == p.pid) { slot.name = name; + slot.change_name = false; } } m_name_events.push_back({p.pid, std::move(name)}); diff --git a/extension/src/net/i_net_session.h b/extension/src/net/i_net_session.h new file mode 100644 index 00000000..dfdff670 --- /dev/null +++ b/extension/src/net/i_net_session.h @@ -0,0 +1,78 @@ +#pragma once +// INetSession — the seam M2Client will talk to so the m2dev-fork stack and the +// 40250 "classic" stack are swappable via MT_PROTOCOL (docs/CLIENT-40250-PORT.md +// §6). Lifecycle + pump only for now; the per-intent send_* surface is added as +// the classic backend grows (both backends already share EntityStore). + +#include +#include + +namespace mtnet { + +class EntityStore; + +class INetSession { +public: + virtual ~INetSession() = default; + + // Coarse lifecycle state for the host node's state machine. + enum class Stage { Offline, Connecting, LoggingIn, CharSelect, Loading, InGame, Failed }; + + // auth_host/port may equal game_host/port when there is no separate auth server. + virtual bool connect(const std::string &game_host, uint16_t game_port, + const std::string &id, const std::string &pw) = 0; + virtual void disconnect() = 0; + + // pick a character-list slot (0-based); sends the select packet. + virtual bool select_char(int slot) = 0; + // explicit CG_ENTERGAME once loading is done (backends may also send it themselves). + virtual bool enter_game() = 0; + + // pump the socket once per frame: I/O + parse into the shared EntityStore. + virtual void pump() = 0; + + virtual Stage stage() const = 0; + virtual bool in_game() const { return stage() == Stage::InGame; } + virtual const std::string &last_error() const = 0; + + // The world model both backends write into. + virtual EntityStore &world() = 0; + + // --- in-game intents (only valid once in_game()) ----------------------- + // x/y are server cm; rot_deg is a compass heading; time_ms from the frame + // clock (0 = let the backend fill it). window: 1=inventory, 2=equipment. + virtual bool send_move(uint8_t func, uint8_t arg, float rot_deg, int32_t x, int32_t y, + uint32_t time_ms = 0) = 0; + virtual bool send_attack(uint8_t type, uint32_t victim_vid) = 0; + virtual bool send_chat(uint8_t type, const std::string &text) = 0; + virtual bool send_target(uint32_t vid) = 0; + virtual bool send_character_position(uint8_t position) = 0; + virtual bool send_click_npc(uint32_t vid) = 0; + virtual bool send_script_answer(uint8_t answer) = 0; + virtual bool send_item_use(uint8_t window, uint16_t cell) = 0; + virtual bool send_item_move(uint8_t window, uint16_t cell, uint8_t to_window, uint16_t to_cell, + uint8_t count) = 0; + virtual bool send_item_drop(uint8_t window, uint16_t cell, uint32_t gold, uint8_t count) = 0; + virtual bool send_item_pickup(uint32_t ground_vid) = 0; + // sends CG_FLY_TARGETING first when target_vid != 0, matching the legacy order. + virtual bool send_use_skill(uint32_t skill_vnum, uint32_t target_vid) = 0; + + // --- P8 social / exchange / storage intents ----------------------------- + virtual bool send_friend_add(const std::string &name) = 0; + virtual bool send_friend_remove(const std::string &name) = 0; + virtual bool send_exchange_start(uint32_t partner_vid) = 0; + virtual bool send_exchange_item_add(uint8_t inv_window, uint16_t inv_cell, + uint8_t display_pos) = 0; + virtual bool send_exchange_gold(uint32_t gold) = 0; + virtual bool send_exchange_accept() = 0; + virtual bool send_exchange_cancel() = 0; + virtual bool send_safebox_checkin(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) = 0; + virtual bool send_safebox_checkout(uint8_t safe_pos, uint8_t inv_window, + uint16_t inv_cell) = 0; + virtual bool send_safebox_move(uint16_t from_cell, uint16_t to_cell, uint8_t count) = 0; + virtual bool send_mall_checkout(uint8_t mall_pos, uint8_t inv_window, + uint16_t inv_cell) = 0; +}; + +} // namespace mtnet diff --git a/extension/src/net/m2_client.cpp b/extension/src/net/m2_client.cpp index b7272d6d..4b96b1ea 100644 --- a/extension/src/net/m2_client.cpp +++ b/extension/src/net/m2_client.cpp @@ -1,10 +1,13 @@ #include "m2_client.h" #include "auth_client.h" +#include "classic/classic_mark_client.h" +#include "classic/classic_session.h" #include "game_client.h" #include "mark_client.h" #include +#include #include #include #include @@ -40,6 +43,7 @@ void M2Client::_bind_methods() { &M2Client::delete_character); ClassDB::bind_method(D_METHOD("change_name", "slot", "name"), &M2Client::change_name); ClassDB::bind_method(D_METHOD("get_empire"), &M2Client::get_empire); + ClassDB::bind_method(D_METHOD("select_empire", "empire"), &M2Client::select_empire); ClassDB::bind_method(D_METHOD("get_slot_count"), &M2Client::get_slot_count); ClassDB::bind_method(D_METHOD("move", "func", "arg", "rot_deg", "x", "y"), &M2Client::move); ClassDB::bind_method(D_METHOD("character_position", "position"), &M2Client::character_position); @@ -73,6 +77,7 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("get_entity", "vid"), &M2Client::get_entity); ClassDB::bind_method(D_METHOD("get_entities"), &M2Client::get_entities); ClassDB::bind_method(D_METHOD("get_main_vid"), &M2Client::get_main_vid); + ClassDB::bind_method(D_METHOD("get_main_pid"), &M2Client::get_main_pid); ClassDB::bind_method(D_METHOD("get_points"), &M2Client::get_points); ClassDB::bind_method(D_METHOD("get_target"), &M2Client::get_target); ClassDB::bind_method(D_METHOD("get_affects"), &M2Client::get_affects); @@ -92,6 +97,7 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item", "window", "cell"), &M2Client::get_item); ClassDB::bind_method(D_METHOD("get_ground_items"), &M2Client::get_ground_items); ClassDB::bind_method(D_METHOD("get_pvp_relations"), &M2Client::get_pvp_relations); + ClassDB::bind_method(D_METHOD("get_duel"), &M2Client::get_duel); ClassDB::bind_method(D_METHOD("suspend"), &M2Client::suspend); ClassDB::bind_method(D_METHOD("resume"), &M2Client::resume); ClassDB::bind_method(D_METHOD("reconnect"), &M2Client::reconnect); @@ -109,6 +115,7 @@ void M2Client::_bind_methods() { ADD_SIGNAL(MethodInfo("char_create_failed", PropertyInfo(Variant::INT, "reason_type"))); ADD_SIGNAL(MethodInfo("char_deleted", PropertyInfo(Variant::INT, "slot"))); ADD_SIGNAL(MethodInfo("char_delete_failed")); + ADD_SIGNAL(MethodInfo("empire_changed", PropertyInfo(Variant::INT, "empire"))); ADD_SIGNAL(MethodInfo("char_name_changed", PropertyInfo(Variant::INT, "pid"), PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("entered_game")); @@ -147,6 +154,7 @@ void M2Client::_bind_methods() { ADD_SIGNAL(MethodInfo("view_equipment", PropertyInfo(Variant::INT, "vid"))); ADD_SIGNAL(MethodInfo("pvp_changed", PropertyInfo(Variant::INT, "src_vid"), PropertyInfo(Variant::INT, "dst_vid"), PropertyInfo(Variant::INT, "mode"))); + ADD_SIGNAL(MethodInfo("duel_changed", PropertyInfo(Variant::DICTIONARY, "duel"))); ADD_SIGNAL(MethodInfo("duel_started")); ADD_SIGNAL(MethodInfo("item_picked_up", PropertyInfo(Variant::INT, "vnum"), PropertyInfo(Variant::INT, "count"), PropertyInfo(Variant::STRING, "from"))); @@ -184,6 +192,7 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("get_party_distribute_mode"), &M2Client::get_party_distribute_mode); ClassDB::bind_method(D_METHOD("add_friend", "name"), &M2Client::add_friend); ClassDB::bind_method(D_METHOD("remove_friend", "name"), &M2Client::remove_friend); + ClassDB::bind_method(D_METHOD("friend_answer", "name", "accept"), &M2Client::friend_answer); ClassDB::bind_method(D_METHOD("get_friends"), &M2Client::get_friends); ClassDB::bind_method(D_METHOD("get_lover"), &M2Client::get_lover); ClassDB::bind_method(D_METHOD("shop_buy", "pos", "count"), &M2Client::shop_buy); @@ -209,12 +218,14 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("get_safebox_size"), &M2Client::get_safebox_size); ClassDB::bind_method(D_METHOD("get_safebox_gold"), &M2Client::get_safebox_gold); ClassDB::bind_method(D_METHOD("get_safebox_items"), &M2Client::get_safebox_items); + ClassDB::bind_method(D_METHOD("safebox_password", "password"), &M2Client::safebox_password); // item-mall (창고몰) ClassDB::bind_method(D_METHOD("is_mall_open"), &M2Client::is_mall_open); ClassDB::bind_method(D_METHOD("get_mall_size"), &M2Client::get_mall_size); ClassDB::bind_method(D_METHOD("get_mall_items"), &M2Client::get_mall_items); ClassDB::bind_method(D_METHOD("mall_checkout", "mall_pos", "inv_window", "inv_cell"), &M2Client::mall_checkout); + ClassDB::bind_method(D_METHOD("mall_password", "password"), &M2Client::mall_password); // private (PC) shop ClassDB::bind_method(D_METHOD("open_private_shop", "sign", "items"), &M2Client::open_private_shop); @@ -226,18 +237,43 @@ void M2Client::_bind_methods() { &M2Client::cube_request_result_list); ClassDB::bind_method(D_METHOD("cube_request_materials", "start_index", "count"), &M2Client::cube_request_materials); + ClassDB::bind_method(D_METHOD("cube_open"), &M2Client::cube_open); + ClassDB::bind_method(D_METHOD("cube_close"), &M2Client::cube_close); + ClassDB::bind_method(D_METHOD("cube_list"), &M2Client::cube_list); + ClassDB::bind_method(D_METHOD("cube_add_item", "cube_index", "inventory_index"), + &M2Client::cube_add_item); + ClassDB::bind_method(D_METHOD("cube_delete_item", "cube_index"), &M2Client::cube_delete_item); ADD_SIGNAL(MethodInfo("party_changed")); ADD_SIGNAL(MethodInfo("party_invite_ask", PropertyInfo(Variant::INT, "leader_pid"))); + ADD_SIGNAL(MethodInfo("party_request_denied")); ADD_SIGNAL(MethodInfo("lover_changed", PropertyInfo(Variant::DICTIONARY, "lover"))); ADD_SIGNAL(MethodInfo("friends_changed")); + ADD_SIGNAL(MethodInfo("friend_invite_ask", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("shop_opened", PropertyInfo(Variant::INT, "vid"))); ADD_SIGNAL(MethodInfo("shop_closed")); ADD_SIGNAL(MethodInfo("shop_error", PropertyInfo(Variant::STRING, "kind"))); ADD_SIGNAL(MethodInfo("exchange_changed")); ADD_SIGNAL(MethodInfo("safebox_changed")); + ADD_SIGNAL(MethodInfo("safebox_password_required")); + ADD_SIGNAL(MethodInfo("safebox_wrong_password")); ADD_SIGNAL(MethodInfo("mall_opened", PropertyInfo(Variant::INT, "size"))); ADD_SIGNAL(MethodInfo("mall_changed")); + ADD_SIGNAL(MethodInfo("mall_password_required")); + ADD_SIGNAL(MethodInfo("private_shop_open_requested")); + ADD_SIGNAL(MethodInfo("my_shop_price_list", PropertyInfo(Variant::INT, "vnum"), + PropertyInfo(Variant::INT, "price"))); + ADD_SIGNAL(MethodInfo("block_mode_changed", PropertyInfo(Variant::INT, "mask"))); + ADD_SIGNAL(MethodInfo("observer_mode_changed", PropertyInfo(Variant::BOOL, "enabled"))); + ADD_SIGNAL(MethodInfo("observer_count_changed", PropertyInfo(Variant::INT, "count"))); + ADD_SIGNAL(MethodInfo("stone_detected", PropertyInfo(Variant::INT, "vid"), + PropertyInfo(Variant::INT, "distance"), PropertyInfo(Variant::FLOAT, "angle"))); + ADD_SIGNAL(MethodInfo("stamina_changed", PropertyInfo(Variant::INT, "current"), + PropertyInfo(Variant::INT, "per_sec"), PropertyInfo(Variant::BOOL, "consuming"))); + ADD_SIGNAL(MethodInfo("mobile_flag_changed", PropertyInfo(Variant::BOOL, "enabled"))); + ADD_SIGNAL(MethodInfo("mobile_auth_required")); + ADD_SIGNAL(MethodInfo("combo_changed", PropertyInfo(Variant::BOOL, "enabled"))); + ADD_SIGNAL(MethodInfo("gift_available")); ADD_SIGNAL(MethodInfo("cube_opened", PropertyInfo(Variant::INT, "npc_vnum"))); ADD_SIGNAL(MethodInfo("cube_closed")); ADD_SIGNAL(MethodInfo("cube_changed")); @@ -251,7 +287,22 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("guild_add_member", "vid"), &M2Client::guild_add_member); ClassDB::bind_method(D_METHOD("guild_remove_member", "pid"), &M2Client::guild_remove_member); ClassDB::bind_method(D_METHOD("guild_offer", "amount"), &M2Client::guild_offer); + ClassDB::bind_method(D_METHOD("guild_charge_gsp", "amount"), &M2Client::guild_charge_gsp); + ClassDB::bind_method(D_METHOD("guild_change_grade_name", "grade", "name"), + &M2Client::guild_change_grade_name); + ClassDB::bind_method(D_METHOD("guild_change_grade_authority", "grade", "authority"), + &M2Client::guild_change_grade_authority); + ClassDB::bind_method(D_METHOD("guild_change_member_grade", "pid", "grade"), + &M2Client::guild_change_member_grade); + ClassDB::bind_method(D_METHOD("guild_change_member_general", "pid", "enabled"), + &M2Client::guild_change_member_general); + ClassDB::bind_method(D_METHOD("guild_post_comment", "text"), &M2Client::guild_post_comment); + ClassDB::bind_method(D_METHOD("guild_delete_comment", "comment_id"), &M2Client::guild_delete_comment); + ClassDB::bind_method(D_METHOD("guild_refresh_comments"), &M2Client::guild_refresh_comments); + ClassDB::bind_method(D_METHOD("guild_answer_invite", "guild_id", "accept"), + &M2Client::guild_answer_invite); ClassDB::bind_method(D_METHOD("guild_answer_make", "name"), &M2Client::guild_answer_make); + ClassDB::bind_method(D_METHOD("get_guild_comments"), &M2Client::get_guild_comments); ClassDB::bind_method(D_METHOD("get_guild_skill"), &M2Client::get_guild_skill); ClassDB::bind_method(D_METHOD("get_guild_wars"), &M2Client::get_guild_wars); ClassDB::bind_method(D_METHOD("get_guild_war"), &M2Client::get_guild_war); @@ -261,6 +312,9 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("declare_guild_war", "guild_name"), &M2Client::declare_guild_war); ADD_SIGNAL(MethodInfo("guild_skill_changed")); ADD_SIGNAL(MethodInfo("guild_war_changed")); + ADD_SIGNAL(MethodInfo("guild_comments_changed")); + ADD_SIGNAL(MethodInfo("guild_invite_ask", PropertyInfo(Variant::INT, "guild_id"), + PropertyInfo(Variant::STRING, "guild_name"))); ADD_SIGNAL(MethodInfo("guild_war_event", PropertyInfo(Variant::INT, "state"), PropertyInfo(Variant::INT, "opp_guild_id"), PropertyInfo(Variant::STRING, "opp_name"))); ADD_SIGNAL(MethodInfo("guild_war_point", PropertyInfo(Variant::INT, "gain_guild_id"), @@ -290,6 +344,7 @@ void M2Client::_bind_methods() { ADD_SIGNAL(MethodInfo("guild_changed")); ADD_SIGNAL(MethodInfo("guild_make_requested")); ADD_SIGNAL(MethodInfo("refine_ask", PropertyInfo(Variant::DICTIONARY, "info"))); + ADD_SIGNAL(MethodInfo("refine_result", PropertyInfo(Variant::BOOL, "ok"))); ADD_SIGNAL(MethodInfo("ds_window_open")); ADD_SIGNAL(MethodInfo("ds_refine_result", PropertyInfo(Variant::BOOL, "ok"), PropertyInfo(Variant::INT, "sub_type"), PropertyInfo(Variant::INT, "cell"))); @@ -301,6 +356,11 @@ void M2Client::_bind_methods() { ClassDB::bind_method(D_METHOD("get_land_areas"), &M2Client::get_land_areas); ClassDB::bind_method(D_METHOD("get_observers"), &M2Client::get_observers); ClassDB::bind_method(D_METHOD("get_world_markers"), &M2Client::get_world_markers); + ClassDB::bind_method(D_METHOD("is_observer_mode"), &M2Client::is_observer_mode); + ClassDB::bind_method(D_METHOD("get_observer_count"), &M2Client::get_observer_count); + ClassDB::bind_method(D_METHOD("has_mobile_flag"), &M2Client::has_mobile_flag); + ClassDB::bind_method(D_METHOD("combo_skill_enabled"), &M2Client::combo_skill_enabled); + ClassDB::bind_method(D_METHOD("get_stamina_state"), &M2Client::get_stamina_state); ADD_SIGNAL(MethodInfo("warp", PropertyInfo(Variant::VECTOR3, "pos"), PropertyInfo(Variant::BOOL, "same_server"))); ADD_SIGNAL(MethodInfo("time_changed", PropertyInfo(Variant::INT, "server_epoch"))); @@ -367,9 +427,16 @@ void M2Client::net_poll() { if (game) { game->process(); } + if (classic_sess) { + classic_sess->set_now((uint32_t)Time::get_singleton()->get_ticks_msec()); + classic_sess->pump(); + } if (mark) { mark->process(); } + if (classic_mark) { + classic_mark->process(); + } } void M2Client::connect_to_server(const String &auth_host, int auth_port, const String &g_host, @@ -388,10 +455,31 @@ void M2Client::connect_to_server(const String &auth_host, int auth_port, const S have_cfg = true; suspended = false; + // MT_PROTOCOL=classic -> 40250 backend: direct connect to the game host, + // with the same post-login feature surface as the shared M2Client API. + if (OS::get_singleton()->get_environment("MT_PROTOCOL") == "classic") { + classic_sess = std::make_unique(); + classic_list_emitted = false; + classic_last_stage = -1; + classic_last_empire = -1; + shop_open_seen = false; + mall_open_seen = false; + last_game_phase = -1; + if (!classic_sess->connect(std::string(g_host.utf8().get_data()), (uint16_t)g_port, + std::string(id.utf8().get_data()), std::string(pw.utf8().get_data()))) { + emit_signal("login_failed", String(classic_sess->last_error().c_str())); + set_stage(Stage::Failed); + classic_sess.reset(); + return; + } + set_stage(Stage::GameConnect); + return; + } + auth = std::make_unique(std::string(id.utf8().get_data()), std::string(pw.utf8().get_data())); char_list_emitted = false; - last_auth_state = last_game_state = last_game_phase = -1; + last_auth_state = last_game_state = last_game_phase = last_game_empire = -1; if (!auth->connect(std::string(auth_host.utf8().get_data()), (uint16_t)auth_port)) { emit_signal("login_failed", String(auth->last_error().c_str())); @@ -411,20 +499,55 @@ void M2Client::disconnect_from_server() { game->disconnect(); game.reset(); } + if (classic_sess) { + classic_sess->disconnect(); + classic_sess.reset(); + } + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + shop_open_seen = false; + mall_open_seen = false; + selected_pid = 0; if (stage != Stage::Idle) { set_stage(Stage::Idle); } } bool M2Client::select_character(int index) { + if (classic_sess) { + const bool ok = classic_sess->select_char(index); + if (ok && index >= 0 && index < (int)classic_sess->char_slots().size()) { + selected_pid = classic_sess->char_slots()[index].id; + } + return ok; + } if (!game) { return false; } - return game->select_character(index); + const bool ok = game->select_character(index); + if (ok) { + for (const auto &slot : game->chars()) { + if (slot.index == index) { + selected_pid = slot.id; + break; + } + } + } + return ok; } bool M2Client::create_character(int slot, const godot::String &name, int job, int shape, int con, int intel, int str, int dex) { + if (classic_sess) { + return classic_sess->create_character(slot, std::string(name.utf8().get_data()), job, shape, + con, intel, str, dex); + } if (!game) { return false; } @@ -433,6 +556,9 @@ bool M2Client::create_character(int slot, const godot::String &name, int job, in } bool M2Client::delete_character(int slot, const godot::String &private_code) { + if (classic_sess) { + return classic_sess->delete_character(slot, std::string(private_code.utf8().get_data())); + } if (!game) { return false; } @@ -440,6 +566,9 @@ bool M2Client::delete_character(int slot, const godot::String &private_code) { } bool M2Client::change_name(int slot, const godot::String &name) { + if (classic_sess) { + return classic_sess->change_name(slot, std::string(name.utf8().get_data())); + } if (!game) { return false; } @@ -447,18 +576,59 @@ bool M2Client::change_name(int slot, const godot::String &name) { } int M2Client::get_empire() const { + if (classic_sess) { + return (int)classic_sess->parser().empire(); + } return game ? (int)game->empire() : 0; } +bool M2Client::select_empire(int empire) { + if (empire < 1 || empire > 3) { + return false; + } + if (classic_sess) { + return classic_sess->send_empire((uint8_t)empire); + } + return game && game->phase() == mtnet::PHASE_SELECT && game->send_empire((uint8_t)empire); +} + int M2Client::get_slot_count() const { + if (classic_sess) { + return classic_sess->parser().slot_count() > 0 ? classic_sess->parser().slot_count() + : mtnet::classic::PLAYER_PER_ACCOUNT; + } return game ? game->slot_count() : mtnet::PLAYER_PER_ACCOUNT4; } godot::Array M2Client::build_char_list() const { Array list; - if (!game) { + if (classic_sess) { + const auto &slots = classic_sess->char_slots(); + for (int i = 0; i < (int)slots.size(); ++i) { + const auto &c = slots[i]; + Dictionary d; + d["index"] = i; + d["id"] = (int64_t)c.id; + d["name"] = String::utf8(c.name.c_str()); + d["job"] = (int)c.job; + d["level"] = (int)c.level; + d["x"] = c.x; + d["y"] = c.y; + d["guild_id"] = (int64_t)c.guild_id; + d["guild_name"] = String::utf8(c.guild_name.c_str()); + d["play_minutes"] = (int)c.play_minutes; + d["st"] = (int)c.st; + d["ht"] = (int)c.ht; + d["dx"] = (int)c.dx; + d["iq"] = (int)c.iq; + d["main_part"] = (int)c.main_part; + d["hair_part"] = (int)c.hair_part; + d["change_name"] = c.change_name; + list.push_back(d); + } return list; } + if (!game) return list; for (const auto &c : game->chars()) { Dictionary d; d["index"] = c.index; @@ -477,6 +647,7 @@ godot::Array M2Client::build_char_list() const { d["iq"] = c.iq; d["main_part"] = c.main_part; d["hair_part"] = c.hair_part; + d["change_name"] = c.change_name; list.push_back(d); } return list; @@ -485,50 +656,72 @@ godot::Array M2Client::build_char_list() const { // --- in-game intents --- bool M2Client::move(int func, int arg, double rot_deg, int x, int y) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } double r = std::fmod(rot_deg, 360.0); if (r < 0.0) { r += 360.0; } - uint8_t rot = (uint8_t)(r / 5.0); // client wire form: degrees / 5 uint32_t t = (uint32_t)Time::get_singleton()->get_ticks_msec(); + if (classic_sess) { + return classic_sess->send_move((uint8_t)func, (uint8_t)arg, (float)r, (int32_t)x, + (int32_t)y, t); + } + if (!game) { + return false; + } + uint8_t rot = (uint8_t)(r / 5.0); // client wire form: degrees / 5 return game->send_move((uint8_t)func, (uint8_t)arg, rot, (int32_t)x, (int32_t)y, t); } bool M2Client::character_position(int position) { - if (!game || !is_in_game() || position < 0 || position > 255) { + if (!is_in_game() || position < 0 || position > 255) { return false; } - return game->send_character_position((uint8_t)position); + if (classic_sess) { + return classic_sess->send_character_position((uint8_t)position); + } + return game && game->send_character_position((uint8_t)position); } bool M2Client::request_warp() { + if (classic_sess) { + return is_in_game() && classic_sess->send_request_warp(); + } return game && is_in_game() && game->send_warp(); } bool M2Client::fishing(double rot_deg) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } double r = std::fmod(rot_deg, 360.0); if (r < 0.0) { r += 360.0; } + if (classic_sess) { + return classic_sess->send_fishing((uint8_t)(r / 5.0)); + } + if (!game) return false; return game->send_fishing((uint8_t)(r / 5.0)); } bool M2Client::request_dungeon() { + if (classic_sess) { + return is_in_game() && classic_sess->send_dungeon(); + } return game && is_in_game() && game->send_dungeon(); } bool M2Client::sync_positions(const Array &positions) { - if (!game || !is_in_game() || positions.is_empty() || positions.size() > 16) { + if (!is_in_game() || positions.is_empty() || positions.size() > 16) { return false; } + std::vector classic_elements; std::vector elements; - elements.reserve(positions.size()); + if (classic_sess) classic_elements.reserve(positions.size()); + else elements.reserve(positions.size()); for (int i = 0; i < positions.size(); ++i) { Variant value = positions[i]; if (value.get_type() != Variant::DICTIONARY) { @@ -545,33 +738,49 @@ bool M2Client::sync_positions(const Array &positions) { y < INT32_MIN || y > INT32_MAX) { return false; } - elements.push_back({(uint32_t)vid, (int32_t)x, (int32_t)y}); + if (classic_sess) classic_elements.push_back({(uint32_t)vid, (int32_t)x, (int32_t)y}); + else elements.push_back({(uint32_t)vid, (int32_t)x, (int32_t)y}); } + if (classic_sess) return classic_sess->send_sync_positions(classic_elements); + if (!game) return false; return game->send_sync_positions(elements); } bool M2Client::attack(int motion, int victim_vid) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_attack((uint8_t)motion, (uint32_t)victim_vid); + if (classic_sess) { + return classic_sess->send_attack((uint8_t)motion, (uint32_t)victim_vid); + } + return game && game->send_attack((uint8_t)motion, (uint32_t)victim_vid); } bool M2Client::set_target(int victim_vid) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_target((uint32_t)victim_vid); + if (classic_sess) { + return classic_sess->send_target((uint32_t)victim_vid); + } + return game && game->send_target((uint32_t)victim_vid); } bool M2Client::say(int type, const String &text) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_chat((uint8_t)type, std::string(text.utf8().get_data())); + if (classic_sess) { + return classic_sess->send_chat((uint8_t)type, std::string(text.utf8().get_data())); + } + return game && game->send_chat((uint8_t)type, std::string(text.utf8().get_data())); } bool M2Client::whisper(const String &to, const String &text) { + if (classic_sess) { + return is_in_game() && classic_sess->send_whisper(std::string(to.utf8().get_data()), + std::string(text.utf8().get_data())); + } if (!game || !is_in_game()) { return false; } @@ -585,7 +794,13 @@ bool M2Client::cast_skill(int motion_idx, double rot_deg, int x, int y) { } bool M2Client::use_skill(int skill_id, int target_vid) { - if (!game || !is_in_game() || skill_id <= 0) { + if (!is_in_game() || skill_id <= 0) { + return false; + } + if (classic_sess) { + return classic_sess->send_use_skill((uint32_t)skill_id, (uint32_t)target_vid); + } + if (!game) { return false; } if (target_vid > 0) { @@ -607,16 +822,20 @@ bool M2Client::use_skill(int skill_id, int target_vid) { } bool M2Client::shoot(int skill_id) { - if (!game || !is_in_game() || skill_id < 0 || skill_id > 255) { + if (!is_in_game() || skill_id < 0 || skill_id > 255) { return false; } + if (classic_sess) return classic_sess->send_shoot((uint8_t)skill_id); + if (!game) return false; return game->send_shoot((uint8_t)skill_id); } bool M2Client::add_fly_targeting(int target_vid, int x, int y) { - if (!game || !is_in_game() || target_vid < 0) { + if (!is_in_game() || target_vid < 0) { return false; } + if (classic_sess) return classic_sess->send_add_fly_targeting((uint32_t)target_vid, (int32_t)x, (int32_t)y); + if (!game) return false; return game->send_add_fly_targeting((uint32_t)target_vid, (int32_t)x, (int32_t)y); } @@ -625,21 +844,23 @@ bool M2Client::skill_up(int skill_id) { } int M2Client::get_skill_group() const { - return game ? (int)game->world().skill_group() : 0; + const mtnet::EntityStore *world = active_world(); + return world ? (int)world->skill_group() : 0; } Array M2Client::get_skills() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int id = 0; id < mtnet::SKILL_MAX_NUM; ++id) { - int lv = game->world().skill_level(id); + int lv = world->skill_level(id); if (lv > 0) { Dictionary d; d["id"] = id; d["level"] = lv; - d["master"] = (int)game->world().skill_master(id); // 0..3 + d["master"] = (int)world->skill_master(id); // 0..3 out.push_back(d); } } @@ -648,11 +869,12 @@ Array M2Client::get_skills() const { Array M2Client::get_quickslots() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int pos = 0; pos < mtnet::QUICKSLOT_MAX_NUM; ++pos) { - mtnet::QuickSlot qs = game->world().quickslot(pos); + mtnet::QuickSlot qs = world->quickslot(pos); if (qs.type == 0) { continue; } @@ -666,61 +888,87 @@ Array M2Client::get_quickslots() const { } bool M2Client::quickslot_add(int pos, int type, int ref) { - if (!game || !is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM || + if (!is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM || type < 1 || type > 4 || ref < 0 || ref > 255) { return false; } + if (classic_sess) return classic_sess->send_quickslot_add((uint8_t)pos, (uint8_t)type, (uint8_t)ref); + if (!game) return false; return game->send_quickslot_add((uint8_t)pos, (uint8_t)type, (uint8_t)ref); } bool M2Client::quickslot_del(int pos) { - if (!game || !is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM) { + if (!is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM) { return false; } + if (classic_sess) return classic_sess->send_quickslot_del((uint8_t)pos); + if (!game) return false; return game->send_quickslot_del((uint8_t)pos); } bool M2Client::quickslot_swap(int pos, int change_pos) { - if (!game || !is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM || + if (!is_in_game() || pos < 0 || pos >= mtnet::QUICKSLOT_MAX_NUM || change_pos < 0 || change_pos >= mtnet::QUICKSLOT_MAX_NUM) { return false; } + if (classic_sess) return classic_sess->send_quickslot_swap((uint8_t)pos, (uint8_t)change_pos); + if (!game) return false; return game->send_quickslot_swap((uint8_t)pos, (uint8_t)change_pos); } bool M2Client::click_npc(int vid) { - return game && is_in_game() && game->send_on_click((uint32_t)vid); + if (!is_in_game()) { + return false; + } + if (classic_sess) { + return classic_sess->send_click_npc((uint32_t)vid); + } + return game && game->send_on_click((uint32_t)vid); } bool M2Client::script_answer(int answer) { - return game && is_in_game() && game->send_script_answer((uint8_t)answer); + if (!is_in_game()) { + return false; + } + if (classic_sess) { + return classic_sess->send_script_answer((uint8_t)answer); + } + return game && game->send_script_answer((uint8_t)answer); } bool M2Client::script_button(int idx) { + if (classic_sess) return is_in_game() && idx >= 0 && classic_sess->send_script_button((uint32_t)idx); return game && is_in_game() && game->send_script_button((uint32_t)idx); } bool M2Client::script_select_item(int selection) { - if (!game || !is_in_game() || selection < 0) { + if (!is_in_game() || selection < 0) { return false; } + if (classic_sess) return classic_sess->send_script_select_item((uint32_t)selection); + if (!game) return false; return game->send_script_select_item((uint32_t)selection); } bool M2Client::quest_input(const String &text) { + if (classic_sess) return is_in_game() && classic_sess->send_quest_input(std::string(text.utf8().get_data())); return game && is_in_game() && game->send_quest_input(std::string(text.utf8().get_data())); } bool M2Client::quest_confirm(bool yes, int request_pid) { + if (classic_sess) return is_in_game() && request_pid >= 0 && + classic_sess->send_quest_confirm(yes, (uint32_t)request_pid); return game && is_in_game() && request_pid >= 0 && game->send_quest_confirm(yes, (uint32_t)request_pid); } bool M2Client::quest_cancel() { + if (classic_sess) return is_in_game() && classic_sess->send_quest_cancel(); return game && is_in_game() && game->send_quest_cancel(); } Array M2Client::get_quests() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (uint16_t idx : game->world().quest_indices()) { - const mtnet::QuestInfo *q = game->world().quest(idx); + for (uint16_t idx : world->quest_indices()) { + const mtnet::QuestInfo *q = world->quest(idx); if (!q) { continue; } @@ -741,34 +989,44 @@ Array M2Client::get_quests() const { // --- P8 social / shop / storage --- bool M2Client::party_invite(int vid) { + if (classic_sess) return is_in_game() && vid > 0 && classic_sess->send_party_invite((uint32_t)vid); return game && is_in_game() && game->send_party_invite((uint32_t)vid); } bool M2Client::party_answer(int leader_pid, bool accept) { + if (classic_sess) return is_in_game() && leader_pid > 0 && + classic_sess->send_party_answer((uint32_t)leader_pid, accept); return game && is_in_game() && game->send_party_invite_answer((uint32_t)leader_pid, accept); } bool M2Client::party_leave(int pid) { + if (classic_sess) return is_in_game() && pid > 0 && classic_sess->send_party_remove((uint32_t)pid); return game && is_in_game() && pid >= 0 && game->send_party_remove((uint32_t)pid); } bool M2Client::party_use_skill(int skill_index, int target_vid) { - if (!game || !is_in_game() || skill_index < 0 || skill_index > 255 || target_vid < 0) { + if (!is_in_game() || skill_index < 0 || skill_index > 255 || target_vid < 0) { return false; } + if (classic_sess) return classic_sess->send_party_use_skill((uint8_t)skill_index, (uint32_t)target_vid); + if (!game) return false; return game->send_party_use_skill((uint8_t)skill_index, (uint32_t)target_vid); } bool M2Client::party_set_distribute(int mode) { + if (classic_sess) return is_in_game() && mode >= 0 && mode <= 255 && + classic_sess->send_party_parameter((uint8_t)mode); return game && is_in_game() && game->send_party_parameter((uint8_t)mode); } bool M2Client::party_set_state(int pid, int role, bool on) { - return game && is_in_game() && pid >= 0 - && game->send_party_set_state((uint32_t)pid, (uint8_t)role, on ? 1 : 0); + if (!is_in_game() || pid <= 0 || role < 0 || role > 255) return false; + if (classic_sess) return classic_sess->send_party_set_state((uint32_t)pid, (uint8_t)role, on); + return game && game->send_party_set_state((uint32_t)pid, (uint8_t)role, on ? 1 : 0); } Array M2Client::get_party() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (uint32_t pid : game->world().party_pids()) { - const mtnet::PartyMember *m = game->world().party_member(pid); + for (uint32_t pid : world->party_pids()) { + const mtnet::PartyMember *m = world->party_member(pid); if (!m) { continue; } @@ -789,24 +1047,46 @@ Array M2Client::get_party() const { return out; } int M2Client::get_party_distribute_mode() const { - return game ? (int)game->world().party_distribute_mode() : 0; + const mtnet::EntityStore *world = active_world(); + return world ? (int)world->party_distribute_mode() : 0; } bool M2Client::add_friend(const String &name) { + if (classic_sess) { + return is_in_game() && classic_sess->send_friend_add(std::string(name.utf8().get_data())); + } return game && is_in_game() && game->send_friend_add(std::string(name.utf8().get_data())); } bool M2Client::remove_friend(const String &name) { + if (classic_sess) { + return is_in_game() && classic_sess->send_friend_remove(std::string(name.utf8().get_data())); + } return game && is_in_game() && game->send_friend_remove(std::string(name.utf8().get_data())); } +bool M2Client::friend_answer(const String &name, bool accept) { + if (!is_in_game() || name.is_empty()) { + return false; + } + // 40250 handles messenger invitations through the normal slash-command + // channel: `/messenger_auth y|n `, not a CG subheader. + const std::string command = "/messenger_auth " + std::string(accept ? "y " : "n ") + + std::string(name.utf8().get_data()); + if (classic_sess) { + return classic_sess->send_chat(mtnet::CHAT_TYPE_TALKING, command); + } + return game && game->send_chat(mtnet::CHAT_TYPE_TALKING, command); +} Array M2Client::get_friends() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (const auto &f : game->world().friends()) { + for (const auto &f : world->friends()) { Dictionary d; d["name"] = String::utf8(f.name.c_str()); d["online"] = f.online; + d["mobile"] = f.mobile; out.push_back(d); } return out; @@ -814,8 +1094,9 @@ Array M2Client::get_friends() const { Dictionary M2Client::get_lover() const { Dictionary d; - if (!game) return d; - const mtnet::LoverInfo &lover = game->world().lover(); + const mtnet::EntityStore *world = active_world(); + if (!world) return d; + const mtnet::LoverInfo &lover = world->lover(); d["valid"] = lover.valid; d["name"] = String::utf8(lover.name.c_str()); d["love_point"] = (int)lover.love_point; @@ -823,17 +1104,23 @@ Dictionary M2Client::get_lover() const { } bool M2Client::shop_buy(int pos, int count) { + if (classic_sess) return is_in_game() && pos >= 0 && pos <= 255 && + classic_sess->send_shop_buy((uint8_t)pos, (uint8_t)(count < 1 ? 1 : count)); return game && is_in_game() && game->send_shop_buy((uint8_t)pos, (uint8_t)(count < 1 ? 1 : count)); } bool M2Client::shop_sell(int inv_cell, int count) { + if (classic_sess) return is_in_game() && inv_cell >= 0 && inv_cell <= 255 && + classic_sess->send_shop_sell((uint8_t)inv_cell, (uint8_t)(count < 1 ? 1 : count)); return game && is_in_game() && game->send_shop_sell((uint8_t)inv_cell, (uint8_t)(count < 1 ? 1 : count)); } bool M2Client::shop_close() { + if (classic_sess) return is_in_game() && classic_sess->send_shop_close(); return game && is_in_game() && game->send_shop_close(); } bool M2Client::is_shop_open() const { - return game && game->world().shop_open(); + const mtnet::EntityStore *world = active_world(); + return world && world->shop_open(); } static Dictionary shop_entry_dict(const mtnet::ShopEntry &s) { Dictionary d; @@ -846,10 +1133,11 @@ static Dictionary shop_entry_dict(const mtnet::ShopEntry &s) { Array M2Client::get_shop_items() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (const auto &s : game->world().shop_items()) { + for (const auto &s : world->shop_items()) { out.push_back(shop_entry_dict(s)); } return out; @@ -857,12 +1145,14 @@ Array M2Client::get_shop_items() const { Dictionary M2Client::get_shop() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *wp = active_world(); + if (!wp) { return d; } - const mtnet::EntityStore &w = game->world(); + const mtnet::EntityStore &w = *wp; d["vid"] = (int)w.shop_vid(); d["open"] = w.shop_open(); + d["selling_price"] = w.shop_selling_price(); Array tabs; if (!w.shop_tabs().empty()) { // SHOP_GC_START_EX — one entry per shelf, each with its name + coin_type. @@ -890,27 +1180,47 @@ Dictionary M2Client::get_shop() const { } bool M2Client::exchange_start(int vid) { + if (classic_sess) { + return is_in_game() && classic_sess->send_exchange_start((uint32_t)vid); + } return game && is_in_game() && game->send_exchange_start((uint32_t)vid); } bool M2Client::exchange_add_item(int inv_window, int inv_cell, int display_pos) { + if (classic_sess) { + return is_in_game() && classic_sess->send_exchange_item_add((uint8_t)inv_window, + (uint16_t)inv_cell, (uint8_t)display_pos); + } return game && is_in_game() && game->send_exchange_item_add((uint8_t)inv_window, (uint16_t)inv_cell, (uint8_t)display_pos); } bool M2Client::exchange_add_gold(int gold) { + if (gold < 0) { + return false; + } + if (classic_sess) { + return is_in_game() && classic_sess->send_exchange_gold((uint32_t)gold); + } return game && is_in_game() && game->send_exchange_gold((uint32_t)gold); } bool M2Client::exchange_accept() { + if (classic_sess) { + return is_in_game() && classic_sess->send_exchange_accept(); + } return game && is_in_game() && game->send_exchange_accept(); } bool M2Client::exchange_cancel() { + if (classic_sess) { + return is_in_game() && classic_sess->send_exchange_cancel(); + } return game && is_in_game() && game->send_exchange_cancel(); } Dictionary M2Client::get_exchange() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - const mtnet::ExchangeState &x = game->world().exchange(); + const mtnet::ExchangeState &x = world->exchange(); d["active"] = x.active; d["partner_vid"] = (int)x.partner_vid; d["self_gold"] = (int64_t)x.self_gold; @@ -937,33 +1247,49 @@ Dictionary M2Client::get_exchange() const { } bool M2Client::safebox_checkin(int safe_pos, int inv_window, int inv_cell) { + if (classic_sess) { + return is_in_game() && classic_sess->send_safebox_checkin((uint8_t)safe_pos, + (uint8_t)inv_window, (uint16_t)inv_cell); + } return game && is_in_game() && game->send_safebox_checkin((uint8_t)safe_pos, (uint8_t)inv_window, (uint16_t)inv_cell); } bool M2Client::safebox_checkout(int safe_pos, int inv_window, int inv_cell) { + if (classic_sess) { + return is_in_game() && classic_sess->send_safebox_checkout((uint8_t)safe_pos, + (uint8_t)inv_window, (uint16_t)inv_cell); + } return game && is_in_game() && game->send_safebox_checkout((uint8_t)safe_pos, (uint8_t)inv_window, (uint16_t)inv_cell); } bool M2Client::safebox_move(int from_cell, int to_cell, int count) { + if (classic_sess) { + return is_in_game() && classic_sess->send_safebox_move((uint16_t)from_cell, + (uint16_t)to_cell, (uint8_t)(count < 1 ? 1 : count)); + } return game && is_in_game() && game->send_safebox_move((uint16_t)from_cell, (uint16_t)to_cell, (uint8_t)(count < 1 ? 1 : count)); } bool M2Client::is_safebox_open() const { - return game && game->world().safebox_open(); + const mtnet::EntityStore *world = active_world(); + return world && world->safebox_open(); } int M2Client::get_safebox_size() const { - return game ? game->world().safebox_size() : 0; + const mtnet::EntityStore *world = active_world(); + return world ? world->safebox_size() : 0; } int M2Client::get_safebox_gold() const { - return game ? (int)game->world().safebox_gold() : 0; + const mtnet::EntityStore *world = active_world(); + return world ? (int)world->safebox_gold() : 0; } Array M2Client::get_safebox_items() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int c = 0; c < mtnet::SAFEBOX_MAX_NUM; ++c) { - const mtnet::Item &it = game->world().safebox_slot(c); + const mtnet::Item &it = world->safebox_slot(c); if (it.empty()) { continue; } @@ -979,18 +1305,21 @@ Array M2Client::get_safebox_items() const { // --- item-mall (창고몰) --- bool M2Client::is_mall_open() const { - return game && game->world().mall_open(); + const mtnet::EntityStore *world = active_world(); + return world && world->mall_open(); } int M2Client::get_mall_size() const { - return game ? game->world().mall_size() : 0; + const mtnet::EntityStore *world = active_world(); + return world ? world->mall_size() : 0; } Array M2Client::get_mall_items() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int c = 0; c < mtnet::MALL_MAX_NUM; ++c) { - const mtnet::Item &it = game->world().mall_slot(c); + const mtnet::Item &it = world->mall_slot(c); if (it.empty()) { continue; } @@ -1003,16 +1332,50 @@ Array M2Client::get_mall_items() const { return out; } bool M2Client::mall_checkout(int mall_pos, int inv_window, int inv_cell) { + if (classic_sess) { + return is_in_game() && classic_sess->send_mall_checkout((uint8_t)mall_pos, + (uint8_t)inv_window, (uint16_t)inv_cell); + } return game && game->send_mall_checkout((uint8_t)mall_pos, (uint8_t)inv_window, (uint16_t)inv_cell); } +bool M2Client::safebox_password(const String &password) { + if (password.is_empty() || password.length() > 6) { + return false; + } + return say(0, String("/safebox_password ") + password); +} + +bool M2Client::mall_password(const String &password) { + if (password.is_empty() || password.length() > 6) { + return false; + } + return say(0, String("/mall_password ") + password); +} + // --- private (PC) shop --- bool M2Client::open_private_shop(const godot::String &sign, const godot::Array &items) { - if (!game) { + if (!game && !classic_sess) { return false; } + if (classic_sess) { + std::vector v; + v.reserve(items.size()); + for (int i = 0; i < items.size() && i < 39; ++i) { + Dictionary d = items[i]; + mtnet::classic::CGMyShopItem e{}; + e.vnum = (uint32_t)(int64_t)d.get("vnum", 0); + e.count = (uint8_t)(int)d.get("count", 1); + e.pos = {(uint8_t)(int)d.get("inv_window", mtnet::WINDOW_INVENTORY), + (uint16_t)(int)d.get("inv_cell", 0)}; + e.price = (uint32_t)(int64_t)d.get("price", 0); + e.display_pos = (uint8_t)(int)d.get("display_pos", i); + v.push_back(e); + } + return classic_sess->send_private_shop(std::string(sign.utf8().get_data()), v); + } std::vector v; for (int i = 0; i < items.size(); ++i) { Dictionary d = items[i]; @@ -1028,6 +1391,12 @@ bool M2Client::open_private_shop(const godot::String &sign, const godot::Array & return game->send_open_private_shop(std::string(sign.utf8().get_data()), v); } bool M2Client::close_private_shop() { + if (classic_sess) { + // 40250 toggles a player's own shop in CInputMain::MyShop: receiving a + // CG_MYSHOP head while GetMyShop() is set closes it. CG_SHOP/END only + // stops an NPC-shop visit and leaves a private shop open. + return is_in_game() && classic_sess->send_private_shop("", {}); + } return game && game->send_close_private_shop(); } @@ -1035,10 +1404,11 @@ bool M2Client::close_private_shop() { Dictionary M2Client::get_cube() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - const mtnet::EntityStore::CubeState &c = game->world().cube(); + const mtnet::EntityStore::CubeState &c = world->cube(); d["open"] = c.open; d["npc_vnum"] = (int)c.npc_vnum; d["need_gold"] = (int64_t)c.need_gold; @@ -1078,23 +1448,55 @@ Dictionary M2Client::get_cube() const { return d; } bool M2Client::cube_make(int result_index) { + if (classic_sess) return is_in_game() && classic_sess->send_cube_make(result_index); return game && game->send_cube_make(result_index); } bool M2Client::cube_request_result_list(int npc_vnum) { + if (classic_sess) return is_in_game() && classic_sess->send_cube_result_list(npc_vnum); return game && game->send_cube_result_list((uint32_t)npc_vnum); } bool M2Client::cube_request_materials(int start_index, int count) { + if (classic_sess) return is_in_game() && classic_sess->send_cube_materials(start_index, count); return game && game->send_cube_material_info(start_index, count); } +bool M2Client::cube_open() { + if (classic_sess) return is_in_game() && classic_sess->send_cube_open(); + return game && is_in_game() && game->send_chat(mtnet::CHAT_TYPE_COMMAND, "/cube open"); +} +bool M2Client::cube_close() { + if (classic_sess) return is_in_game() && classic_sess->send_cube_close(); + return game && is_in_game() && game->send_chat(mtnet::CHAT_TYPE_COMMAND, "/cube close"); +} +bool M2Client::cube_list() { + if (classic_sess) return is_in_game() && classic_sess->send_cube_list(); + return game && is_in_game() && game->send_chat(mtnet::CHAT_TYPE_COMMAND, "/cube list"); +} +bool M2Client::cube_add_item(int cube_index, int inventory_index) { + if (classic_sess) { + return is_in_game() && classic_sess->send_cube_add_item(cube_index, inventory_index); + } + if (!game || !is_in_game() || cube_index < 0 || cube_index >= 24 || + inventory_index < 0 || inventory_index > 255) { + return false; + } + return game->send_chat(mtnet::CHAT_TYPE_COMMAND, "/cube add " + std::to_string(cube_index) + + " " + std::to_string(inventory_index)); +} +bool M2Client::cube_delete_item(int cube_index) { + if (classic_sess) return is_in_game() && classic_sess->send_cube_delete_item(cube_index); + return game && is_in_game() && cube_index >= 0 && cube_index < 24 && + game->send_chat(mtnet::CHAT_TYPE_COMMAND, "/cube delete " + std::to_string(cube_index)); +} // --- guild / refine --- Dictionary M2Client::get_guild() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - const mtnet::GuildState &g = game->world().guild(); + const mtnet::GuildState &g = world->guild(); d["in_guild"] = g.in_guild; d["id"] = (int)g.id; d["name"] = String::utf8(g.name.c_str()); @@ -1109,10 +1511,11 @@ Dictionary M2Client::get_guild() const { } Array M2Client::get_guild_members() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (const auto &m : game->world().guild_members()) { + for (const auto &m : world->guild_members()) { Dictionary d; d["pid"] = (int)m.pid; d["name"] = String::utf8(m.name.c_str()); @@ -1121,17 +1524,19 @@ Array M2Client::get_guild_members() const { d["level"] = (int)m.level; d["offer"] = (int64_t)m.offer; d["general"] = m.is_general; + d["online"] = m.online; out.push_back(d); } return out; } Array M2Client::get_guild_grades() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int i = 0; i < 16; ++i) { - const mtnet::GuildGrade &g = game->world().guild_grade(i); + const mtnet::GuildGrade &g = world->guild_grade(i); Dictionary d; d["name"] = String::utf8(g.name.c_str()); d["auth"] = (int)g.auth; @@ -1140,28 +1545,111 @@ Array M2Client::get_guild_grades() const { return out; } bool M2Client::guild_add_member(int vid) { + if (classic_sess) return is_in_game() && vid > 0 && + classic_sess->send_guild_u32(mtnet::classic::GUILD_CG_ADD_MEMBER, (uint32_t)vid); return game && is_in_game() && game->send_guild_sub_u32(mtnet::GUILD_CG_ADD_MEMBER, (uint32_t)vid); } bool M2Client::guild_remove_member(int pid) { + if (classic_sess) return is_in_game() && pid > 0 && + classic_sess->send_guild_u32(mtnet::classic::GUILD_CG_REMOVE_MEMBER, (uint32_t)pid); return game && is_in_game() && game->send_guild_sub_u32(mtnet::GUILD_CG_REMOVE_MEMBER, (uint32_t)pid); } bool M2Client::guild_offer(int amount) { + if (classic_sess) return is_in_game() && amount >= 0 && + classic_sess->send_guild_u32(mtnet::classic::GUILD_CG_OFFER, (uint32_t)amount); return game && is_in_game() && game->send_guild_sub_u32(mtnet::GUILD_CG_OFFER, (uint32_t)amount); } -bool M2Client::guild_answer_make(const String &name) { +bool M2Client::guild_charge_gsp(int amount) { + if (amount < 0) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_i32(mtnet::classic::GUILD_CG_CHARGE_GSP, (int32_t)amount); return game && is_in_game() && - game->send_guild_answer_make(std::string(name.utf8().get_data())); + game->send_guild_sub_i32(mtnet::GUILD_CG_CHARGE_GSP, (int32_t)amount); +} +bool M2Client::guild_change_grade_name(int grade, const String &name) { + const std::string value = name.utf8().get_data(); + if (grade < 1 || grade >= 16 || value.empty() || + value.size() > mtnet::classic::GUILD_GRADE_NAME_MAX_LEN) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_grade_name((uint8_t)grade, value); + return game && is_in_game() && game->send_guild_grade_name((uint8_t)grade, value); +} +bool M2Client::guild_change_grade_authority(int grade, int authority) { + if (grade < 1 || grade >= 16 || authority < 0 || authority > 255) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_grade_authority((uint8_t)grade, (uint8_t)authority); + return game && is_in_game() && + game->send_guild_grade_authority((uint8_t)grade, (uint8_t)authority); +} +bool M2Client::guild_change_member_grade(int pid, int grade) { + if (pid <= 0 || grade < 1 || grade >= 16) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_member_grade((uint32_t)pid, (uint8_t)grade); + return game && is_in_game() && + game->send_guild_member_grade((uint32_t)pid, (uint8_t)grade); +} +bool M2Client::guild_change_member_general(int pid, bool enabled) { + if (pid <= 0) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_member_general((uint32_t)pid, enabled); + return game && is_in_game() && + game->send_guild_member_general((uint32_t)pid, enabled); +} +bool M2Client::guild_post_comment(const String &text) { + const std::string comment = text.utf8().get_data(); + if (comment.empty() || comment.size() + 1 > mtnet::classic::GUILD_COMMENT_MAX_LEN) return false; + if (classic_sess) return is_in_game() && classic_sess->send_guild_comment(comment); + return game && is_in_game() && game->send_guild_comment(comment); +} +bool M2Client::guild_delete_comment(int comment_id) { + if (comment_id <= 0) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_u32(mtnet::classic::GUILD_CG_DELETE_COMMENT, + (uint32_t)comment_id); + return game && is_in_game() && + game->send_guild_sub_u32(mtnet::GUILD_CG_DELETE_COMMENT, (uint32_t)comment_id); +} +bool M2Client::guild_refresh_comments() { + if (classic_sess) return is_in_game() && + classic_sess->send_guild_sub(mtnet::classic::GUILD_CG_REFRESH_COMMENT); + return game && is_in_game() && game->send_guild_sub(mtnet::GUILD_CG_REFRESH_COMMENT); +} +bool M2Client::guild_answer_invite(int guild_id, bool accept) { + if (guild_id <= 0) return false; + if (classic_sess) return is_in_game() && + classic_sess->send_guild_invite_answer((uint32_t)guild_id, accept); + return game && is_in_game() && game->send_guild_invite_answer((uint32_t)guild_id, accept); +} +bool M2Client::guild_answer_make(const String &name) { + if (classic_sess) return is_in_game() && + classic_sess->send_guild_answer_make(std::string(name.utf8().get_data())); + return game && is_in_game() && + game->send_guild_answer_make(std::string(name.utf8().get_data())); +} +Array M2Client::get_guild_comments() const { + Array out; + const mtnet::EntityStore *world = active_world(); + if (!world) return out; + for (const auto &comment : world->guild_comments()) { + Dictionary d; + d["id"] = (int64_t)comment.id; + d["name"] = String::utf8(comment.name.c_str()); + d["content"] = String::utf8(comment.content.c_str()); + out.push_back(d); + } + return out; } // --- guild war / guild skill --- Dictionary M2Client::get_guild_skill() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - const mtnet::GuildSkillState &s = game->world().guild_skill(); + const mtnet::GuildSkillState &s = world->guild_skill(); d["valid"] = s.valid; d["skill_point"] = (int)s.skill_point; d["guild_point"] = (int)s.guild_point; @@ -1176,10 +1664,11 @@ Dictionary M2Client::get_guild_skill() const { Array M2Client::get_guild_wars() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - const mtnet::EntityStore &w = game->world(); + const mtnet::EntityStore &w = *world; for (const auto &p : w.guild_wars()) { Dictionary d; d["src"] = (int64_t)p.src; @@ -1193,22 +1682,26 @@ Array M2Client::get_guild_wars() const { Dictionary M2Client::get_guild_war() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - const mtnet::GuildWarStatus &g = game->world().guild_war(); + const mtnet::GuildWarStatus &g = world->guild_war(); d["opp_guild_id"] = (int64_t)g.opp_guild_id; - d["opp_name"] = String::utf8(game->world().guild_name(g.opp_guild_id).c_str()); + d["opp_name"] = String::utf8(world->guild_name(g.opp_guild_id).c_str()); d["type"] = (int)g.type; d["state"] = (int)g.state; return d; } String M2Client::get_guild_name(int guild_id) const { - return game ? String::utf8(game->world().guild_name((uint32_t)guild_id).c_str()) : String(); + const mtnet::EntityStore *world = active_world(); + return world ? String::utf8(world->guild_name((uint32_t)guild_id).c_str()) : String(); } bool M2Client::use_guild_skill(int skill_vnum, int target_vid) { + if (classic_sess) return is_in_game() && skill_vnum >= 0 && target_vid >= 0 && + classic_sess->send_guild_skill((uint32_t)skill_vnum, (uint32_t)target_vid); return game && is_in_game() && game->send_guild_use_skill((uint32_t)skill_vnum, (uint32_t)target_vid); } @@ -1220,13 +1713,34 @@ bool M2Client::declare_guild_war(const String &guild_name) { // --- guild marks --- bool M2Client::download_guild_marks(const String &host, int port) { - if (!game || port <= 0 || port > 65535 || host.is_empty()) { + if ((!game && !classic_sess) || port <= 0 || port > 65535 || host.is_empty()) { return false; } mark_host = host; mark_port = port; mark_ready = false; - mark = std::make_unique(game->mark_handle(), game->mark_random_key()); + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + if (classic_sess) { + classic_mark = std::make_unique( + classic_sess->parser().handle(), classic_sess->parser().random_key()); + if (!classic_mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { + UtilityFunctions::push_warning("classic guild-mark connect failed: ", + String(classic_mark->last_error().c_str())); + classic_mark.reset(); + return false; + } + return true; + } + const uint32_t handle = game->mark_handle(); + const uint32_t random_key = game->mark_random_key(); + mark = std::make_unique(handle, random_key); if (!mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { UtilityFunctions::push_warning("guild-mark connect failed: ", String(mark->last_error().c_str())); @@ -1237,14 +1751,36 @@ bool M2Client::download_guild_marks(const String &host, int port) { } bool M2Client::download_guild_symbol(const String &host, int port, int guild_id) { - if (!game || port <= 0 || port > 65535 || host.is_empty() || guild_id <= 0) { + if ((!game && !classic_sess) || port <= 0 || port > 65535 || host.is_empty() || guild_id <= 0) { return false; } symbol_guild_id = 0; symbol_data.clear(); mark_host = host; mark_port = port; - mark = std::make_unique(game->mark_handle(), game->mark_random_key()); + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + if (classic_sess) { + classic_mark = std::make_unique( + classic_sess->parser().handle(), classic_sess->parser().random_key()); + classic_mark->set_download_symbol((uint32_t)guild_id); + if (!classic_mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { + UtilityFunctions::push_warning("classic guild-symbol download connect failed: ", + String(classic_mark->last_error().c_str())); + classic_mark.reset(); + return false; + } + return true; + } + const uint32_t handle = game->mark_handle(); + const uint32_t random_key = game->mark_random_key(); + mark = std::make_unique(handle, random_key); mark->set_download_symbol((uint32_t)guild_id); if (!mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { UtilityFunctions::push_warning("guild-symbol download connect failed: ", @@ -1276,7 +1812,7 @@ Dictionary M2Client::get_mark_server() const { } bool M2Client::upload_guild_mark(const String &host, int port, int guild_id, const Ref &img) { - if (!game || port <= 0 || port > 65535 || host.is_empty() || img.is_null()) { + if ((!game && !classic_sess) || port <= 0 || port > 65535 || host.is_empty() || img.is_null()) { return false; } Ref rgba = img; @@ -1296,7 +1832,29 @@ bool M2Client::upload_guild_mark(const String &host, int port, int guild_id, con } mark_host = host; mark_port = port; - mark = std::make_unique(game->mark_handle(), game->mark_random_key()); + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + if (classic_sess) { + classic_mark = std::make_unique( + classic_sess->parser().handle(), classic_sess->parser().random_key()); + classic_mark->set_upload_mark((uint32_t)guild_id, (const uint32_t *)b.ptr()); + if (!classic_mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { + UtilityFunctions::push_warning("classic guild-mark upload connect failed: ", + String(classic_mark->last_error().c_str())); + classic_mark.reset(); + return false; + } + return true; + } + const uint32_t handle = game->mark_handle(); + const uint32_t random_key = game->mark_random_key(); + mark = std::make_unique(handle, random_key); mark->set_upload_mark((uint32_t)guild_id, (const uint32_t *)b.ptr()); if (!mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { UtilityFunctions::push_warning("guild-mark upload connect failed: ", @@ -1309,13 +1867,35 @@ bool M2Client::upload_guild_mark(const String &host, int port, int guild_id, con bool M2Client::upload_guild_symbol(const String &host, int port, int guild_id, const PackedByteArray &file_bytes) { - if (!game || port <= 0 || port > 65535 || host.is_empty() || file_bytes.is_empty()) { + if ((!game && !classic_sess) || port <= 0 || port > 65535 || host.is_empty() || file_bytes.is_empty()) { return false; } std::vector bytes(file_bytes.ptr(), file_bytes.ptr() + file_bytes.size()); mark_host = host; mark_port = port; - mark = std::make_unique(game->mark_handle(), game->mark_random_key()); + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + if (classic_sess) { + classic_mark = std::make_unique( + classic_sess->parser().handle(), classic_sess->parser().random_key()); + classic_mark->set_upload_symbol((uint32_t)guild_id, std::move(bytes)); + if (!classic_mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { + UtilityFunctions::push_warning("classic guild-symbol upload connect failed: ", + String(classic_mark->last_error().c_str())); + classic_mark.reset(); + return false; + } + return true; + } + const uint32_t handle = game->mark_handle(); + const uint32_t random_key = game->mark_random_key(); + mark = std::make_unique(handle, random_key); mark->set_upload_symbol((uint32_t)guild_id, std::move(bytes)); if (!mark->connect(std::string(host.utf8().get_data()), (uint16_t)port)) { UtilityFunctions::push_warning("guild-symbol upload connect failed: ", @@ -1405,12 +1985,61 @@ void M2Client::pump_mark() { emit_signal("guild_marks_ready", mark_ready ? (int)mark_store->mark_count() : 0); } } + +void M2Client::pump_classic_mark() { + classic_mark->process(); + const bool offline = classic_mark->state() == + mtnet::classic::ClassicStream::State::Offline; + + if (classic_mark->mode() == mtnet::classic::ClassicMarkClient::Mode::DownloadSymbol) { + if (classic_mark->complete()) { + symbol_guild_id = classic_mark->symbol_guild_id(); + symbol_data = classic_mark->symbol_data(); + PackedByteArray b = get_guild_symbol(); + classic_mark.reset(); + emit_signal("guild_symbol_ready", (int64_t)symbol_guild_id, b); + } else if (offline) { + classic_mark.reset(); + } + return; + } + + if (classic_mark->mode() != mtnet::classic::ClassicMarkClient::Mode::Download) { + if (classic_mark->upload_done() || (offline && classic_mark->upload_sent())) { + classic_mark.reset(); + emit_signal("guild_mark_uploaded", true); + } else if (offline) { + classic_mark.reset(); + emit_signal("guild_mark_uploaded", false); + } + return; + } + + if (classic_mark->complete()) { + mark_store = std::make_unique(classic_mark->marks()); + mark_ready = true; + size_t n = mark_store->mark_count(); + classic_mark.reset(); + emit_signal("guild_marks_ready", (int)n); + return; + } + if (offline) { + // Keep successfully received blocks if the stock mark server closes + // immediately after the final block instead of sending PHASE_CLOSE. + mark_store = std::make_unique(classic_mark->marks()); + mark_ready = mark_store->mark_count() > 0; + classic_mark.reset(); + emit_signal("guild_marks_ready", mark_ready ? (int)mark_store->mark_count() : 0); + } +} bool M2Client::refine(int pos, int type) { + if (classic_sess) return is_in_game() && pos >= 0 && pos < mtnet::INVENTORY_MAX_NUM && + type >= 0 && type <= 255 && classic_sess->send_refine((uint8_t)pos, (uint8_t)type); return game && is_in_game() && game->send_refine((uint8_t)pos, (uint8_t)type); } bool M2Client::ds_refine(int mode, const Array &cells) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } static const uint8_t kMode[3] = { @@ -1419,6 +2048,18 @@ bool M2Client::ds_refine(int mode, const Array &cells) { if (mode < 0 || mode > 2) { return false; } + if (classic_sess) { + mtnet::classic::ItemPos grid[mtnet::classic::DS_REFINE_GRID_MAX_NUM] = {}; + int n = (int)cells.size(); + if (n > mtnet::classic::DS_REFINE_GRID_MAX_NUM) n = mtnet::classic::DS_REFINE_GRID_MAX_NUM; + for (int i = 0; i < n; ++i) { + int cell = (int)cells[i]; + if (cell < 0 || cell > 0xffff) return false; + grid[i] = {(uint8_t)mtnet::WINDOW_INVENTORY, (uint16_t)cell}; + } + return classic_sess->send_dragon_soul_refine(kMode[mode], grid, n); + } + if (!game) return false; mtnet::ItemPos grid[mtnet::DS_REFINE_WINDOW_MAX_NUM] = {}; int n = (int)cells.size(); if (n > mtnet::DS_REFINE_WINDOW_MAX_NUM) { @@ -1434,11 +2075,12 @@ bool M2Client::ds_refine(int mode, const Array &cells) { Array M2Client::get_dragon_souls() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int c = 0; c < mtnet::DRAGON_SOUL_MAX_NUM; ++c) { - const mtnet::Item &it = game->world().dragon_soul_slot(c); + const mtnet::Item &it = world->dragon_soul_slot(c); if (it.vnum == 0) { continue; } @@ -1454,17 +2096,20 @@ Array M2Client::get_dragon_souls() const { // --- P9 world systems --- int M2Client::get_channel() const { - return game ? game->world().channel() : 0; + const auto *world = active_world(); + return world ? world->channel() : 0; } int64_t M2Client::get_server_time() const { - return game ? game->world().server_time() : 0; + const auto *world = active_world(); + return world ? world->server_time() : 0; } Array M2Client::get_npc_marks() const { Array out; - if (!game) { + const auto *world = active_world(); + if (!world) { return out; } - for (const auto &m : game->world().npc_marks()) { + for (const auto &m : world->npc_marks()) { Dictionary d; d["type"] = (int)m.type; d["vnum"] = (int)m.vnum; @@ -1477,8 +2122,9 @@ Array M2Client::get_npc_marks() const { } Array M2Client::get_land_areas() const { Array out; - if (!game) return out; - for (const auto &a : game->world().land_areas()) { + const auto *world = active_world(); + if (!world) return out; + for (const auto &a : world->land_areas()) { Dictionary d; d["id"] = (int)a.id; d["guild_id"] = (int)a.guild_id; @@ -1492,8 +2138,9 @@ Array M2Client::get_land_areas() const { } Array M2Client::get_observers() const { Array out; - if (!game) return out; - for (const auto &o : game->world().observers()) { + const auto *world = active_world(); + if (!world) return out; + for (const auto &o : world->observers()) { Dictionary d; d["vid"] = (int)o.vid; fmt::m2coord::Vec3 g = fmt::m2coord::position_to_godot(o.x, o.y, 0); @@ -1502,12 +2149,38 @@ Array M2Client::get_observers() const { } return out; } +bool M2Client::is_observer_mode() const { + const auto *world = active_world(); + return world && world->observer_mode(); +} +int M2Client::get_observer_count() const { + const auto *world = active_world(); + return world ? world->observer_count() : 0; +} +bool M2Client::has_mobile_flag() const { + const auto *world = active_world(); + return world && world->mobile_flag(); +} +bool M2Client::combo_skill_enabled() const { + const auto *world = active_world(); + return world && world->combo_skill_flag(); +} +Dictionary M2Client::get_stamina_state() const { + Dictionary d; + const auto *world = active_world(); + if (!world) return d; + d["consuming"] = world->stamina_consuming(); + d["per_sec"] = (int)world->stamina_per_sec(); + d["current"] = (int)world->current_stamina(); + return d; +} Array M2Client::get_world_markers() const { Array out; - if (!game) { + const auto *world = active_world(); + if (!world) { return out; } - for (const auto &m : game->world().markers()) { + for (const auto &m : world->markers()) { Dictionary d; d["id"] = (int)m.id; d["name"] = String::utf8(m.name.c_str()); @@ -1528,6 +2201,7 @@ static Dictionary entity_dict(const mtnet::Entity &e) { d["race"] = (int)e.race; d["ch_type"] = (int)e.ch_type; // 0 PC, 1 NPC, 2 MONSTER, ... d["name"] = String::utf8(e.name.c_str()); + d["shop_sign"] = String::utf8(e.shop_sign.c_str()); d["is_main"] = e.is_main; d["func"] = (int)e.func; d["position"] = (int)e.position; @@ -1562,21 +2236,30 @@ static Dictionary entity_dict(const mtnet::Entity &e) { return d; } +const mtnet::EntityStore *M2Client::active_world() const { + if (classic_sess) { + return &classic_sess->world(); + } + return game ? &game->world() : nullptr; +} + Dictionary M2Client::get_entity(int vid) const { - if (!game) { + const mtnet::EntityStore *w = active_world(); + if (!w) { return Dictionary(); } - const mtnet::Entity *e = game->world().get((uint32_t)vid); + const mtnet::Entity *e = w->get((uint32_t)vid); return e ? entity_dict(*e) : Dictionary(); } Array M2Client::get_entities() const { Array out; - if (!game) { + const mtnet::EntityStore *w = active_world(); + if (!w) { return out; } - for (uint32_t vid : game->world().vids()) { - if (const mtnet::Entity *e = game->world().get(vid)) { + for (uint32_t vid : w->vids()) { + if (const mtnet::Entity *e = w->get(vid)) { out.push_back(entity_dict(*e)); } } @@ -1584,19 +2267,27 @@ Array M2Client::get_entities() const { } int M2Client::get_main_vid() const { - return game ? (int)game->world().main_vid() : 0; + const mtnet::EntityStore *w = active_world(); + return w ? (int)w->main_vid() : 0; +} + +int M2Client::get_main_pid() const { + return (int)selected_pid; } Dictionary M2Client::get_points() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *w = active_world(); + if (!w) { return d; } - const mtnet::PlayerPoints &p = game->world().points(); + const mtnet::PlayerPoints &p = w->points(); d["hp"] = p.hp(); d["max_hp"] = p.max_hp(); d["sp"] = p.sp(); d["max_sp"] = p.max_sp(); + d["stamina"] = p.stamina(); + d["max_stamina"] = p.max_stamina(); d["level"] = p.level(); // exp values overflow int32 at high level on live servers — surface unsigned. d["exp"] = (int64_t)(uint32_t)p.exp(); @@ -1615,11 +2306,12 @@ Dictionary M2Client::get_points() const { Dictionary M2Client::get_target() const { Dictionary d; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return d; } - d["vid"] = (int)game->world().target_vid(); - d["hp_percent"] = (int)game->world().target_hp_pct(); + d["vid"] = (int)world->target_vid(); + d["hp_percent"] = (int)world->target_hp_pct(); return d; } @@ -1635,10 +2327,11 @@ static Dictionary affect_dict(const mtnet::Affect &a) { Array M2Client::get_affects() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (const auto &a : game->world().affects()) { + for (const auto &a : world->affects()) { out.push_back(affect_dict(a)); } return out; @@ -1647,40 +2340,71 @@ Array M2Client::get_affects() const { // --- items --- bool M2Client::move_item(int fw, int fc, int tw, int tc, int count) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_item_move((uint8_t)fw, (uint16_t)fc, (uint8_t)tw, (uint16_t)tc, (uint8_t)count); + if (classic_sess) { + return classic_sess->send_item_move((uint8_t)fw, (uint16_t)fc, (uint8_t)tw, (uint16_t)tc, + (uint8_t)count); + } + return game && game->send_item_move((uint8_t)fw, (uint16_t)fc, (uint8_t)tw, (uint16_t)tc, + (uint8_t)count); } bool M2Client::use_item(int window, int cell) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_item_use((uint8_t)window, (uint16_t)cell); + if (classic_sess) { + return classic_sess->send_item_use((uint8_t)window, (uint16_t)cell); + } + return game && game->send_item_use((uint8_t)window, (uint16_t)cell); } bool M2Client::drop_item(int window, int cell, int gold) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_item_drop((uint8_t)window, (uint16_t)cell, (uint32_t)gold); + if (classic_sess) { + return classic_sess->send_item_drop((uint8_t)window, (uint16_t)cell, (uint32_t)gold, 0); + } + return game && game->send_item_drop((uint8_t)window, (uint16_t)cell, (uint32_t)gold); } bool M2Client::drop_item_count(int window, int cell, int gold, int count) { - if (!game || !is_in_game() || count < 1 || count > 255) return false; - return game->send_item_drop2((uint8_t)window, (uint16_t)cell, (uint32_t)gold, (uint8_t)count); + if (!is_in_game() || count < 1 || count > 255) return false; + if (classic_sess) { + return classic_sess->send_item_drop((uint8_t)window, (uint16_t)cell, (uint32_t)gold, + (uint8_t)count); + } + return game && game->send_item_drop2((uint8_t)window, (uint16_t)cell, (uint32_t)gold, + (uint8_t)count); } bool M2Client::use_item_to_item(int sw, int sc, int tw, int tc) { - if (!game || !is_in_game()) return false; + if (!is_in_game()) return false; + if (classic_sess) { + if (sw < 0 || sw > 255 || tw < 0 || tw > 255 || sc < 0 || sc > 0xffff || tc < 0 || tc > 0xffff) + return false; + return classic_sess->send_item_use_to_item((uint8_t)sw, (uint16_t)sc, (uint8_t)tw, (uint16_t)tc); + } + if (!game) return false; return game->send_item_use_to_item((uint8_t)sw, (uint16_t)sc, (uint8_t)tw, (uint16_t)tc); } bool M2Client::give_item(int target_vid, int window, int cell, int count) { - if (!game || !is_in_game() || target_vid <= 0 || count < 1 || count > 255) return false; + if (!is_in_game() || target_vid <= 0 || count < 1 || count > 255) return false; + if (classic_sess) { + if (window < 0 || window > 255 || cell < 0 || cell > 0xffff) return false; + return classic_sess->send_item_give((uint32_t)target_vid, (uint8_t)window, (uint16_t)cell, + (uint8_t)count); + } + if (!game) return false; return game->send_give_item((uint32_t)target_vid, (uint8_t)window, (uint16_t)cell, (uint8_t)count); } bool M2Client::pickup_item(int ground_vid) { - if (!game || !is_in_game()) { + if (!is_in_game()) { return false; } - return game->send_item_pickup((uint32_t)ground_vid); + if (classic_sess) { + return classic_sess->send_item_pickup((uint32_t)ground_vid); + } + return game && game->send_item_pickup((uint32_t)ground_vid); } static Dictionary item_dict(const mtnet::Item &it) { @@ -1710,11 +2434,12 @@ static Dictionary item_dict(const mtnet::Item &it) { Array M2Client::get_inventory() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int c = 0; c < mtnet::INVENTORY_MAX_NUM; ++c) { - const mtnet::Item &it = game->world().inv_slot(c); + const mtnet::Item &it = world->inv_slot(c); if (it.empty()) { continue; } @@ -1727,11 +2452,12 @@ Array M2Client::get_inventory() const { Array M2Client::get_equipment() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } for (int w = 0; w < mtnet::WEAR_MAX_NUM; ++w) { - Dictionary d = item_dict(game->world().equip_slot(w)); + Dictionary d = item_dict(world->equip_slot(w)); d["wear"] = w; out.push_back(d); } @@ -1740,9 +2466,10 @@ Array M2Client::get_equipment() const { Array M2Client::get_belt_inventory() const { Array out; - if (!game) return out; + const auto *world = active_world(); + if (!world) return out; for (int c = 0; c < mtnet::BELT_INVENTORY_MAX_NUM; ++c) { - const mtnet::Item &it = game->world().belt_slot(c); + const mtnet::Item &it = world->belt_slot(c); if (it.empty()) continue; Dictionary d = item_dict(it); d["cell"] = c; @@ -1753,8 +2480,9 @@ Array M2Client::get_belt_inventory() const { Array M2Client::get_view_equipment(int vid) const { Array out; - if (!game || vid <= 0) return out; - const mtnet::ViewedEquipment *view = game->world().viewed_equipment((uint32_t)vid); + const auto *world = active_world(); + if (!world || vid <= 0) return out; + const mtnet::ViewedEquipment *view = world->viewed_equipment((uint32_t)vid); if (!view) return out; for (int wear = 0; wear < mtnet::VIEW_EQUIP_WEAR_MAX_NUM; ++wear) { Dictionary d = item_dict(view->items[wear]); @@ -1765,19 +2493,21 @@ Array M2Client::get_view_equipment(int vid) const { } Dictionary M2Client::get_item(int window, int cell) const { - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return Dictionary(); } - return item_dict(game->world().item_slot((uint8_t)window, cell)); + return item_dict(world->item_slot((uint8_t)window, cell)); } Array M2Client::get_ground_items() const { Array out; - if (!game) { + const mtnet::EntityStore *world = active_world(); + if (!world) { return out; } - for (uint32_t vid : game->world().ground_vids()) { - const mtnet::GroundItem *g = game->world().ground(vid); + for (uint32_t vid : world->ground_vids()) { + const mtnet::GroundItem *g = world->ground(vid); if (!g) { continue; } @@ -1794,8 +2524,9 @@ Array M2Client::get_ground_items() const { Array M2Client::get_pvp_relations() const { Array out; - if (!game) return out; - for (const auto &p : game->world().pvp_relations()) { + const auto *world = active_world(); + if (!world) return out; + for (const auto &p : world->pvp_relations()) { Dictionary d; d["src_vid"] = (int)p.src_vid; d["dst_vid"] = (int)p.dst_vid; @@ -1805,6 +2536,20 @@ Array M2Client::get_pvp_relations() const { return out; } +Dictionary M2Client::get_duel() const { + Dictionary out; + const auto *world = active_world(); + if (!world) return out; + Array opponents; + for (uint32_t vid : world->duel_opponents()) { + opponents.push_back((int)vid); + } + out["active"] = !world->duel_opponents().empty(); + out["cannot_attack"] = world->duel_cannot_attack(); + out["opponents"] = opponents; + return out; +} + void M2Client::_process(double) { if (Engine::get_singleton()->is_editor_hint()) { return; @@ -1812,6 +2557,9 @@ void M2Client::_process(double) { if (suspended) { return; // backgrounded — don't touch the socket } + if (classic_sess) { + pump_classic(); + } if (auth) { pump_auth(); } @@ -1821,6 +2569,9 @@ void M2Client::_process(double) { if (mark) { pump_mark(); } + if (classic_mark) { + pump_classic_mark(); + } } void M2Client::_notification(int what) { @@ -1875,6 +2626,37 @@ bool M2Client::reconnect() { // Tear down the current game connection and reconnect to `host:port` reusing the // stored login_key (cross-server GC_WARP, or a fast reconnect). void M2Client::warp_to_game_server(const String &host, int port) { + if (classic_sess) { + classic_sess->disconnect(); + classic_sess.reset(); + if (mark) { + mark->disconnect(); + mark.reset(); + } + if (classic_mark) { + classic_mark->disconnect(); + classic_mark.reset(); + } + game_host = host; + game_port = port; + classic_list_emitted = false; + classic_last_stage = -1; + classic_last_empire = -1; + shop_open_seen = false; + mall_open_seen = false; + dead_seen.clear(); + classic_sess = std::make_unique(); + if (!classic_sess->connect(std::string(host.utf8().get_data()), (uint16_t)port, + std::string(cfg_id.utf8().get_data()), std::string(cfg_pw.utf8().get_data()))) { + emit_signal("login_failed", String(classic_sess->last_error().c_str())); + set_stage(Stage::Failed); + classic_sess.reset(); + return; + } + last_game_phase = -1; + set_stage(Stage::GameConnect); + return; + } if (last_login_key == 0) { return; } @@ -1900,10 +2682,441 @@ void M2Client::warp_to_game_server(const String &host, int port) { return; } last_game_phase = -1; - last_game_state = -1; + last_game_state = last_game_empire = -1; set_stage(Stage::GameConnect); } +void M2Client::pump_classic() { + using St = mtnet::INetSession::Stage; + + classic_sess->set_now((uint32_t)Time::get_singleton()->get_ticks_msec()); + classic_sess->pump(); + const int empire = (int)classic_sess->parser().empire(); + if (empire != classic_last_empire) { + classic_last_empire = empire; + emit_signal("empire_changed", empire); + } + + // stage -> phase_changed / stage_changed / char_list / entered_game + int st = (int)classic_sess->stage(); + if (st != classic_last_stage) { + classic_last_stage = st; + static const char *pn[] = {"close", "handshake", "login", "select", + "loading", "in_game", "failed"}; + int idx = 0; + switch (classic_sess->stage()) { + case St::Offline: idx = 0; break; + case St::Connecting: idx = 1; break; + case St::LoggingIn: idx = 2; break; + case St::CharSelect: idx = 3; break; + case St::Loading: idx = 4; break; + case St::InGame: idx = 5; break; + case St::Failed: idx = 6; break; + } + emit_signal("phase_changed", String(pn[idx])); + if (classic_sess->stage() == St::Failed && stage != Stage::Failed) { + emit_signal("login_failed", String(classic_sess->last_error().c_str())); + set_stage(Stage::Failed); + } else if (classic_sess->stage() == St::LoggingIn && stage == Stage::GameConnect) { + set_stage(Stage::GameLogin); + } + } + + if (!classic_list_emitted && classic_sess->parser().char_list_ready() && + classic_sess->stage() == St::CharSelect) { + classic_list_emitted = true; + emit_signal("char_list", build_char_list()); + } + for (const auto &ev : classic_sess->parser().drain_char_events()) { + using CE = mtnet::classic::ClassicParser::CharEvent; + switch (ev.kind) { + case CE::CreateOk: + emit_signal("char_list", build_char_list()); + emit_signal("char_created", ev.slot); + break; + case CE::CreateFail: + emit_signal("char_create_failed", ev.fail_type); + break; + case CE::DeleteOk: + emit_signal("char_list", build_char_list()); + emit_signal("char_deleted", ev.slot); + break; + case CE::DeleteFail: + emit_signal("char_delete_failed"); + break; + } + } + for (const auto &ev : classic_sess->parser().drain_name_events()) { + emit_signal("char_list", build_char_list()); + emit_signal("char_name_changed", (int64_t)ev.pid, String::utf8(ev.name.c_str())); + } + for (int i = 0, n = classic_sess->parser().drain_guild_make_requests(); i < n; ++i) { + emit_signal("guild_make_requested"); + } + + if (classic_sess->in_game() && stage != Stage::InGame) { + set_stage(Stage::InGame); + emit_signal("entered_game"); + } + + if (classic_sess->in_game()) { + mtnet::EntityStore &w = classic_sess->world(); + // set_now()/tick() already run inside pump(); mirror the deltas the + // classic parser currently produces (grows with classic_parser). + for (const auto &c : w.drain_changes()) { + switch (c.kind) { + case mtnet::EntityStore::ChangeKind::Spawn: + if (const mtnet::Entity *e = w.get(c.vid)) { + emit_signal("entity_spawned", entity_dict(*e)); + } + break; + case mtnet::EntityStore::ChangeKind::Despawn: + dead_seen.erase(c.vid); + emit_signal("entity_despawned", (int)c.vid); + break; + case mtnet::EntityStore::ChangeKind::Move: + emit_signal("entity_moved", (int)c.vid); + break; + case mtnet::EntityStore::ChangeKind::MainSet: + emit_signal("entity_main_set", (int)c.vid); + break; + case mtnet::EntityStore::ChangeKind::Info: + if (const mtnet::Entity *e = w.get(c.vid)) { + emit_signal("entity_info", (int)c.vid, entity_dict(*e)); + } + break; + } + } + for (const auto &m : w.drain_chat()) { + if (m.type == mtnet::CHAT_TYPE_WHISPER) { + emit_signal("whisper_received", (int)m.sub, String::utf8(m.from.c_str()), + String::utf8(m.text.c_str())); + } else { + emit_signal("chat", (int)m.type, (int)m.vid, String::utf8(m.text.c_str())); + } + } + for (uint32_t vid : w.drain_vitals()) { + emit_signal("vitals_changed", (int)vid); + const mtnet::Entity *e = w.get(vid); + if (e && e->dead && !dead_seen.count(vid)) { + dead_seen.insert(vid); + emit_signal("entity_dead", (int)vid); + } + } + if (w.take_points_dirty()) { + emit_signal("points_changed", get_points()); + } + for (const auto &ic : w.drain_inv()) { + emit_signal("inventory_changed", (int)ic.window, (int)ic.cell); + } + for (const auto &gc : w.drain_ground()) { + if (gc.added) { + const mtnet::GroundItem *g = w.ground(gc.vid); + if (g) { + Dictionary d; + d["vid"] = (int)g->vid; + d["vnum"] = (int)g->vnum; + d["owner"] = String::utf8(g->owner.c_str()); + fmt::m2coord::Vec3 gp = fmt::m2coord::position_to_godot(g->x, g->y, g->z); + d["pos"] = Vector3(gp.x, gp.y, gp.z); + emit_signal("ground_item_added", d); + } + } else { + emit_signal("ground_item_removed", (int)gc.vid); + } + } + for (const auto &p : w.drain_pvp_changes()) { + emit_signal("pvp_changed", (int)p.src_vid, (int)p.dst_vid, (int)p.mode); + } + if (w.take_duel_started()) { + emit_signal("duel_changed", get_duel()); + emit_signal("duel_started"); + } + for (const auto &mo : w.drain_motions()) { + emit_signal("motion", (int)mo.vid, (int)mo.victim_vid, (int)mo.motion); + } + for (const auto &dm : w.drain_dig_motions()) { + emit_signal("dig_motion", (int)dm.vid, (int)dm.target_vid, (int)dm.count); + } + for (const auto &fe : w.drain_fishing_events()) { + emit_signal("fishing_event", (int)fe.subheader, (int)fe.info, (int)fe.dir); + } + for (const auto &de : w.drain_dungeon_events()) { + emit_signal("dungeon_event", (int)de.subheader, (int)de.x, (int)de.y, + de.has_destination); + } + for (const auto &oe : w.drain_observer_events()) { + fmt::m2coord::Vec3 g = fmt::m2coord::position_to_godot(oe.x, oe.y, 0); + emit_signal("observer_event", (int)oe.kind, (int)oe.vid, Vector2(g.x, g.z)); + } + for (const auto &ec : w.drain_effect_cues()) { + emit_signal("effect_cue", (int)ec.vid, String::utf8(ec.file.c_str()), + (int)ec.special); + } + for (const auto &fc : w.drain_fly_cues()) { + emit_signal("fly_cue", (int)fc.type, (int)fc.start_vid, (int)fc.end_vid); + } + for (const auto &tc : w.drain_fly_target_cues()) { + emit_signal("fly_targeting", (int)tc.shooter_vid, (int)tc.target_vid, + Vector2((float)tc.x, (float)tc.y), tc.append); + } + for (const auto &d : w.drain_damage()) { + emit_signal("damage", (int)d.vid, (int)d.amount, (int)d.flag); + } + for (uint32_t vid : w.drain_mount_changes()) { + emit_signal("mount_changed", (int)vid); + } + if (w.take_target_dirty()) { + emit_signal("target_info", (int)w.target_vid(), (int)w.target_hp_pct()); + } + if (w.skills_dirty()) { + emit_signal("skills_changed"); + } + if (w.skill_group_dirty()) { + emit_signal("skill_group_changed", (int)w.skill_group()); + } + for (int sk : w.drain_cooldown_ends()) { + emit_signal("skill_cooldown_end", sk); + } + if (w.quickslots_dirty()) { + emit_signal("quickslots_changed"); + } + for (const auto &ac : w.drain_affects()) { + if (ac.added) { + for (const auto &a : w.affects()) { + if (a.type == ac.type) { + emit_signal("affect_added", affect_dict(a)); + break; + } + } + } else { + emit_signal("affect_removed", (int)ac.type); + } + } + for (const auto &ie : w.drain_item_events()) { + if (ie.kind == mtnet::ItemEvent::Get) { + emit_signal("item_picked_up", (int)ie.vnum, (int)ie.count, + String::utf8(ie.from.c_str())); + } else { + emit_signal("item_used", (int)ie.vnum); + } + } + for (uint32_t leader : w.drain_party_invites()) { + emit_signal("party_invite_ask", (int)leader); + } + for (const auto &ev : w.drain_server_commands()) { + switch (ev.kind) { + case mtnet::ServerCommandEvent::PartyRequestDenied: + emit_signal("party_request_denied"); + break; + case mtnet::ServerCommandEvent::SafeboxPasswordRequired: + emit_signal("safebox_password_required"); + break; + case mtnet::ServerCommandEvent::SafeboxWrongPassword: + emit_signal("safebox_wrong_password"); + break; + case mtnet::ServerCommandEvent::MallPasswordRequired: + emit_signal("mall_password_required"); + break; + case mtnet::ServerCommandEvent::RefineSucceeded: + emit_signal("refine_result", true); + break; + case mtnet::ServerCommandEvent::RefineFailed: + emit_signal("refine_result", false); + break; + case mtnet::ServerCommandEvent::PrivateShopOpenRequested: + emit_signal("private_shop_open_requested"); + break; + case mtnet::ServerCommandEvent::MyShopPrice: + emit_signal("my_shop_price_list", (int)ev.value, (int)ev.value2); + break; + case mtnet::ServerCommandEvent::BlockModeChanged: + emit_signal("block_mode_changed", (int)ev.value); + break; + case mtnet::ServerCommandEvent::ObserverModeChanged: + emit_signal("observer_mode_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::ObserverCountChanged: + emit_signal("observer_count_changed", (int)ev.value); + break; + case mtnet::ServerCommandEvent::StoneDetected: + emit_signal("stone_detected", (int)ev.value, (int)ev.value2, ev.value3); + break; + case mtnet::ServerCommandEvent::StaminaStarted: + emit_signal("stamina_changed", (int)ev.value2, (int)ev.value, true); + break; + case mtnet::ServerCommandEvent::StaminaStopped: + emit_signal("stamina_changed", (int)ev.value2, 0, false); + break; + case mtnet::ServerCommandEvent::MobileFlagChanged: + emit_signal("mobile_flag_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::MobileAuthRequired: + emit_signal("mobile_auth_required"); + break; + case mtnet::ServerCommandEvent::ComboChanged: + emit_signal("combo_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::GiftAvailable: + emit_signal("gift_available"); + break; + } + } + if (w.party_dirty()) { + emit_signal("party_changed"); + } + bool shop_was_open = shop_open_seen; + if (w.shop_dirty()) { + shop_open_seen = w.shop_open(); + if (shop_open_seen && !shop_was_open) { + emit_signal("shop_opened", (int)w.shop_vid()); + } else if (!shop_open_seen && shop_was_open) { + emit_signal("shop_closed"); + } + } + for (const auto &err : w.drain_shop_errors()) { + emit_signal("shop_error", String::utf8(err.c_str())); + } + for (const auto &sc : w.drain_scripts()) { + emit_signal("script_dialog", (int)sc.skin, String::utf8(sc.text.c_str())); + } + for (const auto &cc : w.drain_confirms()) { + emit_signal("quest_confirm_ask", String::utf8(cc.msg.c_str()), (int)cc.timeout, + (int)cc.request_pid); + } + for (uint16_t qi : w.drain_quest_changes()) { + emit_signal("quest_info", (int)qi); + } + if (w.friends_dirty()) { + emit_signal("friends_changed"); + } + for (const auto &name : w.drain_friend_invites()) { + emit_signal("friend_invite_ask", String::utf8(name.c_str())); + } + if (w.take_lover_dirty()) { + emit_signal("lover_changed", get_lover()); + } + if (w.exchange_dirty()) { + emit_signal("exchange_changed"); + } + if (w.safebox_dirty()) { + emit_signal("safebox_changed"); + } + if (w.mall_dirty()) { + bool mall_now = w.mall_open(); + if (mall_now && !mall_open_seen) { + emit_signal("mall_opened", w.mall_size()); + } + mall_open_seen = mall_now; + emit_signal("mall_changed"); + } + for (const auto &ev : w.drain_cube_events()) { + using CE = mtnet::EntityStore::CubeEvent; + switch (ev) { + case CE::Opened: + emit_signal("cube_opened", (int)w.cube().npc_vnum); + break; + case CE::Closed: + emit_signal("cube_closed"); + break; + case CE::InfoChanged: + emit_signal("cube_changed"); + break; + case CE::Success: { + auto result = w.cube_last_success(); + emit_signal("cube_result", (int)result.vnum, result.count, true); + break; + } + case CE::Fail: + emit_signal("cube_result", 0, 0, false); + break; + } + } + if (w.guild_dirty()) { + emit_signal("guild_changed"); + } + if (w.guild_comments_dirty()) { + emit_signal("guild_comments_changed"); + } + for (const auto &invite : w.drain_guild_invites()) { + emit_signal("guild_invite_ask", (int64_t)invite.guild_id, + String::utf8(invite.guild_name.c_str())); + } + if (w.guild_skill_dirty()) { + emit_signal("guild_skill_changed"); + } + if (w.guild_war_dirty()) { + emit_signal("guild_war_changed"); + } + for (const auto &ev : w.drain_guild_war_events()) { + emit_signal("guild_war_event", (int)ev.state, (int64_t)ev.opp_guild_id, + String::utf8(w.guild_name(ev.opp_guild_id).c_str())); + } + for (const auto &score : w.drain_guild_war_scores()) { + emit_signal("guild_war_point", (int64_t)score.gain_guild_id, + (int64_t)score.opp_guild_id, score.point); + } + for (const auto &rc : w.drain_refine_cues()) { + Dictionary d; + d["type"] = (int)rc.type; + d["pos"] = (int)rc.pos; + d["src_vnum"] = (int)rc.src_vnum; + d["result_vnum"] = (int)rc.result_vnum; + d["cost"] = rc.cost; + d["prob"] = rc.prob; + Array mats; + for (int i = 0; i < rc.material_count && i < 5; ++i) { + if (rc.materials[i].vnum == 0) { + continue; + } + Dictionary mat; + mat["vnum"] = (int)rc.materials[i].vnum; + mat["count"] = rc.materials[i].count; + mats.push_back(mat); + } + d["materials"] = mats; + emit_signal("refine_ask", d); + } + for (const auto &dc : w.drain_ds_cues()) { + if (dc.sub_type == mtnet::DS_SUB_OPEN) { + emit_signal("ds_window_open"); + } else if (dc.sub_type == mtnet::DS_SUB_REFINE_SUCCEED) { + emit_signal("ds_refine_result", true, (int)dc.sub_type, (int)dc.cell); + } else if (dc.sub_type >= mtnet::DS_SUB_REFINE_FAIL && + dc.sub_type <= mtnet::DS_SUB_REFINE_FAIL_TOO_MUCH_MATERIAL) { + emit_signal("ds_refine_result", false, (int)dc.sub_type, (int)dc.cell); + } + } + for (const auto &warp : w.drain_warps()) { + fmt::m2coord::Vec3 g = fmt::m2coord::position_to_godot(warp.x, warp.y, 0); + emit_signal("warp", Vector3(g.x, g.y, g.z), warp.same_server()); + if (!warp.same_server()) { + uint32_t addr = (uint32_t)warp.addr; + char host[16]; + std::snprintf(host, sizeof(host), "%u.%u.%u.%u", addr & 0xFF, + (addr >> 8) & 0xFF, (addr >> 16) & 0xFF, (addr >> 24) & 0xFF); + warp_to_game_server(String(host), warp.port); + return; + } + } + if (w.take_time_dirty()) { + emit_signal("time_changed", (int64_t)w.server_time()); + } + if (w.take_channel_dirty()) { + emit_signal("channel_changed", w.channel()); + } + if (w.take_npc_marks_dirty()) { + emit_signal("npc_marks_changed"); + } + if (w.take_land_dirty()) { + emit_signal("land_areas_changed"); + } + if (w.take_markers_dirty()) { + emit_signal("world_markers_changed"); + } + } +} + void M2Client::pump_auth() { auth->process(); @@ -1947,6 +3160,10 @@ void M2Client::pump_auth() { void M2Client::pump_game() { game->process(); + if (game->empire_seen() && (int)game->empire() != last_game_empire) { + last_game_empire = game->empire(); + emit_signal("empire_changed", (int)game->empire()); + } if ((int)game->phase() != last_game_phase) { last_game_phase = (int)game->phase(); @@ -2157,7 +3374,10 @@ void M2Client::pump_game() { for (const auto &p : w.drain_pvp_changes()) { emit_signal("pvp_changed", (int)p.src_vid, (int)p.dst_vid, (int)p.mode); } - if (w.take_duel_started()) emit_signal("duel_started"); + if (w.take_duel_started()) { + emit_signal("duel_changed", get_duel()); + emit_signal("duel_started"); + } for (const auto &ie : w.drain_item_events()) { if (ie.kind == mtnet::ItemEvent::Get) { emit_signal("item_picked_up", (int)ie.vnum, (int)ie.count, @@ -2170,15 +3390,76 @@ void M2Client::pump_game() { for (uint32_t leader_pid : w.drain_party_invites()) { emit_signal("party_invite_ask", (int)leader_pid); } - if (w.party_dirty()) { + for (const auto &ev : w.drain_server_commands()) { + switch (ev.kind) { + case mtnet::ServerCommandEvent::PartyRequestDenied: + emit_signal("party_request_denied"); + break; + case mtnet::ServerCommandEvent::SafeboxPasswordRequired: + emit_signal("safebox_password_required"); + break; + case mtnet::ServerCommandEvent::SafeboxWrongPassword: + emit_signal("safebox_wrong_password"); + break; + case mtnet::ServerCommandEvent::MallPasswordRequired: + emit_signal("mall_password_required"); + break; + case mtnet::ServerCommandEvent::RefineSucceeded: + emit_signal("refine_result", true); + break; + case mtnet::ServerCommandEvent::RefineFailed: + emit_signal("refine_result", false); + break; + case mtnet::ServerCommandEvent::PrivateShopOpenRequested: + emit_signal("private_shop_open_requested"); + break; + case mtnet::ServerCommandEvent::MyShopPrice: + emit_signal("my_shop_price_list", (int)ev.value, (int)ev.value2); + break; + case mtnet::ServerCommandEvent::BlockModeChanged: + emit_signal("block_mode_changed", (int)ev.value); + break; + case mtnet::ServerCommandEvent::ObserverModeChanged: + emit_signal("observer_mode_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::ObserverCountChanged: + emit_signal("observer_count_changed", (int)ev.value); + break; + case mtnet::ServerCommandEvent::StoneDetected: + emit_signal("stone_detected", (int)ev.value, (int)ev.value2, ev.value3); + break; + case mtnet::ServerCommandEvent::StaminaStarted: + emit_signal("stamina_changed", (int)ev.value2, (int)ev.value, true); + break; + case mtnet::ServerCommandEvent::StaminaStopped: + emit_signal("stamina_changed", (int)ev.value2, 0, false); + break; + case mtnet::ServerCommandEvent::MobileFlagChanged: + emit_signal("mobile_flag_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::MobileAuthRequired: + emit_signal("mobile_auth_required"); + break; + case mtnet::ServerCommandEvent::ComboChanged: + emit_signal("combo_changed", ev.value != 0); + break; + case mtnet::ServerCommandEvent::GiftAvailable: + emit_signal("gift_available"); + break; + } + } + if (w.party_dirty()) { emit_signal("party_changed"); } if (w.take_lover_dirty()) { emit_signal("lover_changed", get_lover()); } - if (w.friends_dirty()) { + if (w.friends_dirty()) { emit_signal("friends_changed"); } + for (const auto &name : w.drain_friend_invites()) { + emit_signal("friend_invite_ask", String::utf8(name.c_str())); + } bool shop_was_open = shop_open_seen; if (w.shop_dirty()) { shop_open_seen = w.shop_open(); @@ -2230,6 +3511,13 @@ void M2Client::pump_game() { if (w.guild_dirty()) { emit_signal("guild_changed"); } + if (w.guild_comments_dirty()) { + emit_signal("guild_comments_changed"); + } + for (const auto &invite : w.drain_guild_invites()) { + emit_signal("guild_invite_ask", (int64_t)invite.guild_id, + String::utf8(invite.guild_name.c_str())); + } if (w.guild_skill_dirty()) { emit_signal("guild_skill_changed"); } diff --git a/extension/src/net/m2_client.h b/extension/src/net/m2_client.h index 81964d98..d9761fd6 100644 --- a/extension/src/net/m2_client.h +++ b/extension/src/net/m2_client.h @@ -31,6 +31,11 @@ class AuthClient; class GameClient; class MarkClient; class MarkImageSet; +class EntityStore; +namespace classic { +class ClassicSession; +class ClassicMarkClient; +} } // namespace mtnet namespace mtgodot { @@ -61,6 +66,9 @@ public: bool change_name(int slot, const godot::String &name); // GC_EMPIRE (0 = server still wants an empire pick before select). int get_empire() const; + // CG_EMPIRE: choose one of the three empires when the account has no empire. + // Both network backends expose the same intent for the character-select UI. + bool select_empire(int empire); // 3 or 4 depending on which GC_LOGIN_SUCCESS the server sent. int get_slot_count() const; @@ -120,6 +128,7 @@ public: // --- P8 messenger / friends --- bool add_friend(const godot::String &name); bool remove_friend(const godot::String &name); + bool friend_answer(const godot::String &name, bool accept); godot::Array get_friends() const; // [{name, online}] godot::Dictionary get_lover() const; // {valid, name, love_point} @@ -147,12 +156,14 @@ public: int get_safebox_size() const; int get_safebox_gold() const; godot::Array get_safebox_items() const; // [{cell, vnum, count}] + bool safebox_password(const godot::String &password); // --- item-mall (창고몰) --- bool is_mall_open() const; int get_mall_size() const; godot::Array get_mall_items() const; // [{cell, vnum, count}] bool mall_checkout(int mall_pos, int inv_window, int inv_cell); + bool mall_password(const godot::String &password); // --- private (PC) shop --- // items: Array of {vnum, count, inv_cell, price, display_pos} @@ -164,6 +175,11 @@ public: bool cube_make(int result_index); bool cube_request_result_list(int npc_vnum); bool cube_request_materials(int start_index, int count); + bool cube_open(); + bool cube_close(); + bool cube_list(); + bool cube_add_item(int cube_index, int inventory_index); + bool cube_delete_item(int cube_index); // --- guild --- godot::Dictionary get_guild() const; // {in_guild, id, name, level, exp, gold, ...} @@ -172,7 +188,17 @@ public: bool guild_add_member(int vid); bool guild_remove_member(int pid); bool guild_offer(int amount); + bool guild_charge_gsp(int amount); + bool guild_change_grade_name(int grade, const godot::String &name); + bool guild_change_grade_authority(int grade, int authority); + bool guild_change_member_grade(int pid, int grade); + bool guild_change_member_general(int pid, bool enabled); + bool guild_post_comment(const godot::String &text); + bool guild_delete_comment(int comment_id); + bool guild_refresh_comments(); + bool guild_answer_invite(int guild_id, bool accept); bool guild_answer_make(const godot::String &name); + godot::Array get_guild_comments() const; // [{id, name, content}] // --- guild war / guild skill --- godot::Dictionary get_guild_skill() const; // {valid, skill_point, guild_point, max_guild_point, levels[12]} @@ -223,6 +249,11 @@ public: godot::Array get_land_areas() const; // [{id, guild_id, rect}] in server cm godot::Array get_observers() const; // [{vid, pos}] in Godot metres godot::Array get_world_markers() const; // [{id, name, vid, type, pos}] + bool is_observer_mode() const; + int get_observer_count() const; + bool has_mobile_flag() const; + bool combo_skill_enabled() const; + godot::Dictionary get_stamina_state() const; // {consuming, per_sec, current} // items. window: 1=inventory, 2=equipment (mtnet::WINDOW_*). bool move_item(int from_window, int from_cell, int to_window, int to_cell, int count); @@ -239,11 +270,13 @@ public: godot::Dictionary get_item(int window, int cell) const; godot::Array get_ground_items() const; // {vid, vnum, pos} godot::Array get_pvp_relations() const; // [{src_vid, dst_vid, mode}] + godot::Dictionary get_duel() const; // {active, cannot_attack, opponents} // --- networked world snapshot (positions already Godot-space, metres) --- godot::Dictionary get_entity(int vid) const; godot::Array get_entities() const; int get_main_vid() const; + int get_main_pid() const; godot::Dictionary get_points() const; // local player stat block godot::Dictionary get_target() const; // {vid, hp_percent} of selected target godot::Array get_affects() const; // active buffs/debuffs on the local player @@ -287,7 +320,17 @@ private: std::unique_ptr auth; std::unique_ptr game; + // MT_PROTOCOL=classic (40250): replaces auth+game for the flows it supports + // (connect/login/select/enter-game/world/intents). Null otherwise. + std::unique_ptr classic_sess; + bool classic_list_emitted = false; + int classic_last_stage = -1; + int classic_last_empire = -1; + void pump_classic(); + // the EntityStore of whichever backend is active (classic_sess or game). + const mtnet::EntityStore *active_world() const; std::unique_ptr mark; + std::unique_ptr classic_mark; std::unique_ptr mark_store; // survives after `mark` is torn down godot::String mark_host; int mark_port = 0; @@ -295,11 +338,14 @@ private: uint32_t symbol_guild_id = 0; std::vector symbol_data; void pump_mark(); + void pump_classic_mark(); int last_auth_state = -1; int last_game_state = -1; int last_game_phase = -1; + int last_game_empire = -1; bool char_list_emitted = false; + uint32_t selected_pid = 0; godot::Array build_char_list() const; // CG_ENTERGAME is sent ~1.5s into PHASE_LOADING (not immediately) — sending // it before the server finishes the spawn burst makes it drop us ~10s later. diff --git a/extension/src/net/wire.h b/extension/src/net/wire.h index 89fffd6d..345ba64d 100644 --- a/extension/src/net/wire.h +++ b/extension/src/net/wire.h @@ -326,6 +326,8 @@ enum : uint8_t { POINT_MAX_HP = 6, POINT_SP = 7, POINT_MAX_SP = 8, + POINT_STAMINA = 9, + POINT_MAX_STAMINA = 10, POINT_GOLD = 11, POINT_ATT_SPEED = 17, POINT_ENERGY = 128, @@ -457,9 +459,13 @@ enum : uint8_t { // GuildSub::CG GUILD_CG_CHANGE_GRADE_AUTHORITY = 3, GUILD_CG_OFFER = 4, GUILD_CG_POST_COMMENT = 5, + GUILD_CG_DELETE_COMMENT = 6, + GUILD_CG_REFRESH_COMMENT = 7, GUILD_CG_CHANGE_MEMBER_GRADE = 8, GUILD_CG_USE_SKILL = 9, + GUILD_CG_CHANGE_MEMBER_GENERAL = 10, GUILD_CG_INVITE_ANSWER = 11, + GUILD_CG_CHARGE_GSP = 12, GUILD_CG_DEPOSIT_MONEY = 13, GUILD_CG_WITHDRAW_MONEY = 14, }; diff --git a/extension/tests/net_classic_cipher_test.cpp b/extension/tests/net_classic_cipher_test.cpp new file mode 100644 index 00000000..5567f21e --- /dev/null +++ b/extension/tests/net_classic_cipher_test.cpp @@ -0,0 +1,104 @@ +// net_classic_cipher_test — 40250 _IMPROVED_PACKET_ENCRYPTION_ end to end, +// no socket: a client-polarity ClassicCipher and a server-polarity one run the +// DH2 key agreement against each other, then encrypt/decrypt must round-trip +// symmetrically (client.encrypt -> server.decrypt and vice versa). +#include "../src/net/classic/classic_cipher.h" +#include "../src/net/classic/wire_classic.h" + +#include +#include +#include +#include + +using namespace mtnet::classic; + +static int g_fail = 0; +#define CHECK(c, msg) \ + do { \ + if (!(c)) { \ + std::fprintf(stderr, "FAIL: %s\n", msg); \ + ++g_fail; \ + } \ + } while (0) + +int main() { + ClassicCipher client; // polarity = true (EterLib/NetStream.cpp:3004) + ClassicCipher server; // polarity = false (desc.cpp FinishHandshake) + + // Each side generates its DH2 public blob (spub || epub). + uint8_t cbuf[KEY_AGREEMENT_MAX_DATA_LEN]; + uint8_t sbuf[KEY_AGREEMENT_MAX_DATA_LEN]; + size_t clen = sizeof(cbuf); + size_t slen = sizeof(sbuf); + size_t cagreed = client.prepare(cbuf, &clen); + size_t sagreed = server.prepare(sbuf, &slen); + + CHECK(cagreed != 0, "client prepare -> non-zero agreed length"); + CHECK(sagreed != 0, "server prepare -> non-zero agreed length"); + CHECK(cagreed == sagreed, "both sides same agreed-value length (same DH2 params)"); + CHECK(clen > 0 && clen <= KEY_AGREEMENT_MAX_DATA_LEN, "client blob length sane"); + CHECK(clen == slen, "blob lengths match"); + + // Activate: each consumes the PEER's (agreed_length, blob). + bool ca = client.activate(true, sagreed, sbuf, slen); + bool sa = server.activate(false, cagreed, cbuf, clen); + CHECK(ca, "client activate"); + CHECK(sa, "server activate"); + CHECK(client.key_ready() && server.key_ready(), "both have encoder+decoder"); + + // The stream turns real only after GC_KEY_AGREEMENT_COMPLETED. + CHECK(!client.activated(), "cipher not 'activated' until set_activated"); + client.set_activated(true); + server.set_activated(true); + + // --- round trip: client -> server --- + { + std::string plain = "the quick brown fox CG_MOVE \x07\x01\x00\x00 jumps"; + std::vector buf(plain.begin(), plain.end()); + std::vector orig = buf; + client.encrypt(buf.data(), buf.size()); + CHECK(buf != orig, "ciphertext differs from plaintext"); + server.decrypt(buf.data(), buf.size()); + CHECK(buf == orig, "server recovers client's plaintext"); + } + + // --- round trip: server -> client, and CTR keystream continuity --- + { + std::string a = "GC_MAIN_CHARACTER hello world 0123456789"; + std::string b = "second chunk keeps the CTR counter advancing"; + std::vector ba(a.begin(), a.end()), bb(b.begin(), b.end()); + std::vector oa = ba, ob = bb; + server.encrypt(ba.data(), ba.size()); + server.encrypt(bb.data(), bb.size()); + client.decrypt(ba.data(), ba.size()); + client.decrypt(bb.data(), bb.size()); + CHECK(ba == oa && bb == ob, "client recovers server's two chunks (CTR continuity)"); + } + + // --- a fresh pair must derive a *different* key (ephemeral) --- + { + ClassicCipher c2, s2; + uint8_t x[256], y[256]; + size_t xl = sizeof(x), yl = sizeof(y); + size_t xa = c2.prepare(x, &xl); + size_t ya = s2.prepare(y, &yl); + c2.activate(true, ya, y, yl); + s2.activate(false, xa, x, xl); + c2.set_activated(true); + s2.set_activated(true); + + std::string msg = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; // 32 identical bytes + std::vector p1(msg.begin(), msg.end()); + std::vector p2 = p1; + client.encrypt(p1.data(), p1.size()); // from the first session (already advanced) + c2.encrypt(p2.data(), p2.size()); // fresh session + CHECK(p1 != p2, "different sessions produce different ciphertext"); + } + + if (g_fail) { + std::fprintf(stderr, "%d check(s) failed\n", g_fail); + return 1; + } + std::puts("net_classic_cipher_test OK"); + return 0; +} diff --git a/extension/tests/net_classic_encstream_test.cpp b/extension/tests/net_classic_encstream_test.cpp new file mode 100644 index 00000000..e9c244a5 --- /dev/null +++ b/extension/tests/net_classic_encstream_test.cpp @@ -0,0 +1,168 @@ +// net_classic_encstream_test — ClassicStream with _IMPROVED_PACKET_ENCRYPTION_. +// A server-side ClassicCipher plays the peer: HANDSHAKE -> GC_KEY_AGREEMENT -> +// (stream replies CG_KEY_AGREEMENT) -> GC_KEY_AGREEMENT_COMPLETED. After that +// every byte both ways is CTR-encrypted; the test verifies the stream decrypts +// an inbound GC_PHASE and that an outbound CG_MOVE decrypts cleanly server-side. +#include "../src/net/classic/classic_cipher.h" +#include "../src/net/classic/classic_stream.h" +#include "../src/net/classic/wire_classic.h" + +#include +#include +#include +#include + +using namespace mtnet::classic; + +static int g_fail = 0; +#define CHECK(c, msg) \ + do { \ + if (!(c)) { \ + std::fprintf(stderr, "FAIL: %s\n", msg); \ + ++g_fail; \ + } \ + } while (0) + +template +static std::vector raw(const T &s) { + std::vector b(sizeof(T)); + std::memcpy(b.data(), &s, sizeof(T)); + return b; +} +static std::vector drain(ClassicStream &s) { + std::vector out; + uint8_t buf[2048]; + for (size_t n; (n = s.take_outgoing(buf, sizeof(buf)));) { + out.insert(out.end(), buf, buf + n); + } + return out; +} + +int main() { + ClassicStream cs; + cs.set_polarity(true); // client + int phase_seen = -1; + std::string err; + bool cipher_on = false; + cs.on_phase = [&](uint8_t p) { phase_seen = p; }; + cs.on_error = [&](const std::string &e) { err = e; }; + cs.on_cipher_active = [&]() { cipher_on = true; }; + + ClassicCipher server; // polarity = false + + // --- handshake (plaintext) --- + { + Handshake hs{}; + hs.header = HDR_HANDSHAKE; + hs.time = 1000; + hs.delta = 5; + cs.feed(raw(hs).data(), sizeof(hs)); + CHECK(drain(cs).size() == sizeof(Handshake), "handshake echo (plaintext)"); + } + + // --- GC_KEY_AGREEMENT: server sends its DH2 blob --- + { + KeyAgreement srv_pkt{}; + srv_pkt.header = HDR_KEY_AGREEMENT; + size_t dl = sizeof(srv_pkt.data); + size_t agreed = server.prepare(srv_pkt.data, &dl); + CHECK(agreed != 0, "server DH2 prepare"); + srv_pkt.agreed_length = (uint16_t)agreed; + srv_pkt.data_length = (uint16_t)dl; + + cs.feed(raw(srv_pkt).data(), sizeof(srv_pkt)); + + // stream must have replied with CG_KEY_AGREEMENT (plaintext, its own blob) + auto reply = drain(cs); + CHECK(reply.size() == sizeof(KeyAgreement), "CG_KEY_AGREEMENT reply is 261 bytes"); + CHECK(reply[0] == HDR_KEY_AGREEMENT, "reply header 0xFB"); + KeyAgreement cli_pkt{}; + std::memcpy(&cli_pkt, reply.data(), sizeof(cli_pkt)); + CHECK(err.empty(), "no error during key agreement"); + + // server consumes the client's blob + CHECK(server.activate(false, cli_pkt.agreed_length, cli_pkt.data, cli_pkt.data_length), + "server activate with client blob"); + CHECK(!cs.cipher_active(), "stream cipher not active until COMPLETED"); + } + + // --- GC_KEY_AGREEMENT_COMPLETED (plaintext) -> both sides go live --- + { + KeyAgreementCompleted done{}; + done.header = HDR_GC_KEY_AGREEMENT_COMPLETED; + cs.feed(raw(done).data(), sizeof(done)); + server.set_activated(true); + CHECK(cs.cipher_active() && cipher_on, "stream cipher active after COMPLETED"); + } + + // --- server -> client: an ENCRYPTED GC_PHASE(GAME) must decrypt + dispatch --- + { + auto pkt = raw(Phase_{HDR_GC_PHASE, PHASE_GAME}); + server.encrypt(pkt.data(), pkt.size()); + CHECK(pkt[0] != HDR_GC_PHASE, "GC_PHASE really is ciphertext on the wire"); + cs.feed(pkt.data(), pkt.size()); + CHECK(phase_seen == PHASE_GAME, "stream decrypted + dispatched GC_PHASE(GAME)"); + } + + // --- client -> server: an outbound CG_MOVE must be ciphertext the server reads --- + { + cs.set_sequence_mode(true); + CGMove mv{}; + mv.header = HDR_CG_MOVE; + mv.func = 1; + mv.x = 12345; + mv.y = 67890; + cs.send_fixed(&mv, sizeof(mv)); + auto wire = drain(cs); + CHECK(wire.size() == sizeof(CGMove) + 1, "CG_MOVE + seq byte on the wire"); + CHECK(wire[0] != HDR_CG_MOVE, "CG_MOVE header is encrypted on the wire"); + + server.decrypt(wire.data(), wire.size()); + CGMove got{}; + std::memcpy(&got, wire.data(), sizeof(got)); + CHECK(got.header == HDR_CG_MOVE && got.func == 1 && got.x == 12345 && got.y == 67890, + "server decrypts CG_MOVE body"); + CHECK(wire[sizeof(CGMove)] == SEQUENCE_TABLE[0], "seq byte decrypts to table[0]"); + } + + // --- pipelined case: COMPLETED + encrypted packet in one feed() --- + { + ClassicStream cs2; + cs2.set_polarity(true); + int seen2 = -1; + cs2.on_phase = [&](uint8_t p) { seen2 = p; }; + ClassicCipher srv2; + + Handshake hs{}; + hs.header = HDR_HANDSHAKE; + cs2.feed(raw(hs).data(), sizeof(hs)); + drain(cs2); + + KeyAgreement sp{}; + sp.header = HDR_KEY_AGREEMENT; + size_t dl = sizeof(sp.data); + sp.agreed_length = (uint16_t)srv2.prepare(sp.data, &dl); + sp.data_length = (uint16_t)dl; + cs2.feed(raw(sp).data(), sizeof(sp)); + auto rep = drain(cs2); + KeyAgreement cp{}; + std::memcpy(&cp, rep.data(), sizeof(cp)); + srv2.activate(false, cp.agreed_length, cp.data, cp.data_length); + srv2.set_activated(true); + + // one buffer: [COMPLETED plaintext][encrypted GC_PHASE(SELECT)] + std::vector blob = raw(KeyAgreementCompleted{HDR_GC_KEY_AGREEMENT_COMPLETED, {}}); + auto enc = raw(Phase_{HDR_GC_PHASE, PHASE_SELECT}); + srv2.encrypt(enc.data(), enc.size()); + blob.insert(blob.end(), enc.begin(), enc.end()); + cs2.feed(blob.data(), blob.size()); + CHECK(seen2 == PHASE_SELECT, "pipelined COMPLETED+encrypted packet handled"); + } + + if (g_fail) { + std::fprintf(stderr, "%d check(s) failed\n", g_fail); + return 1; + } + std::puts("net_classic_encstream_test OK"); + return 0; +} diff --git a/extension/tests/net_classic_mark_test.cpp b/extension/tests/net_classic_mark_test.cpp new file mode 100644 index 00000000..6b172993 --- /dev/null +++ b/extension/tests/net_classic_mark_test.cpp @@ -0,0 +1,145 @@ +#include "classic/classic_mark_client.h" + +#include +#include +#include +#include + +using namespace mtnet::classic; + +static std::vector take_all(ClassicStream &stream) { + std::vector out(stream.outgoing_pending()); + if (!out.empty()) { + assert(stream.take_outgoing(out.data(), out.size()) == out.size()); + } + return out; +} + +static void put_u16(std::vector &p, size_t off, uint16_t v) { + p[off] = static_cast(v); + p[off + 1] = static_cast(v >> 8); +} + +static void put_u32(std::vector &p, size_t off, uint32_t v) { + p[off] = static_cast(v); + p[off + 1] = static_cast(v >> 8); + p[off + 2] = static_cast(v >> 16); + p[off + 3] = static_cast(v >> 24); +} + +static void test_mark_download() { + ClassicMarkClient client(0x11223344u, 0x55667788u); + Handshake handshake{}; + handshake.header = HDR_HANDSHAKE; + handshake.handshake = 7; + handshake.time = 100; + client.stream().feed(&handshake, sizeof(handshake)); + std::vector login = take_all(client.stream()); + assert(login.size() == sizeof(Handshake) + sizeof(CGMarkLogin)); + assert(login[sizeof(Handshake)] == HDR_CG_MARK_LOGIN); + uint32_t handle = 0; + std::memcpy(&handle, login.data() + sizeof(Handshake) + 1, sizeof(handle)); + assert(handle == 0x11223344u); + uint32_t random_key = 0; + std::memcpy(&random_key, login.data() + sizeof(Handshake) + 5, sizeof(random_key)); + assert(random_key == 0x55667788u); + + Handshake resync = handshake; + resync.time = 200; + resync.delta = 3; + client.stream().feed(&resync, sizeof(resync)); + std::vector repeated_login = take_all(client.stream()); + assert(repeated_login.size() == sizeof(Handshake) + sizeof(CGMarkLogin)); + assert(repeated_login[0] == HDR_HANDSHAKE); + assert(repeated_login[sizeof(Handshake)] == HDR_CG_MARK_LOGIN); + + std::vector phase{HDR_GC_PHASE, PHASE_LOGIN}; + client.stream().feed(phase.data(), phase.size()); + std::vector request = take_all(client.stream()); + assert(request.size() == sizeof(CGMarkIDXList)); + assert(request[0] == HDR_CG_MARK_IDXLIST); + + // One guild maps to image zero, position one. Feed the whole-size frame in + // two chunks to exercise the custom raw framing path. + std::vector idx(sizeof(GCMarkIDXList) + 4); + idx[0] = HDR_GC_MARK_IDXLIST; + put_u32(idx, 1, static_cast(idx.size())); + put_u16(idx, 5, 1); + put_u16(idx, 7, 42); + put_u16(idx, 9, 1); + client.stream().feed(idx.data(), 6); + assert(client.stream().outgoing_pending() == 0); + client.stream().feed(idx.data() + 6, idx.size() - 6); + request = take_all(client.stream()); + assert(request.size() == sizeof(CGMarkCRCList)); + assert(request[0] == HDR_CG_MARK_CRCLIST && request[1] == 0); + assert(client.marks().has_mark(42)); + + // A valid zero-block image response advances the image state and completes + // the download without requiring LZO data in this framing test. + std::vector block(sizeof(GCMarkBlock)); + block[0] = HDR_GC_MARK_BLOCK; + put_u32(block, 1, static_cast(block.size())); + block[5] = 0; + put_u32(block, 6, 0); + client.stream().feed(block.data(), block.size()); + assert(client.complete()); +} + +static void test_symbol_download() { + ClassicMarkClient client(0x11u, 0x22u); + client.set_download_symbol(42); + std::vector phase{HDR_GC_PHASE, PHASE_LOGIN}; + client.stream().feed(phase.data(), phase.size()); + std::vector request = take_all(client.stream()); + assert(request.size() == sizeof(CGSymbolCRC)); + assert(request[0] == HDR_CG_SYMBOL_CRC); + uint32_t gid = 0; + std::memcpy(&gid, request.data() + 1, sizeof(gid)); + assert(gid == 42); + + const std::vector payload{0xAA, 0xBB, 0xCC}; + std::vector symbol(sizeof(GCSymbolData) + payload.size()); + symbol[0] = HDR_GC_SYMBOL_DATA; + put_u16(symbol, 1, static_cast(symbol.size())); + put_u32(symbol, 3, 42); + std::memcpy(symbol.data() + sizeof(GCSymbolData), payload.data(), payload.size()); + client.stream().feed(symbol.data(), symbol.size()); + assert(client.complete()); + assert(client.symbol_guild_id() == 42); + assert(client.symbol_data() == payload); +} + +static void test_upload_layouts() { + uint32_t px[GUILD_MARK_WIDTH * GUILD_MARK_HEIGHT] = {}; + px[0] = 0x44332211u; + ClassicMarkClient mark(1, 2); + mark.set_upload_mark(42, px); + std::vector phase{HDR_GC_PHASE, PHASE_LOGIN}; + mark.stream().feed(phase.data(), phase.size()); + std::vector packet = take_all(mark.stream()); + assert(packet.size() == sizeof(CGMarkUpload)); + assert(packet[0] == HDR_CG_MARK_UPLOAD); + uint32_t gid = 0; + std::memcpy(&gid, packet.data() + 1, sizeof(gid)); + assert(gid == 42); + assert(packet[5] == 0x11 && packet[6] == 0x22 && packet[7] == 0x33 && packet[8] == 0x44); + + ClassicMarkClient symbol(3, 4); + symbol.set_upload_symbol(99, std::vector{1, 2, 3}); + symbol.stream().feed(phase.data(), phase.size()); + packet = take_all(symbol.stream()); + assert(packet.size() == sizeof(CGGuildSymbolUpload) + 3); + assert(packet[0] == HDR_CG_GUILD_SYMBOL_UPLOAD); + assert(packet[1] == packet.size() && packet[2] == 0); + std::memcpy(&gid, packet.data() + 3, sizeof(gid)); + assert(gid == 99); + assert(packet[7] == 1 && packet[8] == 2 && packet[9] == 3); +} + +int main() { + test_mark_download(); + test_symbol_download(); + test_upload_layouts(); + return 0; +} diff --git a/extension/tests/net_classic_session_test.cpp b/extension/tests/net_classic_session_test.cpp new file mode 100644 index 00000000..9e75fc92 --- /dev/null +++ b/extension/tests/net_classic_session_test.cpp @@ -0,0 +1,1085 @@ +// net_classic_session_test — 40250 classic HANDSHAKE -> LOGIN -> SELECT -> +// LOADING -> GAME driven socket-free: scripted server bytes into +// session.stream().feed(), outgoing checked via take_outgoing(). +#include "../src/net/classic/classic_session.h" + +#include +#include +#include +#include + +using namespace mtnet::classic; + +static int g_fail = 0; +#define CHECK(c, msg) \ + do { \ + if (!(c)) { \ + std::fprintf(stderr, "FAIL: %s\n", msg); \ + ++g_fail; \ + } \ + } while (0) + +template +static std::vector raw(const T &s) { + std::vector b(sizeof(T)); + std::memcpy(b.data(), &s, sizeof(T)); + return b; +} + +static void feed(ClassicSession &s, const std::vector &b) { + s.stream().feed(b.data(), b.size()); +} + +static std::vector drain(ClassicSession &s) { + std::vector out; + uint8_t buf[2048]; + for (;;) { + size_t n = s.stream().take_outgoing(buf, sizeof(buf)); + if (!n) { + break; + } + out.insert(out.end(), buf, buf + n); + } + return out; +} + +int main() { + ClassicSession s; + s.set_now(0); + + std::vector got_list; + bool entered = false; + s.on_char_list = [&](const std::vector &l) { got_list = l; }; + s.on_entered_game = [&]() { entered = true; }; + + s.start_offline("admin", "123456789"); + CHECK(s.stage() == mtnet::INetSession::Stage::Connecting, "start_offline -> Connecting"); + + // --- handshake: server HANDSHAKE -> client echoes it back --- + { + Handshake hs{}; + hs.header = HDR_HANDSHAKE; + hs.handshake = 0x1234; + hs.time = 5000; + hs.delta = 10; + feed(s, raw(hs)); + auto out = drain(s); + CHECK(out.size() == sizeof(Handshake), "handshake echo (13 bytes, no seq)"); + Handshake e{}; + std::memcpy(&e, out.data(), sizeof(e)); + CHECK(e.header == HDR_HANDSHAKE && e.time == 5000 + 20 && e.delta == 0, "handshake echo math"); + } + + // --- GC_PHASE(LOGIN): session sends CG_LOGIN + first sequence byte --- + { + Phase_ p{HDR_GC_PHASE, PHASE_LOGIN}; + feed(s, raw(p)); + CHECK(s.stage() == mtnet::INetSession::Stage::LoggingIn, "PHASE_LOGIN -> LoggingIn"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGLogin) + 1, "CG_LOGIN + 1 seq byte"); + CHECK(out[0] == HDR_CG_LOGIN, "outgoing is CG_LOGIN"); + CGLogin lg{}; + std::memcpy(&lg, out.data(), sizeof(lg)); + CHECK(std::strcmp(lg.login, "admin") == 0, "login field"); + CHECK(std::strcmp(lg.passwd, "123456789") == 0, "passwd field"); + CHECK(out[sizeof(CGLogin)] == SEQUENCE_TABLE[0], "trailing seq == table[0]"); + CHECK(s.stream().sequence_index() == 1, "seq index -> 1"); + } + + // --- GC_LOGIN_SUCCESS_NEWSLOT (header 32, 4 slots; 2 filled) --- + { + GCLoginSuccess ls{}; + ls.header = HDR_GC_LOGIN_SUCCESS_NEWSLOT; + ls.handle = 0xAABBCCDD; + ls.random_key = 0x99887766; + ls.players[0].id = 1001; + std::strcpy(ls.players[0].name, "Warrior"); + ls.players[0].job = 0; + ls.players[0].level = 42; + ls.players[0].ht = 20; + ls.players[0].change_name = 1; + ls.players[1].id = 1002; + std::strcpy(ls.players[1].name, "Sura"); + ls.players[1].job = 4; + ls.players[1].level = 7; + feed(s, raw(ls)); + CHECK(s.parser().char_list_ready(), "login success parsed"); + CHECK(s.parser().slot_count() == 4, "4 slots"); + CHECK(s.parser().handle() == 0xAABBCCDD, "handle carried"); + CHECK(s.parser().random_key() == 0x99887766, "random_key carried"); + const auto &sl = s.char_slots(); + CHECK(sl.size() == 4 && sl[0].name == "Warrior" && sl[0].level == 42 && sl[0].change_name, + "slot 0 + forced rename flag"); + CHECK(sl[1].name == "Sura" && sl[1].job == 4, "slot 1"); + CHECK(sl[2].empty() && sl[3].empty(), "slots 2,3 empty"); + } + + // --- GC_CHANGE_NAME completes the forced rename state --- + { + GCChangeNameNotice n{}; + n.header = HDR_GC_CHANGE_NAME; + n.pid = 1001; + std::strcpy(n.name, "Renamed"); + feed(s, raw(n)); + const auto &sl = s.char_slots(); + CHECK(sl[0].name == "Renamed" && !sl[0].change_name, "rename clears forced flag"); + auto names = s.parser().drain_name_events(); + CHECK(names.size() == 1 && names[0].pid == 1001 && names[0].name == "Renamed", + "rename event surfaced"); + } + + // --- GC_PHASE(SELECT): char list surfaces --- + { + Phase_ p{HDR_GC_PHASE, PHASE_SELECT}; + feed(s, raw(p)); + CHECK(s.stage() == mtnet::INetSession::Stage::CharSelect, "PHASE_SELECT -> CharSelect"); + CHECK(got_list.size() == 4 && got_list[0].name == "Renamed" && !got_list[0].change_name, + "on_char_list fired with renamed slot"); + } + + // --- select_char(0) -> CG_CHARACTER_SELECT + seq[1] --- + { + CHECK(s.select_char(0), "select_char(0) ok"); + CHECK(!s.select_char(9), "select_char(9) rejected (out of range)"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGPlayerSelect) + 1, "CG_CHARACTER_SELECT + seq"); + CHECK(out[0] == HDR_CG_CHARACTER_SELECT && out[1] == 0, "select slot 0"); + CHECK(out[sizeof(CGPlayerSelect)] == SEQUENCE_TABLE[1], "seq == table[1]"); + } + + // --- GC_PHASE(LOADING) + GC_MAIN_CHARACTER(113) + a nearby NPC --- + { + Phase_ p{HDR_GC_PHASE, PHASE_LOADING}; + feed(s, raw(p)); + CHECK(s.stage() == mtnet::INetSession::Stage::Loading, "PHASE_LOADING -> Loading"); + + GCMainCharacter mc{}; + mc.header = HDR_GC_MAIN_CHARACTER; + mc.vid = 7777; + mc.race = 4; + std::strcpy(mc.name, "Warrior"); + mc.x = 100000; + mc.y = 200000; + mc.z = 3; + mc.empire = 1; + feed(s, raw(mc)); + CHECK(s.world().main_vid() == 7777, "main vid set"); + const auto *me = s.world().get(7777); + CHECK(me && me->is_main && me->x == 100000.f && me->name == "Warrior", "main entity"); + auto version = drain(s); + CHECK(version.size() == sizeof(CGClientVersion) + 1, "CG_CLIENT_VERSION + seq"); + CGClientVersion cv{}; + std::memcpy(&cv, version.data(), sizeof(cv)); + CHECK(cv.header == HDR_CG_CLIENT_VERSION && std::strcmp(cv.filename, "metin2.bin") == 0 && + std::strcmp(cv.timestamp, "1215955205") == 0, "client version fields"); + CHECK(version[sizeof(CGClientVersion)] == SEQUENCE_TABLE[2], "version seq == table[2]"); + + GCCharacterAdd add{}; + add.header = HDR_GC_CHARACTER_ADD; + add.vid = 8888; + add.race = 101; + add.type = 1; // NPC + add.x = 100500; + add.y = 200500; + add.moving_speed = 150; + feed(s, raw(add)); + const auto *npc = s.world().get(8888); + CHECK(npc && npc->ch_type == 1 && npc->race == 101, "npc spawned"); + CHECK(s.world().size() == 2, "2 entities"); + + GCShopSign sign{}; + sign.header = HDR_GC_SHOP_SIGN; + sign.vid = 8888; + std::strcpy(sign.sign, "Potion shop"); + feed(s, raw(sign)); + CHECK(s.world().get(8888)->shop_sign == "Potion shop", "shop sign set"); + std::memset(sign.sign, 0, sizeof(sign.sign)); + feed(s, raw(sign)); + CHECK(s.world().get(8888)->shop_sign.empty(), "shop sign cleared"); + } + + // --- auto CG_ENTERGAME after the loading delay --- + { + s.set_now(1499); + s.pump(); // no socket -> just the auto-entergame check + tick + CHECK(drain(s).empty(), "no ENTERGAME before delay"); + s.set_now(1500); + s.pump(); + auto out = drain(s); + CHECK(out.size() == sizeof(CGEnterGame) + 1, "CG_ENTERGAME + seq"); + CHECK(out[0] == HDR_CG_ENTERGAME && out[1] == SEQUENCE_TABLE[3], "ENTERGAME + seq[3]"); + } + + // --- GC_PHASE(GAME) --- + { + Phase_ p{HDR_GC_PHASE, PHASE_GAME}; + feed(s, raw(p)); + CHECK(s.stage() == mtnet::INetSession::Stage::InGame, "PHASE_GAME -> InGame"); + CHECK(s.in_game() && entered, "in_game() + on_entered_game"); + } + + // --- GC_MOVE(3): NPC starts moving, interpolation advances on tick --- + { + GCMove mv{}; + mv.header = HDR_GC_MOVE; + mv.func = mtnet::FUNC_MOVE; + mv.rot = 64; + mv.vid = 8888; + mv.x = 110000; + mv.y = 200500; + mv.duration = 1000; + feed(s, raw(mv)); + const auto *npc = s.world().get(8888); + CHECK(npc && npc->moving, "npc moving after GC_MOVE"); + s.set_now(1500 + 500); // halfway through the 1000ms move (started at now=1500) + s.world().tick(); + npc = s.world().get(8888); + CHECK(npc && npc->x > 100500.f && npc->x < 110000.f, "npc interpolated partway"); + } + + // --- GC_WARP(65): packed classic static packet must remain frameable --- + { + GCWarpClassic warp{}; + warp.header = HDR_GC_WARP; + warp.x = 432100; + warp.y = 876500; + warp.addr = 0; + warp.port = 0; + feed(s, raw(warp)); + auto warps = s.world().drain_warps(); + CHECK(warps.size() == 1 && warps[0].x == 432100 && warps[0].y == 876500 && + warps[0].same_server(), "classic GC_WARP parsed and surfaced"); + } + + // --- GC_CHARACTER_POINTS(16): stat block --- + { + GCPoints pts{}; + pts.header = HDR_GC_CHARACTER_POINTS; + pts.points[mtnet::POINT_LEVEL] = 42; + pts.points[mtnet::POINT_MAX_HP] = 3500; + pts.points[mtnet::POINT_HP] = 3500; + feed(s, raw(pts)); + CHECK(s.world().points().level() == 42, "points level"); + CHECK(s.world().points().max_hp() == 3500, "points max_hp"); + const auto *me = s.world().get(7777); + CHECK(me && me->max_hp == 3500 && me->level == 42, "vitals mirrored onto main entity"); + } + + // --- GC_CHARACTER_POINT_CHANGE(17): single stat delta (int32_t header quirk) --- + { + GCPointChange pc{}; + pc.header = HDR_GC_CHARACTER_POINT_CHANGE; + pc.vid = 7777; + pc.type = mtnet::POINT_HP; + pc.value = 1200; + feed(s, raw(pc)); + CHECK(s.world().points().hp() == 1200, "point change -> hp 1200"); + CHECK(s.world().get(7777)->hp == 1200, "point change mirrored"); + } + + // --- in-game intents: CG_MOVE / ATTACK / CHAT / TARGET, each + a seq byte --- + { + // sequence index so far: [0]=CG_LOGIN, [1]=CG_CHARACTER_SELECT, + // [2]=CG_CLIENT_VERSION, [3]=CG_ENTERGAME. + CHECK(s.stream().sequence_index() == 4, "seq index at 4 before intents"); + + CHECK(s.send_move(mtnet::FUNC_MOVE, 0, 90.0f, 111111, 222222, 4242), "send_move"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGMove) + 1, "CG_MOVE + seq"); + CGMove mv{}; + std::memcpy(&mv, out.data(), sizeof(mv)); + CHECK(mv.header == HDR_CG_MOVE && mv.func == mtnet::FUNC_MOVE, "move header/func"); + CHECK(mv.rot == 18, "rot deg 90 -> wire 18 (deg/5)"); + CHECK(mv.x == 111111 && mv.y == 222222 && mv.time == 4242, "move x/y/time"); + CHECK(out[sizeof(CGMove)] == SEQUENCE_TABLE[4], "move seq == table[4]"); + + CHECK(s.send_attack(1, 8888), "send_attack"); + out = drain(s); + CHECK(out.size() == sizeof(CGAttack) + 1 && out[0] == HDR_CG_ATTACK, "CG_ATTACK + seq"); + CGAttack at{}; + std::memcpy(&at, out.data(), sizeof(at)); + CHECK(at.type == 1 && at.victim_vid == 8888, "attack fields"); + CHECK(out[sizeof(CGAttack)] == SEQUENCE_TABLE[5], "attack seq == table[5]"); + + CHECK(s.send_target(8888), "send_target"); + out = drain(s); + CGTarget tg{}; + std::memcpy(&tg, out.data(), sizeof(tg)); + CHECK(out.size() == sizeof(CGTarget) + 1 && tg.vid == 8888, "CG_TARGET + seq"); + CHECK(out[sizeof(CGTarget)] == SEQUENCE_TABLE[6], "target seq == table[6]"); + + // dynamic CG_CHAT: [hdr][u16 len][type]"hello"\0 + seq + CHECK(s.send_chat(0, "hello"), "send_chat"); + out = drain(s); + const size_t chat_len = sizeof(CGChatHead) + 5 + 1; // "hello" + NUL + CHECK(out.size() == chat_len + 1, "CG_CHAT wire size + seq"); + CGChatHead ch{}; + std::memcpy(&ch, out.data(), sizeof(ch)); + CHECK(ch.header == HDR_CG_CHAT && ch.length == chat_len && ch.type == 0, "chat head"); + CHECK(std::memcmp(out.data() + sizeof(CGChatHead), "hello\0", 6) == 0, "chat text + NUL"); + CHECK(out[chat_len] == SEQUENCE_TABLE[7], "chat seq == table[7]"); + + CHECK(s.send_item_move(1, 5, 1, 9, 1), "send_item_move"); + out = drain(s); + CGItemMove im{}; + std::memcpy(&im, out.data(), sizeof(im)); + CHECK(out.size() == sizeof(CGItemMove) + 1, "CG_ITEM_MOVE + seq"); + CHECK(im.pos.window_type == 1 && im.pos.cell == 5 && im.change_pos.cell == 9 && im.num == 1, + "item_move fields"); + } + + // --- GC_ITEM_SET(21) / UPDATE(25) / DEL(20) — inventory --- + { + GCItemSet is{}; + is.header = HDR_GC_ITEM_SET; + is.cell = {1, 4}; // inventory, cell 4 + is.vnum = 27100; // a sword vnum + is.count = 1; + is.flags = 0x2; + is.anti_flags = 0x10; + is.sockets[0] = 28030; + is.attrs[0] = {5, 30}; + is.attrs[1] = {1, 250}; + feed(s, raw(is)); + const mtnet::Item &it = s.world().item_slot(1, 4); + CHECK(it.vnum == 27100 && it.count == 1 && it.flags == 0x2 && it.anti_flags == 0x10, + "item_set landed"); + CHECK(it.sockets[0] == 28030 && it.attrs[0].type == 5 && it.attrs[0].value == 30 && + it.attrs[1].value == 250, + "item_set sockets/attrs decoded from 3-byte wire attr"); + + GCItemUpdate iu{}; + iu.header = HDR_GC_ITEM_UPDATE; + iu.cell = {1, 4}; + iu.count = 3; + feed(s, raw(iu)); + CHECK(s.world().item_slot(1, 4).count == 3, "item_update count -> 3"); + + GCItemDel id{HDR_GC_ITEM_DEL, 4}; + feed(s, raw(id)); + CHECK(s.world().item_slot(1, 4).vnum == 0, "item_del cleared inventory cell 4"); + } + + // --- GC entity state: UPDATE(19) / CHANGE_SPEED(18) / POSITION(43) / MOTION(36) / + // STUN(13) / DEAD(14) / TARGET(63) --- + { + // re-add the NPC (it was despawned above? no — despawn is later). vid 8888 present. + GCCharacterUpdate cu{}; + cu.header = HDR_GC_CHARACTER_UPDATE; + cu.vid = 8888; + cu.parts[0] = 1101; + cu.parts[1] = 2205; + cu.moving_speed = 180; + cu.attack_speed = 140; + cu.guild_id = 77; + cu.alignment = -50; + cu.pk_mode = 1; + cu.mount_vnum = 20101; + feed(s, raw(cu)); + const auto *npc = s.world().get(8888); + CHECK(npc && npc->parts[0] == 1101 && npc->moving_speed == 180 && npc->guild == 77 && + npc->alignment == -50 && npc->pk_mode == 1 && npc->mount_vnum == 20101, + "char_update applied"); + + GCChangeSpeed cs{HDR_GC_CHANGE_SPEED, 8888, 250}; + feed(s, raw(cs)); + CHECK(s.world().get(8888)->moving_speed == 250, "change_speed -> 250"); + + GCCharacterPosition cp{HDR_GC_CHARACTER_POSITION, 8888, 4}; + feed(s, raw(cp)); + CHECK(s.world().get(8888)->position == 4, "position -> 4"); + + GCMotion gm{HDR_GC_MOTION, 8888, 7777, 42}; + feed(s, raw(gm)); + auto ms = s.world().drain_motions(); + CHECK(ms.size() == 1 && ms[0].vid == 8888 && ms[0].victim_vid == 7777 && ms[0].motion == 42, + "motion queued"); + + GCTarget gt{HDR_GC_TARGET, 8888, 65}; + feed(s, raw(gt)); + CHECK(s.world().target_vid() == 8888 && s.world().target_hp_pct() == 65, "target hp 65%"); + + GCStun st{HDR_GC_STUN, 8888}; + feed(s, raw(st)); + CHECK(s.world().get(8888)->stunned, "stun"); + GCDead gd2{HDR_GC_DEAD, 8888}; + feed(s, raw(gd2)); + CHECK(s.world().get(8888)->dead && s.world().get(8888)->hp == 0, "dead + hp 0"); + } + + // --- GC_SKILL_LEVEL(76) / QUICKSLOT(28/29/30) / AFFECT(126/127) / DAMAGE(135) / WHISPER(34) --- + { + GCSkillLevel sk{}; + sk.header = HDR_GC_SKILL_LEVEL; + sk.skills[1] = {1, 17}; // skill 1: master_type 1, level 17 + sk.skills[50] = {0, 40}; // skill 50: normal, level 40 + feed(s, raw(sk)); + CHECK(s.world().skill_level(1) == 17 && s.world().skill_master(1) == 1, "skill 1"); + CHECK(s.world().skill_level(50) == 40, "skill 50"); + + GCQuickSlotAdd qa{}; + qa.header = HDR_GC_QUICKSLOT_ADD; + qa.pos = 3; + qa.slot = {2, 7}; // type=skill, ref=7 + feed(s, raw(qa)); + CHECK(s.world().quickslot(3).type == 2 && s.world().quickslot(3).position == 7, "quickslot 3"); + GCQuickSlotSwap qs2{HDR_GC_QUICKSLOT_SWAP, 3, 8}; + feed(s, raw(qs2)); + CHECK(s.world().quickslot(8).type == 2 && s.world().quickslot(3).type == 0, "quickslot swap"); + GCQuickSlotDel qd{HDR_GC_QUICKSLOT_DEL, 8}; + feed(s, raw(qd)); + CHECK(s.world().quickslot(8).type == 0, "quickslot del"); + + GCAffectAdd aa{}; + aa.header = HDR_GC_AFFECT_ADD; + aa.elem = {90001, 16 /*ATT_GRADE*/, 50, 0, 300}; + feed(s, raw(aa)); + bool found = false; + for (const auto &a : s.world().affects()) { + if (a.type == 90001 && a.value == 50 && a.duration == 300) { + found = true; + } + } + CHECK(found, "affect_add landed"); + GCAffectRemove ar{HDR_GC_AFFECT_REMOVE, 90001, 0}; + feed(s, raw(ar)); + CHECK(s.world().affects().empty(), "affect_remove cleared"); + + GCDamageInfo di{HDR_GC_DAMAGE_INFO, 7777, 0x1, 321}; + feed(s, raw(di)); + auto ds = s.world().drain_damage(); + CHECK(ds.size() == 1 && ds[0].vid == 7777 && ds[0].amount == 321, "damage queued"); + + // GC_WHISPER: [hdr][u16 size][type][name_from[25]][text] + const char *msg = "hey there"; + GCWhisperHead wh{}; + wh.header = HDR_GC_WHISPER; + wh.type = 0; + std::strcpy(wh.name_from, "Gm"); + wh.size = (uint16_t)(sizeof(GCWhisperHead) + std::strlen(msg)); + std::vector wp = raw(wh); + wp.insert(wp.end(), msg, msg + std::strlen(msg)); + feed(s, wp); + auto cm = s.world().drain_chat(); + CHECK(cm.size() == 1 && cm[0].type == mtnet::CHAT_TYPE_WHISPER && cm[0].from == "Gm" && + cm[0].text == "hey there", + "whisper -> chat queue"); + } + + // --- GC party (77..92) --- + { + GCPartyParameter pp{HDR_GC_PARTY_PARAMETER, 1}; + feed(s, raw(pp)); + CHECK(s.world().party_distribute_mode() == 1, "party distribute mode 1"); + + GCPartyAdd pa{}; + pa.header = HDR_GC_PARTY_ADD; + pa.pid = 5001; + std::strcpy(pa.name, "Mate"); + feed(s, raw(pa)); + const auto *pm = s.world().party_member(5001); + CHECK(pm && pm->name == "Mate", "party_add"); + + GCPartyUpdate pu{}; + pu.header = HDR_GC_PARTY_UPDATE; + pu.pid = 5001; + pu.role = 1; // leader bit + pu.percent_hp = 80; + pu.affects[0] = 3; + feed(s, raw(pu)); + pm = s.world().party_member(5001); + CHECK(pm && pm->leader() && pm->hp_pct == 80 && pm->affects[0] == 3, "party_update"); + + GCPartyLink pl{HDR_GC_PARTY_LINK, 5001, 8888}; + feed(s, raw(pl)); + CHECK(s.world().party_member(5001)->vid == 8888, "party_link -> vid"); + GCPartyUnlink pul{HDR_GC_PARTY_UNLINK, 5001, 8888}; + feed(s, raw(pul)); + CHECK(s.world().party_member(5001)->vid == 0, "party_unlink"); + + GCPartyInvite pi{HDR_GC_PARTY_INVITE, 9999}; + feed(s, raw(pi)); + // (drained by pump_classic in the real client; here just verify no crash + member intact) + CHECK(s.world().party_member(5001) != nullptr, "party still intact after invite"); + + GCPartyRemove pr{HDR_GC_PARTY_REMOVE, 5001}; + feed(s, raw(pr)); + CHECK(s.world().party_member(5001) == nullptr, "party_remove"); + } + + // --- GC_SHOP(38, dynamic): START -> items, END -> closed, error sub --- + { + // [subheader=START][u32 vid][ShopItem43 x 40], only first 2 non-empty + std::vector sp; + sp.push_back(SHOP_SUB_START); + uint32_t svid = 4242; + sp.insert(sp.end(), (uint8_t *)&svid, (uint8_t *)&svid + 4); + ShopItem43 items[SHOP_HOST_ITEM_MAX_NUM]{}; + items[0].vnum = 27001; + items[0].price = 5000; + items[0].count = 1; + items[0].display_pos = 0; + items[2].vnum = 10; + items[2].price = 20; + items[2].count = 200; + items[2].display_pos = 2; + sp.insert(sp.end(), (uint8_t *)items, (uint8_t *)items + sizeof(items)); + // wrap as GC_SHOP dynamic packet: [hdr 38][u16 size][body] + uint16_t sz = (uint16_t)(3 + sp.size()); + std::vector pkt; + pkt.push_back(HDR_GC_SHOP); + pkt.insert(pkt.end(), (uint8_t *)&sz, (uint8_t *)&sz + 2); + pkt.insert(pkt.end(), sp.begin(), sp.end()); + feed(s, pkt); + CHECK(s.world().shop_open() && s.world().shop_vid() == 4242, "shop opened"); + const auto &si = s.world().shop_items(); + CHECK(si.size() == 2 && si[0].vnum == 27001 && si[0].price == 5000 && si[1].pos == 2, + "shop items (empties skipped, display_pos kept)"); + + // error sub-header + std::vector ep = {HDR_GC_SHOP, 4, 0, SHOP_SUB_SOLDOUT}; + feed(s, ep); + auto errs = s.world().drain_shop_errors(); + CHECK(errs.size() == 1 && errs[0] == "SOLDOUT", "shop error SOLDOUT"); + + std::vector ce = {HDR_GC_SHOP, 4, 0, SHOP_SUB_END}; + feed(s, ce); + CHECK(!s.world().shop_open() && s.world().shop_items().empty(), "shop closed"); + } + + // --- GC_SCRIPT(45) / GC_QUEST_CONFIRM(46) / GC_QUEST_INFO(81) --- + { + // GC_SCRIPT dynamic: [hdr 45][u16 size][skin][u16 src_size][text] + const char *dlg = "Hello adventurer!"; + std::vector body; + body.push_back(2); // skin + body.push_back(0); + body.push_back(0); // src_size + body.insert(body.end(), dlg, dlg + std::strlen(dlg)); + uint16_t sz = (uint16_t)(3 + body.size()); + std::vector pkt = {HDR_GC_SCRIPT}; + pkt.insert(pkt.end(), (uint8_t *)&sz, (uint8_t *)&sz + 2); + pkt.insert(pkt.end(), body.begin(), body.end()); + feed(s, pkt); + auto sc = s.world().drain_scripts(); + CHECK(sc.size() == 1 && sc[0].skin == 2 && sc[0].text == "Hello adventurer!", "script cue"); + + GCQuestConfirm qc{}; + qc.header = HDR_GC_QUEST_CONFIRM; + std::strcpy(qc.msg, "Accept quest?"); + qc.timeout = 30; + qc.request_pid = 555; + feed(s, raw(qc)); + auto cf = s.world().drain_confirms(); + CHECK(cf.size() == 1 && cf[0].msg == "Accept quest?" && cf[0].timeout == 30 && + cf[0].request_pid == 555, + "quest confirm cue"); + + // GC_QUEST_INFO dynamic: [hdr 81][u16 size][u16 index][u8 flag][TITLE\0][COUNTER_NAME\0][i32] + std::vector qb; + uint16_t qidx = 3; + qb.insert(qb.end(), (uint8_t *)&qidx, (uint8_t *)&qidx + 2); + uint8_t qflag = QUEST_SEND_TITLE | QUEST_SEND_COUNTER_NAME | QUEST_SEND_COUNTER_VALUE; + qb.push_back(qflag); + const char *qt = "Kill 10 wolves"; + qb.insert(qb.end(), qt, qt + std::strlen(qt) + 1); + const char *cn = "Wolves"; + qb.insert(qb.end(), cn, cn + std::strlen(cn) + 1); + int32_t cv = 4; + qb.insert(qb.end(), (uint8_t *)&cv, (uint8_t *)&cv + 4); + uint16_t qsz = (uint16_t)(3 + qb.size()); + std::vector qpkt = {HDR_GC_QUEST_INFO}; + qpkt.insert(qpkt.end(), (uint8_t *)&qsz, (uint8_t *)&qsz + 2); + qpkt.insert(qpkt.end(), qb.begin(), qb.end()); + feed(s, qpkt); + const mtnet::QuestInfo *q = s.world().quest(3); + CHECK(q && q->title == "Kill 10 wolves" && q->counter_name == "Wolves" && + q->counter_value == 4, + "quest info parsed (flag-driven)"); + } + + // --- GC_DUEL_START dynamic: [hdr 40][u16 whole_size][opponent VIDs] --- + { + uint32_t opponent_vids[] = {41001, 41002}; + uint16_t duel_size = (uint16_t)(sizeof(GCDuelStart) + sizeof(opponent_vids)); + std::vector duel_pkt = {HDR_GC_DUEL_START}; + duel_pkt.insert(duel_pkt.end(), (uint8_t *)&duel_size, (uint8_t *)&duel_size + 2); + duel_pkt.insert(duel_pkt.end(), (uint8_t *)opponent_vids, + (uint8_t *)opponent_vids + sizeof(opponent_vids)); + feed(s, duel_pkt); + const auto &opponents = s.world().duel_opponents(); + CHECK(opponents.size() == 2 && opponents[0] == 41001 && opponents[1] == 41002 && + !s.world().duel_cannot_attack(), + "duel start opponent list"); + CHECK(s.world().take_duel_started(), "duel start event"); + + uint16_t empty_duel_size = sizeof(GCDuelStart); + std::vector empty_duel = {HDR_GC_DUEL_START}; + empty_duel.insert(empty_duel.end(), (uint8_t *)&empty_duel_size, + (uint8_t *)&empty_duel_size + 2); + feed(s, empty_duel); + CHECK(s.world().duel_opponents().empty() && s.world().duel_cannot_attack(), + "empty duel start cannot-attack state"); + } + + // --- P8 messenger (74, dynamic): complete list + login/logout deltas --- + { + std::vector body = {MESSENGER_GC_LIST, 1, 5}; + body.insert(body.end(), {'A', 'l', 'i', 'c', 'e'}); + body.push_back(0); + body.push_back(3); + body.insert(body.end(), {'B', 'o', 'b'}); + GCMessengerHead h{HDR_GC_MESSENGER, + static_cast(sizeof(GCMessengerHead) + body.size() - 1), body[0]}; + std::vector pkt = raw(h); + pkt.insert(pkt.end(), body.begin() + 1, body.end()); + feed(s, pkt); + auto fs = s.world().friends(); + CHECK(fs.size() == 2, "messenger list friend count"); + bool alice = false, bob = false; + for (const auto &f : fs) { + alice = alice || (f.name == "Alice" && f.online); + bob = bob || (f.name == "Bob" && !f.online); + } + CHECK(alice && bob, "messenger list online state"); + + std::vector login_body = {MESSENGER_GC_LOGIN, 3, 'B', 'o', 'b'}; + GCMessengerHead login_h{HDR_GC_MESSENGER, + static_cast(sizeof(GCMessengerHead) + login_body.size() - 1), + login_body[0]}; + std::vector login_pkt = raw(login_h); + login_pkt.insert(login_pkt.end(), login_body.begin() + 1, login_body.end()); + feed(s, login_pkt); + fs = s.world().friends(); + bool bob_online = false; + for (const auto &f : fs) { + bob_online = bob_online || (f.name == "Bob" && f.online); + } + CHECK(fs.size() == 2 && bob_online, "messenger login update"); + + std::vector logout_body = {MESSENGER_GC_LOGOUT, 5, 'A', 'l', 'i', 'c', 'e'}; + GCMessengerHead logout_h{HDR_GC_MESSENGER, + static_cast(sizeof(GCMessengerHead) + logout_body.size() - 1), + logout_body[0]}; + std::vector logout_pkt = raw(logout_h); + logout_pkt.insert(logout_pkt.end(), logout_body.begin() + 1, logout_body.end()); + feed(s, logout_pkt); + fs = s.world().friends(); + bool alice_offline = false; + for (const auto &f : fs) { + alice_offline = alice_offline || (f.name == "Alice" && !f.online); + } + CHECK(fs.size() == 2 && alice_offline, "messenger logout update"); + + std::vector mobile_body = {MESSENGER_GC_MOBILE, 1, 5, + 'A', 'l', 'i', 'c', 'e'}; + GCMessengerHead mobile_h{HDR_GC_MESSENGER, + static_cast(sizeof(GCMessengerHead) + mobile_body.size() - 1), + mobile_body[0]}; + std::vector mobile_pkt = raw(mobile_h); + mobile_pkt.insert(mobile_pkt.end(), mobile_body.begin() + 1, mobile_body.end()); + feed(s, mobile_pkt); + bool alice_mobile = false; + for (const auto &f : s.world().friends()) { + alice_mobile = alice_mobile || (f.name == "Alice" && f.mobile); + } + CHECK(alice_mobile, "messenger mobile state"); + } + + // --- P8 exchange (42, static) ------------------------------------------- + { + GCExchange ex{}; + ex.header = HDR_GC_EXCHANGE; + ex.subheader = EXCHANGE_GC_START; + ex.arg1 = 31337; + feed(s, raw(ex)); + CHECK(s.world().exchange().active && s.world().exchange().partner_vid == 31337, + "exchange start"); + + ex = GCExchange{}; + ex.header = HDR_GC_EXCHANGE; + ex.subheader = EXCHANGE_GC_ITEM_ADD; + ex.is_me = 1; + ex.arg1 = 27001; + ex.arg2 = {0, 4}; + ex.arg3 = 7; + feed(s, raw(ex)); + CHECK(s.world().exchange().self_items[4].vnum == 27001 && + s.world().exchange().self_items[4].count == 7, "exchange item add"); + + ex.subheader = EXCHANGE_GC_GOLD_ADD; + ex.arg1 = 123456; + feed(s, raw(ex)); + CHECK(s.world().exchange().self_gold == 123456, "exchange gold"); + ex.subheader = EXCHANGE_GC_ACCEPT; + ex.arg1 = 1; + feed(s, raw(ex)); + CHECK(s.world().exchange().self_accept, "exchange accept"); + ex.subheader = EXCHANGE_GC_END; + feed(s, raw(ex)); + CHECK(!s.world().exchange().active, "exchange end"); + } + + // --- Guild dynamic packets: members, presence, comments, invite, score -- + { + GuildMember38 member{}; + member.pid = 7001; + member.grade = 1; + member.is_general = 1; + member.job = 2; + member.level = 55; + member.offer = 1234; + member.name_flag = 1; + std::strcpy(member.name, "Guildmate"); + std::vector body = {mtnet::GUILD_GC_LIST}; + auto member_bytes = raw(member); + body.insert(body.end(), member_bytes.begin(), member_bytes.end()); + GCMessengerHead gh{HDR_GC_GUILD, + static_cast(sizeof(GCMessengerHead) + body.size() - 1), body[0]}; + std::vector guild_pkt = raw(gh); + guild_pkt.insert(guild_pkt.end(), body.begin() + 1, body.end()); + feed(s, guild_pkt); + auto members = s.world().guild_members(); + CHECK(members.size() == 1 && members[0].pid == 7001 && members[0].name == "Guildmate" && + members[0].is_general, "guild member list"); + + std::vector login_body = {mtnet::GUILD_GC_LOGIN, 0, 0, 0, 0}; + std::memcpy(login_body.data() + 1, &member.pid, sizeof(member.pid)); + gh.size = static_cast(sizeof(GCMessengerHead) + login_body.size() - 1); + gh.subheader = login_body[0]; + guild_pkt = raw(gh); + guild_pkt.insert(guild_pkt.end(), login_body.begin() + 1, login_body.end()); + feed(s, guild_pkt); + members = s.world().guild_members(); + CHECK(members.size() == 1 && members[0].online, "guild member login"); + + GuildComment80 comment{}; + comment.id = 17; + std::strcpy(comment.name, "Guildmate"); + std::strcpy(comment.content, "Welcome to the guild"); + std::vector comments_body = {mtnet::GUILD_GC_COMMENTS, 1}; + auto comment_bytes = raw(comment); + comments_body.insert(comments_body.end(), comment_bytes.begin(), comment_bytes.end()); + gh.size = static_cast(sizeof(GCMessengerHead) + comments_body.size() - 1); + gh.subheader = comments_body[0]; + guild_pkt = raw(gh); + guild_pkt.insert(guild_pkt.end(), comments_body.begin() + 1, comments_body.end()); + feed(s, guild_pkt); + const auto &comments = s.world().guild_comments(); + CHECK(comments.size() == 1 && comments[0].id == 17 && + comments[0].content == "Welcome to the guild", "guild comments"); + + GuildInvite17 invite{9001, "Wolves"}; + std::vector invite_body = {mtnet::GUILD_GC_GUILD_INVITE}; + auto invite_bytes = raw(invite); + invite_body.insert(invite_body.end(), invite_bytes.begin(), invite_bytes.end()); + gh.size = static_cast(sizeof(GCMessengerHead) + invite_body.size() - 1); + gh.subheader = invite_body[0]; + guild_pkt = raw(gh); + guild_pkt.insert(guild_pkt.end(), invite_body.begin() + 1, invite_body.end()); + feed(s, guild_pkt); + auto invites = s.world().drain_guild_invites(); + CHECK(invites.size() == 1 && invites[0].guild_id == 9001 && + invites[0].guild_name == "Wolves", "guild invite"); + + GuildWarPoint12 score{77, 88, 12}; + std::vector score_body = {mtnet::GUILD_GC_WAR_POINT}; + auto score_bytes = raw(score); + score_body.insert(score_body.end(), score_bytes.begin(), score_bytes.end()); + gh.size = static_cast(sizeof(GCMessengerHead) + score_body.size() - 1); + gh.subheader = score_body[0]; + guild_pkt = raw(gh); + guild_pkt.insert(guild_pkt.end(), score_body.begin() + 1, score_body.end()); + feed(s, guild_pkt); + auto scores = s.world().drain_guild_war_scores(); + CHECK(scores.size() == 1 && scores[0].gain_guild_id == 77 && scores[0].point == 12, + "guild war score"); + } + + // --- P8 safebox / mall fixed packets ------------------------------------ + { + GCSafeboxSize sb_size{HDR_GC_SAFEBOX_SIZE, 2}; + feed(s, raw(sb_size)); + GCSafeboxMoneyChange sb_money{HDR_GC_SAFEBOX_MONEY_CHANGE, 987654}; + feed(s, raw(sb_money)); + GCItemSet sb_item{}; + sb_item.header = HDR_GC_SAFEBOX_SET; + sb_item.cell = {3, 8}; + sb_item.vnum = 50001; + sb_item.count = 9; + sb_item.sockets[0] = 60001; + sb_item.attrs[0] = {5, 30}; + feed(s, raw(sb_item)); + CHECK(s.world().safebox_open() && s.world().safebox_size() == 2 && + s.world().safebox_gold() == 987654, "safebox open/money"); + CHECK(s.world().safebox_slot(8).vnum == 50001 && s.world().safebox_slot(8).count == 9 && + s.world().safebox_slot(8).sockets[0] == 60001 && + s.world().safebox_slot(8).attrs[0].value == 30, "safebox item set"); + GCItemDel sb_del{HDR_GC_SAFEBOX_DEL, 8}; + feed(s, raw(sb_del)); + CHECK(s.world().safebox_slot(8).empty(), "safebox item del"); + + GCMallOpen mall_open{HDR_GC_MALL_OPEN, 1}; + feed(s, raw(mall_open)); + GCItemSet mall_item{}; + mall_item.header = HDR_GC_MALL_SET; + mall_item.cell = {4, 3}; + mall_item.vnum = 70001; + mall_item.count = 2; + feed(s, raw(mall_item)); + CHECK(s.world().mall_open() && s.world().mall_size() == 1 && + s.world().mall_slot(3).vnum == 70001, "mall open/item set"); + GCItemDel mall_del{HDR_GC_MALL_DEL, 3}; + feed(s, raw(mall_del)); + CHECK(s.world().mall_slot(3).empty(), "mall item del"); + } + + // --- P8 outbound intents: fixed packets carry one trailing sequence byte --- + { + uint32_t seq = s.stream().sequence_index(); + CHECK(s.send_friend_add("Alice"), "send_friend_add"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGMessenger) + CHARACTER_NAME_MAX_LEN + 1 && + out[0] == HDR_CG_MESSENGER && out[1] == MESSENGER_CG_ADD_BY_NAME && + std::memcmp(out.data() + sizeof(CGMessenger), "Alice", 5) == 0 && + out.back() == SEQUENCE_TABLE[seq], "friend add wire + sequence"); + ++seq; + + CHECK(s.send_friend_remove("Alice"), "send_friend_remove"); + out = drain(s); + CHECK(out.size() == sizeof(CGMessenger) + CHARACTER_NAME_MAX_LEN + 1 && + out[1] == MESSENGER_CG_REMOVE && out.back() == SEQUENCE_TABLE[seq], + "friend remove wire + sequence"); + ++seq; + + CHECK(s.send_exchange_start(31337), "send_exchange_start"); + out = drain(s); + CGExchange cg_ex{}; + std::memcpy(&cg_ex, out.data(), sizeof(cg_ex)); + CHECK(out.size() == sizeof(CGExchange) + 1 && cg_ex.subheader == EXCHANGE_CG_START && + cg_ex.arg1 == 31337 && out.back() == SEQUENCE_TABLE[seq], + "exchange start wire + sequence"); + ++seq; + + CHECK(s.send_exchange_item_add(1, 12, 4), "send_exchange_item_add"); + out = drain(s); + std::memcpy(&cg_ex, out.data(), sizeof(cg_ex)); + CHECK(cg_ex.subheader == EXCHANGE_CG_ITEM_ADD && cg_ex.arg2 == 4 && + cg_ex.pos.window_type == 1 && cg_ex.pos.cell == 12 && out.back() == SEQUENCE_TABLE[seq], + "exchange item wire"); + ++seq; + + CHECK(s.send_exchange_gold(900), "send_exchange_gold"); + out = drain(s); + std::memcpy(&cg_ex, out.data(), sizeof(cg_ex)); + CHECK(cg_ex.subheader == EXCHANGE_CG_GOLD_ADD && cg_ex.arg1 == 900 && + out.back() == SEQUENCE_TABLE[seq], "exchange gold wire"); + ++seq; + + CHECK(s.send_exchange_accept(), "send_exchange_accept"); + out = drain(s); + std::memcpy(&cg_ex, out.data(), sizeof(cg_ex)); + CHECK(cg_ex.subheader == EXCHANGE_CG_ACCEPT && out.back() == SEQUENCE_TABLE[seq], + "exchange accept wire"); + ++seq; + + CHECK(s.send_exchange_cancel(), "send_exchange_cancel"); + out = drain(s); + std::memcpy(&cg_ex, out.data(), sizeof(cg_ex)); + CHECK(cg_ex.subheader == EXCHANGE_CG_CANCEL && out.back() == SEQUENCE_TABLE[seq], + "exchange cancel wire"); + ++seq; + + CHECK(s.send_safebox_checkin(8, 1, 12), "send_safebox_checkin"); + out = drain(s); + CGSafeboxCheckin checkin{}; + std::memcpy(&checkin, out.data(), sizeof(checkin)); + CHECK(checkin.header == HDR_CG_SAFEBOX_CHECKIN && checkin.safe_pos == 8 && + checkin.item_pos.window_type == 1 && checkin.item_pos.cell == 12 && + out.back() == SEQUENCE_TABLE[seq], "safebox checkin wire"); + ++seq; + + CHECK(s.send_safebox_checkout(8, 1, 12), "send_safebox_checkout"); + out = drain(s); + CHECK(out.size() == sizeof(CGSafeboxCheckout) + 1 && + out[0] == HDR_CG_SAFEBOX_CHECKOUT && out.back() == SEQUENCE_TABLE[seq], + "safebox checkout wire"); + ++seq; + + CHECK(s.send_safebox_move(8, 9, 2), "send_safebox_move"); + out = drain(s); + CGItemMove move{}; + std::memcpy(&move, out.data(), sizeof(move)); + CHECK(move.header == HDR_CG_SAFEBOX_ITEM_MOVE && move.pos.window_type == 1 && + move.pos.cell == 8 && move.change_pos.cell == 9 && move.num == 2 && + out.back() == SEQUENCE_TABLE[seq], "safebox move wire"); + ++seq; + + CHECK(s.send_mall_checkout(3, 1, 22), "send_mall_checkout"); + out = drain(s); + CGMallCheckout mall{}; + std::memcpy(&mall, out.data(), sizeof(mall)); + CHECK(mall.header == HDR_CG_MALL_CHECKOUT && mall.mall_pos == 3 && + mall.item_pos.window_type == 1 && mall.item_pos.cell == 22 && + out.back() == SEQUENCE_TABLE[seq], "mall checkout wire"); + CHECK(s.stream().sequence_index() == seq + 1, "P8 sequence index advanced"); + } + + // --- 40250 command-backed cube intents ------------------------------- + { + uint32_t seq = s.stream().sequence_index(); + CHECK(s.send_cube_open(), "cube open"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGChatHead) + 10 + 1 + 1 && + std::memcmp(out.data() + sizeof(CGChatHead), "/cube open", 10) == 0 && + out.back() == SEQUENCE_TABLE[seq], "cube open command wire"); + ++seq; + CHECK(s.send_cube_add_item(2, 17), "cube add"); + out = drain(s); + CHECK(out.size() == sizeof(CGChatHead) + 14 + 1 + 1 && + std::memcmp(out.data() + sizeof(CGChatHead), "/cube add 2 17", 14) == 0 && + out.back() == SEQUENCE_TABLE[seq], "cube add command wire"); + ++seq; + CHECK(s.send_cube_delete_item(2), "cube delete"); + out = drain(s); + CHECK(out.size() == sizeof(CGChatHead) + 14 + 1 + 1 && + std::memcmp(out.data() + sizeof(CGChatHead), "/cube delete 2", 14) == 0 && + out.back() == SEQUENCE_TABLE[seq], "cube delete command wire"); + ++seq; + CHECK(s.send_cube_list(), "cube list"); + out = drain(s); + CHECK(out.size() == sizeof(CGChatHead) + 10 + 1 + 1 && + std::memcmp(out.data() + sizeof(CGChatHead), "/cube list", 10) == 0 && + out.back() == SEQUENCE_TABLE[seq], "cube list command wire"); + ++seq; + CHECK(s.send_cube_close(), "cube close"); + out = drain(s); + CHECK(out.size() == sizeof(CGChatHead) + 11 + 1 + 1 && + std::memcmp(out.data() + sizeof(CGChatHead), "/cube close", 11) == 0 && + out.back() == SEQUENCE_TABLE[seq], "cube close command wire"); + CHECK(!s.send_cube_add_item(24, 17), "cube index bounds"); + } + + // --- Guild comment/invite answer intents ------------------------------- + { + uint32_t seq = s.stream().sequence_index(); + CHECK(s.send_guild_comment("hello"), "send guild comment"); + auto out = drain(s); + CHECK(out.size() == sizeof(CGGuild) + 1 + 5 + 1 + 1 && out[0] == HDR_CG_GUILD && + out[1] == GUILD_CG_POST_COMMENT && out[2] == 6 && + std::memcmp(out.data() + sizeof(CGGuild) + 1, "hello", 5) == 0 && + out[sizeof(CGGuild) + 1 + 5] == 0 && + out.back() == SEQUENCE_TABLE[seq], "guild comment wire"); + ++seq; + CHECK(s.send_guild_grade_name(2, "Officer"), "send guild grade name"); + out = drain(s); + CHECK(out.size() == sizeof(CGGuild) + 1 + 9 + 1 && + out[1] == GUILD_CG_CHANGE_GRADE_NAME && out[2] == 2 && + std::memcmp(out.data() + sizeof(CGGuild) + 1, "Officer", 7) == 0 && + out[sizeof(CGGuild) + 1 + 7] == 0 && + out.back() == SEQUENCE_TABLE[seq], "guild grade name wire"); + ++seq; + CHECK(s.send_guild_grade_authority(2, 7), "send guild grade authority"); + out = drain(s); + CHECK(out.size() == sizeof(CGGuild) + 2 + 1 && + out[1] == GUILD_CG_CHANGE_GRADE_AUTHORITY && out[2] == 2 && out[3] == 7 && + out.back() == SEQUENCE_TABLE[seq], "guild grade authority wire"); + ++seq; + CHECK(s.send_guild_member_grade(1234, 3), "send guild member grade"); + out = drain(s); + uint32_t pid = 0; + std::memcpy(&pid, out.data() + sizeof(CGGuild), sizeof(pid)); + CHECK(out.size() == sizeof(CGGuild) + 4 + 1 + 1 && + out[1] == GUILD_CG_CHANGE_MEMBER_GRADE && pid == 1234 && + out[sizeof(CGGuild) + 4] == 3 && out.back() == SEQUENCE_TABLE[seq], + "guild member grade wire"); + ++seq; + CHECK(s.send_guild_member_general(1234, true), "send guild member general"); + out = drain(s); + std::memcpy(&pid, out.data() + sizeof(CGGuild), sizeof(pid)); + CHECK(out.size() == sizeof(CGGuild) + 4 + 1 + 1 && + out[1] == GUILD_CG_CHANGE_MEMBER_GENERAL && pid == 1234 && + out[sizeof(CGGuild) + 4] == 1 && out.back() == SEQUENCE_TABLE[seq], + "guild member general wire"); + ++seq; + CHECK(s.send_guild_invite_answer(9001, true), "send guild invite answer"); + out = drain(s); + uint32_t gid = 0; + std::memcpy(&gid, out.data() + sizeof(CGGuild), sizeof(gid)); + CHECK(out.size() == sizeof(CGGuild) + 4 + 1 + 1 && out[1] == GUILD_CG_GUILD_INVITE_ANSWER && + gid == 9001 && out[sizeof(CGGuild) + 4] == 1 && + out.back() == SEQUENCE_TABLE[seq], "guild invite answer wire"); + } + + // --- GC_CHAR_ADDITIONAL_INFO(136): fills a spawned entity's name/parts/level --- + { + GCCharAddInfo ci{}; + ci.header = HDR_GC_CHAR_ADDITIONAL_INFO; + ci.vid = 8888; + std::strcpy(ci.name, "Goblin"); + ci.parts[0] = 3; + ci.empire = 1; + ci.guild_id = 0; + ci.level = 12; + feed(s, raw(ci)); + const auto *e = s.world().get(8888); + CHECK(e && e->name == "Goblin" && e->level == 12 && e->parts[0] == 3, "char_add_info"); + } + + // --- GC_SYNC_POSITION(5, dynamic): snap entities --- + { + struct { + uint8_t hdr; + uint16_t size; + } __attribute__((packed)) sph{HDR_GC_SYNC_POSITION, 0}; + SyncPosElement el{8888, 999000, 888000}; + sph.size = (uint16_t)(sizeof(sph) + sizeof(el)); + std::vector sp(sizeof(sph)); + std::memcpy(sp.data(), &sph, sizeof(sph)); + auto eb = raw(el); + sp.insert(sp.end(), eb.begin(), eb.end()); + feed(s, sp); + const auto *e = s.world().get(8888); + CHECK(e && e->x == 999000.f && e->y == 888000.f && !e->moving, "sync_position snapped"); + } + + // --- GC_ITEM_GROUND_ADD(26) / DEL(27) --- + { + GCItemGroundAdd ga{}; + ga.header = HDR_GC_ITEM_GROUND_ADD; + ga.vid = 55555; + ga.vnum = 1; + ga.x = 100200; + ga.y = 200300; + ga.z = 4; + feed(s, raw(ga)); + CHECK(s.world().ground(55555) != nullptr, "ground item added"); + GCItemGroundDel gd{HDR_GC_ITEM_GROUND_DEL, 55555}; + feed(s, raw(gd)); + CHECK(s.world().ground(55555) == nullptr, "ground item removed"); + } + + // --- GC_CHARACTER_DEL(2) --- + { + GCCharacterDel del{HDR_GC_CHARACTER_DEL, 8888}; + feed(s, raw(del)); + CHECK(s.world().get(8888) == nullptr, "npc despawned"); + CHECK(s.world().size() == 1, "1 entity left"); + } + + // --- intents are rejected outside PHASE_GAME --- + { + ClassicSession s2; + CHECK(!s2.send_move(1, 0, 0, 0, 0), "send_move rejected before InGame"); + CHECK(!s2.send_chat(0, "hi"), "send_chat rejected before InGame"); + } + + CHECK(s.last_error().empty(), "no error over the whole flow"); + + if (g_fail) { + std::fprintf(stderr, "%d check(s) failed\n", g_fail); + return 1; + } + std::puts("net_classic_session_test OK"); + return 0; +} diff --git a/extension/tests/net_classic_stream_test.cpp b/extension/tests/net_classic_stream_test.cpp new file mode 100644 index 00000000..d09576f3 --- /dev/null +++ b/extension/tests/net_classic_stream_test.cpp @@ -0,0 +1,241 @@ +// net_classic_stream_test — 40250 "classic" framing layer, socket-free. +// Drives ClassicStream via feed()/take_outgoing() with synthetic packets. +#include "../src/net/classic/classic_stream.h" + +#include +#include +#include +#include + +using namespace mtnet::classic; + +static int g_fail = 0; +#define CHECK(c, msg) \ + do { \ + if (!(c)) { \ + std::fprintf(stderr, "FAIL: %s\n", msg); \ + ++g_fail; \ + } \ + } while (0) + +template +static std::vector raw(const T &s) { + std::vector b(sizeof(T)); + std::memcpy(b.data(), &s, sizeof(T)); + return b; +} + +static std::vector drain(ClassicStream &s) { + std::vector out; + uint8_t buf[4096]; + for (;;) { + size_t n = s.take_outgoing(buf, sizeof(buf)); + if (!n) { + break; + } + out.insert(out.end(), buf, buf + n); + } + return out; +} + +int main() { + // ---------------------------------------------------------- handshake echo + { + ClassicStream s; + Handshake hs{}; + hs.header = HDR_HANDSHAKE; + hs.handshake = 0xDEADBEEF; + hs.time = 1000; + hs.delta = 50; + auto b = raw(hs); + s.feed(b.data(), b.size()); + + auto out = drain(s); + CHECK(out.size() == sizeof(Handshake), "handshake echo is 13 bytes (no seq)"); + Handshake echo{}; + std::memcpy(&echo, out.data(), sizeof(echo)); + CHECK(echo.header == HDR_HANDSHAKE, "echo keeps header 0xFF"); + CHECK(echo.handshake == 0xDEADBEEF, "echo keeps handshake id"); + CHECK(echo.time == 1000u + 2u * 50u, "echo time = time + 2*delta"); + CHECK(echo.delta == 0, "echo delta = 0"); + + Handshake resync{}; + resync.header = HDR_HANDSHAKE; + resync.handshake = 0xDEADBEEF; + resync.time = 2000; + resync.delta = 10; + s.set_sequence_mode(true); + s.set_time_sync_mode(true); + b = raw(resync); + s.feed(b.data(), b.size()); + out = drain(s); + CHECK(out.size() == sizeof(Handshake) + 1, "later handshake uses time-sync + seq"); + Handshake sync_echo{}; + std::memcpy(&sync_echo, out.data(), sizeof(sync_echo)); + CHECK(sync_echo.header == HDR_CG_TIME_SYNC, "later handshake header is CG_TIME_SYNC"); + CHECK(sync_echo.time == 2000u + 2u * 10u && sync_echo.delta == 0, + "later handshake time fields are converged"); + CHECK(out[sizeof(Handshake)] == SEQUENCE_TABLE[0], "time-sync uses next sequence byte"); + } + + // ---------------------------------------------------------- GC_PHASE + { + ClassicStream s; + int seen = -1; + s.on_phase = [&](uint8_t p) { seen = p; }; + Phase_ p{HDR_GC_PHASE, PHASE_LOGIN}; + auto b = raw(p); + s.feed(b.data(), b.size()); + CHECK(seen == PHASE_LOGIN, "GC_PHASE delivers phase 2"); + } + + // ---------------------------------------------------------- GC_PING -> CG_PONG + { + ClassicStream s; + uint8_t ping = HDR_GC_PING; // 44 + s.feed(&ping, 1); + auto out = drain(s); + CHECK(out.size() == 1 && out[0] == HDR_CG_PONG, "PING -> bare CG_PONG (seq off)"); + + s.set_sequence_mode(true); + s.feed(&ping, 1); + out = drain(s); + CHECK(out.size() == 2 && out[0] == HDR_CG_PONG && out[1] == SEQUENCE_TABLE[0], + "PING -> CG_PONG + seq[0] (seq on)"); + } + + // ---------------------------------------------------------- static GC packet + { + ClassicStream s; + uint8_t got_hdr = 0; + uint32_t got_len = 0; + std::vector got_body; + s.on_packet = [&](uint8_t h, const uint8_t *body, uint32_t len) { + got_hdr = h; + got_len = len; + got_body.assign(body, body + len); + return true; + }; + GCMainCharacter mc{}; + mc.header = HDR_GC_MAIN_CHARACTER; + mc.vid = 0x0A0B0C0D; + mc.race = 4; + std::strcpy(mc.name, "Hero"); + mc.x = 123456; + mc.y = 654321; + mc.z = 7; + mc.empire = 2; + mc.skill_group = 1; + auto b = raw(mc); + s.feed(b.data(), b.size()); + CHECK(got_hdr == HDR_GC_MAIN_CHARACTER, "static: header 113 delivered"); + CHECK(got_len == sizeof(GCMainCharacter) - 1, "static: body len = sizeof-1"); + // body starts right after the header byte -> first 4 bytes are the vid + uint32_t vid; + std::memcpy(&vid, got_body.data(), 4); + CHECK(vid == 0x0A0B0C0D, "static: body begins at vid"); + } + + // ---------------------------------------------------------- dynamic GC packet + { + ClassicStream s; + uint8_t got_hdr = 0; + uint32_t got_len = 0; + std::string got_tail; + s.on_packet = [&](uint8_t h, const uint8_t *body, uint32_t len) { + got_hdr = h; + got_len = len; + got_tail.assign(reinterpret_cast(body), len); + return true; + }; + // GC_CHAT: [header][u16 size][type][u32 vid][empire] + "hi" + const char *msg = "hi"; + GCChatHead ch{}; + ch.header = HDR_GC_CHAT; + ch.type = 1; + ch.vid = 42; + ch.empire = 3; + ch.size = static_cast(sizeof(GCChatHead) + std::strlen(msg)); + std::vector pkt = raw(ch); + pkt.insert(pkt.end(), msg, msg + std::strlen(msg)); + s.feed(pkt.data(), pkt.size()); + CHECK(got_hdr == HDR_GC_CHAT, "dynamic: GC_CHAT delivered"); + // body = everything after [header][u16 size] => (type,vid,empire,"hi") + CHECK(got_len == ch.size - sizeof(DynHead), "dynamic: body len = size - 3"); + CHECK(got_tail.size() >= 2 && got_tail.substr(got_tail.size() - 2) == "hi", + "dynamic: text tail present"); + } + + // ---------------------------------------------------------- send seq sequencing + { + ClassicStream s; + s.set_sequence_mode(true); + CGMove mv{}; + mv.header = HDR_CG_MOVE; + mv.func = 1; + mv.x = 10; + mv.y = 20; + s.send_fixed(raw(mv).data(), sizeof(mv)); + s.send_fixed(raw(mv).data(), sizeof(mv)); + auto out = drain(s); + CHECK(out.size() == 2 * (sizeof(CGMove) + 1), "two CG_MOVE + 2 seq bytes"); + CHECK(out[sizeof(CGMove)] == SEQUENCE_TABLE[0], "first seq = table[0]"); + CHECK(out[2 * sizeof(CGMove) + 1] == SEQUENCE_TABLE[1], "second seq = table[1]"); + CHECK(s.sequence_index() == 2, "seq index advanced to 2"); + } + + // seq off => no trailing byte + { + ClassicStream s; + CGMove mv{}; + mv.header = HDR_CG_MOVE; + s.send_fixed(raw(mv).data(), sizeof(mv)); + CHECK(drain(s).size() == sizeof(CGMove), "seq off: no trailing byte"); + } + + // ---------------------------------------------------------- partial feed + { + ClassicStream s; + int hits = 0; + s.on_packet = [&](uint8_t, const uint8_t *, uint32_t) { + ++hits; + return true; + }; + GCCharacterDel del{HDR_GC_CHARACTER_DEL, 99}; + auto b = raw(del); + s.feed(b.data(), 2); // header + 1 byte of vid + CHECK(hits == 0, "partial: nothing delivered yet"); + s.feed(b.data() + 2, b.size() - 2); + CHECK(hits == 1, "partial: delivered once the rest arrives"); + } + + // ---------------------------------------------------------- unknown header + { + ClassicStream s; + std::string err; + s.on_error = [&](const std::string &e) { err = e; }; + uint8_t bad = 200; // ROULETTE — not in the size table yet + s.feed(&bad, 1); + CHECK(!err.empty(), "unknown header -> on_error"); + CHECK(s.state() == ClassicStream::State::Offline, "unknown header -> disconnect"); + } + + // ---- GC_KEY_AGREEMENT: a partial packet just waits (no error, no crash) ---- + // (the full DH2 exchange lives in net_classic_encstream_test.) + { + ClassicStream s; + std::string err; + s.on_error = [&](const std::string &e) { err = e; }; + uint8_t ka[100] = {HDR_KEY_AGREEMENT}; // < sizeof(KeyAgreement) == 261 + s.feed(ka, sizeof(ka)); + s.feed(ka, sizeof(ka)); // still short (200 < 261) + CHECK(err.empty(), "partial GC_KEY_AGREEMENT -> buffered, no error"); + } + + if (g_fail) { + std::fprintf(stderr, "%d check(s) failed\n", g_fail); + return 1; + } + std::puts("net_classic_stream_test OK"); + return 0; +} diff --git a/extension/tests/net_classic_wire_test.cpp b/extension/tests/net_classic_wire_test.cpp new file mode 100644 index 00000000..3d3e8b75 --- /dev/null +++ b/extension/tests/net_classic_wire_test.cpp @@ -0,0 +1,153 @@ +// net_classic_wire_test — 40250 "classic" backend wire layer. +// The struct sizes are already guarded by static_assert in wire_classic.h (so a +// mismatch is a compile error); this test locks down the size-table / sequence / +// dynamic-flag lookups and a couple of round-trip byte layouts. +#include "../src/net/classic/wire_classic.h" + +#include +#include + +using namespace mtnet::classic; + +static int g_fail = 0; +#define CHECK(c, msg) \ + do { \ + if (!(c)) { \ + std::fprintf(stderr, "FAIL: %s\n", msg); \ + ++g_fail; \ + } \ + } while (0) + +int main() { + // --- header values (spot check vs server packet.h) --- + CHECK(HDR_CG_MOVE == 7, "CG_MOVE == 7"); + CHECK(HDR_GC_MAIN_CHARACTER == 113, "GC_MAIN_CHARACTER == 113"); + CHECK(HDR_GC_LOGIN_SUCCESS_NEWSLOT == 32, "GC_LOGIN_SUCCESS_NEWSLOT == 32"); + CHECK(HDR_HANDSHAKE == 0xFF, "HANDSHAKE == 0xFF"); + CHECK(HDR_GC_TIME_SYNC == 0xFC && HDR_CG_TIME_SYNC == 0xFC, "TIME_SYNC == 0xFC"); + CHECK(HDR_KEY_AGREEMENT == 0xFB, "KEY_AGREEMENT == 0xFB"); + CHECK(PHASE_GAME == 5 && PHASE_SELECT == 3, "EPhase ordinals"); + + // --- struct sizes (redundant with static_assert, but explicit) --- + CHECK(sizeof(Handshake) == 13, "sizeof Handshake"); + CHECK(sizeof(CGText) == 1, "sizeof CG_TEXT base"); + CHECK(sizeof(SimplePlayer) == 63, "sizeof SimplePlayer"); + CHECK(sizeof(GCMainCharacter) == 46, "sizeof GCMainCharacter"); + CHECK(sizeof(GCMainCharacter3BGM) == 71 && sizeof(GCMainCharacter4BGM) == 75, + "sizeof main-character BGM variants"); + CHECK(sizeof(GCCharacterAdd2) == 80 && sizeof(GCCharacterUpdate) == 35, + "sizeof character add/update variants"); + CHECK(sizeof(GCFishing) == 7, "sizeof GC_FISHING"); + CHECK(sizeof(GCWarpClassic) == 15, "sizeof classic GC_WARP"); + CHECK(sizeof(GCAuthSuccess) == 6 && sizeof(GCAuthSuccessOpenID) == 37, + "sizeof auth success packets"); + CHECK(sizeof(GCPasspodFailed) == 130 && sizeof(GCXTrapRequest) == 129 && sizeof(GCHSRequest) == 403, + "sizeof optional security packets"); + CHECK(sizeof(GCLoginSuccess) == 329, "sizeof GCLoginSuccess (NEWSLOT, 4 players)"); + CHECK(sizeof(GCPoints) == 1 + 255 * 4, "sizeof GCPoints"); + CHECK(sizeof(GCPointChange) == 17, "sizeof GCPointChange (int header quirk)"); + CHECK(sizeof(CGMove) == 16, "sizeof CGMove"); + CHECK(sizeof(GCMove) == 24, "sizeof GCMove"); + CHECK(sizeof(CGMessenger) == 2 && sizeof(CGExchange) == 10, "sizeof P8 CG packets"); + CHECK(sizeof(GCExchange) == 47, "sizeof GC_EXCHANGE"); + CHECK(sizeof(GCMessengerHead) == 4 && sizeof(GCSafeboxMoneyChange) == 5, + "sizeof P8 dynamic/storage packets"); + + // --- size-table lookup (body size, no trailing seq byte) --- + CHECK(packet_size_gc(HDR_GC_PHASE) == 2, "gc size PHASE"); + CHECK(packet_size_gc(HDR_GC_MAIN_CHARACTER) == 46, "gc size MAIN_CHARACTER"); + CHECK(packet_size_gc(HDR_GC_WARP) == sizeof(GCWarpClassic), "gc size WARP"); + CHECK(packet_size_gc(HDR_GC_MAIN_CHARACTER3_BGM) == 71 && + packet_size_gc(HDR_GC_MAIN_CHARACTER4_BGM_VOL) == 75, "gc size MAIN_CHARACTER BGM"); + CHECK(packet_size_gc(HDR_GC_CHARACTER_ADD2) == 80 && + packet_size_gc(HDR_GC_CHARACTER_UPDATE2) == 35, "gc size character variants"); + CHECK(packet_size_gc(HDR_GC_FISHING) == 7, "gc size FISHING"); + CHECK(packet_size_gc(HDR_GC_AUTH_SUCCESS) == 6 && + packet_size_gc(HDR_GC_XTRAP_CS1_REQUEST) == 129, "gc size auth/security"); + CHECK(packet_size_gc(HDR_GC_LOGIN_SUCCESS_NEWSLOT) == 329, "gc size LOGIN_SUCCESS_NEWSLOT"); + CHECK(packet_size_gc(HDR_GC_CHARACTER_POINTS) == 1021, "gc size CHARACTER_POINTS"); + CHECK(packet_size_gc(HDR_GC_EXCHANGE) == 47, "gc size EXCHANGE"); + CHECK(packet_size_gc(HDR_GC_SAFEBOX_MONEY_CHANGE) == 5, "gc size SAFEBOX_MONEY_CHANGE"); + CHECK(packet_size_gc(HDR_GC_SAFEBOX_SET) == 51, "gc size SAFEBOX_SET"); + CHECK(packet_size_gc(HDR_GC_MALL_OPEN) == 2, "gc size MALL_OPEN"); + CHECK(packet_size_gc(HDR_GC_CHAT) == 0, "gc size CHAT == 0 (dynamic)"); + CHECK(packet_size_cg(HDR_CG_LOGIN) == 49, "cg size LOGIN"); + CHECK(packet_size_cg(HDR_CG_TEXT) == sizeof(CGText), "cg size TEXT base"); + CHECK(packet_size_cg(HDR_CG_MOVE) == 16, "cg size MOVE"); + CHECK(packet_size_cg(HDR_CG_ENTERGAME) == 1, "cg size ENTERGAME"); + CHECK(packet_size_cg(HDR_CG_EXCHANGE) == 10, "cg size EXCHANGE"); + CHECK(packet_size_cg(HDR_CG_MESSENGER) == 2, "cg size MESSENGER base"); + CHECK(packet_size_cg(HDR_CG_SAFEBOX_ITEM_MOVE) == 8, "cg size SAFEBOX_ITEM_MOVE"); + + // --- sequence-byte flags (docs §2.2) --- + CHECK(is_sequence_cg(HDR_CG_MOVE), "CG_MOVE has sequence"); + CHECK(is_sequence_cg(HDR_CG_LOGIN), "CG_LOGIN has sequence"); + CHECK(is_sequence_cg(HDR_CG_TIME_SYNC), "CG_TIME_SYNC has sequence"); + CHECK(!is_sequence_cg(HDR_HANDSHAKE), "HANDSHAKE no sequence"); + CHECK(!is_sequence_cg(HDR_KEY_AGREEMENT), "KEY_AGREEMENT no sequence"); + CHECK(!is_sequence_cg(HDR_CG_MARK_UPLOAD), "MARK_UPLOAD no sequence"); + CHECK(!is_sequence_cg(HDR_CG_DRAGON_SOUL_REFINE), "DRAGON_SOUL_REFINE no sequence"); + CHECK(!is_sequence_cg(HDR_CG_STATE_CHECKER), "STATE_CHECKER no sequence"); + + // --- dynamic-size flags (docs §2.2) --- + CHECK(is_dynamic_gc(HDR_GC_CHAT), "GC_CHAT dynamic"); + CHECK(is_dynamic_gc(HDR_GC_SHOP), "GC_SHOP dynamic"); + CHECK(is_dynamic_gc(HDR_GC_GUILD), "GC_GUILD dynamic"); + CHECK(is_dynamic_gc(HDR_GC_QUEST_INFO), "GC_QUEST_INFO dynamic"); + CHECK(!is_dynamic_gc(HDR_GC_MALL_SET), "GC_MALL_SET NOT dynamic"); + CHECK(!is_dynamic_gc(HDR_GC_SAFEBOX_SET), "GC_SAFEBOX_SET NOT dynamic"); + CHECK(!is_dynamic_gc(HDR_GC_PARTY_ADD), "GC_PARTY_ADD NOT dynamic"); + // client map registers GC_WHISPER STATIC, but its wSize sits where + // TDynamicSizePacketHeader.size does — we frame it via the dynamic path. + CHECK(is_dynamic_gc(HDR_GC_WHISPER), "GC_WHISPER framed as dynamic (wSize prefix)"); + CHECK(is_dynamic_cg(HDR_CG_CHAT) && is_dynamic_cg(HDR_CG_WHISPER), "CG chat/whisper dynamic"); + CHECK(!is_dynamic_cg(HDR_CG_SHOP), "CG_SHOP NOT dynamic"); + + // --- byte-layout round trip: GC_MAIN_CHARACTER --- + { + GCMainCharacter mc{}; + mc.header = HDR_GC_MAIN_CHARACTER; + mc.vid = 0x11223344; + mc.race = 4; + std::strcpy(mc.name, "Hero"); + mc.x = 100000; + mc.y = 200000; + mc.z = 12; + mc.empire = 2; + mc.skill_group = 1; + + uint8_t buf[sizeof(mc)]; + std::memcpy(buf, &mc, sizeof(mc)); + CHECK(buf[0] == 113, "wire byte 0 == header"); + // header(1) vid(4) race(2) name(25) -> x at offset 32 + int32_t x_wire; + std::memcpy(&x_wire, buf + 1 + 4 + 2 + 25, 4); + CHECK(x_wire == 100000, "wire x at offset 32"); + + GCMainCharacter rt{}; + std::memcpy(&rt, buf, sizeof(rt)); + CHECK(rt.vid == 0x11223344 && rt.z == 12 && rt.empire == 2, "round-trip fields"); + CHECK(std::strcmp(rt.name, "Hero") == 0, "round-trip name"); + } + + // --- GCPointChange: real header byte is buf[0] despite `int32_t header` --- + { + GCPointChange pc{}; + pc.header = HDR_GC_CHARACTER_POINT_CHANGE; // 17 + pc.vid = 7; + pc.type = 5; + pc.amount = -3; + pc.value = 42; + uint8_t buf[sizeof(pc)]; + std::memcpy(buf, &pc, sizeof(pc)); + CHECK(buf[0] == 17, "point_change wire byte 0 == 17"); + CHECK(sizeof(pc) == 17, "point_change wire size 17 (4B int header + 4+1+4+4)"); + } + + if (g_fail) { + std::fprintf(stderr, "%d check(s) failed\n", g_fail); + return 1; + } + std::puts("net_classic_wire_test OK"); + return 0; +} diff --git a/extension/tests/net_entity_test.cpp b/extension/tests/net_entity_test.cpp index 7d570c2f..37c58fd0 100644 --- a/extension/tests/net_entity_test.cpp +++ b/extension/tests/net_entity_test.cpp @@ -825,6 +825,20 @@ int main() { if (f.name == "Bob") bob_now = f.online; } CHECK(bob_now, "messenger: LOGIN flips Bob online"); + + const char *invite = "messenger_auth Alice"; + std::vector invite_buf(sizeof(GCChat) + std::strlen(invite) + 1); + GCChat invite_head{}; + invite_head.header = GC_CHAT; + invite_head.length = (uint16_t)invite_buf.size(); + invite_head.type = CHAT_TYPE_COMMAND; + std::memcpy(invite_buf.data(), &invite_head, sizeof(invite_head)); + std::memcpy(invite_buf.data() + sizeof(invite_head), invite, std::strlen(invite) + 1); + es.apply(GC_CHAT, invite_buf.data(), (uint16_t)invite_buf.size()); + auto invites = es.drain_friend_invites(); + CHECK(invites.size() == 1 && invites[0] == "Alice", + "messenger: invitation command surfaced"); + CHECK(es.drain_friend_invites().empty(), "messenger: invitation queue drained"); } // --- P8 NPC shop (GC_SHOP START / END + error) --- @@ -1414,6 +1428,119 @@ int main() { "cube: COMMAND lines never enter the chat log"); } + // --- 40250 command-bus callbacks outside cube ------------------------- + { + auto cmd = [&](const std::string &text) { + std::vector buf(sizeof(GCChat) + text.size() + 1); + GCChat h{}; + h.header = GC_CHAT; + h.length = (uint16_t)buf.size(); + h.type = CHAT_TYPE_COMMAND; + std::memcpy(buf.data(), &h, sizeof(h)); + std::memcpy(buf.data() + sizeof(h), text.c_str(), text.size() + 1); + es.apply(GC_CHAT, buf.data(), (uint16_t)buf.size()); + }; + cmd("PartyRequestDenied"); + cmd("ShowMeSafeboxPassword"); + cmd("ShowMeMallPassword"); + cmd("RefineSuceeded"); + cmd("RefineFailed"); + cmd("OpenPrivateShop"); + cmd("MyShopPriceList 11209 250000"); + cmd("setblockmode 37"); + cmd("ObserverMode 1"); + cmd("ObserverCount 3"); + cmd("StoneDetect 9001 2 90"); + cmd("StartStaminaConsume 10 77"); + cmd("StopStaminaConsume 55"); + cmd("sms"); + cmd("combo 1"); + cmd("mobile_auth"); + cmd("gift"); + cmd("kiss 1 2"); + cmd("slap 1 2"); + cmd("dance6 1"); + cmd("joy 2"); + auto events = es.drain_server_commands(); + int denied = 0, safe = 0, mall = 0, ok = 0, fail = 0, open = 0, price = 0, block = 0; + int observer = 0, observer_count = 0, stone = 0, stamina_start = 0, stamina_stop = 0; + int mobile = 0, mobile_auth = 0, combo = 0, gift = 0; + for (const auto &ev : events) { + switch (ev.kind) { + case ServerCommandEvent::PartyRequestDenied: ++denied; break; + case ServerCommandEvent::SafeboxPasswordRequired: ++safe; break; + case ServerCommandEvent::SafeboxWrongPassword: break; + case ServerCommandEvent::MallPasswordRequired: ++mall; break; + case ServerCommandEvent::RefineSucceeded: ++ok; break; + case ServerCommandEvent::RefineFailed: ++fail; break; + case ServerCommandEvent::PrivateShopOpenRequested: ++open; break; + case ServerCommandEvent::MyShopPrice: + price += ev.value == 11209 && ev.value2 == 250000; + break; + case ServerCommandEvent::BlockModeChanged: + block += ev.value == 37; + break; + case ServerCommandEvent::ObserverModeChanged: + observer += ev.value == 1 && es.observer_mode(); + break; + case ServerCommandEvent::ObserverCountChanged: + observer_count += ev.value == 3 && es.observer_count() == 3; + break; + case ServerCommandEvent::StoneDetected: + stone += ev.value == 9001 && ev.value2 == 2 && ev.value3 == 90.0f; + break; + case ServerCommandEvent::StaminaStarted: + stamina_start += ev.value == 10 && ev.value2 == 77; + break; + case ServerCommandEvent::StaminaStopped: + stamina_stop += ev.value == 0 && ev.value2 == 55; + break; + case ServerCommandEvent::MobileFlagChanged: + mobile += ev.value == 1 && es.mobile_flag(); + break; + case ServerCommandEvent::MobileAuthRequired: + ++mobile_auth; + break; + case ServerCommandEvent::ComboChanged: + combo += ev.value == 1 && es.combo_skill_flag(); + break; + case ServerCommandEvent::GiftAvailable: + ++gift; + break; + } + } + CHECK(denied == 1 && safe == 1 && mall == 1 && ok == 1 && fail == 1 && open == 1 + && price == 1 && block == 1 && observer == 1 && observer_count == 1 + && stone == 1 && stamina_start == 1 && stamina_stop == 1 && mobile == 1 + && mobile_auth == 1 && combo == 1 && gift == 1 && !es.stamina_consuming() + && es.current_stamina() == 55, + "40250 command bus: callbacks surfaced"); + auto motions = es.drain_motions(); + CHECK(motions.size() == 6 && motions[0].vid == 1 && motions[0].victim_vid == 2 + && motions[0].motion == 308 && motions[1].vid == 2 && motions[1].motion == 308 + && motions[2].motion == 320 && motions[3].motion == 316 + && motions[4].motion == 330 && motions[5].motion == 349, + "40250 command bus: emotions feed the GC_MOTION stream"); + es.set_now(1000); + cmd("StartStaminaConsume 10 77"); + es.drain_server_commands(); + es.set_now(1500); + es.tick(); + CHECK(es.stamina_consuming() && es.current_stamina() == 72 + && es.points().stamina() == 72 && es.take_points_dirty(), + "40250 command bus: stamina drains at server-command rate"); + es.mut_safebox_wrong_password(); + bool wrong_password = false; + for (const auto &ev : es.drain_server_commands()) { + wrong_password = wrong_password || ev.kind == ServerCommandEvent::SafeboxWrongPassword; + } + CHECK(wrong_password, "40250 command bus: wrong safebox password surfaced"); + cmd("CloseSafebox"); + cmd("CloseMall"); + CHECK(!es.safebox_open() && !es.mall_open(), + "40250 command bus: storage close callbacks update state"); + } + // --- despawn --- // --- guild land list + minimap observers --- { diff --git a/extension/tests/net_loopback_test.cpp b/extension/tests/net_loopback_test.cpp index 3ba6b2c1..c4a8cf1b 100644 --- a/extension/tests/net_loopback_test.cpp +++ b/extension/tests/net_loopback_test.cpp @@ -47,16 +47,26 @@ public: uint16_t listen_ephemeral() { m_listen = ::socket(AF_INET, SOCK_STREAM, 0); + if (m_listen < 0) { + return 0; + } int one = 1; setsockopt(m_listen, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); sockaddr_in a{}; a.sin_family = AF_INET; a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.sin_port = 0; - bind(m_listen, (sockaddr *)&a, sizeof(a)); - ::listen(m_listen, 1); + if (::bind(m_listen, (sockaddr *)&a, sizeof(a)) != 0 || ::listen(m_listen, 1) != 0) { + ::close(m_listen); + m_listen = -1; + return 0; + } socklen_t l = sizeof(a); - getsockname(m_listen, (sockaddr *)&a, &l); + if (::getsockname(m_listen, (sockaddr *)&a, &l) != 0) { + ::close(m_listen); + m_listen = -1; + return 0; + } int fl = fcntl(m_listen, F_GETFL, 0); fcntl(m_listen, F_SETFL, fl | O_NONBLOCK); return ntohs(a.sin_port); @@ -694,6 +704,10 @@ int main() { { MockServer srv(MockServer::Mode::Auth); uint16_t port = srv.listen_ephemeral(); + if (port == 0) { + std::fprintf(stdout, "SKIP: localhost socket bind unavailable in this environment\n"); + return 0; + } AuthClient auth("admin", "123456789"); CHECK(auth.connect("127.0.0.1", port), "auth connect"); run(srv, auth, 5000, [&] { return auth.done(); }); diff --git a/extension/third_party/CMakeLists.txt b/extension/third_party/CMakeLists.txt index 34be03f0..69853c61 100644 --- a/extension/third_party/CMakeLists.txt +++ b/extension/third_party/CMakeLists.txt @@ -34,6 +34,9 @@ set(ZSTD_MULTITHREAD_SUPPORT OFF CACHE BOOL "" FORCE) add_subdirectory(zstd/build/cmake zstd-build EXCLUDE_FROM_ALL) add_library(mt3p::zstd ALIAS libzstd_static) +# --- Crypto++ (MT_PROTOCOL=classic cipher) ---------------------------------- +add_subdirectory(cryptopp EXCLUDE_FROM_ALL) + # --- miniLZO ------------------------------------------------------------------ # One translation unit, an amalgamation generated from the LZO sources. Its # public API ( via the shim header) is a strict subset of full LZO. diff --git a/extension/third_party/cryptopp/3way.cpp b/extension/third_party/cryptopp/3way.cpp new file mode 100644 index 00000000..aecbaf01 --- /dev/null +++ b/extension/third_party/cryptopp/3way.cpp @@ -0,0 +1,143 @@ +// 3way.cpp - modified by Wei Dai from Joan Daemen's 3way.c +// The original code and all modifications are in the public domain. + +#include "pch.h" +#include "3way.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ThreeWay_TestInstantiations() +{ + ThreeWay::Encryption x1; + ThreeWay::Decryption x2; +} +#endif + +namespace +{ + const word32 START_E = 0x0b0b; // round constant of first encryption round + const word32 START_D = 0xb1b1; // round constant of first decryption round +} + +static inline word32 reverseBits(word32 a) +{ + a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); + a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); + return ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); +} + +#define mu(a0, a1, a2) \ +{ \ + a1 = reverseBits(a1); \ + word32 t = reverseBits(a0); \ + a0 = reverseBits(a2); \ + a2 = t; \ +} + +#define pi_gamma_pi(a0, a1, a2) \ +{ \ + word32 b0, b2; \ + b2 = rotlConstant<1>(a2); \ + b0 = rotlConstant<22>(a0); \ + a0 = rotlConstant<1>(b0 ^ (a1|(~b2))); \ + a2 = rotlConstant<22>(b2 ^ (b0|(~a1))); \ + a1 ^= (b2|(~b0)); \ +} + +// thanks to Paulo Barreto for this optimized theta() +#define theta(a0, a1, a2) \ +{ \ + word32 b0, b1, c; \ + c = a0 ^ a1 ^ a2; \ + c = rotlConstant<16>(c) ^ rotlConstant<8>(c); \ + b0 = (a0 << 24) ^ (a2 >> 8) ^ (a1 << 8) ^ (a0 >> 24); \ + b1 = (a1 << 24) ^ (a0 >> 8) ^ (a2 << 8) ^ (a1 >> 24); \ + a0 ^= c ^ b0; \ + a1 ^= c ^ b1; \ + a2 ^= c ^ (b0 >> 16) ^ (b1 << 16); \ +} + +#define rho(a0, a1, a2) \ +{ \ + theta(a0, a1, a2); \ + pi_gamma_pi(a0, a1, a2); \ +} + +void ThreeWay::Base::UncheckedSetKey(const byte *uk, unsigned int length, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(length); + + m_rounds = GetRoundsAndThrowIfInvalid(params, this); + + for (unsigned int i=0; i<3; i++) + m_k[i] = (word32)uk[4*i+3] | ((word32)uk[4*i+2]<<8) | ((word32)uk[4*i+1]<<16) | ((word32)uk[4*i]<<24); + + if (!IsForwardTransformation()) + { + theta(m_k[0], m_k[1], m_k[2]); + mu(m_k[0], m_k[1], m_k[2]); + m_k[0] = ByteReverse(m_k[0]); + m_k[1] = ByteReverse(m_k[1]); + m_k[2] = ByteReverse(m_k[2]); + } +} + +void ThreeWay::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut Block; + + word32 a0, a1, a2; + Block::Get(inBlock)(a0)(a1)(a2); + + word32 rc = START_E; + + for(unsigned i=0; i Block; + + word32 a0, a1, a2; + Block::Get(inBlock)(a0)(a1)(a2); + + word32 rc = START_D; + + mu(a0, a1, a2); + for(unsigned i=0; i, public FixedKeyLength<12>, public VariableRounds<11> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "3-Way";} +}; + +/// \brief ThreeWay block cipher +/// \sa 3-Way +class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int m_rounds; + FixedSizeSecBlock m_k; + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ThreeWay::Encryption ThreeWayEncryption; +typedef ThreeWay::Decryption ThreeWayDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/CMakeLists.txt b/extension/third_party/cryptopp/CMakeLists.txt new file mode 100644 index 00000000..fbe1a9db --- /dev/null +++ b/extension/third_party/cryptopp/CMakeLists.txt @@ -0,0 +1,60 @@ +# Crypto++ 8.4.0 — vendored from the 40250 client tree +# (ClientVS22/extern/include/cryptopp, CRYPTOPP_VERSION 840). Needed for the +# MT_PROTOCOL=classic backend's _IMPROVED_PACKET_ENCRYPTION_ cipher: +# DH2 key agreement + hint-selected block ciphers (Twofish default) in CTR mode. +# The server links this exact version (Server/.../extern/cryptopp_8_4_0.tar.gz). +# +# No upstream CMakeLists — we glob the library TUs and drop the test / bench / +# adhoc / FIPS-selftest ones. ASM is disabled everywhere (CRYPTOPP_DISABLE_ASM) +# so the same pure-C++/intrinsics build works on the Android NDK and iOS SDK; +# the classic cipher doesn't need AES-NI / SHA-ext. + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +file(GLOB CRYPTOPP_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") + +# TUs that are the cryptest program / benchmarks / dev scratch, not the library. +set(_cp_exclude + adhoc bench1 bench2 bench3 datatest dlltest fipsalgt fipstest pch + regtest1 regtest2 regtest3 regtest4 test + validat0 validat1 validat2 validat3 validat4 validat5 + validat6 validat7 validat8 validat9 validat10) +foreach(_n ${_cp_exclude}) + list(REMOVE_ITEM CRYPTOPP_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${_n}.cpp") +endforeach() + +# Android: cpu.cpp does `#include "cpu-features.h"` (unconditionally on __ANDROID__) +# and calls android_getCpuFeatures() etc. — those live in the NDK's cpufeatures +# helper, which isn't on the sysroot include path by default. +if(ANDROID) + set(_ndk "${CMAKE_ANDROID_NDK}") + if(NOT _ndk) + set(_ndk "$ENV{ANDROID_NDK_HOME}") + endif() + set(_cpufeat "${_ndk}/sources/android/cpufeatures") + if(EXISTS "${_cpufeat}/cpu-features.c") + list(APPEND CRYPTOPP_SRC "${_cpufeat}/cpu-features.c") + else() + message(FATAL_ERROR "cryptopp/Android: cpu-features.c not found under ${_cpufeat}") + endif() +endif() + +add_library(cryptopp STATIC ${CRYPTOPP_SRC}) +target_include_directories(cryptopp SYSTEM PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") +if(ANDROID) + target_include_directories(cryptopp SYSTEM PRIVATE "${_cpufeat}") +endif() +target_compile_features(cryptopp PUBLIC cxx_std_17) +target_compile_definitions(cryptopp PUBLIC + CRYPTOPP_DISABLE_ASM + CRYPTOPP_DISABLE_SSSE3 + CRYPTOPP_DISABLE_AESNI) +# Upstream is not warning-clean under -Wall; this is vendored 3rd-party code. +target_compile_options(cryptopp PRIVATE -w) +if(NOT MSVC) + target_compile_options(cryptopp PRIVATE -fno-strict-aliasing) +endif() + +# Consumers include etc. — parent dir is on the include path +# above (third_party/), so the "cryptopp/" prefix resolves. +add_library(mt3p::cryptopp ALIAS cryptopp) diff --git a/extension/third_party/cryptopp/License.txt b/extension/third_party/cryptopp/License.txt new file mode 100644 index 00000000..e2a30d9a --- /dev/null +++ b/extension/third_party/cryptopp/License.txt @@ -0,0 +1,83 @@ +Compilation Copyright (c) 1995-2019 by Wei Dai. All rights reserved. +This copyright applies only to this software distribution package +as a compilation, and does not imply a copyright on any particular +file in the package. + +All individual files in this compilation are placed in the public domain by +Wei Dai and other contributors. + +I would like to thank the following authors for placing their works into +the public domain: + +Joan Daemen - 3way.cpp +Leonard Janke - cast.cpp, seal.cpp +Steve Reid - cast.cpp +Phil Karn - des.cpp +Andrew M. Kuchling - md2.cpp, md4.cpp +Colin Plumb - md5.cpp +Seal Woods - rc6.cpp +Chris Morgan - rijndael.cpp +Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp +Richard De Moliner - safer.cpp +Matthew Skala - twofish.cpp +Kevin Springle - camellia.cpp, shacal2.cpp, ttmac.cpp, whrlpool.cpp, ripemd.cpp +Ronny Van Keer - sha3.cpp +Aumasson, Neves, Wilcox-O'Hearn and Winnerlein - blake2.cpp, blake2b_simd.cpp, blake2s_simd.cpp +Aaram Yun - aria.cpp, aria_simd.cpp +Han Lulu, Markku-Juhani O. Saarinen - sm4.cpp sm4_simd.cpp +Daniel J. Bernstein, Jack Lloyd - chacha.cpp, chacha_simd.cpp, chacha_avx.cpp +Andrew Moon - ed25519, x25519, donna_32.cpp, donna_64.cpp, donna_sse.cpp + +The Crypto++ Library uses portions of Andy Polyakov's CRYPTOGAMS for Poly1305 +scalar multiplication, aes_armv4.S, sha1_armv4.S and sha256_armv4.S. CRYPTOGAMS +is dual licensed with a permissive BSD-style license. The CRYPTOGAMS license is +reproduced below. + +The Crypto++ Library uses portions of Jack Lloyd's Botan for ChaCha SSE2 and +AVX. Botan placed the code in public domain for Crypto++ to use. + +The Crypto++ Library (as a compilation) is currently licensed under the Boost +Software License 1.0 (http://www.boost.org/users/license.html). + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +CRYPTOGAMS License + +Copyright (c) 2006-2017, CRYPTOGAMS by +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain copyright notices, + this list of conditions and the following disclaimer. +* 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. +* Neither the name of the CRYPTOGAMS nor the names of its copyright + holder and contributors may be used to endorse or promote products + derived from this software without specific prior written permission. diff --git a/extension/third_party/cryptopp/Readme.txt b/extension/third_party/cryptopp/Readme.txt new file mode 100644 index 00000000..0a52d62c --- /dev/null +++ b/extension/third_party/cryptopp/Readme.txt @@ -0,0 +1,406 @@ +Crypto++: free C++ Class Library of Cryptographic Schemes +Version 8.4 - TBD + +Crypto++ Library is a free C++ class library of cryptographic schemes. +Currently the library contains the following algorithms: + + algorithm type name + + authenticated encryption schemes GCM, CCM, EAX, ChaCha20Poly1305 and + XChaCha20Poly1305 + + high speed stream ciphers ChaCha (8/12/20), ChaCha (IETF), Panama, Salsa20, + Sosemanuk, XSalsa20, XChaCha20 + + AES and AES candidates AES (Rijndael), RC6, MARS, Twofish, Serpent, + CAST-256 + + ARIA, Blowfish, Camellia, CHAM, HIGHT, IDEA, + Kalyna (128/256/512), LEA, SEED, RC5, SHACAL-2, + other block ciphers SIMON (64/128), Skipjack, SPECK (64/128), + Simeck, SM4, Threefish (256/512/1024), + Triple-DES (DES-EDE2 and DES-EDE3), TEA, XTEA + + block cipher modes of operation ECB, CBC, CBC ciphertext stealing (CTS), + CFB, OFB, counter mode (CTR), XTS + + message authentication codes BLAKE2s, BLAKE2b, CMAC, CBC-MAC, DMAC, GMAC, HMAC, + Poly1305, Poly1305 (IETF), SipHash, Two-Track-MAC, + VMAC + + BLAKE2s, BLAKE2b, Keccack (F1600), SHA-1, + hash functions SHA-2 (224/256/384/512), SHA-3 (224/256/384/512), + SHAKE (128/256), SipHash, SM3, Tiger, + RIPEMD (128/160/256/320), WHIRLPOOL + + RSA, DSA, Determinsitic DSA, ElGamal, + public-key cryptography Nyberg-Rueppel (NR), Rabin-Williams (RW), LUC, + LUCELG, EC-based German Digital Signature (ECGDSA), + DLIES (variants of DHAES), ESIGN + + padding schemes for public-key PKCS#1 v2.0, OAEP, PSS, PSSR, IEEE P1363 + systems EMSA2 and EMSA5 + + Diffie-Hellman (DH), Unified Diffie-Hellman (DH2), + key agreement schemes Menezes-Qu-Vanstone (MQV), Hashed MQV (HMQV), + Fully Hashed MQV (FHMQV), LUCDIF, XTR-DH + + elliptic curve cryptography ECDSA, Determinsitic ECDSA, ed25519, ECNR, ECIES, + ECDH, ECMQV, x25519 + + insecure or obsolescent MD2, MD4, MD5, Panama Hash, DES, ARC4, SEAL +algorithms retained for backwards 3.0, WAKE-OFB, DESX (DES-XEX3), RC2, + compatibility and historical SAFER, 3-WAY, GOST, SHARK, CAST-128, Square + value + +Other features include: + + * pseudo random number generators (PRNG): ANSI X9.17 appendix C, RandomPool, + DARN, VIA Padlock, RDRAND, RDSEED, NIST Hash and HMAC DRBGs + * password based key derivation functions: PBKDF1 and PBKDF2 from PKCS #5, + PBKDF from PKCS #12 appendix B, HKDF from RFC 5869, Scrypt from RFC 7914 + * Shamir's secret sharing scheme and Rabin's information dispersal algorithm + (IDA) + * fast multi-precision integer (bignum) and polynomial operations + * finite field arithmetics, including GF(p) and GF(2^n) + * prime number generation and verification + * useful non-cryptographic algorithms + + DEFLATE (RFC 1951) compression/decompression with gzip (RFC 1952) and + zlib (RFC 1950) format support + + Hex, base-32, base-64, URL safe base-64 encoding and decoding + + 32-bit CRC, CRC-C and Adler32 checksum + * class wrappers for these platform and operating system features (optional): + + high resolution timers on Windows, Unix, and Mac OS + + /dev/random, /dev/urandom, /dev/srandom + + Microsoft's CryptGenRandom or BCryptGenRandom on Windows + * A high level interface for most of the above, using a filter/pipeline + metaphor + * benchmarks and validation testing + * x86, x64 (x86-64), x32 (ILP32), ARM-32, Aarch32, Aarch64 and Power8 in-core code + for the commonly used algorithms + + run-time CPU feature detection and code selection + + supports GCC-style and MSVC-style inline assembly, and MASM for x64 + + x86, x64 (x86-64), x32 provides MMX, SSE2, and SSE4 implementations + + ARM-32, Aarch32 and Aarch64 provides NEON, ASIMD and ARMv8 implementations + + Power8 provides in-core AES using NX Crypto Acceleration + +The Crypto++ library was orginally written by Wei Dai. The library is now +maintained by several team members and the community. You are welcome to use it +for any purpose without paying anyone, but see License.txt for the fine print. + +The following compilers are supported for this release. Please visit +http://www.cryptopp.com the most up to date build instructions and porting notes. + + * Visual Studio 2003 - 2019 + * GCC 3.3 - 10.1 + * Apple Clang 4.3 - 9.3 + * LLVM Clang 2.9 - 10.0 + * C++ Builder 2015 + * Intel C++ Compiler 9 - 16.0 + * Sun Studio 12u1 - 12.6 + * IBM XL C/C++ 10.0 - 13.3 + +*** Important Usage Notes *** + +1. If a constructor for A takes a pointer to an object B (except primitive +types such as int and char), then A owns B and will delete B at A's +destruction. If a constructor for A takes a reference to an object B, +then the caller retains ownership of B and should not destroy it until +A no longer needs it. + +2. Crypto++ is thread safe at the class level. This means you can use +Crypto++ safely in a multithreaded application, but you must provide +synchronization when multiple threads access a common Crypto++ object. + +*** MSVC-Specific Information *** + +To compile Crypto++ with MSVC, open "cryptest.sln" (for MSVC 2003 - 2015) +and build one or more of the following projects: + +cryptest Non-DLL-Import Configuration - This builds the full static library + along with a full test driver. +cryptest DLL-Import Configuration - This builds a static library containing + only algorithms not in the DLL, along with a full test driver that uses + both the DLL and the static library. +cryptdll - This builds the DLL. Please note that if you wish to use Crypto++ + as a FIPS validated module, you must use a pre-built DLL that has undergone + the FIPS validation process instead of building your own. +dlltest - This builds a sample application that only uses the DLL. + +The DLL used to provide FIPS validated cryptography. The library was moved +to the CMVP's +Historical Validation List. The library and the DLL are no longer considered +validated. You should no longer use the DLL. + +To use the Crypto++ DLL in your application, #include "dll.h" before including +any other Crypto++ header files, and place the DLL in the same directory as +your .exe file. dll.h includes the line #pragma comment(lib, "cryptopp") +so you don't have to explicitly list the import library in your project +settings. To use a static library form of Crypto++, make the "cryptlib" +project a dependency of your application project, or specify it as +an additional library to link with in your project settings. +In either case you should check the compiler options to +make sure that the library and your application are using the same C++ +run-time libraries and calling conventions. + +*** DLL Memory Management *** + +Because it's possible for the Crypto++ DLL to delete objects allocated +by the calling application, they must use the same C++ memory heap. Three +methods are provided to achieve this. +1. The calling application can tell Crypto++ what heap to use. This method + is required when the calling application uses a non-standard heap. +2. Crypto++ can tell the calling application what heap to use. This method + is required when the calling application uses a statically linked C++ Run + Time Library. (Method 1 does not work in this case because the Crypto++ DLL + is initialized before the calling application's heap is initialized.) +3. Crypto++ can automatically use the heap provided by the calling application's + dynamically linked C++ Run Time Library. The calling application must + make sure that the dynamically linked C++ Run Time Library is initialized + before Crypto++ is loaded. (At this time it is not clear if it is possible + to control the order in which DLLs are initialized on Windows 9x machines, + so it might be best to avoid using this method.) + +When Crypto++ attaches to a new process, it searches all modules loaded +into the process space for exported functions "GetNewAndDeleteForCryptoPP" +and "SetNewAndDeleteFromCryptoPP". If one of these functions is found, +Crypto++ uses methods 1 or 2, respectively, by calling the function. +Otherwise, method 3 is used. + +*** Linux and Unix-like Specific Information *** + +A makefile is included for you to compile Crypto++ with GCC and compatibles. +Make sure you are using GNU Make and GNU ld. The make process will produce +two files, libcryptopp.a and cryptest.exe. Run "cryptest.exe v" for the +validation suite and "cryptest.exe tv all" for additional test vectors. + +The makefile uses '-DNDEBUG -g2 -O2' CXXFLAGS by default. If you use an +alternate build system, like Autotools or CMake, then ensure the build system +includes '-DNDEBUG' for production or release builds. The Crypto++ library uses +asserts for debugging and diagnostics during development; it does not +rely on them to crash a program at runtime. + +If an assert triggers in production software, then unprotected sensitive +information could be egressed from the program to the filesystem or the +platform's error reporting program, like Apport on Ubuntu or CrashReporter +on Apple. + +The makefile orders object files to help remediate problems associated with +C++ static initialization order. The library does not use custom linker scripts. +If you use an alternate build system, like Autotools or CMake, and collect source +files into a list, then ensure these three are at the head of the list: 'cryptlib.cpp +cpu.cpp integer.cpp '. They should be linked in the same order: +'cryptlib.o cpu.o integer.o '. + +If your linker supports initialization attributes, like init_priority, then you can +define CRYPTOPP_INIT_PRIORITY to control object initialization order. Set it to a +value like 250. User programs can use CRYPTOPP_USER_PRIORITY to avoid conflicts with +library values. Initialization attributes are more reliable than object file ordering, +but its not ubiquitously supported by linkers. + +The makefile links to the static version of the Crypto++ library to avoid binary +planting and other LD_PRELOAD tricks. You should use the static version of the +library in your programs to help avoid unwanted redirections. + +*** Side Channel Attacks *** + +Crypto++ attempts to resist side channel attacks using various remediations. +The remdiations are applied as a best effort but are probably incomplete. They +are incomplete due to cpu speculation bugs like Spectre, Meltdown, Foreshadow. +The attacks target both cpu caches and internal buffers. Intel generally refers +to internal buffer attacks as "Microarchitectural Data Sampling" (MDS). + +The library uses hardware instructions when possible for block ciphers, hashes +and other operations. The hardware acceleration remediates some timing +attacks. The library also uses cache-aware algoirthms and access patterns +to minimize leakage cache evictions. + +Elliptic curves over binary fields are believed to leak information. The task is a +work in progress. We don't believe binary fields are used in production, so we feel it +is a low risk at the moment. + +Crypto++ does not enagage Specter remediations at this time. The GCC options +for Specter are -mfunction-return=thunk and -mindirect-branch=thunk, and the +library uses them during testing. If you want the Specter workarounds then add +the GCC options to your CXXFLAGS when building the library. + +To help resist attacks you should disable hyperthreading on cpus. If you +suspect or find an information leak then please report it. + +*** Documentation and Support *** + +Crypto++ is documented through inline comments in header files, which are +processed through Doxygen to produce an HTML reference manual. You can find +a link to the manual from http://www.cryptopp.com. Also at that site is +the Crypto++ FAQ, which you should browse through before attempting to +use this library, because it will likely answer many of questions that +may come up. Finally, the site provide the wiki which has many topics +and code examples. + +If you run into any problems, please try the Crypto++ mailing list. +The subscription information and the list archive are available on +http://www.cryptopp.com. + +*** Source Code and Contributing *** + +The source code and its planned changes are available at the following locations. + + * The Crypto++ GitHub repository allows you to view the latest (unreleased) + Crypto++ source code via the Linux kernel's git beginning around June 2015. + Its also serves as an incubator to nuture and grow the library. + * The former Crypto++ SourceForge repository allows you to view the Crypto++ + source code via Apache's subversion until about July 2015. At that time, + SourceForge had infrastructure problems and a cutover to GutHub was performed. + * The Roadmap on the wiki provides the general direction the library is heading. + It includes planned features and releases, and even some wishlist items. + +Contributions of all types are welcomed. Contributions include the following. + + * Bug finding and fixes + * Features and enhancements + * Test scripts and test cases + * Branch and release testing + * Documentation and updates + +If you think you have found a bug in the library, then you should discuss it on the +Users mailing list. Discussing it will help bring the issue to the attention of folks +who can help resolve the issue. If you want to contribute a bug fix to the library, +then make a Pull Request or make a Diff available somewhere. Also see Bug Reports on +the wiki. + +Features and enhancements are welcomend additions to the library. This category tends +to be time consuming because algorithms and their test cases need to be reviewed and +merged. Please be mindful of the test cases, and attempt to procure them from an +independent source. + +The library cherishes test scripts and test cases. They ensure the library is fit and +they help uncover issues with the library before users experience them. If you have +some time, then write some test cases, especially the ones that are intended to break +things. + +Branch and release testing is your chance to ensure Master (and planned merges) meets +your expectations and perform as expected. If you have a few spare cycles, then please +test Master on your favorite platform. We need more testing on MinGW, Windows Phone, +Windows Store, Solaris 10 (and below), and modern iOS and OS X (including TV and +Watch builds). + +Documentation and updates includes both the inline source code annotations using +Doxygen, and the online information provided in the wiki. The wiki is more verbose and +usually provides more contextual information than the API reference. Besides testing, +documentation is one of the highest returns on investment. + +*** History *** + +The items in this section comprise the most recent history. Please see History.txt +for the record back to Crypto++ 1.0. + +8.4.0 - January 2, 2021 + - minor release, recompile of programs required + - expanded community input and support + * 67 unique contributors as of this release + - fix SIGILL on POWER8 when compiling with GCC 10 + - fix potential out-of-bounds write in FixedSizeAllocatorWithCleanup + - fix compile on AIX POWER7 with IBM XLC 12.01 + - fix compile on Solaris with SunCC 12.6 + - revert changes for constant-time elliptic curve algorithms + - fix makefile clean and distclean recipes + +8.3.0 - December 20, 2020 + - minor release, recompile of programs required + - expanded community input and support + * 66 unique contributors as of this release + - fix use of macro CRYPTOPP_ALIGN_DATA + - fix potential out-of-bounds read in ECDSA + - fix std::bad_alloc when using ByteQueue in pipeline + - fix missing CRYPTOPP_CXX17_EXCEPTIONS with Clang + - fix potential out-of-bounds read in GCM mode + - add configure.sh when preprocessor macros fail + - fix potential out-of-bounds read in SipHash + - fix compile error on POWER9 due to vec_xl_be + - fix K233 curve on POWER8 + - add Cirrus CI testing + - fix broken encryption for some 64-bit ciphers + - fix Android cpu-features.c using C++ compiler + - disable RDRAND and RDSEED for some AMD processors + - fix BLAKE2 hash calculation using Salt and Personalization + - refresh Android and iOS build scripts + - add XTS mode + - fix circular dependency between misc.h and secblock.h + - add Certificate interface + - fix recursion in AES::Encryption without AESNI + - add missing OID for ElGamal encryption + - fix missing override in KeyDerivationFunction-derived classes + - fix RDSEED assemble under MSVC + - fix elliptic curve timing leaks (CVE-2019-14318) + - add link-library variable to Makefiles + - fix SIZE_MAX definition in misc.h + - add GetWord64 and PutWord64 to BufferedTransformation + - use HKDF in AutoSeededX917RNG::Reseed + - fix Asan finding in VMAC on i686 in inline asm + - fix undeclared identifier _mm_roti_epi64 on Gentoo + - fix ECIES and GetSymmetricKeyLength + - fix possible divide by zero in PKCS5_PBKDF2_HMAC + - refine ASN.1 encoders and decoders + - disable BMI2 code paths in Integer class + - fix use of CRYPTOPP_CLANG_VERSION + - add NEON SHA1, SHA256 and SHA512 from Cryptogams + - add ARM SHA1, SHA256 and SHA512 from Cryptogams + - make config.h more autoconf friendly + - handle Clang triplet armv8l-unknown-linux-gnueabihf + - fix reference binding to misaligned address in xed25519 + - clear asserts in TestDataNameValuePairs + +8.2.0 - April 28, 2019 + - minor release, no recompile of programs required + - expanded community input and support + * 56 unique contributors as of this release + - use PowerPC unaligned loads and stores with Power8 + - add SKIPJACK test vectors + - fix SHAKE-128 and SHAKE-256 compile + - removed IS_NEON from Makefile + - fix Aarch64 build on Fedora 29 + - fix missing GF2NT_233_Multiply_Reduce_CLMUL in FIPS DLL + - add missing BLAKE2 constructors + - fix missing BlockSize() in BLAKE2 classes + +8.1.0 - February 22, 2019 + - minor release, no recompile of programs required + - expanded community input and support + * 56 unique contributors as of this release + - fix OS X PowerPC builds with Clang + - add Microsoft ARM64 support + - fix iPhone Simulator build due to missing symbols + - add CRYPTOPP_BUGGY_SIMD_LOAD_AND_STORE + - add carryless multiplies for NIST b233 and k233 curves + - fix OpenMP build due to use of OpenMP 4 with down-level compilers + - add SignStream and VerifyStream for ed25519 and large files + - fix missing AlgorithmProvider in PanamaHash + - add SHAKE-128 and SHAKE-256 + - fix AVX2 build due to _mm256_broadcastsi128_si256 + - add IETF ChaCha, XChaCha, ChaChaPoly1305 and XChaChaPoly1305 + +8.0.0 - December 28, 2018 + - major release, recompile of programs required + - expanded community input and support + * 54 unique contributors as of this release + - add x25519 key exchange and ed25519 signature scheme + - add limited Asymmetric Key Package support from RFC 5958 + - add Power9 DARN random number generator support + - add CHAM, HC-128, HC-256, Hight, LEA, Rabbit, Simeck + - fix FixedSizeAllocatorWithCleanup may be unaligned on some platforms + - cutover to GNU Make-based cpu feature tests + - rename files with dashes to underscores + - fix LegacyDecryptor and LegacyDecryptorWithMAC use wrong MAC + - fix incorrect AES/CBC decryption on Windows + - avoid Singleton when possible, avoid std::call_once completely + - fix SPARC alignment problems due to GetAlignmentOf() on word64 + - add ARM AES asm implementation from Cryptogams + - remove CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS support + +June 2015 - Changing of the guard. Wei Dai turned the library over to the + community. The first community release was Crypto++ 5.6.3. Wei is + no longer involved with the daily operations of the project. Wei + still provides guidance when we have questions. + +Originally written by Wei Dai, maintained by the Crypto++ Project diff --git a/extension/third_party/cryptopp/adhoc.cpp b/extension/third_party/cryptopp/adhoc.cpp new file mode 100644 index 00000000..1fc8c301 --- /dev/null +++ b/extension/third_party/cryptopp/adhoc.cpp @@ -0,0 +1,42 @@ +#include "config.h" +#include +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100 4189 4996) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +USING_NAMESPACE(CryptoPP) +USING_NAMESPACE(std) + +#ifndef CRYPTOPP_UNUSED +# define CRYPTOPP_UNUSED(x) (void(x)) +#endif + +// Used for testing the compiler and linker in cryptest.sh +#if defined(CRYPTOPP_ADHOC_MAIN) || defined(ADHOC_MAIN) + +int main(int argc, char *argv[]) +{ + CRYPTOPP_UNUSED(argc), CRYPTOPP_UNUSED(argv); + return 0; +} + +// Classic use of adhoc to setup calling convention +#else + +extern int (*AdhocTest)(int argc, char *argv[]); + +int MyAdhocTest(int argc, char *argv[]) +{ + CRYPTOPP_UNUSED(argc), CRYPTOPP_UNUSED(argv); + return 0; +} + +static int s_i = (AdhocTest = &MyAdhocTest, 0); + +#endif diff --git a/extension/third_party/cryptopp/adler32.cpp b/extension/third_party/cryptopp/adler32.cpp new file mode 100644 index 00000000..2cfb1f44 --- /dev/null +++ b/extension/third_party/cryptopp/adler32.cpp @@ -0,0 +1,82 @@ +// adler32.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "adler32.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Adler32::Update(const byte *input, size_t length) +{ + const unsigned long BASE = 65521; + + unsigned long s1 = m_s1; + unsigned long s2 = m_s2; + + if (length % 8 != 0) + { + do + { + s1 += *input++; + s2 += s1; + length--; + } while (length % 8 != 0); + + if (s1 >= BASE) + s1 -= BASE; + s2 %= BASE; + } + + while (length > 0) + { + s1 += input[0]; s2 += s1; + s1 += input[1]; s2 += s1; + s1 += input[2]; s2 += s1; + s1 += input[3]; s2 += s1; + s1 += input[4]; s2 += s1; + s1 += input[5]; s2 += s1; + s1 += input[6]; s2 += s1; + s1 += input[7]; s2 += s1; + + length -= 8; + input += 8; + + if (s1 >= BASE) + s1 -= BASE; + if (length % 0x8000 == 0) + s2 %= BASE; + } + + CRYPTOPP_ASSERT(s1 < BASE); + CRYPTOPP_ASSERT(s2 < BASE); + + m_s1 = (word16)s1; + m_s2 = (word16)s2; +} + +void Adler32::TruncatedFinal(byte *hash, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + switch (size) + { + default: + hash[3] = byte(m_s1); + // fall through + case 3: + hash[2] = byte(m_s1 >> 8); + // fall through + case 2: + hash[1] = byte(m_s2); + // fall through + case 1: + hash[0] = byte(m_s2 >> 8); + // fall through + case 0: + ; + // fall through + } + + Reset(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/adler32.h b/extension/third_party/cryptopp/adler32.h new file mode 100644 index 00000000..a50d126e --- /dev/null +++ b/extension/third_party/cryptopp/adler32.h @@ -0,0 +1,33 @@ +// adler32.h - originally written and placed in the public domain by Wei Dai + +/// \file adler32.h +/// \brief Class file for ADLER-32 checksum calculations + +#ifndef CRYPTOPP_ADLER32_H +#define CRYPTOPP_ADLER32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ADLER-32 checksum calculations +class Adler32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + Adler32() {Reset();} + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Adler32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + void Reset() {m_s1 = 1; m_s2 = 0;} + + word16 m_s1, m_s2; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/adv_simd.h b/extension/third_party/cryptopp/adv_simd.h new file mode 100644 index 00000000..e5a0a43d --- /dev/null +++ b/extension/third_party/cryptopp/adv_simd.h @@ -0,0 +1,1281 @@ +// adv_simd.h - written and placed in the public domain by Jeffrey Walton + +/// \file adv_simd.h +/// \brief Template for AdvancedProcessBlocks and SIMD processing + +// The SIMD based implementations for ciphers that use SSE, NEON and Power7 +// have a commom pattern. Namely, they have a specialized implementation of +// AdvancedProcessBlocks which processes multiple block using hardware +// acceleration. After several implementations we noticed a lot of copy and +// paste occuring. adv_simd.h provides a template to avoid the copy and paste. +// +// There are 6 templates provided in this file. The number following the +// function name, 128, is the block size in bits. The name following the +// block size is the arrangement and acceleration. For example 4x1_SSE means +// Intel SSE using two encrypt (or decrypt) functions: one that operates on +// 4 SIMD words, and one that operates on 1 SIMD words. +// +// * AdvancedProcessBlocks128_4x1_SSE +// * AdvancedProcessBlocks128_6x2_SSE +// * AdvancedProcessBlocks128_4x1_NEON +// * AdvancedProcessBlocks128_6x1_NEON +// * AdvancedProcessBlocks128_4x1_ALTIVEC +// * AdvancedProcessBlocks128_6x1_ALTIVEC +// +// If an arrangement ends in 2, like 6x2, then the template will handle the +// single block case by padding with 0's and using the two SIMD word +// function. This happens at most one time when processing multiple blocks. +// The extra processing of a zero block is trivial and worth the tradeoff. +// +// The MAYBE_CONST macro present on x86 is a SunCC workaround. Some versions +// of SunCC lose/drop the const-ness in the F1 and F4 functions. It eventually +// results in a failed link due to the const/non-const mismatch. +// +// In July 2020 the library stopped using 64-bit block version of +// AdvancedProcessBlocks. Testing showed unreliable results and failed +// self tests on occasion. Also see Issue 945 and +// https://github.com/weidai11/cryptopp/commit/dd7598e638bb. + +#ifndef CRYPTOPP_ADVANCED_SIMD_TEMPLATES +#define CRYPTOPP_ADVANCED_SIMD_TEMPLATES + +#include "config.h" +#include "misc.h" +#include "stdcpp.h" + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +# include +# include +#endif + +// SunCC needs CRYPTOPP_SSSE3_AVAILABLE, too +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +# include +# include +#endif + +#if defined(__ALTIVEC__) +# include "ppc_simd.h" +#endif + +// ************************ All block ciphers *********************** // + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::BlockTransformation; + +CRYPTOPP_CONSTANT(BT_XorInput = BlockTransformation::BT_XorInput); +CRYPTOPP_CONSTANT(BT_AllowParallel = BlockTransformation::BT_AllowParallel); +CRYPTOPP_CONSTANT(BT_InBlockIsCounter = BlockTransformation::BT_InBlockIsCounter); +CRYPTOPP_CONSTANT(BT_ReverseDirection = BlockTransformation::BT_ReverseDirection); +CRYPTOPP_CONSTANT(BT_DontIncrementInOutPointers = BlockTransformation::BT_DontIncrementInOutPointers); + +ANONYMOUS_NAMESPACE_END + +// *************************** ARM NEON ************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) || (CRYPTOPP_ARM_ASIMD_AVAILABLE) || \ + defined(CRYPTOPP_DOXYGEN_PROCESSING) +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 1 and 6 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x1_NEON processes 6 and 2 NEON SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x1_NEON(F1 func1, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + block2 = vaddq_u64(block1, one); + block3 = vaddq_u64(block2, one); + block4 = vaddq_u64(block3, one); + block5 = vaddq_u64(block4, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_NEON processes 4 and 1 NEON SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. V is the vector type and it is +/// usually uint32x4_t or uint32x4_t. F1, F4, and W must use the same word and +/// vector type. +template +inline size_t AdvancedProcessBlocks128_4x1_NEON(F1 func1, F4 func4, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + uint32x4_t block0, block1, block2, block3; + if (flags & BT_InBlockIsCounter) + { + const uint32x4_t one = s_one; + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + block1 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block0), vreinterpretq_u64_u32(one))); + block2 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block1), vreinterpretq_u64_u32(one))); + block3 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block2), vreinterpretq_u64_u32(one))); + vst1q_u8(const_cast(inBlocks), vreinterpretq_u8_u64(vaddq_u64( + vreinterpretq_u64_u32(block3), vreinterpretq_u64_u32(one)))); + } + else + { + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_t block = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 2 and 6 blocks +/// \tparam F2 function to process 2 128-bit blocks +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x2_NEON processes 6 and 2 NEON SIMD words +/// at a time. For a single block the template uses F2 with a zero block. +/// \details The subkey type is usually word32 or word64. F2 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x2_NEON(F2 func2, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + block2 = vaddq_u64(block1, one); + block3 = vaddq_u64(block2, one); + block4 = vaddq_u64(block3, one); + block5 = vaddq_u64(block4, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + uint64x2_t block0, block1; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block1, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block, zero = {0,0}; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// *************************** Intel SSE ************************** // + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief SunCC workaround +/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block +/// \sa Issue +/// 224, SunCC and failed compile for rijndael.cpp +# define MAYBE_CONST const +/// \brief SunCC workaround +/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block +/// \sa Issue +/// 224, SunCC and failed compile for rijndael.cpp +# define MAYBE_UNCONST_CAST(T, x) (x) +#elif (__SUNPRO_CC >= 0x5130) +# define MAYBE_CONST +# define MAYBE_UNCONST_CAST(T, x) const_cast(x) +#else +# define MAYBE_CONST const +# define MAYBE_UNCONST_CAST(T, x) (x) +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Clang workaround +/// \details Clang issues spurious alignment warnings +/// \sa Issue +/// 20670, _mm_loadu_si128 parameter has wrong type +# define M128_CAST(x) ((__m128i *)(void *)(x)) +/// \brief Clang workaround +/// \details Clang issues spurious alignment warnings +/// \sa Issue +/// 20670, _mm_loadu_si128 parameter has wrong type +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#else +# ifndef M128_CAST +# define M128_CAST(x) ((__m128i *)(void *)(x)) +# endif +# ifndef CONST_M128_CAST +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 2 and 6 blocks +/// \tparam F2 function to process 2 128-bit blocks +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x2_SSE processes 6 and 2 SSE SIMD words +/// at a time. For a single block the template uses F2 with a zero block. +/// \details The subkey type is usually word32 or word64. F2 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x2_SSE(F2 func2, F6 func6, + MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const size_t blockSize = 16; + // const size_t xmmBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + __m128i block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + block2 = _mm_add_epi32(block1, s_one); + block3 = _mm_add_epi32(block2, s_one); + block4 = _mm_add_epi32(block3, s_one); + block5 = _mm_add_epi32(block4, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block5, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block4); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block5); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + __m128i block0, block1; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block1, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block, zero = _mm_setzero_si128(); + block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_SSE processes 4 and 1 SSE SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F4 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_4x1_SSE(F1 func1, F4 func4, + MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const size_t blockSize = 16; + // const size_t xmmBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + __m128i block0, block1, block2, block3; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + block2 = _mm_add_epi32(block1, s_one); + block3 = _mm_add_epi32(block2, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block3, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ************************** Altivec/Power 4 ************************** // + +#if defined(__ALTIVEC__) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_ALTIVEC processes 4 and 1 Altivec SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F4 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_4x1_ALTIVEC(F1 func1, F4 func4, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint32x4_p s_one = {1,0,0,0}; +#else + const uint32x4_p s_one = {0,0,0,1}; +#endif + + const size_t blockSize = 16; + // const size_t simdBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + uint32x4_p block0, block1, block2, block3; + + if (flags & BT_InBlockIsCounter) + { + block0 = VecLoadBE(inBlocks); + block1 = VecAdd(block0, s_one); + block2 = VecAdd(block1, s_one); + block3 = VecAdd(block2, s_one); + + // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE). + // CTR_ModePolicy::OperateKeystream is wired such that after + // returning from this function CTR_ModePolicy will detect wrap on + // on the last counter byte and increment the next to last byte. + // The problem is, with a big-endian load, inBlocks[15] is really + // located at index 15. The vector addition using a 32-bit element + // generates a carry into inBlocks[14] and then CTR_ModePolicy + // increments inBlocks[14] too. + const_cast(inBlocks)[15] += 6; + } + else + { + block0 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, rounds); + + if (xorOutput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + VecStoreBE(block0, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block1, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block2, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block3, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_p block = VecLoadBE(inBlocks); + + if (xorInput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, rounds); + + if (xorOutput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + VecStoreBE(block, outBlocks); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 6 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x1_ALTIVEC processes 6 and 1 Altivec SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x1_ALTIVEC(F1 func1, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint32x4_p s_one = {1,0,0,0}; +#else + const uint32x4_p s_one = {0,0,0,1}; +#endif + + const size_t blockSize = 16; + // const size_t simdBlockSize = 16; + + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & BT_XorInput); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & BT_XorInput); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint32x4_p block0, block1, block2, block3, block4, block5; + + if (flags & BT_InBlockIsCounter) + { + block0 = VecLoadBE(inBlocks); + block1 = VecAdd(block0, s_one); + block2 = VecAdd(block1, s_one); + block3 = VecAdd(block2, s_one); + block4 = VecAdd(block3, s_one); + block5 = VecAdd(block4, s_one); + + // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE). + // CTR_ModePolicy::OperateKeystream is wired such that after + // returning from this function CTR_ModePolicy will detect wrap on + // on the last counter byte and increment the next to last byte. + // The problem is, with a big-endian load, inBlocks[15] is really + // located at index 15. The vector addition using a 32-bit element + // generates a carry into inBlocks[14] and then CTR_ModePolicy + // increments inBlocks[14] too. + // + // To find this bug we needed a test case with a ctr of 0xNN...FA. + // The last octet is 0xFA and adding 6 creates the wrap to trigger + // the issue. If the last octet was 0xFC then 4 would trigger it. + // We dumb-lucked into the test with SPECK-128. The test case of + // interest is the one with IV 348ECA9766C09F04 826520DE47A212FA. + uint8x16_p temp = VecAdd((uint8x16_p)block5, (uint8x16_p)s_one); + VecStoreBE(temp, const_cast(inBlocks)); + } + else + { + block0 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = VecXor(block4, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = VecXor(block5, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, rounds); + + if (xorOutput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = VecXor(block4, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = VecXor(block5, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + VecStoreBE(block0, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block1, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block2, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block3, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block4, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block5, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_p block = VecLoadBE(inBlocks); + + if (xorInput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, rounds); + + if (xorOutput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + VecStoreBE(block, outBlocks); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // __ALTIVEC__ + +#endif // CRYPTOPP_ADVANCED_SIMD_TEMPLATES diff --git a/extension/third_party/cryptopp/aes.h b/extension/third_party/cryptopp/aes.h new file mode 100644 index 00000000..72ff2ccc --- /dev/null +++ b/extension/third_party/cryptopp/aes.h @@ -0,0 +1,30 @@ +// aes.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Class file for the AES cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 + +#ifndef CRYPTOPP_AES_H +#define CRYPTOPP_AES_H + +#include "rijndael.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AES block cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \sa AES winner, announced on 10/2/2000 +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 +DOCUMENTED_TYPEDEF(Rijndael, AES); + +typedef RijndaelEncryption AESEncryption; +typedef RijndaelDecryption AESDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/aes_armv4.S b/extension/third_party/cryptopp/aes_armv4.S new file mode 100644 index 00000000..6651a702 --- /dev/null +++ b/extension/third_party/cryptopp/aes_armv4.S @@ -0,0 +1,1215 @@ +@ Copyright 2007-2018 The OpenSSL Project Authors. All Rights Reserved. +@ +@ ==================================================================== +@ Written by Andy Polyakov for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ JW, JUL 2018: Begin defines from taken from arm_arch.h +@ The defines were included through the header. + +# if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +# endif + +# if !defined(__ARM_MAX_ARCH__) +# define __ARM_MAX_ARCH__ __ARM_ARCH__ +# endif + +# if __ARM_MAX_ARCH__<__ARM_ARCH__ +# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__" +# elif __ARM_MAX_ARCH__!=__ARM_ARCH__ +# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__) +# error "can't build universal big-endian binary" +# endif +# endif + +@ JW, JUL 2018: End defines from taken from arm_arch.h +@ Back to original Cryptogams code + +#if defined(__thumb2__) && !defined(__APPLE__) +.syntax unified +.thumb +#else +.code 32 +#undef __thumb2__ +#endif + +.text + +.type AES_Te,%object +.align 5 +AES_Te: +.word 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d +.word 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554 +.word 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d +.word 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a +.word 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87 +.word 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b +.word 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea +.word 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b +.word 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a +.word 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f +.word 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108 +.word 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f +.word 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e +.word 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5 +.word 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d +.word 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f +.word 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e +.word 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb +.word 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce +.word 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497 +.word 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c +.word 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed +.word 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b +.word 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a +.word 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16 +.word 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594 +.word 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81 +.word 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3 +.word 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a +.word 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504 +.word 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163 +.word 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d +.word 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f +.word 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739 +.word 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47 +.word 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395 +.word 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f +.word 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883 +.word 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c +.word 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76 +.word 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e +.word 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4 +.word 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6 +.word 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b +.word 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7 +.word 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0 +.word 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25 +.word 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818 +.word 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72 +.word 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651 +.word 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21 +.word 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85 +.word 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa +.word 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12 +.word 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0 +.word 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9 +.word 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133 +.word 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7 +.word 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920 +.word 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a +.word 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17 +.word 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8 +.word 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11 +.word 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +@ Te4[256] +.byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 +.byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 +.byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 +.byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 +.byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc +.byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 +.byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a +.byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 +.byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 +.byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 +.byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b +.byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf +.byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 +.byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 +.byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 +.byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 +.byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 +.byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 +.byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 +.byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb +.byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c +.byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 +.byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 +.byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 +.byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 +.byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a +.byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e +.byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e +.byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 +.byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf +.byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 +.byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +@ rcon[] +.word 0x01000000, 0x02000000, 0x04000000, 0x08000000 +.word 0x10000000, 0x20000000, 0x40000000, 0x80000000 +.word 0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0 +.size AES_Te,.-AES_Te + +@ void cryptogams_AES_encrypt_block(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.globl cryptogams_AES_encrypt_block +.type cryptogams_AES_encrypt_block,%function +.align 5 +cryptogams_AES_encrypt_block: +#ifndef __thumb2__ + sub r3,pc,#8 @ cryptogams_AES_encrypt_block +#else + adr r3,. +#endif + stmdb sp!,{r1,r4-r12,lr} +#if defined(__thumb2__) || defined(__APPLE__) + adr r10,AES_Te +#else + sub r10,r3,#cryptogams_AES_encrypt_block-AES_Te @ Te +#endif + mov r12,r0 @ inp + mov r11,r2 +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + orr r3,r3,r5,lsl#16 + orr r3,r3,r6,lsl#24 +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif +#endif + bl _cryptogams_armv4_AES_encrypt_block + + ldr r12,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r12,#0] + str r1,[r12,#4] + str r2,[r12,#8] + str r3,[r12,#12] +#else + mov r4,r0,lsr#24 @ write output in endian-neutral + mov r5,r0,lsr#16 @ manner... + mov r6,r0,lsr#8 + strb r4,[r12,#0] + strb r5,[r12,#1] + mov r4,r1,lsr#24 + strb r6,[r12,#2] + mov r5,r1,lsr#16 + strb r0,[r12,#3] + mov r6,r1,lsr#8 + strb r4,[r12,#4] + strb r5,[r12,#5] + mov r4,r2,lsr#24 + strb r6,[r12,#6] + mov r5,r2,lsr#16 + strb r1,[r12,#7] + mov r6,r2,lsr#8 + strb r4,[r12,#8] + strb r5,[r12,#9] + mov r4,r3,lsr#24 + strb r6,[r12,#10] + mov r5,r3,lsr#16 + strb r2,[r12,#11] + mov r6,r3,lsr#8 + strb r4,[r12,#12] + strb r5,[r12,#13] + strb r6,[r12,#14] + strb r3,[r12,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_AES_encrypt_block,.-cryptogams_AES_encrypt_block + +.type _cryptogams_armv4_AES_encrypt_block,%function +.align 2 +_cryptogams_armv4_AES_encrypt_block: + str lr,[sp,#-4]! @ push lr + ldmia r11!,{r4,r5,r6,r7} + eor r0,r0,r4 + ldr r12,[r11,#240-16] + eor r1,r1,r5 + eor r2,r2,r6 + eor r3,r3,r7 + sub r12,r12,#1 + mov lr,#255 + + and r7,lr,r0 + and r8,lr,r0,lsr#8 + and r9,lr,r0,lsr#16 + mov r0,r0,lsr#24 +.Lenc_loop: + ldr r4,[r10,r7,lsl#2] @ Te3[s0>>0] + and r7,lr,r1,lsr#16 @ i0 + ldr r5,[r10,r8,lsl#2] @ Te2[s0>>8] + and r8,lr,r1 + ldr r6,[r10,r9,lsl#2] @ Te1[s0>>16] + and r9,lr,r1,lsr#8 + ldr r0,[r10,r0,lsl#2] @ Te0[s0>>24] + mov r1,r1,lsr#24 + + ldr r7,[r10,r7,lsl#2] @ Te1[s1>>16] + ldr r8,[r10,r8,lsl#2] @ Te3[s1>>0] + ldr r9,[r10,r9,lsl#2] @ Te2[s1>>8] + eor r0,r0,r7,ror#8 + ldr r1,[r10,r1,lsl#2] @ Te0[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r5,r8,ror#8 + and r8,lr,r2,lsr#16 @ i1 + eor r6,r6,r9,ror#8 + and r9,lr,r2 + ldr r7,[r10,r7,lsl#2] @ Te2[s2>>8] + eor r1,r1,r4,ror#24 + ldr r8,[r10,r8,lsl#2] @ Te1[s2>>16] + mov r2,r2,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Te3[s2>>0] + eor r0,r0,r7,ror#16 + ldr r2,[r10,r2,lsl#2] @ Te0[s2>>24] + and r7,lr,r3 @ i0 + eor r1,r1,r8,ror#8 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r6,r9,ror#16 + and r9,lr,r3,lsr#16 @ i2 + ldr r7,[r10,r7,lsl#2] @ Te3[s3>>0] + eor r2,r2,r5,ror#16 + ldr r8,[r10,r8,lsl#2] @ Te2[s3>>8] + mov r3,r3,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Te1[s3>>16] + eor r0,r0,r7,ror#24 + ldr r7,[r11],#16 + eor r1,r1,r8,ror#16 + ldr r3,[r10,r3,lsl#2] @ Te0[s3>>24] + eor r2,r2,r9,ror#8 + ldr r4,[r11,#-12] + eor r3,r3,r6,ror#8 + + ldr r5,[r11,#-8] + eor r0,r0,r7 + ldr r6,[r11,#-4] + and r7,lr,r0 + eor r1,r1,r4 + and r8,lr,r0,lsr#8 + eor r2,r2,r5 + and r9,lr,r0,lsr#16 + eor r3,r3,r6 + mov r0,r0,lsr#24 + + subs r12,r12,#1 + bne .Lenc_loop + + add r10,r10,#2 + + ldrb r4,[r10,r7,lsl#2] @ Te4[s0>>0] + and r7,lr,r1,lsr#16 @ i0 + ldrb r5,[r10,r8,lsl#2] @ Te4[s0>>8] + and r8,lr,r1 + ldrb r6,[r10,r9,lsl#2] @ Te4[s0>>16] + and r9,lr,r1,lsr#8 + ldrb r0,[r10,r0,lsl#2] @ Te4[s0>>24] + mov r1,r1,lsr#24 + + ldrb r7,[r10,r7,lsl#2] @ Te4[s1>>16] + ldrb r8,[r10,r8,lsl#2] @ Te4[s1>>0] + ldrb r9,[r10,r9,lsl#2] @ Te4[s1>>8] + eor r0,r7,r0,lsl#8 + ldrb r1,[r10,r1,lsl#2] @ Te4[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r8,r5,lsl#8 + and r8,lr,r2,lsr#16 @ i1 + eor r6,r9,r6,lsl#8 + and r9,lr,r2 + ldrb r7,[r10,r7,lsl#2] @ Te4[s2>>8] + eor r1,r4,r1,lsl#24 + ldrb r8,[r10,r8,lsl#2] @ Te4[s2>>16] + mov r2,r2,lsr#24 + + ldrb r9,[r10,r9,lsl#2] @ Te4[s2>>0] + eor r0,r7,r0,lsl#8 + ldrb r2,[r10,r2,lsl#2] @ Te4[s2>>24] + and r7,lr,r3 @ i0 + eor r1,r1,r8,lsl#16 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r9,r6,lsl#8 + and r9,lr,r3,lsr#16 @ i2 + ldrb r7,[r10,r7,lsl#2] @ Te4[s3>>0] + eor r2,r5,r2,lsl#24 + ldrb r8,[r10,r8,lsl#2] @ Te4[s3>>8] + mov r3,r3,lsr#24 + + ldrb r9,[r10,r9,lsl#2] @ Te4[s3>>16] + eor r0,r7,r0,lsl#8 + ldr r7,[r11,#0] + ldrb r3,[r10,r3,lsl#2] @ Te4[s3>>24] + eor r1,r1,r8,lsl#8 + ldr r4,[r11,#4] + eor r2,r2,r9,lsl#16 + ldr r5,[r11,#8] + eor r3,r6,r3,lsl#24 + ldr r6,[r11,#12] + + eor r0,r0,r7 + eor r1,r1,r4 + eor r2,r2,r5 + eor r3,r3,r6 + + sub r10,r10,#2 + ldr pc,[sp],#4 @ pop and return +.size _cryptogams_armv4_AES_encrypt_block,.-_cryptogams_armv4_AES_encrypt_block + +.globl cryptogams_AES_set_encrypt_key +.type cryptogams_AES_set_encrypt_key,%function +.align 5 +cryptogams_AES_set_encrypt_key: +_armv4_AES_set_encrypt_key: +#ifndef __thumb2__ + sub r3,pc,#8 @ AES_set_encrypt_key +#else + adr r3,. +#endif + teq r0,#0 +#ifdef __thumb2__ + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + teq r2,#0 +#ifdef __thumb2__ + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + + teq r1,#128 + beq .Lok + teq r1,#192 + beq .Lok + teq r1,#256 +#ifdef __thumb2__ + itt ne @ Thumb2 thing, sanity check in ARM +#endif + movne r0,#-1 + bne .Labrt + +.Lok: stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + mov r12,r0 @ inp + mov lr,r1 @ bits + mov r11,r2 @ key + +#if defined(__thumb2__) || defined(__APPLE__) + adr r10,AES_Te+1024 @ Te4 +#else + sub r10,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4 +#endif + +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + str r0,[r11],#16 + orr r3,r3,r5,lsl#16 + str r1,[r11,#-12] + orr r3,r3,r6,lsl#24 + str r2,[r11,#-8] + str r3,[r11,#-4] +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r11],#16 + str r1,[r11,#-12] + str r2,[r11,#-8] + str r3,[r11,#-4] +#endif + + teq lr,#128 + bne .Lnot128 + mov r12,#10 + str r12,[r11,#240-16] + add r6,r10,#256 @ rcon + mov lr,#255 + +.L128_loop: + and r5,lr,r3,lsr#24 + and r7,lr,r3,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r3,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r3 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r5,r5,r4 + eor r0,r0,r5 @ rk[4]=rk[0]^... + eor r1,r1,r0 @ rk[5]=rk[1]^rk[4] + str r0,[r11],#16 + eor r2,r2,r1 @ rk[6]=rk[2]^rk[5] + str r1,[r11,#-12] + eor r3,r3,r2 @ rk[7]=rk[3]^rk[6] + str r2,[r11,#-8] + subs r12,r12,#1 + str r3,[r11,#-4] + bne .L128_loop + sub r2,r11,#176 + b .Ldone + +.Lnot128: +#if __ARM_ARCH__<7 + ldrb r8,[r12,#19] + ldrb r4,[r12,#18] + ldrb r5,[r12,#17] + ldrb r6,[r12,#16] + orr r8,r8,r4,lsl#8 + ldrb r9,[r12,#23] + orr r8,r8,r5,lsl#16 + ldrb r4,[r12,#22] + orr r8,r8,r6,lsl#24 + ldrb r5,[r12,#21] + ldrb r6,[r12,#20] + orr r9,r9,r4,lsl#8 + orr r9,r9,r5,lsl#16 + str r8,[r11],#8 + orr r9,r9,r6,lsl#24 + str r9,[r11,#-4] +#else + ldr r8,[r12,#16] + ldr r9,[r12,#20] +#ifdef __ARMEL__ + rev r8,r8 + rev r9,r9 +#endif + str r8,[r11],#8 + str r9,[r11,#-4] +#endif + + teq lr,#192 + bne .Lnot192 + mov r12,#12 + str r12,[r11,#240-24] + add r6,r10,#256 @ rcon + mov lr,#255 + mov r12,#8 + +.L192_loop: + and r5,lr,r9,lsr#24 + and r7,lr,r9,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r9,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r9 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r9,r5,r4 + eor r0,r0,r9 @ rk[6]=rk[0]^... + eor r1,r1,r0 @ rk[7]=rk[1]^rk[6] + str r0,[r11],#24 + eor r2,r2,r1 @ rk[8]=rk[2]^rk[7] + str r1,[r11,#-20] + eor r3,r3,r2 @ rk[9]=rk[3]^rk[8] + str r2,[r11,#-16] + subs r12,r12,#1 + str r3,[r11,#-12] +#ifdef __thumb2__ + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,r11,#216 + beq .Ldone + + ldr r7,[r11,#-32] + ldr r8,[r11,#-28] + eor r7,r7,r3 @ rk[10]=rk[4]^rk[9] + eor r9,r8,r7 @ rk[11]=rk[5]^rk[10] + str r7,[r11,#-8] + str r9,[r11,#-4] + b .L192_loop + +.Lnot192: +#if __ARM_ARCH__<7 + ldrb r8,[r12,#27] + ldrb r4,[r12,#26] + ldrb r5,[r12,#25] + ldrb r6,[r12,#24] + orr r8,r8,r4,lsl#8 + ldrb r9,[r12,#31] + orr r8,r8,r5,lsl#16 + ldrb r4,[r12,#30] + orr r8,r8,r6,lsl#24 + ldrb r5,[r12,#29] + ldrb r6,[r12,#28] + orr r9,r9,r4,lsl#8 + orr r9,r9,r5,lsl#16 + str r8,[r11],#8 + orr r9,r9,r6,lsl#24 + str r9,[r11,#-4] +#else + ldr r8,[r12,#24] + ldr r9,[r12,#28] +#ifdef __ARMEL__ + rev r8,r8 + rev r9,r9 +#endif + str r8,[r11],#8 + str r9,[r11,#-4] +#endif + + mov r12,#14 + str r12,[r11,#240-32] + add r6,r10,#256 @ rcon + mov lr,#255 + mov r12,#7 + +.L256_loop: + and r5,lr,r9,lsr#24 + and r7,lr,r9,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r9,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r9 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r9,r5,r4 + eor r0,r0,r9 @ rk[8]=rk[0]^... + eor r1,r1,r0 @ rk[9]=rk[1]^rk[8] + str r0,[r11],#32 + eor r2,r2,r1 @ rk[10]=rk[2]^rk[9] + str r1,[r11,#-28] + eor r3,r3,r2 @ rk[11]=rk[3]^rk[10] + str r2,[r11,#-24] + subs r12,r12,#1 + str r3,[r11,#-20] +#ifdef __thumb2__ + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,r11,#256 + beq .Ldone + + and r5,lr,r3 + and r7,lr,r3,lsr#8 + ldrb r5,[r10,r5] + and r8,lr,r3,lsr#16 + ldrb r7,[r10,r7] + and r9,lr,r3,lsr#24 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#8 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r11,#-48] + orr r5,r5,r9,lsl#24 + + ldr r7,[r11,#-44] + ldr r8,[r11,#-40] + eor r4,r4,r5 @ rk[12]=rk[4]^... + ldr r9,[r11,#-36] + eor r7,r7,r4 @ rk[13]=rk[5]^rk[12] + str r4,[r11,#-16] + eor r8,r8,r7 @ rk[14]=rk[6]^rk[13] + str r7,[r11,#-12] + eor r9,r9,r8 @ rk[15]=rk[7]^rk[14] + str r8,[r11,#-8] + str r9,[r11,#-4] + b .L256_loop + +.align 2 +.Ldone: mov r0,#0 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} +.Labrt: +#if __ARM_ARCH__>=5 + bx lr @ .word 0xe12fff1e +#else + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_AES_set_encrypt_key,.-cryptogams_AES_set_encrypt_key + +.globl cryptogams_AES_set_decrypt_key +.type cryptogams_AES_set_decrypt_key,%function +.align 5 +cryptogams_AES_set_decrypt_key: + str lr,[sp,#-4]! @ push lr + bl _armv4_AES_set_encrypt_key + teq r0,#0 + ldr lr,[sp],#4 @ pop lr + bne .Labrt + + mov r0,r2 @ AES_set_encrypt_key preserves r2, + mov r1,r2 @ which is AES_KEY *key + b _armv4_AES_set_enc2dec_key +.size cryptogams_AES_set_decrypt_key,.-cryptogams_AES_set_decrypt_key + +@ void cryptogams_AES_set_enc2dec_key(const AES_KEY *inp,AES_KEY *out) +.globl cryptogams_AES_set_enc2dec_key +.type cryptogams_AES_set_enc2dec_key,%function +.align 5 +cryptogams_AES_set_enc2dec_key: +_armv4_AES_set_enc2dec_key: + stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + + ldr r12,[r0,#240] + mov r7,r0 @ input + add r8,r0,r12,lsl#4 + mov r11,r1 @ output + add r10,r1,r12,lsl#4 + str r12,[r1,#240] + +.Linv: ldr r0,[r7],#16 + ldr r1,[r7,#-12] + ldr r2,[r7,#-8] + ldr r3,[r7,#-4] + ldr r4,[r8],#-16 + ldr r5,[r8,#16+4] + ldr r6,[r8,#16+8] + ldr r9,[r8,#16+12] + str r0,[r10],#-16 + str r1,[r10,#16+4] + str r2,[r10,#16+8] + str r3,[r10,#16+12] + str r4,[r11],#16 + str r5,[r11,#-12] + str r6,[r11,#-8] + str r9,[r11,#-4] + teq r7,r8 + bne .Linv + + ldr r0,[r7] + ldr r1,[r7,#4] + ldr r2,[r7,#8] + ldr r3,[r7,#12] + str r0,[r11] + str r1,[r11,#4] + str r2,[r11,#8] + str r3,[r11,#12] + sub r11,r11,r12,lsl#3 + ldr r0,[r11,#16]! @ prefetch tp1 + mov r7,#0x80 + mov r8,#0x1b + orr r7,r7,#0x8000 + orr r8,r8,#0x1b00 + orr r7,r7,r7,lsl#16 + orr r8,r8,r8,lsl#16 + sub r12,r12,#1 + mvn r9,r7 + mov r12,r12,lsl#2 @ (rounds-1)*4 + +.Lmix: and r4,r0,r7 + and r1,r0,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r1,r4,r1,lsl#1 @ tp2 + + and r4,r1,r7 + and r2,r1,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r2,r4,r2,lsl#1 @ tp4 + + and r4,r2,r7 + and r3,r2,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r3,r4,r3,lsl#1 @ tp8 + + eor r4,r1,r2 + eor r5,r0,r3 @ tp9 + eor r4,r4,r3 @ tpe + eor r4,r4,r1,ror#24 + eor r4,r4,r5,ror#24 @ ^= ROTATE(tpb=tp9^tp2,8) + eor r4,r4,r2,ror#16 + eor r4,r4,r5,ror#16 @ ^= ROTATE(tpd=tp9^tp4,16) + eor r4,r4,r5,ror#8 @ ^= ROTATE(tp9,24) + + ldr r0,[r11,#4] @ prefetch tp1 + str r4,[r11],#4 + subs r12,r12,#1 + bne .Lmix + + mov r0,#0 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_AES_set_enc2dec_key,.-cryptogams_AES_set_enc2dec_key + +.type AES_Td,%object +.align 5 +AES_Td: +.word 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96 +.word 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393 +.word 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25 +.word 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f +.word 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1 +.word 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6 +.word 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da +.word 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844 +.word 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd +.word 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4 +.word 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45 +.word 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94 +.word 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7 +.word 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a +.word 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5 +.word 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c +.word 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1 +.word 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a +.word 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75 +.word 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051 +.word 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46 +.word 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff +.word 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77 +.word 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb +.word 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000 +.word 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e +.word 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927 +.word 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a +.word 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e +.word 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16 +.word 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d +.word 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8 +.word 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd +.word 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34 +.word 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163 +.word 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120 +.word 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d +.word 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0 +.word 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422 +.word 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef +.word 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36 +.word 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4 +.word 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662 +.word 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5 +.word 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3 +.word 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b +.word 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8 +.word 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6 +.word 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6 +.word 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0 +.word 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815 +.word 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f +.word 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df +.word 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f +.word 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e +.word 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713 +.word 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89 +.word 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c +.word 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf +.word 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86 +.word 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f +.word 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541 +.word 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190 +.word 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +@ Td4[256] +.byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 +.byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb +.byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 +.byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb +.byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d +.byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e +.byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 +.byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 +.byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 +.byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 +.byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda +.byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 +.byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a +.byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 +.byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 +.byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b +.byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea +.byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 +.byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 +.byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e +.byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 +.byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b +.byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 +.byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 +.byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 +.byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f +.byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d +.byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef +.byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 +.byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 +.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 +.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +.size AES_Td,.-AES_Td + +@ void cryptogams_AES_decrypt_block(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.globl cryptogams_AES_decrypt_block +.type cryptogams_AES_decrypt_block,%function +.align 5 +cryptogams_AES_decrypt_block: +#ifndef __thumb2__ + sub r3,pc,#8 @ cryptogams_AES_decrypt_block +#else + adr r3,. +#endif + stmdb sp!,{r1,r4-r12,lr} +#if defined(__thumb2__) || defined(__APPLE__) + adr r10,AES_Td +#else + sub r10,r3,#cryptogams_AES_decrypt_block-AES_Td @ Td +#endif + mov r12,r0 @ inp + mov r11,r2 +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + orr r3,r3,r5,lsl#16 + orr r3,r3,r6,lsl#24 +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif +#endif + bl _cryptogams_armv4_AES_decrypt_block + + ldr r12,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r12,#0] + str r1,[r12,#4] + str r2,[r12,#8] + str r3,[r12,#12] +#else + mov r4,r0,lsr#24 @ write output in endian-neutral + mov r5,r0,lsr#16 @ manner... + mov r6,r0,lsr#8 + strb r4,[r12,#0] + strb r5,[r12,#1] + mov r4,r1,lsr#24 + strb r6,[r12,#2] + mov r5,r1,lsr#16 + strb r0,[r12,#3] + mov r6,r1,lsr#8 + strb r4,[r12,#4] + strb r5,[r12,#5] + mov r4,r2,lsr#24 + strb r6,[r12,#6] + mov r5,r2,lsr#16 + strb r1,[r12,#7] + mov r6,r2,lsr#8 + strb r4,[r12,#8] + strb r5,[r12,#9] + mov r4,r3,lsr#24 + strb r6,[r12,#10] + mov r5,r3,lsr#16 + strb r2,[r12,#11] + mov r6,r3,lsr#8 + strb r4,[r12,#12] + strb r5,[r12,#13] + strb r6,[r12,#14] + strb r3,[r12,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_AES_decrypt_block,.-cryptogams_AES_decrypt_block + +.type _cryptogams_armv4_AES_decrypt_block,%function +.align 2 +_cryptogams_armv4_AES_decrypt_block: + str lr,[sp,#-4]! @ push lr + ldmia r11!,{r4,r5,r6,r7} + eor r0,r0,r4 + ldr r12,[r11,#240-16] + eor r1,r1,r5 + eor r2,r2,r6 + eor r3,r3,r7 + sub r12,r12,#1 + mov lr,#255 + + and r7,lr,r0,lsr#16 + and r8,lr,r0,lsr#8 + and r9,lr,r0 + mov r0,r0,lsr#24 +.Ldec_loop: + ldr r4,[r10,r7,lsl#2] @ Td1[s0>>16] + and r7,lr,r1 @ i0 + ldr r5,[r10,r8,lsl#2] @ Td2[s0>>8] + and r8,lr,r1,lsr#16 + ldr r6,[r10,r9,lsl#2] @ Td3[s0>>0] + and r9,lr,r1,lsr#8 + ldr r0,[r10,r0,lsl#2] @ Td0[s0>>24] + mov r1,r1,lsr#24 + + ldr r7,[r10,r7,lsl#2] @ Td3[s1>>0] + ldr r8,[r10,r8,lsl#2] @ Td1[s1>>16] + ldr r9,[r10,r9,lsl#2] @ Td2[s1>>8] + eor r0,r0,r7,ror#24 + ldr r1,[r10,r1,lsl#2] @ Td0[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r8,r5,ror#8 + and r8,lr,r2 @ i1 + eor r6,r9,r6,ror#8 + and r9,lr,r2,lsr#16 + ldr r7,[r10,r7,lsl#2] @ Td2[s2>>8] + eor r1,r1,r4,ror#8 + ldr r8,[r10,r8,lsl#2] @ Td3[s2>>0] + mov r2,r2,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Td1[s2>>16] + eor r0,r0,r7,ror#16 + ldr r2,[r10,r2,lsl#2] @ Td0[s2>>24] + and r7,lr,r3,lsr#16 @ i0 + eor r1,r1,r8,ror#24 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r9,r6,ror#8 + and r9,lr,r3 @ i2 + ldr r7,[r10,r7,lsl#2] @ Td1[s3>>16] + eor r2,r2,r5,ror#8 + ldr r8,[r10,r8,lsl#2] @ Td2[s3>>8] + mov r3,r3,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Td3[s3>>0] + eor r0,r0,r7,ror#8 + ldr r7,[r11],#16 + eor r1,r1,r8,ror#16 + ldr r3,[r10,r3,lsl#2] @ Td0[s3>>24] + eor r2,r2,r9,ror#24 + + ldr r4,[r11,#-12] + eor r0,r0,r7 + ldr r5,[r11,#-8] + eor r3,r3,r6,ror#8 + ldr r6,[r11,#-4] + and r7,lr,r0,lsr#16 + eor r1,r1,r4 + and r8,lr,r0,lsr#8 + eor r2,r2,r5 + and r9,lr,r0 + eor r3,r3,r6 + mov r0,r0,lsr#24 + + subs r12,r12,#1 + bne .Ldec_loop + + add r10,r10,#1024 + + ldr r5,[r10,#0] @ prefetch Td4 + ldr r6,[r10,#32] + ldr r4,[r10,#64] + ldr r5,[r10,#96] + ldr r6,[r10,#128] + ldr r4,[r10,#160] + ldr r5,[r10,#192] + ldr r6,[r10,#224] + + ldrb r0,[r10,r0] @ Td4[s0>>24] + ldrb r4,[r10,r7] @ Td4[s0>>16] + and r7,lr,r1 @ i0 + ldrb r5,[r10,r8] @ Td4[s0>>8] + and r8,lr,r1,lsr#16 + ldrb r6,[r10,r9] @ Td4[s0>>0] + and r9,lr,r1,lsr#8 + + add r1,r10,r1,lsr#24 + ldrb r7,[r10,r7] @ Td4[s1>>0] + ldrb r1,[r1] @ Td4[s1>>24] + ldrb r8,[r10,r8] @ Td4[s1>>16] + eor r0,r7,r0,lsl#24 + ldrb r9,[r10,r9] @ Td4[s1>>8] + eor r1,r4,r1,lsl#8 + and r7,lr,r2,lsr#8 @ i0 + eor r5,r5,r8,lsl#8 + and r8,lr,r2 @ i1 + ldrb r7,[r10,r7] @ Td4[s2>>8] + eor r6,r6,r9,lsl#8 + ldrb r8,[r10,r8] @ Td4[s2>>0] + and r9,lr,r2,lsr#16 + + add r2,r10,r2,lsr#24 + ldrb r2,[r2] @ Td4[s2>>24] + eor r0,r0,r7,lsl#8 + ldrb r9,[r10,r9] @ Td4[s2>>16] + eor r1,r8,r1,lsl#16 + and r7,lr,r3,lsr#16 @ i0 + eor r2,r5,r2,lsl#16 + and r8,lr,r3,lsr#8 @ i1 + ldrb r7,[r10,r7] @ Td4[s3>>16] + eor r6,r6,r9,lsl#16 + ldrb r8,[r10,r8] @ Td4[s3>>8] + and r9,lr,r3 @ i2 + + add r3,r10,r3,lsr#24 + ldrb r9,[r10,r9] @ Td4[s3>>0] + ldrb r3,[r3] @ Td4[s3>>24] + eor r0,r0,r7,lsl#16 + ldr r7,[r11,#0] + eor r1,r1,r8,lsl#8 + ldr r4,[r11,#4] + eor r2,r9,r2,lsl#8 + ldr r5,[r11,#8] + eor r3,r6,r3,lsl#24 + ldr r6,[r11,#12] + + eor r0,r0,r7 + eor r1,r1,r4 + eor r2,r2,r5 + eor r3,r3,r6 + + sub r10,r10,#1024 + ldr pc,[sp],#4 @ pop and return +.size _cryptogams_armv4_AES_decrypt_block,.-_cryptogams_armv4_AES_decrypt_block diff --git a/extension/third_party/cryptopp/aes_armv4.h b/extension/third_party/cryptopp/aes_armv4.h new file mode 100644 index 00000000..2c2eec72 --- /dev/null +++ b/extension/third_party/cryptopp/aes_armv4.h @@ -0,0 +1,30 @@ +/* Header file for use with Cryptogam's ARMv4 AES. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ and */ +/* https://wiki.openssl.org/index.php?title=Cryptogams_AES */ + +#ifndef CRYPTOGAMS_AES_ARMV4_H +#define CRYPTOGAMS_AES_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define AES_MAXNR 14 +//typedef struct AES_KEY_st { +// unsigned int rd_key[4 * (AES_MAXNR + 1)]; +// int rounds; +//} AES_KEY; + +// Instead of AES_KEY we use a 'word32 rkey[4*15+4]'. It has space for +// both the AES_MAXNR round keys and the number of rounds in the tail. + +int cryptogams_AES_set_encrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey); +int cryptogams_AES_set_decrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey); +void cryptogams_AES_encrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey); +void cryptogams_AES_decrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey); + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_AES_ARMV4_H */ diff --git a/extension/third_party/cryptopp/algebra.cpp b/extension/third_party/cryptopp/algebra.cpp new file mode 100644 index 00000000..c3b3fdc1 --- /dev/null +++ b/extension/third_party/cryptopp/algebra.cpp @@ -0,0 +1,341 @@ +// algebra.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_ALGEBRA_CPP // SunCC workaround: compiler could cause this file to be included twice +#define CRYPTOPP_ALGEBRA_CPP + +#include "algebra.h" +#include "integer.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +template const T& AbstractGroup::Double(const Element &a) const +{ + return this->Add(a, a); +} + +template const T& AbstractGroup::Subtract(const Element &a, const Element &b) const +{ + // make copy of a in case Inverse() overwrites it + Element a1(a); + return this->Add(a1, Inverse(b)); +} + +template T& AbstractGroup::Accumulate(Element &a, const Element &b) const +{ + return a = this->Add(a, b); +} + +template T& AbstractGroup::Reduce(Element &a, const Element &b) const +{ + return a = this->Subtract(a, b); +} + +template const T& AbstractRing::Square(const Element &a) const +{ + return this->Multiply(a, a); +} + +template const T& AbstractRing::Divide(const Element &a, const Element &b) const +{ + // make copy of a in case MultiplicativeInverse() overwrites it + Element a1(a); + return this->Multiply(a1, this->MultiplicativeInverse(b)); +} + +template const T& AbstractEuclideanDomain::Mod(const Element &a, const Element &b) const +{ + Element q; + this->DivisionAlgorithm(result, q, a, b); + return result; +} + +template const T& AbstractEuclideanDomain::Gcd(const Element &a, const Element &b) const +{ + Element g[3]={b, a}; + unsigned int i0=0, i1=1, i2=2; + + while (!this->Equal(g[i1], this->Identity())) + { + g[i2] = this->Mod(g[i0], g[i1]); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return result = g[i0]; +} + +template const typename QuotientRing::Element& QuotientRing::MultiplicativeInverse(const Element &a) const +{ + Element g[3]={m_modulus, a}; + Element v[3]={m_domain.Identity(), m_domain.MultiplicativeIdentity()}; + Element y; + unsigned int i0=0, i1=1, i2=2; + + while (!this->Equal(g[i1], this->Identity())) + { + // y = g[i0] / g[i1]; + // g[i2] = g[i0] % g[i1]; + m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]); + // v[i2] = v[i0] - (v[i1] * y); + v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y)); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]) : m_domain.Identity(); +} + +template T AbstractGroup::ScalarMultiply(const Element &base, const Integer &exponent) const +{ + Element result; + this->SimultaneousMultiply(&result, base, &exponent, 1); + return result; +} + +template T AbstractGroup::CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const +{ + const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount()); + if (expLen==0) + return this->Identity(); + + const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3)); + const unsigned tableSize = 1< powerTable(tableSize << w); + + powerTable[1] = x; + powerTable[tableSize] = y; + if (w==1) + powerTable[3] = this->Add(x,y); + else + { + powerTable[2] = this->Double(x); + powerTable[2*tableSize] = this->Double(y); + + unsigned i, j; + + for (i=3; i=0; i--) + { + power1 = 2*power1 + e1.GetBit(i); + power2 = 2*power2 + e2.GetBit(i); + + if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize) + { + unsigned squaresBefore = prevPosition-i; + unsigned squaresAfter = 0; + prevPosition = i; + while ((power1 || power2) && power1%2 == 0 && power2%2==0) + { + power1 /= 2; + power2 /= 2; + squaresBefore--; + squaresAfter++; + } + if (firstTime) + { + result = powerTable[(power2<Double(result); + if (power1 || power2) + Accumulate(result, powerTable[(power2<Double(result); + power1 = power2 = 0; + } + } + return result; +} + +template Element GeneralCascadeMultiplication(const AbstractGroup &group, Iterator begin, Iterator end) +{ + if (end-begin == 1) + return group.ScalarMultiply(begin->base, begin->exponent); + else if (end-begin == 2) + return group.CascadeScalarMultiply(begin->base, begin->exponent, (begin+1)->base, (begin+1)->exponent); + else + { + Integer q, t; + Iterator last = end; + --last; + + std::make_heap(begin, end); + std::pop_heap(begin, end); + + while (!!begin->exponent) + { + // last->exponent is largest exponent, begin->exponent is next largest + t = last->exponent; + Integer::Divide(last->exponent, q, t, begin->exponent); + + if (q == Integer::One()) + group.Accumulate(begin->base, last->base); // avoid overhead of ScalarMultiply() + else + group.Accumulate(begin->base, group.ScalarMultiply(last->base, q)); + + std::push_heap(begin, end); + std::pop_heap(begin, end); + } + + return group.ScalarMultiply(last->base, last->exponent); + } +} + +struct WindowSlider +{ + WindowSlider(const Integer &expIn, bool fastNegate, unsigned int windowSizeIn=0) + : exp(expIn), windowModulus(Integer::One()), windowSize(windowSizeIn), windowBegin(0), expWindow(0) + , fastNegate(fastNegate), negateNext(false), firstTime(true), finished(false) + { + if (windowSize == 0) + { + unsigned int expLen = exp.BitCount(); + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7))))); + } + windowModulus <<= windowSize; + } + + void FindNextWindow() + { + unsigned int expLen = exp.WordCount() * WORD_BITS; + unsigned int skipCount = firstTime ? 0 : windowSize; + firstTime = false; + while (!exp.GetBit(skipCount)) + { + if (skipCount >= expLen) + { + finished = true; + return; + } + skipCount++; + } + + exp >>= skipCount; + windowBegin += skipCount; + expWindow = word32(exp % (word(1) << windowSize)); + + if (fastNegate && exp.GetBit(windowSize)) + { + negateNext = true; + expWindow = (word32(1) << windowSize) - expWindow; + exp += windowModulus; + } + else + negateNext = false; + } + + Integer exp, windowModulus; + unsigned int windowSize, windowBegin; + word32 expWindow; + bool fastNegate, negateNext, firstTime, finished; +}; + +template +void AbstractGroup::SimultaneousMultiply(T *results, const T &base, const Integer *expBegin, unsigned int expCount) const +{ + std::vector > buckets(expCount); + std::vector exponents; + exponents.reserve(expCount); + unsigned int i; + + for (i=0; expBegin && iNotNegative()); + exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0)); + exponents[i].FindNextWindow(); + buckets[i].resize(((size_t) 1) << (exponents[i].windowSize-1), Identity()); + } + + unsigned int expBitPosition = 0; + Element g = base; + bool notDone = true; + + while (notDone) + { + notDone = false; + for (i=0; i 1) + { + for (int j = (int)buckets[i].size()-2; j >= 1; j--) + { + Accumulate(buckets[i][j], buckets[i][j+1]); + Accumulate(r, buckets[i][j]); + } + Accumulate(buckets[i][0], buckets[i][1]); + r = Add(Double(r), buckets[i][0]); + } + } +} + +template T AbstractRing::Exponentiate(const Element &base, const Integer &exponent) const +{ + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; +} + +template T AbstractRing::CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const +{ + return MultiplicativeGroup().AbstractGroup::CascadeScalarMultiply(x, e1, y, e2); +} + +template Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end) +{ + return GeneralCascadeMultiplication(ring.MultiplicativeGroup(), begin, end); +} + +template +void AbstractRing::SimultaneousExponentiate(T *results, const T &base, const Integer *exponents, unsigned int expCount) const +{ + MultiplicativeGroup().AbstractGroup::SimultaneousMultiply(results, base, exponents, expCount); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/algebra.h b/extension/third_party/cryptopp/algebra.h new file mode 100644 index 00000000..fed8e85f --- /dev/null +++ b/extension/third_party/cryptopp/algebra.h @@ -0,0 +1,453 @@ +// algebra.h - originally written and placed in the public domain by Wei Dai + +/// \file algebra.h +/// \brief Classes for performing mathematics over different fields + +#ifndef CRYPTOPP_ALGEBRA_H +#define CRYPTOPP_ALGEBRA_H + +#include "config.h" +#include "integer.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; + +/// \brief Abstract group +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractGroup +{ +public: + typedef T Element; + + virtual ~AbstractGroup() {} + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \return true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + virtual bool Equal(const Element &a, const Element &b) const =0; + + /// \brief Provides the Identity element + /// \return the Identity element + virtual const Element& Identity() const =0; + + /// \brief Adds elements in the group + /// \param a first element + /// \param b second element + /// \return the sum of a and b + virtual const Element& Add(const Element &a, const Element &b) const =0; + + /// \brief Inverts the element in the group + /// \param a first element + /// \return the inverse of the element + virtual const Element& Inverse(const Element &a) const =0; + + /// \brief Determine if inversion is fast + /// \return true if inversion is fast, false otherwise + virtual bool InversionIsFast() const {return false;} + + /// \brief Doubles an element in the group + /// \param a the element + /// \return the element doubled + virtual const Element& Double(const Element &a) const; + + /// \brief Subtracts elements in the group + /// \param a first element + /// \param b second element + /// \return the difference of a and b. The element a must provide a Subtract member function. + virtual const Element& Subtract(const Element &a, const Element &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + virtual Element& Accumulate(Element &a, const Element &b) const; + + /// \brief Reduces an element in the congruence class + /// \param a element to reduce + /// \param b the congruence class + /// \return the reduced element + virtual Element& Reduce(Element &a, const Element &b) const; + + /// \brief Performs a scalar multiplication + /// \param a multiplicand + /// \param e multiplier + /// \return the product + virtual Element ScalarMultiply(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first multiplicand + /// \param e1 the first multiplier + /// \param y second multiplicand + /// \param e2 the second multiplier + /// \return TODO + virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Multiplies a base to multiple exponents in a group + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousMultiply() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; +}; + +/// \brief Abstract ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup +{ +public: + typedef T Element; + + /// \brief Construct an AbstractRing + AbstractRing() {m_mg.m_pRing = this;} + + /// \brief Copy construct an AbstractRing + /// \param source other AbstractRing + AbstractRing(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;} + + /// \brief Assign an AbstractRing + /// \param source other AbstractRing + AbstractRing& operator=(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); return *this;} + + /// \brief Determines whether an element is a unit in the group + /// \param a the element + /// \return true if the element is a unit after reduction, false otherwise. + virtual bool IsUnit(const Element &a) const =0; + + /// \brief Retrieves the multiplicative identity + /// \return the multiplicative identity + virtual const Element& MultiplicativeIdentity() const =0; + + /// \brief Multiplies elements in the group + /// \param a the multiplicand + /// \param b the multiplier + /// \return the product of a and b + virtual const Element& Multiply(const Element &a, const Element &b) const =0; + + /// \brief Calculate the multiplicative inverse of an element in the group + /// \param a the element + virtual const Element& MultiplicativeInverse(const Element &a) const =0; + + /// \brief Square an element in the group + /// \param a the element + /// \return the element squared + virtual const Element& Square(const Element &a) const; + + /// \brief Divides elements in the group + /// \param a the dividend + /// \param b the divisor + /// \return the quotient + virtual const Element& Divide(const Element &a, const Element &b) const; + + /// \brief Raises a base to an exponent in the group + /// \param a the base + /// \param e the exponent + /// \return the exponentiation + virtual Element Exponentiate(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \return TODO + virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the Ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Retrieves the multiplicative group + /// \return the multiplicative group + virtual const AbstractGroup& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup + { + public: + const AbstractRing& GetRing() const + {return *m_pRing;} + + bool Equal(const Element &a, const Element &b) const + {return GetRing().Equal(a, b);} + + const Element& Identity() const + {return GetRing().MultiplicativeIdentity();} + + const Element& Add(const Element &a, const Element &b) const + {return GetRing().Multiply(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return a = GetRing().Multiply(a, b);} + + const Element& Inverse(const Element &a) const + {return GetRing().MultiplicativeInverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return GetRing().Divide(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return a = GetRing().Divide(a, b);} + + const Element& Double(const Element &a) const + {return GetRing().Square(a);} + + Element ScalarMultiply(const Element &a, const Integer &e) const + {return GetRing().Exponentiate(a, e);} + + Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const + {return GetRing().CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);} + + const AbstractRing *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +/// \brief Base and exponent +/// \tparam T base class or type +/// \tparam E exponent class or type +template +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {} + bool operator<(const BaseAndExponent &rhs) const {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template + Element GeneralCascadeMultiplication(const AbstractGroup &group, Iterator begin, Iterator end); +template + Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end); + +// ******************************************************** + +/// \brief Abstract Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing +{ +public: + typedef T Element; + + /// \brief Performs the division algorithm on two elements in the ring + /// \param r the remainder + /// \param q the quotient + /// \param a the dividend + /// \param d the divisor + virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0; + + /// \brief Performs a modular reduction in the ring + /// \param a the element + /// \param b the modulus + /// \return the result of a%b. + virtual const Element& Mod(const Element &a, const Element &b) const =0; + + /// \brief Calculates the greatest common denominator in the ring + /// \param a the first element + /// \param b the second element + /// \return the the greatest common denominator of a and b. + virtual const Element& Gcd(const Element &a, const Element &b) const; + +protected: + mutable Element result; +}; + +// ******************************************************** + +/// \brief Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class EuclideanDomainOf : public AbstractEuclideanDomain +{ +public: + typedef T Element; + + EuclideanDomainOf() {} + + bool Equal(const Element &a, const Element &b) const + {return a==b;} + + const Element& Identity() const + {return Element::Zero();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a+b;} + + Element& Accumulate(Element &a, const Element &b) const + {return a+=b;} + + const Element& Inverse(const Element &a) const + {return result = -a;} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a-b;} + + Element& Reduce(Element &a, const Element &b) const + {return a-=b;} + + const Element& Double(const Element &a) const + {return result = a.Doubled();} + + const Element& MultiplicativeIdentity() const + {return Element::One();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a*b;} + + const Element& Square(const Element &a) const + {return result = a.Squared();} + + bool IsUnit(const Element &a) const + {return a.IsUnit();} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse();} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a/b;} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a%b;} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d);} + + bool operator==(const EuclideanDomainOf &rhs) const + {CRYPTOPP_UNUSED(rhs); return true;} + +private: + mutable Element result; +}; + +/// \brief Quotient ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class QuotientRing : public AbstractRing +{ +public: + typedef T EuclideanDomain; + typedef typename T::Element Element; + + QuotientRing(const EuclideanDomain &domain, const Element &modulus) + : m_domain(domain), m_modulus(modulus) {} + + const EuclideanDomain & GetDomain() const + {return m_domain;} + + const Element& GetModulus() const + {return m_modulus;} + + bool Equal(const Element &a, const Element &b) const + {return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());} + + const Element& Identity() const + {return m_domain.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return m_domain.Add(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return m_domain.Accumulate(a, b);} + + const Element& Inverse(const Element &a) const + {return m_domain.Inverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return m_domain.Subtract(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return m_domain.Reduce(a, b);} + + const Element& Double(const Element &a) const + {return m_domain.Double(a);} + + bool IsUnit(const Element &a) const + {return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));} + + const Element& MultiplicativeIdentity() const + {return m_domain.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);} + + const Element& Square(const Element &a) const + {return m_domain.Mod(m_domain.Square(a), m_modulus);} + + const Element& MultiplicativeInverse(const Element &a) const; + + bool operator==(const QuotientRing &rhs) const + {return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;} + +protected: + EuclideanDomain m_domain; + Element m_modulus; +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "algebra.cpp" +#endif + +#endif diff --git a/extension/third_party/cryptopp/algparam.cpp b/extension/third_party/cryptopp/algparam.cpp new file mode 100644 index 00000000..ff394f21 --- /dev/null +++ b/extension/third_party/cryptopp/algparam.cpp @@ -0,0 +1,75 @@ +// algparam.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "algparam.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +bool CombinedNameValuePairs::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (strcmp(name, "ValueNames") == 0) + return m_pairs1.GetVoidValue(name, valueType, pValue) && m_pairs2.GetVoidValue(name, valueType, pValue); + else + return m_pairs1.GetVoidValue(name, valueType, pValue) || m_pairs2.GetVoidValue(name, valueType, pValue); +} + +void AlgorithmParametersBase::operator=(const AlgorithmParametersBase &rhs) +{ + CRYPTOPP_UNUSED(rhs); + CRYPTOPP_ASSERT(false); +} + +bool AlgorithmParametersBase::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (strcmp(name, "ValueNames") == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(std::string), valueType); + if (m_next.get()) + m_next->GetVoidValue(name, valueType, pValue); + (*reinterpret_cast(pValue) += m_name) += ";"; + return true; + } + else if (strcmp(name, m_name) == 0) + { + AssignValue(name, valueType, pValue); + m_used = true; + return true; + } + else if (m_next.get()) + return m_next->GetVoidValue(name, valueType, pValue); + else + return false; +} + +AlgorithmParameters::AlgorithmParameters() + : m_defaultThrowIfNotUsed(true) +{ +} + +AlgorithmParameters::AlgorithmParameters(const AlgorithmParameters &x) + : m_defaultThrowIfNotUsed(x.m_defaultThrowIfNotUsed) +{ + m_next.reset(const_cast(x).m_next.release()); +} + +AlgorithmParameters & AlgorithmParameters::operator=(const AlgorithmParameters &x) +{ + m_next.reset(const_cast(x).m_next.release()); + return *this; +} + +bool AlgorithmParameters::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (m_next.get()) + return m_next->GetVoidValue(name, valueType, pValue); + else + return false; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/algparam.h b/extension/third_party/cryptopp/algparam.h new file mode 100644 index 00000000..f904c4f9 --- /dev/null +++ b/extension/third_party/cryptopp/algparam.h @@ -0,0 +1,520 @@ +// algparam.h - originally written and placed in the public domain by Wei Dai + +/// \file algparam.h +/// \brief Classes for working with NameValuePairs + +#ifndef CRYPTOPP_ALGPARAM_H +#define CRYPTOPP_ALGPARAM_H + +#include "config.h" +#include "cryptlib.h" + +#include "smartptr.h" +#include "secblock.h" +#include "integer.h" +#include "misc.h" + +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ConstByteArrayParameter +{ +public: + /// \brief Construct a ConstByteArrayParameter + /// \param data a C-String + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign(reinterpret_cast(data), data ? strlen(data) : 0, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign(data, size, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \tparam T a std::basic_string or std::vector class + /// \param string a std::basic_string or std::vector object + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + template ConstByteArrayParameter(const T &string, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1); + Assign(reinterpret_cast(&string[0]), string.size(), deepCopy); + } + + /// \brief Assign contents from a memory buffer + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + void Assign(const byte *data, size_t size, bool deepCopy) + { + // This fires, which means: no data with a size, or data with no size. + // CRYPTOPP_ASSERT((data && size) || !(data || size)); + if (deepCopy) + m_block.Assign(data, size); + else + { + m_data = data; + m_size = size; + } + m_deepCopy = deepCopy; + } + + /// \brief Pointer to the first byte in the memory block + const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;} + /// \brief Pointer beyond the last byte in the memory block + const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_deepCopy ? m_block.size() : m_size;} + +private: + bool m_deepCopy; + const byte *m_data; + size_t m_size; + SecByteBlock m_block; +}; + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ByteArrayParameter +{ +public: + /// \brief Construct a ByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0) + : m_data(data), m_size(size) {} + + /// \brief Construct a ByteArrayParameter + /// \param block a SecByteBlock + ByteArrayParameter(SecByteBlock &block) + : m_data(block.begin()), m_size(block.size()) {} + + /// \brief Pointer to the first byte in the memory block + byte *begin() const {return m_data;} + /// \brief Pointer beyond the last byte in the memory block + byte *end() const {return m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_size;} + +private: + byte *m_data; + size_t m_size; +}; + +/// \brief Combines two sets of NameValuePairs +/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs. +/// If a name is not found in the first set, then the second set is searched for the +/// name and value pair. The second set of NameValuePairs often provides default values. +class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs +{ +public: + /// \brief Construct a CombinedNameValuePairs + /// \param pairs1 reference to the first set of NameValuePairs + /// \param pairs2 reference to the second set of NameValuePairs + CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2) + : m_pairs1(pairs1), m_pairs2(pairs2) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +private: + const NameValuePairs &m_pairs1, &m_pairs2; +}; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +template +class GetValueHelperClass +{ +public: + GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst) + : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) + { + if (strcmp(m_name, "ValueNames") == 0) + { + m_found = m_getValueNames = true; + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType); + if (searchFirst) + searchFirst->GetVoidValue(m_name, valueType, pValue); + if (typeid(T) != typeid(BASE)) + pObject->BASE::GetVoidValue(m_name, valueType, pValue); + ((*reinterpret_cast(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';'; + } + + if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType); + *reinterpret_cast(pValue) = pObject; + m_found = true; + return; + } + + if (!m_found && searchFirst) + m_found = searchFirst->GetVoidValue(m_name, valueType, pValue); + + if (!m_found && typeid(T) != typeid(BASE)) + m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue); + } + + operator bool() const {return m_found;} + + template + GetValueHelperClass & operator()(const char *name, const R & (T::*pm)() const) + { + if (m_getValueNames) + (*reinterpret_cast(m_pValue) += name) += ";"; + if (!m_found && strcmp(name, m_name) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType); + *reinterpret_cast(m_pValue) = (m_pObject->*pm)(); + m_found = true; + } + return *this; + } + + GetValueHelperClass &Assignable() + { +#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason + if (m_getValueNames) + ((*reinterpret_cast(m_pValue) += "ThisObject:") += typeid(T).name()) += ';'; + if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); + *reinterpret_cast(m_pValue) = *m_pObject; + m_found = true; + } +#endif + return *this; + } + +private: + const T *m_pObject; + const char *m_name; + const std::type_info *m_valueType; + void *m_pValue; + bool m_found, m_getValueNames; +}; + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +// ******************************************************** + +template +class AssignFromHelperClass +{ +public: + AssignFromHelperClass(T *pObject, const NameValuePairs &source) + : m_pObject(pObject), m_source(source), m_done(false) + { + if (source.GetThisObject(*pObject)) + m_done = true; + else if (typeid(BASE) != typeid(T)) + pObject->BASE::AssignFrom(source); + } + + template + AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&)) + { + if (!m_done) + { + R value; + if (!m_source.GetValue(name, value)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'"); + (m_pObject->*pm)(value); + } + return *this; + } + + template + AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&)) + { + if (!m_done) + { + R value1; + if (!m_source.GetValue(name1, value1)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'"); + S value2; + if (!m_source.GetValue(name2, value2)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'"); + (m_pObject->*pm)(value1, value2); + } + return *this; + } + +private: + T *m_pObject; + const NameValuePairs &m_source; + bool m_done; +}; + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ******************************************************** + +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER +// Allow the linker to discard Integer code if not needed. +// Also see http://github.com/weidai11/cryptopp/issues/389. +CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt); +#endif + +CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId(); + +/// \brief Base class for AlgorithmParameters +class CRYPTOPP_DLL AlgorithmParametersBase +{ +public: + /// \brief Exception thrown when an AlgorithmParameter is unused + class ParameterNotUsed : public Exception + { + public: + ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {} + }; + + virtual ~AlgorithmParametersBase() CRYPTOPP_THROW + { + +#if defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS) + if (std::uncaught_exceptions() == 0) +#elif defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION) + if (std::uncaught_exception() == false) +#else + try +#endif + { + if (m_throwIfNotUsed && !m_used) + throw ParameterNotUsed(m_name); + } +#if !defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION) +# if !defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS) + catch(const Exception&) + { + } +# endif +#endif + } + + // this is actually a move, not a copy + AlgorithmParametersBase(const AlgorithmParametersBase &x) + : m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used) + { + m_next.reset(const_cast(x).m_next.release()); + x.m_used = true; + } + + /// \brief Construct a AlgorithmParametersBase + /// \param name the parameter name + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersBase(const char *name, bool throwIfNotUsed) + : m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + friend class AlgorithmParameters; + void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60 + + virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0; + virtual void MoveInto(void *p) const =0; // not really const + + const char *m_name; + bool m_throwIfNotUsed; + mutable bool m_used; + member_ptr m_next; +}; + +/// \brief Template base class for AlgorithmParameters +/// \tparam T the class or type +template +class AlgorithmParametersTemplate : public AlgorithmParametersBase +{ +public: + /// \brief Construct an AlgorithmParametersTemplate + /// \param name the name of the value + /// \param value a reference to the value + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed) + : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value) + { + } + + void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const + { +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER + // Special case for retrieving an Integer parameter when an int was passed in + if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value))) +#endif + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType); + *reinterpret_cast(pValue) = m_value; + } + } + +#if defined(DEBUG_NEW) && (_MSC_VER >= 1300) +# pragma push_macro("new") +# undef new +#endif + + void MoveInto(void *buffer) const + { + AlgorithmParametersTemplate* p = new(buffer) AlgorithmParametersTemplate(*this); + CRYPTOPP_UNUSED(p); // silence warning + } + +#if defined(DEBUG_NEW) && (_MSC_VER >= 1300) +# pragma pop_macro("new") +#endif + +protected: + T m_value; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; + +/// \brief An object that implements NameValuePairs +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using operator() on the object returned by MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs +{ +public: + /// \brief Construct a AlgorithmParameters + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ AlgorithmParameters(); + +#ifdef __BORLANDC__ + /// \brief Construct a AlgorithmParameters + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + /// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), + /// such as MSVC 7.0 and earlier. + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ template + AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true) + : m_next(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)) + , m_defaultThrowIfNotUsed(throwIfNotUsed) + { + } +#endif + + AlgorithmParameters(const AlgorithmParameters &x); + + AlgorithmParameters & operator=(const AlgorithmParameters &x); + + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + template + AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed) + { + member_ptr p(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)); + p->m_next.reset(m_next.release()); + m_next.reset(p.release()); + m_defaultThrowIfNotUsed = throwIfNotUsed; + return *this; + } + + /// \brief Appends a NameValuePair to a collection of NameValuePairs + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + template + AlgorithmParameters & operator()(const char *name, const T &value) + { + return operator()(name, value, m_defaultThrowIfNotUsed); + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + member_ptr m_next; + bool m_defaultThrowIfNotUsed; +}; + +/// \brief Create an object that implements NameValuePairs +/// \tparam T the class or type +/// \param name the name of the object or value to retrieve +/// \param value reference to a variable that receives the value +/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed +/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), +/// such as MSVC 7.0 and earlier. +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using \p operator() on the object returned by \p MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+#ifdef __BORLANDC__ +typedef AlgorithmParameters MakeParameters; +#else +template +AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true) +{ + return AlgorithmParameters()(name, value, throwIfNotUsed); +} +#endif + +#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2) + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/allocate.cpp b/extension/third_party/cryptopp/allocate.cpp new file mode 100644 index 00000000..745eb781 --- /dev/null +++ b/extension/third_party/cryptopp/allocate.cpp @@ -0,0 +1,107 @@ +// allocate.cpp - written and placed in the public domain by Jeffrey Walton + +// The functions in allocate.h and allocate.cpp were originally in misc.h +// and misc.cpp. They were extracted in September 2019 to sidestep a circular +// dependency with misc.h and secblock.h. + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "allocate.h" +#include "stdcpp.h" +#include "misc.h" +#include "trap.h" + +// for memalign +#if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX) +# include +#endif +// for posix_memalign +#if defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE) +# include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +void CallNewHandler() +{ + using std::new_handler; + using std::set_new_handler; + + new_handler newHandler = set_new_handler(NULLPTR); + if (newHandler) + set_new_handler(newHandler); + + if (newHandler) + newHandler(); + else + throw std::bad_alloc(); +} + +void * AlignedAllocate(size_t size) +{ + byte *p; +#if defined(CRYPTOPP_MM_MALLOC_AVAILABLE) + while ((p = (byte *)_mm_malloc(size, 16)) == NULLPTR) +#elif defined(CRYPTOPP_MEMALIGN_AVAILABLE) + while ((p = (byte *)memalign(16, size)) == NULLPTR) +#elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16) + while ((p = (byte *)malloc(size)) == NULLPTR) +#elif defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE) + while (posix_memalign(reinterpret_cast(&p), 16, size) != 0) +#else + while ((p = (byte *)malloc(size + 16)) == NULLPTR) +#endif + CallNewHandler(); + +#ifdef CRYPTOPP_NO_ALIGNED_ALLOC + size_t adjustment = 16-((size_t)p%16); + CRYPTOPP_ASSERT(adjustment > 0); + p += adjustment; + p[-1] = (byte)adjustment; +#endif + + // If this assert fires then there are problems that need + // to be fixed. Please open a bug report. + CRYPTOPP_ASSERT(IsAlignedOn(p, 16)); + return p; +} + +void AlignedDeallocate(void *p) +{ + // Guard pointer due to crash on AIX when CRYPTOPP_NO_ALIGNED_ALLOC + // is in effect. The guard was previously in place in SecBlock, + // but it was removed at f4d68353ca7c as part of GH #875. + CRYPTOPP_ASSERT(p); + + if (p != NULLPTR) + { +#ifdef CRYPTOPP_MM_MALLOC_AVAILABLE + _mm_free(p); +#elif defined(CRYPTOPP_NO_ALIGNED_ALLOC) + p = (byte *)p - ((byte *)p)[-1]; + free(p); +#else + free(p); +#endif + } +} + +void * UnalignedAllocate(size_t size) +{ + void *p; + while ((p = malloc(size)) == NULLPTR) + CallNewHandler(); + return p; +} + +void UnalignedDeallocate(void *p) +{ + free(p); +} + +NAMESPACE_END + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/allocate.h b/extension/third_party/cryptopp/allocate.h new file mode 100644 index 00000000..64e1ac79 --- /dev/null +++ b/extension/third_party/cryptopp/allocate.h @@ -0,0 +1,74 @@ +// allocate.h - written and placed in the public domain by Jeffrey Walton + +// The functions in allocate.h and allocate.cpp were originally in misc.h +// and misc.cpp. They were extracted in September 2019 to sidestep a circular +// dependency with misc.h and secblock.h. + +/// \file allocate.h +/// \brief Functions for allocating aligned buffers + +#ifndef CRYPTOPP_ALLOCATE_H +#define CRYPTOPP_ALLOCATE_H + +#include "config.h" +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Attempts to reclaim unused memory +/// \throw bad_alloc +/// \details In the normal course of running a program, a request for memory +/// normally succeeds. If a call to AlignedAllocate or UnalignedAllocate fails, +/// then CallNewHandler is called in n effort to recover. Internally, +/// CallNewHandler calls set_new_handler(nullptr) in an effort to free memory. +/// There is no guarantee CallNewHandler will be able to obtain more memory so +/// an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler +/// throws a bad_alloc exception. +/// \throw bad_alloc on failure +/// \since Crypto++ 5.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate +CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler(); + +/// \brief Allocates a buffer on 16-byte boundary +/// \param size the size of the buffer +/// \details AlignedAllocate is primarily used when the data will be +/// processed by SSE, NEON, ARMv8 or PowerPC instructions. The assembly +/// language routines rely on the alignment. If the alignment is not +/// respected, then a SIGBUS could be generated on Unix and Linux, and an +/// EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows. +/// \details Formerly, AlignedAllocate and AlignedDeallocate were only +/// available on certain platforms when CRYTPOPP_DISABLE_ASM was not in +/// effect. However, Android and iOS debug simulator builds got into a +/// state where the aligned allocator was not available and caused link +/// failures. +/// \since AlignedAllocate for SIMD since Crypto++ 1.0, AlignedAllocate +/// for all builds since Crypto++ 8.1 +/// \sa AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with AlignedAllocate +/// \param ptr the buffer to free +/// \since AlignedDeallocate for SIMD since Crypto++ 1.0, AlignedAllocate +/// for all builds since Crypto++ 8.1 +/// \sa AlignedAllocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr); + +/// \brief Allocates a buffer +/// \param size the size of the buffer +/// \since Crypto++ 1.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with UnalignedAllocate +/// \param ptr the buffer to free +/// \since Crypto++ 1.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr); + +NAMESPACE_END + +#endif // CRYPTOPP_ALLOCATE_H diff --git a/extension/third_party/cryptopp/arc4.cpp b/extension/third_party/cryptopp/arc4.cpp new file mode 100644 index 00000000..2bc2dd1f --- /dev/null +++ b/extension/third_party/cryptopp/arc4.cpp @@ -0,0 +1,122 @@ +// arc4.cpp - originally written and placed in the public domain by Wei Dai + +// The ARC4 algorithm was first revealed in an anonymous email to the +// cypherpunks mailing list. This file originally contained some +// code copied from this email. The code has since been rewritten in order +// to clarify the copyright status of this file. It should now be +// completely in the public domain. + +#include "pch.h" +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include "arc4.h" + +NAMESPACE_BEGIN(CryptoPP) +namespace Weak1 { + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ARC4_TestInstantiations() +{ + ARC4 x; +} +#endif + +ARC4_Base::~ARC4_Base() +{ + m_x = m_y = 0; +} + +void ARC4_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(length); + + m_x = 1; + m_y = 0; + + unsigned int i; + for (i=0; i<256; i++) + m_state[i] = byte(i); + + unsigned int keyIndex = 0, stateIndex = 0; + for (i=0; i<256; i++) + { + unsigned int a = m_state[i]; + stateIndex += key[keyIndex] + a; + stateIndex &= 0xff; + m_state[i] = m_state[stateIndex]; + m_state[stateIndex] = byte(a); + if (++keyIndex >= length) + keyIndex = 0; + } + + int discardBytes = params.GetIntValueWithDefault("DiscardBytes", GetDefaultDiscardBytes()); + DiscardBytes(discardBytes); +} + +template +static inline unsigned int MakeByte(T &x, T &y, byte *s) +{ + unsigned int a = s[x]; + y = byte((y+a) & 0xff); + unsigned int b = s[y]; + s[x] = byte(b); + s[y] = byte(a); + x = byte((x+1) & 0xff); + return s[(a+b) & 0xff]; +} + +void ARC4_Base::GenerateBlock(byte *output, size_t size) +{ + while (size--) + *output++ = static_cast(MakeByte(m_x, m_y, m_state)); +} + +void ARC4_Base::ProcessData(byte *outString, const byte *inString, size_t length) +{ + if (length == 0) + return; + + byte *const s = m_state; + unsigned int x = m_x; + unsigned int y = m_y; + + if (inString == outString) + { + do + { + *outString++ ^= MakeByte(x, y, s); + } while (--length); + } + else + { + do + { + *outString++ = *inString++ ^ byte(MakeByte(x, y, s)); + } + while(--length); + } + + m_x = byte(x); + m_y = byte(y); +} + +void ARC4_Base::DiscardBytes(size_t n) +{ + if (n == 0) + return; + + byte *const s = m_state; + unsigned int x = m_x; + unsigned int y = m_y; + + do + { + MakeByte(x, y, s); + } + while(--n); + + m_x = byte(x); + m_y = byte(y); +} + +} +NAMESPACE_END diff --git a/extension/third_party/cryptopp/arc4.h b/extension/third_party/cryptopp/arc4.h new file mode 100644 index 00000000..baed9e76 --- /dev/null +++ b/extension/third_party/cryptopp/arc4.h @@ -0,0 +1,89 @@ +// arc4.h - originally written and placed in the public domain by Wei Dai + +/// \file arc4.h +/// \brief Classes for ARC4 cipher +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_ARC4_H +#define CRYPTOPP_ARC4_H + +#include "cryptlib.h" +#include "strciphr.h" +#include "secblock.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief ARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE ARC4_Base : public VariableKeyLength<16, 1, 256>, public RandomNumberGenerator, public SymmetricCipher, public SymmetricCipherDocumentation +{ +public: + ~ARC4_Base(); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARC4";} + + void GenerateBlock(byte *output, size_t size); + void DiscardBytes(size_t n); + + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual unsigned int GetDefaultDiscardBytes() const {return 0;} + + FixedSizeSecBlock m_state; + byte m_x, m_y; +}; + +/// \brief Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, ARC4); + +/// \brief MARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \details MARC4 discards the first 256 bytes of keystream, which may be weaker than the rest +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE MARC4_Base : public ARC4_Base +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARC4";} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + unsigned int GetDefaultDiscardBytes() const {return 256;} +}; + +/// \brief Modified Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, MARC4); + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/argnames.h b/extension/third_party/cryptopp/argnames.h new file mode 100644 index 00000000..3d2859a8 --- /dev/null +++ b/extension/third_party/cryptopp/argnames.h @@ -0,0 +1,99 @@ +// argnames.h - originally written and placed in the public domain by Wei Dai + +/// \file argnames.h +/// \brief Standard names for retrieving values by name when working with \p NameValuePairs + +#ifndef CRYPTOPP_ARGNAMES_H +#define CRYPTOPP_ARGNAMES_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +DOCUMENTED_NAMESPACE_BEGIN(Name) + +#define CRYPTOPP_DEFINE_NAME_STRING(name) inline const char *name() {return #name;} + +CRYPTOPP_DEFINE_NAME_STRING(ValueNames) ///< string, a list of value names with a semicolon (';') after each name +CRYPTOPP_DEFINE_NAME_STRING(Version) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Seed) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Key) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(IV) ///< ConstByteArrayParameter, also accepts const byte * for backwards compatibility +CRYPTOPP_DEFINE_NAME_STRING(StolenIV) ///< byte * +CRYPTOPP_DEFINE_NAME_STRING(Nonce) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Rounds) ///< int +CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(WordSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(BlockSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(KeySize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(ModulusSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(Modulus) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicElement) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Cofactor) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator) ///< Integer, ECP::Point, or EC2N::Point +CRYPTOPP_DEFINE_NAME_STRING(Curve) ///< ECP or EC2N +CRYPTOPP_DEFINE_NAME_STRING(GroupOID) ///< OID +CRYPTOPP_DEFINE_NAME_STRING(PointerToPrimeSelector) ///< const PrimeSelector * +CRYPTOPP_DEFINE_NAME_STRING(Prime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Prime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PutMessage) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(TruncatedDigestSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(BlockPaddingScheme) ///< StreamTransformationFilter::BlockPaddingScheme +CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(AuthenticatedDecryptionFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(InputBuffer) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer) ///< ByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(InputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(InputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(InputStreamPointer) ///< std::istream * +CRYPTOPP_DEFINE_NAME_STRING(InputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(OutputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(OutputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(OutputStreamPointer) ///< std::ostream * +CRYPTOPP_DEFINE_NAME_STRING(OutputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(EncodingParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(KeyDerivationParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Separator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Terminator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Uppercase) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(GroupSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Pad) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(PaddingByte) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(Log2Base) ///< int +CRYPTOPP_DEFINE_NAME_STRING(EncodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(DecodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(InsertLineBreaks) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(MaxLineLength) ///< int +CRYPTOPP_DEFINE_NAME_STRING(DigestSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(L1KeyLength) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TableSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Blinding) ///< bool, timing attack mitigations, ON by default +CRYPTOPP_DEFINE_NAME_STRING(DerivedKey) ///< ByteArrayParameter, key derivation, derived key +CRYPTOPP_DEFINE_NAME_STRING(DerivedKeyLength) ///< int, key derivation, derived key length in bytes +CRYPTOPP_DEFINE_NAME_STRING(Personalization) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(PersonalizationSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Salt) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Tweak) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(SaltSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TreeMode) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(FileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(FileTime) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Comment) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(Identity) ///< ConstByteArrayParameter +DOCUMENTED_NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/aria.cpp b/extension/third_party/cryptopp/aria.cpp new file mode 100644 index 00000000..bc7509fd --- /dev/null +++ b/extension/third_party/cryptopp/aria.cpp @@ -0,0 +1,343 @@ +// aria.cpp - written and placed in the public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" + +#include "aria.h" +#include "misc.h" +#include "cpu.h" + +#if CRYPTOPP_SSE2_INTRIN_AVAILABLE +# define CRYPTOPP_ENABLE_ARIA_SSE2_INTRINSICS 1 +#endif + +#if CRYPTOPP_SSSE3_AVAILABLE +# define CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS 1 +#endif + +// GCC cast warning. Note: this is used on round key table, +// which is word32 and naturally aligned. +#define UINT32_CAST(x) ((word32 *)(void *)(x)) + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(ARIATab) + +extern const word32 S1[256]; +extern const word32 S2[256]; +extern const word32 X1[256]; +extern const word32 X2[256]; +extern const word32 KRK[3][4]; + +NAMESPACE_END +NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +using CryptoPP::ARIATab::S1; +using CryptoPP::ARIATab::S2; +using CryptoPP::ARIATab::X1; +using CryptoPP::ARIATab::X2; +using CryptoPP::ARIATab::KRK; + +inline byte ARIA_BRF(const word32 x, const int y) { + return static_cast(GETBYTE(x, y)); +} + +// Key XOR Layer +#define ARIA_KXL { \ + typedef BlockGetAndPut NativeBlock; \ + NativeBlock::Put(rk, t)(t[0])(t[1])(t[2])(t[3]); \ + } + +// S-Box Layer 1 + M +#define SBL1_M(T0,T1,T2,T3) { \ + T0=S1[ARIA_BRF(T0,3)]^S2[ARIA_BRF(T0,2)]^X1[ARIA_BRF(T0,1)]^X2[ARIA_BRF(T0,0)]; \ + T1=S1[ARIA_BRF(T1,3)]^S2[ARIA_BRF(T1,2)]^X1[ARIA_BRF(T1,1)]^X2[ARIA_BRF(T1,0)]; \ + T2=S1[ARIA_BRF(T2,3)]^S2[ARIA_BRF(T2,2)]^X1[ARIA_BRF(T2,1)]^X2[ARIA_BRF(T2,0)]; \ + T3=S1[ARIA_BRF(T3,3)]^S2[ARIA_BRF(T3,2)]^X1[ARIA_BRF(T3,1)]^X2[ARIA_BRF(T3,0)]; \ + } + +// S-Box Layer 2 + M +#define SBL2_M(T0,T1,T2,T3) { \ + T0=X1[ARIA_BRF(T0,3)]^X2[ARIA_BRF(T0,2)]^S1[ARIA_BRF(T0,1)]^S2[ARIA_BRF(T0,0)]; \ + T1=X1[ARIA_BRF(T1,3)]^X2[ARIA_BRF(T1,2)]^S1[ARIA_BRF(T1,1)]^S2[ARIA_BRF(T1,0)]; \ + T2=X1[ARIA_BRF(T2,3)]^X2[ARIA_BRF(T2,2)]^S1[ARIA_BRF(T2,1)]^S2[ARIA_BRF(T2,0)]; \ + T3=X1[ARIA_BRF(T3,3)]^X2[ARIA_BRF(T3,2)]^S1[ARIA_BRF(T3,1)]^S2[ARIA_BRF(T3,0)]; \ + } + +#define ARIA_P(T0,T1,T2,T3) { \ + (T1) = (((T1)<< 8)&0xff00ff00) ^ (((T1)>> 8)&0x00ff00ff); \ + (T2) = rotrConstant<16>(T2); \ + (T3) = ByteReverse((T3)); \ + } + +#define ARIA_M(X,Y) { \ + Y=(X)<<8 ^ (X)>>8 ^ (X)<<16 ^ (X)>>16 ^ (X)<<24 ^ (X)>>24; \ + } + +#define ARIA_MM(T0,T1,T2,T3) { \ + (T1)^=(T2); (T2)^=(T3); (T0)^=(T1); \ + (T3)^=(T1); (T2)^=(T0); (T1)^=(T2); \ + } + +#define ARIA_FO {SBL1_M(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3]) ARIA_P(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3])} +#define ARIA_FE {SBL2_M(t[0],t[1],t[2],t[3]) ARIA_MM(t[0],t[1],t[2],t[3]) ARIA_P(t[2],t[3],t[0],t[1]) ARIA_MM(t[0],t[1],t[2],t[3])} + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +extern void ARIA_UncheckedSetKey_Schedule_NEON(byte* rk, word32* ws, unsigned int keylen); +extern void ARIA_ProcessAndXorBlock_NEON(const byte* xorBlock, byte* outblock, const byte *rk, word32 *t); +#endif + +#if (CRYPTOPP_SSSE3_AVAILABLE) +extern void ARIA_ProcessAndXorBlock_SSSE3(const byte* xorBlock, byte* outBlock, const byte *rk, word32 *t); +#endif + +// n-bit right shift of Y XORed to X +template +inline void ARIA_GSRK(const word32 X[4], const word32 Y[4], byte RK[16]) +{ + // MSVC is not generating a "rotate immediate". Constify to help it along. + static const unsigned int Q = 4-(N/32); + static const unsigned int R = N % 32; + UINT32_CAST(RK)[0] = (X[0]) ^ ((Y[(Q )%4])>>R) ^ ((Y[(Q+3)%4])<<(32-R)); + UINT32_CAST(RK)[1] = (X[1]) ^ ((Y[(Q+1)%4])>>R) ^ ((Y[(Q )%4])<<(32-R)); + UINT32_CAST(RK)[2] = (X[2]) ^ ((Y[(Q+2)%4])>>R) ^ ((Y[(Q+1)%4])<<(32-R)); + UINT32_CAST(RK)[3] = (X[3]) ^ ((Y[(Q+3)%4])>>R) ^ ((Y[(Q+2)%4])<<(32-R)); +} + +void ARIA::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + + m_rk.New(16*17); // round keys + m_w.New(4*7); // w0, w1, w2, w3, t and u + + byte *rk = m_rk.data(); + int Q, q, R, r; + + switch (keylen) + { + case 16: + R = r = m_rounds = 12; + Q = q = 0; + break; + case 32: + R = r = m_rounds = 16; + Q = q = 2; + break; + case 24: + R = r = m_rounds = 14; + Q = q = 1; + break; + default: + Q = q = R = r = m_rounds = 0; + CRYPTOPP_ASSERT(0); + } + + // w0 has room for 32 bytes. w1-w3 each has room for 16 bytes. t and u are 16 byte temp areas. + word32 *w0 = m_w.data(), *w1 = m_w.data()+8, *w2 = m_w.data()+12, *w3 = m_w.data()+16, *t = m_w.data()+20; + + GetBlockblock(key); + block(w0[0])(w0[1])(w0[2])(w0[3]); + + t[0]=w0[0]^KRK[q][0]; t[1]=w0[1]^KRK[q][1]; + t[2]=w0[2]^KRK[q][2]; t[3]=w0[3]^KRK[q][3]; + + ARIA_FO; + + if (keylen == 32) + { + block(w1[0])(w1[1])(w1[2])(w1[3]); + } + else if (keylen == 24) + { + block(w1[0])(w1[1]); w1[2] = w1[3] = 0; + } + else + { + w1[0]=w1[1]=w1[2]=w1[3]=0; + } + + w1[0]^=t[0]; w1[1]^=t[1]; w1[2]^=t[2]; w1[3]^=t[3]; + ::memcpy(t, w1, 16); + + q = (q==2) ? 0 : (q+1); + t[0]^=KRK[q][0]; t[1]^=KRK[q][1]; t[2]^=KRK[q][2]; t[3]^=KRK[q][3]; + + ARIA_FE; + + t[0]^=w0[0]; t[1]^=w0[1]; t[2]^=w0[2]; t[3]^=w0[3]; + ::memcpy(w2, t, 16); + + q = (q==2) ? 0 : (q+1); + t[0]^=KRK[q][0]; t[1]^=KRK[q][1]; t[2]^=KRK[q][2]; t[3]^=KRK[q][3]; + + ARIA_FO; + + w3[0]=t[0]^w1[0]; w3[1]=t[1]^w1[1]; w3[2]=t[2]^w1[2]; w3[3]=t[3]^w1[3]; + +#if CRYPTOPP_ARM_NEON_AVAILABLE + if (HasNEON()) + { + ARIA_UncheckedSetKey_Schedule_NEON(rk, m_w, keylen); + } + else +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + { + ARIA_GSRK<19>(w0, w1, rk + 0); + ARIA_GSRK<19>(w1, w2, rk + 16); + ARIA_GSRK<19>(w2, w3, rk + 32); + ARIA_GSRK<19>(w3, w0, rk + 48); + ARIA_GSRK<31>(w0, w1, rk + 64); + ARIA_GSRK<31>(w1, w2, rk + 80); + ARIA_GSRK<31>(w2, w3, rk + 96); + ARIA_GSRK<31>(w3, w0, rk + 112); + ARIA_GSRK<67>(w0, w1, rk + 128); + ARIA_GSRK<67>(w1, w2, rk + 144); + ARIA_GSRK<67>(w2, w3, rk + 160); + ARIA_GSRK<67>(w3, w0, rk + 176); + ARIA_GSRK<97>(w0, w1, rk + 192); + + if (keylen > 16) + { + ARIA_GSRK<97>(w1, w2, rk + 208); + ARIA_GSRK<97>(w2, w3, rk + 224); + + if (keylen > 24) + { + ARIA_GSRK< 97>(w3, w0, rk + 240); + ARIA_GSRK<109>(w0, w1, rk + 256); + } + } + } + + // Decryption operation + if (!IsForwardTransformation()) + { + word32 *a, *z, *s; + rk = m_rk.data(); + r = R; q = Q; + + a=UINT32_CAST(rk); s=m_w.data()+24; z=a+r*4; + ::memcpy(t, a, 16); ::memcpy(a, z, 16); ::memcpy(z, t, 16); + + a+=4; z-=4; + for (; a(m_rk.data()); + word32 *t = const_cast(m_w.data()+20); + + // Timing attack countermeasure. See comments in Rijndael for more details. + // We used Yun's 32-bit implementation, so we use words rather than bytes. + const int cacheLineSize = GetCacheLineSize(); + unsigned int i; + volatile word32 _u = 0; + word32 u = _u; + + for (i=0; iblock(inBlock); + block(t[0])(t[1])(t[2])(t[3]); + + if (m_rounds > 12) { + ARIA_KXL; rk+= 16; ARIA_FO; + ARIA_KXL; rk+= 16; ARIA_FE; + } + + if (m_rounds > 14) { + ARIA_KXL; rk+= 16; ARIA_FO; + ARIA_KXL; rk+= 16; ARIA_FE; + } + + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE; + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE; + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE; + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE; + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; ARIA_FE; + ARIA_KXL; rk+= 16; ARIA_FO; ARIA_KXL; rk+= 16; + +#if CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS + if (HasSSSE3()) + { + ARIA_ProcessAndXorBlock_SSSE3(xorBlock, outBlock, rk, t); + return; + } + else +#endif // CRYPTOPP_ENABLE_ARIA_SSSE3_INTRINSICS +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + { + ARIA_ProcessAndXorBlock_NEON(xorBlock, outBlock, rk, t); + return; + } + else +#endif // CRYPTOPP_ARM_NEON_AVAILABLE +#if (CRYPTOPP_LITTLE_ENDIAN) + { + outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] ) ^ rk[ 3]; + outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8) ^ rk[ 2]; + outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] ) ^ rk[ 1]; + outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] ) ^ rk[ 0]; + outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] ) ^ rk[ 7]; + outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8) ^ rk[ 6]; + outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] ) ^ rk[ 5]; + outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] ) ^ rk[ 4]; + outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] ) ^ rk[11]; + outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8) ^ rk[10]; + outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] ) ^ rk[ 9]; + outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] ) ^ rk[ 8]; + outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] ) ^ rk[15]; + outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8) ^ rk[14]; + outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] ) ^ rk[13]; + outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] ) ^ rk[12]; + } +#else + { + outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] ) ^ rk[ 0]; + outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8) ^ rk[ 1]; + outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] ) ^ rk[ 2]; + outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] ) ^ rk[ 3]; + outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] ) ^ rk[ 4]; + outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8) ^ rk[ 5]; + outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] ) ^ rk[ 6]; + outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] ) ^ rk[ 7]; + outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] ) ^ rk[ 8]; + outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8) ^ rk[ 9]; + outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] ) ^ rk[10]; + outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] ) ^ rk[11]; + outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] ) ^ rk[12]; + outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8) ^ rk[13]; + outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] ) ^ rk[14]; + outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] ) ^ rk[15]; + } +#endif // CRYPTOPP_LITTLE_ENDIAN + + if (xorBlock != NULLPTR) + for (unsigned int n=0; nRFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage + +#ifndef CRYPTOPP_ARIA_H +#define CRYPTOPP_ARIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ARIA block cipher information +/// \since Crypto++ 6.0 +struct ARIA_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARIA";} +}; + +/// \brief ARIA block cipher +/// \details The Crypto++ ARIA implementation is based on the 32-bit implementation by Aaram Yun +/// from the National Security Research Institute, KOREA. Aaram Yun's implementation is based on +/// the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from the Korea +/// Internet & Security Agency website. +/// \sa RFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage +/// \sa ARIA +/// \since Crypto++ 6.0 +class ARIA : public ARIA_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + Base() : m_rounds(0) {} + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + // Reference implementation allocates a table of 17 round keys. + typedef SecBlock > AlignedByteBlock; + typedef SecBlock > AlignedWordBlock; + + AlignedByteBlock m_rk; // round keys + AlignedWordBlock m_w; // w0, w1, w2, w3, t and u + unsigned int m_rounds; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ARIA::Encryption ARIAEncryption; +typedef ARIA::Decryption ARIADecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/aria_simd.cpp b/extension/third_party/cryptopp/aria_simd.cpp new file mode 100644 index 00000000..4d212cf1 --- /dev/null +++ b/extension/third_party/cryptopp/aria_simd.cpp @@ -0,0 +1,198 @@ +// aria_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to ARMv7a and +// ARMv8a NEON instructions. A separate source file is needed +// because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "misc.h" + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char ARIA_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(ARIATab) + +extern const word32 S1[256]; +extern const word32 S2[256]; +extern const word32 X1[256]; +extern const word32 X2[256]; +extern const word32 KRK[3][4]; + +NAMESPACE_END +NAMESPACE_END + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; + +inline byte ARIA_BRF(const word32 x, const int y) { + return static_cast(GETBYTE(x, y)); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +using CryptoPP::ARIATab::S1; +using CryptoPP::ARIATab::S2; +using CryptoPP::ARIATab::X1; +using CryptoPP::ARIATab::X2; +using CryptoPP::ARIATab::KRK; + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +template +inline void ARIA_GSRK_NEON(const uint32x4_t X, const uint32x4_t Y, byte RK[16]) +{ + enum { Q1 = (4-(N/32)) % 4, + Q2 = (3-(N/32)) % 4, + R = N % 32 + }; + + vst1q_u8(RK, vreinterpretq_u8_u32( + veorq_u32(X, veorq_u32( + vshrq_n_u32(vextq_u32(Y, Y, Q1), R), + vshlq_n_u32(vextq_u32(Y, Y, Q2), 32-R))))); +} + +void ARIA_UncheckedSetKey_Schedule_NEON(byte* rk, word32* ws, unsigned int keylen) +{ + const uint32x4_t w0 = vld1q_u32(ws+ 0); + const uint32x4_t w1 = vld1q_u32(ws+ 8); + const uint32x4_t w2 = vld1q_u32(ws+12); + const uint32x4_t w3 = vld1q_u32(ws+16); + + ARIA_GSRK_NEON<19>(w0, w1, rk + 0); + ARIA_GSRK_NEON<19>(w1, w2, rk + 16); + ARIA_GSRK_NEON<19>(w2, w3, rk + 32); + ARIA_GSRK_NEON<19>(w3, w0, rk + 48); + ARIA_GSRK_NEON<31>(w0, w1, rk + 64); + ARIA_GSRK_NEON<31>(w1, w2, rk + 80); + ARIA_GSRK_NEON<31>(w2, w3, rk + 96); + ARIA_GSRK_NEON<31>(w3, w0, rk + 112); + ARIA_GSRK_NEON<67>(w0, w1, rk + 128); + ARIA_GSRK_NEON<67>(w1, w2, rk + 144); + ARIA_GSRK_NEON<67>(w2, w3, rk + 160); + ARIA_GSRK_NEON<67>(w3, w0, rk + 176); + ARIA_GSRK_NEON<97>(w0, w1, rk + 192); + + if (keylen > 16) + { + ARIA_GSRK_NEON<97>(w1, w2, rk + 208); + ARIA_GSRK_NEON<97>(w2, w3, rk + 224); + + if (keylen > 24) + { + ARIA_GSRK_NEON< 97>(w3, w0, rk + 240); + ARIA_GSRK_NEON<109>(w0, w1, rk + 256); + } + } +} + +void ARIA_ProcessAndXorBlock_NEON(const byte* xorBlock, byte* outBlock, const byte *rk, word32 *t) +{ + outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] ); + outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8); + outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] ); + outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] ); + outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] ); + outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8); + outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] ); + outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] ); + outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] ); + outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8); + outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] ); + outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] ); + outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] ); + outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8); + outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] ); + outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] ); + + // 'outBlock' and 'xorBlock' may be unaligned. + if (xorBlock != NULLPTR) + { + vst1q_u8(outBlock, + veorq_u8( + vld1q_u8(xorBlock), + veorq_u8( + vld1q_u8(outBlock), + vrev32q_u8(vld1q_u8((rk)))))); + } + else + { + vst1q_u8(outBlock, + veorq_u8( + vld1q_u8(outBlock), + vrev32q_u8(vld1q_u8(rk)))); + } +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +void ARIA_ProcessAndXorBlock_SSSE3(const byte* xorBlock, byte* outBlock, const byte *rk, word32 *t) +{ + const __m128i MASK = _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3); + + outBlock[ 0] = (byte)(X1[ARIA_BRF(t[0],3)] ); + outBlock[ 1] = (byte)(X2[ARIA_BRF(t[0],2)]>>8); + outBlock[ 2] = (byte)(S1[ARIA_BRF(t[0],1)] ); + outBlock[ 3] = (byte)(S2[ARIA_BRF(t[0],0)] ); + outBlock[ 4] = (byte)(X1[ARIA_BRF(t[1],3)] ); + outBlock[ 5] = (byte)(X2[ARIA_BRF(t[1],2)]>>8); + outBlock[ 6] = (byte)(S1[ARIA_BRF(t[1],1)] ); + outBlock[ 7] = (byte)(S2[ARIA_BRF(t[1],0)] ); + outBlock[ 8] = (byte)(X1[ARIA_BRF(t[2],3)] ); + outBlock[ 9] = (byte)(X2[ARIA_BRF(t[2],2)]>>8); + outBlock[10] = (byte)(S1[ARIA_BRF(t[2],1)] ); + outBlock[11] = (byte)(S2[ARIA_BRF(t[2],0)] ); + outBlock[12] = (byte)(X1[ARIA_BRF(t[3],3)] ); + outBlock[13] = (byte)(X2[ARIA_BRF(t[3],2)]>>8); + outBlock[14] = (byte)(S1[ARIA_BRF(t[3],1)] ); + outBlock[15] = (byte)(S2[ARIA_BRF(t[3],0)] ); + + // 'outBlock' and 'xorBlock' may be unaligned. + if (xorBlock != NULLPTR) + { + _mm_storeu_si128(M128_CAST(outBlock), + _mm_xor_si128( + _mm_loadu_si128(CONST_M128_CAST(xorBlock)), + _mm_xor_si128( + _mm_loadu_si128(CONST_M128_CAST(outBlock)), + _mm_shuffle_epi8(_mm_load_si128(CONST_M128_CAST(rk)), MASK))) + ); + } + else + { + _mm_storeu_si128(M128_CAST(outBlock), + _mm_xor_si128(_mm_loadu_si128(CONST_M128_CAST(outBlock)), + _mm_shuffle_epi8(_mm_load_si128(CONST_M128_CAST(rk)), MASK))); + } +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ariatab.cpp b/extension/third_party/cryptopp/ariatab.cpp new file mode 100644 index 00000000..6c8a1566 --- /dev/null +++ b/extension/third_party/cryptopp/ariatab.cpp @@ -0,0 +1,166 @@ +// ariatab.cpp - written and placed in the public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(ARIATab) + +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word32 S1[256]={ + 0x00636363,0x007c7c7c,0x00777777,0x007b7b7b,0x00f2f2f2,0x006b6b6b,0x006f6f6f,0x00c5c5c5, + 0x00303030,0x00010101,0x00676767,0x002b2b2b,0x00fefefe,0x00d7d7d7,0x00ababab,0x00767676, + 0x00cacaca,0x00828282,0x00c9c9c9,0x007d7d7d,0x00fafafa,0x00595959,0x00474747,0x00f0f0f0, + 0x00adadad,0x00d4d4d4,0x00a2a2a2,0x00afafaf,0x009c9c9c,0x00a4a4a4,0x00727272,0x00c0c0c0, + 0x00b7b7b7,0x00fdfdfd,0x00939393,0x00262626,0x00363636,0x003f3f3f,0x00f7f7f7,0x00cccccc, + 0x00343434,0x00a5a5a5,0x00e5e5e5,0x00f1f1f1,0x00717171,0x00d8d8d8,0x00313131,0x00151515, + 0x00040404,0x00c7c7c7,0x00232323,0x00c3c3c3,0x00181818,0x00969696,0x00050505,0x009a9a9a, + 0x00070707,0x00121212,0x00808080,0x00e2e2e2,0x00ebebeb,0x00272727,0x00b2b2b2,0x00757575, + 0x00090909,0x00838383,0x002c2c2c,0x001a1a1a,0x001b1b1b,0x006e6e6e,0x005a5a5a,0x00a0a0a0, + 0x00525252,0x003b3b3b,0x00d6d6d6,0x00b3b3b3,0x00292929,0x00e3e3e3,0x002f2f2f,0x00848484, + 0x00535353,0x00d1d1d1,0x00000000,0x00ededed,0x00202020,0x00fcfcfc,0x00b1b1b1,0x005b5b5b, + 0x006a6a6a,0x00cbcbcb,0x00bebebe,0x00393939,0x004a4a4a,0x004c4c4c,0x00585858,0x00cfcfcf, + 0x00d0d0d0,0x00efefef,0x00aaaaaa,0x00fbfbfb,0x00434343,0x004d4d4d,0x00333333,0x00858585, + 0x00454545,0x00f9f9f9,0x00020202,0x007f7f7f,0x00505050,0x003c3c3c,0x009f9f9f,0x00a8a8a8, + 0x00515151,0x00a3a3a3,0x00404040,0x008f8f8f,0x00929292,0x009d9d9d,0x00383838,0x00f5f5f5, + 0x00bcbcbc,0x00b6b6b6,0x00dadada,0x00212121,0x00101010,0x00ffffff,0x00f3f3f3,0x00d2d2d2, + 0x00cdcdcd,0x000c0c0c,0x00131313,0x00ececec,0x005f5f5f,0x00979797,0x00444444,0x00171717, + 0x00c4c4c4,0x00a7a7a7,0x007e7e7e,0x003d3d3d,0x00646464,0x005d5d5d,0x00191919,0x00737373, + 0x00606060,0x00818181,0x004f4f4f,0x00dcdcdc,0x00222222,0x002a2a2a,0x00909090,0x00888888, + 0x00464646,0x00eeeeee,0x00b8b8b8,0x00141414,0x00dedede,0x005e5e5e,0x000b0b0b,0x00dbdbdb, + 0x00e0e0e0,0x00323232,0x003a3a3a,0x000a0a0a,0x00494949,0x00060606,0x00242424,0x005c5c5c, + 0x00c2c2c2,0x00d3d3d3,0x00acacac,0x00626262,0x00919191,0x00959595,0x00e4e4e4,0x00797979, + 0x00e7e7e7,0x00c8c8c8,0x00373737,0x006d6d6d,0x008d8d8d,0x00d5d5d5,0x004e4e4e,0x00a9a9a9, + 0x006c6c6c,0x00565656,0x00f4f4f4,0x00eaeaea,0x00656565,0x007a7a7a,0x00aeaeae,0x00080808, + 0x00bababa,0x00787878,0x00252525,0x002e2e2e,0x001c1c1c,0x00a6a6a6,0x00b4b4b4,0x00c6c6c6, + 0x00e8e8e8,0x00dddddd,0x00747474,0x001f1f1f,0x004b4b4b,0x00bdbdbd,0x008b8b8b,0x008a8a8a, + 0x00707070,0x003e3e3e,0x00b5b5b5,0x00666666,0x00484848,0x00030303,0x00f6f6f6,0x000e0e0e, + 0x00616161,0x00353535,0x00575757,0x00b9b9b9,0x00868686,0x00c1c1c1,0x001d1d1d,0x009e9e9e, + 0x00e1e1e1,0x00f8f8f8,0x00989898,0x00111111,0x00696969,0x00d9d9d9,0x008e8e8e,0x00949494, + 0x009b9b9b,0x001e1e1e,0x00878787,0x00e9e9e9,0x00cecece,0x00555555,0x00282828,0x00dfdfdf, + 0x008c8c8c,0x00a1a1a1,0x00898989,0x000d0d0d,0x00bfbfbf,0x00e6e6e6,0x00424242,0x00686868, + 0x00414141,0x00999999,0x002d2d2d,0x000f0f0f,0x00b0b0b0,0x00545454,0x00bbbbbb,0x00161616 +}; + +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word32 S2[256]={ + 0xe200e2e2,0x4e004e4e,0x54005454,0xfc00fcfc,0x94009494,0xc200c2c2,0x4a004a4a,0xcc00cccc, + 0x62006262,0x0d000d0d,0x6a006a6a,0x46004646,0x3c003c3c,0x4d004d4d,0x8b008b8b,0xd100d1d1, + 0x5e005e5e,0xfa00fafa,0x64006464,0xcb00cbcb,0xb400b4b4,0x97009797,0xbe00bebe,0x2b002b2b, + 0xbc00bcbc,0x77007777,0x2e002e2e,0x03000303,0xd300d3d3,0x19001919,0x59005959,0xc100c1c1, + 0x1d001d1d,0x06000606,0x41004141,0x6b006b6b,0x55005555,0xf000f0f0,0x99009999,0x69006969, + 0xea00eaea,0x9c009c9c,0x18001818,0xae00aeae,0x63006363,0xdf00dfdf,0xe700e7e7,0xbb00bbbb, + 0x00000000,0x73007373,0x66006666,0xfb00fbfb,0x96009696,0x4c004c4c,0x85008585,0xe400e4e4, + 0x3a003a3a,0x09000909,0x45004545,0xaa00aaaa,0x0f000f0f,0xee00eeee,0x10001010,0xeb00ebeb, + 0x2d002d2d,0x7f007f7f,0xf400f4f4,0x29002929,0xac00acac,0xcf00cfcf,0xad00adad,0x91009191, + 0x8d008d8d,0x78007878,0xc800c8c8,0x95009595,0xf900f9f9,0x2f002f2f,0xce00cece,0xcd00cdcd, + 0x08000808,0x7a007a7a,0x88008888,0x38003838,0x5c005c5c,0x83008383,0x2a002a2a,0x28002828, + 0x47004747,0xdb00dbdb,0xb800b8b8,0xc700c7c7,0x93009393,0xa400a4a4,0x12001212,0x53005353, + 0xff00ffff,0x87008787,0x0e000e0e,0x31003131,0x36003636,0x21002121,0x58005858,0x48004848, + 0x01000101,0x8e008e8e,0x37003737,0x74007474,0x32003232,0xca00caca,0xe900e9e9,0xb100b1b1, + 0xb700b7b7,0xab00abab,0x0c000c0c,0xd700d7d7,0xc400c4c4,0x56005656,0x42004242,0x26002626, + 0x07000707,0x98009898,0x60006060,0xd900d9d9,0xb600b6b6,0xb900b9b9,0x11001111,0x40004040, + 0xec00ecec,0x20002020,0x8c008c8c,0xbd00bdbd,0xa000a0a0,0xc900c9c9,0x84008484,0x04000404, + 0x49004949,0x23002323,0xf100f1f1,0x4f004f4f,0x50005050,0x1f001f1f,0x13001313,0xdc00dcdc, + 0xd800d8d8,0xc000c0c0,0x9e009e9e,0x57005757,0xe300e3e3,0xc300c3c3,0x7b007b7b,0x65006565, + 0x3b003b3b,0x02000202,0x8f008f8f,0x3e003e3e,0xe800e8e8,0x25002525,0x92009292,0xe500e5e5, + 0x15001515,0xdd00dddd,0xfd00fdfd,0x17001717,0xa900a9a9,0xbf00bfbf,0xd400d4d4,0x9a009a9a, + 0x7e007e7e,0xc500c5c5,0x39003939,0x67006767,0xfe00fefe,0x76007676,0x9d009d9d,0x43004343, + 0xa700a7a7,0xe100e1e1,0xd000d0d0,0xf500f5f5,0x68006868,0xf200f2f2,0x1b001b1b,0x34003434, + 0x70007070,0x05000505,0xa300a3a3,0x8a008a8a,0xd500d5d5,0x79007979,0x86008686,0xa800a8a8, + 0x30003030,0xc600c6c6,0x51005151,0x4b004b4b,0x1e001e1e,0xa600a6a6,0x27002727,0xf600f6f6, + 0x35003535,0xd200d2d2,0x6e006e6e,0x24002424,0x16001616,0x82008282,0x5f005f5f,0xda00dada, + 0xe600e6e6,0x75007575,0xa200a2a2,0xef00efef,0x2c002c2c,0xb200b2b2,0x1c001c1c,0x9f009f9f, + 0x5d005d5d,0x6f006f6f,0x80008080,0x0a000a0a,0x72007272,0x44004444,0x9b009b9b,0x6c006c6c, + 0x90009090,0x0b000b0b,0x5b005b5b,0x33003333,0x7d007d7d,0x5a005a5a,0x52005252,0xf300f3f3, + 0x61006161,0xa100a1a1,0xf700f7f7,0xb000b0b0,0xd600d6d6,0x3f003f3f,0x7c007c7c,0x6d006d6d, + 0xed00eded,0x14001414,0xe000e0e0,0xa500a5a5,0x3d003d3d,0x22002222,0xb300b3b3,0xf800f8f8, + 0x89008989,0xde00dede,0x71007171,0x1a001a1a,0xaf00afaf,0xba00baba,0xb500b5b5,0x81008181 +}; + +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word32 X1[256]={ + 0x52520052,0x09090009,0x6a6a006a,0xd5d500d5,0x30300030,0x36360036,0xa5a500a5,0x38380038, + 0xbfbf00bf,0x40400040,0xa3a300a3,0x9e9e009e,0x81810081,0xf3f300f3,0xd7d700d7,0xfbfb00fb, + 0x7c7c007c,0xe3e300e3,0x39390039,0x82820082,0x9b9b009b,0x2f2f002f,0xffff00ff,0x87870087, + 0x34340034,0x8e8e008e,0x43430043,0x44440044,0xc4c400c4,0xdede00de,0xe9e900e9,0xcbcb00cb, + 0x54540054,0x7b7b007b,0x94940094,0x32320032,0xa6a600a6,0xc2c200c2,0x23230023,0x3d3d003d, + 0xeeee00ee,0x4c4c004c,0x95950095,0x0b0b000b,0x42420042,0xfafa00fa,0xc3c300c3,0x4e4e004e, + 0x08080008,0x2e2e002e,0xa1a100a1,0x66660066,0x28280028,0xd9d900d9,0x24240024,0xb2b200b2, + 0x76760076,0x5b5b005b,0xa2a200a2,0x49490049,0x6d6d006d,0x8b8b008b,0xd1d100d1,0x25250025, + 0x72720072,0xf8f800f8,0xf6f600f6,0x64640064,0x86860086,0x68680068,0x98980098,0x16160016, + 0xd4d400d4,0xa4a400a4,0x5c5c005c,0xcccc00cc,0x5d5d005d,0x65650065,0xb6b600b6,0x92920092, + 0x6c6c006c,0x70700070,0x48480048,0x50500050,0xfdfd00fd,0xeded00ed,0xb9b900b9,0xdada00da, + 0x5e5e005e,0x15150015,0x46460046,0x57570057,0xa7a700a7,0x8d8d008d,0x9d9d009d,0x84840084, + 0x90900090,0xd8d800d8,0xabab00ab,0x00000000,0x8c8c008c,0xbcbc00bc,0xd3d300d3,0x0a0a000a, + 0xf7f700f7,0xe4e400e4,0x58580058,0x05050005,0xb8b800b8,0xb3b300b3,0x45450045,0x06060006, + 0xd0d000d0,0x2c2c002c,0x1e1e001e,0x8f8f008f,0xcaca00ca,0x3f3f003f,0x0f0f000f,0x02020002, + 0xc1c100c1,0xafaf00af,0xbdbd00bd,0x03030003,0x01010001,0x13130013,0x8a8a008a,0x6b6b006b, + 0x3a3a003a,0x91910091,0x11110011,0x41410041,0x4f4f004f,0x67670067,0xdcdc00dc,0xeaea00ea, + 0x97970097,0xf2f200f2,0xcfcf00cf,0xcece00ce,0xf0f000f0,0xb4b400b4,0xe6e600e6,0x73730073, + 0x96960096,0xacac00ac,0x74740074,0x22220022,0xe7e700e7,0xadad00ad,0x35350035,0x85850085, + 0xe2e200e2,0xf9f900f9,0x37370037,0xe8e800e8,0x1c1c001c,0x75750075,0xdfdf00df,0x6e6e006e, + 0x47470047,0xf1f100f1,0x1a1a001a,0x71710071,0x1d1d001d,0x29290029,0xc5c500c5,0x89890089, + 0x6f6f006f,0xb7b700b7,0x62620062,0x0e0e000e,0xaaaa00aa,0x18180018,0xbebe00be,0x1b1b001b, + 0xfcfc00fc,0x56560056,0x3e3e003e,0x4b4b004b,0xc6c600c6,0xd2d200d2,0x79790079,0x20200020, + 0x9a9a009a,0xdbdb00db,0xc0c000c0,0xfefe00fe,0x78780078,0xcdcd00cd,0x5a5a005a,0xf4f400f4, + 0x1f1f001f,0xdddd00dd,0xa8a800a8,0x33330033,0x88880088,0x07070007,0xc7c700c7,0x31310031, + 0xb1b100b1,0x12120012,0x10100010,0x59590059,0x27270027,0x80800080,0xecec00ec,0x5f5f005f, + 0x60600060,0x51510051,0x7f7f007f,0xa9a900a9,0x19190019,0xb5b500b5,0x4a4a004a,0x0d0d000d, + 0x2d2d002d,0xe5e500e5,0x7a7a007a,0x9f9f009f,0x93930093,0xc9c900c9,0x9c9c009c,0xefef00ef, + 0xa0a000a0,0xe0e000e0,0x3b3b003b,0x4d4d004d,0xaeae00ae,0x2a2a002a,0xf5f500f5,0xb0b000b0, + 0xc8c800c8,0xebeb00eb,0xbbbb00bb,0x3c3c003c,0x83830083,0x53530053,0x99990099,0x61610061, + 0x17170017,0x2b2b002b,0x04040004,0x7e7e007e,0xbaba00ba,0x77770077,0xd6d600d6,0x26260026, + 0xe1e100e1,0x69690069,0x14140014,0x63630063,0x55550055,0x21210021,0x0c0c000c,0x7d7d007d +}; + +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word32 X2[256]={ + 0x30303000,0x68686800,0x99999900,0x1b1b1b00,0x87878700,0xb9b9b900,0x21212100,0x78787800, + 0x50505000,0x39393900,0xdbdbdb00,0xe1e1e100,0x72727200,0x09090900,0x62626200,0x3c3c3c00, + 0x3e3e3e00,0x7e7e7e00,0x5e5e5e00,0x8e8e8e00,0xf1f1f100,0xa0a0a000,0xcccccc00,0xa3a3a300, + 0x2a2a2a00,0x1d1d1d00,0xfbfbfb00,0xb6b6b600,0xd6d6d600,0x20202000,0xc4c4c400,0x8d8d8d00, + 0x81818100,0x65656500,0xf5f5f500,0x89898900,0xcbcbcb00,0x9d9d9d00,0x77777700,0xc6c6c600, + 0x57575700,0x43434300,0x56565600,0x17171700,0xd4d4d400,0x40404000,0x1a1a1a00,0x4d4d4d00, + 0xc0c0c000,0x63636300,0x6c6c6c00,0xe3e3e300,0xb7b7b700,0xc8c8c800,0x64646400,0x6a6a6a00, + 0x53535300,0xaaaaaa00,0x38383800,0x98989800,0x0c0c0c00,0xf4f4f400,0x9b9b9b00,0xededed00, + 0x7f7f7f00,0x22222200,0x76767600,0xafafaf00,0xdddddd00,0x3a3a3a00,0x0b0b0b00,0x58585800, + 0x67676700,0x88888800,0x06060600,0xc3c3c300,0x35353500,0x0d0d0d00,0x01010100,0x8b8b8b00, + 0x8c8c8c00,0xc2c2c200,0xe6e6e600,0x5f5f5f00,0x02020200,0x24242400,0x75757500,0x93939300, + 0x66666600,0x1e1e1e00,0xe5e5e500,0xe2e2e200,0x54545400,0xd8d8d800,0x10101000,0xcecece00, + 0x7a7a7a00,0xe8e8e800,0x08080800,0x2c2c2c00,0x12121200,0x97979700,0x32323200,0xababab00, + 0xb4b4b400,0x27272700,0x0a0a0a00,0x23232300,0xdfdfdf00,0xefefef00,0xcacaca00,0xd9d9d900, + 0xb8b8b800,0xfafafa00,0xdcdcdc00,0x31313100,0x6b6b6b00,0xd1d1d100,0xadadad00,0x19191900, + 0x49494900,0xbdbdbd00,0x51515100,0x96969600,0xeeeeee00,0xe4e4e400,0xa8a8a800,0x41414100, + 0xdadada00,0xffffff00,0xcdcdcd00,0x55555500,0x86868600,0x36363600,0xbebebe00,0x61616100, + 0x52525200,0xf8f8f800,0xbbbbbb00,0x0e0e0e00,0x82828200,0x48484800,0x69696900,0x9a9a9a00, + 0xe0e0e000,0x47474700,0x9e9e9e00,0x5c5c5c00,0x04040400,0x4b4b4b00,0x34343400,0x15151500, + 0x79797900,0x26262600,0xa7a7a700,0xdedede00,0x29292900,0xaeaeae00,0x92929200,0xd7d7d700, + 0x84848400,0xe9e9e900,0xd2d2d200,0xbababa00,0x5d5d5d00,0xf3f3f300,0xc5c5c500,0xb0b0b000, + 0xbfbfbf00,0xa4a4a400,0x3b3b3b00,0x71717100,0x44444400,0x46464600,0x2b2b2b00,0xfcfcfc00, + 0xebebeb00,0x6f6f6f00,0xd5d5d500,0xf6f6f600,0x14141400,0xfefefe00,0x7c7c7c00,0x70707000, + 0x5a5a5a00,0x7d7d7d00,0xfdfdfd00,0x2f2f2f00,0x18181800,0x83838300,0x16161600,0xa5a5a500, + 0x91919100,0x1f1f1f00,0x05050500,0x95959500,0x74747400,0xa9a9a900,0xc1c1c100,0x5b5b5b00, + 0x4a4a4a00,0x85858500,0x6d6d6d00,0x13131300,0x07070700,0x4f4f4f00,0x4e4e4e00,0x45454500, + 0xb2b2b200,0x0f0f0f00,0xc9c9c900,0x1c1c1c00,0xa6a6a600,0xbcbcbc00,0xececec00,0x73737300, + 0x90909000,0x7b7b7b00,0xcfcfcf00,0x59595900,0x8f8f8f00,0xa1a1a100,0xf9f9f900,0x2d2d2d00, + 0xf2f2f200,0xb1b1b100,0x00000000,0x94949400,0x37373700,0x9f9f9f00,0xd0d0d000,0x2e2e2e00, + 0x9c9c9c00,0x6e6e6e00,0x28282800,0x3f3f3f00,0x80808000,0xf0f0f000,0x3d3d3d00,0xd3d3d300, + 0x25252500,0x8a8a8a00,0xb5b5b500,0xe7e7e700,0x42424200,0xb3b3b300,0xc7c7c700,0xeaeaea00, + 0xf7f7f700,0x4c4c4c00,0x11111100,0x33333300,0x03030300,0xa2a2a200,0xacacac00,0x60606000 +}; + +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word32 KRK[3][4] = { + {0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0}, + {0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0}, + {0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e} +}; + +NAMESPACE_END +NAMESPACE_END diff --git a/extension/third_party/cryptopp/arm_simd.h b/extension/third_party/cryptopp/arm_simd.h new file mode 100644 index 00000000..c2ccdacd --- /dev/null +++ b/extension/third_party/cryptopp/arm_simd.h @@ -0,0 +1,188 @@ +// arm_simd.h - written and placed in public domain by Jeffrey Walton + +/// \file arm_simd.h +/// \brief Support functions for ARM and vector operations + +#ifndef CRYPTOPP_ARM_SIMD_H +#define CRYPTOPP_ARM_SIMD_H + +#include "config.h" + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_ARM_PMULL_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details PMULL_00() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x00). +/// The 0x00 indicates the low 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_00(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(_MSC_VER) + const __n64 x = { vgetq_lane_u64(a, 0) }; + const __n64 y = { vgetq_lane_u64(b, 0) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm __volatile("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),0), + vgetq_lane_u64(vreinterpretq_u64_u8(b),0))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details PMULL_01 performs() polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x01). +/// The 0x01 indicates the low 64-bits of a and high +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_01(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(_MSC_VER) + const __n64 x = { vgetq_lane_u64(a, 0) }; + const __n64 y = { vgetq_lane_u64(b, 1) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm __volatile("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (a), "w" (vget_high_u64(b)) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),0), + vgetq_lane_u64(vreinterpretq_u64_u8(b),1))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details PMULL_10() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x10). +/// The 0x10 indicates the high 64-bits of a and low +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_10(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(_MSC_VER) + const __n64 x = { vgetq_lane_u64(a, 1) }; + const __n64 y = { vgetq_lane_u64(b, 0) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm __volatile("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (vget_high_u64(a)), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),1), + vgetq_lane_u64(vreinterpretq_u64_u8(b),0))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details PMULL_11() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x11). +/// The 0x11 indicates the high 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_11(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(_MSC_VER) + const __n64 x = { vgetq_lane_u64(a, 1) }; + const __n64 y = { vgetq_lane_u64(b, 1) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm __volatile("pmull2 %0.1q, %1.2d, %2.2d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),1), + vgetq_lane_u64(vreinterpretq_u64_u8(b),1))); +#endif +} + +/// \brief Vector extraction +/// \param a the first term +/// \param b the second term +/// \param c the byte count +/// \return vector +/// \details VEXT_U8() extracts the first c bytes of vector +/// a and the remaining bytes in b. +/// \since Crypto++ 8.0 +inline uint64x2_t VEXT_U8(uint64x2_t a, uint64x2_t b, unsigned int c) +{ +#if defined(_MSC_VER) + return (uint64x2_t)vextq_u8( + vreinterpretq_u8_u64(a), vreinterpretq_u8_u64(b), c); +#else + uint64x2_t r; + __asm __volatile("ext %0.16b, %1.16b, %2.16b, %3 \n\t" + :"=w" (r) : "w" (a), "w" (b), "I" (c) ); + return r; +#endif +} + +/// \brief Vector extraction +/// \tparam C the byte count +/// \param a the first term +/// \param b the second term +/// \return vector +/// \details VEXT_U8() extracts the first C bytes of vector +/// a and the remaining bytes in b. +/// \since Crypto++ 8.0 +template +inline uint64x2_t VEXT_U8(uint64x2_t a, uint64x2_t b) +{ + // https://github.com/weidai11/cryptopp/issues/366 +#if defined(_MSC_VER) + return (uint64x2_t)vextq_u8( + vreinterpretq_u8_u64(a), vreinterpretq_u8_u64(b), C); +#else + uint64x2_t r; + __asm __volatile("ext %0.16b, %1.16b, %2.16b, %3 \n\t" + :"=w" (r) : "w" (a), "w" (b), "I" (C) ); + return r; +#endif +} + +#endif // CRYPTOPP_ARM_PMULL_AVAILABLE + +#endif // CRYPTOPP_ARM_SIMD_H diff --git a/extension/third_party/cryptopp/asn.cpp b/extension/third_party/cryptopp/asn.cpp new file mode 100644 index 00000000..d3ceef9d --- /dev/null +++ b/extension/third_party/cryptopp/asn.cpp @@ -0,0 +1,717 @@ +// asn.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "cryptlib.h" +#include "asn.h" +#include "misc.h" + +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +size_t DERLengthEncode(BufferedTransformation &bt, lword length) +{ + size_t i=0; + if (length <= 0x7f) + { + bt.Put(byte(length)); + i++; + } + else + { + bt.Put(byte(BytePrecision(length) | 0x80)); + i++; + for (int j=BytePrecision(length); j; --j) + { + bt.Put(byte(length >> (j-1)*8)); + i++; + } + } + return i; +} + +bool BERLengthDecode(BufferedTransformation &bt, lword &length, bool &definiteLength) +{ + byte b; + + if (!bt.Get(b)) + return false; + + if (!(b & 0x80)) + { + definiteLength = true; + length = b; + } + else + { + unsigned int lengthBytes = b & 0x7f; + + if (lengthBytes == 0) + { + definiteLength = false; + return true; + } + + definiteLength = true; + length = 0; + while (lengthBytes--) + { + if (length >> (8*(sizeof(length)-1))) + BERDecodeError(); // length about to overflow + + if (!bt.Get(b)) + return false; + + length = (length << 8) | b; + } + } + return true; +} + +bool BERLengthDecode(BufferedTransformation &bt, size_t &length) +{ + lword lw = 0; + bool definiteLength = false; + if (!BERLengthDecode(bt, lw, definiteLength)) + BERDecodeError(); + if (!SafeConvert(lw, length)) + BERDecodeError(); + return definiteLength; +} + +void DEREncodeNull(BufferedTransformation &out) +{ + out.Put(TAG_NULL); + out.Put(0); +} + +void BERDecodeNull(BufferedTransformation &in) +{ + byte b; + if (!in.Get(b) || b != TAG_NULL) + BERDecodeError(); + size_t length; + if (!BERLengthDecode(in, length) || length != 0) + BERDecodeError(); +} + +/// ASN Strings +size_t DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen) +{ + bt.Put(OCTET_STRING); + size_t lengthBytes = DERLengthEncode(bt, strLen); + bt.Put(str, strLen); + return 1+lengthBytes+strLen; +} + +size_t DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str) +{ + return DEREncodeOctetString(bt, ConstBytePtr(str), BytePtrSize(str)); +} + +size_t BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str) +{ + byte b; + if (!bt.Get(b) || b != OCTET_STRING) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + str.New(bc); + if (bc != bt.Get(BytePtr(str), bc)) + BERDecodeError(); + return bc; +} + +size_t BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str) +{ + byte b; + if (!bt.Get(b) || b != OCTET_STRING) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + bt.TransferTo(str, bc); + return bc; +} + +size_t DEREncodeTextString(BufferedTransformation &bt, const byte* str, size_t strLen, byte asnTag) +{ + bt.Put(asnTag); + size_t lengthBytes = DERLengthEncode(bt, strLen); + bt.Put(str, strLen); + return 1+lengthBytes+strLen; +} + +size_t DEREncodeTextString(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag) +{ + return DEREncodeTextString(bt, ConstBytePtr(str), BytePtrSize(str), asnTag); +} + +size_t DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag) +{ + return DEREncodeTextString(bt, ConstBytePtr(str), BytePtrSize(str), asnTag); +} + +size_t BERDecodeTextString(BufferedTransformation &bt, SecByteBlock &str, byte asnTag) +{ + byte b; + if (!bt.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + str.resize(bc); + if (bc != bt.Get(BytePtr(str), BytePtrSize(str))) + BERDecodeError(); + + return bc; +} + +size_t BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag) +{ + byte b; + if (!bt.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + str.resize(bc); + if (bc != bt.Get(BytePtr(str), BytePtrSize(str))) + BERDecodeError(); + + return bc; +} + +size_t DEREncodeDate(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag) +{ + bt.Put(asnTag); + size_t lengthBytes = DERLengthEncode(bt, str.size()); + bt.Put(ConstBytePtr(str), BytePtrSize(str)); + return 1+lengthBytes+str.size(); +} + +size_t BERDecodeDate(BufferedTransformation &bt, SecByteBlock &str, byte asnTag) +{ + byte b; + if (!bt.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + str.resize(bc); + if (bc != bt.Get(BytePtr(str), BytePtrSize(str))) + BERDecodeError(); + + return bc; +} + +size_t DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits) +{ + bt.Put(BIT_STRING); + size_t lengthBytes = DERLengthEncode(bt, strLen+1); + bt.Put((byte)unusedBits); + bt.Put(str, strLen); + return 2+lengthBytes+strLen; +} + +size_t BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits) +{ + byte b; + if (!bt.Get(b) || b != BIT_STRING) + BERDecodeError(); + + size_t bc; + if (!BERLengthDecode(bt, bc)) + BERDecodeError(); + if (bc == 0) + BERDecodeError(); + if (bc > bt.MaxRetrievable()) // Issue 346 + BERDecodeError(); + + // X.690, 8.6.2.2: "The number [of unused bits] shall be in the range zero to seven" + byte unused; + if (!bt.Get(unused) || unused > 7) + BERDecodeError(); + unusedBits = unused; + str.resize(bc-1); + if ((bc-1) != bt.Get(BytePtr(str), bc-1)) + BERDecodeError(); + return bc-1; +} + +void DERReencode(BufferedTransformation &source, BufferedTransformation &dest) +{ + byte tag; + source.Peek(tag); + BERGeneralDecoder decoder(source, tag); + DERGeneralEncoder encoder(dest, tag); + if (decoder.IsDefiniteLength()) + decoder.TransferTo(encoder, decoder.RemainingLength()); + else + { + while (!decoder.EndReached()) + DERReencode(decoder, encoder); + } + decoder.MessageEnd(); + encoder.MessageEnd(); +} + +size_t BERDecodePeekLength(const BufferedTransformation &bt) +{ + lword count = (std::min)(bt.MaxRetrievable(), static_cast(16)); + if (count == 0) return 0; + + ByteQueue tagAndLength; + bt.CopyTo(tagAndLength, count); + + // Skip tag + tagAndLength.Skip(1); + + // BERLengthDecode fails for indefinite length. + size_t length; + if (!BERLengthDecode(tagAndLength, length)) + return 0; + + return length; +} + +void OID::EncodeValue(BufferedTransformation &bt, word32 v) +{ + for (unsigned int i=RoundUpToMultipleOf(STDMAX(7U,BitPrecision(v)), 7U)-7; i != 0; i-=7) + bt.Put((byte)(0x80 | ((v >> i) & 0x7f))); + bt.Put((byte)(v & 0x7f)); +} + +size_t OID::DecodeValue(BufferedTransformation &bt, word32 &v) +{ + byte b; + size_t i=0; + v = 0; + while (true) + { + if (!bt.Get(b)) + BERDecodeError(); + i++; + if (v >> (8*sizeof(v)-7)) // v about to overflow + BERDecodeError(); + v <<= 7; + v += b & 0x7f; + if (!(b & 0x80)) + return i; + } +} + +void OID::DEREncode(BufferedTransformation &bt) const +{ + CRYPTOPP_ASSERT(m_values.size() >= 2); + ByteQueue temp; + temp.Put(byte(m_values[0] * 40 + m_values[1])); + for (size_t i=2; i 0) + { + word32 v; + size_t valueLen = DecodeValue(bt, v); + if (valueLen > length) + BERDecodeError(); + m_values.push_back(v); + length -= valueLen; + } +} + +void OID::BERDecodeAndCheck(BufferedTransformation &bt) const +{ + OID oid(bt); + if (*this != oid) + BERDecodeError(); +} + +std::ostream& OID::Print(std::ostream& out) const +{ + std::ostringstream oss; + for (size_t i = 0; i < m_values.size(); ++i) + { + oss << m_values[i]; + if (i+1 < m_values.size()) + oss << "."; + } + return out << oss.str(); +} + +inline BufferedTransformation & EncodedObjectFilter::CurrentTarget() +{ + if (m_flags & PUT_OBJECTS) + return *AttachedTransformation(); + else + return TheBitBucket(); +} + +void EncodedObjectFilter::Put(const byte *inString, size_t length) +{ + if (m_nCurrentObject == m_nObjects) + { + AttachedTransformation()->Put(inString, length); + return; + } + + LazyPutter lazyPutter(m_queue, inString, length); + + while (m_queue.AnyRetrievable()) + { + switch (m_state) + { + case IDENTIFIER: + if (!m_queue.Get(m_id)) + return; + m_queue.TransferTo(CurrentTarget(), 1); + m_state = LENGTH; + // fall through + case LENGTH: + { + byte b; + if (m_level > 0 && m_id == 0 && m_queue.Peek(b) && b == 0) + { + m_queue.TransferTo(CurrentTarget(), 1); + m_level--; + m_state = IDENTIFIER; + break; + } + ByteQueue::Walker walker(m_queue); + bool definiteLength = false; + if (!BERLengthDecode(walker, m_lengthRemaining, definiteLength)) + return; + m_queue.TransferTo(CurrentTarget(), walker.GetCurrentPosition()); + if (!((m_id & CONSTRUCTED) || definiteLength)) + BERDecodeError(); + if (!definiteLength) + { + if (!(m_id & CONSTRUCTED)) + BERDecodeError(); + m_level++; + m_state = IDENTIFIER; + break; + } + m_state = BODY; + } + // fall through + case BODY: + m_lengthRemaining -= m_queue.TransferTo(CurrentTarget(), m_lengthRemaining); + + if (m_lengthRemaining == 0) + m_state = IDENTIFIER; + // fall through + case TAIL: + case ALL_DONE: + default: ; + } + + if (m_state == IDENTIFIER && m_level == 0) + { + // just finished processing a level 0 object + ++m_nCurrentObject; + + if (m_flags & PUT_MESSANGE_END_AFTER_EACH_OBJECT) + AttachedTransformation()->MessageEnd(); + + if (m_nCurrentObject == m_nObjects) + { + if (m_flags & PUT_MESSANGE_END_AFTER_ALL_OBJECTS) + AttachedTransformation()->MessageEnd(); + + if (m_flags & PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS) + AttachedTransformation()->MessageSeriesEnd(); + + m_queue.TransferAllTo(*AttachedTransformation()); + return; + } + } + } +} + +BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation &inQueue) + : m_inQueue(inQueue), m_length(0), m_finished(false) +{ + Init(DefaultTag); +} + +BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag) + : m_inQueue(inQueue), m_length(0), m_finished(false) +{ + Init(asnTag); +} + +BERGeneralDecoder::BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag) + : m_inQueue(inQueue), m_length(0), m_finished(false) +{ + Init(asnTag); +} + +void BERGeneralDecoder::Init(byte asnTag) +{ + byte b; + if (!m_inQueue.Get(b) || b != asnTag) + BERDecodeError(); + + if (!BERLengthDecode(m_inQueue, m_length, m_definiteLength)) + BERDecodeError(); + + if (!m_definiteLength && !(asnTag & CONSTRUCTED)) + BERDecodeError(); // cannot be primitive and have indefinite length +} + +BERGeneralDecoder::~BERGeneralDecoder() +{ + try // avoid throwing in destructor + { + if (!m_finished) + MessageEnd(); + } + catch (const Exception&) + { + // CRYPTOPP_ASSERT(0); + } +} + +bool BERGeneralDecoder::EndReached() const +{ + if (m_definiteLength) + return m_length == 0; + else + { // check end-of-content octets + word16 i; + return (m_inQueue.PeekWord16(i)==2 && i==0); + } +} + +byte BERGeneralDecoder::PeekByte() const +{ + byte b; + if (!Peek(b)) + BERDecodeError(); + return b; +} + +void BERGeneralDecoder::CheckByte(byte check) +{ + byte b; + if (!Get(b) || b != check) + BERDecodeError(); +} + +void BERGeneralDecoder::MessageEnd() +{ + m_finished = true; + if (m_definiteLength) + { + if (m_length != 0) + BERDecodeError(); + } + else + { // remove end-of-content octets + word16 i; + if (m_inQueue.GetWord16(i) != 2 || i != 0) + BERDecodeError(); + } +} + +size_t BERGeneralDecoder::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + if (m_definiteLength && transferBytes > m_length) + transferBytes = m_length; + size_t blockedBytes = m_inQueue.TransferTo2(target, transferBytes, channel, blocking); + ReduceLength(transferBytes); + return blockedBytes; +} + +size_t BERGeneralDecoder::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + if (m_definiteLength) + end = STDMIN(m_length, end); + return m_inQueue.CopyRangeTo2(target, begin, end, channel, blocking); +} + +lword BERGeneralDecoder::ReduceLength(lword delta) +{ + if (m_definiteLength) + { + if (m_length < delta) + BERDecodeError(); + m_length -= delta; + } + return delta; +} + +DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation &outQueue) + : m_outQueue(outQueue), m_asnTag(DefaultTag), m_finished(false) +{ +} + +DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag) + : m_outQueue(outQueue), m_asnTag(asnTag), m_finished(false) +{ +} + +DERGeneralEncoder::DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag) + : m_outQueue(outQueue), m_asnTag(asnTag), m_finished(false) +{ +} + +DERGeneralEncoder::~DERGeneralEncoder() +{ + try // avoid throwing in constructor + { + if (!m_finished) + MessageEnd(); + } + catch (const Exception&) + { + CRYPTOPP_ASSERT(0); + } +} + +void DERGeneralEncoder::MessageEnd() +{ + m_finished = true; + lword length = CurrentSize(); + m_outQueue.Put(m_asnTag); + DERLengthEncode(m_outQueue, length); + TransferTo(m_outQueue); +} + +// ************************************************************* + +void X509PublicKey::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder subjectPublicKeyInfo(bt); + BERSequenceDecoder algorithm(subjectPublicKeyInfo); + GetAlgorithmID().BERDecodeAndCheck(algorithm); + bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); + subjectPublicKey.CheckByte(0); // unused bits + BERDecodePublicKey(subjectPublicKey, parametersPresent, (size_t)subjectPublicKey.RemainingLength()); + subjectPublicKey.MessageEnd(); + subjectPublicKeyInfo.MessageEnd(); +} + +void X509PublicKey::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder subjectPublicKeyInfo(bt); + + DERSequenceEncoder algorithm(subjectPublicKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + DEREncodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING); + subjectPublicKey.Put(0); // unused bits + DEREncodePublicKey(subjectPublicKey); + subjectPublicKey.MessageEnd(); + + subjectPublicKeyInfo.MessageEnd(); +} + +void PKCS8PrivateKey::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKeyInfo(bt); + word32 version; + BERDecodeUnsigned(privateKeyInfo, version, INTEGER, 0, 0); // check version + + BERSequenceDecoder algorithm(privateKeyInfo); + GetAlgorithmID().BERDecodeAndCheck(algorithm); + bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING); + BERDecodePrivateKey(octetString, parametersPresent, (size_t)privateKeyInfo.RemainingLength()); + octetString.MessageEnd(); + + if (!privateKeyInfo.EndReached()) + BERDecodeOptionalAttributes(privateKeyInfo); + privateKeyInfo.MessageEnd(); +} + +void PKCS8PrivateKey::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKeyInfo(bt); + DEREncodeUnsigned(privateKeyInfo, 0); // version + + DERSequenceEncoder algorithm(privateKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + DEREncodeAlgorithmParameters(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING); + DEREncodePrivateKey(octetString); + octetString.MessageEnd(); + + DEREncodeOptionalAttributes(privateKeyInfo); + privateKeyInfo.MessageEnd(); +} + +void PKCS8PrivateKey::BERDecodeOptionalAttributes(BufferedTransformation &bt) +{ + DERReencode(bt, m_optionalAttributes); +} + +void PKCS8PrivateKey::DEREncodeOptionalAttributes(BufferedTransformation &bt) const +{ + m_optionalAttributes.CopyTo(bt); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/asn.h b/extension/third_party/cryptopp/asn.h new file mode 100644 index 00000000..ab713ad2 --- /dev/null +++ b/extension/third_party/cryptopp/asn.h @@ -0,0 +1,965 @@ +// asn.h - originally written and placed in the public domain by Wei Dai + +/// \file asn.h +/// \brief Classes and functions for working with ANS.1 objects + +#ifndef CRYPTOPP_ASN_H +#define CRYPTOPP_ASN_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "queue.h" +#include "misc.h" + +#include + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ASN.1 types +/// \note These tags are not complete +enum ASNTag +{ + /// \brief ASN.1 Boolean + BOOLEAN = 0x01, + /// \brief ASN.1 Integer + INTEGER = 0x02, + /// \brief ASN.1 Bit string + BIT_STRING = 0x03, + /// \brief ASN.1 Octet string + OCTET_STRING = 0x04, + /// \brief ASN.1 Null + TAG_NULL = 0x05, + /// \brief ASN.1 Object identifier + OBJECT_IDENTIFIER = 0x06, + /// \brief ASN.1 Object descriptor + OBJECT_DESCRIPTOR = 0x07, + /// \brief ASN.1 External reference + EXTERNAL = 0x08, + /// \brief ASN.1 Real integer + REAL = 0x09, + /// \brief ASN.1 Enumerated value + ENUMERATED = 0x0a, + /// \brief ASN.1 UTF-8 string + UTF8_STRING = 0x0c, + /// \brief ASN.1 Sequence + SEQUENCE = 0x10, + /// \brief ASN.1 Set + SET = 0x11, + /// \brief ASN.1 Numeric string + NUMERIC_STRING = 0x12, + /// \brief ASN.1 Printable string + PRINTABLE_STRING = 0x13, + /// \brief ASN.1 T61 string + T61_STRING = 0x14, + /// \brief ASN.1 Videotext string + VIDEOTEXT_STRING = 0x15, + /// \brief ASN.1 IA5 string + IA5_STRING = 0x16, + /// \brief ASN.1 UTC time + UTC_TIME = 0x17, + /// \brief ASN.1 Generalized time + GENERALIZED_TIME = 0x18, + /// \brief ASN.1 Graphic string + GRAPHIC_STRING = 0x19, + /// \brief ASN.1 Visible string + VISIBLE_STRING = 0x1a, + /// \brief ASN.1 General string + GENERAL_STRING = 0x1b, + /// \brief ASN.1 Universal string + UNIVERSAL_STRING = 0x1c, + /// \brief ASN.1 BMP string + BMP_STRING = 0x1e +}; + +/// \brief ASN.1 flags +/// \note These flags are not complete +enum ASNIdFlag +{ + /// \brief ASN.1 Universal class + UNIVERSAL = 0x00, + // DATA = 0x01, + // HEADER = 0x02, + /// \brief ASN.1 Primitive flag + PRIMITIVE = 0x00, + /// \brief ASN.1 Constructed flag + CONSTRUCTED = 0x20, + /// \brief ASN.1 Application class + APPLICATION = 0x40, + /// \brief ASN.1 Context specific class + CONTEXT_SPECIFIC = 0x80, + /// \brief ASN.1 Private class + PRIVATE = 0xc0 +}; + +/// \brief Raises a BERDecodeErr +inline void BERDecodeError() {throw BERDecodeErr();} + +/// \brief Exception thrown when an unknown object identifier is encountered +class CRYPTOPP_DLL UnknownOID : public BERDecodeErr +{ +public: + /// \brief Construct an UnknownOID + UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {} + /// \brief Construct an UnknownOID + /// \param err error message to use for the execption + UnknownOID(const char *err) : BERDecodeErr(err) {} +}; + +/// \brief DER encode a length +/// \param bt BufferedTransformation object for writing +/// \param length the size to encode +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DERLengthEncode(BufferedTransformation &bt, lword length); + +/// \brief BER decode a length +/// \param bt BufferedTransformation object for reading +/// \param length the decoded size +/// \return true if the value was decoded +/// \throw BERDecodeError if the value fails to decode or is too large for size_t +/// \details BERLengthDecode() returns false if the encoding is indefinite length. +CRYPTOPP_DLL bool CRYPTOPP_API BERLengthDecode(BufferedTransformation &bt, size_t &length); + +/// \brief DER encode NULL +/// \param bt BufferedTransformation object for writing +CRYPTOPP_DLL void CRYPTOPP_API DEREncodeNull(BufferedTransformation &bt); + +/// \brief BER decode NULL +/// \param bt BufferedTransformation object for reading +CRYPTOPP_DLL void CRYPTOPP_API BERDecodeNull(BufferedTransformation &bt); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the string to encode +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string, in bytes +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const byte* str, size_t strLen, byte asnTag); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 6.0 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag); + +/// \brief BER decode text string +/// \param bt BufferedTransformation object for reading +/// \param str the string to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, SecByteBlock &str, byte asnTag); + +/// \brief BER decode text string +/// \param bt BufferedTransformation object for reading +/// \param str the string to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 6.0 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag); + +/// \brief DER encode date +/// \param bt BufferedTransformation object for writing +/// \param str the date to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeDate(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag); + +/// \brief BER decode date +/// \param bt BufferedTransformation object for reading +/// \param str the date to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeDate(BufferedTransformation &bt, SecByteBlock &str, byte asnTag); + +/// \brief DER encode bit string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \param unusedBits the number of unused bits +/// \return the number of octets used for the encoding +/// \details The caller is responsible for shifting octets if unusedBits is +/// not 0. For example, to DER encode a web server X.509 key usage, the 101b +/// bit mask is often used (digitalSignature and keyEncipherment). In this +/// case str is one octet with a value=0xa0 and unusedBits=5. The +/// value 0xa0 is 101b << 5. +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0); + +/// \brief DER decode bit string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \param unusedBits the number of unused bits +/// \details The caller is responsible for shifting octets if unusedBits is +/// not 0. For example, to DER encode a web server X.509 key usage, the 101b +/// bit mask is often used (digitalSignature and keyEncipherment). In this +/// case str is one octet with a value=0xa0 and unusedBits=5. The +/// value 0xa0 is 101b << 5. +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits); + +/// \brief BER decode and DER re-encode +/// \param bt BufferedTransformation object for writing +/// \param dest BufferedTransformation object +CRYPTOPP_DLL void CRYPTOPP_API DERReencode(BufferedTransformation &bt, BufferedTransformation &dest); + +/// \brief BER decode size +/// \param bt BufferedTransformation object for reading +/// \return the length of the ASN.1 value, in bytes +/// \details BERDecodePeekLength() determines the length of a value without +/// consuming octets in the stream. The stream must use definite length encoding. +/// If indefinite length encoding is used or an error occurs, then 0 is returned. +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodePeekLength(const BufferedTransformation &bt); + +/// \brief Object Identifier +class CRYPTOPP_DLL OID +{ +public: + virtual ~OID() {} + + /// \brief Construct an OID + OID() {} + + /// \brief Construct an OID + /// \param v value to initialize the OID + OID(word32 v) : m_values(1, v) {} + + /// \brief Construct an OID + /// \param bt BufferedTransformation object + OID(BufferedTransformation &bt) { + BERDecode(bt); + } + + /// \brief Append a value to an OID + /// \param rhs the value to append + inline OID & operator+=(word32 rhs) { + m_values.push_back(rhs); return *this; + } + + /// \brief DER encode this OID + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + /// \throw BERDecodeErr() if decoded value doesn't match an expected OID + /// \details BERDecodeAndCheck() can be used to parse an OID and verify it matches an expected. + ///
+	///   BERSequenceDecoder key(bt);
+	///   ...
+	///   BERSequenceDecoder algorithm(key);
+	///   GetAlgorithmID().BERDecodeAndCheck(algorithm);
+	/// 
+ void BERDecodeAndCheck(BufferedTransformation &bt) const; + + /// \brief Determine if OID is empty + /// \return true if OID has 0 elements, false otherwise + /// \since Crypto++ 8.0 + bool Empty() const { + return m_values.empty(); + } + + /// \brief Retrieve OID value array + /// \return OID value vector + /// \since Crypto++ 8.0 + const std::vector& GetValues() const { + return m_values; + } + + /// \brief Print an OID + /// \param out ostream object + /// \return ostream reference + /// \details Print() writes the OID in a customary format, like + /// 1.2.840.113549.1.1.11. The caller is reposnsible to convert the + /// OID to a friendly name, like sha256WithRSAEncryption. + /// \since Crypto++ 8.3 + std::ostream& Print(std::ostream& out) const; + +protected: + friend bool operator==(const OID &lhs, const OID &rhs); + friend bool operator!=(const OID &lhs, const OID &rhs); + friend bool operator<(const OID &lhs, const OID &rhs); + friend bool operator<=(const OID &lhs, const OID &rhs); + friend bool operator>=(const OID &lhs, const OID &rhs); + + std::vector m_values; + +private: + static void EncodeValue(BufferedTransformation &bt, word32 v); + static size_t DecodeValue(BufferedTransformation &bt, word32 &v); +}; + +/// \brief ASN.1 encoded object filter +class EncodedObjectFilter : public Filter +{ +public: + enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8}; + enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state; + + virtual ~EncodedObjectFilter() {} + + /// \brief Construct an EncodedObjectFilter + /// \param attachment a BufferedTrasformation to attach to this object + /// \param nObjects the number of objects + /// \param flags bitwise OR of EncodedObjectFilter::Flag + EncodedObjectFilter(BufferedTransformation *attachment = NULLPTR, unsigned int nObjects = 1, word32 flags = 0); + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + void Put(const byte *inString, size_t length); + + unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;} + unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];} + +private: + BufferedTransformation & CurrentTarget(); + + ByteQueue m_queue; + std::vector m_positions; + lword m_lengthRemaining; + word32 m_nObjects, m_nCurrentObject, m_level, m_flags; + byte m_id; +}; + +/// \brief BER General Decoder +class CRYPTOPP_DLL BERGeneralDecoder : public Store +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | CONSTRUCTED}; + + virtual ~BERGeneralDecoder(); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERGeneralDecoder uses DefaultTag + explicit BERGeneralDecoder(BufferedTransformation &inQueue); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag); + + /// \brief Determine length encoding + /// \return true if the ASN.1 object is definite length encoded, false otherwise + bool IsDefiniteLength() const { + return m_definiteLength; + } + + /// \brief Determine remaining length + /// \return number of octets that remain to be consumed + /// \details RemainingLength() is only valid if IsDefiniteLength() + /// returns true. + lword RemainingLength() const { + CRYPTOPP_ASSERT(m_definiteLength); + return IsDefiniteLength() ? m_length : 0; + } + + /// \brief Determine end of stream + /// \return true if all octets have been consumed, false otherwise + bool EndReached() const; + + /// \brief Determine next octet + /// \return next octet in the stream + /// \details PeekByte does not consume the octet. + /// \throw BERDecodeError if there are no octets remaining + byte PeekByte() const; + + /// \brief Determine next octet + /// \details CheckByte reads the next byte in the stream and verifies + /// the octet matches b. + /// \throw BERDecodeError if the next octet is not b + void CheckByte(byte b); + + /// \brief Transfer bytes to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param transferBytes the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when + /// processing input + /// \return the number of bytes that remain in the transfer block + /// (i.e., bytes not transferred) + /// \details TransferTo2() removes bytes and moves + /// them to the destination. Transfer begins at the index position + /// in the current stream, and not from an absolute position in the + /// stream. + /// \details transferBytes is an \a IN and \a OUT parameter. When + /// the call is made, transferBytes is the requested size of the + /// transfer. When the call returns, transferBytes is the number + /// of bytes that were transferred. + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + + /// \brief Copy bytes to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param begin the 0-based index of the first byte to copy in + /// the stream + /// \param end the 0-based index of the last byte to copy in + /// the stream + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when + /// processing input + /// \return the number of bytes that remain in the copy block + /// (i.e., bytes not copied) + /// \details CopyRangeTo2 copies bytes to the + /// destination. The bytes are not removed from this object. Copying + /// begins at the index position in the current stream, and not from + /// an absolute position in the stream. + /// \details begin is an \a IN and \a OUT parameter. When the call is + /// made, begin is the starting position of the copy. When the call + /// returns, begin is the position of the first byte that was \a not + /// copied (which may be different than end). begin can be used for + /// subsequent calls to CopyRangeTo2(). + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + /// \brief Signals the end of messages to the object + /// \details Call this to denote end of sequence + void MessageEnd(); + +protected: + BufferedTransformation &m_inQueue; + lword m_length; + bool m_finished, m_definiteLength; + +private: + void Init(byte asnTag); + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} + lword ReduceLength(lword delta); +}; + +/// \brief DER General Encoder +class CRYPTOPP_DLL DERGeneralEncoder : public ByteQueue +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | CONSTRUCTED}; + + virtual ~DERGeneralEncoder(); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERGeneralEncoder uses DefaultTag + explicit DERGeneralEncoder(BufferedTransformation &outQueue); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag); + + /// \brief Signals the end of messages to the object + /// \details Call this to denote end of sequence + void MessageEnd(); + +private: + BufferedTransformation &m_outQueue; + byte m_asnTag; + bool m_finished; +}; + +/// \brief BER Sequence Decoder +class CRYPTOPP_DLL BERSequenceDecoder : public BERGeneralDecoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | CONSTRUCTED}; + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSequenceDecoder uses DefaultTag + explicit BERSequenceDecoder(BufferedTransformation &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSequenceDecoder uses DefaultTag + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Sequence Encoder +class CRYPTOPP_DLL DERSequenceEncoder : public DERGeneralEncoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | CONSTRUCTED}; + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSequenceEncoder uses DefaultTag + explicit DERSequenceEncoder(BufferedTransformation &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSequenceEncoder uses DefaultTag + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief BER Set Decoder +class CRYPTOPP_DLL BERSetDecoder : public BERGeneralDecoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SET | CONSTRUCTED}; + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSetDecoder uses DefaultTag + explicit BERSetDecoder(BufferedTransformation &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSetDecoder uses DefaultTag + explicit BERSetDecoder(BERSetDecoder &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Set Encoder +class CRYPTOPP_DLL DERSetEncoder : public DERGeneralEncoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SET | CONSTRUCTED}; + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSetEncoder uses DefaultTag + explicit DERSetEncoder(BufferedTransformation &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSetEncoder uses DefaultTag + explicit DERSetEncoder(DERSetEncoder &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief Optional data encoder and decoder +/// \tparam T class or type +template +class ASNOptional : public member_ptr +{ +public: + /// \brief BER decode optional data + /// \param seqDecoder sequence with the optional ASN.1 data + /// \param tag ASN.1 tag to match as optional data + /// \param mask the mask to apply when matching the tag + /// \sa ASNTag and ASNIdFlag + void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED) + { + byte b; + if (seqDecoder.Peek(b) && (b & mask) == tag) + reset(new T(seqDecoder)); + } + + /// \brief DER encode optional data + /// \param out BufferedTransformation object + void DEREncode(BufferedTransformation &out) + { + if (this->get() != NULLPTR) + this->get()->DEREncode(out); + } +}; + +/// \brief Encode and decode ASN.1 objects with additional information +/// \tparam BASE base class or type +/// \details Encodes and decodes public keys, private keys and group +/// parameters with OID identifying the algorithm or scheme. +template +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1CryptoMaterial : public ASN1Object, public BASE +{ +public: + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo and privateKeyInfo parts. + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + void Load(BufferedTransformation &bt) + {BERDecode(bt);} +}; + +/// \brief Encodes and decodes subjectPublicKeyInfo +class CRYPTOPP_DLL X509PublicKey : public ASN1CryptoMaterial +{ +public: + virtual ~X509PublicKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + virtual OID GetAlgorithmID() const =0; + + /// \brief Decode algorithm parameters + /// \param bt BufferedTransformation object + /// \sa BERDecodePublicKey, RFC + /// 2459, section 7.3.1 + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + + /// \brief Encode algorithm parameters + /// \param bt BufferedTransformation object + /// \sa DEREncodePublicKey, RFC + /// 2459, section 7.3.1 + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} + + /// \brief Decode subjectPublicKey part of subjectPublicKeyInfo + /// \param bt BufferedTransformation object + /// \param parametersPresent flag indicating if algorithm parameters are present + /// \param size number of octets to read for the parameters, in bytes + /// \details BERDecodePublicKey() the decodes subjectPublicKey part of + /// subjectPublicKeyInfo, without the BIT STRING header. + /// \details When parametersPresent = true then BERDecodePublicKey() calls + /// BERDecodeAlgorithmParameters() to parse algorithm parameters. + /// \sa BERDecodeAlgorithmParameters + virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + + /// \brief Encode subjectPublicKey part of subjectPublicKeyInfo + /// \param bt BufferedTransformation object + /// \details DEREncodePublicKey() encodes the subjectPublicKey part of + /// subjectPublicKeyInfo, without the BIT STRING header. + /// \sa DEREncodeAlgorithmParameters + virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0; +}; + +/// \brief Encodes and Decodes privateKeyInfo +class CRYPTOPP_DLL PKCS8PrivateKey : public ASN1CryptoMaterial +{ +public: + virtual ~PKCS8PrivateKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + virtual OID GetAlgorithmID() const =0; + + /// \brief Decode optional parameters + /// \param bt BufferedTransformation object + /// \sa BERDecodePrivateKey, RFC + /// 2459, section 7.3.1 + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + + /// \brief Encode optional parameters + /// \param bt BufferedTransformation object + /// \sa DEREncodePrivateKey, RFC + /// 2459, section 7.3.1 + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} + + /// \brief Decode privateKey part of privateKeyInfo + /// \param bt BufferedTransformation object + /// \param parametersPresent flag indicating if algorithm parameters are present + /// \param size number of octets to read for the parameters, in bytes + /// \details BERDecodePrivateKey() the decodes privateKey part of privateKeyInfo, + /// without the OCTET STRING header. + /// \details When parametersPresent = true then BERDecodePrivateKey() calls + /// BERDecodeAlgorithmParameters() to parse algorithm parameters. + /// \sa BERDecodeAlgorithmParameters + virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + + /// \brief Encode privateKey part of privateKeyInfo + /// \param bt BufferedTransformation object + /// \details DEREncodePrivateKey() encodes the privateKey part of privateKeyInfo, + /// without the OCTET STRING header. + /// \sa DEREncodeAlgorithmParameters + virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0; + + /// \brief Decode optional attributes + /// \param bt BufferedTransformation object + /// \details BERDecodeOptionalAttributes() decodes optional attributes including + /// context-specific tag. + /// \sa BERDecodeAlgorithmParameters, DEREncodeOptionalAttributes + /// \note default implementation stores attributes to be output using + /// DEREncodeOptionalAttributes + virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt); + + /// \brief Encode optional attributes + /// \param bt BufferedTransformation object + /// \details DEREncodeOptionalAttributes() encodes optional attributes including + /// context-specific tag. + /// \sa BERDecodeAlgorithmParameters + virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const; + +protected: + ByteQueue m_optionalAttributes; +}; + +// ******************************************************** + +/// \brief DER Encode unsigned value +/// \tparam T class or type +/// \param out BufferedTransformation object +/// \param w unsigned value to encode +/// \param asnTag the ASN.1 identifier +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +size_t DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER) +{ + byte buf[sizeof(w)+1]; + unsigned int bc; + if (asnTag == BOOLEAN) + { + buf[sizeof(w)] = w ? 0xff : 0; + bc = 1; + } + else + { + buf[0] = 0; + for (unsigned int i=0; i> (sizeof(w)-1-i)*8); + bc = sizeof(w); + while (bc > 1 && buf[sizeof(w)+1-bc] == 0) + --bc; + if (buf[sizeof(w)+1-bc] & 0x80) + ++bc; + } + out.Put(asnTag); + size_t lengthBytes = DERLengthEncode(out, bc); + out.Put(buf+sizeof(w)+1-bc, bc); + return 1+lengthBytes+bc; +} + +/// \brief BER Decode unsigned value +/// \tparam T fundamental C++ type +/// \param in BufferedTransformation object +/// \param w the decoded value +/// \param asnTag the ASN.1 identifier +/// \param minValue the minimum expected value +/// \param maxValue the maximum expected value +/// \throw BERDecodeErr() if the value cannot be parsed or the decoded value is not within range. +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER, + T minValue = 0, T maxValue = T(0xffffffff)) +{ + byte b; + if (!in.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + bool definite = BERLengthDecode(in, bc); + if (!definite) + BERDecodeError(); + if (bc > in.MaxRetrievable()) // Issue 346 + BERDecodeError(); + if (asnTag == BOOLEAN && bc != 1) // X.690, 8.2.1 + BERDecodeError(); + if ((asnTag == INTEGER || asnTag == ENUMERATED) && bc == 0) // X.690, 8.3.1 and 8.4 + BERDecodeError(); + + SecByteBlock buf(bc); + + if (bc != in.Get(buf, bc)) + BERDecodeError(); + + // This consumes leading 0 octets. According to X.690, 8.3.2, it could be non-conforming behavior. + // X.690, 8.3.2 says "the bits of the first octet and bit 8 of the second octet ... (a) shall + // not all be ones and (b) shall not all be zeros ... These rules ensure that an integer value + // is always encoded in the smallest possible number of octet". + // We invented AER (Alternate Encoding Rules), which is more relaxed than BER, CER, and DER. + const byte *ptr = buf; + while (bc > sizeof(w) && *ptr == 0) + { + bc--; + ptr++; + } + if (bc > sizeof(w)) + BERDecodeError(); + + w = 0; + for (unsigned int i=0; i maxValue) + BERDecodeError(); +} + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compare two OIDs for equality +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the OIDs are equal, false otherwise +inline bool operator==(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for inequality +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the OIDs are not equal, false otherwise +inline bool operator!=(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is less than the second OID, false otherwise +/// \details operator<() calls std::lexicographical_compare() on each element in the array of values. +inline bool operator<(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is less than or equal to the second OID, false otherwise +/// \details operator<=() is implemented in terms of operator==() and operator<(). +/// \since Crypto++ 8.3 +inline bool operator<=(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is greater than or equal to the second OID, false otherwise +/// \details operator>=() is implemented in terms of operator<(). +/// \since Crypto++ 8.3 +inline bool operator>=(const OID &lhs, const OID &rhs); +/// \brief Append a value to an OID +/// \param lhs the OID +/// \param rhs the value to append +inline OID operator+(const OID &lhs, unsigned long rhs); +/// \brief Print a OID value +/// \param out the output stream +/// \param oid the OID +inline std::ostream& operator<<(std::ostream& out, const OID &oid) + { return oid.Print(out); } +#else +inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values == rhs.m_values;} +inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values != rhs.m_values;} +inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());} +inline bool operator<=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return ! (lhs= blockSize) + { + memcpy(data+num, input, blockSize-num); + AuthenticateBlocks(data, blockSize); + input += (blockSize-num); + len -= (blockSize-num); + num = 0; + // drop through and do the rest + } + else + { + memcpy(data+num, input, len); + num += (unsigned int)len; + return; + } + } + + // now process the input data in blocks of blockSize bytes and save the leftovers to m_data + if (len >= blockSize) + { + size_t leftOver = AuthenticateBlocks(input, len); + input += (len - leftOver); + len = leftOver; + } + + if (data && len) + memcpy(data, input, len); + num = (unsigned int)len; +} + +void AuthenticatedSymmetricCipherBase::SetKey(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + m_bufferedDataLength = 0; + m_state = State_Start; + + this->SetKeyWithoutResync(userKey, keylength, params); + m_state = State_KeySet; + + size_t length; + const byte *iv = GetIVAndThrowIfInvalid(params, length); + if (iv) + Resynchronize(iv, (int)length); +} + +void AuthenticatedSymmetricCipherBase::Resynchronize(const byte *iv, int length) +{ + if (m_state < State_KeySet) + throw BadState(AlgorithmName(), "Resynchronize", "key is set"); + + m_bufferedDataLength = 0; + m_totalHeaderLength = m_totalMessageLength = m_totalFooterLength = 0; + m_state = State_KeySet; + + Resync(iv, this->ThrowIfInvalidIVLength(length)); + m_state = State_IVSet; +} + +void AuthenticatedSymmetricCipherBase::Update(const byte *input, size_t length) +{ + // Part of original authenc.cpp code. Don't remove it. + if (length == 0) {return;} + + switch (m_state) + { + case State_Start: + case State_KeySet: + throw BadState(AlgorithmName(), "Update", "setting key and IV"); + case State_IVSet: + AuthenticateData(input, length); + m_totalHeaderLength += length; + break; + case State_AuthUntransformed: + case State_AuthTransformed: + AuthenticateLastConfidentialBlock(); + m_bufferedDataLength = 0; + m_state = State_AuthFooter; + // fall through + case State_AuthFooter: + AuthenticateData(input, length); + m_totalFooterLength += length; + break; + default: + CRYPTOPP_ASSERT(false); + } +} + +void AuthenticatedSymmetricCipherBase::ProcessData(byte *outString, const byte *inString, size_t length) +{ + if (m_state >= State_IVSet && length > MaxMessageLength()-m_totalMessageLength) + throw InvalidArgument(AlgorithmName() + ": message length exceeds maximum"); + m_totalMessageLength += length; + +reswitch: + switch (m_state) + { + case State_Start: + case State_KeySet: + throw BadState(AlgorithmName(), "ProcessData", "setting key and IV"); + case State_AuthFooter: + throw BadState(AlgorithmName(), "ProcessData was called after footer input has started"); + case State_IVSet: + AuthenticateLastHeaderBlock(); + m_bufferedDataLength = 0; + m_state = AuthenticationIsOnPlaintext()==IsForwardTransformation() ? State_AuthUntransformed : State_AuthTransformed; + goto reswitch; + case State_AuthUntransformed: + AuthenticateData(inString, length); + AccessSymmetricCipher().ProcessData(outString, inString, length); + break; + case State_AuthTransformed: + AccessSymmetricCipher().ProcessData(outString, inString, length); + AuthenticateData(outString, length); + break; + default: + CRYPTOPP_ASSERT(false); + } +} + +void AuthenticatedSymmetricCipherBase::TruncatedFinal(byte *mac, size_t macSize) +{ + // https://github.com/weidai11/cryptopp/issues/954 + this->ThrowIfInvalidTruncatedSize(macSize); + + if (m_totalHeaderLength > MaxHeaderLength()) + throw InvalidArgument(AlgorithmName() + ": header length of " + IntToString(m_totalHeaderLength) + " exceeds the maximum of " + IntToString(MaxHeaderLength())); + + if (m_totalFooterLength > MaxFooterLength()) + { + if (MaxFooterLength() == 0) + throw InvalidArgument(AlgorithmName() + ": additional authenticated data (AAD) cannot be input after data to be encrypted or decrypted"); + else + throw InvalidArgument(AlgorithmName() + ": footer length of " + IntToString(m_totalFooterLength) + " exceeds the maximum of " + IntToString(MaxFooterLength())); + } + + switch (m_state) + { + case State_Start: + case State_KeySet: + throw BadState(AlgorithmName(), "TruncatedFinal", "setting key and IV"); + + case State_IVSet: + AuthenticateLastHeaderBlock(); + m_bufferedDataLength = 0; + // fall through + + case State_AuthUntransformed: + case State_AuthTransformed: + AuthenticateLastConfidentialBlock(); + m_bufferedDataLength = 0; + // fall through + + case State_AuthFooter: + AuthenticateLastFooterBlock(mac, macSize); + m_bufferedDataLength = 0; + break; + + default: + CRYPTOPP_ASSERT(false); + } + + m_state = State_KeySet; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/authenc.h b/extension/third_party/cryptopp/authenc.h new file mode 100644 index 00000000..980de0b4 --- /dev/null +++ b/extension/third_party/cryptopp/authenc.h @@ -0,0 +1,87 @@ +// authenc.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for authenticated encryption modes of operation +/// \details Authenticated encryption (AE) schemes combine confidentiality and authenticity +/// into a single mode of operation They gained traction in the early 2000's because manually +/// combining them was error prone for the typical developer. Around that time, the desire to +/// authenticate but not ecrypt additional data (AAD) was also identified. When both features +/// are available from a scheme, the system is referred to as an AEAD scheme. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the +/// motivation for the API, like calling AAD a "header", can be found in Bellare, +/// Rogaway and Wagner's The EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_AUTHENC_H +#define CRYPTOPP_AUTHENC_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipherBase() serves as a base implementation for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the +/// motivation for the API, like calling AAD a "header", can be found in Bellare, +/// Rogaway and Wagner's The EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipherBase : public AuthenticatedSymmetricCipher +{ +public: + AuthenticatedSymmetricCipherBase() : m_totalHeaderLength(0), m_totalMessageLength(0), + m_totalFooterLength(0), m_bufferedDataLength(0), m_state(State_Start) {} + + // StreamTransformation interface + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + + void SetKey(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Restart() {if (m_state > State_KeySet) m_state = State_KeySet;} + void Resynchronize(const byte *iv, int length=-1); + void Update(const byte *input, size_t length); + void ProcessData(byte *outString, const byte *inString, size_t length); + void TruncatedFinal(byte *mac, size_t macSize); + +protected: + void UncheckedSetKey(const byte * key, unsigned int length,const CryptoPP::NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(key), CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); CRYPTOPP_ASSERT(false);} + + void AuthenticateData(const byte *data, size_t len); + const SymmetricCipher & GetSymmetricCipher() const + {return const_cast(this)->AccessSymmetricCipher();} + + virtual SymmetricCipher & AccessSymmetricCipher() =0; + virtual bool AuthenticationIsOnPlaintext() const =0; + virtual unsigned int AuthenticationBlockSize() const =0; + virtual void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) =0; + virtual void Resync(const byte *iv, size_t len) =0; + virtual size_t AuthenticateBlocks(const byte *data, size_t len) =0; + virtual void AuthenticateLastHeaderBlock() =0; + virtual void AuthenticateLastConfidentialBlock() {} + virtual void AuthenticateLastFooterBlock(byte *mac, size_t macSize) =0; + + // State_AuthUntransformed: authentication is applied to plain text (Authenticate-then-Encrypt) + // State_AuthTransformed: authentication is applied to cipher text (Encrypt-then-Authenticate) + enum State {State_Start, State_KeySet, State_IVSet, State_AuthUntransformed, State_AuthTransformed, State_AuthFooter}; + + AlignedSecByteBlock m_buffer; + lword m_totalHeaderLength, m_totalMessageLength, m_totalFooterLength; + unsigned int m_bufferedDataLength; + State m_state; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/base32.cpp b/extension/third_party/cryptopp/base32.cpp new file mode 100644 index 00000000..2f0c4c7f --- /dev/null +++ b/extension/third_party/cryptopp/base32.cpp @@ -0,0 +1,97 @@ +// base32.cpp - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. + +#include "pch.h" +#include "base32.h" + +NAMESPACE_BEGIN(CryptoPP) +ANONYMOUS_NAMESPACE_BEGIN + +const byte s_stdUpper[] = "ABCDEFGHIJKMNPQRSTUVWXYZ23456789"; +const byte s_stdLower[] = "abcdefghijkmnpqrstuvwxyz23456789"; +const byte s_hexUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; +const byte s_hexLower[] = "0123456789abcdefghijklmnopqrstuv"; + +const int s_array[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, -1, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, -1, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +const int s_hexArray[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +ANONYMOUS_NAMESPACE_END + +void Base32Encoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool uppercase = parameters.GetValueWithDefault(Name::Uppercase(), true); + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_stdUpper[0] : &s_stdLower[0], false)(Name::Log2Base(), 5, true))); +} + +void Base32Decoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDefaultDecodingLookupArray(), false)(Name::Log2Base(), 5, true))); +} + +// Unrolled initialization, http://github.com/weidai11/cryptopp/issues/376 +const int *Base32Decoder::GetDefaultDecodingLookupArray() +{ + return s_array; +} + +void Base32HexEncoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool uppercase = parameters.GetValueWithDefault(Name::Uppercase(), true); + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_hexUpper[0] : &s_hexLower[0], false)(Name::Log2Base(), 5, true))); +} + +void Base32HexDecoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDefaultDecodingLookupArray(), false)(Name::Log2Base(), 5, true))); +} + +// Unrolled initialization, http://github.com/weidai11/cryptopp/issues/376 +const int *Base32HexDecoder::GetDefaultDecodingLookupArray() +{ + return s_hexArray; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/base32.h b/extension/third_party/cryptopp/base32.h new file mode 100644 index 00000000..4eeae43c --- /dev/null +++ b/extension/third_party/cryptopp/base32.h @@ -0,0 +1,158 @@ +// base32.h - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. + +/// \file base32.h +/// \brief Classes for Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + +#ifndef CRYPTOPP_BASE32_H +#define CRYPTOPP_BASE32_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base32 encodes data using DUDE encoding +/// \details Converts data to base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32Encoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32Encoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     Base32Encoder encoder;
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using DUDE encoding +/// \details Converts data from base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying a Base32Decoder after construction. + Base32Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     Base32Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 32, true /*insensitive*/);
+	///
+	///     Base32Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +/// \brief Base32 encodes data using extended hex +/// \details Converts data to base32 using extended hex alphabet. The alphabet is different than Base32Encoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32HexEncoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32HexEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using extended hex +/// \details Converts data from base32 using extended hex alphabet. The alphabet is different than Base32Decoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/base64.cpp b/extension/third_party/cryptopp/base64.cpp new file mode 100644 index 00000000..9c899cbc --- /dev/null +++ b/extension/third_party/cryptopp/base64.cpp @@ -0,0 +1,111 @@ +// base64.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" +#include "base64.h" + +NAMESPACE_BEGIN(CryptoPP) +ANONYMOUS_NAMESPACE_BEGIN + +const byte s_stdVec[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const byte s_urlVec[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +const byte s_padding = '='; +const int s_stdArray[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; +const int s_urlArray[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +ANONYMOUS_NAMESPACE_END + +void Base64Encoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool insertLineBreaks = parameters.GetValueWithDefault(Name::InsertLineBreaks(), true); + int maxLineLength = parameters.GetIntValueWithDefault(Name::MaxLineLength(), 72); + + const char *lineBreak = insertLineBreaks ? "\n" : ""; + + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), &s_stdVec[0], false) + (Name::PaddingByte(), s_padding) + (Name::GroupSize(), insertLineBreaks ? maxLineLength : 0) + (Name::Separator(), ConstByteArrayParameter(lineBreak)) + (Name::Terminator(), ConstByteArrayParameter(lineBreak)) + (Name::Log2Base(), 6, true))); +} + +void Base64URLEncoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool insertLineBreaks = parameters.GetValueWithDefault(Name::InsertLineBreaks(), true); + int maxLineLength = parameters.GetIntValueWithDefault(Name::MaxLineLength(), 72); + + const char *lineBreak = insertLineBreaks ? "\n" : ""; + + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), &s_urlVec[0], false) + (Name::PaddingByte(), s_padding) + (Name::GroupSize(), insertLineBreaks ? maxLineLength : 0) + (Name::Separator(), ConstByteArrayParameter(lineBreak)) + (Name::Terminator(), ConstByteArrayParameter(lineBreak)) + (Name::Log2Base(), 6, true))); +} + +void Base64Decoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDecodingLookupArray(), false)(Name::Log2Base(), 6, true))); +} + +const int *Base64Decoder::GetDecodingLookupArray() +{ + return s_stdArray; +} + +void Base64URLDecoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDecodingLookupArray(), false)(Name::Log2Base(), 6, true))); +} + +// Unrolled initialization, http://github.com/weidai11/cryptopp/issues/376 +const int *Base64URLDecoder::GetDecodingLookupArray() +{ + return s_urlArray; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/base64.h b/extension/third_party/cryptopp/base64.h new file mode 100644 index 00000000..5defc374 --- /dev/null +++ b/extension/third_party/cryptopp/base64.h @@ -0,0 +1,158 @@ +// base64.h - originally written and placed in the public domain by Wei Dai + +/// \file base64.h +/// \brief Classes for the Base64Encoder, Base64Decoder, Base64URLEncoder and Base64URLDecoder + +#ifndef CRYPTOPP_BASE64_H +#define CRYPTOPP_BASE64_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base64 encodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64Encoder constructs a default encoder. The constructor lacks a parameter for padding, and you must + /// use IsolatedInitialize() to modify the Base64Encoder after construction. + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Encoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = true, int maxLineLength = 72) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), insertLineBreaks)(Name::MaxLineLength(), maxLineLength)); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648 web safe alphabet by performing the following: + ///
+	///     Base64Encoder encoder;
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base64URLEncoder for an encoder that provides the web safe alphabet, and Base64Decoder::IsolatedInitialize() + /// for an example of modifying a decoder's lookup table after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The default decoding alpahbet is RFC 4868. You can change the to RFC 4868 web safe alphabet + /// by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false);
+	///
+	///     Base64Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base64URLDecoder for a decoder that provides the web safe alphabet, and Base64Encoder::IsolatedInitialize() + /// for an example of modifying an encoder's alphabet after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +/// \brief Base64 encodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64URLEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64URLEncoder() constructs a default encoder using a web safe alphabet. The constructor ignores + /// insertLineBreaks and maxLineLength because the web and URL safe specifications don't use them. They are + /// present in the constructor for API compatibility with Base64Encoder so it is a drop-in replacement. The + /// constructor also disables padding on the encoder for the same reason. + /// \details If you need line breaks or padding, then you must use IsolatedInitialize() to set them + /// after constructing a Base64URLEncoder. + /// \sa Base64Encoder for an encoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + Base64URLEncoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = false, int maxLineLength = -1) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + CRYPTOPP_UNUSED(insertLineBreaks), CRYPTOPP_UNUSED(maxLineLength); + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), false)(Name::MaxLineLength(), -1)(Name::Pad(),false)); + } + + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64URLEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Name::Pad(), true)(Name::InsertLineBreaks(), true);
+	///     encoder.IsolatedInitialize(params);
+ /// \sa Base64Encoder for an encoder that provides a classic alphabet. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64URLDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \details Base64URLDecoder() constructs a default decoder using a web safe alphabet. + /// \sa Base64Decoder for a decoder that provides a classic alphabet. + Base64URLDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on + /// attached transformations. If initialization should be propagated, then use the Initialize() function. + /// \sa Base64Decoder for a decoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/basecode.cpp b/extension/third_party/cryptopp/basecode.cpp new file mode 100644 index 00000000..a9a27892 --- /dev/null +++ b/extension/third_party/cryptopp/basecode.cpp @@ -0,0 +1,247 @@ +// basecode.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-value" +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "basecode.h" +#include "fltrimpl.h" +#include + +NAMESPACE_BEGIN(CryptoPP) + +void BaseN_Encoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("BaseN_Encoder", Name::EncodingLookupArray(), m_alphabet); + + parameters.GetRequiredIntParameter("BaseN_Encoder", Name::Log2Base(), m_bitsPerChar); + if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8) + throw InvalidArgument("BaseN_Encoder: Log2Base must be between 1 and 7 inclusive"); + + byte padding; + bool pad; + if (parameters.GetValue(Name::PaddingByte(), padding)) + pad = parameters.GetValueWithDefault(Name::Pad(), true); + else + pad = false; + m_padding = pad ? padding : -1; + + m_bytePos = m_bitPos = 0; + + int i = 8; + while (i%m_bitsPerChar != 0) + i += 8; + m_outputBlockSize = i/m_bitsPerChar; + + m_outBuf.New(m_outputBlockSize); +} + +size_t BaseN_Encoder::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + while (m_inputPosition < length) + { + if (m_bytePos == 0) + memset(m_outBuf, 0, m_outputBlockSize); + + { + unsigned int b = begin[m_inputPosition++], bitsLeftInSource = 8; + while (true) + { + CRYPTOPP_ASSERT(m_bitsPerChar-m_bitPos >= 0); + unsigned int bitsLeftInTarget = (unsigned int)(m_bitsPerChar-m_bitPos); + m_outBuf[m_bytePos] |= b >> (8-bitsLeftInTarget); + if (bitsLeftInSource >= bitsLeftInTarget) + { + m_bitPos = 0; + ++m_bytePos; + bitsLeftInSource -= bitsLeftInTarget; + if (bitsLeftInSource == 0) + break; + b <<= bitsLeftInTarget; + b &= 0xff; + } + else + { + m_bitPos += bitsLeftInSource; + break; + } + } + } + + CRYPTOPP_ASSERT(m_bytePos <= m_outputBlockSize); + if (m_bytePos == m_outputBlockSize) + { + int i; + for (i=0; i 0) + ++m_bytePos; + + int i; + for (i=0; i 0) + { + memset(m_outBuf+m_bytePos, m_padding, m_outputBlockSize-m_bytePos); + m_bytePos = m_outputBlockSize; + } + FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd); + m_bytePos = m_bitPos = 0; + } + FILTER_END_NO_MESSAGE_END; +} + +void BaseN_Decoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("BaseN_Decoder", Name::DecodingLookupArray(), m_lookup); + + parameters.GetRequiredIntParameter("BaseN_Decoder", Name::Log2Base(), m_bitsPerChar); + if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8) + throw InvalidArgument("BaseN_Decoder: Log2Base must be between 1 and 7 inclusive"); + + m_bytePos = m_bitPos = 0; + + int i = m_bitsPerChar; + while (i%8 != 0) + i += m_bitsPerChar; + m_outputBlockSize = i/8; + + m_outBuf.New(m_outputBlockSize); +} + +size_t BaseN_Decoder::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + while (m_inputPosition < length) + { + unsigned int value; + value = m_lookup[begin[m_inputPosition++]]; + if (value >= 256) + continue; + + if (m_bytePos == 0 && m_bitPos == 0) + memset(m_outBuf, 0, m_outputBlockSize); + + { + int newBitPos = m_bitPos + m_bitsPerChar; + if (newBitPos <= 8) + m_outBuf[m_bytePos] |= value << (8-newBitPos); + else + { + m_outBuf[m_bytePos] |= value >> (newBitPos-8); + m_outBuf[m_bytePos+1] |= value << (16-newBitPos); + } + + m_bitPos = newBitPos; + while (m_bitPos >= 8) + { + m_bitPos -= 8; + ++m_bytePos; + } + } + + if (m_bytePos == m_outputBlockSize) + { + FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0); + m_bytePos = m_bitPos = 0; + } + } + if (messageEnd) + { + FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd); + m_bytePos = m_bitPos = 0; + } + FILTER_END_NO_MESSAGE_END; +} + +void BaseN_Decoder::InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive) +{ + std::fill(lookup, lookup+256, -1); + + for (unsigned int i=0; i +{ +public: + /// \brief Construct a BaseN_Encoder + /// \param attachment a BufferedTransformation to attach to this object + BaseN_Encoder(BufferedTransformation *attachment=NULLPTR) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Encoder + /// \param alphabet table of ASCII characters to use as the alphabet + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \param padding the character to use as padding + /// \pre log2base must be between 1 and 7 inclusive + /// \throw InvalidArgument if log2base is not between 1 and 7 + BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULLPTR, int padding=-1) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + BaseN_Encoder::IsolatedInitialize( + MakeParameters + (Name::EncodingLookupArray(), alphabet) + (Name::Log2Base(), log2base) + (Name::Pad(), padding != -1) + (Name::PaddingByte(), byte(padding))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + const byte *m_alphabet; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Decoder for bases that are a power of 2 +class CRYPTOPP_DLL BaseN_Decoder : public Unflushable +{ +public: + /// \brief Construct a BaseN_Decoder + /// \param attachment a BufferedTransformation to attach to this object + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Decoder + /// \param lookup table of values + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \details log2base is the exponent (like 5 in 25), and not + /// the number of elements (like 32). + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + BaseN_Decoder::IsolatedInitialize( + MakeParameters + (Name::DecodingLookupArray(), lookup) + (Name::Log2Base(), log2base)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Initializes BaseN lookup array + /// \param lookup table of values + /// \param alphabet table of ASCII characters + /// \param base the base for the encoder + /// \param caseInsensitive flag indicating whether the alphabet is case sensitivie + /// \pre COUNTOF(lookup) == 256 + /// \pre COUNTOF(alphabet) == base + /// \details Internally, the function sets the first 256 elements in the lookup table to + /// their value from the alphabet array or -1. base is the number of element (like 32), + /// and not an exponent (like 5 in 25) + static void CRYPTOPP_API InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive); + +private: + const int *m_lookup; + int m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Filter that breaks input stream into groups of fixed size +class CRYPTOPP_DLL Grouper : public Bufferless +{ +public: + /// \brief Construct a Grouper + /// \param attachment a BufferedTransformation to attach to this object + Grouper(BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) {Detach(attachment);} + + /// \brief Construct a Grouper + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \param attachment a BufferedTransformation to attach to this object + Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) + { + Detach(attachment); + Grouper::IsolatedInitialize( + MakeParameters + (Name::GroupSize(), groupSize) + (Name::Separator(), ConstByteArrayParameter(separator)) + (Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + SecByteBlock m_separator, m_terminator; + size_t m_groupSize, m_counter; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/bench.h b/extension/third_party/cryptopp/bench.h new file mode 100644 index 00000000..2c30e971 --- /dev/null +++ b/extension/third_party/cryptopp/bench.h @@ -0,0 +1,105 @@ +// bench.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_BENCH_H +#define CRYPTOPP_BENCH_H + +#include "cryptlib.h" + +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +// More granular control over benchmarks +enum TestClass { + /// \brief Random number generators + UnkeyedRNG=(1<<0), + /// \brief Message digests + UnkeyedHash=(1<<1), + /// \brief Other unkeyed algorithms + UnkeyedOther=(1<<2), + + /// \brief Message authentication codes + SharedKeyMAC=(1<<3), + /// \brief Stream ciphers + SharedKeyStream=(1<<4), + /// \brief Block ciphers ciphers + SharedKeyBlock=(1<<5), + /// \brief Other shared key algorithms + SharedKeyOther=(1<<6), + + /// \brief Key agreement algorithms over integers + PublicKeyAgreement=(1<<7), + /// \brief Encryption algorithms over integers + PublicKeyEncryption=(1<<8), + /// \brief Signature algorithms over integers + PublicKeySignature=(1<<9), + /// \brief Other public key algorithms over integers + PublicKeyOther=(1<<10), + + /// \brief Key agreement algorithms over EC + PublicKeyAgreementEC=(1<<11), + /// \brief Encryption algorithms over EC + PublicKeyEncryptionEC=(1<<12), + /// \brief Signature algorithms over EC + PublicKeySignatureEC=(1<<13), + /// \brief Other public key algorithms over EC + PublicKeyOtherEC=(1<<14), + + Unkeyed=UnkeyedRNG|UnkeyedHash|UnkeyedOther, + SharedKey=SharedKeyMAC|SharedKeyStream|SharedKeyBlock|SharedKeyOther, + PublicKey=PublicKeyAgreement|PublicKeyEncryption|PublicKeySignature|PublicKeyOther, + PublicKeyEC=PublicKeyAgreementEC|PublicKeyEncryptionEC|PublicKeySignatureEC|PublicKeyOtherEC, + + All=Unkeyed|SharedKey|PublicKey|PublicKeyEC, + + TestFirst=(0), TestLast=(1<<15) +}; + +extern const double CLOCK_TICKS_PER_SECOND; +extern double g_allocatedTime; +extern double g_hertz; +extern double g_logTotal; +extern unsigned int g_logCount; +extern const byte defaultKey[]; + +// Test book keeping +extern time_t g_testBegin; +extern time_t g_testEnd; + +// Benchmark command handler +void BenchmarkWithCommand(int argc, const char* const argv[]); +// Top level, prints preamble and postamble +void Benchmark(Test::TestClass suites, double t, double hertz); +// Unkeyed systems +void BenchmarkUnkeyedAlgorithms(double t, double hertz); +// Shared key systems +void BenchmarkSharedKeyedAlgorithms(double t, double hertz); +// Public key systems over integers +void BenchmarkPublicKeyAlgorithms(double t, double hertz); +// Public key systems over elliptic curves +void BenchmarkEllipticCurveAlgorithms(double t, double hertz); + +// These are defined in bench1.cpp +extern void OutputResultKeying(double iterations, double timeTaken); +extern void OutputResultBytes(const char *name, const char *provider, double length, double timeTaken); +extern void OutputResultOperations(const char *name, const char *provider, const char *operation, bool pc, unsigned long iterations, double timeTaken); + +// These are defined in bench1.cpp +extern void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal); +extern void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal); +extern void BenchMark(const char *name, HashTransformation &ht, double timeTotal); +extern void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal); + +// These are defined in bench2.cpp +extern void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs ¶ms); +extern void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/extension/third_party/cryptopp/bench1.cpp b/extension/third_party/cryptopp/bench1.cpp new file mode 100644 index 00000000..5a7d66a1 --- /dev/null +++ b/extension/third_party/cryptopp/bench1.cpp @@ -0,0 +1,518 @@ +// bench1.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#include "cryptlib.h" +#include "bench.h" +#include "validate.h" + +#include "cpu.h" +#include "factory.h" +#include "algparam.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#include "osrng.h" +#include "drbg.h" +#include "darn.h" +#include "mersenne.h" +#include "rdrand.h" +#include "padlkrng.h" + +#include +#include +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4355) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +#ifdef CLOCKS_PER_SEC +const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC; +#elif defined(CLK_TCK) +const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK; +#else +const double CLOCK_TICKS_PER_SECOND = 1000000.0; +#endif + +extern const byte defaultKey[] = "0123456789" // 168 + NULL + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "00000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000"; + +double g_allocatedTime = 0.0, g_hertz = 0.0, g_logTotal = 0.0; +unsigned int g_logCount = 0; +time_t g_testBegin, g_testEnd; + +inline std::string HertzToString(double hertz) +{ + std::ostringstream oss; + oss.precision(3); + + if (hertz >= 0.999e+9) + oss << hertz / 1e+9 << " GHz"; + else if (hertz >= 0.999e+6) + oss << hertz / 1e+6 << " MHz"; + else if (hertz >= 0.999e+3) + oss << hertz / 1e+3 << " KHz"; + else + oss << hertz << " Hz"; + + return oss.str(); +} + +void OutputResultBytes(const char *name, const char *provider, double length, double timeTaken) +{ + std::ostringstream oss; + + // Coverity finding + if (length < 0.000001f) length = 0.000001f; + if (timeTaken < 0.000001f) timeTaken = 0.000001f; + + double mbs = length / timeTaken / (1024*1024); + oss << "\n" << name << "" << provider; + oss << std::setiosflags(std::ios::fixed); + oss << "" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << mbs; + if (g_hertz > 1.0f) + { + const double cpb = timeTaken * g_hertz / length; + if (cpb < 24.0f) + oss << "" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << cpb; + else + oss << "" << std::setprecision(1) << std::setiosflags(std::ios::fixed) << cpb; + } + g_logTotal += log(mbs); + g_logCount++; + + std::cout << oss.str(); +} + +void OutputResultKeying(double iterations, double timeTaken) +{ + std::ostringstream oss; + + // Coverity finding + if (iterations < 0.000001f) iterations = 0.000001f; + if (timeTaken < 0.000001f) timeTaken = 0.000001f; + + oss << "" << std::setprecision(3) << std::setiosflags(std::ios::fixed) << (1000*1000*timeTaken/iterations); + + // Coverity finding + if (g_hertz > 1.0f) + oss << "" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << timeTaken * g_hertz / iterations; + + std::cout << oss.str(); +} + +void OutputResultOperations(const char *name, const char *provider, const char *operation, bool pc, unsigned long iterations, double timeTaken) +{ + CRYPTOPP_UNUSED(provider); + std::ostringstream oss; + + // Coverity finding + if (!iterations) iterations++; + if (timeTaken < 0.000001f) timeTaken = 0.000001f; + + oss << "\n" << name << " " << operation << (pc ? " with precomputation" : ""); + //oss << "" << provider; + oss << "" << std::setprecision(3) << std::setiosflags(std::ios::fixed) << (1000*timeTaken/iterations); + + // Coverity finding + if (g_hertz > 1.0f) + { + const double t = timeTaken * g_hertz / iterations / 1000000; + oss << "" << std::setprecision(3) << std::setiosflags(std::ios::fixed) << t; + } + + g_logTotal += log(iterations/timeTaken); + g_logCount++; + + std::cout << oss.str(); +} + +/* +void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal) +{ + const int BUF_SIZE = RoundUpToMultipleOf(2048U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize()); + AlignedSecByteBlock buf(BUF_SIZE); + buf.SetMark(16); + + const int nBlocks = BUF_SIZE / cipher.BlockSize(); + unsigned long i=0, blocks=1; + double timeTaken; + + clock_t start = ::clock(); + do + { + blocks *= 2; + for (; i(&rng); + if (cipher != NULLPTR) + { + const size_t size = cipher->DefaultKeyLength(); + if (cipher->IsResynchronizable()) + cipher->SetKeyWithIV(buf, size, buf+size); + else + cipher->SetKey(buf, size); + } + + unsigned long long blocks = 1; + double timeTaken; + + clock_t start = ::clock(); + do + { + rng.GenerateBlock(buf, buf.size()); + blocks++; + timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND; + } while (timeTaken < timeTotal); + + std::string provider = rng.AlgorithmProvider(); + OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken); +} + +// Hack, but we probably need a KeyedRandomNumberGenerator interface +// and a few methods to generalize keying a RNG. X917RNG, Hash_DRBG, +// HMAC_DRBG, AES/CFB RNG and a few others could use it. "A few others" +// includes BLAKE2, ChaCha and Poly1305 when used as a RNG. +void BenchMark(const char *name, NIST_DRBG &rng, double timeTotal) +{ + const int BUF_SIZE = 2048U; + AlignedSecByteBlock buf(BUF_SIZE); + Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE); + buf.SetMark(16); + + rng.IncorporateEntropy(buf, rng.MinEntropyLength()); + unsigned long long blocks = 1; + double timeTaken; + + clock_t start = ::clock(); + do + { + rng.GenerateBlock(buf, buf.size()); + blocks++; + timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND; + } while (timeTaken < timeTotal); + + std::string provider = rng.AlgorithmProvider(); + OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken); +} + +template +void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName = NULLPTR, const NameValuePairs ¶ms = g_nullNameValuePairs) +{ + CRYPTOPP_UNUSED(params); + std::string name = factoryName; + if (displayName) + name = displayName; + + member_ptr obj(ObjectFactoryRegistry::Registry().CreateObject(factoryName)); + BenchMark(name.c_str(), *obj, g_allocatedTime); +} + +void AddHtmlHeader() +{ + std::ostringstream oss; + + // HTML5 + oss << ""; + oss << "\n"; + + oss << "\n"; + oss << "\n"; + oss << "\nSpeed Comparison of Popular Crypto Algorithms"; + oss << "\n"; + oss << "\n"; + + oss << "\n"; + + oss << "\n

Crypto++ " << CRYPTOPP_VERSION / 100; + oss << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << " Benchmarks

"; + + oss << "\n

Here are speed benchmarks for some commonly used cryptographic algorithms.

"; + + if (g_hertz > 1.0f) + oss << "\n

CPU frequency of the test platform is " << HertzToString(g_hertz) << ".

"; + else + oss << "\n

CPU frequency of the test platform was not provided.

" << std::endl; + + std::cout << oss.str(); +} + +void AddHtmlFooter() +{ + std::ostringstream oss; + oss << "\n\n\n"; + std::cout << oss.str(); +} + +void BenchmarkWithCommand(int argc, const char* const argv[]) +{ + std::string command(argv[1]); + float runningTime(argc >= 3 ? Test::StringToValue(argv[2]) : 1.0f); + float cpuFreq(argc >= 4 ? Test::StringToValue(argv[3])*float(1e9) : 0.0f); + std::string algoName(argc >= 5 ? argv[4] : ""); + + // https://github.com/weidai11/cryptopp/issues/983 + if (runningTime > 10.0f) + runningTime = 10.0f; + + if (command == "b") // All benchmarks + Benchmark(Test::All, runningTime, cpuFreq); + else if (command == "b4") // Public key algorithms over EC + Test::Benchmark(Test::PublicKeyEC, runningTime, cpuFreq); + else if (command == "b3") // Public key algorithms + Test::Benchmark(Test::PublicKey, runningTime, cpuFreq); + else if (command == "b2") // Shared key algorithms + Test::Benchmark(Test::SharedKey, runningTime, cpuFreq); + else if (command == "b1") // Unkeyed algorithms + Test::Benchmark(Test::Unkeyed, runningTime, cpuFreq); +} + +void Benchmark(Test::TestClass suites, double t, double hertz) +{ + g_allocatedTime = t; + g_hertz = hertz; + + // Add
in between tables + size_t count_breaks = 0; + + AddHtmlHeader(); + + g_testBegin = ::time(NULLPTR); + + if (static_cast(suites) == 0 || static_cast(suites) > TestLast) + suites = Test::All; + + // Unkeyed algorithms + if (suites & Test::Unkeyed) + { + if (count_breaks) + std::cout << "\n
"; + count_breaks++; + + BenchmarkUnkeyedAlgorithms(t, hertz); + } + + // Shared key algorithms + if (suites & Test::SharedKey) + { + if (count_breaks) + std::cout << "\n
"; + count_breaks++; + + BenchmarkSharedKeyedAlgorithms(t, hertz); + } + + // Public key algorithms + if (suites & Test::PublicKey) + { + if (count_breaks) + std::cout << "\n
"; + count_breaks++; + + BenchmarkPublicKeyAlgorithms(t, hertz); + } + + // Public key algorithms over EC + if (suites & Test::PublicKeyEC) + { + if (count_breaks) + std::cout << "\n
"; + count_breaks++; + + BenchmarkEllipticCurveAlgorithms(t, hertz); + } + + g_testEnd = ::time(NULLPTR); + + std::ostringstream oss; + oss << "\n

Throughput Geometric Average: " << std::setiosflags(std::ios::fixed); + oss << std::exp(g_logTotal/(g_logCount > 0.0f ? g_logCount : 1.0f)) << std::endl; + + oss << "\n

Test started at " << TimeToString(g_testBegin); + oss << "\n
Test ended at " << TimeToString(g_testEnd); + oss << "\n"; + std::cout << oss.str(); + + AddHtmlFooter(); +} + +void BenchmarkUnkeyedAlgorithms(double t, double hertz) +{ + g_allocatedTime = t; + g_hertz = hertz; + + const char *cpb; + if (g_hertz > 1.0f) + cpb = "Cycles/Byte"; + else + cpb = ""; + + std::cout << "\n"; + + std::cout << "\n"; + std::cout << ""; + std::cout << "\n"; + std::cout << "\n"; + { +#ifdef NONBLOCKING_RNG_AVAILABLE + BenchMarkByNameKeyLess("NonblockingRng"); +#endif +#ifdef OS_RNG_AVAILABLE + BenchMarkByNameKeyLess("AutoSeededRandomPool"); + BenchMarkByNameKeyLess("AutoSeededX917RNG(AES)"); +#endif + BenchMarkByNameKeyLess("MT19937"); +#if (CRYPTOPP_BOOL_X86) && !defined(CRYPTOPP_DISABLE_ASM) + if (HasPadlockRNG()) + BenchMarkByNameKeyLess("PadlockRNG"); +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) && !defined(CRYPTOPP_DISABLE_ASM) + if (HasRDRAND()) + BenchMarkByNameKeyLess("RDRAND"); + if (HasRDSEED()) + BenchMarkByNameKeyLess("RDSEED"); +#endif +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) && !defined(CRYPTOPP_DISABLE_ASM) + if (HasDARN()) + BenchMarkByNameKeyLess("DARN"); +#endif + BenchMarkByNameKeyLess("AES/OFB RNG"); + BenchMarkByNameKeyLess("Hash_DRBG(SHA1)"); + BenchMarkByNameKeyLess("Hash_DRBG(SHA256)"); + BenchMarkByNameKeyLess("HMAC_DRBG(SHA1)"); + BenchMarkByNameKeyLess("HMAC_DRBG(SHA256)"); + } + + std::cout << "\n"; + { + BenchMarkByNameKeyLess("CRC32"); + BenchMarkByNameKeyLess("CRC32C"); + BenchMarkByNameKeyLess("Adler32"); + BenchMarkByNameKeyLess("MD5"); + BenchMarkByNameKeyLess("SHA-1"); + BenchMarkByNameKeyLess("SHA-256"); + BenchMarkByNameKeyLess("SHA-512"); + BenchMarkByNameKeyLess("SHA3-224"); + BenchMarkByNameKeyLess("SHA3-256"); + BenchMarkByNameKeyLess("SHA3-384"); + BenchMarkByNameKeyLess("SHA3-512"); + BenchMarkByNameKeyLess("Keccak-224"); + BenchMarkByNameKeyLess("Keccak-256"); + BenchMarkByNameKeyLess("Keccak-384"); + BenchMarkByNameKeyLess("Keccak-512"); + BenchMarkByNameKeyLess("Tiger"); + BenchMarkByNameKeyLess("Whirlpool"); + BenchMarkByNameKeyLess("RIPEMD-160"); + BenchMarkByNameKeyLess("RIPEMD-320"); + BenchMarkByNameKeyLess("RIPEMD-128"); + BenchMarkByNameKeyLess("RIPEMD-256"); + BenchMarkByNameKeyLess("SM3"); + BenchMarkByNameKeyLess("BLAKE2s"); + BenchMarkByNameKeyLess("BLAKE2b"); + } + + std::cout << "\n
AlgorithmProviderMiB/Second" << cpb; + + std::cout << "\n
" << std::endl; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/bench2.cpp b/extension/third_party/cryptopp/bench2.cpp new file mode 100644 index 00000000..2cfd6200 --- /dev/null +++ b/extension/third_party/cryptopp/bench2.cpp @@ -0,0 +1,267 @@ +// bench2.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#include "cryptlib.h" +#include "bench.h" +#include "validate.h" + +#include "cpu.h" +#include "factory.h" +#include "algparam.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#include "vmac.h" +#include "hmac.h" +#include "ttmac.h" +#include "cmac.h" +#include "dmac.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4355) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs ¶ms) +{ + unsigned long iterations = 0; + double timeTaken; + + clock_t start = ::clock(); + do + { + for (unsigned int i=0; i<1024; i++) + c.SetKey(defaultKey, keyLength, params); + timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND; + iterations += 1024; + } + while (timeTaken < g_allocatedTime); + + OutputResultKeying(iterations, timeTaken); +} + +void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal) +{ + if (cipher.NeedsPrespecifiedDataLengths()) + cipher.SpecifyDataLengths(0, cipher.MaxMessageLength(), 0); + + BenchMark(name, static_cast(cipher), timeTotal); +} + +template +void BenchMarkByName2(const char *factoryName, size_t keyLength=0, const char *displayName=NULLPTR, const NameValuePairs ¶ms = g_nullNameValuePairs) +{ + std::string name(factoryName ? factoryName : ""); + member_ptr obj(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + + if (keyLength == 0) + keyLength = obj->DefaultKeyLength(); + + if (displayName != NULLPTR) + name = displayName; + else if (keyLength != 0) + name += " (" + IntToString(keyLength * 8) + "-bit key)"; + + obj->SetKey(defaultKey, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false))); + BenchMark(name.c_str(), *static_cast(obj.get()), g_allocatedTime); + BenchMarkKeying(*obj, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false))); +} + +template +void BenchMarkByName(const char *factoryName, size_t keyLength=0, const char *displayName=NULLPTR, const NameValuePairs ¶ms = g_nullNameValuePairs) +{ + BenchMarkByName2(factoryName, keyLength, displayName, params); +} + +void BenchmarkSharedKeyedAlgorithms(double t, double hertz) +{ + g_allocatedTime = t; + g_hertz = hertz; + + const char *cpb, *cpk; + if (g_hertz > 1.0f) + { + cpb = "Cycles/Byte"; + cpk = "Cycles to
Setup Key and IV"; + } + else + { + cpb = cpk = ""; + } + + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + { +#if CRYPTOPP_AESNI_AVAILABLE + if (HasCLMUL()) + BenchMarkByName2("AES/GCM", 0, "GMAC(AES)"); + else +#elif CRYPTOPP_ARM_PMULL_AVAILABLE + if (HasPMULL()) + BenchMarkByName2("AES/GCM", 0, "GMAC(AES)"); + else +#elif CRYPTOPP_POWER8_VMULL_AVAILABLE + if (HasPMULL()) + BenchMarkByName2("AES/GCM", 0, "GMAC(AES)"); + else +#endif + { + BenchMarkByName2("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048)); + BenchMarkByName2("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64 * 1024)); + } + + BenchMarkByName("VMAC(AES)-64"); + BenchMarkByName("VMAC(AES)-128"); + BenchMarkByName("HMAC(SHA-1)"); + BenchMarkByName("HMAC(SHA-256)"); + BenchMarkByName("Two-Track-MAC"); + BenchMarkByName("CMAC(AES)"); + BenchMarkByName("DMAC(AES)"); + BenchMarkByName("Poly1305(AES)"); + BenchMarkByName("Poly1305TLS"); + BenchMarkByName("BLAKE2s"); + BenchMarkByName("BLAKE2b"); + BenchMarkByName("SipHash-2-4"); + BenchMarkByName("SipHash-4-8"); + } + + std::cout << "\n"; + { + BenchMarkByName("Panama-LE"); + BenchMarkByName("Panama-BE"); + BenchMarkByName("Salsa20", 0, "Salsa20"); + BenchMarkByName("Salsa20", 0, "Salsa20/12", MakeParameters(Name::Rounds(), 12)); + BenchMarkByName("Salsa20", 0, "Salsa20/8", MakeParameters(Name::Rounds(), 8)); + BenchMarkByName("ChaCha", 0, "ChaCha20"); + BenchMarkByName("ChaCha", 0, "ChaCha12", MakeParameters(Name::Rounds(), 12)); + BenchMarkByName("ChaCha", 0, "ChaCha8", MakeParameters(Name::Rounds(), 8)); + BenchMarkByName("ChaChaTLS"); + BenchMarkByName("Sosemanuk"); + BenchMarkByName("Rabbit"); + BenchMarkByName("RabbitWithIV"); + BenchMarkByName("HC-128"); + BenchMarkByName("HC-256"); + BenchMarkByName("MARC4"); + BenchMarkByName("SEAL-3.0-LE"); + BenchMarkByName("WAKE-OFB-LE"); + } + + std::cout << "\n"; + { + BenchMarkByName("AES/CTR", 16); + BenchMarkByName("AES/CTR", 24); + BenchMarkByName("AES/CTR", 32); + BenchMarkByName("AES/CBC", 16); + BenchMarkByName("AES/CBC", 24); + BenchMarkByName("AES/CBC", 32); + BenchMarkByName("AES/XTS", 32); + BenchMarkByName("AES/XTS", 48); + BenchMarkByName("AES/XTS", 64); + BenchMarkByName("AES/OFB", 16); + BenchMarkByName("AES/CFB", 16); + BenchMarkByName("AES/ECB", 16); + BenchMarkByName("ARIA/CTR", 16); + BenchMarkByName("ARIA/CTR", 32); + BenchMarkByName("HIGHT/CTR"); + BenchMarkByName("Camellia/CTR", 16); + BenchMarkByName("Camellia/CTR", 32); + BenchMarkByName("Twofish/CTR"); + BenchMarkByName("Threefish-256(256)/CTR", 32); + BenchMarkByName("Threefish-512(512)/CTR", 64); + BenchMarkByName("Threefish-1024(1024)/CTR", 128); + BenchMarkByName("Serpent/CTR"); + BenchMarkByName("CAST-128/CTR"); + BenchMarkByName("CAST-256/CTR", 32); + BenchMarkByName("RC6/CTR"); + BenchMarkByName("MARS/CTR"); + BenchMarkByName("SHACAL-2/CTR", 16); + BenchMarkByName("SHACAL-2/CTR", 64); + BenchMarkByName("DES/CTR"); + BenchMarkByName("DES-XEX3/CTR"); + BenchMarkByName("DES-EDE3/CTR"); + BenchMarkByName("IDEA/CTR"); + BenchMarkByName("RC5/CTR", 0, "RC5 (r=16)"); + BenchMarkByName("Blowfish/CTR"); + BenchMarkByName("SKIPJACK/CTR"); + BenchMarkByName("SEED/CTR", 0, "SEED/CTR (1/2 K table)"); + BenchMarkByName("SM4/CTR"); + + BenchMarkByName("Kalyna-128/CTR", 16, "Kalyna-128(128)/CTR (128-bit key)"); + BenchMarkByName("Kalyna-128/CTR", 32, "Kalyna-128(256)/CTR (256-bit key)"); + BenchMarkByName("Kalyna-256/CTR", 32, "Kalyna-256(256)/CTR (256-bit key)"); + BenchMarkByName("Kalyna-256/CTR", 64, "Kalyna-256(512)/CTR (512-bit key)"); + BenchMarkByName("Kalyna-512/CTR", 64, "Kalyna-512(512)/CTR (512-bit key)"); + } + + std::cout << "\n"; + { + BenchMarkByName("CHAM-64/CTR", 16, "CHAM-64(128)/CTR (128-bit key)"); + BenchMarkByName("CHAM-128/CTR", 16, "CHAM-128(128)/CTR (128-bit key)"); + BenchMarkByName("CHAM-128/CTR", 32, "CHAM-128(256)/CTR (256-bit key)"); + + BenchMarkByName("LEA-128/CTR", 16, "LEA-128(128)/CTR (128-bit key)"); + BenchMarkByName("LEA-128/CTR", 24, "LEA-128(192)/CTR (192-bit key)"); + BenchMarkByName("LEA-128/CTR", 32, "LEA-128(256)/CTR (256-bit key)"); + + BenchMarkByName("SIMECK-32/CTR", 8, "SIMECK-32(64)/CTR (64-bit key)"); + BenchMarkByName("SIMECK-64/CTR", 16, "SIMECK-64(128)/CTR (128-bit key)"); + + BenchMarkByName("SIMON-64/CTR", 12, "SIMON-64(96)/CTR (96-bit key)"); + BenchMarkByName("SIMON-64/CTR", 16, "SIMON-64(128)/CTR (128-bit key)"); + BenchMarkByName("SIMON-128/CTR", 16, "SIMON-128(128)/CTR (128-bit key)"); + BenchMarkByName("SIMON-128/CTR", 24, "SIMON-128(192)/CTR (192-bit key)"); + BenchMarkByName("SIMON-128/CTR", 32, "SIMON-128(256)/CTR (256-bit key)"); + + BenchMarkByName("SPECK-64/CTR", 12, "SPECK-64(96)/CTR (96-bit key)"); + BenchMarkByName("SPECK-64/CTR", 16, "SPECK-64(128)/CTR (128-bit key)"); + BenchMarkByName("SPECK-128/CTR", 16, "SPECK-128(128)/CTR (128-bit key)"); + BenchMarkByName("SPECK-128/CTR", 24, "SPECK-128(192)/CTR (192-bit key)"); + BenchMarkByName("SPECK-128/CTR", 32, "SPECK-128(256)/CTR (256-bit key)"); + + BenchMarkByName("TEA/CTR"); + BenchMarkByName("XTEA/CTR"); + } + + std::cout << "\n"; + { +#if CRYPTOPP_AESNI_AVAILABLE + if (HasCLMUL()) + BenchMarkByName2("AES/GCM", 0, "AES/GCM"); + else +#elif CRYPTOPP_ARM_PMULL_AVAILABLE + if (HasPMULL()) + BenchMarkByName2("AES/GCM", 0, "AES/GCM"); + else +#elif CRYPTOPP_POWER8_VMULL_AVAILABLE + if (HasPMULL()) + BenchMarkByName2("AES/GCM", 0, "AES/GCM"); + else +#endif + { + BenchMarkByName2("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048)); + BenchMarkByName2("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64 * 1024)); + } + BenchMarkByName2("AES/CCM"); + BenchMarkByName2("AES/EAX"); + BenchMarkByName2("ChaCha20/Poly1305"); + BenchMarkByName2("XChaCha20/Poly1305"); + } + + std::cout << "\n
AlgorithmProviderMiB/Second" << cpb; + std::cout << "Microseconds to
Setup Key and IV" << cpk; + + std::cout << "\n
" << std::endl; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/bench3.cpp b/extension/third_party/cryptopp/bench3.cpp new file mode 100644 index 00000000..ac5d9321 --- /dev/null +++ b/extension/third_party/cryptopp/bench3.cpp @@ -0,0 +1,480 @@ +// bench3.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#include "cryptlib.h" +#include "bench.h" +#include "validate.h" + +#include "cpu.h" +#include "factory.h" +#include "algparam.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#include "pubkey.h" +#include "gfpcrypt.h" +#include "eccrypto.h" +#include "pkcspad.h" + +#include "files.h" +#include "filters.h" +#include "hex.h" +#include "rsa.h" +#include "nr.h" +#include "dsa.h" +#include "luc.h" +#include "rw.h" +#include "ecp.h" +#include "ec2n.h" +#include "asn.h" +#include "dh.h" +#include "mqv.h" +#include "hmqv.h" +#include "fhmqv.h" +#include "xed25519.h" +#include "xtrcrypt.h" +#include "esign.h" +#include "pssr.h" +#include "oids.h" +#include "randpool.h" +#include "stdcpp.h" +#include "hrtimer.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +void BenchMarkEncryption(const char *name, PK_Encryptor &key, double timeTotal, bool pc = false) +{ + unsigned int len = 16; + SecByteBlock plaintext(len), ciphertext(key.CiphertextLength(len)); + Test::GlobalRNG().GenerateBlock(plaintext, len); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + key.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = key.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Encryption", pc, i, timeTaken); + + if (!pc && key.GetMaterial().SupportsPrecomputation()) + { + key.AccessMaterial().Precompute(16); + BenchMarkEncryption(name, key, timeTotal, true); + } +} + +void BenchMarkDecryption(const char *name, PK_Decryptor &priv, PK_Encryptor &pub, double timeTotal) +{ + unsigned int len = 16; + SecByteBlock ciphertext(pub.CiphertextLength(len)); + SecByteBlock plaintext(pub.MaxPlaintextLength(ciphertext.size())); + Test::GlobalRNG().GenerateBlock(plaintext, len); + pub.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + priv.Decrypt(Test::GlobalRNG(), ciphertext, ciphertext.size(), plaintext); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = priv.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Decryption", false, i, timeTaken); +} + +void BenchMarkSigning(const char *name, PK_Signer &key, double timeTotal, bool pc=false) +{ + unsigned int len = 16; + AlignedSecByteBlock message(len), signature(key.SignatureLength()); + Test::GlobalRNG().GenerateBlock(message, len); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + (void)key.SignMessage(Test::GlobalRNG(), message, len, signature); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = key.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Signature", pc, i, timeTaken); + + if (!pc && key.GetMaterial().SupportsPrecomputation()) + { + key.AccessMaterial().Precompute(16); + BenchMarkSigning(name, key, timeTotal, true); + } +} + +void BenchMarkVerification(const char *name, const PK_Signer &priv, PK_Verifier &pub, double timeTotal, bool pc=false) +{ + unsigned int len = 16; + AlignedSecByteBlock message(len), signature(pub.SignatureLength()); + Test::GlobalRNG().GenerateBlock(message, len); + priv.SignMessage(Test::GlobalRNG(), message, len, signature); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + (void)pub.VerifyMessage(message, len, signature, signature.size()); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = pub.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Verification", pc, i, timeTaken); + + if (!pc && pub.GetMaterial().SupportsPrecomputation()) + { + pub.AccessMaterial().Precompute(16); + BenchMarkVerification(name, priv, pub, timeTotal, true); + } +} + +void BenchMarkKeyGen(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + SecByteBlock priv(d.PrivateKeyLength()), pub(d.PublicKeyLength()); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + d.GenerateKeyPair(Test::GlobalRNG(), priv, pub); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = d.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Key-Pair Generation", pc, i, timeTaken); + + if (!pc && d.GetMaterial().SupportsPrecomputation()) + { + d.AccessMaterial().Precompute(16); + BenchMarkKeyGen(name, d, timeTotal, true); + } +} + +void BenchMarkKeyGen(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + SecByteBlock priv(d.EphemeralPrivateKeyLength()), pub(d.EphemeralPublicKeyLength()); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + d.GenerateEphemeralKeyPair(Test::GlobalRNG(), priv, pub); + ++i; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = d.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Key-Pair Generation", pc, i, timeTaken); + + if (!pc && d.GetMaterial().SupportsPrecomputation()) + { + d.AccessMaterial().Precompute(16); + BenchMarkKeyGen(name, d, timeTotal, true); + } +} + +void BenchMarkAgreement(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength()); + SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength()); + d.GenerateKeyPair(Test::GlobalRNG(), priv1, pub1); + d.GenerateKeyPair(Test::GlobalRNG(), priv2, pub2); + SecByteBlock val(d.AgreedValueLength()); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + d.Agree(val, priv1, pub2); + d.Agree(val, priv2, pub1); + i+=2; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = d.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Key Agreement", pc, i, timeTaken); +} + +void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false) +{ + SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength()); + SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength()); + SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength()); + SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength()); + d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv1, spub1); + d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv2, spub2); + d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv1, epub1); + d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv2, epub2); + SecByteBlock val(d.AgreedValueLength()); + + unsigned int i = 0; + double timeTaken; + + ThreadUserTimer timer; + timer.StartTimer(); + + do + { + d.Agree(val, spriv1, epriv1, spub2, epub2); + d.Agree(val, spriv2, epriv2, spub1, epub1); + i+=2; timeTaken = timer.ElapsedTimeAsDouble(); + } + while (timeTaken < timeTotal); + + std::string provider = d.AlgorithmProvider(); + OutputResultOperations(name, provider.c_str(), "Key Agreement", pc, i, timeTaken); +} + +template +void BenchMarkCrypto(const char *filename, const char *name, double timeTotal) +{ + FileSource f(DataDir(filename).c_str(), true, new HexDecoder); + typename SCHEME::Decryptor priv(f); + typename SCHEME::Encryptor pub(priv); + BenchMarkEncryption(name, pub, timeTotal); + BenchMarkDecryption(name, priv, pub, timeTotal); +} + +template +void BenchMarkSignature(const char *filename, const char *name, double timeTotal) +{ + FileSource f(DataDir(filename).c_str(), true, new HexDecoder); + typename SCHEME::Signer priv(f); + typename SCHEME::Verifier pub(priv); + BenchMarkSigning(name, priv, timeTotal); + BenchMarkVerification(name, priv, pub, timeTotal); +} + +template +void BenchMarkKeyAgreement(const char *filename, const char *name, double timeTotal) +{ + FileSource f(DataDir(filename).c_str(), true, new HexDecoder); + D d(f); + BenchMarkKeyGen(name, d, timeTotal); + BenchMarkAgreement(name, d, timeTotal); +} + +void BenchmarkPublicKeyAlgorithms(double t, double hertz) +{ + g_allocatedTime = t; + g_hertz = hertz; + + const char *mco; + if (g_hertz > 1.0f) + mco = "Megacycles/Operation"; + else + mco = ""; + + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + { + BenchMarkCrypto > >("TestData/rsa1024.dat", "RSA 1024", t); + BenchMarkCrypto > >("TestData/luc1024.dat", "LUC 1024", t); + BenchMarkCrypto >("TestData/dlie1024.dat", "DLIES 1024", t); + BenchMarkCrypto >("TestData/lucc512.dat", "LUCELG 512", t); + } + + std::cout << "\n"; + { + BenchMarkCrypto > >("TestData/rsa2048.dat", "RSA 2048", t); + BenchMarkCrypto > >("TestData/luc2048.dat", "LUC 2048", t); + BenchMarkCrypto >("TestData/dlie2048.dat", "DLIES 2048", t); + BenchMarkCrypto >("TestData/lucc1024.dat", "LUCELG 1024", t); + } + + std::cout << "\n"; + { + BenchMarkSignature >("TestData/rsa1024.dat", "RSA 1024", t); + BenchMarkSignature >("TestData/rw1024.dat", "RW 1024", t); + BenchMarkSignature >("TestData/luc1024.dat", "LUC 1024", t); + BenchMarkSignature >("TestData/nr1024.dat", "NR 1024", t); + BenchMarkSignature("TestData/dsa1024.dat", "DSA 1024", t); + BenchMarkSignature >("TestData/lucs512.dat", "LUC-HMP 512", t); + BenchMarkSignature >("TestData/esig1023.dat", "ESIGN 1023", t); + BenchMarkSignature >("TestData/esig1536.dat", "ESIGN 1536", t); + } + + std::cout << "\n"; + { + BenchMarkSignature >("TestData/rsa2048.dat", "RSA 2048", t); + BenchMarkSignature >("TestData/rw2048.dat", "RW 2048", t); + BenchMarkSignature >("TestData/luc2048.dat", "LUC 2048", t); + BenchMarkSignature >("TestData/nr2048.dat", "NR 2048", t); + BenchMarkSignature >("TestData/lucs1024.dat", "LUC-HMP 1024", t); + BenchMarkSignature >("TestData/esig2046.dat", "ESIGN 2046", t); + } + + std::cout << "\n"; + { + BenchMarkKeyAgreement("TestData/xtrdh171.dat", "XTR-DH 171", t); + BenchMarkKeyAgreement("TestData/xtrdh342.dat", "XTR-DH 342", t); + BenchMarkKeyAgreement("TestData/dh1024.dat", "DH 1024", t); + BenchMarkKeyAgreement("TestData/dh2048.dat", "DH 2048", t); + BenchMarkKeyAgreement("TestData/lucd512.dat", "LUCDIF 512", t); + BenchMarkKeyAgreement("TestData/lucd1024.dat", "LUCDIF 1024", t); + BenchMarkKeyAgreement("TestData/mqv1024.dat", "MQV 1024", t); + BenchMarkKeyAgreement("TestData/mqv2048.dat", "MQV 2048", t); + } + + std::cout << "\n
OperationMilliseconds/Operation" << mco; + + std::cout << "\n
" << std::endl; +} + +void BenchmarkEllipticCurveAlgorithms(double t, double hertz) +{ + g_allocatedTime = t; + g_hertz = hertz; + + const char *mco; + if (g_hertz > 1.0f) + mco = "Megacycles/Operation"; + else + mco = ""; + + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + std::cout << "\n"; + { + ed25519::Signer sign(Test::GlobalRNG()); + ed25519::Verifier verify(sign); + x25519 agree(Test::GlobalRNG()); + + BenchMarkSigning("ed25519", sign, t); + BenchMarkVerification("ed25519", sign, verify, t); + BenchMarkKeyGen("x25519", agree, t); + BenchMarkAgreement("x25519", agree, t); + } + +#if 0 + std::cout << "\n"; + { + BenchMarkKeyAgreement("TestData/mqv160.dat", "MQV P-160", t); + BenchMarkKeyAgreement("TestData/mqv256.dat", "MQV P-256", t); + BenchMarkKeyAgreement("TestData/mqv384.dat", "MQV P-384", t); + BenchMarkKeyAgreement("TestData/mqv512.dat", "MQV P-521", t); + + BenchMarkKeyAgreement("TestData/hmqv160.dat", "HMQV P-160", t); + BenchMarkKeyAgreement("TestData/hmqv256.dat", "HMQV P-256", t); + BenchMarkKeyAgreement("TestData/hmqv384.dat", "HMQV P-384", t); + BenchMarkKeyAgreement("TestData/hmqv512.dat", "HMQV P-521", t); + + BenchMarkKeyAgreement("TestData/fhmqv160.dat", "FHMQV P-160", t); + BenchMarkKeyAgreement("TestData/fhmqv256.dat", "FHMQV P-256", t); + BenchMarkKeyAgreement("TestData/fhmqv384.dat", "FHMQV P-384", t); + BenchMarkKeyAgreement("TestData/fhmqv512.dat", "FHMQV P-521", t); + } +#endif + + std::cout << "\n"; + { + ECIES::Decryptor cpriv(Test::GlobalRNG(), ASN1::secp256k1()); + ECIES::Encryptor cpub(cpriv); + ECDSA::Signer spriv(cpriv); + ECDSA::Verifier spub(spriv); + ECDSA_RFC6979::Signer spriv2(cpriv); + ECDSA_RFC6979::Verifier spub2(spriv); + ECGDSA::Signer spriv3(Test::GlobalRNG(), ASN1::secp256k1()); + ECGDSA::Verifier spub3(spriv3); + ECDH::Domain ecdhc(ASN1::secp256k1()); + ECMQV::Domain ecmqvc(ASN1::secp256k1()); + + BenchMarkEncryption("ECIES over GF(p) 256", cpub, t); + BenchMarkDecryption("ECIES over GF(p) 256", cpriv, cpub, t); + BenchMarkSigning("ECDSA over GF(p) 256", spriv, t); + BenchMarkVerification("ECDSA over GF(p) 256", spriv, spub, t); + BenchMarkSigning("ECDSA-RFC6979 over GF(p) 256", spriv2, t); + BenchMarkVerification("ECDSA-RFC6979 over GF(p) 256", spriv2, spub2, t); + BenchMarkSigning("ECGDSA over GF(p) 256", spriv3, t); + BenchMarkVerification("ECGDSA over GF(p) 256", spriv3, spub3, t); + BenchMarkKeyGen("ECDHC over GF(p) 256", ecdhc, t); + BenchMarkAgreement("ECDHC over GF(p) 256", ecdhc, t); + BenchMarkKeyGen("ECMQVC over GF(p) 256", ecmqvc, t); + BenchMarkAgreement("ECMQVC over GF(p) 256", ecmqvc, t); + } + + std::cout << "\n"; + { + ECIES::Decryptor cpriv(Test::GlobalRNG(), ASN1::sect233r1()); + ECIES::Encryptor cpub(cpriv); + ECDSA::Signer spriv(cpriv); + ECDSA::Verifier spub(spriv); + ECDSA_RFC6979::Signer spriv2(cpriv); + ECDSA_RFC6979::Verifier spub2(spriv); + ECGDSA::Signer spriv3(Test::GlobalRNG(), ASN1::sect233r1()); + ECGDSA::Verifier spub3(spriv3); + ECDH::Domain ecdhc(ASN1::sect233r1()); + ECMQV::Domain ecmqvc(ASN1::sect233r1()); + + BenchMarkEncryption("ECIES over GF(2^n) 233", cpub, t); + BenchMarkDecryption("ECIES over GF(2^n) 233", cpriv, cpub, t); + BenchMarkSigning("ECDSA over GF(2^n) 233", spriv, t); + BenchMarkVerification("ECDSA over GF(2^n) 233", spriv, spub, t); + BenchMarkSigning("ECDSA-RFC6979 over GF(2^n) 233", spriv2, t); + BenchMarkVerification("ECDSA-RFC6979 over GF(2^n) 233", spriv2, spub2, t); + BenchMarkSigning("ECGDSA over GF(2^n) 233", spriv3, t); + BenchMarkVerification("ECGDSA over GF(2^n) 233", spriv3, spub3, t); + BenchMarkKeyGen("ECDHC over GF(2^n) 233", ecdhc, t); + BenchMarkAgreement("ECDHC over GF(2^n) 233", ecdhc, t); + BenchMarkKeyGen("ECMQVC over GF(2^n) 233", ecmqvc, t); + BenchMarkAgreement("ECMQVC over GF(2^n) 233", ecmqvc, t); + } + + std::cout << "\n
OperationMilliseconds/Operation" << mco; + + std::cout << "\n
" << std::endl; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/bfinit.cpp b/extension/third_party/cryptopp/bfinit.cpp new file mode 100644 index 00000000..06db2096 --- /dev/null +++ b/extension/third_party/cryptopp/bfinit.cpp @@ -0,0 +1,277 @@ +#include "pch.h" +#include "blowfish.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 Blowfish::Base::p_init[Blowfish::ROUNDS+2] = +{ + 608135816U, 2242054355U, 320440878U, 57701188U, + 2752067618U, 698298832U, 137296536U, 3964562569U, + 1160258022U, 953160567U, 3193202383U, 887688300U, + 3232508343U, 3380367581U, 1065670069U, 3041331479U, + 2450970073U, 2306472731U +} ; + +const word32 Blowfish::Base::s_init[4*256] = { + 3509652390U, 2564797868U, 805139163U, 3491422135U, + 3101798381U, 1780907670U, 3128725573U, 4046225305U, + 614570311U, 3012652279U, 134345442U, 2240740374U, + 1667834072U, 1901547113U, 2757295779U, 4103290238U, + 227898511U, 1921955416U, 1904987480U, 2182433518U, + 2069144605U, 3260701109U, 2620446009U, 720527379U, + 3318853667U, 677414384U, 3393288472U, 3101374703U, + 2390351024U, 1614419982U, 1822297739U, 2954791486U, + 3608508353U, 3174124327U, 2024746970U, 1432378464U, + 3864339955U, 2857741204U, 1464375394U, 1676153920U, + 1439316330U, 715854006U, 3033291828U, 289532110U, + 2706671279U, 2087905683U, 3018724369U, 1668267050U, + 732546397U, 1947742710U, 3462151702U, 2609353502U, + 2950085171U, 1814351708U, 2050118529U, 680887927U, + 999245976U, 1800124847U, 3300911131U, 1713906067U, + 1641548236U, 4213287313U, 1216130144U, 1575780402U, + 4018429277U, 3917837745U, 3693486850U, 3949271944U, + 596196993U, 3549867205U, 258830323U, 2213823033U, + 772490370U, 2760122372U, 1774776394U, 2652871518U, + 566650946U, 4142492826U, 1728879713U, 2882767088U, + 1783734482U, 3629395816U, 2517608232U, 2874225571U, + 1861159788U, 326777828U, 3124490320U, 2130389656U, + 2716951837U, 967770486U, 1724537150U, 2185432712U, + 2364442137U, 1164943284U, 2105845187U, 998989502U, + 3765401048U, 2244026483U, 1075463327U, 1455516326U, + 1322494562U, 910128902U, 469688178U, 1117454909U, + 936433444U, 3490320968U, 3675253459U, 1240580251U, + 122909385U, 2157517691U, 634681816U, 4142456567U, + 3825094682U, 3061402683U, 2540495037U, 79693498U, + 3249098678U, 1084186820U, 1583128258U, 426386531U, + 1761308591U, 1047286709U, 322548459U, 995290223U, + 1845252383U, 2603652396U, 3431023940U, 2942221577U, + 3202600964U, 3727903485U, 1712269319U, 422464435U, + 3234572375U, 1170764815U, 3523960633U, 3117677531U, + 1434042557U, 442511882U, 3600875718U, 1076654713U, + 1738483198U, 4213154764U, 2393238008U, 3677496056U, + 1014306527U, 4251020053U, 793779912U, 2902807211U, + 842905082U, 4246964064U, 1395751752U, 1040244610U, + 2656851899U, 3396308128U, 445077038U, 3742853595U, + 3577915638U, 679411651U, 2892444358U, 2354009459U, + 1767581616U, 3150600392U, 3791627101U, 3102740896U, + 284835224U, 4246832056U, 1258075500U, 768725851U, + 2589189241U, 3069724005U, 3532540348U, 1274779536U, + 3789419226U, 2764799539U, 1660621633U, 3471099624U, + 4011903706U, 913787905U, 3497959166U, 737222580U, + 2514213453U, 2928710040U, 3937242737U, 1804850592U, + 3499020752U, 2949064160U, 2386320175U, 2390070455U, + 2415321851U, 4061277028U, 2290661394U, 2416832540U, + 1336762016U, 1754252060U, 3520065937U, 3014181293U, + 791618072U, 3188594551U, 3933548030U, 2332172193U, + 3852520463U, 3043980520U, 413987798U, 3465142937U, + 3030929376U, 4245938359U, 2093235073U, 3534596313U, + 375366246U, 2157278981U, 2479649556U, 555357303U, + 3870105701U, 2008414854U, 3344188149U, 4221384143U, + 3956125452U, 2067696032U, 3594591187U, 2921233993U, + 2428461U, 544322398U, 577241275U, 1471733935U, + 610547355U, 4027169054U, 1432588573U, 1507829418U, + 2025931657U, 3646575487U, 545086370U, 48609733U, + 2200306550U, 1653985193U, 298326376U, 1316178497U, + 3007786442U, 2064951626U, 458293330U, 2589141269U, + 3591329599U, 3164325604U, 727753846U, 2179363840U, + 146436021U, 1461446943U, 4069977195U, 705550613U, + 3059967265U, 3887724982U, 4281599278U, 3313849956U, + 1404054877U, 2845806497U, 146425753U, 1854211946U, + + 1266315497U, 3048417604U, 3681880366U, 3289982499U, + 2909710000U, 1235738493U, 2632868024U, 2414719590U, + 3970600049U, 1771706367U, 1449415276U, 3266420449U, + 422970021U, 1963543593U, 2690192192U, 3826793022U, + 1062508698U, 1531092325U, 1804592342U, 2583117782U, + 2714934279U, 4024971509U, 1294809318U, 4028980673U, + 1289560198U, 2221992742U, 1669523910U, 35572830U, + 157838143U, 1052438473U, 1016535060U, 1802137761U, + 1753167236U, 1386275462U, 3080475397U, 2857371447U, + 1040679964U, 2145300060U, 2390574316U, 1461121720U, + 2956646967U, 4031777805U, 4028374788U, 33600511U, + 2920084762U, 1018524850U, 629373528U, 3691585981U, + 3515945977U, 2091462646U, 2486323059U, 586499841U, + 988145025U, 935516892U, 3367335476U, 2599673255U, + 2839830854U, 265290510U, 3972581182U, 2759138881U, + 3795373465U, 1005194799U, 847297441U, 406762289U, + 1314163512U, 1332590856U, 1866599683U, 4127851711U, + 750260880U, 613907577U, 1450815602U, 3165620655U, + 3734664991U, 3650291728U, 3012275730U, 3704569646U, + 1427272223U, 778793252U, 1343938022U, 2676280711U, + 2052605720U, 1946737175U, 3164576444U, 3914038668U, + 3967478842U, 3682934266U, 1661551462U, 3294938066U, + 4011595847U, 840292616U, 3712170807U, 616741398U, + 312560963U, 711312465U, 1351876610U, 322626781U, + 1910503582U, 271666773U, 2175563734U, 1594956187U, + 70604529U, 3617834859U, 1007753275U, 1495573769U, + 4069517037U, 2549218298U, 2663038764U, 504708206U, + 2263041392U, 3941167025U, 2249088522U, 1514023603U, + 1998579484U, 1312622330U, 694541497U, 2582060303U, + 2151582166U, 1382467621U, 776784248U, 2618340202U, + 3323268794U, 2497899128U, 2784771155U, 503983604U, + 4076293799U, 907881277U, 423175695U, 432175456U, + 1378068232U, 4145222326U, 3954048622U, 3938656102U, + 3820766613U, 2793130115U, 2977904593U, 26017576U, + 3274890735U, 3194772133U, 1700274565U, 1756076034U, + 4006520079U, 3677328699U, 720338349U, 1533947780U, + 354530856U, 688349552U, 3973924725U, 1637815568U, + 332179504U, 3949051286U, 53804574U, 2852348879U, + 3044236432U, 1282449977U, 3583942155U, 3416972820U, + 4006381244U, 1617046695U, 2628476075U, 3002303598U, + 1686838959U, 431878346U, 2686675385U, 1700445008U, + 1080580658U, 1009431731U, 832498133U, 3223435511U, + 2605976345U, 2271191193U, 2516031870U, 1648197032U, + 4164389018U, 2548247927U, 300782431U, 375919233U, + 238389289U, 3353747414U, 2531188641U, 2019080857U, + 1475708069U, 455242339U, 2609103871U, 448939670U, + 3451063019U, 1395535956U, 2413381860U, 1841049896U, + 1491858159U, 885456874U, 4264095073U, 4001119347U, + 1565136089U, 3898914787U, 1108368660U, 540939232U, + 1173283510U, 2745871338U, 3681308437U, 4207628240U, + 3343053890U, 4016749493U, 1699691293U, 1103962373U, + 3625875870U, 2256883143U, 3830138730U, 1031889488U, + 3479347698U, 1535977030U, 4236805024U, 3251091107U, + 2132092099U, 1774941330U, 1199868427U, 1452454533U, + 157007616U, 2904115357U, 342012276U, 595725824U, + 1480756522U, 206960106U, 497939518U, 591360097U, + 863170706U, 2375253569U, 3596610801U, 1814182875U, + 2094937945U, 3421402208U, 1082520231U, 3463918190U, + 2785509508U, 435703966U, 3908032597U, 1641649973U, + 2842273706U, 3305899714U, 1510255612U, 2148256476U, + 2655287854U, 3276092548U, 4258621189U, 236887753U, + 3681803219U, 274041037U, 1734335097U, 3815195456U, + 3317970021U, 1899903192U, 1026095262U, 4050517792U, + 356393447U, 2410691914U, 3873677099U, 3682840055U, + + 3913112168U, 2491498743U, 4132185628U, 2489919796U, + 1091903735U, 1979897079U, 3170134830U, 3567386728U, + 3557303409U, 857797738U, 1136121015U, 1342202287U, + 507115054U, 2535736646U, 337727348U, 3213592640U, + 1301675037U, 2528481711U, 1895095763U, 1721773893U, + 3216771564U, 62756741U, 2142006736U, 835421444U, + 2531993523U, 1442658625U, 3659876326U, 2882144922U, + 676362277U, 1392781812U, 170690266U, 3921047035U, + 1759253602U, 3611846912U, 1745797284U, 664899054U, + 1329594018U, 3901205900U, 3045908486U, 2062866102U, + 2865634940U, 3543621612U, 3464012697U, 1080764994U, + 553557557U, 3656615353U, 3996768171U, 991055499U, + 499776247U, 1265440854U, 648242737U, 3940784050U, + 980351604U, 3713745714U, 1749149687U, 3396870395U, + 4211799374U, 3640570775U, 1161844396U, 3125318951U, + 1431517754U, 545492359U, 4268468663U, 3499529547U, + 1437099964U, 2702547544U, 3433638243U, 2581715763U, + 2787789398U, 1060185593U, 1593081372U, 2418618748U, + 4260947970U, 69676912U, 2159744348U, 86519011U, + 2512459080U, 3838209314U, 1220612927U, 3339683548U, + 133810670U, 1090789135U, 1078426020U, 1569222167U, + 845107691U, 3583754449U, 4072456591U, 1091646820U, + 628848692U, 1613405280U, 3757631651U, 526609435U, + 236106946U, 48312990U, 2942717905U, 3402727701U, + 1797494240U, 859738849U, 992217954U, 4005476642U, + 2243076622U, 3870952857U, 3732016268U, 765654824U, + 3490871365U, 2511836413U, 1685915746U, 3888969200U, + 1414112111U, 2273134842U, 3281911079U, 4080962846U, + 172450625U, 2569994100U, 980381355U, 4109958455U, + 2819808352U, 2716589560U, 2568741196U, 3681446669U, + 3329971472U, 1835478071U, 660984891U, 3704678404U, + 4045999559U, 3422617507U, 3040415634U, 1762651403U, + 1719377915U, 3470491036U, 2693910283U, 3642056355U, + 3138596744U, 1364962596U, 2073328063U, 1983633131U, + 926494387U, 3423689081U, 2150032023U, 4096667949U, + 1749200295U, 3328846651U, 309677260U, 2016342300U, + 1779581495U, 3079819751U, 111262694U, 1274766160U, + 443224088U, 298511866U, 1025883608U, 3806446537U, + 1145181785U, 168956806U, 3641502830U, 3584813610U, + 1689216846U, 3666258015U, 3200248200U, 1692713982U, + 2646376535U, 4042768518U, 1618508792U, 1610833997U, + 3523052358U, 4130873264U, 2001055236U, 3610705100U, + 2202168115U, 4028541809U, 2961195399U, 1006657119U, + 2006996926U, 3186142756U, 1430667929U, 3210227297U, + 1314452623U, 4074634658U, 4101304120U, 2273951170U, + 1399257539U, 3367210612U, 3027628629U, 1190975929U, + 2062231137U, 2333990788U, 2221543033U, 2438960610U, + 1181637006U, 548689776U, 2362791313U, 3372408396U, + 3104550113U, 3145860560U, 296247880U, 1970579870U, + 3078560182U, 3769228297U, 1714227617U, 3291629107U, + 3898220290U, 166772364U, 1251581989U, 493813264U, + 448347421U, 195405023U, 2709975567U, 677966185U, + 3703036547U, 1463355134U, 2715995803U, 1338867538U, + 1343315457U, 2802222074U, 2684532164U, 233230375U, + 2599980071U, 2000651841U, 3277868038U, 1638401717U, + 4028070440U, 3237316320U, 6314154U, 819756386U, + 300326615U, 590932579U, 1405279636U, 3267499572U, + 3150704214U, 2428286686U, 3959192993U, 3461946742U, + 1862657033U, 1266418056U, 963775037U, 2089974820U, + 2263052895U, 1917689273U, 448879540U, 3550394620U, + 3981727096U, 150775221U, 3627908307U, 1303187396U, + 508620638U, 2975983352U, 2726630617U, 1817252668U, + 1876281319U, 1457606340U, 908771278U, 3720792119U, + 3617206836U, 2455994898U, 1729034894U, 1080033504U, + + 976866871U, 3556439503U, 2881648439U, 1522871579U, + 1555064734U, 1336096578U, 3548522304U, 2579274686U, + 3574697629U, 3205460757U, 3593280638U, 3338716283U, + 3079412587U, 564236357U, 2993598910U, 1781952180U, + 1464380207U, 3163844217U, 3332601554U, 1699332808U, + 1393555694U, 1183702653U, 3581086237U, 1288719814U, + 691649499U, 2847557200U, 2895455976U, 3193889540U, + 2717570544U, 1781354906U, 1676643554U, 2592534050U, + 3230253752U, 1126444790U, 2770207658U, 2633158820U, + 2210423226U, 2615765581U, 2414155088U, 3127139286U, + 673620729U, 2805611233U, 1269405062U, 4015350505U, + 3341807571U, 4149409754U, 1057255273U, 2012875353U, + 2162469141U, 2276492801U, 2601117357U, 993977747U, + 3918593370U, 2654263191U, 753973209U, 36408145U, + 2530585658U, 25011837U, 3520020182U, 2088578344U, + 530523599U, 2918365339U, 1524020338U, 1518925132U, + 3760827505U, 3759777254U, 1202760957U, 3985898139U, + 3906192525U, 674977740U, 4174734889U, 2031300136U, + 2019492241U, 3983892565U, 4153806404U, 3822280332U, + 352677332U, 2297720250U, 60907813U, 90501309U, + 3286998549U, 1016092578U, 2535922412U, 2839152426U, + 457141659U, 509813237U, 4120667899U, 652014361U, + 1966332200U, 2975202805U, 55981186U, 2327461051U, + 676427537U, 3255491064U, 2882294119U, 3433927263U, + 1307055953U, 942726286U, 933058658U, 2468411793U, + 3933900994U, 4215176142U, 1361170020U, 2001714738U, + 2830558078U, 3274259782U, 1222529897U, 1679025792U, + 2729314320U, 3714953764U, 1770335741U, 151462246U, + 3013232138U, 1682292957U, 1483529935U, 471910574U, + 1539241949U, 458788160U, 3436315007U, 1807016891U, + 3718408830U, 978976581U, 1043663428U, 3165965781U, + 1927990952U, 4200891579U, 2372276910U, 3208408903U, + 3533431907U, 1412390302U, 2931980059U, 4132332400U, + 1947078029U, 3881505623U, 4168226417U, 2941484381U, + 1077988104U, 1320477388U, 886195818U, 18198404U, + 3786409000U, 2509781533U, 112762804U, 3463356488U, + 1866414978U, 891333506U, 18488651U, 661792760U, + 1628790961U, 3885187036U, 3141171499U, 876946877U, + 2693282273U, 1372485963U, 791857591U, 2686433993U, + 3759982718U, 3167212022U, 3472953795U, 2716379847U, + 445679433U, 3561995674U, 3504004811U, 3574258232U, + 54117162U, 3331405415U, 2381918588U, 3769707343U, + 4154350007U, 1140177722U, 4074052095U, 668550556U, + 3214352940U, 367459370U, 261225585U, 2610173221U, + 4209349473U, 3468074219U, 3265815641U, 314222801U, + 3066103646U, 3808782860U, 282218597U, 3406013506U, + 3773591054U, 379116347U, 1285071038U, 846784868U, + 2669647154U, 3771962079U, 3550491691U, 2305946142U, + 453669953U, 1268987020U, 3317592352U, 3279303384U, + 3744833421U, 2610507566U, 3859509063U, 266596637U, + 3847019092U, 517658769U, 3462560207U, 3443424879U, + 370717030U, 4247526661U, 2224018117U, 4143653529U, + 4112773975U, 2788324899U, 2477274417U, 1456262402U, + 2901442914U, 1517677493U, 1846949527U, 2295493580U, + 3734397586U, 2176403920U, 1280348187U, 1908823572U, + 3871786941U, 846861322U, 1172426758U, 3287448474U, + 3383383037U, 1655181056U, 3139813346U, 901632758U, + 1897031941U, 2986607138U, 3066810236U, 3447102507U, + 1393639104U, 373351379U, 950779232U, 625454576U, + 3124240540U, 4148612726U, 2007998917U, 544563296U, + 2244738638U, 2330496472U, 2058025392U, 1291430526U, + 424198748U, 50039436U, 29584100U, 3605783033U, + 2429876329U, 2791104160U, 1057563949U, 3255363231U, + 3075367218U, 3463963227U, 1469046755U, 985887462U +}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/blake2.cpp b/extension/third_party/cryptopp/blake2.cpp new file mode 100644 index 00000000..3504f131 --- /dev/null +++ b/extension/third_party/cryptopp/blake2.cpp @@ -0,0 +1,797 @@ +// blake2.cpp - written and placed in the public domain by Jeffrey Walton +// and Zooko Wilcox-O'Hearn. Based on Aumasson, Neves, +// Wilcox-O'Hearn and Winnerlein's reference BLAKE2 +// implementation at http://github.com/BLAKE2/BLAKE2. +// +// The BLAKE2b and BLAKE2s numbers are consistent with the BLAKE2 team's +// numbers. However, we have an Altivec implementation of BLAKE2s, +// and a POWER8 implementation of BLAKE2b (BLAKE2 team is missing them). +// Altivec code is about 2x faster than C++ when using GCC 5.0 or +// above. The POWER8 code is about 2.5x faster than C++ when using GCC 5.0 +// or above. If you use GCC 4.0 (PowerMac) or GCC 4.8 (GCC Compile Farm) +// then the PowerPC code will be slower than C++. Be sure to use GCC 5.0 +// or above for PowerPC builds or disable Altivec for BLAKE2b and BLAKE2s +// if using the old compilers. + +#include "pch.h" +#include "config.h" +#include "cryptlib.h" +#include "argnames.h" +#include "algparam.h" +#include "blake2.h" +#include "cpu.h" + +// Uncomment for benchmarking C++ against SSE2 or NEON. +// Do so in both blake2.cpp and blake2_simd.cpp. +// #undef CRYPTOPP_SSE41_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE +// #undef CRYPTOPP_ALTIVEC_AVAILABLE +// #undef CRYPTOPP_POWER8_AVAILABLE + +// Disable NEON/ASIMD for Cortex-A53 and A57. The shifts are too slow and C/C++ is about +// 3 cpb faster than NEON/ASIMD. Also see http://github.com/weidai11/cryptopp/issues/367. +#if (defined(__aarch32__) || defined(__aarch64__)) && defined(CRYPTOPP_SLOW_ARMV8_SHIFT) +# undef CRYPTOPP_ARM_NEON_AVAILABLE +#endif + +// BLAKE2s bug on AIX 7.1 (POWER7) with XLC 12.01 +// https://github.com/weidai11/cryptopp/issues/743 +#if defined(__xlC__) && (__xlC__ < 0x0d01) +# define CRYPTOPP_DISABLE_ALTIVEC 1 +# undef CRYPTOPP_POWER7_AVAILABLE +# undef CRYPTOPP_POWER8_AVAILABLE +# undef CRYPTOPP_ALTIVEC_AVAILABLE +#endif + +// Can't use GetAlignmentOf() because of C++11 and constexpr +// Can use 'const unsigned int' because of MSVC 2013 +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# define ALIGN_SPEC32 16 +# define ALIGN_SPEC64 16 +#else +# define ALIGN_SPEC32 4 +# define ALIGN_SPEC64 8 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// Export the tables to the SIMD files +extern const word32 BLAKE2S_IV[8]; +extern const word64 BLAKE2B_IV[8]; + +CRYPTOPP_ALIGN_DATA(ALIGN_SPEC32) +const word32 BLAKE2S_IV[8] = { + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +CRYPTOPP_ALIGN_DATA(ALIGN_SPEC64) +const word64 BLAKE2B_IV[8] = { + W64LIT(0x6a09e667f3bcc908), W64LIT(0xbb67ae8584caa73b), + W64LIT(0x3c6ef372fe94f82b), W64LIT(0xa54ff53a5f1d36f1), + W64LIT(0x510e527fade682d1), W64LIT(0x9b05688c2b3e6c1f), + W64LIT(0x1f83d9abfb41bd6b), W64LIT(0x5be0cd19137e2179) +}; + +NAMESPACE_END + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::rotrConstant; + +CRYPTOPP_ALIGN_DATA(ALIGN_SPEC32) +const byte BLAKE2S_SIGMA[10][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, +}; + +CRYPTOPP_ALIGN_DATA(ALIGN_SPEC32) +const byte BLAKE2B_SIGMA[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +template +inline void BLAKE2B_G(const word64 m[16], word64& a, word64& b, word64& c, word64& d) +{ + a = a + b + m[BLAKE2B_SIGMA[R][2*N+0]]; + d = rotrConstant<32>(d ^ a); + c = c + d; + b = rotrConstant<24>(b ^ c); + a = a + b + m[BLAKE2B_SIGMA[R][2*N+1]]; + d = rotrConstant<16>(d ^ a); + c = c + d; + b = rotrConstant<63>(b ^ c); +} + +template +inline void BLAKE2B_ROUND(const word64 m[16], word64 v[16]) +{ + BLAKE2B_G(m,v[ 0],v[ 4],v[ 8],v[12]); + BLAKE2B_G(m,v[ 1],v[ 5],v[ 9],v[13]); + BLAKE2B_G(m,v[ 2],v[ 6],v[10],v[14]); + BLAKE2B_G(m,v[ 3],v[ 7],v[11],v[15]); + BLAKE2B_G(m,v[ 0],v[ 5],v[10],v[15]); + BLAKE2B_G(m,v[ 1],v[ 6],v[11],v[12]); + BLAKE2B_G(m,v[ 2],v[ 7],v[ 8],v[13]); + BLAKE2B_G(m,v[ 3],v[ 4],v[ 9],v[14]); +} + +template +inline void BLAKE2S_G(const word32 m[16], word32& a, word32& b, word32& c, word32& d) +{ + a = a + b + m[BLAKE2S_SIGMA[R][2*N+0]]; + d = rotrConstant<16>(d ^ a); + c = c + d; + b = rotrConstant<12>(b ^ c); + a = a + b + m[BLAKE2S_SIGMA[R][2*N+1]]; + d = rotrConstant<8>(d ^ a); + c = c + d; + b = rotrConstant<7>(b ^ c); +} + +template +inline void BLAKE2S_ROUND(const word32 m[16], word32 v[]) +{ + BLAKE2S_G(m,v[ 0],v[ 4],v[ 8],v[12]); + BLAKE2S_G(m,v[ 1],v[ 5],v[ 9],v[13]); + BLAKE2S_G(m,v[ 2],v[ 6],v[10],v[14]); + BLAKE2S_G(m,v[ 3],v[ 7],v[11],v[15]); + BLAKE2S_G(m,v[ 0],v[ 5],v[10],v[15]); + BLAKE2S_G(m,v[ 1],v[ 6],v[11],v[12]); + BLAKE2S_G(m,v[ 2],v[ 7],v[ 8],v[13]); + BLAKE2S_G(m,v[ 3],v[ 4],v[ 9],v[14]); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void BLAKE2_Compress32_CXX(const byte* input, BLAKE2s_State& state); +void BLAKE2_Compress64_CXX(const byte* input, BLAKE2b_State& state); + +#if CRYPTOPP_SSE41_AVAILABLE +extern void BLAKE2_Compress32_SSE4(const byte* input, BLAKE2s_State& state); +extern void BLAKE2_Compress64_SSE4(const byte* input, BLAKE2b_State& state); +#endif + +#if CRYPTOPP_ARM_NEON_AVAILABLE +extern void BLAKE2_Compress32_NEON(const byte* input, BLAKE2s_State& state); +extern void BLAKE2_Compress64_NEON(const byte* input, BLAKE2b_State& state); +#endif + +#if CRYPTOPP_ALTIVEC_AVAILABLE +extern void BLAKE2_Compress32_ALTIVEC(const byte* input, BLAKE2s_State& state); +#endif + +#if CRYPTOPP_POWER8_AVAILABLE +extern void BLAKE2_Compress64_POWER8(const byte* input, BLAKE2b_State& state); +#endif + +unsigned int BLAKE2b::OptimalDataAlignment() const +{ +#if defined(CRYPTOPP_SSE41_AVAILABLE) + if (HasSSE41()) + return 16; // load __m128i + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return 8; // load uint64x2_t + else +#endif +#if (CRYPTOPP_POWER8_AVAILABLE) + if (HasPower8()) + return 16; // load vector long long + else +#endif + return GetAlignmentOf(); +} + +std::string BLAKE2b::AlgorithmProvider() const +{ +#if defined(CRYPTOPP_SSE41_AVAILABLE) + if (HasSSE41()) + return "SSE4.1"; + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; + else +#endif +#if (CRYPTOPP_POWER8_AVAILABLE) + if (HasPower8()) + return "Power8"; + else +#endif + return "C++"; +} + +unsigned int BLAKE2s::OptimalDataAlignment() const +{ +#if defined(CRYPTOPP_SSE41_AVAILABLE) + if (HasSSE41()) + return 16; // load __m128i + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return 4; // load uint32x4_t + else +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return 16; // load vector unsigned int + else +#endif + return GetAlignmentOf(); +} + +std::string BLAKE2s::AlgorithmProvider() const +{ +#if defined(CRYPTOPP_SSE41_AVAILABLE) + if (HasSSE41()) + return "SSE4.1"; + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; + else +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return "Altivec"; + else +#endif + return "C++"; +} + +void BLAKE2s_State::Reset() +{ + std::memset(m_hft, 0x00, m_hft.SizeInBytes()); + m_len = 0; +} + +void BLAKE2b_State::Reset() +{ + std::memset(m_hft, 0x00, m_hft.SizeInBytes()); + m_len = 0; +} + +BLAKE2s_ParameterBlock::BLAKE2s_ParameterBlock(size_t digestLen, size_t keyLen, + const byte* saltStr, size_t saltLen, + const byte* personalizationStr, size_t personalizationLen) +{ + Reset(digestLen, keyLen); + + if (saltStr && saltLen) + memcpy_s(salt(), SALTSIZE, saltStr, saltLen); + + if (personalizationStr && personalizationLen) + memcpy_s(personalization(), PERSONALIZATIONSIZE, personalizationStr, personalizationLen); +} + +BLAKE2b_ParameterBlock::BLAKE2b_ParameterBlock(size_t digestLen, size_t keyLen, + const byte* saltStr, size_t saltLen, + const byte* personalizationStr, size_t personalizationLen) +{ + Reset(digestLen, keyLen); + + if (saltStr && saltLen) + memcpy_s(salt(), SALTSIZE, saltStr, saltLen); + + if (personalizationStr && personalizationLen) + memcpy_s(personalization(), PERSONALIZATIONSIZE, personalizationStr, personalizationLen); +} + +void BLAKE2s_ParameterBlock::Reset(size_t digestLen, size_t keyLen) +{ + std::memset(m_data, 0x00, m_data.size()); + m_data[DigestOff] = static_cast(digestLen); + m_data[KeyOff] = static_cast(keyLen); + m_data[FanoutOff] = m_data[DepthOff] = 1; +} + +void BLAKE2b_ParameterBlock::Reset(size_t digestLen, size_t keyLen) +{ + std::memset(m_data, 0x00, m_data.size()); + m_data[DigestOff] = static_cast(digestLen); + m_data[KeyOff] = static_cast(keyLen); + m_data[FanoutOff] = m_data[DepthOff] = 1; +} + +BLAKE2s::BLAKE2s(bool treeMode, unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(0), m_treeMode(treeMode) +{ + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + + UncheckedSetKey(NULLPTR, 0, MakeParameters + (Name::DigestSize(), (int)digestSize) + (Name::TreeMode(), treeMode)); +} + +BLAKE2b::BLAKE2b(bool treeMode, unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(0), m_treeMode(treeMode) +{ + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + + UncheckedSetKey(NULLPTR, 0, MakeParameters + (Name::DigestSize(), (int)digestSize) + (Name::TreeMode(), treeMode)); +} + +BLAKE2s::BLAKE2s(unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(0), m_treeMode(false) +{ + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + + UncheckedSetKey(NULLPTR, 0, MakeParameters + (Name::DigestSize(), (int)digestSize) + (Name::TreeMode(), false)); +} + +BLAKE2b::BLAKE2b(unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(0), m_treeMode(false) +{ + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + + UncheckedSetKey(NULLPTR, 0, MakeParameters + (Name::DigestSize(), (int)digestSize) + (Name::TreeMode(), false)); +} + +BLAKE2s::BLAKE2s(const byte *key, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength, bool treeMode, unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(static_cast(keyLength)), m_treeMode(treeMode) +{ + CRYPTOPP_ASSERT(keyLength <= MAX_KEYLENGTH); + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + CRYPTOPP_ASSERT(saltLength <= SALTSIZE); + CRYPTOPP_ASSERT(personalizationLength <= PERSONALIZATIONSIZE); + + UncheckedSetKey(key, static_cast(keyLength), MakeParameters + (Name::DigestSize(),(int)digestSize) + (Name::TreeMode(),treeMode) + (Name::Salt(), ConstByteArrayParameter(salt, saltLength)) + (Name::Personalization(), ConstByteArrayParameter(personalization, personalizationLength))); +} + +BLAKE2b::BLAKE2b(const byte *key, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength, bool treeMode, unsigned int digestSize) + : m_digestSize(digestSize), m_keyLength(static_cast(keyLength)), m_treeMode(treeMode) +{ + CRYPTOPP_ASSERT(keyLength <= MAX_KEYLENGTH); + CRYPTOPP_ASSERT(digestSize <= DIGESTSIZE); + CRYPTOPP_ASSERT(saltLength <= SALTSIZE); + CRYPTOPP_ASSERT(personalizationLength <= PERSONALIZATIONSIZE); + + UncheckedSetKey(key, static_cast(keyLength), MakeParameters + (Name::DigestSize(),(int)digestSize) + (Name::TreeMode(),treeMode) + (Name::Salt(), ConstByteArrayParameter(salt, saltLength)) + (Name::Personalization(), ConstByteArrayParameter(personalization, personalizationLength))); +} + +void BLAKE2s::UncheckedSetKey(const byte *key, unsigned int length, const CryptoPP::NameValuePairs& params) +{ + if (key && length) + { + m_key.New(BLOCKSIZE); + std::memcpy(m_key, key, length); + std::memset(m_key + length, 0x00, BLOCKSIZE - length); + m_keyLength = length; + } + else + { + m_key.resize(0); + m_keyLength = 0; + } + + m_digestSize = static_cast(params.GetIntValueWithDefault( + Name::DigestSize(), static_cast(m_digestSize))); + + m_state.Reset(); + m_block.Reset(m_digestSize, m_keyLength); + (void)params.GetValue(Name::TreeMode(), m_treeMode); + + ConstByteArrayParameter t; + if (params.GetValue(Name::Salt(), t) && t.begin() && t.size()) + memcpy_s(m_block.salt(), SALTSIZE, t.begin(), t.size()); + + if (params.GetValue(Name::Personalization(), t) && t.begin() && t.size()) + memcpy_s(m_block.personalization(), PERSONALIZATIONSIZE, t.begin(), t.size()); + + Restart(); +} + +void BLAKE2b::UncheckedSetKey(const byte *key, unsigned int length, const CryptoPP::NameValuePairs& params) +{ + if (key && length) + { + m_key.New(BLOCKSIZE); + std::memcpy(m_key, key, length); + std::memset(m_key + length, 0x00, BLOCKSIZE - length); + m_keyLength = length; + } + else + { + m_key.resize(0); + m_keyLength = 0; + } + + m_digestSize = static_cast(params.GetIntValueWithDefault( + Name::DigestSize(), static_cast(m_digestSize))); + + m_state.Reset(); + m_block.Reset(m_digestSize, m_keyLength); + (void)params.GetValue(Name::TreeMode(), m_treeMode); + + ConstByteArrayParameter t; + if (params.GetValue(Name::Salt(), t) && t.begin() && t.size()) + memcpy_s(m_block.salt(), SALTSIZE, t.begin(), t.size()); + + if (params.GetValue(Name::Personalization(), t) && t.begin() && t.size()) + memcpy_s(m_block.personalization(), PERSONALIZATIONSIZE, t.begin(), t.size()); + + Restart(); +} + +void BLAKE2s::Restart() +{ + static const word32 zero[2] = {0,0}; + Restart(m_block, zero); +} + +void BLAKE2b::Restart() +{ + static const word64 zero[2] = {0,0}; + Restart(m_block, zero); +} + +void BLAKE2s::Restart(const BLAKE2s_ParameterBlock& block, const word32 counter[2]) +{ + // We take a counter as a parameter to allow customized state. + m_state.Reset(); + if (counter != NULLPTR) + { + word32* t = m_state.t(); + t[0] = counter[0]; + t[1] = counter[1]; + } + + // We take a parameter block as a parameter to allow customized state. + // Avoid the copy of the parameter block when we are passing our own block. + if (block.data() != m_block.data()) { + std::memcpy(m_block.data(), block.data(), m_block.size()); + } + + m_block.m_data[BLAKE2s_ParameterBlock::DigestOff] = (byte)m_digestSize; + m_block.m_data[BLAKE2s_ParameterBlock::KeyOff] = (byte)m_keyLength; + + const word32* iv = BLAKE2S_IV; + PutBlock put(m_block.data(), m_state.h()); + put(iv[0])(iv[1])(iv[2])(iv[3])(iv[4])(iv[5])(iv[6])(iv[7]); + + // When BLAKE2 is keyed, the input stream is simply {key || 0 || message}. + // The key is padded to a full Blocksize with 0. Key it during Restart to + // avoid FirstPut and friends. Key size == 0 means no key. + if (m_keyLength) + Update(m_key, BLOCKSIZE); +} + +void BLAKE2b::Restart(const BLAKE2b_ParameterBlock& block, const word64 counter[2]) +{ + // We take a counter as a parameter to allow customized state. + m_state.Reset(); + if (counter != NULLPTR) + { + word64* t = m_state.t(); + t[0] = counter[0]; + t[1] = counter[1]; + } + + // We take a parameter block as a parameter to allow customized state. + // Avoid the copy of the parameter block when we are passing our own block. + if (block.data() != m_block.data()) { + std::memcpy(m_block.data(), block.data(), m_block.size()); + } + + m_block.m_data[BLAKE2b_ParameterBlock::DigestOff] = (byte)m_digestSize; + m_block.m_data[BLAKE2b_ParameterBlock::KeyOff] = (byte)m_keyLength; + + const word64* iv = BLAKE2B_IV; + PutBlock put(m_block.data(), m_state.h()); + put(iv[0])(iv[1])(iv[2])(iv[3])(iv[4])(iv[5])(iv[6])(iv[7]); + + // When BLAKE2 is keyed, the input stream is simply {key || 0 || message}. + // The key is padded to a full Blocksize with 0. Key it during Restart to + // avoid FirstPut and friends. Key size == 0 means no key. + if (m_keyLength) + Update(m_key, BLOCKSIZE); +} + +void BLAKE2s::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(input != NULLPTR || length == 0); + + if (length > BLOCKSIZE - m_state.m_len) + { + if (m_state.m_len != 0) + { + // Complete current block + const size_t fill = BLOCKSIZE - m_state.m_len; + std::memcpy(m_state.m_buf+m_state.m_len, input, fill); + + IncrementCounter(BLOCKSIZE); + Compress(m_state.m_buf); + m_state.m_len = 0; + + length -= fill, input += fill; + } + + // Compress in-place to avoid copies + while (length > BLOCKSIZE) + { + IncrementCounter(BLOCKSIZE); + Compress(input); + length -= BLOCKSIZE, input += BLOCKSIZE; + } + } + + // Copy tail bytes + if (length) + { + CRYPTOPP_ASSERT(length <= BLOCKSIZE - m_state.m_len); + std::memcpy(m_state.m_buf+m_state.m_len, input, length); + m_state.m_len += static_cast(length); + } +} + +void BLAKE2b::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(input != NULLPTR || length == 0); + + if (length > BLOCKSIZE - m_state.m_len) + { + if (m_state.m_len != 0) + { + // Complete current block + const size_t fill = BLOCKSIZE - m_state.m_len; + std::memcpy(m_state.m_buf+m_state.m_len, input, fill); + + IncrementCounter(BLOCKSIZE); + Compress(m_state.m_buf); + m_state.m_len = 0; + + length -= fill, input += fill; + } + + // Compress in-place to avoid copies + while (length > BLOCKSIZE) + { + CRYPTOPP_ASSERT(m_state.m_len == 0); + IncrementCounter(BLOCKSIZE); + Compress(input); + length -= BLOCKSIZE, input += BLOCKSIZE; + } + } + + // Copy tail bytes + if (length) + { + CRYPTOPP_ASSERT(length <= BLOCKSIZE - m_state.m_len); + std::memcpy(m_state.m_buf + m_state.m_len, input, length); + m_state.m_len += static_cast(length); + } +} + +void BLAKE2s::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + this->ThrowIfInvalidTruncatedSize(size); + word32* f = m_state.f(); + + // Set last block unconditionally + f[0] = ~static_cast(0); + + // Set last node if tree mode + if (m_treeMode) + f[1] = ~static_cast(0); + + // Increment counter for tail bytes only + IncrementCounter(m_state.m_len); + + std::memset(m_state.m_buf + m_state.m_len, 0x00, BLOCKSIZE - m_state.m_len); + Compress(m_state.m_buf); + + // Copy to caller buffer + std::memcpy(hash, m_state.h(), size); + + Restart(); +} + +void BLAKE2b::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + this->ThrowIfInvalidTruncatedSize(size); + word64* f = m_state.f(); + + // Set last block unconditionally + f[0] = ~static_cast(0); + + // Set last node if tree mode + if (m_treeMode) + f[1] = ~static_cast(0); + + // Increment counter for tail bytes only + IncrementCounter(m_state.m_len); + + std::memset(m_state.m_buf + m_state.m_len, 0x00, BLOCKSIZE - m_state.m_len); + Compress(m_state.m_buf); + + // Copy to caller buffer + std::memcpy(hash, m_state.h(), size); + + Restart(); +} + +void BLAKE2s::IncrementCounter(size_t count) +{ + word32* t = m_state.t(); + t[0] += static_cast(count); + t[1] += !!(t[0] < count); +} + +void BLAKE2b::IncrementCounter(size_t count) +{ + word64* t = m_state.t(); + t[0] += static_cast(count); + t[1] += !!(t[0] < count); +} + +void BLAKE2s::Compress(const byte *input) +{ +#if CRYPTOPP_SSE41_AVAILABLE + if(HasSSE41()) + { + return BLAKE2_Compress32_SSE4(input, m_state); + } +#endif +#if CRYPTOPP_ARM_NEON_AVAILABLE + if(HasNEON()) + { + return BLAKE2_Compress32_NEON(input, m_state); + } +#endif +#if CRYPTOPP_ALTIVEC_AVAILABLE + if(HasAltivec()) + { + return BLAKE2_Compress32_ALTIVEC(input, m_state); + } +#endif + return BLAKE2_Compress32_CXX(input, m_state); +} + +void BLAKE2b::Compress(const byte *input) +{ +#if CRYPTOPP_SSE41_AVAILABLE + if(HasSSE41()) + { + return BLAKE2_Compress64_SSE4(input, m_state); + } +#endif +#if CRYPTOPP_ARM_NEON_AVAILABLE + if(HasNEON()) + { + return BLAKE2_Compress64_NEON(input, m_state); + } +#endif +#if CRYPTOPP_POWER8_AVAILABLE + if(HasPower8()) + { + return BLAKE2_Compress64_POWER8(input, m_state); + } +#endif + return BLAKE2_Compress64_CXX(input, m_state); +} + +void BLAKE2_Compress64_CXX(const byte* input, BLAKE2b_State& state) +{ + word64 m[16], v[16]; + + GetBlock get1(input); + get1(m[0])(m[1])(m[2])(m[3])(m[4])(m[5])(m[6])(m[7])(m[8])(m[9])(m[10])(m[11])(m[12])(m[13])(m[14])(m[15]); + + GetBlock get2(state.h()); + get2(v[0])(v[1])(v[2])(v[3])(v[4])(v[5])(v[6])(v[7]); + + const word64* iv = BLAKE2B_IV; + const word64* tf = state.t(); + v[ 8] = iv[0]; + v[ 9] = iv[1]; + v[10] = iv[2]; + v[11] = iv[3]; + v[12] = tf[0] ^ iv[4]; + v[13] = tf[1] ^ iv[5]; + v[14] = tf[2] ^ iv[6]; + v[15] = tf[3] ^ iv[7]; + + BLAKE2B_ROUND<0>(m, v); + BLAKE2B_ROUND<1>(m, v); + BLAKE2B_ROUND<2>(m, v); + BLAKE2B_ROUND<3>(m, v); + BLAKE2B_ROUND<4>(m, v); + BLAKE2B_ROUND<5>(m, v); + BLAKE2B_ROUND<6>(m, v); + BLAKE2B_ROUND<7>(m, v); + BLAKE2B_ROUND<8>(m, v); + BLAKE2B_ROUND<9>(m, v); + BLAKE2B_ROUND<10>(m, v); + BLAKE2B_ROUND<11>(m, v); + + word64* h = state.h(); + for (unsigned int i = 0; i < 8; ++i) + h[i] = h[i] ^ ConditionalByteReverse(LITTLE_ENDIAN_ORDER, v[i] ^ v[i + 8]); +} + +void BLAKE2_Compress32_CXX(const byte* input, BLAKE2s_State& state) +{ + word32 m[16], v[16]; + + GetBlock get1(input); + get1(m[0])(m[1])(m[2])(m[3])(m[4])(m[5])(m[6])(m[7])(m[8])(m[9])(m[10])(m[11])(m[12])(m[13])(m[14])(m[15]); + + GetBlock get2(state.h()); + get2(v[0])(v[1])(v[2])(v[3])(v[4])(v[5])(v[6])(v[7]); + + const word32* iv = BLAKE2S_IV; + const word32* tf = state.t(); + v[ 8] = iv[0]; + v[ 9] = iv[1]; + v[10] = iv[2]; + v[11] = iv[3]; + v[12] = tf[0] ^ iv[4]; + v[13] = tf[1] ^ iv[5]; + v[14] = tf[2] ^ iv[6]; + v[15] = tf[3] ^ iv[7]; + + BLAKE2S_ROUND<0>(m, v); + BLAKE2S_ROUND<1>(m, v); + BLAKE2S_ROUND<2>(m, v); + BLAKE2S_ROUND<3>(m, v); + BLAKE2S_ROUND<4>(m, v); + BLAKE2S_ROUND<5>(m, v); + BLAKE2S_ROUND<6>(m, v); + BLAKE2S_ROUND<7>(m, v); + BLAKE2S_ROUND<8>(m, v); + BLAKE2S_ROUND<9>(m, v); + + word32* h = state.h(); + for (unsigned int i = 0; i < 8; ++i) + h[i] = h[i] ^ ConditionalByteReverse(LITTLE_ENDIAN_ORDER, v[i] ^ v[i + 8]); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/blake2.h b/extension/third_party/cryptopp/blake2.h new file mode 100644 index 00000000..896421a8 --- /dev/null +++ b/extension/third_party/cryptopp/blake2.h @@ -0,0 +1,444 @@ +// blake2.h - written and placed in the public domain by Jeffrey Walton +// and Zooko Wilcox-O'Hearn. Based on Aumasson, Neves, +// Wilcox-O'Hearn and Winnerlein's reference BLAKE2 +// implementation at http://github.com/BLAKE2/BLAKE2. + +/// \file blake2.h +/// \brief Classes for BLAKE2b and BLAKE2s message digests and keyed message digests +/// \details This implementation follows Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// Static algorithm name return either "BLAKE2b" or "BLAKE2s". An object algorithm name follows +/// the naming described in RFC 7693, The +/// BLAKE2 Cryptographic Hash and Message Authentication Code (MAC). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 + +#ifndef CRYPTOPP_BLAKE2_H +#define CRYPTOPP_BLAKE2_H + +#include "cryptlib.h" +#include "secblock.h" +#include "seckey.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief BLAKE2s hash information +/// \since Crypto++ 5.6.4 +struct BLAKE2s_Info : public VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + typedef VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase; + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH); + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH); + + CRYPTOPP_CONSTANT(BLOCKSIZE = 64); + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + CRYPTOPP_CONSTANT(SALTSIZE = 8); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 8); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";} +}; + +/// \brief BLAKE2b hash information +/// \since Crypto++ 5.6.4 +struct BLAKE2b_Info : public VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + typedef VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase; + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH); + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH); + + CRYPTOPP_CONSTANT(BLOCKSIZE = 128); + CRYPTOPP_CONSTANT(DIGESTSIZE = 64); + CRYPTOPP_CONSTANT(SALTSIZE = 16); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 16); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";} +}; + +/// \brief BLAKE2s parameter block +struct CRYPTOPP_NO_VTABLE BLAKE2s_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE); + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE); + + BLAKE2s_ParameterBlock() + { + Reset(); + } + + BLAKE2s_ParameterBlock(size_t digestSize) + { + Reset(digestSize); + } + + BLAKE2s_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0); + + byte* data() { + return m_data.data(); + } + + const byte* data() const { + return m_data.data(); + } + + size_t size() const { + return m_data.size(); + } + + byte* salt() { + return m_data + SaltOff; + } + + byte* personalization() { + return m_data + PersonalizationOff; + } + + // Offsets into the byte array + enum { + DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8, + NodeDepthOff = 14, InnerOff = 15, SaltOff = 16, PersonalizationOff = 24 + }; + + FixedSizeAlignedSecBlock m_data; +}; + +/// \brief BLAKE2b parameter block +struct CRYPTOPP_NO_VTABLE BLAKE2b_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE); + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE); + + BLAKE2b_ParameterBlock() + { + Reset(); + } + + BLAKE2b_ParameterBlock(size_t digestSize) + { + Reset(digestSize); + } + + BLAKE2b_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0); + + byte* data() { + return m_data.data(); + } + + const byte* data() const { + return m_data.data(); + } + + size_t size() const { + return m_data.size(); + } + + byte* salt() { + return m_data + SaltOff; + } + + byte* personalization() { + return m_data + PersonalizationOff; + } + + // Offsets into the byte array + enum { + DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8, + NodeDepthOff = 16, InnerOff = 17, RfuOff = 18, SaltOff = 32, PersonalizationOff = 48 + }; + + FixedSizeAlignedSecBlock m_data; +}; + +/// \brief BLAKE2s state information +/// \since Crypto++ 5.6.4 +struct CRYPTOPP_NO_VTABLE BLAKE2s_State +{ + BLAKE2s_State() { + Reset(); + } + + void Reset(); + + inline word32* h() { + return m_hft.data(); + } + + inline word32* t() { + return m_hft.data() + 8; + } + + inline word32* f() { + return m_hft.data() + 10; + } + + inline byte* data() { + return m_buf.data(); + } + + // SSE4, Power7 and NEON depend upon t[] and f[] being side-by-side + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE); + FixedSizeAlignedSecBlock m_hft; + FixedSizeAlignedSecBlock m_buf; + size_t m_len; +}; + +/// \brief BLAKE2b state information +/// \since Crypto++ 5.6.4 +struct CRYPTOPP_NO_VTABLE BLAKE2b_State +{ + BLAKE2b_State() { + Reset(); + } + + void Reset(); + + inline word64* h() { + return m_hft.data(); + } + + inline word64* t() { + return m_hft.data() + 8; + } + + inline word64* f() { + return m_hft.data() + 10; + } + + inline byte* data() { + return m_buf.data(); + } + + // SSE4, Power8 and NEON depend upon t[] and f[] being side-by-side + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE); + FixedSizeAlignedSecBlock m_hft; + FixedSizeAlignedSecBlock m_buf; + size_t m_len; +}; + +/// \brief The BLAKE2s cryptographic hash function +/// \details BLAKE2s can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2s constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 +class BLAKE2s : public SimpleKeyingInterfaceImpl +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2s_Info::DEFAULT_KEYLENGTH); + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2s_Info::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2s_Info::MAX_KEYLENGTH); + + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE); + + typedef BLAKE2s_State State; + typedef BLAKE2s_ParameterBlock ParameterBlock; + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";} + + virtual ~BLAKE2s() {} + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + /// \since Crypto++ 5.6.4 + BLAKE2s(bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \details treeMode flag is set to false + /// \since Crypto++ 8.2 + BLAKE2s(unsigned int digestSize); + + /// \brief Construct a BLAKE2s hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as personalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + /// \since Crypto++ 5.6.4 + BLAKE2s(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Retrieve the object's name + /// \return the object's algorithm name following RFC 7693 + /// \details Object algorithm name follows the naming described in + /// RFC 7693, The BLAKE2 Cryptographic Hash and + /// Message Authentication Code (MAC). For example, "BLAKE2b-512" and "BLAKE2s-256". + std::string AlgorithmName() const {return std::string(BLAKE2s_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);} + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const; + + void Update(const byte *input, size_t length); + void Restart(); + + /// \brief Restart a hash with parameter block and counter + /// \param block parameter block + /// \param counter counter array + /// \details Parameter block is persisted across calls to Restart(). + void Restart(const BLAKE2s_ParameterBlock& block, const word32 counter[2]); + + /// \brief Set tree mode + /// \param mode the new tree mode + /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1]. + /// If treeMode=false (default), then State::f[1] is never set. If + /// treeMode=true, then State::f[1] is set when State::f[0] is set. + /// Tree mode is persisted across calls to Restart(). + void SetTreeMode(bool mode) {m_treeMode=mode;} + + /// \brief Get tree mode + /// \return the current tree mode + /// \details Tree mode is persisted across calls to Restart(). + bool GetTreeMode() const {return m_treeMode;} + + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's. + void Compress(const byte *input); + inline void IncrementCounter(size_t count=BLOCKSIZE); + + void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params); + +private: + State m_state; + ParameterBlock m_block; + AlignedSecByteBlock m_key; + word32 m_digestSize, m_keyLength; + bool m_treeMode; +}; + +/// \brief The BLAKE2b cryptographic hash function +/// \details BLAKE2b can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2b constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 +class BLAKE2b : public SimpleKeyingInterfaceImpl +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2b_Info::DEFAULT_KEYLENGTH); + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2b_Info::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2b_Info::MAX_KEYLENGTH); + + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE); + + typedef BLAKE2b_State State; + typedef BLAKE2b_ParameterBlock ParameterBlock; + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";} + + virtual ~BLAKE2b() {} + + /// \brief Construct a BLAKE2b hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + /// \since Crypto++ 5.6.4 + BLAKE2b(bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \details treeMode flag is set to false + /// \since Crypto++ 8.2 + BLAKE2b(unsigned int digestSize); + + /// \brief Construct a BLAKE2b hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as personalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + /// \since Crypto++ 5.6.4 + BLAKE2b(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Retrieve the object's name + /// \return the object's algorithm name following RFC 7693 + /// \details Object algorithm name follows the naming described in + /// RFC 7693, The BLAKE2 Cryptographic Hash and + /// Message Authentication Code (MAC). For example, "BLAKE2b-512" and "BLAKE2s-256". + std::string AlgorithmName() const {return std::string(BLAKE2b_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);} + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const; + + void Update(const byte *input, size_t length); + void Restart(); + + /// \brief Restart a hash with parameter block and counter + /// \param block parameter block + /// \param counter counter array + /// \details Parameter block is persisted across calls to Restart(). + void Restart(const BLAKE2b_ParameterBlock& block, const word64 counter[2]); + + /// \brief Set tree mode + /// \param mode the new tree mode + /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1]. + /// If treeMode=false (default), then State::f[1] is never set. If + /// treeMode=true, then State::f[1] is set when State::f[0] is set. + /// Tree mode is persisted across calls to Restart(). + void SetTreeMode(bool mode) {m_treeMode=mode;} + + /// \brief Get tree mode + /// \return the current tree mode + /// \details Tree mode is persisted across calls to Restart(). + bool GetTreeMode() const {return m_treeMode;} + + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + + // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's. + void Compress(const byte *input); + inline void IncrementCounter(size_t count=BLOCKSIZE); + + void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params); + +private: + State m_state; + ParameterBlock m_block; + AlignedSecByteBlock m_key; + word32 m_digestSize, m_keyLength; + bool m_treeMode; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/blake2b_simd.cpp b/extension/third_party/cryptopp/blake2b_simd.cpp new file mode 100644 index 00000000..f408b8fa --- /dev/null +++ b/extension/third_party/cryptopp/blake2b_simd.cpp @@ -0,0 +1,1276 @@ +// blake2_simd.cpp - written and placed in the public domain by +// Samuel Neves, Jeffrey Walton, Uri Blumenthal +// and Marcel Raad. +// +// This source file uses intrinsics to gain access to ARMv7a/ARMv8a +// NEON, Power8 and SSE4.1 instructions. A separate source file is +// needed because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "misc.h" +#include "blake2.h" + +// Uncomment for benchmarking C++ against SSE2 or NEON. +// Do so in both blake2.cpp and blake2_simd.cpp. +// #undef CRYPTOPP_SSE41_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE +// #undef CRYPTOPP_ALTIVEC_AVAILABLE + +// Disable NEON/ASIMD for Cortex-A53 and A57. The shifts are too slow and C/C++ is about +// 3 cpb faster than NEON/ASIMD. Also see http://github.com/weidai11/cryptopp/issues/367. +#if (defined(__aarch32__) || defined(__aarch64__)) && defined(CRYPTOPP_SLOW_ARMV8_SHIFT) +# undef CRYPTOPP_ARM_NEON_AVAILABLE +#endif + +// BLAKE2s bug on AIX 7.1 (POWER7) with XLC 12.01 +// https://github.com/weidai11/cryptopp/issues/743 +#if defined(__xlC__) && (__xlC__ < 0x0d01) +# define CRYPTOPP_DISABLE_ALTIVEC 1 +# undef CRYPTOPP_POWER8_AVAILABLE +# undef CRYPTOPP_ALTIVEC_AVAILABLE +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if (CRYPTOPP_SSE41_AVAILABLE) +# include +# include +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_POWER8_AVAILABLE) +# include "ppc_simd.h" +#endif + +#if defined(CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE) +/* Ignore "warning: vec_lvsl is deprecated..." */ +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char BLAKE2B_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// Exported by blake2.cpp +extern const word32 BLAKE2S_IV[8]; +extern const word64 BLAKE2B_IV[8]; + +#if CRYPTOPP_SSE41_AVAILABLE + +#define LOADU(p) _mm_loadu_si128((const __m128i *)(const void*)(p)) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(void*)(p), r) +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +void BLAKE2_Compress64_SSE4(const byte* input, BLAKE2b_State& state) +{ + #define BLAKE2B_LOAD_MSG_0_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m1); \ + b1 = _mm_unpacklo_epi64(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m0, m1); \ + b1 = _mm_unpackhi_epi64(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m5); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m5); \ + b1 = _mm_unpackhi_epi64(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m2); \ + b1 = _mm_unpackhi_epi64(m4, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_alignr_epi8(m3, m7, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_3(b0, b1) \ + do { \ + b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ + b1 = _mm_unpackhi_epi64(m5, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m1); \ + b1 = _mm_unpackhi_epi64(m3, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_1(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m6, m5, 8); \ + b1 = _mm_unpackhi_epi64(m2, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m0); \ + b1 = _mm_blend_epi16(m1, m6, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m5, m1, 0xF0); \ + b1 = _mm_unpackhi_epi64(m3, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m3); \ + b1 = _mm_alignr_epi8(m2, m0, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m3, m1); \ + b1 = _mm_unpackhi_epi64(m6, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m0); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m1, m2, 0xF0); \ + b1 = _mm_blend_epi16(m2, m7, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m3, m5); \ + b1 = _mm_unpacklo_epi64(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m2); \ + b1 = _mm_unpacklo_epi64(m1, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_2(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m0, m3, 0xF0); \ + b1 = _mm_blend_epi16(m2, m7, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m7, m5, 0xF0); \ + b1 = _mm_blend_epi16(m3, m1, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_4(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m6, m0, 8); \ + b1 = _mm_blend_epi16(m4, m6, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m1, m3); \ + b1 = _mm_unpacklo_epi64(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m5); \ + b1 = _mm_unpackhi_epi64(m5, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m2, m3, 0xF0); \ + b1 = _mm_unpackhi_epi64(m7, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m6, m2); \ + b1 = _mm_blend_epi16(m7, m4, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_1(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m6, m0, 0xF0); \ + b1 = _mm_unpacklo_epi64(m7, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m2, m7); \ + b1 = _mm_alignr_epi8(m5, m6, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m3); \ + b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m3, m1); \ + b1 = _mm_blend_epi16(m1, m5, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m6, m3); \ + b1 = _mm_blend_epi16(m6, m1, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_2(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m7, m5, 8); \ + b1 = _mm_unpackhi_epi64(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_3(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m2, m7); \ + b1 = _mm_unpacklo_epi64(m4, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m2); \ + b1 = _mm_unpacklo_epi64(m3, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m3, m7); \ + b1 = _mm_alignr_epi8(m0, m5, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m7, m4); \ + b1 = _mm_alignr_epi8(m4, m1, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_3(b0, b1) \ + do { \ + b0 = m6; \ + b1 = _mm_alignr_epi8(m5, m0, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_4(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m1, m3, 0xF0); \ + b1 = m2; \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_unpackhi_epi64(m3, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m1, m2); \ + b1 = _mm_blend_epi16(m3, m2, 0xF0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_3(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m7, m4); \ + b1 = _mm_unpackhi_epi64(m1, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_4(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m7, m5, 8); \ + b1 = _mm_unpacklo_epi64(m6, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m1); \ + b1 = _mm_unpacklo_epi64(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m0, m1); \ + b1 = _mm_unpackhi_epi64(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m5); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m5); \ + b1 = _mm_unpackhi_epi64(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m2); \ + b1 = _mm_unpackhi_epi64(m4, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_alignr_epi8(m3, m7, 8); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_3(b0, b1) \ + do { \ + b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ + b1 = _mm_unpackhi_epi64(m5, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m1); \ + b1 = _mm_unpackhi_epi64(m3, m1); \ + } while(0) + +#ifdef __XOP__ +# define MM_ROTI_EPI64(r, c) \ + _mm_roti_epi64(r, c) +#else +# define MM_ROTI_EPI64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) +#endif + +#define BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = MM_ROTI_EPI64(row4l, -32); \ + row4h = MM_ROTI_EPI64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = MM_ROTI_EPI64(row2l, -24); \ + row2h = MM_ROTI_EPI64(row2h, -24); + +#define BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = MM_ROTI_EPI64(row4l, -16); \ + row4h = MM_ROTI_EPI64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = MM_ROTI_EPI64(row2l, -63); \ + row2h = MM_ROTI_EPI64(row2h, -63); \ + +#define BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row4l;\ + t1 = row2l;\ + row4l = row3l;\ + row3l = row3h;\ + row3h = row4l;\ + row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \ + row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \ + row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \ + row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1)) + +#define BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row3l;\ + row3l = row3h;\ + row3h = t0;\ + t0 = row2l;\ + t1 = row4l;\ + row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \ + row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \ + row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \ + row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1)) + +#define BLAKE2B_ROUND(r) \ + BLAKE2B_LOAD_MSG_ ##r ##_1(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_2(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + BLAKE2B_LOAD_MSG_ ##r ##_3(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_4(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); + + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; + + const __m128i r16 = _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9); + const __m128i r24 = _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10); + + const __m128i m0 = LOADU(input + 00); + const __m128i m1 = LOADU(input + 16); + const __m128i m2 = LOADU(input + 32); + const __m128i m3 = LOADU(input + 48); + const __m128i m4 = LOADU(input + 64); + const __m128i m5 = LOADU(input + 80); + const __m128i m6 = LOADU(input + 96); + const __m128i m7 = LOADU(input + 112); + + row1l = LOADU(state.h()+0); + row1h = LOADU(state.h()+2); + row2l = LOADU(state.h()+4); + row2h = LOADU(state.h()+6); + row3l = LOADU(BLAKE2B_IV+0); + row3h = LOADU(BLAKE2B_IV+2); + row4l = _mm_xor_si128(LOADU(BLAKE2B_IV+4), LOADU(state.t()+0)); + row4h = _mm_xor_si128(LOADU(BLAKE2B_IV+6), LOADU(state.f()+0)); + + BLAKE2B_ROUND(0); + BLAKE2B_ROUND(1); + BLAKE2B_ROUND(2); + BLAKE2B_ROUND(3); + BLAKE2B_ROUND(4); + BLAKE2B_ROUND(5); + BLAKE2B_ROUND(6); + BLAKE2B_ROUND(7); + BLAKE2B_ROUND(8); + BLAKE2B_ROUND(9); + BLAKE2B_ROUND(10); + BLAKE2B_ROUND(11); + + row1l = _mm_xor_si128(row3l, row1l); + row1h = _mm_xor_si128(row3h, row1h); + STOREU(state.h()+0, _mm_xor_si128(LOADU(state.h()+0), row1l)); + STOREU(state.h()+2, _mm_xor_si128(LOADU(state.h()+2), row1h)); + row2l = _mm_xor_si128(row4l, row2l); + row2h = _mm_xor_si128(row4h, row2h); + STOREU(state.h()+4, _mm_xor_si128(LOADU(state.h()+4), row2l)); + STOREU(state.h()+6, _mm_xor_si128(LOADU(state.h()+6), row2h)); +} +#endif // CRYPTOPP_SSE41_AVAILABLE + +#if CRYPTOPP_ARM_NEON_AVAILABLE +void BLAKE2_Compress64_NEON(const byte* input, BLAKE2b_State& state) +{ + #define BLAKE2B_LOAD_MSG_0_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m1)); b1 = vcombine_u64(vget_low_u64(m2), vget_low_u64(m3)); } while(0) + + #define BLAKE2B_LOAD_MSG_0_2(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m0), vget_high_u64(m1)); b1 = vcombine_u64(vget_high_u64(m2), vget_high_u64(m3)); } while(0) + + #define BLAKE2B_LOAD_MSG_0_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m4), vget_low_u64(m5)); b1 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_0_4(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m5)); b1 = vcombine_u64(vget_high_u64(m6), vget_high_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_1_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m7), vget_low_u64(m2)); b1 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m6)); } while(0) + + #define BLAKE2B_LOAD_MSG_1_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m5), vget_low_u64(m4)); b1 = vextq_u64(m7, m3, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_1_3(b0, b1) \ + do { b0 = vextq_u64(m0, m0, 1); b1 = vcombine_u64(vget_high_u64(m5), vget_high_u64(m2)); } while(0) + + #define BLAKE2B_LOAD_MSG_1_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m1)); b1 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m1)); } while(0) + + #define BLAKE2B_LOAD_MSG_2_1(b0, b1) \ + do { b0 = vextq_u64(m5, m6, 1); b1 = vcombine_u64(vget_high_u64(m2), vget_high_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_2_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m4), vget_low_u64(m0)); b1 = vcombine_u64(vget_low_u64(m1), vget_high_u64(m6)); } while(0) + + #define BLAKE2B_LOAD_MSG_2_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m5), vget_high_u64(m1)); b1 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m4)); } while(0) + + #define BLAKE2B_LOAD_MSG_2_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m7), vget_low_u64(m3)); b1 = vextq_u64(m0, m2, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_3_1(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m1)); b1 = vcombine_u64(vget_high_u64(m6), vget_high_u64(m5)); } while(0) + + #define BLAKE2B_LOAD_MSG_3_2(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m0)); b1 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_3_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m1), vget_high_u64(m2)); b1 = vcombine_u64(vget_low_u64(m2), vget_high_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_3_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m3), vget_low_u64(m5)); b1 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m4)); } while(0) + + #define BLAKE2B_LOAD_MSG_4_1(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m2)); b1 = vcombine_u64(vget_low_u64(m1), vget_low_u64(m5)); } while(0) + + #define BLAKE2B_LOAD_MSG_4_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m0), vget_high_u64(m3)); b1 = vcombine_u64(vget_low_u64(m2), vget_high_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_4_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m7), vget_high_u64(m5)); b1 = vcombine_u64(vget_low_u64(m3), vget_high_u64(m1)); } while(0) + + #define BLAKE2B_LOAD_MSG_4_4(b0, b1) \ + do { b0 = vextq_u64(m0, m6, 1); b1 = vcombine_u64(vget_low_u64(m4), vget_high_u64(m6)); } while(0) + + #define BLAKE2B_LOAD_MSG_5_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m1), vget_low_u64(m3)); b1 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m4)); } while(0) + + #define BLAKE2B_LOAD_MSG_5_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m5)); b1 = vcombine_u64(vget_high_u64(m5), vget_high_u64(m1)); } while(0) + + #define BLAKE2B_LOAD_MSG_5_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m2), vget_high_u64(m3)); b1 = vcombine_u64(vget_high_u64(m7), vget_high_u64(m0)); } while(0) + + #define BLAKE2B_LOAD_MSG_5_4(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m6), vget_high_u64(m2)); b1 = vcombine_u64(vget_low_u64(m7), vget_high_u64(m4)); } while(0) + + #define BLAKE2B_LOAD_MSG_6_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m6), vget_high_u64(m0)); b1 = vcombine_u64(vget_low_u64(m7), vget_low_u64(m2)); } while(0) + + #define BLAKE2B_LOAD_MSG_6_2(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m2), vget_high_u64(m7)); b1 = vextq_u64(m6, m5, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_6_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m3)); b1 = vextq_u64(m4, m4, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_6_4(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m1)); b1 = vcombine_u64(vget_low_u64(m1), vget_high_u64(m5)); } while(0) + + #define BLAKE2B_LOAD_MSG_7_1(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m6), vget_high_u64(m3)); b1 = vcombine_u64(vget_low_u64(m6), vget_high_u64(m1)); } while(0) + + #define BLAKE2B_LOAD_MSG_7_2(b0, b1) \ + do { b0 = vextq_u64(m5, m7, 1); b1 = vcombine_u64(vget_high_u64(m0), vget_high_u64(m4)); } while(0) + + #define BLAKE2B_LOAD_MSG_7_3(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m2), vget_high_u64(m7)); b1 = vcombine_u64(vget_low_u64(m4), vget_low_u64(m1)); } while(0) + + #define BLAKE2B_LOAD_MSG_7_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m2)); b1 = vcombine_u64(vget_low_u64(m3), vget_low_u64(m5)); } while(0) + + #define BLAKE2B_LOAD_MSG_8_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m3), vget_low_u64(m7)); b1 = vextq_u64(m5, m0, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_8_2(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m7), vget_high_u64(m4)); b1 = vextq_u64(m1, m4, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_8_3(b0, b1) \ + do { b0 = m6; b1 = vextq_u64(m0, m5, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_8_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m1), vget_high_u64(m3)); b1 = m2; } while(0) + + #define BLAKE2B_LOAD_MSG_9_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m5), vget_low_u64(m4)); b1 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m0)); } while(0) + + #define BLAKE2B_LOAD_MSG_9_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m1), vget_low_u64(m2)); b1 = vcombine_u64(vget_low_u64(m3), vget_high_u64(m2)); } while(0) + + #define BLAKE2B_LOAD_MSG_9_3(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m7), vget_high_u64(m4)); b1 = vcombine_u64(vget_high_u64(m1), vget_high_u64(m6)); } while(0) + + #define BLAKE2B_LOAD_MSG_9_4(b0, b1) \ + do { b0 = vextq_u64(m5, m7, 1); b1 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m0)); } while(0) + + #define BLAKE2B_LOAD_MSG_10_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m0), vget_low_u64(m1)); b1 = vcombine_u64(vget_low_u64(m2), vget_low_u64(m3)); } while(0) + + #define BLAKE2B_LOAD_MSG_10_2(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m0), vget_high_u64(m1)); b1 = vcombine_u64(vget_high_u64(m2), vget_high_u64(m3)); } while(0) + + #define BLAKE2B_LOAD_MSG_10_3(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m4), vget_low_u64(m5)); b1 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_10_4(b0, b1) \ + do { b0 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m5)); b1 = vcombine_u64(vget_high_u64(m6), vget_high_u64(m7)); } while(0) + + #define BLAKE2B_LOAD_MSG_11_1(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m7), vget_low_u64(m2)); b1 = vcombine_u64(vget_high_u64(m4), vget_high_u64(m6)); } while(0) + + #define BLAKE2B_LOAD_MSG_11_2(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m5), vget_low_u64(m4)); b1 = vextq_u64(m7, m3, 1); } while(0) + + #define BLAKE2B_LOAD_MSG_11_3(b0, b1) \ + do { b0 = vextq_u64(m0, m0, 1); b1 = vcombine_u64(vget_high_u64(m5), vget_high_u64(m2)); } while(0) + + #define BLAKE2B_LOAD_MSG_11_4(b0, b1) \ + do { b0 = vcombine_u64(vget_low_u64(m6), vget_low_u64(m1)); b1 = vcombine_u64(vget_high_u64(m3), vget_high_u64(m1)); } while(0) + + #define vrorq_n_u64_32(x) vreinterpretq_u64_u32(vrev64q_u32(vreinterpretq_u32_u64((x)))) + + #define vrorq_n_u64_24(x) vcombine_u64( \ + vreinterpret_u64_u8(vext_u8(vreinterpret_u8_u64(vget_low_u64(x)), vreinterpret_u8_u64(vget_low_u64(x)), 3)), \ + vreinterpret_u64_u8(vext_u8(vreinterpret_u8_u64(vget_high_u64(x)), vreinterpret_u8_u64(vget_high_u64(x)), 3))) + + #define vrorq_n_u64_16(x) vcombine_u64( \ + vreinterpret_u64_u8(vext_u8(vreinterpret_u8_u64(vget_low_u64(x)), vreinterpret_u8_u64(vget_low_u64(x)), 2)), \ + vreinterpret_u64_u8(vext_u8(vreinterpret_u8_u64(vget_high_u64(x)), vreinterpret_u8_u64(vget_high_u64(x)), 2))) + + #define vrorq_n_u64_63(x) veorq_u64(vaddq_u64(x, x), vshrq_n_u64(x, 63)) + + #define BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + do { \ + row1l = vaddq_u64(vaddq_u64(row1l, b0), row2l); \ + row1h = vaddq_u64(vaddq_u64(row1h, b1), row2h); \ + row4l = veorq_u64(row4l, row1l); row4h = veorq_u64(row4h, row1h); \ + row4l = vrorq_n_u64_32(row4l); row4h = vrorq_n_u64_32(row4h); \ + row3l = vaddq_u64(row3l, row4l); row3h = vaddq_u64(row3h, row4h); \ + row2l = veorq_u64(row2l, row3l); row2h = veorq_u64(row2h, row3h); \ + row2l = vrorq_n_u64_24(row2l); row2h = vrorq_n_u64_24(row2h); \ + } while(0) + + #define BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + do { \ + row1l = vaddq_u64(vaddq_u64(row1l, b0), row2l); \ + row1h = vaddq_u64(vaddq_u64(row1h, b1), row2h); \ + row4l = veorq_u64(row4l, row1l); row4h = veorq_u64(row4h, row1h); \ + row4l = vrorq_n_u64_16(row4l); row4h = vrorq_n_u64_16(row4h); \ + row3l = vaddq_u64(row3l, row4l); row3h = vaddq_u64(row3h, row4h); \ + row2l = veorq_u64(row2l, row3l); row2h = veorq_u64(row2h, row3h); \ + row2l = vrorq_n_u64_63(row2l); row2h = vrorq_n_u64_63(row2h); \ + } while(0) + + #define BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + do { \ + uint64x2_t t0 = vextq_u64(row2l, row2h, 1); \ + uint64x2_t t1 = vextq_u64(row2h, row2l, 1); \ + row2l = t0; row2h = t1; t0 = row3l; row3l = row3h; row3h = t0; \ + t0 = vextq_u64(row4h, row4l, 1); t1 = vextq_u64(row4l, row4h, 1); \ + row4l = t0; row4h = t1; \ + } while(0) + + #define BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + do { \ + uint64x2_t t0 = vextq_u64(row2h, row2l, 1); \ + uint64x2_t t1 = vextq_u64(row2l, row2h, 1); \ + row2l = t0; row2h = t1; t0 = row3l; row3l = row3h; row3h = t0; \ + t0 = vextq_u64(row4l, row4h, 1); t1 = vextq_u64(row4h, row4l, 1); \ + row4l = t0; row4h = t1; \ + } while(0) + + #define BLAKE2B_ROUND(r) \ + do { \ + uint64x2_t b0, b1; \ + BLAKE2B_LOAD_MSG_ ##r ##_1(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_2(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + BLAKE2B_LOAD_MSG_ ##r ##_3(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_4(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + } while(0) + + const uint64x2_t m0 = vreinterpretq_u64_u8(vld1q_u8(input + 00)); + const uint64x2_t m1 = vreinterpretq_u64_u8(vld1q_u8(input + 16)); + const uint64x2_t m2 = vreinterpretq_u64_u8(vld1q_u8(input + 32)); + const uint64x2_t m3 = vreinterpretq_u64_u8(vld1q_u8(input + 48)); + const uint64x2_t m4 = vreinterpretq_u64_u8(vld1q_u8(input + 64)); + const uint64x2_t m5 = vreinterpretq_u64_u8(vld1q_u8(input + 80)); + const uint64x2_t m6 = vreinterpretq_u64_u8(vld1q_u8(input + 96)); + const uint64x2_t m7 = vreinterpretq_u64_u8(vld1q_u8(input + 112)); + + uint64x2_t row1l, row1h, row2l, row2h; + uint64x2_t row3l, row3h, row4l, row4h; + + const uint64x2_t h0 = row1l = vld1q_u64(state.h()+0); + const uint64x2_t h1 = row1h = vld1q_u64(state.h()+2); + const uint64x2_t h2 = row2l = vld1q_u64(state.h()+4); + const uint64x2_t h3 = row2h = vld1q_u64(state.h()+6); + + row3l = vld1q_u64(BLAKE2B_IV+0); + row3h = vld1q_u64(BLAKE2B_IV+2); + row4l = veorq_u64(vld1q_u64(BLAKE2B_IV+4), vld1q_u64(state.t()+0)); + row4h = veorq_u64(vld1q_u64(BLAKE2B_IV+6), vld1q_u64(state.f()+0)); + + BLAKE2B_ROUND(0); + BLAKE2B_ROUND(1); + BLAKE2B_ROUND(2); + BLAKE2B_ROUND(3); + BLAKE2B_ROUND(4); + BLAKE2B_ROUND(5); + BLAKE2B_ROUND(6); + BLAKE2B_ROUND(7); + BLAKE2B_ROUND(8); + BLAKE2B_ROUND(9); + BLAKE2B_ROUND(10); + BLAKE2B_ROUND(11); + + vst1q_u64(state.h()+0, veorq_u64(h0, veorq_u64(row1l, row3l))); + vst1q_u64(state.h()+2, veorq_u64(h1, veorq_u64(row1h, row3h))); + vst1q_u64(state.h()+4, veorq_u64(h2, veorq_u64(row2l, row4l))); + vst1q_u64(state.h()+6, veorq_u64(h3, veorq_u64(row2h, row4h))); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_POWER8_AVAILABLE) + +inline uint64x2_p VecLoad64(const void* p) +{ + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(p)); +} + +inline uint64x2_p VecLoad64LE(const void* p, const uint8x16_p le_mask) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p v = vec_xl(0, CONST_V32_CAST(p)); + return (uint64x2_p)VecPermute(v, v, le_mask); +#else + CRYPTOPP_UNUSED(le_mask); + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(p)); +#endif +} + +inline void VecStore64(void* p, const uint64x2_p x) +{ + vec_xst((uint32x4_p)x, 0, NCONST_V32_CAST(p)); +} + +inline void VecStore64LE(void* p, const uint64x2_p x, const uint8x16_p le_mask) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint64x2_p v = VecPermute(x, x, le_mask); + vec_xst((uint32x4_p)v, 0, NCONST_V32_CAST(p)); +#else + CRYPTOPP_UNUSED(le_mask); + vec_xst((uint32x4_p)x, 0, NCONST_V32_CAST(p)); +#endif +} + +#if defined(CRYPTOPP_BIG_ENDIAN) +#define vec_shl_8(a,b) (uint64x2_p)vec_sld((uint8x16_p)a,(uint8x16_p)b,8) +#else +#define vec_shl_8(a,b) (uint64x2_p)vec_sld((uint8x16_p)b,(uint8x16_p)a,8) +#endif + +#define vec_merge_hi(a, b) vec_mergeh(a,b) +#define vec_merge_hi_lo(a, b) vec_mergeh(a,(uint64x2_p)vec_sld((uint8x16_p)b,(uint8x16_p)b,8)) +#define vec_merge_lo(a, b) vec_mergel(a,b) + +void BLAKE2_Compress64_POWER8(const byte* input, BLAKE2b_State& state) +{ + #define BLAKE2B_LOAD_MSG_0_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m0, m1); \ + b1 = vec_merge_hi(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_2(b0, b1) \ + do { \ + b0 = vec_merge_lo(m0, m1); \ + b1 = vec_merge_lo(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_3(b0, b1) \ + do { \ + b0 = vec_merge_hi(m4, m5); \ + b1 = vec_merge_hi(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_0_4(b0, b1) \ + do { \ + b0 = vec_merge_lo(m4, m5); \ + b1 = vec_merge_lo(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m7, m2); \ + b1 = vec_merge_lo(m4, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_2(b0, b1) \ + do { \ + b0 = vec_merge_hi(m5, m4); \ + b1 = vec_shl_8(m7, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_3(b0, b1) \ + do { \ + b0 = vec_shl_8(m0, m0); \ + b1 = vec_merge_lo(m5, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_1_4(b0, b1) \ + do { \ + b0 = vec_merge_hi(m6, m1); \ + b1 = vec_merge_lo(m3, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_1(b0, b1) \ + do { \ + b0 = vec_shl_8(m5, m6); \ + b1 = vec_merge_lo(m2, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_2(b0, b1) \ + do { \ + b0 = vec_merge_hi(m4, m0); \ + b1 = vec_merge_hi_lo(m1, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_3(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m5, m1); \ + b1 = vec_merge_lo(m3, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_2_4(b0, b1) \ + do { \ + b0 = vec_merge_hi(m7, m3); \ + b1 = vec_shl_8(m0, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_1(b0, b1) \ + do { \ + b0 = vec_merge_lo(m3, m1); \ + b1 = vec_merge_lo(m6, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_2(b0, b1) \ + do { \ + b0 = vec_merge_lo(m4, m0); \ + b1 = vec_merge_hi(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_3(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m1, m2); \ + b1 = vec_merge_hi_lo(m2, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_3_4(b0, b1) \ + do { \ + b0 = vec_merge_hi(m3, m5); \ + b1 = vec_merge_hi(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_1(b0, b1) \ + do { \ + b0 = vec_merge_lo(m4, m2); \ + b1 = vec_merge_hi(m1, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_2(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m0, m3); \ + b1 = vec_merge_hi_lo(m2, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_3(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m7, m5); \ + b1 = vec_merge_hi_lo(m3, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_4_4(b0, b1) \ + do { \ + b0 = vec_shl_8(m0, m6); \ + b1 = vec_merge_hi_lo(m4, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m1, m3); \ + b1 = vec_merge_hi(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_2(b0, b1) \ + do { \ + b0 = vec_merge_hi(m6, m5); \ + b1 = vec_merge_lo(m5, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_3(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m2, m3); \ + b1 = vec_merge_lo(m7, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_5_4(b0, b1) \ + do { \ + b0 = vec_merge_lo(m6, m2); \ + b1 = vec_merge_hi_lo(m7, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_1(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m6, m0); \ + b1 = vec_merge_hi(m7, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_2(b0, b1) \ + do { \ + b0 = vec_merge_lo(m2, m7); \ + b1 = vec_shl_8(m6, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_3(b0, b1) \ + do { \ + b0 = vec_merge_hi(m0, m3); \ + b1 = vec_shl_8(m4, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_6_4(b0, b1) \ + do { \ + b0 = vec_merge_lo(m3, m1); \ + b1 = vec_merge_hi_lo(m1, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_1(b0, b1) \ + do { \ + b0 = vec_merge_lo(m6, m3); \ + b1 = vec_merge_hi_lo(m6, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_2(b0, b1) \ + do { \ + b0 = vec_shl_8(m5, m7); \ + b1 = vec_merge_lo(m0, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_3(b0, b1) \ + do { \ + b0 = vec_merge_lo(m2, m7); \ + b1 = vec_merge_hi(m4, m1); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_7_4(b0, b1) \ + do { \ + b0 = vec_merge_hi(m0, m2); \ + b1 = vec_merge_hi(m3, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m3, m7); \ + b1 = vec_shl_8(m5, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_2(b0, b1) \ + do { \ + b0 = vec_merge_lo(m7, m4); \ + b1 = vec_shl_8(m1, m4); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_3(b0, b1) \ + do { \ + b0 = m6; \ + b1 = vec_shl_8(m0, m5); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_8_4(b0, b1) \ + do { \ + b0 = vec_merge_hi_lo(m1, m3); \ + b1 = m2; \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m5, m4); \ + b1 = vec_merge_lo(m3, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_2(b0, b1) \ + do { \ + b0 = vec_merge_hi(m1, m2); \ + b1 = vec_merge_hi_lo(m3, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_3(b0, b1) \ + do { \ + b0 = vec_merge_lo(m7, m4); \ + b1 = vec_merge_lo(m1, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_9_4(b0, b1) \ + do { \ + b0 = vec_shl_8(m5, m7); \ + b1 = vec_merge_hi(m6, m0); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m0, m1); \ + b1 = vec_merge_hi(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_2(b0, b1) \ + do { \ + b0 = vec_merge_lo(m0, m1); \ + b1 = vec_merge_lo(m2, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_3(b0, b1) \ + do { \ + b0 = vec_merge_hi(m4, m5); \ + b1 = vec_merge_hi(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_10_4(b0, b1) \ + do { \ + b0 = vec_merge_lo(m4, m5); \ + b1 = vec_merge_lo(m6, m7); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_1(b0, b1) \ + do { \ + b0 = vec_merge_hi(m7, m2); \ + b1 = vec_merge_lo(m4, m6); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_2(b0, b1) \ + do { \ + b0 = vec_merge_hi(m5, m4); \ + b1 = vec_shl_8(m7, m3); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_3(b0, b1) \ + do { \ + b0 = vec_shl_8(m0, m0); \ + b1 = vec_merge_lo(m5, m2); \ + } while(0) + + #define BLAKE2B_LOAD_MSG_11_4(b0, b1) \ + do { \ + b0 = vec_merge_hi(m6, m1); \ + b1 = vec_merge_lo(m3, m1); \ + } while(0) + + // Power8 has packed 64-bit rotate, but in terms of left rotate + const uint64x2_p ROR16_MASK = { 64-16, 64-16 }; + const uint64x2_p ROR24_MASK = { 64-24, 64-24 }; + const uint64x2_p ROR32_MASK = { 64-32, 64-32 }; + const uint64x2_p ROR63_MASK = { 64-63, 64-63 }; + + #define vec_ror_32(x) vec_rl(x, ROR32_MASK) + #define vec_ror_24(x) vec_rl(x, ROR24_MASK) + #define vec_ror_16(x) vec_rl(x, ROR16_MASK) + #define vec_ror_63(x) vec_rl(x, ROR63_MASK) + + #define BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + do { \ + row1l = VecAdd(VecAdd(row1l, b0), row2l); \ + row1h = VecAdd(VecAdd(row1h, b1), row2h); \ + row4l = VecXor(row4l, row1l); row4h = VecXor(row4h, row1h); \ + row4l = vec_ror_32(row4l); row4h = vec_ror_32(row4h); \ + row3l = VecAdd(row3l, row4l); row3h = VecAdd(row3h, row4h); \ + row2l = VecXor(row2l, row3l); row2h = VecXor(row2h, row3h); \ + row2l = vec_ror_24(row2l); row2h = vec_ror_24(row2h); \ + } while(0) + + #define BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + do { \ + row1l = VecAdd(VecAdd(row1l, b0), row2l); \ + row1h = VecAdd(VecAdd(row1h, b1), row2h); \ + row4l = VecXor(row4l, row1l); row4h = VecXor(row4h, row1h); \ + row4l = vec_ror_16(row4l); row4h = vec_ror_16(row4h); \ + row3l = VecAdd(row3l, row4l); row3h = VecAdd(row3h, row4h); \ + row2l = VecXor(row2l, row3l); row2h = VecXor(row2h, row3h); \ + row2l = vec_ror_63(row2l); row2h = vec_ror_63(row2h); \ + } while(0) + + #define BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + do { \ + uint64x2_p t0 = vec_shl_8(row2l, row2h); \ + uint64x2_p t1 = vec_shl_8(row2h, row2l); \ + row2l = t0; row2h = t1; t0 = row3l; row3l = row3h; row3h = t0; \ + t0 = vec_shl_8(row4h, row4l); t1 = vec_shl_8(row4l, row4h); \ + row4l = t0; row4h = t1; \ + } while(0) + + #define BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + do { \ + uint64x2_p t0 = vec_shl_8(row2h, row2l); \ + uint64x2_p t1 = vec_shl_8(row2l, row2h); \ + row2l = t0; row2h = t1; t0 = row3l; row3l = row3h; row3h = t0; \ + t0 = vec_shl_8(row4l, row4h); t1 = vec_shl_8(row4h, row4l); \ + row4l = t0; row4h = t1; \ + } while(0) + + #define BLAKE2B_ROUND(r) \ + do { \ + uint64x2_p b0, b1; \ + BLAKE2B_LOAD_MSG_ ##r ##_1(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_2(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + BLAKE2B_LOAD_MSG_ ##r ##_3(b0, b1); \ + BLAKE2B_G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_LOAD_MSG_ ##r ##_4(b0, b1); \ + BLAKE2B_G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + BLAKE2B_UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + } while(0) + + // Possibly unaligned user messages + uint64x2_p m0, m1, m2, m3, m4, m5, m6, m7; + // Endian conversion mask + const uint8x16_p le_mask = {7,6,5,4, 3,2,1,0, 15,14,13,12, 11,10,9,8}; + +#if defined(_ARCH_PWR9) + // POWER9 provides loads for char's and short's + m0 = (uint64x2_p) vec_xl( 0, CONST_V8_CAST( input )); + m1 = (uint64x2_p) vec_xl( 16, CONST_V8_CAST( input )); + m2 = (uint64x2_p) vec_xl( 32, CONST_V8_CAST( input )); + m3 = (uint64x2_p) vec_xl( 48, CONST_V8_CAST( input )); + m4 = (uint64x2_p) vec_xl( 64, CONST_V8_CAST( input )); + m5 = (uint64x2_p) vec_xl( 80, CONST_V8_CAST( input )); + m6 = (uint64x2_p) vec_xl( 96, CONST_V8_CAST( input )); + m7 = (uint64x2_p) vec_xl(112, CONST_V8_CAST( input )); + +# if defined(CRYPTOPP_BIG_ENDIAN) + m0 = vec_perm(m0, m0, le_mask); + m1 = vec_perm(m1, m1, le_mask); + m2 = vec_perm(m2, m2, le_mask); + m3 = vec_perm(m3, m3, le_mask); + m4 = vec_perm(m4, m4, le_mask); + m5 = vec_perm(m5, m5, le_mask); + m6 = vec_perm(m6, m6, le_mask); + m7 = vec_perm(m7, m7, le_mask); +# endif +#else + // Altivec only provides 16-byte aligned loads + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + m0 = (uint64x2_p) vec_ld( 0, CONST_V8_CAST( input )); + m1 = (uint64x2_p) vec_ld( 16, CONST_V8_CAST( input )); + m2 = (uint64x2_p) vec_ld( 32, CONST_V8_CAST( input )); + m3 = (uint64x2_p) vec_ld( 48, CONST_V8_CAST( input )); + m4 = (uint64x2_p) vec_ld( 64, CONST_V8_CAST( input )); + m5 = (uint64x2_p) vec_ld( 80, CONST_V8_CAST( input )); + m6 = (uint64x2_p) vec_ld( 96, CONST_V8_CAST( input )); + m7 = (uint64x2_p) vec_ld(112, CONST_V8_CAST( input )); + + // Alignment check for load of the message buffer + const uintptr_t addr = (uintptr_t)input; + if (addr%16 == 0) + { + // Already aligned. Perform a little-endian swap as required +# if defined(CRYPTOPP_BIG_ENDIAN) + m0 = vec_perm(m0, m0, le_mask); + m1 = vec_perm(m1, m1, le_mask); + m2 = vec_perm(m2, m2, le_mask); + m3 = vec_perm(m3, m3, le_mask); + m4 = vec_perm(m4, m4, le_mask); + m5 = vec_perm(m5, m5, le_mask); + m6 = vec_perm(m6, m6, le_mask); + m7 = vec_perm(m7, m7, le_mask); +# endif + } + else + { + // Not aligned. Fix vectors and perform a little-endian swap as required + // http://mirror.informatimago.com/next/developer.apple.com/ + // hardwaredrivers/ve/code_optimization.html + uint64x2_p ex; uint8x16_p perm; + ex = (uint64x2_p) vec_ld(112+15, CONST_V8_CAST( input )); + perm = vec_lvsl(0, CONST_V8_CAST( addr )); + +# if defined(CRYPTOPP_BIG_ENDIAN) + // Combine the vector permute with the little-endian swap + perm = vec_perm(perm, perm, le_mask); +# endif + + m0 = vec_perm(m0, m1, perm); + m1 = vec_perm(m1, m2, perm); + m2 = vec_perm(m2, m3, perm); + m3 = vec_perm(m3, m4, perm); + m4 = vec_perm(m4, m5, perm); + m5 = vec_perm(m5, m6, perm); + m6 = vec_perm(m6, m7, perm); + m7 = vec_perm(m7, ex, perm); + } +#endif + + uint64x2_p row1l, row1h, row2l, row2h; + uint64x2_p row3l, row3h, row4l, row4h; + + const uint64x2_p h0 = row1l = VecLoad64LE(state.h()+0, le_mask); + const uint64x2_p h1 = row1h = VecLoad64LE(state.h()+2, le_mask); + const uint64x2_p h2 = row2l = VecLoad64LE(state.h()+4, le_mask); + const uint64x2_p h3 = row2h = VecLoad64LE(state.h()+6, le_mask); + + row3l = VecLoad64(BLAKE2B_IV+0); + row3h = VecLoad64(BLAKE2B_IV+2); + row4l = VecXor(VecLoad64(BLAKE2B_IV+4), VecLoad64(state.t()+0)); + row4h = VecXor(VecLoad64(BLAKE2B_IV+6), VecLoad64(state.f()+0)); + + BLAKE2B_ROUND(0); + BLAKE2B_ROUND(1); + BLAKE2B_ROUND(2); + BLAKE2B_ROUND(3); + BLAKE2B_ROUND(4); + BLAKE2B_ROUND(5); + BLAKE2B_ROUND(6); + BLAKE2B_ROUND(7); + BLAKE2B_ROUND(8); + BLAKE2B_ROUND(9); + BLAKE2B_ROUND(10); + BLAKE2B_ROUND(11); + + VecStore64LE(state.h()+0, VecXor(h0, VecXor(row1l, row3l)), le_mask); + VecStore64LE(state.h()+2, VecXor(h1, VecXor(row1h, row3h)), le_mask); + VecStore64LE(state.h()+4, VecXor(h2, VecXor(row2l, row4l)), le_mask); + VecStore64LE(state.h()+6, VecXor(h3, VecXor(row2h, row4h)), le_mask); +} +#endif // CRYPTOPP_POWER8_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/blake2s_simd.cpp b/extension/third_party/cryptopp/blake2s_simd.cpp new file mode 100644 index 00000000..4d00f609 --- /dev/null +++ b/extension/third_party/cryptopp/blake2s_simd.cpp @@ -0,0 +1,1091 @@ +// blake2_simd.cpp - written and placed in the public domain by +// Samuel Neves, Jeffrey Walton, Uri Blumenthal +// and Marcel Raad. +// +// This source file uses intrinsics to gain access to ARMv7a/ARMv8a +// NEON, Power7 and SSE4.1 instructions. A separate source file is +// needed because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. + +// The BLAKE2b and BLAKE2s numbers are consistent with the BLAKE2 team's +// numbers. However, we have an Altivec implementation of BLAKE2s, +// and a POWER8 implementation of BLAKE2b (BLAKE2 team is missing them). +// Altivec code is about 2x faster than C++ when using GCC 5.0 or +// above. The POWER8 code is about 2.5x faster than C++ when using GCC 5.0 +// or above. If you use GCC 4.0 (PowerMac) or GCC 4.8 (GCC Compile Farm) +// then the PowerPC code will be slower than C++. Be sure to use GCC 5.0 +// or above for PowerPC builds or disable Altivec for BLAKE2b and BLAKE2s +// if using the old compilers. + +#include "pch.h" +#include "config.h" +#include "misc.h" +#include "blake2.h" + +// Uncomment for benchmarking C++ against SSE2 or NEON. +// Do so in both blake2.cpp and blake2_simd.cpp. +// #undef CRYPTOPP_SSE41_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE +// #undef CRYPTOPP_ALTIVEC_AVAILABLE + +// Disable NEON/ASIMD for Cortex-A53 and A57. The shifts are too slow and C/C++ is about +// 3 cpb faster than NEON/ASIMD. Also see http://github.com/weidai11/cryptopp/issues/367. +#if (defined(__aarch32__) || defined(__aarch64__)) && defined(CRYPTOPP_SLOW_ARMV8_SHIFT) +# undef CRYPTOPP_ARM_NEON_AVAILABLE +#endif + +// BLAKE2s bug on AIX 7.1 (POWER7) with XLC 12.01 +// https://github.com/weidai11/cryptopp/issues/743 +#if defined(__xlC__) && (__xlC__ < 0x0d01) +# define CRYPTOPP_DISABLE_ALTIVEC 1 +# undef CRYPTOPP_POWER7_AVAILABLE +# undef CRYPTOPP_ALTIVEC_AVAILABLE +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if (CRYPTOPP_SSE41_AVAILABLE) +# include +# include +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +#if defined(CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE) +/* Ignore "warning: vec_lvsl is deprecated..." */ +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char BLAKE2S_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// Exported by blake2.cpp +extern const word32 BLAKE2S_IV[8]; +extern const word64 BLAKE2B_IV[8]; + +#if CRYPTOPP_SSE41_AVAILABLE + +#define LOADU(p) _mm_loadu_si128((const __m128i *)(const void*)(p)) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(void*)(p), r) +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +void BLAKE2_Compress32_SSE4(const byte* input, BLAKE2s_State& state) +{ + #define BLAKE2S_LOAD_MSG_0_1(buf) \ + buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(2,0,2,0))); + + #define BLAKE2S_LOAD_MSG_0_2(buf) \ + buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(3,1,3,1))); + + #define BLAKE2S_LOAD_MSG_0_3(buf) \ + t0 = _mm_shuffle_epi32(m2, _MM_SHUFFLE(3,2,0,1)); \ + t1 = _mm_shuffle_epi32(m3, _MM_SHUFFLE(0,1,3,2)); \ + buf = _mm_blend_epi16(t0, t1, 0xC3); + + #define BLAKE2S_LOAD_MSG_0_4(buf) \ + t0 = _mm_blend_epi16(t0, t1, 0x3C); \ + buf = _mm_shuffle_epi32(t0, _MM_SHUFFLE(2,3,0,1)); + + #define BLAKE2S_LOAD_MSG_1_1(buf) \ + t0 = _mm_blend_epi16(m1, m2, 0x0C); \ + t1 = _mm_slli_si128(m3, 4); \ + t2 = _mm_blend_epi16(t0, t1, 0xF0); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + + #define BLAKE2S_LOAD_MSG_1_2(buf) \ + t0 = _mm_shuffle_epi32(m2,_MM_SHUFFLE(0,0,2,0)); \ + t1 = _mm_blend_epi16(m1,m3,0xC0); \ + t2 = _mm_blend_epi16(t0, t1, 0xF0); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1)); + + #define BLAKE2S_LOAD_MSG_1_3(buf) \ + t0 = _mm_slli_si128(m1, 4); \ + t1 = _mm_blend_epi16(m2, t0, 0x30); \ + t2 = _mm_blend_epi16(m0, t1, 0xF0); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,0,1,2)); + + #define BLAKE2S_LOAD_MSG_1_4(buf) \ + t0 = _mm_unpackhi_epi32(m0,m1); \ + t1 = _mm_slli_si128(m3, 4); \ + t2 = _mm_blend_epi16(t0, t1, 0x0C); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,0,1,2)); + + #define BLAKE2S_LOAD_MSG_2_1(buf) \ + t0 = _mm_unpackhi_epi32(m2,m3); \ + t1 = _mm_blend_epi16(m3,m1,0x0C); \ + t2 = _mm_blend_epi16(t0, t1, 0x0F); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + + #define BLAKE2S_LOAD_MSG_2_2(buf) \ + t0 = _mm_unpacklo_epi32(m2,m0); \ + t1 = _mm_blend_epi16(t0, m0, 0xF0); \ + t2 = _mm_slli_si128(m3, 8); \ + buf = _mm_blend_epi16(t1, t2, 0xC0); + + #define BLAKE2S_LOAD_MSG_2_3(buf) \ + t0 = _mm_blend_epi16(m0, m2, 0x3C); \ + t1 = _mm_srli_si128(m1, 12); \ + t2 = _mm_blend_epi16(t0,t1,0x03); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(0,3,2,1)); + + #define BLAKE2S_LOAD_MSG_2_4(buf) \ + t0 = _mm_slli_si128(m3, 4); \ + t1 = _mm_blend_epi16(m0, m1, 0x33); \ + t2 = _mm_blend_epi16(t1, t0, 0xC0); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,2,3,0)); + + #define BLAKE2S_LOAD_MSG_3_1(buf) \ + t0 = _mm_unpackhi_epi32(m0,m1); \ + t1 = _mm_unpackhi_epi32(t0, m2); \ + t2 = _mm_blend_epi16(t1, m3, 0x0C); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + + #define BLAKE2S_LOAD_MSG_3_2(buf) \ + t0 = _mm_slli_si128(m2, 8); \ + t1 = _mm_blend_epi16(m3,m0,0x0C); \ + t2 = _mm_blend_epi16(t1, t0, 0xC0); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3)); + + #define BLAKE2S_LOAD_MSG_3_3(buf) \ + t0 = _mm_blend_epi16(m0,m1,0x0F); \ + t1 = _mm_blend_epi16(t0, m3, 0xC0); \ + buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(0,1,2,3)); + + #define BLAKE2S_LOAD_MSG_3_4(buf) \ + t0 = _mm_alignr_epi8(m0, m1, 4); \ + buf = _mm_blend_epi16(t0, m2, 0x33); + + #define BLAKE2S_LOAD_MSG_4_1(buf) \ + t0 = _mm_unpacklo_epi64(m1,m2); \ + t1 = _mm_unpackhi_epi64(m0,m2); \ + t2 = _mm_blend_epi16(t0,t1,0x33); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3)); + + #define BLAKE2S_LOAD_MSG_4_2(buf) \ + t0 = _mm_unpackhi_epi64(m1,m3); \ + t1 = _mm_unpacklo_epi64(m0,m1); \ + buf = _mm_blend_epi16(t0,t1,0x33); + + #define BLAKE2S_LOAD_MSG_4_3(buf) \ + t0 = _mm_unpackhi_epi64(m3,m1); \ + t1 = _mm_unpackhi_epi64(m2,m0); \ + t2 = _mm_blend_epi16(t1,t0,0x33); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + + #define BLAKE2S_LOAD_MSG_4_4(buf) \ + t0 = _mm_blend_epi16(m0,m2,0x03); \ + t1 = _mm_slli_si128(t0, 8); \ + t2 = _mm_blend_epi16(t1,m3,0x0F); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,3,1)); + + #define BLAKE2S_LOAD_MSG_5_1(buf) \ + t0 = _mm_unpackhi_epi32(m0,m1); \ + t1 = _mm_unpacklo_epi32(m0,m2); \ + buf = _mm_unpacklo_epi64(t0,t1); + + #define BLAKE2S_LOAD_MSG_5_2(buf) \ + t0 = _mm_srli_si128(m2, 4); \ + t1 = _mm_blend_epi16(m0,m3,0x03); \ + buf = _mm_blend_epi16(t1,t0,0x3C); + + #define BLAKE2S_LOAD_MSG_5_3(buf) \ + t0 = _mm_blend_epi16(m1,m0,0x0C); \ + t1 = _mm_srli_si128(m3, 4); \ + t2 = _mm_blend_epi16(t0,t1,0x30); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1)); + + #define BLAKE2S_LOAD_MSG_5_4(buf) \ + t0 = _mm_unpacklo_epi64(m2,m1); \ + t1 = _mm_shuffle_epi32(m3, _MM_SHUFFLE(2,0,1,0)); \ + t2 = _mm_srli_si128(t0, 4); \ + buf = _mm_blend_epi16(t1,t2,0x33); + + #define BLAKE2S_LOAD_MSG_6_1(buf) \ + t0 = _mm_slli_si128(m1, 12); \ + t1 = _mm_blend_epi16(m0,m3,0x33); \ + buf = _mm_blend_epi16(t1,t0,0xC0); + + #define BLAKE2S_LOAD_MSG_6_2(buf) \ + t0 = _mm_blend_epi16(m3,m2,0x30); \ + t1 = _mm_srli_si128(m1, 4); \ + t2 = _mm_blend_epi16(t0,t1,0x03); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,3,0)); + + #define BLAKE2S_LOAD_MSG_6_3(buf) \ + t0 = _mm_unpacklo_epi64(m0,m2); \ + t1 = _mm_srli_si128(m1, 4); \ + t2 = _mm_blend_epi16(t0,t1,0x0C); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + + #define BLAKE2S_LOAD_MSG_6_4(buf) \ + t0 = _mm_unpackhi_epi32(m1,m2); \ + t1 = _mm_unpackhi_epi64(m0,t0); \ + buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(0,1,2,3)); + + #define BLAKE2S_LOAD_MSG_7_1(buf) \ + t0 = _mm_unpackhi_epi32(m0,m1); \ + t1 = _mm_blend_epi16(t0,m3,0x0F); \ + buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(2,0,3,1)); + + #define BLAKE2S_LOAD_MSG_7_2(buf) \ + t0 = _mm_blend_epi16(m2,m3,0x30); \ + t1 = _mm_srli_si128(m0,4); \ + t2 = _mm_blend_epi16(t0,t1,0x03); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,0,2,3)); + + #define BLAKE2S_LOAD_MSG_7_3(buf) \ + t0 = _mm_unpackhi_epi64(m0,m3); \ + t1 = _mm_unpacklo_epi64(m1,m2); \ + t2 = _mm_blend_epi16(t0,t1,0x3C); \ + buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(2,3,1,0)); + + #define BLAKE2S_LOAD_MSG_7_4(buf) \ + t0 = _mm_unpacklo_epi32(m0,m1); \ + t1 = _mm_unpackhi_epi32(m1,m2); \ + t2 = _mm_unpacklo_epi64(t0,t1); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + + #define BLAKE2S_LOAD_MSG_8_1(buf) \ + t0 = _mm_unpackhi_epi32(m1,m3); \ + t1 = _mm_unpacklo_epi64(t0,m0); \ + t2 = _mm_blend_epi16(t1,m2,0xC0); \ + buf = _mm_shufflehi_epi16(t2,_MM_SHUFFLE(1,0,3,2)); + + #define BLAKE2S_LOAD_MSG_8_2(buf) \ + t0 = _mm_unpackhi_epi32(m0,m3); \ + t1 = _mm_blend_epi16(m2,t0,0xF0); \ + buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(0,2,1,3)); + + #define BLAKE2S_LOAD_MSG_8_3(buf) \ + t0 = _mm_unpacklo_epi64(m0,m3); \ + t1 = _mm_srli_si128(m2,8); \ + t2 = _mm_blend_epi16(t0,t1,0x03); \ + buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,3,2,0)); + + #define BLAKE2S_LOAD_MSG_8_4(buf) \ + t0 = _mm_blend_epi16(m1,m0,0x30); \ + buf = _mm_shuffle_epi32(t0,_MM_SHUFFLE(0,3,2,1)); + + #define BLAKE2S_LOAD_MSG_9_1(buf) \ + t0 = _mm_blend_epi16(m0,m2,0x03); \ + t1 = _mm_blend_epi16(m1,m2,0x30); \ + t2 = _mm_blend_epi16(t1,t0,0x0F); \ + buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(1,3,0,2)); + + #define BLAKE2S_LOAD_MSG_9_2(buf) \ + t0 = _mm_slli_si128(m0,4); \ + t1 = _mm_blend_epi16(m1,t0,0xC0); \ + buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(1,2,0,3)); + + #define BLAKE2S_LOAD_MSG_9_3(buf) \ + t0 = _mm_unpackhi_epi32(m0,m3); \ + t1 = _mm_unpacklo_epi32(m2,m3); \ + t2 = _mm_unpackhi_epi64(t0,t1); \ + buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(0,2,1,3)); + + #define BLAKE2S_LOAD_MSG_9_4(buf) \ + t0 = _mm_blend_epi16(m3,m2,0xC0); \ + t1 = _mm_unpacklo_epi32(m0,m3); \ + t2 = _mm_blend_epi16(t0,t1,0x0F); \ + buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(1,2,3,0)); + +#ifdef __XOP__ +# define MM_ROTI_EPI32(r, c) \ + _mm_roti_epi32(r, c) +#else +# define MM_ROTI_EPI32(r, c) ( \ + (8==-(c)) ? _mm_shuffle_epi8(r,r8) \ + : (16==-(c)) ? _mm_shuffle_epi8(r,r16) \ + : _mm_xor_si128(_mm_srli_epi32((r), -(c)), \ + _mm_slli_epi32((r), 32-(-(c))))) +#endif + +#define BLAKE2S_G1(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = MM_ROTI_EPI32(row4, -16); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = MM_ROTI_EPI32(row2, -12); + +#define BLAKE2S_G2(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = MM_ROTI_EPI32(row4, -8); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = MM_ROTI_EPI32(row2, -7); + +#define DIAGONALIZE(row1,row2,row3,row4) \ + row1 = _mm_shuffle_epi32( row1, _MM_SHUFFLE(2,1,0,3) ); \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(1,0,3,2) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(0,3,2,1) ); + +#define UNDIAGONALIZE(row1,row2,row3,row4) \ + row1 = _mm_shuffle_epi32( row1, _MM_SHUFFLE(0,3,2,1) ); \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(1,0,3,2) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(2,1,0,3) ); + +#define BLAKE2S_ROUND(r) \ + BLAKE2S_LOAD_MSG_ ##r ##_1(buf1); \ + BLAKE2S_G1(row1,row2,row3,row4,buf1); \ + BLAKE2S_LOAD_MSG_ ##r ##_2(buf2); \ + BLAKE2S_G2(row1,row2,row3,row4,buf2); \ + DIAGONALIZE(row1,row2,row3,row4); \ + BLAKE2S_LOAD_MSG_ ##r ##_3(buf3); \ + BLAKE2S_G1(row1,row2,row3,row4,buf3); \ + BLAKE2S_LOAD_MSG_ ##r ##_4(buf4); \ + BLAKE2S_G2(row1,row2,row3,row4,buf4); \ + UNDIAGONALIZE(row1,row2,row3,row4); + + __m128i row1, row2, row3, row4; + __m128i buf1, buf2, buf3, buf4; + __m128i t0, t1, t2, ff0, ff1; + + const __m128i r8 = _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1); + const __m128i r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + + const __m128i m0 = LOADU(input + 00); + const __m128i m1 = LOADU(input + 16); + const __m128i m2 = LOADU(input + 32); + const __m128i m3 = LOADU(input + 48); + + row1 = ff0 = LOADU(state.h()+0); + row2 = ff1 = LOADU(state.h()+4); + row3 = LOADU(BLAKE2S_IV+0); + row4 = _mm_xor_si128(LOADU(BLAKE2S_IV+4), LOADU(state.t()+0)); + + BLAKE2S_ROUND(0); + BLAKE2S_ROUND(1); + BLAKE2S_ROUND(2); + BLAKE2S_ROUND(3); + BLAKE2S_ROUND(4); + BLAKE2S_ROUND(5); + BLAKE2S_ROUND(6); + BLAKE2S_ROUND(7); + BLAKE2S_ROUND(8); + BLAKE2S_ROUND(9); + + STOREU(state.h()+0, _mm_xor_si128(ff0, _mm_xor_si128(row1, row3))); + STOREU(state.h()+4, _mm_xor_si128(ff1, _mm_xor_si128(row2, row4))); +} +#endif // CRYPTOPP_SSE41_AVAILABLE + +#if CRYPTOPP_ARM_NEON_AVAILABLE +void BLAKE2_Compress32_NEON(const byte* input, BLAKE2s_State& state) +{ + #define BLAKE2S_LOAD_MSG_0_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m0), vget_high_u32(m0)).val[0]; \ + t1 = vzip_u32(vget_low_u32(m1), vget_high_u32(m1)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_0_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m0), vget_high_u32(m0)).val[1]; \ + t1 = vzip_u32(vget_low_u32(m1), vget_high_u32(m1)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_0_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m2), vget_high_u32(m2)).val[0]; \ + t1 = vzip_u32(vget_low_u32(m3), vget_high_u32(m3)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_0_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m2), vget_high_u32(m2)).val[1]; \ + t1 = vzip_u32(vget_low_u32(m3), vget_high_u32(m3)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_1_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m3), vget_low_u32(m1)).val[0]; \ + t1 = vzip_u32(vget_low_u32(m2), vget_low_u32(m3)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_1_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m2), vget_low_u32(m2)).val[0]; \ + t1 = vext_u32(vget_high_u32(m3), vget_high_u32(m1), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_1_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vext_u32(vget_low_u32(m0), vget_low_u32(m0), 1); \ + t1 = vzip_u32(vget_high_u32(m2), vget_low_u32(m1)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_1_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m3), vget_high_u32(m0)).val[0]; \ + t1 = vzip_u32(vget_high_u32(m1), vget_high_u32(m0)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_2_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vext_u32(vget_high_u32(m2), vget_low_u32(m3), 1); \ + t1 = vzip_u32(vget_low_u32(m1), vget_high_u32(m3)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_2_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m2), vget_low_u32(m0)).val[0]; \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m0), vget_low_u32(m3)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_2_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m2), vget_high_u32(m0)); \ + t1 = vzip_u32(vget_high_u32(m1), vget_low_u32(m2)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_2_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m3), vget_high_u32(m1)).val[0]; \ + t1 = vext_u32(vget_low_u32(m0), vget_low_u32(m1), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_3_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m1), vget_high_u32(m0)).val[1]; \ + t1 = vzip_u32(vget_low_u32(m3), vget_high_u32(m2)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_3_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m2), vget_low_u32(m0)).val[1]; \ + t1 = vzip_u32(vget_low_u32(m3), vget_high_u32(m3)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_3_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m0), vget_low_u32(m1)); \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m1), vget_high_u32(m3)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_3_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m1), vget_high_u32(m2)).val[0]; \ + t1 = vzip_u32(vget_low_u32(m0), vget_low_u32(m2)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_4_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m2), vget_low_u32(m1)).val[1]; \ + t1 = vzip_u32((vget_high_u32(m0)), vget_high_u32(m2)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_4_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m0), vget_high_u32(m1)); \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m1), vget_high_u32(m3)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_4_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m3), vget_high_u32(m2)); \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m1), vget_high_u32(m0)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_4_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vext_u32(vget_low_u32(m0), vget_low_u32(m3), 1); \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m2), vget_low_u32(m3)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_5_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32((vget_high_u32(m0)), vget_high_u32(m1)).val[0]; \ + t1 = vzip_u32(vget_low_u32(m0), vget_low_u32(m2)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_5_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m3), vget_high_u32(m2)).val[0]; \ + t1 = vzip_u32(vget_high_u32(m2), vget_high_u32(m0)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_5_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m1), vget_high_u32(m1)); \ + t1 = vzip_u32(vget_high_u32(m3), vget_low_u32(m0)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_5_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m3), vget_low_u32(m1)).val[1]; \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m3), vget_low_u32(m2)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_6_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m3), vget_low_u32(m0)); \ + t1 = vzip_u32(vget_high_u32(m3), vget_low_u32(m1)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_6_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m1), vget_high_u32(m3)).val[1]; \ + t1 = vext_u32(vget_low_u32(m3), vget_high_u32(m2), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_6_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m0), vget_high_u32(m1)).val[0]; \ + t1 = vext_u32(vget_low_u32(m2), vget_low_u32(m2), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_6_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m1), vget_high_u32(m0)).val[1]; \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m0), vget_high_u32(m2)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_7_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m3), vget_high_u32(m1)).val[1]; \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m3), vget_high_u32(m0)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_7_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vext_u32(vget_high_u32(m2), vget_high_u32(m3), 1); \ + t1 = vzip_u32(vget_low_u32(m0), vget_low_u32(m2)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_7_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m1), vget_high_u32(m3)).val[1]; \ + t1 = vzip_u32(vget_low_u32(m2), vget_high_u32(m0)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_7_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_low_u32(m0), vget_low_u32(m1)).val[0]; \ + t1 = vzip_u32(vget_high_u32(m1), vget_high_u32(m2)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_8_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m1), vget_high_u32(m3)).val[0]; \ + t1 = vext_u32(vget_high_u32(m2), vget_low_u32(m0), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_8_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m3), vget_low_u32(m2)).val[1]; \ + t1 = vext_u32(vget_high_u32(m0), vget_low_u32(m2), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_8_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m3), vget_low_u32(m3)); \ + t1 = vext_u32(vget_low_u32(m0), vget_high_u32(m2), 1); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_8_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m0), vget_high_u32(m1)); \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_low_u32(m1), vget_low_u32(m1)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_9_1(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m2), vget_low_u32(m2)).val[0]; \ + t1 = vzip_u32(vget_high_u32(m1), vget_low_u32(m0)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_9_2(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32((vget_high_u32(m0)), vget_low_u32(m1)).val[0]; \ + t1 = vbsl_u32(vcreate_u32(0xFFFFFFFF), vget_high_u32(m1), vget_low_u32(m1)); \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_9_3(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vzip_u32(vget_high_u32(m3), vget_low_u32(m2)).val[1]; \ + t1 = vzip_u32((vget_high_u32(m0)), vget_low_u32(m3)).val[1]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define BLAKE2S_LOAD_MSG_9_4(buf) \ + do { uint32x2_t t0, t1; \ + t0 = vext_u32(vget_high_u32(m2), vget_high_u32(m3), 1); \ + t1 = vzip_u32(vget_low_u32(m3), vget_low_u32(m0)).val[0]; \ + buf = vcombine_u32(t0, t1); } while(0) + + #define vrorq_n_u32_16(x) vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(x))) + + #define vrorq_n_u32_8(x) vsriq_n_u32(vshlq_n_u32((x), 24), (x), 8) + + #define vrorq_n_u32(x, c) vsriq_n_u32(vshlq_n_u32((x), 32-(c)), (x), (c)) + + #define BLAKE2S_G1(row1,row2,row3,row4,buf) \ + do { \ + row1 = vaddq_u32(vaddq_u32(row1, buf), row2); row4 = veorq_u32(row4, row1); \ + row4 = vrorq_n_u32_16(row4); row3 = vaddq_u32(row3, row4); \ + row2 = veorq_u32(row2, row3); row2 = vrorq_n_u32(row2, 12); \ + } while(0) + + #define BLAKE2S_G2(row1,row2,row3,row4,buf) \ + do { \ + row1 = vaddq_u32(vaddq_u32(row1, buf), row2); row4 = veorq_u32(row4, row1); \ + row4 = vrorq_n_u32_8(row4); row3 = vaddq_u32(row3, row4); \ + row2 = veorq_u32(row2, row3); row2 = vrorq_n_u32(row2, 7); \ + } while(0) + + #define BLAKE2S_DIAGONALIZE(row1,row2,row3,row4) \ + do { \ + row4 = vextq_u32(row4, row4, 3); row3 = vextq_u32(row3, row3, 2); row2 = vextq_u32(row2, row2, 1); \ + } while(0) + + #define BLAKE2S_UNDIAGONALIZE(row1,row2,row3,row4) \ + do { \ + row4 = vextq_u32(row4, row4, 1); \ + row3 = vextq_u32(row3, row3, 2); \ + row2 = vextq_u32(row2, row2, 3); \ + } while(0) + + #define BLAKE2S_ROUND(r) \ + do { \ + uint32x4_t buf1, buf2, buf3, buf4; \ + BLAKE2S_LOAD_MSG_ ##r ##_1(buf1); \ + BLAKE2S_G1(row1,row2,row3,row4,buf1); \ + BLAKE2S_LOAD_MSG_ ##r ##_2(buf2); \ + BLAKE2S_G2(row1,row2,row3,row4,buf2); \ + BLAKE2S_DIAGONALIZE(row1,row2,row3,row4); \ + BLAKE2S_LOAD_MSG_ ##r ##_3(buf3); \ + BLAKE2S_G1(row1,row2,row3,row4,buf3); \ + BLAKE2S_LOAD_MSG_ ##r ##_4(buf4); \ + BLAKE2S_G2(row1,row2,row3,row4,buf4); \ + BLAKE2S_UNDIAGONALIZE(row1,row2,row3,row4); \ + } while(0) + + const uint32x4_t m0 = vreinterpretq_u32_u8(vld1q_u8(input + 00)); + const uint32x4_t m1 = vreinterpretq_u32_u8(vld1q_u8(input + 16)); + const uint32x4_t m2 = vreinterpretq_u32_u8(vld1q_u8(input + 32)); + const uint32x4_t m3 = vreinterpretq_u32_u8(vld1q_u8(input + 48)); + + uint32x4_t row1, row2, row3, row4; + + const uint32x4_t f0 = row1 = vld1q_u32(state.h()+0); + const uint32x4_t f1 = row2 = vld1q_u32(state.h()+4); + row3 = vld1q_u32(BLAKE2S_IV+0); + row4 = veorq_u32(vld1q_u32(BLAKE2S_IV+4), vld1q_u32(state.t()+0)); + + BLAKE2S_ROUND(0); + BLAKE2S_ROUND(1); + BLAKE2S_ROUND(2); + BLAKE2S_ROUND(3); + BLAKE2S_ROUND(4); + BLAKE2S_ROUND(5); + BLAKE2S_ROUND(6); + BLAKE2S_ROUND(7); + BLAKE2S_ROUND(8); + BLAKE2S_ROUND(9); + + vst1q_u32(state.h()+0, veorq_u32(f0, veorq_u32(row1, row3))); + vst1q_u32(state.h()+4, veorq_u32(f1, veorq_u32(row2, row4))); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + +template +inline uint32x4_p VecLoad32(const T* p) +{ + return VecLoad(p); +} + +template +inline uint32x4_p VecLoad32LE(const T* p, const uint8x16_p le_mask) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p v = VecLoad(p); + return VecPermute(v, v, le_mask); +#else + CRYPTOPP_UNUSED(le_mask); + return VecLoad(p); +#endif +} + +template +inline void VecStore32(T* p, const uint32x4_p x) +{ + VecStore(x, p); +} + +template +inline void VecStore32LE(T* p, const uint32x4_p x, const uint8x16_p le_mask) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p v = VecPermute(x, x, le_mask); + VecStore(v, p); +#else + CRYPTOPP_UNUSED(le_mask); + VecStore(x, p); +#endif +} + +template +inline uint32x4_p VectorSet32(const uint32x4_p a, const uint32x4_p b) +{ + // Re-index. I'd like to use something like Z=Y*4 and then + // VecShiftLeftOctet(b) but it crashes early Red Hat + // GCC compilers. + enum {X=E1&3, Y=E2&3}; + + // Don't care element + const unsigned int DC = 31; + + // Element 0 combinations + if (X == 0 && Y == 0) + { + const uint8x16_p mask = {0,1,2,3, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, b, mask); + } + else if (X == 0 && Y == 1) + { + const uint8x16_p mask = {0,1,2,3, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<4>(b), mask); + } + else if (X == 0 && Y == 2) + { + const uint8x16_p mask = {0,1,2,3, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<8>(b), mask); + } + else if (X == 0 && Y == 3) + { + const uint8x16_p mask = {0,1,2,3, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<12>(b), mask); + } + + // Element 1 combinations + else if (X == 1 && Y == 0) + { + const uint8x16_p mask = {4,5,6,7, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, b, mask); + } + else if (X == 1 && Y == 1) + { + const uint8x16_p mask = {4,5,6,7, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<4>(b), mask); + } + else if (X == 1 && Y == 2) + { + const uint8x16_p mask = {4,5,6,7, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<8>(b), mask); + } + else if (X == 1 && Y == 3) + { + const uint8x16_p mask = {4,5,6,7, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<12>(b), mask); + } + + // Element 2 combinations + else if (X == 2 && Y == 0) + { + const uint8x16_p mask = {8,9,10,11, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, b, mask); + } + else if (X == 2 && Y == 1) + { + const uint8x16_p mask = {8,9,10,11, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<4>(b), mask); + } + else if (X == 2 && Y == 2) + { + const uint8x16_p mask = {8,9,10,11, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<8>(b), mask); + } + else if (X == 2 && Y == 3) + { + const uint8x16_p mask = {8,9,10,11, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<12>(b), mask); + } + + // Element 3 combinations + else if (X == 3 && Y == 0) + { + const uint8x16_p mask = {12,13,14,15, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, b, mask); + } + else if (X == 3 && Y == 1) + { + const uint8x16_p mask = {12,13,14,15, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<4>(b), mask); + } + else if (X == 3 && Y == 2) + { + const uint8x16_p mask = {12,13,14,15, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<8>(b), mask); + } + else if (X == 3 && Y == 3) + { + const uint8x16_p mask = {12,13,14,15, 16,17,18,19, DC,DC,DC,DC, DC,DC,DC,DC}; + return VecPermute(a, VecShiftLeftOctet<12>(b), mask); + } + + // Quiet IBM XLC warning + return VecXor(a, a); +} + +template +inline uint32x4_p VectorSet32(const uint32x4_p a, const uint32x4_p b, + const uint32x4_p c, const uint32x4_p d) +{ + // Re-index + enum {W=E1&3, X=E2&3, Y=E3&3, Z=E4&3}; + + const uint32x4_p t0 = VectorSet32(a, b); + const uint32x4_p t1 = VectorSet32(c, d); + + // PowerPC follows SSE2's implementation, and this is _mm_set_epi32. + const uint8x16_p mask = {20,21,22,23, 16,17,18,19, 4,5,6,7, 0,1,2,3}; + return VecPermute(t0, t1, mask); +} + +template<> +uint32x4_p VectorSet32<2,0,2,0>(const uint32x4_p a, const uint32x4_p b, + const uint32x4_p c, const uint32x4_p d) +{ + // a=b, c=d, mask is {2,0, 2,0} + CRYPTOPP_UNUSED(b); CRYPTOPP_UNUSED(d); + const uint8x16_p mask = {16,17,18,19, 24,25,26,27, 0,1,2,3, 8,9,10,11}; + return VecPermute(a, c, mask); +} + +template<> +uint32x4_p VectorSet32<3,1,3,1>(const uint32x4_p a, const uint32x4_p b, + const uint32x4_p c, const uint32x4_p d) +{ + // a=b, c=d, mask is {3,1, 3,1} + CRYPTOPP_UNUSED(b); CRYPTOPP_UNUSED(d); + const uint8x16_p mask = {20,21,22,23, 28,29,30,31, 4,5,6,7, 12,13,14,15}; + return VecPermute(a, c, mask); +} + +void BLAKE2_Compress32_ALTIVEC(const byte* input, BLAKE2s_State& state) +{ + # define m1 m0 + # define m2 m0 + # define m3 m0 + + # define m5 m4 + # define m6 m4 + # define m7 m4 + + # define m9 m8 + # define m10 m8 + # define m11 m8 + + # define m13 m12 + # define m14 m12 + # define m15 m12 + + // #define BLAKE2S_LOAD_MSG_0_1(buf) buf = VectorSet32<6,4,2,0>(m6,m4,m2,m0); + #define BLAKE2S_LOAD_MSG_0_1(buf) buf = VectorSet32<2,0,2,0>(m6,m4,m2,m0); + // #define BLAKE2S_LOAD_MSG_0_2(buf) buf = VectorSet32<7,5,3,1>(m7,m5,m3,m1); + #define BLAKE2S_LOAD_MSG_0_2(buf) buf = VectorSet32<3,1,3,1>(m7,m5,m3,m1); + // #define BLAKE2S_LOAD_MSG_0_3(buf) buf = VectorSet32<14,12,10,8>(m14,m12,m10,m8); + #define BLAKE2S_LOAD_MSG_0_3(buf) buf = VectorSet32<2,0,2,0>(m14,m12,m10,m8); + // #define BLAKE2S_LOAD_MSG_0_4(buf) buf = VectorSet32<15,13,11,9>(m15,m13,m11,m9); + #define BLAKE2S_LOAD_MSG_0_4(buf) buf = VectorSet32<3,1,3,1>(m15,m13,m11,m9); + + #define BLAKE2S_LOAD_MSG_1_1(buf) buf = VectorSet32<13,9,4,14>(m13,m9,m4,m14); + #define BLAKE2S_LOAD_MSG_1_2(buf) buf = VectorSet32<6,15,8,10>(m6,m15,m8,m10) + #define BLAKE2S_LOAD_MSG_1_3(buf) buf = VectorSet32<5,11,0,1>(m5,m11,m0,m1) + #define BLAKE2S_LOAD_MSG_1_4(buf) buf = VectorSet32<3,7,2,12>(m3,m7,m2,m12) + + #define BLAKE2S_LOAD_MSG_2_1(buf) buf = VectorSet32<15,5,12,11>(m15,m5,m12,m11) + #define BLAKE2S_LOAD_MSG_2_2(buf) buf = VectorSet32<13,2,0,8>(m13,m2,m0,m8) + #define BLAKE2S_LOAD_MSG_2_3(buf) buf = VectorSet32<9,7,3,10>(m9,m7,m3,m10) + #define BLAKE2S_LOAD_MSG_2_4(buf) buf = VectorSet32<4,1,6,14>(m4,m1,m6,m14) + + #define BLAKE2S_LOAD_MSG_3_1(buf) buf = VectorSet32<11,13,3,7>(m11,m13,m3,m7) + #define BLAKE2S_LOAD_MSG_3_2(buf) buf = VectorSet32<14,12,1,9>(m14,m12,m1,m9) + #define BLAKE2S_LOAD_MSG_3_3(buf) buf = VectorSet32<15,4,5,2>(m15,m4,m5,m2) + #define BLAKE2S_LOAD_MSG_3_4(buf) buf = VectorSet32<8,0,10,6>(m8,m0,m10,m6) + + #define BLAKE2S_LOAD_MSG_4_1(buf) buf = VectorSet32<10,2,5,9>(m10,m2,m5,m9) + #define BLAKE2S_LOAD_MSG_4_2(buf) buf = VectorSet32<15,4,7,0>(m15,m4,m7,m0) + #define BLAKE2S_LOAD_MSG_4_3(buf) buf = VectorSet32<3,6,11,14>(m3,m6,m11,m14) + #define BLAKE2S_LOAD_MSG_4_4(buf) buf = VectorSet32<13,8,12,1>(m13,m8,m12,m1) + + #define BLAKE2S_LOAD_MSG_5_1(buf) buf = VectorSet32<8,0,6,2>(m8,m0,m6,m2) + #define BLAKE2S_LOAD_MSG_5_2(buf) buf = VectorSet32<3,11,10,12>(m3,m11,m10,m12) + #define BLAKE2S_LOAD_MSG_5_3(buf) buf = VectorSet32<1,15,7,4>(m1,m15,m7,m4) + #define BLAKE2S_LOAD_MSG_5_4(buf) buf = VectorSet32<9,14,5,13>(m9,m14,m5,m13) + + #define BLAKE2S_LOAD_MSG_6_1(buf) buf = VectorSet32<4,14,1,12>(m4,m14,m1,m12) + #define BLAKE2S_LOAD_MSG_6_2(buf) buf = VectorSet32<10,13,15,5>(m10,m13,m15,m5) + #define BLAKE2S_LOAD_MSG_6_3(buf) buf = VectorSet32<8,9,6,0>(m8,m9,m6,m0) + #define BLAKE2S_LOAD_MSG_6_4(buf) buf = VectorSet32<11,2,3,7>(m11,m2,m3,m7) + + #define BLAKE2S_LOAD_MSG_7_1(buf) buf = VectorSet32<3,12,7,13>(m3,m12,m7,m13) + #define BLAKE2S_LOAD_MSG_7_2(buf) buf = VectorSet32<9,1,14,11>(m9,m1,m14,m11) + #define BLAKE2S_LOAD_MSG_7_3(buf) buf = VectorSet32<2,8,15,5>(m2,m8,m15,m5) + #define BLAKE2S_LOAD_MSG_7_4(buf) buf = VectorSet32<10,6,4,0>(m10,m6,m4,m0) + + #define BLAKE2S_LOAD_MSG_8_1(buf) buf = VectorSet32<0,11,14,6>(m0,m11,m14,m6) + #define BLAKE2S_LOAD_MSG_8_2(buf) buf = VectorSet32<8,3,9,15>(m8,m3,m9,m15) + #define BLAKE2S_LOAD_MSG_8_3(buf) buf = VectorSet32<10,1,13,12>(m10,m1,m13,m12) + #define BLAKE2S_LOAD_MSG_8_4(buf) buf = VectorSet32<5,4,7,2>(m5,m4,m7,m2) + + #define BLAKE2S_LOAD_MSG_9_1(buf) buf = VectorSet32<1,7,8,10>(m1,m7,m8,m10) + #define BLAKE2S_LOAD_MSG_9_2(buf) buf = VectorSet32<5,6,4,2>(m5,m6,m4,m2) + #define BLAKE2S_LOAD_MSG_9_3(buf) buf = VectorSet32<13,3,9,15>(m13,m3,m9,m15) + #define BLAKE2S_LOAD_MSG_9_4(buf) buf = VectorSet32<0,12,14,11>(m0,m12,m14,m11) + + #define vec_ror_16(x) VecRotateRight<16>(x) + #define vec_ror_12(x) VecRotateRight<12>(x) + #define vec_ror_8(x) VecRotateRight<8>(x) + #define vec_ror_7(x) VecRotateRight<7>(x) + + #define BLAKE2S_G1(row1,row2,row3,row4,buf) \ + row1 = VecAdd(VecAdd(row1, buf), row2); \ + row4 = VecXor(row4, row1); \ + row4 = vec_ror_16(row4); \ + row3 = VecAdd(row3, row4); \ + row2 = VecXor(row2, row3); \ + row2 = vec_ror_12(row2); + + #define BLAKE2S_G2(row1,row2,row3,row4,buf) \ + row1 = VecAdd(VecAdd(row1, buf), row2); \ + row4 = VecXor(row4, row1); \ + row4 = vec_ror_8(row4); \ + row3 = VecAdd(row3, row4); \ + row2 = VecXor(row2, row3); \ + row2 = vec_ror_7(row2); + + const uint8x16_p D2103_MASK = {12,13,14,15, 0,1,2,3, 4,5,6,7, 8,9,10,11}; + const uint8x16_p D1032_MASK = {8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7}; + const uint8x16_p D0321_MASK = {4,5,6,7, 8,9,10,11, 12,13,14,15, 0,1,2,3}; + + #define BLAKE2S_DIAGONALIZE(row1,row2,row3,row4) \ + row4 = VecPermute(row4, row4, D2103_MASK); \ + row3 = VecPermute(row3, row3, D1032_MASK); \ + row2 = VecPermute(row2, row2, D0321_MASK); + + #define BLAKE2S_UNDIAGONALIZE(row1,row2,row3,row4) \ + row4 = VecPermute(row4, row4, D0321_MASK); \ + row3 = VecPermute(row3, row3, D1032_MASK); \ + row2 = VecPermute(row2, row2, D2103_MASK); + + #define BLAKE2S_ROUND(r) \ + BLAKE2S_LOAD_MSG_ ##r ##_1(buf1); \ + BLAKE2S_G1(row1,row2,row3,row4,buf1); \ + BLAKE2S_LOAD_MSG_ ##r ##_2(buf2); \ + BLAKE2S_G2(row1,row2,row3,row4,buf2); \ + BLAKE2S_DIAGONALIZE(row1,row2,row3,row4); \ + BLAKE2S_LOAD_MSG_ ##r ##_3(buf3); \ + BLAKE2S_G1(row1,row2,row3,row4,buf3); \ + BLAKE2S_LOAD_MSG_ ##r ##_4(buf4); \ + BLAKE2S_G2(row1,row2,row3,row4,buf4); \ + BLAKE2S_UNDIAGONALIZE(row1,row2,row3,row4); + + // Possibly unaligned user messages + uint32x4_p m0, m4, m8, m12; + // Endian conversion mask + const uint8x16_p le_mask = {3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12}; + +#if defined(_ARCH_PWR9) + // POWER9 provides loads for char's and short's + m0 = (uint32x4_p) vec_xl( 0, CONST_V8_CAST( input )); + m4 = (uint32x4_p) vec_xl( 16, CONST_V8_CAST( input )); + m8 = (uint32x4_p) vec_xl( 32, CONST_V8_CAST( input )); + m12 = (uint32x4_p) vec_xl( 48, CONST_V8_CAST( input )); + +# if defined(CRYPTOPP_BIG_ENDIAN) + m0 = vec_perm(m0, m0, le_mask); + m4 = vec_perm(m4, m4, le_mask); + m8 = vec_perm(m8, m8, le_mask); + m12 = vec_perm(m12, m12, le_mask); +# endif +#else + // Altivec only provides 16-byte aligned loads + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + m0 = (uint32x4_p) vec_ld( 0, CONST_V8_CAST( input )); + m4 = (uint32x4_p) vec_ld( 16, CONST_V8_CAST( input )); + m8 = (uint32x4_p) vec_ld( 32, CONST_V8_CAST( input )); + m12 = (uint32x4_p) vec_ld( 48, CONST_V8_CAST( input )); + + // Alignment check for load of the message buffer + const uintptr_t addr = (uintptr_t)input; + if (addr%16 == 0) + { + // Already aligned. Perform a little-endian swap as required +# if defined(CRYPTOPP_BIG_ENDIAN) + m0 = vec_perm(m0, m0, le_mask); + m4 = vec_perm(m4, m4, le_mask); + m8 = vec_perm(m8, m8, le_mask); + m12 = vec_perm(m12, m12, le_mask); +# endif + } + else + { + // Not aligned. Fix vectors and perform a little-endian swap as required + // http://mirror.informatimago.com/next/developer.apple.com/ + // hardwaredrivers/ve/code_optimization.html + uint32x4_p ex; uint8x16_p perm; + ex = (uint32x4_p) vec_ld(48+15, CONST_V8_CAST( input )); + perm = vec_lvsl(0, CONST_V8_CAST( addr )); + +# if defined(CRYPTOPP_BIG_ENDIAN) + // Combine the vector permute with the little-endian swap + perm = vec_perm(perm, perm, le_mask); +# endif + + m0 = vec_perm(m0, m4, perm); + m4 = vec_perm(m4, m8, perm); + m8 = vec_perm(m8, m12, perm); + m12 = vec_perm(m12, ex, perm); + } +#endif + + uint32x4_p row1, row2, row3, row4; + uint32x4_p buf1, buf2, buf3, buf4; + uint32x4_p ff0, ff1; + + row1 = ff0 = VecLoad32LE(state.h()+0, le_mask); + row2 = ff1 = VecLoad32LE(state.h()+4, le_mask); + row3 = VecLoad32(BLAKE2S_IV+0); + row4 = VecXor(VecLoad32(BLAKE2S_IV+4), VecLoad32(state.t()+0)); + + BLAKE2S_ROUND(0); + BLAKE2S_ROUND(1); + BLAKE2S_ROUND(2); + BLAKE2S_ROUND(3); + BLAKE2S_ROUND(4); + BLAKE2S_ROUND(5); + BLAKE2S_ROUND(6); + BLAKE2S_ROUND(7); + BLAKE2S_ROUND(8); + BLAKE2S_ROUND(9); + + VecStore32LE(state.h()+0, VecXor(ff0, VecXor(row1, row3)), le_mask); + VecStore32LE(state.h()+4, VecXor(ff1, VecXor(row2, row4)), le_mask); +} +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/blowfish.cpp b/extension/third_party/cryptopp/blowfish.cpp new file mode 100644 index 00000000..e615da3b --- /dev/null +++ b/extension/third_party/cryptopp/blowfish.cpp @@ -0,0 +1,99 @@ +// blowfish.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "blowfish.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Blowfish::Base::UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + unsigned i, j=0, k; + word32 data, dspace[2] = {0, 0}; + + memcpy(pbox, p_init, sizeof(p_init)); + memcpy(sbox, s_init, sizeof(s_init)); + + // Xor key string into encryption key vector + for (i=0 ; i Block; + + word32 left, right; + Block::Get(inBlock)(left)(right); + + const word32 *const s=sbox; + const word32 *p=pbox; + + left ^= p[0]; + + for (unsigned i=0; i, public VariableKeyLength<16, 4, 56>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Blowfish";} +}; + +// Blowfish + +/// \brief Blowfish block cipher +/// \since Crypto++ 1.0 +class Blowfish : public Blowfish_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs ¶ms); + + private: + void crypt_block(const word32 in[2], word32 out[2]) const; + + static const word32 p_init[ROUNDS+2]; + static const word32 s_init[4*256]; + + FixedSizeSecBlock pbox; + FixedSizeSecBlock sbox; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Blowfish::Encryption BlowfishEncryption; +typedef Blowfish::Decryption BlowfishDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/blumshub.cpp b/extension/third_party/cryptopp/blumshub.cpp new file mode 100644 index 00000000..7465d8da --- /dev/null +++ b/extension/third_party/cryptopp/blumshub.cpp @@ -0,0 +1,64 @@ +// blumshub.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "blumshub.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +PublicBlumBlumShub::PublicBlumBlumShub(const Integer &n, const Integer &seed) + : modn(n), + current(modn.Square(modn.Square(seed))), + maxBits(BitPrecision(n.BitCount())-1), + bitsLeft(maxBits) +{ +} + +unsigned int PublicBlumBlumShub::GenerateBit() +{ + if (bitsLeft==0) + { + current = modn.Square(current); + bitsLeft = maxBits; + } + + return static_cast(current.GetBit(--bitsLeft)); +} + +byte PublicBlumBlumShub::GenerateByte() +{ + byte b=0; + for (int i=0; i<8; i++) + b = byte((b << 1) | PublicBlumBlumShub::GenerateBit()); + return b; +} + +void PublicBlumBlumShub::GenerateBlock(byte *output, size_t size) +{ + while (size--) + *output++ = PublicBlumBlumShub::GenerateByte(); +} + +void PublicBlumBlumShub::ProcessData(byte *outString, const byte *inString, size_t length) +{ + while (length--) + *outString++ = *inString++ ^ PublicBlumBlumShub::GenerateByte(); +} + +BlumBlumShub::BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed) + : PublicBlumBlumShub(p*q, seed), + p(p), q(q), + x0(modn.Square(seed)) +{ +} + +void BlumBlumShub::Seek(lword index) +{ + Integer i(Integer::POSITIVE, index); + i *= 8; + Integer e = a_exp_b_mod_c (2, i / maxBits + 1, (p-1)*(q-1)); + current = modn.Exponentiate(x0, e); + bitsLeft = maxBits - i % maxBits; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/blumshub.h b/extension/third_party/cryptopp/blumshub.h new file mode 100644 index 00000000..8c1c981f --- /dev/null +++ b/extension/third_party/cryptopp/blumshub.h @@ -0,0 +1,70 @@ +// blumshub.h - originally written and placed in the public domain by Wei Dai + +/// \file blumshub.h +/// \brief Classes for Blum Blum Shub generator + +#ifndef CRYPTOPP_BLUMSHUB_H +#define CRYPTOPP_BLUMSHUB_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief BlumBlumShub without factorization of the modulus +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class PublicBlumBlumShub : public RandomNumberGenerator, + public StreamTransformation +{ +public: + virtual ~PublicBlumBlumShub() {} + + /// \brief Construct a PublicBlumBlumShub + /// \param n the modulus + /// \param seed the seed for the generator + /// \details seed is the secret key and should be about as large as n. + PublicBlumBlumShub(const Integer &n, const Integer &seed); + + unsigned int GenerateBit(); + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + +protected: + ModularArithmetic modn; + Integer current; + word maxBits, bitsLeft; +}; + +/// \brief BlumBlumShub with factorization of the modulus +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class BlumBlumShub : public PublicBlumBlumShub +{ +public: + virtual ~BlumBlumShub() {} + + /// \brief Construct a BlumBlumShub + /// \param p the first prime factor + /// \param q the second prime factor + /// \param seed the seed for the generator + /// \details Esure p and q are both primes congruent to 3 mod 4 and at least 512 bits long. + /// seed is the secret key and should be about as large as p*q. + BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed); + + bool IsRandomAccess() const {return true;} + void Seek(lword index); + +protected: + const Integer p, q; + const Integer x0; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/camellia.cpp b/extension/third_party/cryptopp/camellia.cpp new file mode 100644 index 00000000..30b8bc99 --- /dev/null +++ b/extension/third_party/cryptopp/camellia.cpp @@ -0,0 +1,539 @@ +// camellia.cpp - by Kevin Springle, 2003 +// This code is hereby placed in the public domain. + +/* +Optimisations and defense against timing attacks added in Jan 2007 by Wei Dai. + +The first 2 rounds and the last round seem especially vulnerable to timing +attacks. The protection is similar to what was implemented for Rijndael. +See comments at top of rijndael.cpp for more details. +*/ + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4456) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6246) +# endif +#endif + +#include "camellia.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +// round implementation that uses a small table for protection against timing attacks +#define SLOW_ROUND(lh, ll, rh, rl, kh, kl) { \ + word32 zr = ll ^ kl; \ + word32 zl = lh ^ kh; \ + zr= rotlConstant<1>(s1[GETBYTE(zr, 3)]) | \ + (rotrConstant<1>(s1[GETBYTE(zr, 2)]) << 24) | \ + (s1[rotlConstant<1>(CRYPTOPP_GET_BYTE_AS_BYTE(zr, 1))] << 16) | \ + (s1[GETBYTE(zr, 0)] << 8); \ + zl= (s1[GETBYTE(zl, 3)] << 24) | \ + (rotlConstant<1>(s1[GETBYTE(zl, 2)]) << 16) | \ + (rotrConstant<1>(s1[GETBYTE(zl, 1)]) << 8) | \ + s1[rotlConstant<1>(CRYPTOPP_GET_BYTE_AS_BYTE(zl, 0))]; \ + zl ^= zr; \ + zr = zl ^ rotlConstant<8>(zr); \ + zl = zr ^ rotrConstant<8>(zl); \ + rh ^= rotlConstant<16>(zr); \ + rh ^= zl; \ + rl ^= rotlConstant<8>(zl); \ + } + +// normal round - same output as above but using larger tables for faster speed +#define ROUND(lh, ll, rh, rl, kh, kl) { \ + word32 th = lh ^ kh; \ + word32 tl = ll ^ kl; \ + word32 d = SP[0][GETBYTE(tl,0)] ^ SP[1][GETBYTE(tl,3)] ^ SP[2][GETBYTE(tl,2)] ^ SP[3][GETBYTE(tl,1)]; \ + word32 u = SP[0][GETBYTE(th,3)] ^ SP[1][GETBYTE(th,2)] ^ SP[2][GETBYTE(th,1)] ^ SP[3][GETBYTE(th,0)]; \ + d ^= u; \ + rh ^= d; \ + rl ^= d; \ + rl ^= rotrConstant<8>(u);} + +#define DOUBLE_ROUND(lh, ll, rh, rl, k0, k1, k2, k3) \ + ROUND(lh, ll, rh, rl, k0, k1) \ + ROUND(rh, rl, lh, ll, k2, k3) + +#if (CRYPTOPP_LITTLE_ENDIAN) +#define EFI(i) (1-(i)) +#else +#define EFI(i) (i) +#endif + +void Camellia::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs &) +{ + m_rounds = (keylen >= 24) ? 4 : 3; + unsigned int kslen = (8 * m_rounds + 2); + m_key.New(kslen*2); + word32 *ks32 = m_key.data(); + int m=0, a=0; + if (!IsForwardTransformation()) + m = -1, a = kslen-1; + + word32 kl0, kl1, kl2, kl3; + GetBlock getBlock(key); + getBlock(kl0)(kl1)(kl2)(kl3); + word32 k0=kl0, k1=kl1, k2=kl2, k3=kl3; + +#define CALC_ADDR2(base, i, j) ((byte *)(base)+8*(i)+4*(j)+((-16*(i))&m)) +#define CALC_ADDR(base, i) CALC_ADDR2(base, i, 0) + +#if 1 + word64 kwl, kwr; + ks32 += 2*a; +#define PREPARE_KS_ROUNDS \ + kwl = (word64(k0) << 32) | k1; \ + kwr = (word64(k2) << 32) | k3 +#define KS_ROUND_0(i) \ + CRYPTOPP_ASSERT(IsAlignedOn(CALC_ADDR(ks32, i+EFI(0)),GetAlignmentOf())); \ + CRYPTOPP_ASSERT(IsAlignedOn(CALC_ADDR(ks32, i+EFI(1)),GetAlignmentOf())); \ + *(word64*)(void*)CALC_ADDR(ks32, i+EFI(0)) = kwl; \ + *(word64*)(void*)CALC_ADDR(ks32, i+EFI(1)) = kwr +#define KS_ROUND(i, r, which) \ + CRYPTOPP_ASSERT(IsAlignedOn(CALC_ADDR(ks32, i+EFI(r<64)),GetAlignmentOf())); \ + CRYPTOPP_ASSERT(IsAlignedOn(CALC_ADDR(ks32, i+EFI(r>64)),GetAlignmentOf())); \ + if (which & (1<> (64 - (r%64))); \ + if (which & (1<64))) *(word64*)(void*)CALC_ADDR(ks32, i+EFI(r>64)) = (kwl << (r%64)) | (kwr >> (64 - (r%64))) +#else + // SSE2 version is 30% faster on Intel Core 2. Doesn't seem worth the hassle of maintenance, but left here + // #if'd out in case someone needs it. + __m128i kw, kw2; + __m128i *ks128 = (__m128i *)ks32+a/2; + ks32 += 2*a; +#define PREPARE_KS_ROUNDS \ + kw = _mm_set_epi32(k0, k1, k2, k3); \ + if (m) kw2 = kw, kw = _mm_shuffle_epi32(kw, _MM_SHUFFLE(1, 0, 3, 2)); \ + else kw2 = _mm_shuffle_epi32(kw, _MM_SHUFFLE(1, 0, 3, 2)) +#define KS_ROUND_0(i) \ + _mm_store_si128((__m128i *)CALC_ADDR(ks128, i), kw) +#define KS_ROUND(i, r, which) { \ + __m128i temp; \ + if (r<64 && (which!=1 || m)) temp = _mm_or_si128(_mm_slli_epi64(kw, r%64), _mm_srli_epi64(kw2, 64-r%64)); \ + else temp = _mm_or_si128(_mm_slli_epi64(kw2, r%64), _mm_srli_epi64(kw, 64-r%64)); \ + if (which & 2) _mm_store_si128((__m128i *)CALC_ADDR(ks128, i), temp); \ + else _mm_storel_epi64((__m128i*)CALC_ADDR(ks32, i+EFI(0)), temp); \ + } +#endif + + if (keylen == 16) + { + // KL + PREPARE_KS_ROUNDS; + KS_ROUND_0(0); + KS_ROUND(4, 15, 3); + KS_ROUND(10, 45, 3); + KS_ROUND(12, 60, 2); + KS_ROUND(16, 77, 3); + KS_ROUND(18, 94, 3); + KS_ROUND(22, 111, 3); + + // KA + k0=kl0, k1=kl1, k2=kl2, k3=kl3; + DOUBLE_ROUND(k0, k1, k2, k3, 0xA09E667Ful, 0x3BCC908Bul, 0xB67AE858ul, 0x4CAA73B2ul); + k0^=kl0, k1^=kl1, k2^=kl2, k3^=kl3; + DOUBLE_ROUND(k0, k1, k2, k3, 0xC6EF372Ful, 0xE94F82BEul, 0x54FF53A5ul, 0xF1D36F1Cul); + + PREPARE_KS_ROUNDS; + KS_ROUND_0(2); + KS_ROUND(6, 15, 3); + KS_ROUND(8, 30, 3); + KS_ROUND(12, 45, 1); + KS_ROUND(14, 60, 3); + KS_ROUND(20, 94, 3); + KS_ROUND(24, 47, 3); + } + else + { + // KL + PREPARE_KS_ROUNDS; + KS_ROUND_0(0); + KS_ROUND(12, 45, 3); + KS_ROUND(16, 60, 3); + KS_ROUND(22, 77, 3); + KS_ROUND(30, 111, 3); + + // KR + word32 kr0, kr1, kr2, kr3; + GetBlock(key+16)(kr0)(kr1); + if (keylen == 24) + kr2 = ~kr0, kr3 = ~kr1; + else + GetBlock(key+24)(kr2)(kr3); + k0=kr0, k1=kr1, k2=kr2, k3=kr3; + + PREPARE_KS_ROUNDS; + KS_ROUND(4, 15, 3); + KS_ROUND(8, 30, 3); + KS_ROUND(18, 60, 3); + KS_ROUND(26, 94, 3); + + // KA + k0^=kl0, k1^=kl1, k2^=kl2, k3^=kl3; + DOUBLE_ROUND(k0, k1, k2, k3, 0xA09E667Ful, 0x3BCC908Bul, 0xB67AE858ul, 0x4CAA73B2ul); + k0^=kl0, k1^=kl1, k2^=kl2, k3^=kl3; + DOUBLE_ROUND(k0, k1, k2, k3, 0xC6EF372Ful, 0xE94F82BEul, 0x54FF53A5ul, 0xF1D36F1Cul); + + PREPARE_KS_ROUNDS; + KS_ROUND(6, 15, 3); + KS_ROUND(14, 45, 3); + KS_ROUND(24, 77, 3); + KS_ROUND(28, 94, 3); + + // KB + k0^=kr0, k1^=kr1, k2^=kr2, k3^=kr3; + DOUBLE_ROUND(k0, k1, k2, k3, 0x10E527FAul, 0xDE682D1Dul, 0xB05688C2ul, 0xB3E6C1FDul); + + PREPARE_KS_ROUNDS; + KS_ROUND_0(2); + KS_ROUND(10, 30, 3); + KS_ROUND(20, 60, 3); + KS_ROUND(32, 47, 3); + } +} + +void Camellia::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ +#define KS(i, j) ks[i*4 + EFI(j/2)*2 + EFI(j%2)] + +#define FL(klh, kll, krh, krl) \ + ll ^= rotlConstant<1>(lh & klh);\ + lh ^= (ll | kll); \ + rh ^= (rl | krl); \ + rl ^= rotlConstant<1>(rh & krh); + + word32 lh, ll, rh, rl; + typedef BlockGetAndPut Block; + Block::Get(inBlock)(lh)(ll)(rh)(rl); + const word32 *ks = m_key.data(); + lh ^= KS(0,0); + ll ^= KS(0,1); + rh ^= KS(0,2); + rl ^= KS(0,3); + + // Timing attack countermeasure. see comments in Rijndael for more details + const int cacheLineSize = GetCacheLineSize(); + unsigned int i; + volatile word32 _u = 0; + word32 u = _u; + + for (i=0; i<256; i+=cacheLineSize) + u &= *(const word32 *)(void*)(s1+i); + u &= *(const word32 *)(void*)(s1+252); + lh |= u; ll |= u; + + SLOW_ROUND(lh, ll, rh, rl, KS(1,0), KS(1,1)) + SLOW_ROUND(rh, rl, lh, ll, KS(1,2), KS(1,3)) + for (i = m_rounds-1; i > 0; --i) + { + DOUBLE_ROUND(lh, ll, rh, rl, KS(2,0), KS(2,1), KS(2,2), KS(2,3)) + DOUBLE_ROUND(lh, ll, rh, rl, KS(3,0), KS(3,1), KS(3,2), KS(3,3)) + FL(KS(4,0), KS(4,1), KS(4,2), KS(4,3)); + DOUBLE_ROUND(lh, ll, rh, rl, KS(5,0), KS(5,1), KS(5,2), KS(5,3)) + ks += 16; + } + DOUBLE_ROUND(lh, ll, rh, rl, KS(2,0), KS(2,1), KS(2,2), KS(2,3)) + ROUND(lh, ll, rh, rl, KS(3,0), KS(3,1)) + SLOW_ROUND(rh, rl, lh, ll, KS(3,2), KS(3,3)) + lh ^= KS(4,0); + ll ^= KS(4,1); + rh ^= KS(4,2); + rl ^= KS(4,3); + Block::Put(xorBlock, outBlock)(rh)(rl)(lh)(ll); +} + +// The Camellia s-boxes + +CRYPTOPP_ALIGN_DATA(4) +const byte Camellia::Base::s1[256] = +{ + 112,130,44,236,179,39,192,229,228,133,87,53,234,12,174,65, + 35,239,107,147,69,25,165,33,237,14,79,78,29,101,146,189, + 134,184,175,143,124,235,31,206,62,48,220,95,94,197,11,26, + 166,225,57,202,213,71,93,61,217,1,90,214,81,86,108,77, + 139,13,154,102,251,204,176,45,116,18,43,32,240,177,132,153, + 223,76,203,194,52,126,118,5,109,183,169,49,209,23,4,215, + 20,88,58,97,222,27,17,28,50,15,156,22,83,24,242,34, + 254,68,207,178,195,181,122,145,36,8,232,168,96,252,105,80, + 170,208,160,125,161,137,98,151,84,91,30,149,224,255,100,210, + 16,196,0,72,163,247,117,219,138,3,230,218,9,63,221,148, + 135,92,131,2,205,74,144,51,115,103,246,243,157,127,191,226, + 82,155,216,38,200,55,198,59,129,150,111,75,19,190,99,46, + 233,121,167,140,159,110,188,142,41,245,249,182,47,253,180,89, + 120,152,6,106,231,70,113,186,212,37,171,66,136,162,141,250, + 114,7,185,85,248,238,172,10,54,73,42,104,60,56,241,164, + 64,40,211,123,187,201,67,193,21,227,173,244,119,199,128,158 +}; + +const word32 Camellia::Base::SP[4][256] = { + { + 0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, + 0xb3b3b300, 0x27272700, 0xc0c0c000, 0xe5e5e500, + 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500, + 0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100, + 0x23232300, 0xefefef00, 0x6b6b6b00, 0x93939300, + 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100, + 0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, + 0x1d1d1d00, 0x65656500, 0x92929200, 0xbdbdbd00, + 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00, + 0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00, + 0x3e3e3e00, 0x30303000, 0xdcdcdc00, 0x5f5f5f00, + 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00, + 0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, + 0xd5d5d500, 0x47474700, 0x5d5d5d00, 0x3d3d3d00, + 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600, + 0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00, + 0x8b8b8b00, 0x0d0d0d00, 0x9a9a9a00, 0x66666600, + 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00, + 0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, + 0xf0f0f000, 0xb1b1b100, 0x84848400, 0x99999900, + 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200, + 0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500, + 0x6d6d6d00, 0xb7b7b700, 0xa9a9a900, 0x31313100, + 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700, + 0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, + 0xdedede00, 0x1b1b1b00, 0x11111100, 0x1c1c1c00, + 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600, + 0x53535300, 0x18181800, 0xf2f2f200, 0x22222200, + 0xfefefe00, 0x44444400, 0xcfcfcf00, 0xb2b2b200, + 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100, + 0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, + 0x60606000, 0xfcfcfc00, 0x69696900, 0x50505000, + 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00, + 0xa1a1a100, 0x89898900, 0x62626200, 0x97979700, + 0x54545400, 0x5b5b5b00, 0x1e1e1e00, 0x95959500, + 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200, + 0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, + 0xa3a3a300, 0xf7f7f700, 0x75757500, 0xdbdbdb00, + 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00, + 0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400, + 0x87878700, 0x5c5c5c00, 0x83838300, 0x02020200, + 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300, + 0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, + 0x9d9d9d00, 0x7f7f7f00, 0xbfbfbf00, 0xe2e2e200, + 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600, + 0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00, + 0x81818100, 0x96969600, 0x6f6f6f00, 0x4b4b4b00, + 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00, + 0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, + 0x9f9f9f00, 0x6e6e6e00, 0xbcbcbc00, 0x8e8e8e00, + 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600, + 0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900, + 0x78787800, 0x98989800, 0x06060600, 0x6a6a6a00, + 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00, + 0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, + 0x88888800, 0xa2a2a200, 0x8d8d8d00, 0xfafafa00, + 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500, + 0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00, + 0x36363600, 0x49494900, 0x2a2a2a00, 0x68686800, + 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400, + 0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, + 0xbbbbbb00, 0xc9c9c900, 0x43434300, 0xc1c1c100, + 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400, + 0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00 + }, + { + 0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, + 0x00676767, 0x004e4e4e, 0x00818181, 0x00cbcbcb, + 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a, + 0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282, + 0x00464646, 0x00dfdfdf, 0x00d6d6d6, 0x00272727, + 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242, + 0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, + 0x003a3a3a, 0x00cacaca, 0x00252525, 0x007b7b7b, + 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f, + 0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d, + 0x007c7c7c, 0x00606060, 0x00b9b9b9, 0x00bebebe, + 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434, + 0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, + 0x00ababab, 0x008e8e8e, 0x00bababa, 0x007a7a7a, + 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad, + 0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a, + 0x00171717, 0x001a1a1a, 0x00353535, 0x00cccccc, + 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a, + 0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, + 0x00e1e1e1, 0x00636363, 0x00090909, 0x00333333, + 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585, + 0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a, + 0x00dadada, 0x006f6f6f, 0x00535353, 0x00626262, + 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf, + 0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, + 0x00bdbdbd, 0x00363636, 0x00222222, 0x00383838, + 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c, + 0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444, + 0x00fdfdfd, 0x00888888, 0x009f9f9f, 0x00656565, + 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323, + 0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, + 0x00c0c0c0, 0x00f9f9f9, 0x00d2d2d2, 0x00a0a0a0, + 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa, + 0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f, + 0x00a8a8a8, 0x00b6b6b6, 0x003c3c3c, 0x002b2b2b, + 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5, + 0x00202020, 0x00898989, 0x00000000, 0x00909090, + 0x00474747, 0x00efefef, 0x00eaeaea, 0x00b7b7b7, + 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5, + 0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929, + 0x000f0f0f, 0x00b8b8b8, 0x00070707, 0x00040404, + 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666, + 0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, + 0x003b3b3b, 0x00fefefe, 0x007f7f7f, 0x00c5c5c5, + 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c, + 0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676, + 0x00030303, 0x002d2d2d, 0x00dedede, 0x00969696, + 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c, + 0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, + 0x003f3f3f, 0x00dcdcdc, 0x00797979, 0x001d1d1d, + 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d, + 0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2, + 0x00f0f0f0, 0x00313131, 0x000c0c0c, 0x00d4d4d4, + 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575, + 0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, + 0x00111111, 0x00454545, 0x001b1b1b, 0x00f5f5f5, + 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa, + 0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414, + 0x006c6c6c, 0x00929292, 0x00545454, 0x00d0d0d0, + 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949, + 0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, + 0x00777777, 0x00939393, 0x00868686, 0x00838383, + 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9, + 0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d + }, + { + 0x38003838, 0x41004141, 0x16001616, 0x76007676, + 0xd900d9d9, 0x93009393, 0x60006060, 0xf200f2f2, + 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a, + 0x75007575, 0x06000606, 0x57005757, 0xa000a0a0, + 0x91009191, 0xf700f7f7, 0xb500b5b5, 0xc900c9c9, + 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090, + 0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, + 0x8e008e8e, 0xb200b2b2, 0x49004949, 0xde00dede, + 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7, + 0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767, + 0x1f001f1f, 0x18001818, 0x6e006e6e, 0xaf00afaf, + 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d, + 0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, + 0xea00eaea, 0xa300a3a3, 0xae00aeae, 0x9e009e9e, + 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b, + 0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6, + 0xc500c5c5, 0x86008686, 0x4d004d4d, 0x33003333, + 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696, + 0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, + 0x78007878, 0xd800d8d8, 0x42004242, 0xcc00cccc, + 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161, + 0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282, + 0xb600b6b6, 0xdb00dbdb, 0xd400d4d4, 0x98009898, + 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb, + 0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, + 0x6f006f6f, 0x8d008d8d, 0x88008888, 0x0e000e0e, + 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b, + 0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111, + 0x7f007f7f, 0x22002222, 0xe700e7e7, 0x59005959, + 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8, + 0x12001212, 0x04000404, 0x74007474, 0x54005454, + 0x30003030, 0x7e007e7e, 0xb400b4b4, 0x28002828, + 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe, + 0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb, + 0x2a002a2a, 0xad00adad, 0x0f000f0f, 0xca00caca, + 0x70007070, 0xff00ffff, 0x32003232, 0x69006969, + 0x08000808, 0x62006262, 0x00000000, 0x24002424, + 0xd100d1d1, 0xfb00fbfb, 0xba00baba, 0xed00eded, + 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d, + 0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a, + 0xc300c3c3, 0x2e002e2e, 0xc100c1c1, 0x01000101, + 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999, + 0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, + 0xce00cece, 0xbf00bfbf, 0xdf00dfdf, 0x71007171, + 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313, + 0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d, + 0xc000c0c0, 0x4b004b4b, 0xb700b7b7, 0xa500a5a5, + 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717, + 0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, + 0xcf00cfcf, 0x37003737, 0x5e005e5e, 0x47004747, + 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b, + 0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac, + 0x3c003c3c, 0x4c004c4c, 0x03000303, 0x35003535, + 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d, + 0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, + 0x44004444, 0x51005151, 0xc600c6c6, 0x7d007d7d, + 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa, + 0x7c007c7c, 0x77007777, 0x56005656, 0x05000505, + 0x1b001b1b, 0xa400a4a4, 0x15001515, 0x34003434, + 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252, + 0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, + 0xdd00dddd, 0xe400e4e4, 0xa100a1a1, 0xe000e0e0, + 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a, + 0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f + }, + { + 0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, + 0xe4e400e4, 0x57570057, 0xeaea00ea, 0xaeae00ae, + 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5, + 0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092, + 0x86860086, 0xafaf00af, 0x7c7c007c, 0x1f1f001f, + 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b, + 0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, + 0xd9d900d9, 0x5a5a005a, 0x51510051, 0x6c6c006c, + 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0, + 0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084, + 0xdfdf00df, 0xcbcb00cb, 0x34340034, 0x76760076, + 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004, + 0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, + 0x32320032, 0x9c9c009c, 0x53530053, 0xf2f200f2, + 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a, + 0x24240024, 0xe8e800e8, 0x60600060, 0x69690069, + 0xaaaa00aa, 0xa0a000a0, 0xa1a100a1, 0x62620062, + 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064, + 0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, + 0x8a8a008a, 0xe6e600e6, 0x09090009, 0xdddd00dd, + 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090, + 0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf, + 0x52520052, 0xd8d800d8, 0xc8c800c8, 0xc6c600c6, + 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063, + 0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, + 0x29290029, 0xf9f900f9, 0x2f2f002f, 0xb4b400b4, + 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071, + 0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d, + 0x72720072, 0xb9b900b9, 0xf8f800f8, 0xacac00ac, + 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1, + 0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, + 0x15150015, 0xadad00ad, 0x77770077, 0x80800080, + 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5, + 0x85850085, 0x35350035, 0x0c0c000c, 0x41410041, + 0xefef00ef, 0x93930093, 0x19190019, 0x21210021, + 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd, + 0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, + 0x30300030, 0x5f5f005f, 0xc5c500c5, 0x1a1a001a, + 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d, + 0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d, + 0x0d0d000d, 0x66660066, 0xcccc00cc, 0x2d2d002d, + 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099, + 0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, + 0xb7b700b7, 0x31310031, 0x17170017, 0xd7d700d7, + 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c, + 0x0f0f000f, 0x16160016, 0x18180018, 0x22220022, + 0x44440044, 0xb2b200b2, 0xb5b500b5, 0x91910091, + 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050, + 0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, + 0x5b5b005b, 0x95950095, 0xffff00ff, 0xd2d200d2, + 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db, + 0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094, + 0x5c5c005c, 0x02020002, 0x4a4a004a, 0x33330033, + 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2, + 0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, + 0x96960096, 0x4b4b004b, 0xbebe00be, 0x2e2e002e, + 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e, + 0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059, + 0x98980098, 0x6a6a006a, 0x46460046, 0xbaba00ba, + 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa, + 0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, + 0x49490049, 0x68680068, 0x38380038, 0xa4a400a4, + 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1, + 0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e + }}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/camellia.h b/extension/third_party/cryptopp/camellia.h new file mode 100644 index 00000000..e83a2060 --- /dev/null +++ b/extension/third_party/cryptopp/camellia.h @@ -0,0 +1,49 @@ +// camellia.h - originally written and placed in the public domain by Wei Dai + +/// \file camellia.h +/// \brief Classes for the Camellia block cipher + +#ifndef CRYPTOPP_CAMELLIA_H +#define CRYPTOPP_CAMELLIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Camellia block cipher information +struct Camellia_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Camellia";} +}; + +/// \brief Camellia block cipher +/// \sa Camellia +class Camellia : public Camellia_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + CRYPTOPP_ALIGN_DATA(4) static const byte s1[256]; + static const word32 SP[4][256]; + + unsigned int m_rounds; + SecBlock m_key; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Camellia::Encryption CamelliaEncryption; +typedef Camellia::Decryption CamelliaDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/cast.cpp b/extension/third_party/cryptopp/cast.cpp new file mode 100644 index 00000000..a63e3f8b --- /dev/null +++ b/extension/third_party/cryptopp/cast.cpp @@ -0,0 +1,292 @@ +// cast.cpp - originally written and placed in the public domain by Wei Dai and Leonard Janke +// based on Steve Reid's public domain cast.c + +#include "pch.h" +#include "cast.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/* Macros to access 8-bit bytes out of a 32-bit word */ +#define U8a(x) GETBYTE(x,3) +#define U8b(x) GETBYTE(x,2) +#define U8c(x) GETBYTE(x,1) +#define U8d(x) GETBYTE(x,0) + +/* CAST uses three different round functions */ +#define f1(l, r, km, kr) \ + t = rotlVariable(km + r, kr); \ + l ^= ((S[0][U8a(t)] ^ S[1][U8b(t)]) - \ + S[2][U8c(t)]) + S[3][U8d(t)]; +#define f2(l, r, km, kr) \ + t = rotlVariable(km ^ r, kr); \ + l ^= ((S[0][U8a(t)] - S[1][U8b(t)]) + \ + S[2][U8c(t)]) ^ S[3][U8d(t)]; +#define f3(l, r, km, kr) \ + t = rotlVariable(km - r, kr); \ + l ^= ((S[0][U8a(t)] + S[1][U8b(t)]) ^ \ + S[2][U8c(t)]) - S[3][U8d(t)]; + +#define F1(l, r, i, j) f1(l, r, K[i], K[i+j]) +#define F2(l, r, i, j) f2(l, r, K[i], K[i+j]) +#define F3(l, r, i, j) f3(l, r, K[i], K[i+j]) + +typedef BlockGetAndPut Block; + +void CAST128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 &t=m_t[0], &l=m_t[1], &r=m_t[2]; + + /* Get inblock into l,r */ + Block::Get(inBlock)(l)(r); + /* Do the work */ + F1(l, r, 0, 16); + F2(r, l, 1, 16); + F3(l, r, 2, 16); + F1(r, l, 3, 16); + F2(l, r, 4, 16); + F3(r, l, 5, 16); + F1(l, r, 6, 16); + F2(r, l, 7, 16); + F3(l, r, 8, 16); + F1(r, l, 9, 16); + F2(l, r, 10, 16); + F3(r, l, 11, 16); + /* Only do full 16 rounds if key length > 80 bits */ + if (!reduced) { + F1(l, r, 12, 16); + F2(r, l, 13, 16); + F3(l, r, 14, 16); + F1(r, l, 15, 16); + } + /* Put l,r into outblock */ + Block::Put(xorBlock, outBlock)(r)(l); +} + +void CAST128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 &t=m_t[0], &l=m_t[1], &r=m_t[2]; + + /* Get inblock into l,r */ + Block::Get(inBlock)(r)(l); + /* Only do full 16 rounds if key length > 80 bits */ + if (!reduced) { + F1(r, l, 15, 16); + F3(l, r, 14, 16); + F2(r, l, 13, 16); + F1(l, r, 12, 16); + } + F3(r, l, 11, 16); + F2(l, r, 10, 16); + F1(r, l, 9, 16); + F3(l, r, 8, 16); + F2(r, l, 7, 16); + F1(l, r, 6, 16); + F3(r, l, 5, 16); + F2(l, r, 4, 16); + F1(r, l, 3, 16); + F3(l, r, 2, 16); + F2(r, l, 1, 16); + F1(l, r, 0, 16); + /* Put l,r into outblock */ + Block::Put(xorBlock, outBlock)(l)(r); +} + +void CAST128::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + reduced = (keylength <= 10); + + word32 X[4], Z[4]={0}; + GetUserKey(BIG_ENDIAN_ORDER, X, 4, userKey, keylength); + +#define x(i) GETBYTE(X[i/4], 3-i%4) +#define z(i) GETBYTE(Z[i/4], 3-i%4) + + unsigned int i; + for (i=0; i<=16; i+=16) + { + // this part is copied directly from RFC 2144 (with some search and replace) by Wei Dai + Z[0] = X[0] ^ S[4][x(0xD)] ^ S[5][x(0xF)] ^ S[6][x(0xC)] ^ S[7][x(0xE)] ^ S[6][x(0x8)]; + Z[1] = X[2] ^ S[4][z(0x0)] ^ S[5][z(0x2)] ^ S[6][z(0x1)] ^ S[7][z(0x3)] ^ S[7][x(0xA)]; + Z[2] = X[3] ^ S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[4][x(0x9)]; + Z[3] = X[1] ^ S[4][z(0xA)] ^ S[5][z(0x9)] ^ S[6][z(0xB)] ^ S[7][z(0x8)] ^ S[5][x(0xB)]; + K[i+0] = S[4][z(0x8)] ^ S[5][z(0x9)] ^ S[6][z(0x7)] ^ S[7][z(0x6)] ^ S[4][z(0x2)]; + K[i+1] = S[4][z(0xA)] ^ S[5][z(0xB)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[5][z(0x6)]; + K[i+2] = S[4][z(0xC)] ^ S[5][z(0xD)] ^ S[6][z(0x3)] ^ S[7][z(0x2)] ^ S[6][z(0x9)]; + K[i+3] = S[4][z(0xE)] ^ S[5][z(0xF)] ^ S[6][z(0x1)] ^ S[7][z(0x0)] ^ S[7][z(0xC)]; + X[0] = Z[2] ^ S[4][z(0x5)] ^ S[5][z(0x7)] ^ S[6][z(0x4)] ^ S[7][z(0x6)] ^ S[6][z(0x0)]; + X[1] = Z[0] ^ S[4][x(0x0)] ^ S[5][x(0x2)] ^ S[6][x(0x1)] ^ S[7][x(0x3)] ^ S[7][z(0x2)]; + X[2] = Z[1] ^ S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[4][z(0x1)]; + X[3] = Z[3] ^ S[4][x(0xA)] ^ S[5][x(0x9)] ^ S[6][x(0xB)] ^ S[7][x(0x8)] ^ S[5][z(0x3)]; + K[i+4] = S[4][x(0x3)] ^ S[5][x(0x2)] ^ S[6][x(0xC)] ^ S[7][x(0xD)] ^ S[4][x(0x8)]; + K[i+5] = S[4][x(0x1)] ^ S[5][x(0x0)] ^ S[6][x(0xE)] ^ S[7][x(0xF)] ^ S[5][x(0xD)]; + K[i+6] = S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x8)] ^ S[7][x(0x9)] ^ S[6][x(0x3)]; + K[i+7] = S[4][x(0x5)] ^ S[5][x(0x4)] ^ S[6][x(0xA)] ^ S[7][x(0xB)] ^ S[7][x(0x7)]; + Z[0] = X[0] ^ S[4][x(0xD)] ^ S[5][x(0xF)] ^ S[6][x(0xC)] ^ S[7][x(0xE)] ^ S[6][x(0x8)]; + Z[1] = X[2] ^ S[4][z(0x0)] ^ S[5][z(0x2)] ^ S[6][z(0x1)] ^ S[7][z(0x3)] ^ S[7][x(0xA)]; + Z[2] = X[3] ^ S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x5)] ^ S[7][z(0x4)] ^ S[4][x(0x9)]; + Z[3] = X[1] ^ S[4][z(0xA)] ^ S[5][z(0x9)] ^ S[6][z(0xB)] ^ S[7][z(0x8)] ^ S[5][x(0xB)]; + K[i+8] = S[4][z(0x3)] ^ S[5][z(0x2)] ^ S[6][z(0xC)] ^ S[7][z(0xD)] ^ S[4][z(0x9)]; + K[i+9] = S[4][z(0x1)] ^ S[5][z(0x0)] ^ S[6][z(0xE)] ^ S[7][z(0xF)] ^ S[5][z(0xC)]; + K[i+10] = S[4][z(0x7)] ^ S[5][z(0x6)] ^ S[6][z(0x8)] ^ S[7][z(0x9)] ^ S[6][z(0x2)]; + K[i+11] = S[4][z(0x5)] ^ S[5][z(0x4)] ^ S[6][z(0xA)] ^ S[7][z(0xB)] ^ S[7][z(0x6)]; + X[0] = Z[2] ^ S[4][z(0x5)] ^ S[5][z(0x7)] ^ S[6][z(0x4)] ^ S[7][z(0x6)] ^ S[6][z(0x0)]; + X[1] = Z[0] ^ S[4][x(0x0)] ^ S[5][x(0x2)] ^ S[6][x(0x1)] ^ S[7][x(0x3)] ^ S[7][z(0x2)]; + X[2] = Z[1] ^ S[4][x(0x7)] ^ S[5][x(0x6)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[4][z(0x1)]; + X[3] = Z[3] ^ S[4][x(0xA)] ^ S[5][x(0x9)] ^ S[6][x(0xB)] ^ S[7][x(0x8)] ^ S[5][z(0x3)]; + K[i+12] = S[4][x(0x8)] ^ S[5][x(0x9)] ^ S[6][x(0x7)] ^ S[7][x(0x6)] ^ S[4][x(0x3)]; + K[i+13] = S[4][x(0xA)] ^ S[5][x(0xB)] ^ S[6][x(0x5)] ^ S[7][x(0x4)] ^ S[5][x(0x7)]; + K[i+14] = S[4][x(0xC)] ^ S[5][x(0xD)] ^ S[6][x(0x3)] ^ S[7][x(0x2)] ^ S[6][x(0x8)]; + K[i+15] = S[4][x(0xE)] ^ S[5][x(0xF)] ^ S[6][x(0x1)] ^ S[7][x(0x0)] ^ S[7][x(0xD)]; + } + + for (i=16; i<32; i++) + K[i] &= 0x1f; +} + +// The following CAST-256 implementation was contributed by Leonard Janke + +const word32 CAST256::Base::t_m[8][24]={ +{ 0x5a827999, 0xd151d6a1, 0x482133a9, 0xbef090b1, 0x35bfedb9, 0xac8f4ac1, + 0x235ea7c9, 0x9a2e04d1, 0x10fd61d9, 0x87ccbee1, 0xfe9c1be9, 0x756b78f1, + 0xec3ad5f9, 0x630a3301, 0xd9d99009, 0x50a8ed11, 0xc7784a19, 0x3e47a721, + 0xb5170429, 0x2be66131, 0xa2b5be39, 0x19851b41, 0x90547849, 0x0723d551}, +{ 0xc95c653a, 0x402bc242, 0xb6fb1f4a, 0x2dca7c52, 0xa499d95a, 0x1b693662, + 0x9238936a, 0x0907f072, 0x7fd74d7a, 0xf6a6aa82, 0x6d76078a, 0xe4456492, + 0x5b14c19a, 0xd1e41ea2, 0x48b37baa, 0xbf82d8b2, 0x365235ba, 0xad2192c2, + 0x23f0efca, 0x9ac04cd2, 0x118fa9da, 0x885f06e2, 0xff2e63ea, 0x75fdc0f2}, +{ 0x383650db, 0xaf05ade3, 0x25d50aeb, 0x9ca467f3, 0x1373c4fb, 0x8a432203, + 0x01127f0b, 0x77e1dc13, 0xeeb1391b, 0x65809623, 0xdc4ff32b, 0x531f5033, + 0xc9eead3b, 0x40be0a43, 0xb78d674b, 0x2e5cc453, 0xa52c215b, 0x1bfb7e63, + 0x92cadb6b, 0x099a3873, 0x8069957b, 0xf738f283, 0x6e084f8b, 0xe4d7ac93}, +{ 0xa7103c7c, 0x1ddf9984, 0x94aef68c, 0x0b7e5394, 0x824db09c, 0xf91d0da4, + 0x6fec6aac, 0xe6bbc7b4, 0x5d8b24bc, 0xd45a81c4, 0x4b29decc, 0xc1f93bd4, + 0x38c898dc, 0xaf97f5e4, 0x266752ec, 0x9d36aff4, 0x14060cfc, 0x8ad56a04, + 0x01a4c70c, 0x78742414, 0xef43811c, 0x6612de24, 0xdce23b2c, 0x53b19834}, +{ 0x15ea281d, 0x8cb98525, 0x0388e22d, 0x7a583f35, 0xf1279c3d, 0x67f6f945, + 0xdec6564d, 0x5595b355, 0xcc65105d, 0x43346d65, 0xba03ca6d, 0x30d32775, + 0xa7a2847d, 0x1e71e185, 0x95413e8d, 0x0c109b95, 0x82dff89d, 0xf9af55a5, + 0x707eb2ad, 0xe74e0fb5, 0x5e1d6cbd, 0xd4ecc9c5, 0x4bbc26cd, 0xc28b83d5}, +{ 0x84c413be, 0xfb9370c6, 0x7262cdce, 0xe9322ad6, 0x600187de, 0xd6d0e4e6, + 0x4da041ee, 0xc46f9ef6, 0x3b3efbfe, 0xb20e5906, 0x28ddb60e, 0x9fad1316, + 0x167c701e, 0x8d4bcd26, 0x041b2a2e, 0x7aea8736, 0xf1b9e43e, 0x68894146, + 0xdf589e4e, 0x5627fb56, 0xccf7585e, 0x43c6b566, 0xba96126e, 0x31656f76}, +{ 0xf39dff5f, 0x6a6d5c67, 0xe13cb96f, 0x580c1677, 0xcedb737f, 0x45aad087, + 0xbc7a2d8f, 0x33498a97, 0xaa18e79f, 0x20e844a7, 0x97b7a1af, 0x0e86feb7, + 0x85565bbf, 0xfc25b8c7, 0x72f515cf, 0xe9c472d7, 0x6093cfdf, 0xd7632ce7, + 0x4e3289ef, 0xc501e6f7, 0x3bd143ff, 0xb2a0a107, 0x296ffe0f, 0xa03f5b17}, +{ 0x6277eb00, 0xd9474808, 0x5016a510, 0xc6e60218, 0x3db55f20, 0xb484bc28, + 0x2b541930, 0xa2237638, 0x18f2d340, 0x8fc23048, 0x06918d50, 0x7d60ea58, + 0xf4304760, 0x6affa468, 0xe1cf0170, 0x589e5e78, 0xcf6dbb80, 0x463d1888, + 0xbd0c7590, 0x33dbd298, 0xaaab2fa0, 0x217a8ca8, 0x9849e9b0, 0x0f1946b8} +}; + +const unsigned int CAST256::Base::t_r[8][24]={ + {19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11, 19, 27, 3, 11}, + {4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28, 4, 12, 20, 28}, + {21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13, 21, 29, 5, 13}, + {6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30, 6, 14, 22, 30}, + {23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15, 23, 31, 7, 15}, + {8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0}, + {25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17, 25, 1, 9, 17}, + {10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2, 10, 18, 26, 2} +}; + +#define Q(i) \ + F1(block[2],block[3],8*i+4,-4); \ + F2(block[1],block[2],8*i+5,-4); \ + F3(block[0],block[1],8*i+6,-4); \ + F1(block[3],block[0],8*i+7,-4); + +#define QBar(i) \ + F1(block[3],block[0],8*i+7,-4); \ + F3(block[0],block[1],8*i+6,-4); \ + F2(block[1],block[2],8*i+5,-4); \ + F1(block[2],block[3],8*i+4,-4); + +/* CAST256's encrypt/decrypt functions are identical except for the order that +the keys are used */ + +void CAST256::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // TODO: add a SecBlock workspace to the class when the ABI can change + word32 t, block[4]; + Block::Get(inBlock)(block[0])(block[1])(block[2])(block[3]); + + // Perform 6 forward quad rounds + Q(0); + Q(1); + Q(2); + Q(3); + Q(4); + Q(5); + + // Perform 6 reverse quad rounds + QBar(6); + QBar(7); + QBar(8); + QBar(9); + QBar(10); + QBar(11); + + Block::Put(xorBlock, outBlock)(block[0])(block[1])(block[2])(block[3]); +} + +/* Set up a CAST-256 key */ + +void CAST256::Base::Omega(int i, word32 kappa[8]) +{ + word32 t; + + f1(kappa[6],kappa[7],t_m[0][i],t_r[0][i]); + f2(kappa[5],kappa[6],t_m[1][i],t_r[1][i]); + f3(kappa[4],kappa[5],t_m[2][i],t_r[2][i]); + f1(kappa[3],kappa[4],t_m[3][i],t_r[3][i]); + f2(kappa[2],kappa[3],t_m[4][i],t_r[4][i]); + f3(kappa[1],kappa[2],t_m[5][i],t_r[5][i]); + f1(kappa[0],kappa[1],t_m[6][i],t_r[6][i]); + f2(kappa[7],kappa[0],t_m[7][i],t_r[7][i]); +} + +void CAST256::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + GetUserKey(BIG_ENDIAN_ORDER, kappa.begin(), 8, userKey, keylength); + + for(int i=0; i<12; ++i) + { + Omega(2*i,kappa); + Omega(2*i+1,kappa); + + K[8*i]=kappa[0] & 31; + K[8*i+1]=kappa[2] & 31; + K[8*i+2]=kappa[4] & 31; + K[8*i+3]=kappa[6] & 31; + K[8*i+4]=kappa[7]; + K[8*i+5]=kappa[5]; + K[8*i+6]=kappa[3]; + K[8*i+7]=kappa[1]; + } + + if (!IsForwardTransformation()) + { + for(int j=0; j<6; ++j) + { + for(int i=0; i<4; ++i) + { + int i1=8*j+i; + int i2=8*(11-j)+i; + + CRYPTOPP_ASSERT(i1, public VariableKeyLength<16, 5, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-128";} +}; + +/// \brief CAST128 block cipher +/// \sa CAST-128 +/// \since Crypto++ 2.2 +class CAST128 : public CAST128_Info, public BlockCipherDocumentation +{ + /// \brief CAST128 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + bool reduced; + FixedSizeSecBlock K; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief CAST128 block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief CAST128 block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief CAST256 block cipher information +/// \since Crypto++ 4.0 +struct CAST256_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-256";} +}; + +/// \brief CAST256 block cipher +/// \sa CAST-256 +/// \since Crypto++ 4.0 +class CAST256 : public CAST256_Info, public BlockCipherDocumentation +{ + /// \brief CAST256 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + static const word32 t_m[8][24]; + static const unsigned int t_r[8][24]; + + static void Omega(int i, word32 kappa[8]); + + FixedSizeSecBlock K; + mutable FixedSizeSecBlock kappa; + mutable FixedSizeSecBlock m_t; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef CAST128::Encryption CAST128Encryption; +typedef CAST128::Decryption CAST128Decryption; + +typedef CAST256::Encryption CAST256Encryption; +typedef CAST256::Decryption CAST256Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/casts.cpp b/extension/third_party/cryptopp/casts.cpp new file mode 100644 index 00000000..d823d725 --- /dev/null +++ b/extension/third_party/cryptopp/casts.cpp @@ -0,0 +1,545 @@ +#include "pch.h" +#include "cast.h" + +NAMESPACE_BEGIN(CryptoPP) + +// CAST S-boxes + +const word32 CAST::S[8][256] = { +{ + 0x30FB40D4UL, 0x9FA0FF0BUL, 0x6BECCD2FUL, 0x3F258C7AUL, + 0x1E213F2FUL, 0x9C004DD3UL, 0x6003E540UL, 0xCF9FC949UL, + 0xBFD4AF27UL, 0x88BBBDB5UL, 0xE2034090UL, 0x98D09675UL, + 0x6E63A0E0UL, 0x15C361D2UL, 0xC2E7661DUL, 0x22D4FF8EUL, + 0x28683B6FUL, 0xC07FD059UL, 0xFF2379C8UL, 0x775F50E2UL, + 0x43C340D3UL, 0xDF2F8656UL, 0x887CA41AUL, 0xA2D2BD2DUL, + 0xA1C9E0D6UL, 0x346C4819UL, 0x61B76D87UL, 0x22540F2FUL, + 0x2ABE32E1UL, 0xAA54166BUL, 0x22568E3AUL, 0xA2D341D0UL, + 0x66DB40C8UL, 0xA784392FUL, 0x004DFF2FUL, 0x2DB9D2DEUL, + 0x97943FACUL, 0x4A97C1D8UL, 0x527644B7UL, 0xB5F437A7UL, + 0xB82CBAEFUL, 0xD751D159UL, 0x6FF7F0EDUL, 0x5A097A1FUL, + 0x827B68D0UL, 0x90ECF52EUL, 0x22B0C054UL, 0xBC8E5935UL, + 0x4B6D2F7FUL, 0x50BB64A2UL, 0xD2664910UL, 0xBEE5812DUL, + 0xB7332290UL, 0xE93B159FUL, 0xB48EE411UL, 0x4BFF345DUL, + 0xFD45C240UL, 0xAD31973FUL, 0xC4F6D02EUL, 0x55FC8165UL, + 0xD5B1CAADUL, 0xA1AC2DAEUL, 0xA2D4B76DUL, 0xC19B0C50UL, + 0x882240F2UL, 0x0C6E4F38UL, 0xA4E4BFD7UL, 0x4F5BA272UL, + 0x564C1D2FUL, 0xC59C5319UL, 0xB949E354UL, 0xB04669FEUL, + 0xB1B6AB8AUL, 0xC71358DDUL, 0x6385C545UL, 0x110F935DUL, + 0x57538AD5UL, 0x6A390493UL, 0xE63D37E0UL, 0x2A54F6B3UL, + 0x3A787D5FUL, 0x6276A0B5UL, 0x19A6FCDFUL, 0x7A42206AUL, + 0x29F9D4D5UL, 0xF61B1891UL, 0xBB72275EUL, 0xAA508167UL, + 0x38901091UL, 0xC6B505EBUL, 0x84C7CB8CUL, 0x2AD75A0FUL, + 0x874A1427UL, 0xA2D1936BUL, 0x2AD286AFUL, 0xAA56D291UL, + 0xD7894360UL, 0x425C750DUL, 0x93B39E26UL, 0x187184C9UL, + 0x6C00B32DUL, 0x73E2BB14UL, 0xA0BEBC3CUL, 0x54623779UL, + 0x64459EABUL, 0x3F328B82UL, 0x7718CF82UL, 0x59A2CEA6UL, + 0x04EE002EUL, 0x89FE78E6UL, 0x3FAB0950UL, 0x325FF6C2UL, + 0x81383F05UL, 0x6963C5C8UL, 0x76CB5AD6UL, 0xD49974C9UL, + 0xCA180DCFUL, 0x380782D5UL, 0xC7FA5CF6UL, 0x8AC31511UL, + 0x35E79E13UL, 0x47DA91D0UL, 0xF40F9086UL, 0xA7E2419EUL, + 0x31366241UL, 0x051EF495UL, 0xAA573B04UL, 0x4A805D8DUL, + 0x548300D0UL, 0x00322A3CUL, 0xBF64CDDFUL, 0xBA57A68EUL, + 0x75C6372BUL, 0x50AFD341UL, 0xA7C13275UL, 0x915A0BF5UL, + 0x6B54BFABUL, 0x2B0B1426UL, 0xAB4CC9D7UL, 0x449CCD82UL, + 0xF7FBF265UL, 0xAB85C5F3UL, 0x1B55DB94UL, 0xAAD4E324UL, + 0xCFA4BD3FUL, 0x2DEAA3E2UL, 0x9E204D02UL, 0xC8BD25ACUL, + 0xEADF55B3UL, 0xD5BD9E98UL, 0xE31231B2UL, 0x2AD5AD6CUL, + 0x954329DEUL, 0xADBE4528UL, 0xD8710F69UL, 0xAA51C90FUL, + 0xAA786BF6UL, 0x22513F1EUL, 0xAA51A79BUL, 0x2AD344CCUL, + 0x7B5A41F0UL, 0xD37CFBADUL, 0x1B069505UL, 0x41ECE491UL, + 0xB4C332E6UL, 0x032268D4UL, 0xC9600ACCUL, 0xCE387E6DUL, + 0xBF6BB16CUL, 0x6A70FB78UL, 0x0D03D9C9UL, 0xD4DF39DEUL, + 0xE01063DAUL, 0x4736F464UL, 0x5AD328D8UL, 0xB347CC96UL, + 0x75BB0FC3UL, 0x98511BFBUL, 0x4FFBCC35UL, 0xB58BCF6AUL, + 0xE11F0ABCUL, 0xBFC5FE4AUL, 0xA70AEC10UL, 0xAC39570AUL, + 0x3F04442FUL, 0x6188B153UL, 0xE0397A2EUL, 0x5727CB79UL, + 0x9CEB418FUL, 0x1CACD68DUL, 0x2AD37C96UL, 0x0175CB9DUL, + 0xC69DFF09UL, 0xC75B65F0UL, 0xD9DB40D8UL, 0xEC0E7779UL, + 0x4744EAD4UL, 0xB11C3274UL, 0xDD24CB9EUL, 0x7E1C54BDUL, + 0xF01144F9UL, 0xD2240EB1UL, 0x9675B3FDUL, 0xA3AC3755UL, + 0xD47C27AFUL, 0x51C85F4DUL, 0x56907596UL, 0xA5BB15E6UL, + 0x580304F0UL, 0xCA042CF1UL, 0x011A37EAUL, 0x8DBFAADBUL, + 0x35BA3E4AUL, 0x3526FFA0UL, 0xC37B4D09UL, 0xBC306ED9UL, + 0x98A52666UL, 0x5648F725UL, 0xFF5E569DUL, 0x0CED63D0UL, + 0x7C63B2CFUL, 0x700B45E1UL, 0xD5EA50F1UL, 0x85A92872UL, + 0xAF1FBDA7UL, 0xD4234870UL, 0xA7870BF3UL, 0x2D3B4D79UL, + 0x42E04198UL, 0x0CD0EDE7UL, 0x26470DB8UL, 0xF881814CUL, + 0x474D6AD7UL, 0x7C0C5E5CUL, 0xD1231959UL, 0x381B7298UL, + 0xF5D2F4DBUL, 0xAB838653UL, 0x6E2F1E23UL, 0x83719C9EUL, + 0xBD91E046UL, 0x9A56456EUL, 0xDC39200CUL, 0x20C8C571UL, + 0x962BDA1CUL, 0xE1E696FFUL, 0xB141AB08UL, 0x7CCA89B9UL, + 0x1A69E783UL, 0x02CC4843UL, 0xA2F7C579UL, 0x429EF47DUL, + 0x427B169CUL, 0x5AC9F049UL, 0xDD8F0F00UL, 0x5C8165BFUL +}, + +{ + 0x1F201094UL, 0xEF0BA75BUL, 0x69E3CF7EUL, 0x393F4380UL, + 0xFE61CF7AUL, 0xEEC5207AUL, 0x55889C94UL, 0x72FC0651UL, + 0xADA7EF79UL, 0x4E1D7235UL, 0xD55A63CEUL, 0xDE0436BAUL, + 0x99C430EFUL, 0x5F0C0794UL, 0x18DCDB7DUL, 0xA1D6EFF3UL, + 0xA0B52F7BUL, 0x59E83605UL, 0xEE15B094UL, 0xE9FFD909UL, + 0xDC440086UL, 0xEF944459UL, 0xBA83CCB3UL, 0xE0C3CDFBUL, + 0xD1DA4181UL, 0x3B092AB1UL, 0xF997F1C1UL, 0xA5E6CF7BUL, + 0x01420DDBUL, 0xE4E7EF5BUL, 0x25A1FF41UL, 0xE180F806UL, + 0x1FC41080UL, 0x179BEE7AUL, 0xD37AC6A9UL, 0xFE5830A4UL, + 0x98DE8B7FUL, 0x77E83F4EUL, 0x79929269UL, 0x24FA9F7BUL, + 0xE113C85BUL, 0xACC40083UL, 0xD7503525UL, 0xF7EA615FUL, + 0x62143154UL, 0x0D554B63UL, 0x5D681121UL, 0xC866C359UL, + 0x3D63CF73UL, 0xCEE234C0UL, 0xD4D87E87UL, 0x5C672B21UL, + 0x071F6181UL, 0x39F7627FUL, 0x361E3084UL, 0xE4EB573BUL, + 0x602F64A4UL, 0xD63ACD9CUL, 0x1BBC4635UL, 0x9E81032DUL, + 0x2701F50CUL, 0x99847AB4UL, 0xA0E3DF79UL, 0xBA6CF38CUL, + 0x10843094UL, 0x2537A95EUL, 0xF46F6FFEUL, 0xA1FF3B1FUL, + 0x208CFB6AUL, 0x8F458C74UL, 0xD9E0A227UL, 0x4EC73A34UL, + 0xFC884F69UL, 0x3E4DE8DFUL, 0xEF0E0088UL, 0x3559648DUL, + 0x8A45388CUL, 0x1D804366UL, 0x721D9BFDUL, 0xA58684BBUL, + 0xE8256333UL, 0x844E8212UL, 0x128D8098UL, 0xFED33FB4UL, + 0xCE280AE1UL, 0x27E19BA5UL, 0xD5A6C252UL, 0xE49754BDUL, + 0xC5D655DDUL, 0xEB667064UL, 0x77840B4DUL, 0xA1B6A801UL, + 0x84DB26A9UL, 0xE0B56714UL, 0x21F043B7UL, 0xE5D05860UL, + 0x54F03084UL, 0x066FF472UL, 0xA31AA153UL, 0xDADC4755UL, + 0xB5625DBFUL, 0x68561BE6UL, 0x83CA6B94UL, 0x2D6ED23BUL, + 0xECCF01DBUL, 0xA6D3D0BAUL, 0xB6803D5CUL, 0xAF77A709UL, + 0x33B4A34CUL, 0x397BC8D6UL, 0x5EE22B95UL, 0x5F0E5304UL, + 0x81ED6F61UL, 0x20E74364UL, 0xB45E1378UL, 0xDE18639BUL, + 0x881CA122UL, 0xB96726D1UL, 0x8049A7E8UL, 0x22B7DA7BUL, + 0x5E552D25UL, 0x5272D237UL, 0x79D2951CUL, 0xC60D894CUL, + 0x488CB402UL, 0x1BA4FE5BUL, 0xA4B09F6BUL, 0x1CA815CFUL, + 0xA20C3005UL, 0x8871DF63UL, 0xB9DE2FCBUL, 0x0CC6C9E9UL, + 0x0BEEFF53UL, 0xE3214517UL, 0xB4542835UL, 0x9F63293CUL, + 0xEE41E729UL, 0x6E1D2D7CUL, 0x50045286UL, 0x1E6685F3UL, + 0xF33401C6UL, 0x30A22C95UL, 0x31A70850UL, 0x60930F13UL, + 0x73F98417UL, 0xA1269859UL, 0xEC645C44UL, 0x52C877A9UL, + 0xCDFF33A6UL, 0xA02B1741UL, 0x7CBAD9A2UL, 0x2180036FUL, + 0x50D99C08UL, 0xCB3F4861UL, 0xC26BD765UL, 0x64A3F6ABUL, + 0x80342676UL, 0x25A75E7BUL, 0xE4E6D1FCUL, 0x20C710E6UL, + 0xCDF0B680UL, 0x17844D3BUL, 0x31EEF84DUL, 0x7E0824E4UL, + 0x2CCB49EBUL, 0x846A3BAEUL, 0x8FF77888UL, 0xEE5D60F6UL, + 0x7AF75673UL, 0x2FDD5CDBUL, 0xA11631C1UL, 0x30F66F43UL, + 0xB3FAEC54UL, 0x157FD7FAUL, 0xEF8579CCUL, 0xD152DE58UL, + 0xDB2FFD5EUL, 0x8F32CE19UL, 0x306AF97AUL, 0x02F03EF8UL, + 0x99319AD5UL, 0xC242FA0FUL, 0xA7E3EBB0UL, 0xC68E4906UL, + 0xB8DA230CUL, 0x80823028UL, 0xDCDEF3C8UL, 0xD35FB171UL, + 0x088A1BC8UL, 0xBEC0C560UL, 0x61A3C9E8UL, 0xBCA8F54DUL, + 0xC72FEFFAUL, 0x22822E99UL, 0x82C570B4UL, 0xD8D94E89UL, + 0x8B1C34BCUL, 0x301E16E6UL, 0x273BE979UL, 0xB0FFEAA6UL, + 0x61D9B8C6UL, 0x00B24869UL, 0xB7FFCE3FUL, 0x08DC283BUL, + 0x43DAF65AUL, 0xF7E19798UL, 0x7619B72FUL, 0x8F1C9BA4UL, + 0xDC8637A0UL, 0x16A7D3B1UL, 0x9FC393B7UL, 0xA7136EEBUL, + 0xC6BCC63EUL, 0x1A513742UL, 0xEF6828BCUL, 0x520365D6UL, + 0x2D6A77ABUL, 0x3527ED4BUL, 0x821FD216UL, 0x095C6E2EUL, + 0xDB92F2FBUL, 0x5EEA29CBUL, 0x145892F5UL, 0x91584F7FUL, + 0x5483697BUL, 0x2667A8CCUL, 0x85196048UL, 0x8C4BACEAUL, + 0x833860D4UL, 0x0D23E0F9UL, 0x6C387E8AUL, 0x0AE6D249UL, + 0xB284600CUL, 0xD835731DUL, 0xDCB1C647UL, 0xAC4C56EAUL, + 0x3EBD81B3UL, 0x230EABB0UL, 0x6438BC87UL, 0xF0B5B1FAUL, + 0x8F5EA2B3UL, 0xFC184642UL, 0x0A036B7AUL, 0x4FB089BDUL, + 0x649DA589UL, 0xA345415EUL, 0x5C038323UL, 0x3E5D3BB9UL, + 0x43D79572UL, 0x7E6DD07CUL, 0x06DFDF1EUL, 0x6C6CC4EFUL, + 0x7160A539UL, 0x73BFBE70UL, 0x83877605UL, 0x4523ECF1UL +}, + +{ + 0x8DEFC240UL, 0x25FA5D9FUL, 0xEB903DBFUL, 0xE810C907UL, + 0x47607FFFUL, 0x369FE44BUL, 0x8C1FC644UL, 0xAECECA90UL, + 0xBEB1F9BFUL, 0xEEFBCAEAUL, 0xE8CF1950UL, 0x51DF07AEUL, + 0x920E8806UL, 0xF0AD0548UL, 0xE13C8D83UL, 0x927010D5UL, + 0x11107D9FUL, 0x07647DB9UL, 0xB2E3E4D4UL, 0x3D4F285EUL, + 0xB9AFA820UL, 0xFADE82E0UL, 0xA067268BUL, 0x8272792EUL, + 0x553FB2C0UL, 0x489AE22BUL, 0xD4EF9794UL, 0x125E3FBCUL, + 0x21FFFCEEUL, 0x825B1BFDUL, 0x9255C5EDUL, 0x1257A240UL, + 0x4E1A8302UL, 0xBAE07FFFUL, 0x528246E7UL, 0x8E57140EUL, + 0x3373F7BFUL, 0x8C9F8188UL, 0xA6FC4EE8UL, 0xC982B5A5UL, + 0xA8C01DB7UL, 0x579FC264UL, 0x67094F31UL, 0xF2BD3F5FUL, + 0x40FFF7C1UL, 0x1FB78DFCUL, 0x8E6BD2C1UL, 0x437BE59BUL, + 0x99B03DBFUL, 0xB5DBC64BUL, 0x638DC0E6UL, 0x55819D99UL, + 0xA197C81CUL, 0x4A012D6EUL, 0xC5884A28UL, 0xCCC36F71UL, + 0xB843C213UL, 0x6C0743F1UL, 0x8309893CUL, 0x0FEDDD5FUL, + 0x2F7FE850UL, 0xD7C07F7EUL, 0x02507FBFUL, 0x5AFB9A04UL, + 0xA747D2D0UL, 0x1651192EUL, 0xAF70BF3EUL, 0x58C31380UL, + 0x5F98302EUL, 0x727CC3C4UL, 0x0A0FB402UL, 0x0F7FEF82UL, + 0x8C96FDADUL, 0x5D2C2AAEUL, 0x8EE99A49UL, 0x50DA88B8UL, + 0x8427F4A0UL, 0x1EAC5790UL, 0x796FB449UL, 0x8252DC15UL, + 0xEFBD7D9BUL, 0xA672597DUL, 0xADA840D8UL, 0x45F54504UL, + 0xFA5D7403UL, 0xE83EC305UL, 0x4F91751AUL, 0x925669C2UL, + 0x23EFE941UL, 0xA903F12EUL, 0x60270DF2UL, 0x0276E4B6UL, + 0x94FD6574UL, 0x927985B2UL, 0x8276DBCBUL, 0x02778176UL, + 0xF8AF918DUL, 0x4E48F79EUL, 0x8F616DDFUL, 0xE29D840EUL, + 0x842F7D83UL, 0x340CE5C8UL, 0x96BBB682UL, 0x93B4B148UL, + 0xEF303CABUL, 0x984FAF28UL, 0x779FAF9BUL, 0x92DC560DUL, + 0x224D1E20UL, 0x8437AA88UL, 0x7D29DC96UL, 0x2756D3DCUL, + 0x8B907CEEUL, 0xB51FD240UL, 0xE7C07CE3UL, 0xE566B4A1UL, + 0xC3E9615EUL, 0x3CF8209DUL, 0x6094D1E3UL, 0xCD9CA341UL, + 0x5C76460EUL, 0x00EA983BUL, 0xD4D67881UL, 0xFD47572CUL, + 0xF76CEDD9UL, 0xBDA8229CUL, 0x127DADAAUL, 0x438A074EUL, + 0x1F97C090UL, 0x081BDB8AUL, 0x93A07EBEUL, 0xB938CA15UL, + 0x97B03CFFUL, 0x3DC2C0F8UL, 0x8D1AB2ECUL, 0x64380E51UL, + 0x68CC7BFBUL, 0xD90F2788UL, 0x12490181UL, 0x5DE5FFD4UL, + 0xDD7EF86AUL, 0x76A2E214UL, 0xB9A40368UL, 0x925D958FUL, + 0x4B39FFFAUL, 0xBA39AEE9UL, 0xA4FFD30BUL, 0xFAF7933BUL, + 0x6D498623UL, 0x193CBCFAUL, 0x27627545UL, 0x825CF47AUL, + 0x61BD8BA0UL, 0xD11E42D1UL, 0xCEAD04F4UL, 0x127EA392UL, + 0x10428DB7UL, 0x8272A972UL, 0x9270C4A8UL, 0x127DE50BUL, + 0x285BA1C8UL, 0x3C62F44FUL, 0x35C0EAA5UL, 0xE805D231UL, + 0x428929FBUL, 0xB4FCDF82UL, 0x4FB66A53UL, 0x0E7DC15BUL, + 0x1F081FABUL, 0x108618AEUL, 0xFCFD086DUL, 0xF9FF2889UL, + 0x694BCC11UL, 0x236A5CAEUL, 0x12DECA4DUL, 0x2C3F8CC5UL, + 0xD2D02DFEUL, 0xF8EF5896UL, 0xE4CF52DAUL, 0x95155B67UL, + 0x494A488CUL, 0xB9B6A80CUL, 0x5C8F82BCUL, 0x89D36B45UL, + 0x3A609437UL, 0xEC00C9A9UL, 0x44715253UL, 0x0A874B49UL, + 0xD773BC40UL, 0x7C34671CUL, 0x02717EF6UL, 0x4FEB5536UL, + 0xA2D02FFFUL, 0xD2BF60C4UL, 0xD43F03C0UL, 0x50B4EF6DUL, + 0x07478CD1UL, 0x006E1888UL, 0xA2E53F55UL, 0xB9E6D4BCUL, + 0xA2048016UL, 0x97573833UL, 0xD7207D67UL, 0xDE0F8F3DUL, + 0x72F87B33UL, 0xABCC4F33UL, 0x7688C55DUL, 0x7B00A6B0UL, + 0x947B0001UL, 0x570075D2UL, 0xF9BB88F8UL, 0x8942019EUL, + 0x4264A5FFUL, 0x856302E0UL, 0x72DBD92BUL, 0xEE971B69UL, + 0x6EA22FDEUL, 0x5F08AE2BUL, 0xAF7A616DUL, 0xE5C98767UL, + 0xCF1FEBD2UL, 0x61EFC8C2UL, 0xF1AC2571UL, 0xCC8239C2UL, + 0x67214CB8UL, 0xB1E583D1UL, 0xB7DC3E62UL, 0x7F10BDCEUL, + 0xF90A5C38UL, 0x0FF0443DUL, 0x606E6DC6UL, 0x60543A49UL, + 0x5727C148UL, 0x2BE98A1DUL, 0x8AB41738UL, 0x20E1BE24UL, + 0xAF96DA0FUL, 0x68458425UL, 0x99833BE5UL, 0x600D457DUL, + 0x282F9350UL, 0x8334B362UL, 0xD91D1120UL, 0x2B6D8DA0UL, + 0x642B1E31UL, 0x9C305A00UL, 0x52BCE688UL, 0x1B03588AUL, + 0xF7BAEFD5UL, 0x4142ED9CUL, 0xA4315C11UL, 0x83323EC5UL, + 0xDFEF4636UL, 0xA133C501UL, 0xE9D3531CUL, 0xEE353783UL +}, + +{ + 0x9DB30420UL, 0x1FB6E9DEUL, 0xA7BE7BEFUL, 0xD273A298UL, + 0x4A4F7BDBUL, 0x64AD8C57UL, 0x85510443UL, 0xFA020ED1UL, + 0x7E287AFFUL, 0xE60FB663UL, 0x095F35A1UL, 0x79EBF120UL, + 0xFD059D43UL, 0x6497B7B1UL, 0xF3641F63UL, 0x241E4ADFUL, + 0x28147F5FUL, 0x4FA2B8CDUL, 0xC9430040UL, 0x0CC32220UL, + 0xFDD30B30UL, 0xC0A5374FUL, 0x1D2D00D9UL, 0x24147B15UL, + 0xEE4D111AUL, 0x0FCA5167UL, 0x71FF904CUL, 0x2D195FFEUL, + 0x1A05645FUL, 0x0C13FEFEUL, 0x081B08CAUL, 0x05170121UL, + 0x80530100UL, 0xE83E5EFEUL, 0xAC9AF4F8UL, 0x7FE72701UL, + 0xD2B8EE5FUL, 0x06DF4261UL, 0xBB9E9B8AUL, 0x7293EA25UL, + 0xCE84FFDFUL, 0xF5718801UL, 0x3DD64B04UL, 0xA26F263BUL, + 0x7ED48400UL, 0x547EEBE6UL, 0x446D4CA0UL, 0x6CF3D6F5UL, + 0x2649ABDFUL, 0xAEA0C7F5UL, 0x36338CC1UL, 0x503F7E93UL, + 0xD3772061UL, 0x11B638E1UL, 0x72500E03UL, 0xF80EB2BBUL, + 0xABE0502EUL, 0xEC8D77DEUL, 0x57971E81UL, 0xE14F6746UL, + 0xC9335400UL, 0x6920318FUL, 0x081DBB99UL, 0xFFC304A5UL, + 0x4D351805UL, 0x7F3D5CE3UL, 0xA6C866C6UL, 0x5D5BCCA9UL, + 0xDAEC6FEAUL, 0x9F926F91UL, 0x9F46222FUL, 0x3991467DUL, + 0xA5BF6D8EUL, 0x1143C44FUL, 0x43958302UL, 0xD0214EEBUL, + 0x022083B8UL, 0x3FB6180CUL, 0x18F8931EUL, 0x281658E6UL, + 0x26486E3EUL, 0x8BD78A70UL, 0x7477E4C1UL, 0xB506E07CUL, + 0xF32D0A25UL, 0x79098B02UL, 0xE4EABB81UL, 0x28123B23UL, + 0x69DEAD38UL, 0x1574CA16UL, 0xDF871B62UL, 0x211C40B7UL, + 0xA51A9EF9UL, 0x0014377BUL, 0x041E8AC8UL, 0x09114003UL, + 0xBD59E4D2UL, 0xE3D156D5UL, 0x4FE876D5UL, 0x2F91A340UL, + 0x557BE8DEUL, 0x00EAE4A7UL, 0x0CE5C2ECUL, 0x4DB4BBA6UL, + 0xE756BDFFUL, 0xDD3369ACUL, 0xEC17B035UL, 0x06572327UL, + 0x99AFC8B0UL, 0x56C8C391UL, 0x6B65811CUL, 0x5E146119UL, + 0x6E85CB75UL, 0xBE07C002UL, 0xC2325577UL, 0x893FF4ECUL, + 0x5BBFC92DUL, 0xD0EC3B25UL, 0xB7801AB7UL, 0x8D6D3B24UL, + 0x20C763EFUL, 0xC366A5FCUL, 0x9C382880UL, 0x0ACE3205UL, + 0xAAC9548AUL, 0xECA1D7C7UL, 0x041AFA32UL, 0x1D16625AUL, + 0x6701902CUL, 0x9B757A54UL, 0x31D477F7UL, 0x9126B031UL, + 0x36CC6FDBUL, 0xC70B8B46UL, 0xD9E66A48UL, 0x56E55A79UL, + 0x026A4CEBUL, 0x52437EFFUL, 0x2F8F76B4UL, 0x0DF980A5UL, + 0x8674CDE3UL, 0xEDDA04EBUL, 0x17A9BE04UL, 0x2C18F4DFUL, + 0xB7747F9DUL, 0xAB2AF7B4UL, 0xEFC34D20UL, 0x2E096B7CUL, + 0x1741A254UL, 0xE5B6A035UL, 0x213D42F6UL, 0x2C1C7C26UL, + 0x61C2F50FUL, 0x6552DAF9UL, 0xD2C231F8UL, 0x25130F69UL, + 0xD8167FA2UL, 0x0418F2C8UL, 0x001A96A6UL, 0x0D1526ABUL, + 0x63315C21UL, 0x5E0A72ECUL, 0x49BAFEFDUL, 0x187908D9UL, + 0x8D0DBD86UL, 0x311170A7UL, 0x3E9B640CUL, 0xCC3E10D7UL, + 0xD5CAD3B6UL, 0x0CAEC388UL, 0xF73001E1UL, 0x6C728AFFUL, + 0x71EAE2A1UL, 0x1F9AF36EUL, 0xCFCBD12FUL, 0xC1DE8417UL, + 0xAC07BE6BUL, 0xCB44A1D8UL, 0x8B9B0F56UL, 0x013988C3UL, + 0xB1C52FCAUL, 0xB4BE31CDUL, 0xD8782806UL, 0x12A3A4E2UL, + 0x6F7DE532UL, 0x58FD7EB6UL, 0xD01EE900UL, 0x24ADFFC2UL, + 0xF4990FC5UL, 0x9711AAC5UL, 0x001D7B95UL, 0x82E5E7D2UL, + 0x109873F6UL, 0x00613096UL, 0xC32D9521UL, 0xADA121FFUL, + 0x29908415UL, 0x7FBB977FUL, 0xAF9EB3DBUL, 0x29C9ED2AUL, + 0x5CE2A465UL, 0xA730F32CUL, 0xD0AA3FE8UL, 0x8A5CC091UL, + 0xD49E2CE7UL, 0x0CE454A9UL, 0xD60ACD86UL, 0x015F1919UL, + 0x77079103UL, 0xDEA03AF6UL, 0x78A8565EUL, 0xDEE356DFUL, + 0x21F05CBEUL, 0x8B75E387UL, 0xB3C50651UL, 0xB8A5C3EFUL, + 0xD8EEB6D2UL, 0xE523BE77UL, 0xC2154529UL, 0x2F69EFDFUL, + 0xAFE67AFBUL, 0xF470C4B2UL, 0xF3E0EB5BUL, 0xD6CC9876UL, + 0x39E4460CUL, 0x1FDA8538UL, 0x1987832FUL, 0xCA007367UL, + 0xA99144F8UL, 0x296B299EUL, 0x492FC295UL, 0x9266BEABUL, + 0xB5676E69UL, 0x9BD3DDDAUL, 0xDF7E052FUL, 0xDB25701CUL, + 0x1B5E51EEUL, 0xF65324E6UL, 0x6AFCE36CUL, 0x0316CC04UL, + 0x8644213EUL, 0xB7DC59D0UL, 0x7965291FUL, 0xCCD6FD43UL, + 0x41823979UL, 0x932BCDF6UL, 0xB657C34DUL, 0x4EDFD282UL, + 0x7AE5290CUL, 0x3CB9536BUL, 0x851E20FEUL, 0x9833557EUL, + 0x13ECF0B0UL, 0xD3FFB372UL, 0x3F85C5C1UL, 0x0AEF7ED2UL +}, + +{ + 0x7EC90C04UL, 0x2C6E74B9UL, 0x9B0E66DFUL, 0xA6337911UL, + 0xB86A7FFFUL, 0x1DD358F5UL, 0x44DD9D44UL, 0x1731167FUL, + 0x08FBF1FAUL, 0xE7F511CCUL, 0xD2051B00UL, 0x735ABA00UL, + 0x2AB722D8UL, 0x386381CBUL, 0xACF6243AUL, 0x69BEFD7AUL, + 0xE6A2E77FUL, 0xF0C720CDUL, 0xC4494816UL, 0xCCF5C180UL, + 0x38851640UL, 0x15B0A848UL, 0xE68B18CBUL, 0x4CAADEFFUL, + 0x5F480A01UL, 0x0412B2AAUL, 0x259814FCUL, 0x41D0EFE2UL, + 0x4E40B48DUL, 0x248EB6FBUL, 0x8DBA1CFEUL, 0x41A99B02UL, + 0x1A550A04UL, 0xBA8F65CBUL, 0x7251F4E7UL, 0x95A51725UL, + 0xC106ECD7UL, 0x97A5980AUL, 0xC539B9AAUL, 0x4D79FE6AUL, + 0xF2F3F763UL, 0x68AF8040UL, 0xED0C9E56UL, 0x11B4958BUL, + 0xE1EB5A88UL, 0x8709E6B0UL, 0xD7E07156UL, 0x4E29FEA7UL, + 0x6366E52DUL, 0x02D1C000UL, 0xC4AC8E05UL, 0x9377F571UL, + 0x0C05372AUL, 0x578535F2UL, 0x2261BE02UL, 0xD642A0C9UL, + 0xDF13A280UL, 0x74B55BD2UL, 0x682199C0UL, 0xD421E5ECUL, + 0x53FB3CE8UL, 0xC8ADEDB3UL, 0x28A87FC9UL, 0x3D959981UL, + 0x5C1FF900UL, 0xFE38D399UL, 0x0C4EFF0BUL, 0x062407EAUL, + 0xAA2F4FB1UL, 0x4FB96976UL, 0x90C79505UL, 0xB0A8A774UL, + 0xEF55A1FFUL, 0xE59CA2C2UL, 0xA6B62D27UL, 0xE66A4263UL, + 0xDF65001FUL, 0x0EC50966UL, 0xDFDD55BCUL, 0x29DE0655UL, + 0x911E739AUL, 0x17AF8975UL, 0x32C7911CUL, 0x89F89468UL, + 0x0D01E980UL, 0x524755F4UL, 0x03B63CC9UL, 0x0CC844B2UL, + 0xBCF3F0AAUL, 0x87AC36E9UL, 0xE53A7426UL, 0x01B3D82BUL, + 0x1A9E7449UL, 0x64EE2D7EUL, 0xCDDBB1DAUL, 0x01C94910UL, + 0xB868BF80UL, 0x0D26F3FDUL, 0x9342EDE7UL, 0x04A5C284UL, + 0x636737B6UL, 0x50F5B616UL, 0xF24766E3UL, 0x8ECA36C1UL, + 0x136E05DBUL, 0xFEF18391UL, 0xFB887A37UL, 0xD6E7F7D4UL, + 0xC7FB7DC9UL, 0x3063FCDFUL, 0xB6F589DEUL, 0xEC2941DAUL, + 0x26E46695UL, 0xB7566419UL, 0xF654EFC5UL, 0xD08D58B7UL, + 0x48925401UL, 0xC1BACB7FUL, 0xE5FF550FUL, 0xB6083049UL, + 0x5BB5D0E8UL, 0x87D72E5AUL, 0xAB6A6EE1UL, 0x223A66CEUL, + 0xC62BF3CDUL, 0x9E0885F9UL, 0x68CB3E47UL, 0x086C010FUL, + 0xA21DE820UL, 0xD18B69DEUL, 0xF3F65777UL, 0xFA02C3F6UL, + 0x407EDAC3UL, 0xCBB3D550UL, 0x1793084DUL, 0xB0D70EBAUL, + 0x0AB378D5UL, 0xD951FB0CUL, 0xDED7DA56UL, 0x4124BBE4UL, + 0x94CA0B56UL, 0x0F5755D1UL, 0xE0E1E56EUL, 0x6184B5BEUL, + 0x580A249FUL, 0x94F74BC0UL, 0xE327888EUL, 0x9F7B5561UL, + 0xC3DC0280UL, 0x05687715UL, 0x646C6BD7UL, 0x44904DB3UL, + 0x66B4F0A3UL, 0xC0F1648AUL, 0x697ED5AFUL, 0x49E92FF6UL, + 0x309E374FUL, 0x2CB6356AUL, 0x85808573UL, 0x4991F840UL, + 0x76F0AE02UL, 0x083BE84DUL, 0x28421C9AUL, 0x44489406UL, + 0x736E4CB8UL, 0xC1092910UL, 0x8BC95FC6UL, 0x7D869CF4UL, + 0x134F616FUL, 0x2E77118DUL, 0xB31B2BE1UL, 0xAA90B472UL, + 0x3CA5D717UL, 0x7D161BBAUL, 0x9CAD9010UL, 0xAF462BA2UL, + 0x9FE459D2UL, 0x45D34559UL, 0xD9F2DA13UL, 0xDBC65487UL, + 0xF3E4F94EUL, 0x176D486FUL, 0x097C13EAUL, 0x631DA5C7UL, + 0x445F7382UL, 0x175683F4UL, 0xCDC66A97UL, 0x70BE0288UL, + 0xB3CDCF72UL, 0x6E5DD2F3UL, 0x20936079UL, 0x459B80A5UL, + 0xBE60E2DBUL, 0xA9C23101UL, 0xEBA5315CUL, 0x224E42F2UL, + 0x1C5C1572UL, 0xF6721B2CUL, 0x1AD2FFF3UL, 0x8C25404EUL, + 0x324ED72FUL, 0x4067B7FDUL, 0x0523138EUL, 0x5CA3BC78UL, + 0xDC0FD66EUL, 0x75922283UL, 0x784D6B17UL, 0x58EBB16EUL, + 0x44094F85UL, 0x3F481D87UL, 0xFCFEAE7BUL, 0x77B5FF76UL, + 0x8C2302BFUL, 0xAAF47556UL, 0x5F46B02AUL, 0x2B092801UL, + 0x3D38F5F7UL, 0x0CA81F36UL, 0x52AF4A8AUL, 0x66D5E7C0UL, + 0xDF3B0874UL, 0x95055110UL, 0x1B5AD7A8UL, 0xF61ED5ADUL, + 0x6CF6E479UL, 0x20758184UL, 0xD0CEFA65UL, 0x88F7BE58UL, + 0x4A046826UL, 0x0FF6F8F3UL, 0xA09C7F70UL, 0x5346ABA0UL, + 0x5CE96C28UL, 0xE176EDA3UL, 0x6BAC307FUL, 0x376829D2UL, + 0x85360FA9UL, 0x17E3FE2AUL, 0x24B79767UL, 0xF5A96B20UL, + 0xD6CD2595UL, 0x68FF1EBFUL, 0x7555442CUL, 0xF19F06BEUL, + 0xF9E0659AUL, 0xEEB9491DUL, 0x34010718UL, 0xBB30CAB8UL, + 0xE822FE15UL, 0x88570983UL, 0x750E6249UL, 0xDA627E55UL, + 0x5E76FFA8UL, 0xB1534546UL, 0x6D47DE08UL, 0xEFE9E7D4UL +}, + +{ + 0xF6FA8F9DUL, 0x2CAC6CE1UL, 0x4CA34867UL, 0xE2337F7CUL, + 0x95DB08E7UL, 0x016843B4UL, 0xECED5CBCUL, 0x325553ACUL, + 0xBF9F0960UL, 0xDFA1E2EDUL, 0x83F0579DUL, 0x63ED86B9UL, + 0x1AB6A6B8UL, 0xDE5EBE39UL, 0xF38FF732UL, 0x8989B138UL, + 0x33F14961UL, 0xC01937BDUL, 0xF506C6DAUL, 0xE4625E7EUL, + 0xA308EA99UL, 0x4E23E33CUL, 0x79CBD7CCUL, 0x48A14367UL, + 0xA3149619UL, 0xFEC94BD5UL, 0xA114174AUL, 0xEAA01866UL, + 0xA084DB2DUL, 0x09A8486FUL, 0xA888614AUL, 0x2900AF98UL, + 0x01665991UL, 0xE1992863UL, 0xC8F30C60UL, 0x2E78EF3CUL, + 0xD0D51932UL, 0xCF0FEC14UL, 0xF7CA07D2UL, 0xD0A82072UL, + 0xFD41197EUL, 0x9305A6B0UL, 0xE86BE3DAUL, 0x74BED3CDUL, + 0x372DA53CUL, 0x4C7F4448UL, 0xDAB5D440UL, 0x6DBA0EC3UL, + 0x083919A7UL, 0x9FBAEED9UL, 0x49DBCFB0UL, 0x4E670C53UL, + 0x5C3D9C01UL, 0x64BDB941UL, 0x2C0E636AUL, 0xBA7DD9CDUL, + 0xEA6F7388UL, 0xE70BC762UL, 0x35F29ADBUL, 0x5C4CDD8DUL, + 0xF0D48D8CUL, 0xB88153E2UL, 0x08A19866UL, 0x1AE2EAC8UL, + 0x284CAF89UL, 0xAA928223UL, 0x9334BE53UL, 0x3B3A21BFUL, + 0x16434BE3UL, 0x9AEA3906UL, 0xEFE8C36EUL, 0xF890CDD9UL, + 0x80226DAEUL, 0xC340A4A3UL, 0xDF7E9C09UL, 0xA694A807UL, + 0x5B7C5ECCUL, 0x221DB3A6UL, 0x9A69A02FUL, 0x68818A54UL, + 0xCEB2296FUL, 0x53C0843AUL, 0xFE893655UL, 0x25BFE68AUL, + 0xB4628ABCUL, 0xCF222EBFUL, 0x25AC6F48UL, 0xA9A99387UL, + 0x53BDDB65UL, 0xE76FFBE7UL, 0xE967FD78UL, 0x0BA93563UL, + 0x8E342BC1UL, 0xE8A11BE9UL, 0x4980740DUL, 0xC8087DFCUL, + 0x8DE4BF99UL, 0xA11101A0UL, 0x7FD37975UL, 0xDA5A26C0UL, + 0xE81F994FUL, 0x9528CD89UL, 0xFD339FEDUL, 0xB87834BFUL, + 0x5F04456DUL, 0x22258698UL, 0xC9C4C83BUL, 0x2DC156BEUL, + 0x4F628DAAUL, 0x57F55EC5UL, 0xE2220ABEUL, 0xD2916EBFUL, + 0x4EC75B95UL, 0x24F2C3C0UL, 0x42D15D99UL, 0xCD0D7FA0UL, + 0x7B6E27FFUL, 0xA8DC8AF0UL, 0x7345C106UL, 0xF41E232FUL, + 0x35162386UL, 0xE6EA8926UL, 0x3333B094UL, 0x157EC6F2UL, + 0x372B74AFUL, 0x692573E4UL, 0xE9A9D848UL, 0xF3160289UL, + 0x3A62EF1DUL, 0xA787E238UL, 0xF3A5F676UL, 0x74364853UL, + 0x20951063UL, 0x4576698DUL, 0xB6FAD407UL, 0x592AF950UL, + 0x36F73523UL, 0x4CFB6E87UL, 0x7DA4CEC0UL, 0x6C152DAAUL, + 0xCB0396A8UL, 0xC50DFE5DUL, 0xFCD707ABUL, 0x0921C42FUL, + 0x89DFF0BBUL, 0x5FE2BE78UL, 0x448F4F33UL, 0x754613C9UL, + 0x2B05D08DUL, 0x48B9D585UL, 0xDC049441UL, 0xC8098F9BUL, + 0x7DEDE786UL, 0xC39A3373UL, 0x42410005UL, 0x6A091751UL, + 0x0EF3C8A6UL, 0x890072D6UL, 0x28207682UL, 0xA9A9F7BEUL, + 0xBF32679DUL, 0xD45B5B75UL, 0xB353FD00UL, 0xCBB0E358UL, + 0x830F220AUL, 0x1F8FB214UL, 0xD372CF08UL, 0xCC3C4A13UL, + 0x8CF63166UL, 0x061C87BEUL, 0x88C98F88UL, 0x6062E397UL, + 0x47CF8E7AUL, 0xB6C85283UL, 0x3CC2ACFBUL, 0x3FC06976UL, + 0x4E8F0252UL, 0x64D8314DUL, 0xDA3870E3UL, 0x1E665459UL, + 0xC10908F0UL, 0x513021A5UL, 0x6C5B68B7UL, 0x822F8AA0UL, + 0x3007CD3EUL, 0x74719EEFUL, 0xDC872681UL, 0x073340D4UL, + 0x7E432FD9UL, 0x0C5EC241UL, 0x8809286CUL, 0xF592D891UL, + 0x08A930F6UL, 0x957EF305UL, 0xB7FBFFBDUL, 0xC266E96FUL, + 0x6FE4AC98UL, 0xB173ECC0UL, 0xBC60B42AUL, 0x953498DAUL, + 0xFBA1AE12UL, 0x2D4BD736UL, 0x0F25FAABUL, 0xA4F3FCEBUL, + 0xE2969123UL, 0x257F0C3DUL, 0x9348AF49UL, 0x361400BCUL, + 0xE8816F4AUL, 0x3814F200UL, 0xA3F94043UL, 0x9C7A54C2UL, + 0xBC704F57UL, 0xDA41E7F9UL, 0xC25AD33AUL, 0x54F4A084UL, + 0xB17F5505UL, 0x59357CBEUL, 0xEDBD15C8UL, 0x7F97C5ABUL, + 0xBA5AC7B5UL, 0xB6F6DEAFUL, 0x3A479C3AUL, 0x5302DA25UL, + 0x653D7E6AUL, 0x54268D49UL, 0x51A477EAUL, 0x5017D55BUL, + 0xD7D25D88UL, 0x44136C76UL, 0x0404A8C8UL, 0xB8E5A121UL, + 0xB81A928AUL, 0x60ED5869UL, 0x97C55B96UL, 0xEAEC991BUL, + 0x29935913UL, 0x01FDB7F1UL, 0x088E8DFAUL, 0x9AB6F6F5UL, + 0x3B4CBF9FUL, 0x4A5DE3ABUL, 0xE6051D35UL, 0xA0E1D855UL, + 0xD36B4CF1UL, 0xF544EDEBUL, 0xB0E93524UL, 0xBEBB8FBDUL, + 0xA2D762CFUL, 0x49C92F54UL, 0x38B5F331UL, 0x7128A454UL, + 0x48392905UL, 0xA65B1DB8UL, 0x851C97BDUL, 0xD675CF2FUL +}, + +{ + 0x85E04019UL, 0x332BF567UL, 0x662DBFFFUL, 0xCFC65693UL, + 0x2A8D7F6FUL, 0xAB9BC912UL, 0xDE6008A1UL, 0x2028DA1FUL, + 0x0227BCE7UL, 0x4D642916UL, 0x18FAC300UL, 0x50F18B82UL, + 0x2CB2CB11UL, 0xB232E75CUL, 0x4B3695F2UL, 0xB28707DEUL, + 0xA05FBCF6UL, 0xCD4181E9UL, 0xE150210CUL, 0xE24EF1BDUL, + 0xB168C381UL, 0xFDE4E789UL, 0x5C79B0D8UL, 0x1E8BFD43UL, + 0x4D495001UL, 0x38BE4341UL, 0x913CEE1DUL, 0x92A79C3FUL, + 0x089766BEUL, 0xBAEEADF4UL, 0x1286BECFUL, 0xB6EACB19UL, + 0x2660C200UL, 0x7565BDE4UL, 0x64241F7AUL, 0x8248DCA9UL, + 0xC3B3AD66UL, 0x28136086UL, 0x0BD8DFA8UL, 0x356D1CF2UL, + 0x107789BEUL, 0xB3B2E9CEUL, 0x0502AA8FUL, 0x0BC0351EUL, + 0x166BF52AUL, 0xEB12FF82UL, 0xE3486911UL, 0xD34D7516UL, + 0x4E7B3AFFUL, 0x5F43671BUL, 0x9CF6E037UL, 0x4981AC83UL, + 0x334266CEUL, 0x8C9341B7UL, 0xD0D854C0UL, 0xCB3A6C88UL, + 0x47BC2829UL, 0x4725BA37UL, 0xA66AD22BUL, 0x7AD61F1EUL, + 0x0C5CBAFAUL, 0x4437F107UL, 0xB6E79962UL, 0x42D2D816UL, + 0x0A961288UL, 0xE1A5C06EUL, 0x13749E67UL, 0x72FC081AUL, + 0xB1D139F7UL, 0xF9583745UL, 0xCF19DF58UL, 0xBEC3F756UL, + 0xC06EBA30UL, 0x07211B24UL, 0x45C28829UL, 0xC95E317FUL, + 0xBC8EC511UL, 0x38BC46E9UL, 0xC6E6FA14UL, 0xBAE8584AUL, + 0xAD4EBC46UL, 0x468F508BUL, 0x7829435FUL, 0xF124183BUL, + 0x821DBA9FUL, 0xAFF60FF4UL, 0xEA2C4E6DUL, 0x16E39264UL, + 0x92544A8BUL, 0x009B4FC3UL, 0xABA68CEDUL, 0x9AC96F78UL, + 0x06A5B79AUL, 0xB2856E6EUL, 0x1AEC3CA9UL, 0xBE838688UL, + 0x0E0804E9UL, 0x55F1BE56UL, 0xE7E5363BUL, 0xB3A1F25DUL, + 0xF7DEBB85UL, 0x61FE033CUL, 0x16746233UL, 0x3C034C28UL, + 0xDA6D0C74UL, 0x79AAC56CUL, 0x3CE4E1ADUL, 0x51F0C802UL, + 0x98F8F35AUL, 0x1626A49FUL, 0xEED82B29UL, 0x1D382FE3UL, + 0x0C4FB99AUL, 0xBB325778UL, 0x3EC6D97BUL, 0x6E77A6A9UL, + 0xCB658B5CUL, 0xD45230C7UL, 0x2BD1408BUL, 0x60C03EB7UL, + 0xB9068D78UL, 0xA33754F4UL, 0xF430C87DUL, 0xC8A71302UL, + 0xB96D8C32UL, 0xEBD4E7BEUL, 0xBE8B9D2DUL, 0x7979FB06UL, + 0xE7225308UL, 0x8B75CF77UL, 0x11EF8DA4UL, 0xE083C858UL, + 0x8D6B786FUL, 0x5A6317A6UL, 0xFA5CF7A0UL, 0x5DDA0033UL, + 0xF28EBFB0UL, 0xF5B9C310UL, 0xA0EAC280UL, 0x08B9767AUL, + 0xA3D9D2B0UL, 0x79D34217UL, 0x021A718DUL, 0x9AC6336AUL, + 0x2711FD60UL, 0x438050E3UL, 0x069908A8UL, 0x3D7FEDC4UL, + 0x826D2BEFUL, 0x4EEB8476UL, 0x488DCF25UL, 0x36C9D566UL, + 0x28E74E41UL, 0xC2610ACAUL, 0x3D49A9CFUL, 0xBAE3B9DFUL, + 0xB65F8DE6UL, 0x92AEAF64UL, 0x3AC7D5E6UL, 0x9EA80509UL, + 0xF22B017DUL, 0xA4173F70UL, 0xDD1E16C3UL, 0x15E0D7F9UL, + 0x50B1B887UL, 0x2B9F4FD5UL, 0x625ABA82UL, 0x6A017962UL, + 0x2EC01B9CUL, 0x15488AA9UL, 0xD716E740UL, 0x40055A2CUL, + 0x93D29A22UL, 0xE32DBF9AUL, 0x058745B9UL, 0x3453DC1EUL, + 0xD699296EUL, 0x496CFF6FUL, 0x1C9F4986UL, 0xDFE2ED07UL, + 0xB87242D1UL, 0x19DE7EAEUL, 0x053E561AUL, 0x15AD6F8CUL, + 0x66626C1CUL, 0x7154C24CUL, 0xEA082B2AUL, 0x93EB2939UL, + 0x17DCB0F0UL, 0x58D4F2AEUL, 0x9EA294FBUL, 0x52CF564CUL, + 0x9883FE66UL, 0x2EC40581UL, 0x763953C3UL, 0x01D6692EUL, + 0xD3A0C108UL, 0xA1E7160EUL, 0xE4F2DFA6UL, 0x693ED285UL, + 0x74904698UL, 0x4C2B0EDDUL, 0x4F757656UL, 0x5D393378UL, + 0xA132234FUL, 0x3D321C5DUL, 0xC3F5E194UL, 0x4B269301UL, + 0xC79F022FUL, 0x3C997E7EUL, 0x5E4F9504UL, 0x3FFAFBBDUL, + 0x76F7AD0EUL, 0x296693F4UL, 0x3D1FCE6FUL, 0xC61E45BEUL, + 0xD3B5AB34UL, 0xF72BF9B7UL, 0x1B0434C0UL, 0x4E72B567UL, + 0x5592A33DUL, 0xB5229301UL, 0xCFD2A87FUL, 0x60AEB767UL, + 0x1814386BUL, 0x30BCC33DUL, 0x38A0C07DUL, 0xFD1606F2UL, + 0xC363519BUL, 0x589DD390UL, 0x5479F8E6UL, 0x1CB8D647UL, + 0x97FD61A9UL, 0xEA7759F4UL, 0x2D57539DUL, 0x569A58CFUL, + 0xE84E63ADUL, 0x462E1B78UL, 0x6580F87EUL, 0xF3817914UL, + 0x91DA55F4UL, 0x40A230F3UL, 0xD1988F35UL, 0xB6E318D2UL, + 0x3FFA50BCUL, 0x3D40F021UL, 0xC3C0BDAEUL, 0x4958C24CUL, + 0x518F36B2UL, 0x84B1D370UL, 0x0FEDCE83UL, 0x878DDADAUL, + 0xF2A279C7UL, 0x94E01BE8UL, 0x90716F4BUL, 0x954B8AA3UL +}, + +{ + 0xE216300DUL, 0xBBDDFFFCUL, 0xA7EBDABDUL, 0x35648095UL, + 0x7789F8B7UL, 0xE6C1121BUL, 0x0E241600UL, 0x052CE8B5UL, + 0x11A9CFB0UL, 0xE5952F11UL, 0xECE7990AUL, 0x9386D174UL, + 0x2A42931CUL, 0x76E38111UL, 0xB12DEF3AUL, 0x37DDDDFCUL, + 0xDE9ADEB1UL, 0x0A0CC32CUL, 0xBE197029UL, 0x84A00940UL, + 0xBB243A0FUL, 0xB4D137CFUL, 0xB44E79F0UL, 0x049EEDFDUL, + 0x0B15A15DUL, 0x480D3168UL, 0x8BBBDE5AUL, 0x669DED42UL, + 0xC7ECE831UL, 0x3F8F95E7UL, 0x72DF191BUL, 0x7580330DUL, + 0x94074251UL, 0x5C7DCDFAUL, 0xABBE6D63UL, 0xAA402164UL, + 0xB301D40AUL, 0x02E7D1CAUL, 0x53571DAEUL, 0x7A3182A2UL, + 0x12A8DDECUL, 0xFDAA335DUL, 0x176F43E8UL, 0x71FB46D4UL, + 0x38129022UL, 0xCE949AD4UL, 0xB84769ADUL, 0x965BD862UL, + 0x82F3D055UL, 0x66FB9767UL, 0x15B80B4EUL, 0x1D5B47A0UL, + 0x4CFDE06FUL, 0xC28EC4B8UL, 0x57E8726EUL, 0x647A78FCUL, + 0x99865D44UL, 0x608BD593UL, 0x6C200E03UL, 0x39DC5FF6UL, + 0x5D0B00A3UL, 0xAE63AFF2UL, 0x7E8BD632UL, 0x70108C0CUL, + 0xBBD35049UL, 0x2998DF04UL, 0x980CF42AUL, 0x9B6DF491UL, + 0x9E7EDD53UL, 0x06918548UL, 0x58CB7E07UL, 0x3B74EF2EUL, + 0x522FFFB1UL, 0xD24708CCUL, 0x1C7E27CDUL, 0xA4EB215BUL, + 0x3CF1D2E2UL, 0x19B47A38UL, 0x424F7618UL, 0x35856039UL, + 0x9D17DEE7UL, 0x27EB35E6UL, 0xC9AFF67BUL, 0x36BAF5B8UL, + 0x09C467CDUL, 0xC18910B1UL, 0xE11DBF7BUL, 0x06CD1AF8UL, + 0x7170C608UL, 0x2D5E3354UL, 0xD4DE495AUL, 0x64C6D006UL, + 0xBCC0C62CUL, 0x3DD00DB3UL, 0x708F8F34UL, 0x77D51B42UL, + 0x264F620FUL, 0x24B8D2BFUL, 0x15C1B79EUL, 0x46A52564UL, + 0xF8D7E54EUL, 0x3E378160UL, 0x7895CDA5UL, 0x859C15A5UL, + 0xE6459788UL, 0xC37BC75FUL, 0xDB07BA0CUL, 0x0676A3ABUL, + 0x7F229B1EUL, 0x31842E7BUL, 0x24259FD7UL, 0xF8BEF472UL, + 0x835FFCB8UL, 0x6DF4C1F2UL, 0x96F5B195UL, 0xFD0AF0FCUL, + 0xB0FE134CUL, 0xE2506D3DUL, 0x4F9B12EAUL, 0xF215F225UL, + 0xA223736FUL, 0x9FB4C428UL, 0x25D04979UL, 0x34C713F8UL, + 0xC4618187UL, 0xEA7A6E98UL, 0x7CD16EFCUL, 0x1436876CUL, + 0xF1544107UL, 0xBEDEEE14UL, 0x56E9AF27UL, 0xA04AA441UL, + 0x3CF7C899UL, 0x92ECBAE6UL, 0xDD67016DUL, 0x151682EBUL, + 0xA842EEDFUL, 0xFDBA60B4UL, 0xF1907B75UL, 0x20E3030FUL, + 0x24D8C29EUL, 0xE139673BUL, 0xEFA63FB8UL, 0x71873054UL, + 0xB6F2CF3BUL, 0x9F326442UL, 0xCB15A4CCUL, 0xB01A4504UL, + 0xF1E47D8DUL, 0x844A1BE5UL, 0xBAE7DFDCUL, 0x42CBDA70UL, + 0xCD7DAE0AUL, 0x57E85B7AUL, 0xD53F5AF6UL, 0x20CF4D8CUL, + 0xCEA4D428UL, 0x79D130A4UL, 0x3486EBFBUL, 0x33D3CDDCUL, + 0x77853B53UL, 0x37EFFCB5UL, 0xC5068778UL, 0xE580B3E6UL, + 0x4E68B8F4UL, 0xC5C8B37EUL, 0x0D809EA2UL, 0x398FEB7CUL, + 0x132A4F94UL, 0x43B7950EUL, 0x2FEE7D1CUL, 0x223613BDUL, + 0xDD06CAA2UL, 0x37DF932BUL, 0xC4248289UL, 0xACF3EBC3UL, + 0x5715F6B7UL, 0xEF3478DDUL, 0xF267616FUL, 0xC148CBE4UL, + 0x9052815EUL, 0x5E410FABUL, 0xB48A2465UL, 0x2EDA7FA4UL, + 0xE87B40E4UL, 0xE98EA084UL, 0x5889E9E1UL, 0xEFD390FCUL, + 0xDD07D35BUL, 0xDB485694UL, 0x38D7E5B2UL, 0x57720101UL, + 0x730EDEBCUL, 0x5B643113UL, 0x94917E4FUL, 0x503C2FBAUL, + 0x646F1282UL, 0x7523D24AUL, 0xE0779695UL, 0xF9C17A8FUL, + 0x7A5B2121UL, 0xD187B896UL, 0x29263A4DUL, 0xBA510CDFUL, + 0x81F47C9FUL, 0xAD1163EDUL, 0xEA7B5965UL, 0x1A00726EUL, + 0x11403092UL, 0x00DA6D77UL, 0x4A0CDD61UL, 0xAD1F4603UL, + 0x605BDFB0UL, 0x9EEDC364UL, 0x22EBE6A8UL, 0xCEE7D28AUL, + 0xA0E736A0UL, 0x5564A6B9UL, 0x10853209UL, 0xC7EB8F37UL, + 0x2DE705CAUL, 0x8951570FUL, 0xDF09822BUL, 0xBD691A6CUL, + 0xAA12E4F2UL, 0x87451C0FUL, 0xE0F6A27AUL, 0x3ADA4819UL, + 0x4CF1764FUL, 0x0D771C2BUL, 0x67CDB156UL, 0x350D8384UL, + 0x5938FA0FUL, 0x42399EF3UL, 0x36997B07UL, 0x0E84093DUL, + 0x4AA93E61UL, 0x8360D87BUL, 0x1FA98B0CUL, 0x1149382CUL, + 0xE97625A5UL, 0x0614D1B7UL, 0x0E25244BUL, 0x0C768347UL, + 0x589E8D82UL, 0x0D2059D1UL, 0xA466BB1EUL, 0xF8DA0A82UL, + 0x04F19130UL, 0xBA6E4EC0UL, 0x99265164UL, 0x1EE7230DUL, + 0x50B2AD80UL, 0xEAEE6801UL, 0x8DB2A283UL, 0xEA8BF59EUL +}}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/cbcmac.cpp b/extension/third_party/cryptopp/cbcmac.cpp new file mode 100644 index 00000000..b0c46de2 --- /dev/null +++ b/extension/third_party/cryptopp/cbcmac.cpp @@ -0,0 +1,62 @@ +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "cbcmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +void CBC_MAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + AccessCipher().SetKey(key, length, params); + m_reg.CleanNew(AccessCipher().BlockSize()); + m_counter = 0; +} + +void CBC_MAC_Base::Update(const byte *input, size_t length) +{ + unsigned int blockSize = AccessCipher().BlockSize(); + + while (m_counter && length) + { + m_reg[m_counter++] ^= *input++; + if (m_counter == blockSize) + ProcessBuf(); + length--; + } + + if (length >= blockSize) + { + size_t leftOver = AccessCipher().AdvancedProcessBlocks(m_reg, input, m_reg, length, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); + input += (length - leftOver); + length = leftOver; + } + + while (length--) + { + m_reg[m_counter++] ^= *input++; + if (m_counter == blockSize) + ProcessBuf(); + } +} + +void CBC_MAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + if (m_counter) + ProcessBuf(); + + memcpy(mac, m_reg, size); + memset(m_reg, 0, AccessCipher().BlockSize()); +} + +void CBC_MAC_Base::ProcessBuf() +{ + AccessCipher().ProcessBlock(m_reg); + m_counter = 0; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/cbcmac.h b/extension/third_party/cryptopp/cbcmac.h new file mode 100644 index 00000000..8ad81b52 --- /dev/null +++ b/extension/third_party/cryptopp/cbcmac.h @@ -0,0 +1,59 @@ +// cbcmac.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for CBC MAC +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_CBCMAC_H +#define CRYPTOPP_CBCMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CBC-MAC base class +/// \since Crypto++ 3.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_MAC_Base : public MessageAuthenticationCode +{ +public: + CBC_MAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return const_cast(this)->AccessCipher().BlockSize();} + +protected: + virtual BlockCipher & AccessCipher() =0; + +private: + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CBC-MAC +/// \tparam T BlockCipherDocumentation derived class +/// \details CBC-MAC is compatible with FIPS 113. The MAC is secure only for fixed +/// length messages. For variable length messages use CMAC or DMAC. +/// \sa CBC-MAC +/// \since Crypto++ 3.1 +template +class CBC_MAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + CBC_MAC() {} + CBC_MAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CBC-MAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ccm.cpp b/extension/third_party/cryptopp/ccm.cpp new file mode 100644 index 00000000..c0c2c352 --- /dev/null +++ b/extension/third_party/cryptopp/ccm.cpp @@ -0,0 +1,139 @@ +// ccm.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "ccm.h" + +NAMESPACE_BEGIN(CryptoPP) + +void CCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + BlockCipher &blockCipher = AccessBlockCipher(); + blockCipher.SetKey(userKey, keylength, params); + + if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE) + throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16"); + + m_digestSize = params.GetIntValueWithDefault(Name::DigestSize(), DefaultDigestSize()); + if (m_digestSize % 2 > 0 || m_digestSize < 4 || m_digestSize > 16) + throw InvalidArgument(AlgorithmName() + ": DigestSize must be 4, 6, 8, 10, 12, 14, or 16"); + + m_buffer.Grow(2*REQUIRED_BLOCKSIZE); + m_L = 8; +} + +void CCM_Base::Resync(const byte *iv, size_t len) +{ + BlockCipher &cipher = AccessBlockCipher(); + + m_L = REQUIRED_BLOCKSIZE-1-(int)len; + CRYPTOPP_ASSERT(m_L >= 2); + if (m_L > 8) + m_L = 8; + + m_buffer[0] = byte(m_L-1); // flag + memcpy(m_buffer+1, iv, len); + memset(m_buffer+1+len, 0, REQUIRED_BLOCKSIZE-1-len); + + if (m_state >= State_IVSet) + m_ctr.Resynchronize(m_buffer, REQUIRED_BLOCKSIZE); + else + m_ctr.SetCipherWithIV(cipher, m_buffer); + + m_ctr.Seek(REQUIRED_BLOCKSIZE); + m_aadLength = 0; + m_messageLength = 0; +} + +void CCM_Base::UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword /*footerLength*/) +{ + if (m_state != State_IVSet) + throw BadState(AlgorithmName(), "SpecifyDataLengths", "or after State_IVSet"); + + m_aadLength = headerLength; + m_messageLength = messageLength; + + byte *cbcBuffer = CBC_Buffer(); + const BlockCipher &cipher = GetBlockCipher(); + + cbcBuffer[0] = byte(64*(headerLength>0) + 8*((m_digestSize-2)/2) + (m_L-1)); // flag + PutWord(true, BIG_ENDIAN_ORDER, cbcBuffer+REQUIRED_BLOCKSIZE-8, m_messageLength); + memcpy(cbcBuffer+1, m_buffer+1, REQUIRED_BLOCKSIZE-1-m_L); + cipher.ProcessBlock(cbcBuffer); + + if (headerLength>0) + { + CRYPTOPP_ASSERT(m_bufferedDataLength == 0); + + if (headerLength < ((1<<16) - (1<<8))) + { + PutWord(true, BIG_ENDIAN_ORDER, m_buffer, (word16)headerLength); + m_bufferedDataLength = 2; + } + else if (headerLength < (W64LIT(1)<<32)) + { + m_buffer[0] = 0xff; + m_buffer[1] = 0xfe; + PutWord(false, BIG_ENDIAN_ORDER, m_buffer+2, (word32)headerLength); + m_bufferedDataLength = 6; + } + else + { + m_buffer[0] = 0xff; + m_buffer[1] = 0xff; + PutWord(false, BIG_ENDIAN_ORDER, m_buffer+2, headerLength); + m_bufferedDataLength = 10; + } + } +} + +size_t CCM_Base::AuthenticateBlocks(const byte *data, size_t len) +{ + byte *cbcBuffer = CBC_Buffer(); + const BlockCipher &cipher = GetBlockCipher(); + return cipher.AdvancedProcessBlocks(cbcBuffer, data, cbcBuffer, len, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); +} + +void CCM_Base::AuthenticateLastHeaderBlock() +{ + byte *cbcBuffer = CBC_Buffer(); + const BlockCipher &cipher = GetBlockCipher(); + + if (m_aadLength != m_totalHeaderLength) + throw InvalidArgument(AlgorithmName() + ": header length doesn't match that given in SpecifyDataLengths"); + + if (m_bufferedDataLength > 0) + { + xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); + cipher.ProcessBlock(cbcBuffer); + m_bufferedDataLength = 0; + } +} + +void CCM_Base::AuthenticateLastConfidentialBlock() +{ + byte *cbcBuffer = CBC_Buffer(); + const BlockCipher &cipher = GetBlockCipher(); + + if (m_messageLength != m_totalMessageLength) + throw InvalidArgument(AlgorithmName() + ": message length doesn't match that given in SpecifyDataLengths"); + + if (m_bufferedDataLength > 0) + { + xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); + cipher.ProcessBlock(cbcBuffer); + m_bufferedDataLength = 0; + } +} + +void CCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) +{ + m_ctr.Seek(0); + m_ctr.ProcessData(mac, CBC_Buffer(), macSize); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ccm.h b/extension/third_party/cryptopp/ccm.h new file mode 100644 index 00000000..5207a2fd --- /dev/null +++ b/extension/third_party/cryptopp/ccm.h @@ -0,0 +1,123 @@ +// ccm.h - originally written and placed in the public domain by Wei Dai + +/// \file ccm.h +/// \brief CCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CCM_H +#define CRYPTOPP_CCM_H + +#include "authenc.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CCM_Base() + : m_digestSize(0), m_L(0), m_messageLength(0), m_aadLength(0) {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/CCM");} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t keylength) const + {return GetBlockCipher().GetValidKeyLength(keylength);} + bool IsValidKeyLength(size_t keylength) const + {return GetBlockCipher().IsValidKeyLength(keylength);} + unsigned int OptimalDataAlignment() const + {return GetBlockCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 8;} + unsigned int MinIVLength() const + {return 7;} + unsigned int MaxIVLength() const + {return 13;} + unsigned int DigestSize() const + {return m_digestSize;} + lword MaxHeaderLength() const + {return W64LIT(0)-1;} + lword MaxMessageLength() const + {return m_L<8 ? (W64LIT(1)<<(8*m_L))-1 : W64LIT(0)-1;} + bool NeedsPrespecifiedDataLengths() const + {return true;} + void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return true;} + unsigned int AuthenticationBlockSize() const + {return GetBlockCipher().BlockSize();} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual int DefaultDigestSize() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();} + byte *CBC_Buffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + + enum {REQUIRED_BLOCKSIZE = 16}; + int m_digestSize, m_L; + word64 m_messageLength, m_aadLength; + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief CCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class CCM_Final : public CCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/CCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + BlockCipher & AccessBlockCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DefaultDigestSize;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief CCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \details \p CCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa CCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct CCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef CCM_Final Encryption; + typedef CCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/chacha.cpp b/extension/third_party/cryptopp/chacha.cpp new file mode 100644 index 00000000..11c8a399 --- /dev/null +++ b/extension/third_party/cryptopp/chacha.cpp @@ -0,0 +1,568 @@ +// chacha.cpp - written and placed in the public domain by Jeffrey Walton. +// Based on Wei Dai's Salsa20, Botan's SSE2 implementation, +// and Bernstein's reference ChaCha family implementation at +// http://cr.yp.to/chacha.html. + +#include "pch.h" +#include "config.h" +#include "chacha.h" +#include "argnames.h" +#include "misc.h" +#include "cpu.h" + +// Internal compiler error in GCC 3.3 and below +#if defined(__GNUC__) && (__GNUC__ < 4) +# undef CRYPTOPP_SSE2_INTRIN_AVAILABLE +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +extern void ChaCha_OperateKeystream_NEON(const word32 *state, const byte* input, byte *output, unsigned int rounds); +#endif + +#if (CRYPTOPP_AVX2_AVAILABLE) +extern void ChaCha_OperateKeystream_AVX2(const word32 *state, const byte* input, byte *output, unsigned int rounds); +#endif +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +extern void ChaCha_OperateKeystream_SSE2(const word32 *state, const byte* input, byte *output, unsigned int rounds); +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +extern void ChaCha_OperateKeystream_ALTIVEC(const word32 *state, const byte* input, byte *output, unsigned int rounds); +#endif + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ChaCha_TestInstantiations() +{ + ChaCha::Encryption x; + ChaChaTLS::Encryption y; + XChaCha20::Encryption z; +} +#endif + +NAMESPACE_END // CryptoPP + +////////////////////////////// ChaCha Core ////////////////////////////// + +#define CHACHA_QUARTER_ROUND(a,b,c,d) \ + a += b; d ^= a; d = rotlConstant<16,word32>(d); \ + c += d; b ^= c; b = rotlConstant<12,word32>(b); \ + a += b; d ^= a; d = rotlConstant<8,word32>(d); \ + c += d; b ^= c; b = rotlConstant<7,word32>(b); + +#define CHACHA_OUTPUT(x){\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, x0 + state[0]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, x1 + state[1]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, x2 + state[2]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, x3 + state[3]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 4, x4 + state[4]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 5, x5 + state[5]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 6, x6 + state[6]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 7, x7 + state[7]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 8, x8 + state[8]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 9, x9 + state[9]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 10, x10 + state[10]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 11, x11 + state[11]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 12, x12 + state[12]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 13, x13 + state[13]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 14, x14 + state[14]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 15, x15 + state[15]);} + +ANONYMOUS_NAMESPACE_BEGIN + +// Hacks... Bring in all symbols, and supply +// the stuff the templates normally provide. +using namespace CryptoPP; +typedef word32 WordType; +enum {BYTES_PER_ITERATION=64}; + +// MultiBlockSafe detects a condition that can arise in the SIMD +// implementations where we overflow one of the 32-bit state words during +// addition in an intermediate result. Preconditions for the issue include +// a user seeks to around 2^32 blocks (256 GB of data) for ChaCha; or a +// user specifies an arbitrarily large initial counter block for ChaChaTLS. +// Also see https://github.com/weidai11/cryptopp/issues/732. +inline bool MultiBlockSafe(unsigned int ctrLow, unsigned int blocks) +{ + return 0xffffffff - ctrLow > blocks; +} + +// OperateKeystream always produces a key stream. The key stream is written +// to output. Optionally a message may be supplied to xor with the key stream. +// The message is input, and output = output ^ input. +void ChaCha_OperateKeystream(KeystreamOperation operation, + word32 state[16], word32& ctrLow, word32& ctrHigh, word32 rounds, + byte *output, const byte *input, size_t iterationCount) +{ + do + { +#if (CRYPTOPP_AVX2_AVAILABLE) + if (HasAVX2()) + { + while (iterationCount >= 8 && MultiBlockSafe(state[12], 8)) + { + const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL; + ChaCha_OperateKeystream_AVX2(state, xorInput ? input : NULLPTR, output, rounds); + + // MultiBlockSafe avoids overflow on the counter words + state[12] += 8; + + input += (!!xorInput) * 8 * BYTES_PER_ITERATION; + output += 8 * BYTES_PER_ITERATION; + iterationCount -= 8; + } + } +#endif + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (HasSSE2()) + { + while (iterationCount >= 4 && MultiBlockSafe(state[12], 4)) + { + const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL; + ChaCha_OperateKeystream_SSE2(state, xorInput ? input : NULLPTR, output, rounds); + + // MultiBlockSafe avoids overflow on the counter words + state[12] += 4; + + input += (!!xorInput)*4*BYTES_PER_ITERATION; + output += 4*BYTES_PER_ITERATION; + iterationCount -= 4; + } + } +#endif + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + { + while (iterationCount >= 4 && MultiBlockSafe(state[12], 4)) + { + const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL; + ChaCha_OperateKeystream_NEON(state, xorInput ? input : NULLPTR, output, rounds); + + // MultiBlockSafe avoids overflow on the counter words + state[12] += 4; + + input += (!!xorInput)*4*BYTES_PER_ITERATION; + output += 4*BYTES_PER_ITERATION; + iterationCount -= 4; + } + } +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + { + while (iterationCount >= 4 && MultiBlockSafe(state[12], 4)) + { + const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL; + ChaCha_OperateKeystream_ALTIVEC(state, xorInput ? input : NULLPTR, output, rounds); + + // MultiBlockSafe avoids overflow on the counter words + state[12] += 4; + + input += (!!xorInput)*4*BYTES_PER_ITERATION; + output += 4*BYTES_PER_ITERATION; + iterationCount -= 4; + } + } +#endif + + if (iterationCount) + { + word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + + x0 = state[0]; x1 = state[1]; x2 = state[2]; x3 = state[3]; + x4 = state[4]; x5 = state[5]; x6 = state[6]; x7 = state[7]; + x8 = state[8]; x9 = state[9]; x10 = state[10]; x11 = state[11]; + x12 = state[12]; x13 = state[13]; x14 = state[14]; x15 = state[15]; + + for (int i = static_cast(rounds); i > 0; i -= 2) + { + CHACHA_QUARTER_ROUND(x0, x4, x8, x12); + CHACHA_QUARTER_ROUND(x1, x5, x9, x13); + CHACHA_QUARTER_ROUND(x2, x6, x10, x14); + CHACHA_QUARTER_ROUND(x3, x7, x11, x15); + + CHACHA_QUARTER_ROUND(x0, x5, x10, x15); + CHACHA_QUARTER_ROUND(x1, x6, x11, x12); + CHACHA_QUARTER_ROUND(x2, x7, x8, x13); + CHACHA_QUARTER_ROUND(x3, x4, x9, x14); + } + + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(CHACHA_OUTPUT, BYTES_PER_ITERATION); + + // This is state[12] and state[13] from ChaCha. In the case of + // ChaChaTLS ctrHigh is a reference to a discard value. + if (++ctrLow == 0) + ctrHigh++; + } + + // We may re-enter a SIMD keystream operation from here. + } while (iterationCount--); +} + +// XChaCha key derivation +void HChaCha_OperateKeystream(const word32 state[16], word32 output[8]) +{ + word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + + x0 = state[0]; x1 = state[1]; x2 = state[2]; x3 = state[3]; + x4 = state[4]; x5 = state[5]; x6 = state[6]; x7 = state[7]; + x8 = state[8]; x9 = state[9]; x10 = state[10]; x11 = state[11]; + x12 = state[12]; x13 = state[13]; x14 = state[14]; x15 = state[15]; + + for (int i = 20; i > 0; i -= 2) + { + CHACHA_QUARTER_ROUND(x0, x4, x8, x12); + CHACHA_QUARTER_ROUND(x1, x5, x9, x13); + CHACHA_QUARTER_ROUND(x2, x6, x10, x14); + CHACHA_QUARTER_ROUND(x3, x7, x11, x15); + + CHACHA_QUARTER_ROUND(x0, x5, x10, x15); + CHACHA_QUARTER_ROUND(x1, x6, x11, x12); + CHACHA_QUARTER_ROUND(x2, x7, x8, x13); + CHACHA_QUARTER_ROUND(x3, x4, x9, x14); + } + + output[0] = x0; output[1] = x1; + output[2] = x2; output[3] = x3; + output[4] = x12; output[5] = x13; + output[6] = x14; output[7] = x15; +} + +std::string ChaCha_AlgorithmProvider() +{ +#if (CRYPTOPP_AVX2_AVAILABLE) + if (HasAVX2()) + return "AVX2"; + else +#endif +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (HasSSE2()) + return "SSE2"; + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; + else +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return "Altivec"; + else +#endif + return "C++"; +} + +unsigned int ChaCha_GetAlignment() +{ +#if (CRYPTOPP_AVX2_AVAILABLE) + if (HasAVX2()) + return 16; + else +#endif +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (HasSSE2()) + return 16; + else +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return 16; + else +#endif + return GetAlignmentOf(); +} + +unsigned int ChaCha_GetOptimalBlockSize() +{ +#if (CRYPTOPP_AVX2_AVAILABLE) + if (HasAVX2()) + return 8 * BYTES_PER_ITERATION; + else +#endif +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (HasSSE2()) + return 4*BYTES_PER_ITERATION; + else +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return 4*BYTES_PER_ITERATION; + else +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return 4*BYTES_PER_ITERATION; + else +#endif + return BYTES_PER_ITERATION; +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein ChaCha ////////////////////////////// + +std::string ChaCha_Policy::AlgorithmName() const +{ + return std::string("ChaCha")+IntToString(m_rounds); +} + +std::string ChaCha_Policy::AlgorithmProvider() const +{ + return ChaCha_AlgorithmProvider(); +} + +void ChaCha_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 16 || length == 32); + CRYPTOPP_UNUSED(key); CRYPTOPP_UNUSED(length); + + // Use previous rounds as the default value + int rounds = params.GetIntValueWithDefault(Name::Rounds(), m_rounds); + if (rounds != 20 && rounds != 12 && rounds != 8) + throw InvalidRounds(ChaCha::StaticAlgorithmName(), rounds); + + // Latch a good value + m_rounds = rounds; + + // "expand 16-byte k" or "expand 32-byte k" + m_state[0] = 0x61707865; + m_state[1] = (length == 16) ? 0x3120646e : 0x3320646e; + m_state[2] = (length == 16) ? 0x79622d36 : 0x79622d32; + m_state[3] = 0x6b206574; + + GetBlock get1(key); + get1(m_state[4])(m_state[5])(m_state[6])(m_state[7]); + + GetBlock get2(key + ((length == 32) ? 16 : 0)); + get2(m_state[8])(m_state[9])(m_state[10])(m_state[11]); +} + +void ChaCha_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==8); CRYPTOPP_UNUSED(length); + + GetBlock get(IV); + m_state[12] = m_state[13] = 0; + get(m_state[14])(m_state[15]); +} + +void ChaCha_Policy::SeekToIteration(lword iterationCount) +{ + m_state[12] = (word32)iterationCount; // low word + m_state[13] = (word32)SafeRightShift<32>(iterationCount); +} + +unsigned int ChaCha_Policy::GetAlignment() const +{ + return ChaCha_GetAlignment(); +} + +unsigned int ChaCha_Policy::GetOptimalBlockSize() const +{ + return ChaCha_GetOptimalBlockSize(); +} + +void ChaCha_Policy::OperateKeystream(KeystreamOperation operation, + byte *output, const byte *input, size_t iterationCount) +{ + ChaCha_OperateKeystream(operation, m_state, m_state[12], m_state[13], + m_rounds, output, input, iterationCount); +} + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +std::string ChaChaTLS_Policy::AlgorithmName() const +{ + return std::string("ChaChaTLS"); +} + +std::string ChaChaTLS_Policy::AlgorithmProvider() const +{ + return ChaCha_AlgorithmProvider(); +} + +void ChaChaTLS_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 32); + CRYPTOPP_UNUSED(length); + + // ChaChaTLS is always 20 rounds. Fetch Rounds() to avoid a spurious failure. + int rounds = params.GetIntValueWithDefault(Name::Rounds(), ROUNDS); + if (rounds != 20) + throw InvalidRounds(ChaChaTLS::StaticAlgorithmName(), rounds); + + // RFC 8439 test vectors use an initial block counter. However, the counter + // can be an arbitrary value per RFC 8439 Section 2.4. We stash the counter + // away in state[16] and use it for a Resynchronize() operation. I think + // the initial counter is used more like a Tweak when non-0, and it should + // be provided in Resynchronize() (light-weight re-keying). However, + // Resynchronize() does not have an overload that allows us to pass it into + // the function, so we have to use the heavier-weight SetKey to change it. + word64 block; + if (params.GetValue("InitialBlock", block)) + m_counter = static_cast(block); + else + m_counter = 0; + + // State words are defined in RFC 8439, Section 2.3. Key is 32-bytes. + GetBlock get(key); + get(m_state[KEY+0])(m_state[KEY+1])(m_state[KEY+2])(m_state[KEY+3]) + (m_state[KEY+4])(m_state[KEY+5])(m_state[KEY+6])(m_state[KEY+7]); +} + +void ChaChaTLS_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==12); + + // State words are defined in RFC 8439, Section 2.3. + m_state[0] = 0x61707865; m_state[1] = 0x3320646e; + m_state[2] = 0x79622d32; m_state[3] = 0x6b206574; + + // Copy saved key into state + std::memcpy(m_state+4, m_state+KEY, 8*sizeof(word32)); + + // State words are defined in RFC 8439, Section 2.3 + GetBlock get(IV); + m_state[12] = m_counter; + get(m_state[13])(m_state[14])(m_state[15]); +} + +void ChaChaTLS_Policy::SeekToIteration(lword iterationCount) +{ + // Should we throw here??? If the initial block counter is + // large then we can wrap and process more data as long as + // data processed in the security context does not exceed + // 2^32 blocks or approximately 256 GB of data. + CRYPTOPP_ASSERT(iterationCount <= std::numeric_limits::max()); + m_state[12] = (word32)iterationCount; // low word +} + +unsigned int ChaChaTLS_Policy::GetAlignment() const +{ + return ChaCha_GetAlignment(); +} + +unsigned int ChaChaTLS_Policy::GetOptimalBlockSize() const +{ + return ChaCha_GetOptimalBlockSize(); +} + +void ChaChaTLS_Policy::OperateKeystream(KeystreamOperation operation, + byte *output, const byte *input, size_t iterationCount) +{ + word32 discard=0; + ChaCha_OperateKeystream(operation, m_state, m_state[12], discard, + ROUNDS, output, input, iterationCount); + + // If this fires it means ChaCha_OperateKeystream generated a counter + // block carry that was discarded. The problem is, the RFC does not + // specify what should happen when the counter block wraps. All we can + // do is inform the user that something bad may happen because we don't + // know what we should do. + // Also see https://github.com/weidai11/cryptopp/issues/790 and + // https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU + // CRYPTOPP_ASSERT(discard==0); +} + +////////////////////////////// IETF XChaCha20 ////////////////////////////// + +std::string XChaCha20_Policy::AlgorithmName() const +{ + return std::string("XChaCha20"); +} + +std::string XChaCha20_Policy::AlgorithmProvider() const +{ + return ChaCha_AlgorithmProvider(); +} + +void XChaCha20_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 32); + CRYPTOPP_UNUSED(length); + + // Use previous rounds as the default value + int rounds = params.GetIntValueWithDefault(Name::Rounds(), m_rounds); + if (rounds != 20 && rounds != 12) + throw InvalidRounds(ChaCha::StaticAlgorithmName(), rounds); + + // Latch a good value + m_rounds = rounds; + + word64 block; + if (params.GetValue("InitialBlock", block)) + m_counter = static_cast(block); + else + m_counter = 1; + + // Stash key away for use in CipherResynchronize + GetBlock get(key); + get(m_state[KEY+0])(m_state[KEY+1])(m_state[KEY+2])(m_state[KEY+3]) + (m_state[KEY+4])(m_state[KEY+5])(m_state[KEY+6])(m_state[KEY+7]); +} + +void XChaCha20_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==24); + + // HChaCha derivation + m_state[0] = 0x61707865; m_state[1] = 0x3320646e; + m_state[2] = 0x79622d32; m_state[3] = 0x6b206574; + + // Copy saved key into state + std::memcpy(m_state+4, m_state+KEY, 8*sizeof(word32)); + + GetBlock get(iv); + get(m_state[12])(m_state[13])(m_state[14])(m_state[15]); + + // Operate the keystream without adding state back in. + // This function also gathers the key words into a + // contiguous 8-word block. + HChaCha_OperateKeystream(m_state, m_state+4); + + // XChaCha state + m_state[0] = 0x61707865; m_state[1] = 0x3320646e; + m_state[2] = 0x79622d32; m_state[3] = 0x6b206574; + + // Setup new IV + m_state[12] = m_counter; + m_state[13] = 0; + m_state[14] = GetWord(false, LITTLE_ENDIAN_ORDER, iv+16); + m_state[15] = GetWord(false, LITTLE_ENDIAN_ORDER, iv+20); +} + +void XChaCha20_Policy::SeekToIteration(lword iterationCount) +{ + // Should we throw here??? XChaCha does not have a block + // counter, so I'm not sure how to seek on it. + CRYPTOPP_ASSERT(0); CRYPTOPP_UNUSED(iterationCount); +} + +unsigned int XChaCha20_Policy::GetAlignment() const +{ + return ChaCha_GetAlignment(); +} + +unsigned int XChaCha20_Policy::GetOptimalBlockSize() const +{ + return ChaCha_GetOptimalBlockSize(); +} + +void XChaCha20_Policy::OperateKeystream(KeystreamOperation operation, + byte *output, const byte *input, size_t iterationCount) +{ + ChaCha_OperateKeystream(operation, m_state, m_state[12], m_state[13], + m_rounds, output, input, iterationCount); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/chacha.h b/extension/third_party/cryptopp/chacha.h new file mode 100644 index 00000000..8c6dfde5 --- /dev/null +++ b/extension/third_party/cryptopp/chacha.h @@ -0,0 +1,223 @@ +// chacha.h - written and placed in the public domain by Jeffrey Walton. +// Based on Wei Dai's Salsa20, Botan's SSE2 implementation, +// and Bernstein's reference ChaCha family implementation at +// http://cr.yp.to/chacha.html. + +// The library added Bernstein's ChaCha classses at Crypto++ 5.6.4. The IETF +// uses a slightly different implementation than Bernstein, and the IETF +// ChaCha and XChaCha classes were added at Crypto++ 8.1. We wanted to maintain +// ABI compatibility at the 8.1 release so the original ChaCha classes were not +// disturbed. Instead new classes were added for IETF ChaCha. The back-end +// implementation shares code as expected, however. + +/// \file chacha.h +/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers +/// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from ChaCha, a +/// variant of Salsa20 (2008.01.28). Crypto++ also provides the +/// IETF implementation of ChaCha using the ChaChaTLS name. Bernstein's +/// implementation is _slightly_ different from the TLS working group's +/// implementation for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, +/// and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. Finally, +/// the library provides XChaCha: +/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03). +/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS and XChaCha20 since Crypto++ 8.1 + +#ifndef CRYPTOPP_CHACHA_H +#define CRYPTOPP_CHACHA_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein ChaCha ////////////////////////////// + +/// \brief ChaCha stream cipher information +/// \since Crypto++ 5.6.4 +struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details Bernstein named the cipher variants ChaCha8, ChaCha12 and + /// ChaCha20. More generally, Bernstein called the family ChaCha{r}. + /// AlgorithmName() provides the exact name once rounds are set. + static const char* StaticAlgorithmName() { + return "ChaCha"; + } +}; + +/// \brief ChaCha stream cipher implementation +/// \since Crypto++ 5.6.4 +class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~ChaCha_Policy() {} + ChaCha_Policy() : m_rounds(ROUNDS) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + FixedSizeAlignedSecBlock m_state; + unsigned int m_rounds; +}; + +/// \brief ChaCha stream cipher +/// \details This is Bernstein and ECRYPT's ChaCha. It is _slightly_ different +/// from the IETF's version of ChaCha called ChaChaTLS. +/// \sa ChaCha, a variant +/// of Salsa20 (2008.01.28). +/// \since Crypto++ 5.6.4 +struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation +{ + /// \brief ChaCha Encryption + typedef SymmetricCipherFinal >, ChaCha_Info > Encryption; + /// \brief ChaCha Decryption + typedef Encryption Decryption; +}; + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +/// \brief IETF ChaCha20 stream cipher information +/// \since Crypto++ 8.1 +struct ChaChaTLS_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 12>, FixedRounds<20> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details This is the IETF's variant of Bernstein's ChaCha from RFC + /// 8439. IETF ChaCha is called ChaChaTLS in the Crypto++ library. It + /// is _slightly_ different from Bernstein's implementation. + static const char* StaticAlgorithmName() { + return "ChaChaTLS"; + } +}; + +/// \brief IETF ChaCha20 stream cipher implementation +/// \since Crypto++ 8.1 +class CRYPTOPP_NO_VTABLE ChaChaTLS_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~ChaChaTLS_Policy() {} + ChaChaTLS_Policy() : m_counter(0) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + FixedSizeAlignedSecBlock m_state; + unsigned int m_counter; + CRYPTOPP_CONSTANT(ROUNDS = ChaChaTLS_Info::ROUNDS); + CRYPTOPP_CONSTANT(KEY = 16); // Index into m_state + CRYPTOPP_CONSTANT(CTR = 24); // Index into m_state +}; + +/// \brief IETF ChaCha20 stream cipher +/// \details This is the IETF's variant of Bernstein's ChaCha from RFC 8439. +/// IETF ChaCha is called ChaChaTLS in the Crypto++ library. It is +/// _slightly_ different from the Bernstein implementation. ChaCha-TLS +/// can be used for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and +/// TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \sa RFC 8439, ChaCha20 and +/// Poly1305 for IETF Protocols, How +/// to handle block counter wrap in IETF's ChaCha algorithm? and +/// Issue +/// 790, ChaChaTLS results when counter block wraps. +/// \since Crypto++ 8.1 +struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation +{ + /// \brief ChaCha-TLS Encryption + typedef SymmetricCipherFinal >, ChaChaTLS_Info > Encryption; + /// \brief ChaCha-TLS Decryption + typedef Encryption Decryption; +}; + +////////////////////////////// IETF XChaCha20 draft ////////////////////////////// + +/// \brief IETF XChaCha20 stream cipher information +/// \since Crypto++ 8.1 +struct XChaCha20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details This is the IETF's XChaCha from draft-arciszewski-xchacha. + static const char* StaticAlgorithmName() { + return "XChaCha20"; + } +}; + +/// \brief IETF XChaCha20 stream cipher implementation +/// \since Crypto++ 8.1 +class CRYPTOPP_NO_VTABLE XChaCha20_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~XChaCha20_Policy() {} + XChaCha20_Policy() : m_counter(0), m_rounds(ROUNDS) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return false;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + FixedSizeAlignedSecBlock m_state; + unsigned int m_counter, m_rounds; + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + CRYPTOPP_CONSTANT(KEY = 16); // Index into m_state +}; + +/// \brief IETF XChaCha20 stream cipher +/// \details This is the IETF's XChaCha from draft-arciszewski-xchacha. +/// \sa XChaCha: +/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03), How +/// to handle block counter wrap in IETF's ChaCha algorithm? and +/// Issue +/// 790, ChaCha20 results when counter block wraps. +/// \since Crypto++ 8.1 +struct XChaCha20 : public XChaCha20_Info, public SymmetricCipherDocumentation +{ + /// \brief XChaCha Encryption + typedef SymmetricCipherFinal >, XChaCha20_Info > Encryption; + /// \brief XChaCha Decryption + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_CHACHA_H diff --git a/extension/third_party/cryptopp/chacha_avx.cpp b/extension/third_party/cryptopp/chacha_avx.cpp new file mode 100644 index 00000000..c647fa1e --- /dev/null +++ b/extension/third_party/cryptopp/chacha_avx.cpp @@ -0,0 +1,421 @@ +// chacha_avx.cpp - written and placed in the public domain by +// Jack Lloyd and Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// AVX2 instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate +// instructions sets in some build configurations. +// +// AVX2 implementation based on Botan's chacha_avx.cpp. Many thanks +// to Jack Lloyd and the Botan team for allowing us to use it. +// +// Here are some relative numbers for ChaCha8: +// * Intel Skylake, 3.0 GHz: AVX2 at 4411 MB/s; 0.57 cpb. +// * Intel Broadwell, 2.3 GHz: AVX2 at 3828 MB/s; 0.58 cpb. +// * AMD Bulldozer, 3.3 GHz: AVX2 at 1680 MB/s; 1.47 cpb. + +#include "pch.h" +#include "config.h" + +#include "chacha.h" +#include "misc.h" + +#if defined(CRYPTOPP_AVX2_AVAILABLE) +# include +# include +# include +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char CHACHA_AVX_FNAME[] = __FILE__; + +// Sun Studio 12.4 OK, 12.5 and 12.6 compile error. +#if (__SUNPRO_CC >= 0x5140) && (__SUNPRO_CC <= 0x5150) +# define MAYBE_CONST +#else +# define MAYBE_CONST const +#endif + +// VS2017 and global optimization bug. TODO, figure out when +// we can re-enable full optimizations for VS2017. Also see +// https://github.com/weidai11/cryptopp/issues/649 and +// https://github.com/weidai11/cryptopp/issues/735. The +// 649 issue affects AES but it is the same here. The 735 +// issue is ChaCha AVX2 cut-in where it surfaced again. +#if (_MSC_VER >= 1910) +# ifndef CRYPTOPP_DEBUG +# pragma optimize("", off) +# pragma optimize("ts", on) +# endif +#endif + +// The data is aligned, but Clang issues warning based on type +// and not the actual alignment of the variable and data. +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wcast-align" +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +#if (CRYPTOPP_AVX2_AVAILABLE) + +template +inline __m256i RotateLeft(const __m256i val) +{ + return _mm256_or_si256(_mm256_slli_epi32(val, R), _mm256_srli_epi32(val, 32-R)); +} + +template <> +inline __m256i RotateLeft<8>(const __m256i val) +{ + const __m256i mask = _mm256_set_epi8(14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3, + 14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3); + return _mm256_shuffle_epi8(val, mask); +} + +template <> +inline __m256i RotateLeft<16>(const __m256i val) +{ + const __m256i mask = _mm256_set_epi8(13,12,15,14, 9,8,11,10, 5,4,7,6, 1,0,3,2, + 13,12,15,14, 9,8,11,10, 5,4,7,6, 1,0,3,2); + return _mm256_shuffle_epi8(val, mask); +} + +#endif // CRYPTOPP_AVX2_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_AVX2_AVAILABLE) + +void ChaCha_OperateKeystream_AVX2(const word32 *state, const byte* input, byte *output, unsigned int rounds) +{ + const __m256i state0 = _mm256_broadcastsi128_si256( + _mm_loadu_si128(reinterpret_cast(state+0*4))); + const __m256i state1 = _mm256_broadcastsi128_si256( + _mm_loadu_si128(reinterpret_cast(state+1*4))); + const __m256i state2 = _mm256_broadcastsi128_si256( + _mm_loadu_si128(reinterpret_cast(state+2*4))); + const __m256i state3 = _mm256_broadcastsi128_si256( + _mm_loadu_si128(reinterpret_cast(state+3*4))); + + const __m256i CTR0 = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 4); + const __m256i CTR1 = _mm256_set_epi32(0, 0, 0, 1, 0, 0, 0, 5); + const __m256i CTR2 = _mm256_set_epi32(0, 0, 0, 2, 0, 0, 0, 6); + const __m256i CTR3 = _mm256_set_epi32(0, 0, 0, 3, 0, 0, 0, 7); + + __m256i X0_0 = state0; + __m256i X0_1 = state1; + __m256i X0_2 = state2; + __m256i X0_3 = _mm256_add_epi64(state3, CTR0); + + __m256i X1_0 = state0; + __m256i X1_1 = state1; + __m256i X1_2 = state2; + __m256i X1_3 = _mm256_add_epi64(state3, CTR1); + + __m256i X2_0 = state0; + __m256i X2_1 = state1; + __m256i X2_2 = state2; + __m256i X2_3 = _mm256_add_epi64(state3, CTR2); + + __m256i X3_0 = state0; + __m256i X3_1 = state1; + __m256i X3_2 = state2; + __m256i X3_3 = _mm256_add_epi64(state3, CTR3); + + for (int i = static_cast(rounds); i > 0; i -= 2) + { + X0_0 = _mm256_add_epi32(X0_0, X0_1); + X1_0 = _mm256_add_epi32(X1_0, X1_1); + X2_0 = _mm256_add_epi32(X2_0, X2_1); + X3_0 = _mm256_add_epi32(X3_0, X3_1); + + X0_3 = _mm256_xor_si256(X0_3, X0_0); + X1_3 = _mm256_xor_si256(X1_3, X1_0); + X2_3 = _mm256_xor_si256(X2_3, X2_0); + X3_3 = _mm256_xor_si256(X3_3, X3_0); + + X0_3 = RotateLeft<16>(X0_3); + X1_3 = RotateLeft<16>(X1_3); + X2_3 = RotateLeft<16>(X2_3); + X3_3 = RotateLeft<16>(X3_3); + + X0_2 = _mm256_add_epi32(X0_2, X0_3); + X1_2 = _mm256_add_epi32(X1_2, X1_3); + X2_2 = _mm256_add_epi32(X2_2, X2_3); + X3_2 = _mm256_add_epi32(X3_2, X3_3); + + X0_1 = _mm256_xor_si256(X0_1, X0_2); + X1_1 = _mm256_xor_si256(X1_1, X1_2); + X2_1 = _mm256_xor_si256(X2_1, X2_2); + X3_1 = _mm256_xor_si256(X3_1, X3_2); + + X0_1 = RotateLeft<12>(X0_1); + X1_1 = RotateLeft<12>(X1_1); + X2_1 = RotateLeft<12>(X2_1); + X3_1 = RotateLeft<12>(X3_1); + + X0_0 = _mm256_add_epi32(X0_0, X0_1); + X1_0 = _mm256_add_epi32(X1_0, X1_1); + X2_0 = _mm256_add_epi32(X2_0, X2_1); + X3_0 = _mm256_add_epi32(X3_0, X3_1); + + X0_3 = _mm256_xor_si256(X0_3, X0_0); + X1_3 = _mm256_xor_si256(X1_3, X1_0); + X2_3 = _mm256_xor_si256(X2_3, X2_0); + X3_3 = _mm256_xor_si256(X3_3, X3_0); + + X0_3 = RotateLeft<8>(X0_3); + X1_3 = RotateLeft<8>(X1_3); + X2_3 = RotateLeft<8>(X2_3); + X3_3 = RotateLeft<8>(X3_3); + + X0_2 = _mm256_add_epi32(X0_2, X0_3); + X1_2 = _mm256_add_epi32(X1_2, X1_3); + X2_2 = _mm256_add_epi32(X2_2, X2_3); + X3_2 = _mm256_add_epi32(X3_2, X3_3); + + X0_1 = _mm256_xor_si256(X0_1, X0_2); + X1_1 = _mm256_xor_si256(X1_1, X1_2); + X2_1 = _mm256_xor_si256(X2_1, X2_2); + X3_1 = _mm256_xor_si256(X3_1, X3_2); + + X0_1 = RotateLeft<7>(X0_1); + X1_1 = RotateLeft<7>(X1_1); + X2_1 = RotateLeft<7>(X2_1); + X3_1 = RotateLeft<7>(X3_1); + + X0_1 = _mm256_shuffle_epi32(X0_1, _MM_SHUFFLE(0, 3, 2, 1)); + X0_2 = _mm256_shuffle_epi32(X0_2, _MM_SHUFFLE(1, 0, 3, 2)); + X0_3 = _mm256_shuffle_epi32(X0_3, _MM_SHUFFLE(2, 1, 0, 3)); + + X1_1 = _mm256_shuffle_epi32(X1_1, _MM_SHUFFLE(0, 3, 2, 1)); + X1_2 = _mm256_shuffle_epi32(X1_2, _MM_SHUFFLE(1, 0, 3, 2)); + X1_3 = _mm256_shuffle_epi32(X1_3, _MM_SHUFFLE(2, 1, 0, 3)); + + X2_1 = _mm256_shuffle_epi32(X2_1, _MM_SHUFFLE(0, 3, 2, 1)); + X2_2 = _mm256_shuffle_epi32(X2_2, _MM_SHUFFLE(1, 0, 3, 2)); + X2_3 = _mm256_shuffle_epi32(X2_3, _MM_SHUFFLE(2, 1, 0, 3)); + + X3_1 = _mm256_shuffle_epi32(X3_1, _MM_SHUFFLE(0, 3, 2, 1)); + X3_2 = _mm256_shuffle_epi32(X3_2, _MM_SHUFFLE(1, 0, 3, 2)); + X3_3 = _mm256_shuffle_epi32(X3_3, _MM_SHUFFLE(2, 1, 0, 3)); + + X0_0 = _mm256_add_epi32(X0_0, X0_1); + X1_0 = _mm256_add_epi32(X1_0, X1_1); + X2_0 = _mm256_add_epi32(X2_0, X2_1); + X3_0 = _mm256_add_epi32(X3_0, X3_1); + + X0_3 = _mm256_xor_si256(X0_3, X0_0); + X1_3 = _mm256_xor_si256(X1_3, X1_0); + X2_3 = _mm256_xor_si256(X2_3, X2_0); + X3_3 = _mm256_xor_si256(X3_3, X3_0); + + X0_3 = RotateLeft<16>(X0_3); + X1_3 = RotateLeft<16>(X1_3); + X2_3 = RotateLeft<16>(X2_3); + X3_3 = RotateLeft<16>(X3_3); + + X0_2 = _mm256_add_epi32(X0_2, X0_3); + X1_2 = _mm256_add_epi32(X1_2, X1_3); + X2_2 = _mm256_add_epi32(X2_2, X2_3); + X3_2 = _mm256_add_epi32(X3_2, X3_3); + + X0_1 = _mm256_xor_si256(X0_1, X0_2); + X1_1 = _mm256_xor_si256(X1_1, X1_2); + X2_1 = _mm256_xor_si256(X2_1, X2_2); + X3_1 = _mm256_xor_si256(X3_1, X3_2); + + X0_1 = RotateLeft<12>(X0_1); + X1_1 = RotateLeft<12>(X1_1); + X2_1 = RotateLeft<12>(X2_1); + X3_1 = RotateLeft<12>(X3_1); + + X0_0 = _mm256_add_epi32(X0_0, X0_1); + X1_0 = _mm256_add_epi32(X1_0, X1_1); + X2_0 = _mm256_add_epi32(X2_0, X2_1); + X3_0 = _mm256_add_epi32(X3_0, X3_1); + + X0_3 = _mm256_xor_si256(X0_3, X0_0); + X1_3 = _mm256_xor_si256(X1_3, X1_0); + X2_3 = _mm256_xor_si256(X2_3, X2_0); + X3_3 = _mm256_xor_si256(X3_3, X3_0); + + X0_3 = RotateLeft<8>(X0_3); + X1_3 = RotateLeft<8>(X1_3); + X2_3 = RotateLeft<8>(X2_3); + X3_3 = RotateLeft<8>(X3_3); + + X0_2 = _mm256_add_epi32(X0_2, X0_3); + X1_2 = _mm256_add_epi32(X1_2, X1_3); + X2_2 = _mm256_add_epi32(X2_2, X2_3); + X3_2 = _mm256_add_epi32(X3_2, X3_3); + + X0_1 = _mm256_xor_si256(X0_1, X0_2); + X1_1 = _mm256_xor_si256(X1_1, X1_2); + X2_1 = _mm256_xor_si256(X2_1, X2_2); + X3_1 = _mm256_xor_si256(X3_1, X3_2); + + X0_1 = RotateLeft<7>(X0_1); + X1_1 = RotateLeft<7>(X1_1); + X2_1 = RotateLeft<7>(X2_1); + X3_1 = RotateLeft<7>(X3_1); + + X0_1 = _mm256_shuffle_epi32(X0_1, _MM_SHUFFLE(2, 1, 0, 3)); + X0_2 = _mm256_shuffle_epi32(X0_2, _MM_SHUFFLE(1, 0, 3, 2)); + X0_3 = _mm256_shuffle_epi32(X0_3, _MM_SHUFFLE(0, 3, 2, 1)); + + X1_1 = _mm256_shuffle_epi32(X1_1, _MM_SHUFFLE(2, 1, 0, 3)); + X1_2 = _mm256_shuffle_epi32(X1_2, _MM_SHUFFLE(1, 0, 3, 2)); + X1_3 = _mm256_shuffle_epi32(X1_3, _MM_SHUFFLE(0, 3, 2, 1)); + + X2_1 = _mm256_shuffle_epi32(X2_1, _MM_SHUFFLE(2, 1, 0, 3)); + X2_2 = _mm256_shuffle_epi32(X2_2, _MM_SHUFFLE(1, 0, 3, 2)); + X2_3 = _mm256_shuffle_epi32(X2_3, _MM_SHUFFLE(0, 3, 2, 1)); + + X3_1 = _mm256_shuffle_epi32(X3_1, _MM_SHUFFLE(2, 1, 0, 3)); + X3_2 = _mm256_shuffle_epi32(X3_2, _MM_SHUFFLE(1, 0, 3, 2)); + X3_3 = _mm256_shuffle_epi32(X3_3, _MM_SHUFFLE(0, 3, 2, 1)); + } + + X0_0 = _mm256_add_epi32(X0_0, state0); + X0_1 = _mm256_add_epi32(X0_1, state1); + X0_2 = _mm256_add_epi32(X0_2, state2); + X0_3 = _mm256_add_epi32(X0_3, state3); + X0_3 = _mm256_add_epi64(X0_3, CTR0); + + X1_0 = _mm256_add_epi32(X1_0, state0); + X1_1 = _mm256_add_epi32(X1_1, state1); + X1_2 = _mm256_add_epi32(X1_2, state2); + X1_3 = _mm256_add_epi32(X1_3, state3); + X1_3 = _mm256_add_epi64(X1_3, CTR1); + + X2_0 = _mm256_add_epi32(X2_0, state0); + X2_1 = _mm256_add_epi32(X2_1, state1); + X2_2 = _mm256_add_epi32(X2_2, state2); + X2_3 = _mm256_add_epi32(X2_3, state3); + X2_3 = _mm256_add_epi64(X2_3, CTR2); + + X3_0 = _mm256_add_epi32(X3_0, state0); + X3_1 = _mm256_add_epi32(X3_1, state1); + X3_2 = _mm256_add_epi32(X3_2, state2); + X3_3 = _mm256_add_epi32(X3_3, state3); + X3_3 = _mm256_add_epi64(X3_3, CTR3); + + if (input) + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+0*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X0_0, X0_1, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+0*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+1*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X0_2, X0_3, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+1*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+2*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X1_0, X1_1, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+2*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+3*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X1_2, X1_3, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+3*32))))); + } + else + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+0*32), + _mm256_permute2x128_si256(X0_0, X0_1, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+1*32), + _mm256_permute2x128_si256(X0_2, X0_3, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+2*32), + _mm256_permute2x128_si256(X1_0, X1_1, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+3*32), + _mm256_permute2x128_si256(X1_2, X1_3, 1 + (3 << 4))); + } + + if (input) + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+4*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X2_0, X2_1, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+4*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+5*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X2_2, X2_3, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+5*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+6*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X3_0, X3_1, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+6*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+7*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X3_2, X3_3, 1 + (3 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+7*32))))); + } + else + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+4*32), + _mm256_permute2x128_si256(X2_0, X2_1, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+5*32), + _mm256_permute2x128_si256(X2_2, X2_3, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+6*32), + _mm256_permute2x128_si256(X3_0, X3_1, 1 + (3 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+7*32), + _mm256_permute2x128_si256(X3_2, X3_3, 1 + (3 << 4))); + } + + if (input) + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+ 8*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X0_0, X0_1, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+8*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+ 9*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X0_2, X0_3, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+9*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+10*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X1_0, X1_1, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+10*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+11*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X1_2, X1_3, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+11*32))))); + } + else + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+ 8*32), + _mm256_permute2x128_si256(X0_0, X0_1, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+ 9*32), + _mm256_permute2x128_si256(X0_2, X0_3, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+10*32), + _mm256_permute2x128_si256(X1_0, X1_1, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+11*32), + _mm256_permute2x128_si256(X1_2, X1_3, 0 + (2 << 4))); + } + + if (input) + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+12*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X2_0, X2_1, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+12*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+13*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X2_2, X2_3, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+13*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+14*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X3_0, X3_1, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+14*32))))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+15*32), + _mm256_xor_si256(_mm256_permute2x128_si256(X3_2, X3_3, 0 + (2 << 4)), + _mm256_loadu_si256(const_cast(reinterpret_cast(input+15*32))))); + } + else + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+12*32), + _mm256_permute2x128_si256(X2_0, X2_1, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+13*32), + _mm256_permute2x128_si256(X2_2, X2_3, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+14*32), + _mm256_permute2x128_si256(X3_0, X3_1, 0 + (2 << 4))); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(output+15*32), + _mm256_permute2x128_si256(X3_2, X3_3, 0 + (2 << 4))); + } + + // https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties + _mm256_zeroupper(); +} + +#endif // CRYPTOPP_AVX2_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/chacha_simd.cpp b/extension/third_party/cryptopp/chacha_simd.cpp new file mode 100644 index 00000000..4e5a3cc3 --- /dev/null +++ b/extension/third_party/cryptopp/chacha_simd.cpp @@ -0,0 +1,1109 @@ +// chacha_simd.cpp - written and placed in the public domain by +// Jack Lloyd and Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSE2, ARM NEON and ARMv8a, Power7 and Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. +// +// SSE2 implementation based on Botan's chacha_sse2.cpp. Many thanks +// to Jack Lloyd and the Botan team for allowing us to use it. +// +// The SSE2 implementation is kind of unusual among Crypto++ algorithms. +// We guard on CRYTPOPP_SSE2_AVAILABLE and use HasSSE2() at runtime. However, +// if the compiler says a target machine has SSSE3 or XOP available (say, by +// way of -march=native), then we can pull another 150 to 800 MB/s out of +// ChaCha. To capture SSSE3 and XOP we use the compiler defines __SSSE3__ and +// __XOP__ and forgo runtime tests. +// +// Runtime tests for HasSSSE3() and HasXop() are too expensive to make a +// sub-case of SSE2. The rotates are on a critical path and the runtime tests +// crush performance. +// +// Here are some relative numbers for ChaCha8: +// * Intel Skylake, 3.0 GHz: SSE2 at 2160 MB/s; SSSE3 at 2310 MB/s. +// * AMD Bulldozer, 3.3 GHz: SSE2 at 1680 MB/s; XOP at 2510 MB/s. + +#include "pch.h" +#include "config.h" + +#include "chacha.h" +#include "misc.h" + +// Internal compiler error in GCC 3.3 and below +#if defined(__GNUC__) && (__GNUC__ < 4) +# undef CRYPTOPP_SSE2_INTRIN_AVAILABLE +#endif + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +# include +# include +#endif + +#if defined(__SSSE3__) +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char CHACHA_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +// ***************************** NEON ***************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +template +inline uint32x4_t RotateLeft(const uint32x4_t& val) +{ + return vorrq_u32(vshlq_n_u32(val, R), vshrq_n_u32(val, 32 - R)); +} + +template +inline uint32x4_t RotateRight(const uint32x4_t& val) +{ + return vorrq_u32(vshlq_n_u32(val, 32 - R), vshrq_n_u32(val, R)); +} + +template <> +inline uint32x4_t RotateLeft<8>(const uint32x4_t& val) +{ +#if defined(__aarch32__) || defined(__aarch64__) + const uint8_t maskb[16] = { 3,0,1,2, 7,4,5,6, 11,8,9,10, 15,12,13,14 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u32_u8( + vqtbl1q_u8(vreinterpretq_u8_u32(val), mask)); +#else + // fallback to slower C++ rotation. + return vorrq_u32(vshlq_n_u32(val, 8), + vshrq_n_u32(val, 32 - 8)); +#endif +} + +template <> +inline uint32x4_t RotateLeft<16>(const uint32x4_t& val) +{ +#if defined(__aarch32__) || defined(__aarch64__) + return vreinterpretq_u32_u16( + vrev32q_u16(vreinterpretq_u16_u32(val))); +#else + // fallback to slower C++ rotation. + return vorrq_u32(vshlq_n_u32(val, 16), + vshrq_n_u32(val, 32 - 16)); +#endif +} + +template <> +inline uint32x4_t RotateRight<8>(const uint32x4_t& val) +{ +#if defined(__aarch32__) || defined(__aarch64__) + const uint8_t maskb[16] = { 1,2,3,0, 5,6,7,4, 9,10,11,8, 13,14,15,12 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u32_u8( + vqtbl1q_u8(vreinterpretq_u8_u32(val), mask)); +#else + // fallback to slower C++ rotation. + return vorrq_u32(vshrq_n_u32(val, 8), + vshlq_n_u32(val, 32 - 8)); +#endif +} + +template <> +inline uint32x4_t RotateRight<16>(const uint32x4_t& val) +{ +#if defined(__aarch32__) || defined(__aarch64__) + return vreinterpretq_u32_u16( + vrev32q_u16(vreinterpretq_u16_u32(val))); +#else + // fallback to slower C++ rotation. + return vorrq_u32(vshrq_n_u32(val, 16), + vshlq_n_u32(val, 32 - 16)); +#endif +} + +// ChaCha's use of x86 shuffle is really a 4, 8, or 12 byte +// rotation on the 128-bit vector word: +// * [3,2,1,0] => [0,3,2,1] is Extract<1>(x) +// * [3,2,1,0] => [1,0,3,2] is Extract<2>(x) +// * [3,2,1,0] => [2,1,0,3] is Extract<3>(x) +template +inline uint32x4_t Extract(const uint32x4_t& val) +{ + return vextq_u32(val, val, S); +} + +// Helper to perform 64-bit addition across two elements of 32-bit vectors +inline uint32x4_t Add64(const uint32x4_t& a, const uint32x4_t& b) +{ + return vreinterpretq_u32_u64( + vaddq_u64( + vreinterpretq_u64_u32(a), + vreinterpretq_u64_u32(b))); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** SSE2 ***************************** // + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + +template +inline __m128i RotateLeft(const __m128i val) +{ +#ifdef __XOP__ + return _mm_roti_epi32(val, R); +#else + return _mm_or_si128(_mm_slli_epi32(val, R), _mm_srli_epi32(val, 32-R)); +#endif +} + +template <> +inline __m128i RotateLeft<8>(const __m128i val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 8); +#elif defined(__SSSE3__) + const __m128i mask = _mm_set_epi8(14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3); + return _mm_shuffle_epi8(val, mask); +#else + return _mm_or_si128(_mm_slli_epi32(val, 8), _mm_srli_epi32(val, 32-8)); +#endif +} + +template <> +inline __m128i RotateLeft<16>(const __m128i val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 16); +#elif defined(__SSSE3__) + const __m128i mask = _mm_set_epi8(13,12,15,14, 9,8,11,10, 5,4,7,6, 1,0,3,2); + return _mm_shuffle_epi8(val, mask); +#else + return _mm_or_si128(_mm_slli_epi32(val, 16), _mm_srli_epi32(val, 32-16)); +#endif +} + +#endif // CRYPTOPP_SSE2_INTRIN_AVAILABLE + +// **************************** Altivec **************************** // + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + +// ChaCha_OperateKeystream is optimized for Altivec. However, Altivec +// is supported by using vec_ld and vec_st, and using a composite VecAdd +// that supports 64-bit element adds. vec_ld and vec_st add significant +// overhead when memory is not aligned. Despite the drawbacks Altivec +// is profitable. The numbers for ChaCha8 are: +// +// PowerMac, C++, 2.0 GHz: 205 MB/s, 9.29 cpb +// PowerMac, Altivec, 2.0 GHz: 471 MB/s, 4.09 cpb + +using CryptoPP::uint8x16_p; +using CryptoPP::uint32x4_p; +using CryptoPP::VecLoad; +using CryptoPP::VecLoadAligned; +using CryptoPP::VecStore; +using CryptoPP::VecPermute; + +// Permutes bytes in packed 32-bit words to little endian. +// State is already in proper endian order. Input and +// output must be permuted during load and save. +inline uint32x4_p VecLoad32LE(const uint8_t src[16]) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12}; + const uint32x4_p val = VecLoad(src); + return VecPermute(val, val, mask); +#else + return VecLoad(src); +#endif +} + +// Permutes bytes in packed 32-bit words to little endian. +// State is already in proper endian order. Input and +// output must be permuted during load and save. +inline void VecStore32LE(uint8_t dest[16], const uint32x4_p& val) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12}; + VecStore(VecPermute(val, val, mask), dest); +#else + return VecStore(val, dest); +#endif +} + +// ChaCha's use of x86 shuffle is really a 4, 8, or 12 byte +// rotation on the 128-bit vector word: +// * [3,2,1,0] => [0,3,2,1] is Shuffle<1>(x) +// * [3,2,1,0] => [1,0,3,2] is Shuffle<2>(x) +// * [3,2,1,0] => [2,1,0,3] is Shuffle<3>(x) +template +inline uint32x4_p Shuffle(const uint32x4_p& val) +{ + CRYPTOPP_ASSERT(0); + return val; +} + +template <> +inline uint32x4_p Shuffle<1>(const uint32x4_p& val) +{ + const uint8x16_p mask = {4,5,6,7, 8,9,10,11, 12,13,14,15, 0,1,2,3}; + return VecPermute(val, val, mask); +} + +template <> +inline uint32x4_p Shuffle<2>(const uint32x4_p& val) +{ + const uint8x16_p mask = {8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7}; + return VecPermute(val, val, mask); +} + +template <> +inline uint32x4_p Shuffle<3>(const uint32x4_p& val) +{ + const uint8x16_p mask = {12,13,14,15, 0,1,2,3, 4,5,6,7, 8,9,10,11}; + return VecPermute(val, val, mask); +} + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +// ***************************** NEON ***************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +void ChaCha_OperateKeystream_NEON(const word32 *state, const byte* input, byte *output, unsigned int rounds) +{ + const uint32x4_t state0 = vld1q_u32(state + 0*4); + const uint32x4_t state1 = vld1q_u32(state + 1*4); + const uint32x4_t state2 = vld1q_u32(state + 2*4); + const uint32x4_t state3 = vld1q_u32(state + 3*4); + + const unsigned int w[] = {1,0,0,0, 2,0,0,0, 3,0,0,0}; + const uint32x4_t CTRS[3] = { + vld1q_u32(w+0), vld1q_u32(w+4), vld1q_u32(w+8) + }; + + uint32x4_t r0_0 = state0; + uint32x4_t r0_1 = state1; + uint32x4_t r0_2 = state2; + uint32x4_t r0_3 = state3; + + uint32x4_t r1_0 = state0; + uint32x4_t r1_1 = state1; + uint32x4_t r1_2 = state2; + uint32x4_t r1_3 = Add64(r0_3, CTRS[0]); + + uint32x4_t r2_0 = state0; + uint32x4_t r2_1 = state1; + uint32x4_t r2_2 = state2; + uint32x4_t r2_3 = Add64(r0_3, CTRS[1]); + + uint32x4_t r3_0 = state0; + uint32x4_t r3_1 = state1; + uint32x4_t r3_2 = state2; + uint32x4_t r3_3 = Add64(r0_3, CTRS[2]); + + for (int i = static_cast(rounds); i > 0; i -= 2) + { + r0_0 = vaddq_u32(r0_0, r0_1); + r1_0 = vaddq_u32(r1_0, r1_1); + r2_0 = vaddq_u32(r2_0, r2_1); + r3_0 = vaddq_u32(r3_0, r3_1); + + r0_3 = veorq_u32(r0_3, r0_0); + r1_3 = veorq_u32(r1_3, r1_0); + r2_3 = veorq_u32(r2_3, r2_0); + r3_3 = veorq_u32(r3_3, r3_0); + + r0_3 = RotateLeft<16>(r0_3); + r1_3 = RotateLeft<16>(r1_3); + r2_3 = RotateLeft<16>(r2_3); + r3_3 = RotateLeft<16>(r3_3); + + r0_2 = vaddq_u32(r0_2, r0_3); + r1_2 = vaddq_u32(r1_2, r1_3); + r2_2 = vaddq_u32(r2_2, r2_3); + r3_2 = vaddq_u32(r3_2, r3_3); + + r0_1 = veorq_u32(r0_1, r0_2); + r1_1 = veorq_u32(r1_1, r1_2); + r2_1 = veorq_u32(r2_1, r2_2); + r3_1 = veorq_u32(r3_1, r3_2); + + r0_1 = RotateLeft<12>(r0_1); + r1_1 = RotateLeft<12>(r1_1); + r2_1 = RotateLeft<12>(r2_1); + r3_1 = RotateLeft<12>(r3_1); + + r0_0 = vaddq_u32(r0_0, r0_1); + r1_0 = vaddq_u32(r1_0, r1_1); + r2_0 = vaddq_u32(r2_0, r2_1); + r3_0 = vaddq_u32(r3_0, r3_1); + + r0_3 = veorq_u32(r0_3, r0_0); + r1_3 = veorq_u32(r1_3, r1_0); + r2_3 = veorq_u32(r2_3, r2_0); + r3_3 = veorq_u32(r3_3, r3_0); + + r0_3 = RotateLeft<8>(r0_3); + r1_3 = RotateLeft<8>(r1_3); + r2_3 = RotateLeft<8>(r2_3); + r3_3 = RotateLeft<8>(r3_3); + + r0_2 = vaddq_u32(r0_2, r0_3); + r1_2 = vaddq_u32(r1_2, r1_3); + r2_2 = vaddq_u32(r2_2, r2_3); + r3_2 = vaddq_u32(r3_2, r3_3); + + r0_1 = veorq_u32(r0_1, r0_2); + r1_1 = veorq_u32(r1_1, r1_2); + r2_1 = veorq_u32(r2_1, r2_2); + r3_1 = veorq_u32(r3_1, r3_2); + + r0_1 = RotateLeft<7>(r0_1); + r1_1 = RotateLeft<7>(r1_1); + r2_1 = RotateLeft<7>(r2_1); + r3_1 = RotateLeft<7>(r3_1); + + r0_1 = Extract<1>(r0_1); + r0_2 = Extract<2>(r0_2); + r0_3 = Extract<3>(r0_3); + + r1_1 = Extract<1>(r1_1); + r1_2 = Extract<2>(r1_2); + r1_3 = Extract<3>(r1_3); + + r2_1 = Extract<1>(r2_1); + r2_2 = Extract<2>(r2_2); + r2_3 = Extract<3>(r2_3); + + r3_1 = Extract<1>(r3_1); + r3_2 = Extract<2>(r3_2); + r3_3 = Extract<3>(r3_3); + + r0_0 = vaddq_u32(r0_0, r0_1); + r1_0 = vaddq_u32(r1_0, r1_1); + r2_0 = vaddq_u32(r2_0, r2_1); + r3_0 = vaddq_u32(r3_0, r3_1); + + r0_3 = veorq_u32(r0_3, r0_0); + r1_3 = veorq_u32(r1_3, r1_0); + r2_3 = veorq_u32(r2_3, r2_0); + r3_3 = veorq_u32(r3_3, r3_0); + + r0_3 = RotateLeft<16>(r0_3); + r1_3 = RotateLeft<16>(r1_3); + r2_3 = RotateLeft<16>(r2_3); + r3_3 = RotateLeft<16>(r3_3); + + r0_2 = vaddq_u32(r0_2, r0_3); + r1_2 = vaddq_u32(r1_2, r1_3); + r2_2 = vaddq_u32(r2_2, r2_3); + r3_2 = vaddq_u32(r3_2, r3_3); + + r0_1 = veorq_u32(r0_1, r0_2); + r1_1 = veorq_u32(r1_1, r1_2); + r2_1 = veorq_u32(r2_1, r2_2); + r3_1 = veorq_u32(r3_1, r3_2); + + r0_1 = RotateLeft<12>(r0_1); + r1_1 = RotateLeft<12>(r1_1); + r2_1 = RotateLeft<12>(r2_1); + r3_1 = RotateLeft<12>(r3_1); + + r0_0 = vaddq_u32(r0_0, r0_1); + r1_0 = vaddq_u32(r1_0, r1_1); + r2_0 = vaddq_u32(r2_0, r2_1); + r3_0 = vaddq_u32(r3_0, r3_1); + + r0_3 = veorq_u32(r0_3, r0_0); + r1_3 = veorq_u32(r1_3, r1_0); + r2_3 = veorq_u32(r2_3, r2_0); + r3_3 = veorq_u32(r3_3, r3_0); + + r0_3 = RotateLeft<8>(r0_3); + r1_3 = RotateLeft<8>(r1_3); + r2_3 = RotateLeft<8>(r2_3); + r3_3 = RotateLeft<8>(r3_3); + + r0_2 = vaddq_u32(r0_2, r0_3); + r1_2 = vaddq_u32(r1_2, r1_3); + r2_2 = vaddq_u32(r2_2, r2_3); + r3_2 = vaddq_u32(r3_2, r3_3); + + r0_1 = veorq_u32(r0_1, r0_2); + r1_1 = veorq_u32(r1_1, r1_2); + r2_1 = veorq_u32(r2_1, r2_2); + r3_1 = veorq_u32(r3_1, r3_2); + + r0_1 = RotateLeft<7>(r0_1); + r1_1 = RotateLeft<7>(r1_1); + r2_1 = RotateLeft<7>(r2_1); + r3_1 = RotateLeft<7>(r3_1); + + r0_1 = Extract<3>(r0_1); + r0_2 = Extract<2>(r0_2); + r0_3 = Extract<1>(r0_3); + + r1_1 = Extract<3>(r1_1); + r1_2 = Extract<2>(r1_2); + r1_3 = Extract<1>(r1_3); + + r2_1 = Extract<3>(r2_1); + r2_2 = Extract<2>(r2_2); + r2_3 = Extract<1>(r2_3); + + r3_1 = Extract<3>(r3_1); + r3_2 = Extract<2>(r3_2); + r3_3 = Extract<1>(r3_3); + } + + r0_0 = vaddq_u32(r0_0, state0); + r0_1 = vaddq_u32(r0_1, state1); + r0_2 = vaddq_u32(r0_2, state2); + r0_3 = vaddq_u32(r0_3, state3); + + r1_0 = vaddq_u32(r1_0, state0); + r1_1 = vaddq_u32(r1_1, state1); + r1_2 = vaddq_u32(r1_2, state2); + r1_3 = vaddq_u32(r1_3, state3); + r1_3 = Add64(r1_3, CTRS[0]); + + r2_0 = vaddq_u32(r2_0, state0); + r2_1 = vaddq_u32(r2_1, state1); + r2_2 = vaddq_u32(r2_2, state2); + r2_3 = vaddq_u32(r2_3, state3); + r2_3 = Add64(r2_3, CTRS[1]); + + r3_0 = vaddq_u32(r3_0, state0); + r3_1 = vaddq_u32(r3_1, state1); + r3_2 = vaddq_u32(r3_2, state2); + r3_3 = vaddq_u32(r3_3, state3); + r3_3 = Add64(r3_3, CTRS[2]); + + if (input) + { + r0_0 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 0*16)), r0_0); + r0_1 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 1*16)), r0_1); + r0_2 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 2*16)), r0_2); + r0_3 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 3*16)), r0_3); + } + + vst1q_u8(output + 0*16, vreinterpretq_u8_u32(r0_0)); + vst1q_u8(output + 1*16, vreinterpretq_u8_u32(r0_1)); + vst1q_u8(output + 2*16, vreinterpretq_u8_u32(r0_2)); + vst1q_u8(output + 3*16, vreinterpretq_u8_u32(r0_3)); + + if (input) + { + r1_0 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 4*16)), r1_0); + r1_1 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 5*16)), r1_1); + r1_2 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 6*16)), r1_2); + r1_3 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 7*16)), r1_3); + } + + vst1q_u8(output + 4*16, vreinterpretq_u8_u32(r1_0)); + vst1q_u8(output + 5*16, vreinterpretq_u8_u32(r1_1)); + vst1q_u8(output + 6*16, vreinterpretq_u8_u32(r1_2)); + vst1q_u8(output + 7*16, vreinterpretq_u8_u32(r1_3)); + + if (input) + { + r2_0 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 8*16)), r2_0); + r2_1 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 9*16)), r2_1); + r2_2 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 10*16)), r2_2); + r2_3 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 11*16)), r2_3); + } + + vst1q_u8(output + 8*16, vreinterpretq_u8_u32(r2_0)); + vst1q_u8(output + 9*16, vreinterpretq_u8_u32(r2_1)); + vst1q_u8(output + 10*16, vreinterpretq_u8_u32(r2_2)); + vst1q_u8(output + 11*16, vreinterpretq_u8_u32(r2_3)); + + if (input) + { + r3_0 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 12*16)), r3_0); + r3_1 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 13*16)), r3_1); + r3_2 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 14*16)), r3_2); + r3_3 = veorq_u32(vreinterpretq_u32_u8(vld1q_u8(input + 15*16)), r3_3); + } + + vst1q_u8(output + 12*16, vreinterpretq_u8_u32(r3_0)); + vst1q_u8(output + 13*16, vreinterpretq_u8_u32(r3_1)); + vst1q_u8(output + 14*16, vreinterpretq_u8_u32(r3_2)); + vst1q_u8(output + 15*16, vreinterpretq_u8_u32(r3_3)); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** SSE2 ***************************** // + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) + +void ChaCha_OperateKeystream_SSE2(const word32 *state, const byte* input, byte *output, unsigned int rounds) +{ + const __m128i state0 = _mm_load_si128(reinterpret_cast(state+0*4)); + const __m128i state1 = _mm_load_si128(reinterpret_cast(state+1*4)); + const __m128i state2 = _mm_load_si128(reinterpret_cast(state+2*4)); + const __m128i state3 = _mm_load_si128(reinterpret_cast(state+3*4)); + + __m128i r0_0 = state0; + __m128i r0_1 = state1; + __m128i r0_2 = state2; + __m128i r0_3 = state3; + + __m128i r1_0 = state0; + __m128i r1_1 = state1; + __m128i r1_2 = state2; + __m128i r1_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 1)); + + __m128i r2_0 = state0; + __m128i r2_1 = state1; + __m128i r2_2 = state2; + __m128i r2_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 2)); + + __m128i r3_0 = state0; + __m128i r3_1 = state1; + __m128i r3_2 = state2; + __m128i r3_3 = _mm_add_epi64(r0_3, _mm_set_epi32(0, 0, 0, 3)); + + for (int i = static_cast(rounds); i > 0; i -= 2) + { + r0_0 = _mm_add_epi32(r0_0, r0_1); + r1_0 = _mm_add_epi32(r1_0, r1_1); + r2_0 = _mm_add_epi32(r2_0, r2_1); + r3_0 = _mm_add_epi32(r3_0, r3_1); + + r0_3 = _mm_xor_si128(r0_3, r0_0); + r1_3 = _mm_xor_si128(r1_3, r1_0); + r2_3 = _mm_xor_si128(r2_3, r2_0); + r3_3 = _mm_xor_si128(r3_3, r3_0); + + r0_3 = RotateLeft<16>(r0_3); + r1_3 = RotateLeft<16>(r1_3); + r2_3 = RotateLeft<16>(r2_3); + r3_3 = RotateLeft<16>(r3_3); + + r0_2 = _mm_add_epi32(r0_2, r0_3); + r1_2 = _mm_add_epi32(r1_2, r1_3); + r2_2 = _mm_add_epi32(r2_2, r2_3); + r3_2 = _mm_add_epi32(r3_2, r3_3); + + r0_1 = _mm_xor_si128(r0_1, r0_2); + r1_1 = _mm_xor_si128(r1_1, r1_2); + r2_1 = _mm_xor_si128(r2_1, r2_2); + r3_1 = _mm_xor_si128(r3_1, r3_2); + + r0_1 = RotateLeft<12>(r0_1); + r1_1 = RotateLeft<12>(r1_1); + r2_1 = RotateLeft<12>(r2_1); + r3_1 = RotateLeft<12>(r3_1); + + r0_0 = _mm_add_epi32(r0_0, r0_1); + r1_0 = _mm_add_epi32(r1_0, r1_1); + r2_0 = _mm_add_epi32(r2_0, r2_1); + r3_0 = _mm_add_epi32(r3_0, r3_1); + + r0_3 = _mm_xor_si128(r0_3, r0_0); + r1_3 = _mm_xor_si128(r1_3, r1_0); + r2_3 = _mm_xor_si128(r2_3, r2_0); + r3_3 = _mm_xor_si128(r3_3, r3_0); + + r0_3 = RotateLeft<8>(r0_3); + r1_3 = RotateLeft<8>(r1_3); + r2_3 = RotateLeft<8>(r2_3); + r3_3 = RotateLeft<8>(r3_3); + + r0_2 = _mm_add_epi32(r0_2, r0_3); + r1_2 = _mm_add_epi32(r1_2, r1_3); + r2_2 = _mm_add_epi32(r2_2, r2_3); + r3_2 = _mm_add_epi32(r3_2, r3_3); + + r0_1 = _mm_xor_si128(r0_1, r0_2); + r1_1 = _mm_xor_si128(r1_1, r1_2); + r2_1 = _mm_xor_si128(r2_1, r2_2); + r3_1 = _mm_xor_si128(r3_1, r3_2); + + r0_1 = RotateLeft<7>(r0_1); + r1_1 = RotateLeft<7>(r1_1); + r2_1 = RotateLeft<7>(r2_1); + r3_1 = RotateLeft<7>(r3_1); + + r0_1 = _mm_shuffle_epi32(r0_1, _MM_SHUFFLE(0, 3, 2, 1)); + r0_2 = _mm_shuffle_epi32(r0_2, _MM_SHUFFLE(1, 0, 3, 2)); + r0_3 = _mm_shuffle_epi32(r0_3, _MM_SHUFFLE(2, 1, 0, 3)); + + r1_1 = _mm_shuffle_epi32(r1_1, _MM_SHUFFLE(0, 3, 2, 1)); + r1_2 = _mm_shuffle_epi32(r1_2, _MM_SHUFFLE(1, 0, 3, 2)); + r1_3 = _mm_shuffle_epi32(r1_3, _MM_SHUFFLE(2, 1, 0, 3)); + + r2_1 = _mm_shuffle_epi32(r2_1, _MM_SHUFFLE(0, 3, 2, 1)); + r2_2 = _mm_shuffle_epi32(r2_2, _MM_SHUFFLE(1, 0, 3, 2)); + r2_3 = _mm_shuffle_epi32(r2_3, _MM_SHUFFLE(2, 1, 0, 3)); + + r3_1 = _mm_shuffle_epi32(r3_1, _MM_SHUFFLE(0, 3, 2, 1)); + r3_2 = _mm_shuffle_epi32(r3_2, _MM_SHUFFLE(1, 0, 3, 2)); + r3_3 = _mm_shuffle_epi32(r3_3, _MM_SHUFFLE(2, 1, 0, 3)); + + r0_0 = _mm_add_epi32(r0_0, r0_1); + r1_0 = _mm_add_epi32(r1_0, r1_1); + r2_0 = _mm_add_epi32(r2_0, r2_1); + r3_0 = _mm_add_epi32(r3_0, r3_1); + + r0_3 = _mm_xor_si128(r0_3, r0_0); + r1_3 = _mm_xor_si128(r1_3, r1_0); + r2_3 = _mm_xor_si128(r2_3, r2_0); + r3_3 = _mm_xor_si128(r3_3, r3_0); + + r0_3 = RotateLeft<16>(r0_3); + r1_3 = RotateLeft<16>(r1_3); + r2_3 = RotateLeft<16>(r2_3); + r3_3 = RotateLeft<16>(r3_3); + + r0_2 = _mm_add_epi32(r0_2, r0_3); + r1_2 = _mm_add_epi32(r1_2, r1_3); + r2_2 = _mm_add_epi32(r2_2, r2_3); + r3_2 = _mm_add_epi32(r3_2, r3_3); + + r0_1 = _mm_xor_si128(r0_1, r0_2); + r1_1 = _mm_xor_si128(r1_1, r1_2); + r2_1 = _mm_xor_si128(r2_1, r2_2); + r3_1 = _mm_xor_si128(r3_1, r3_2); + + r0_1 = RotateLeft<12>(r0_1); + r1_1 = RotateLeft<12>(r1_1); + r2_1 = RotateLeft<12>(r2_1); + r3_1 = RotateLeft<12>(r3_1); + + r0_0 = _mm_add_epi32(r0_0, r0_1); + r1_0 = _mm_add_epi32(r1_0, r1_1); + r2_0 = _mm_add_epi32(r2_0, r2_1); + r3_0 = _mm_add_epi32(r3_0, r3_1); + + r0_3 = _mm_xor_si128(r0_3, r0_0); + r1_3 = _mm_xor_si128(r1_3, r1_0); + r2_3 = _mm_xor_si128(r2_3, r2_0); + r3_3 = _mm_xor_si128(r3_3, r3_0); + + r0_3 = RotateLeft<8>(r0_3); + r1_3 = RotateLeft<8>(r1_3); + r2_3 = RotateLeft<8>(r2_3); + r3_3 = RotateLeft<8>(r3_3); + + r0_2 = _mm_add_epi32(r0_2, r0_3); + r1_2 = _mm_add_epi32(r1_2, r1_3); + r2_2 = _mm_add_epi32(r2_2, r2_3); + r3_2 = _mm_add_epi32(r3_2, r3_3); + + r0_1 = _mm_xor_si128(r0_1, r0_2); + r1_1 = _mm_xor_si128(r1_1, r1_2); + r2_1 = _mm_xor_si128(r2_1, r2_2); + r3_1 = _mm_xor_si128(r3_1, r3_2); + + r0_1 = RotateLeft<7>(r0_1); + r1_1 = RotateLeft<7>(r1_1); + r2_1 = RotateLeft<7>(r2_1); + r3_1 = RotateLeft<7>(r3_1); + + r0_1 = _mm_shuffle_epi32(r0_1, _MM_SHUFFLE(2, 1, 0, 3)); + r0_2 = _mm_shuffle_epi32(r0_2, _MM_SHUFFLE(1, 0, 3, 2)); + r0_3 = _mm_shuffle_epi32(r0_3, _MM_SHUFFLE(0, 3, 2, 1)); + + r1_1 = _mm_shuffle_epi32(r1_1, _MM_SHUFFLE(2, 1, 0, 3)); + r1_2 = _mm_shuffle_epi32(r1_2, _MM_SHUFFLE(1, 0, 3, 2)); + r1_3 = _mm_shuffle_epi32(r1_3, _MM_SHUFFLE(0, 3, 2, 1)); + + r2_1 = _mm_shuffle_epi32(r2_1, _MM_SHUFFLE(2, 1, 0, 3)); + r2_2 = _mm_shuffle_epi32(r2_2, _MM_SHUFFLE(1, 0, 3, 2)); + r2_3 = _mm_shuffle_epi32(r2_3, _MM_SHUFFLE(0, 3, 2, 1)); + + r3_1 = _mm_shuffle_epi32(r3_1, _MM_SHUFFLE(2, 1, 0, 3)); + r3_2 = _mm_shuffle_epi32(r3_2, _MM_SHUFFLE(1, 0, 3, 2)); + r3_3 = _mm_shuffle_epi32(r3_3, _MM_SHUFFLE(0, 3, 2, 1)); + } + + r0_0 = _mm_add_epi32(r0_0, state0); + r0_1 = _mm_add_epi32(r0_1, state1); + r0_2 = _mm_add_epi32(r0_2, state2); + r0_3 = _mm_add_epi32(r0_3, state3); + + r1_0 = _mm_add_epi32(r1_0, state0); + r1_1 = _mm_add_epi32(r1_1, state1); + r1_2 = _mm_add_epi32(r1_2, state2); + r1_3 = _mm_add_epi32(r1_3, state3); + r1_3 = _mm_add_epi64(r1_3, _mm_set_epi32(0, 0, 0, 1)); + + r2_0 = _mm_add_epi32(r2_0, state0); + r2_1 = _mm_add_epi32(r2_1, state1); + r2_2 = _mm_add_epi32(r2_2, state2); + r2_3 = _mm_add_epi32(r2_3, state3); + r2_3 = _mm_add_epi64(r2_3, _mm_set_epi32(0, 0, 0, 2)); + + r3_0 = _mm_add_epi32(r3_0, state0); + r3_1 = _mm_add_epi32(r3_1, state1); + r3_2 = _mm_add_epi32(r3_2, state2); + r3_3 = _mm_add_epi32(r3_3, state3); + r3_3 = _mm_add_epi64(r3_3, _mm_set_epi32(0, 0, 0, 3)); + + if (input) + { + r0_0 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+0*16)), r0_0); + r0_1 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+1*16)), r0_1); + r0_2 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+2*16)), r0_2); + r0_3 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+3*16)), r0_3); + } + + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+0*16), r0_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+1*16), r0_1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+2*16), r0_2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+3*16), r0_3); + + if (input) + { + r1_0 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+4*16)), r1_0); + r1_1 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+5*16)), r1_1); + r1_2 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+6*16)), r1_2); + r1_3 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+7*16)), r1_3); + } + + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+4*16), r1_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+5*16), r1_1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+6*16), r1_2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+7*16), r1_3); + + if (input) + { + r2_0 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+ 8*16)), r2_0); + r2_1 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+ 9*16)), r2_1); + r2_2 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+10*16)), r2_2); + r2_3 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+11*16)), r2_3); + } + + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+ 8*16), r2_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+ 9*16), r2_1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+10*16), r2_2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+11*16), r2_3); + + if (input) + { + r3_0 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+12*16)), r3_0); + r3_1 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+13*16)), r3_1); + r3_2 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+14*16)), r3_2); + r3_3 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(input+15*16)), r3_3); + } + + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+12*16), r3_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+13*16), r3_1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+14*16), r3_2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(output+15*16), r3_3); +} + +#endif // CRYPTOPP_SSE2_INTRIN_AVAILABLE + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + +// ChaCha_OperateKeystream_CORE will use either POWER7 or ALTIVEC, +// depending on the flags used to compile this source file. The +// abstractions are handled in VecLoad, VecStore and friends. In +// the future we may to provide both POWER7 or ALTIVEC at the same +// time to better support distros. +inline void ChaCha_OperateKeystream_CORE(const word32 *state, const byte* input, byte *output, unsigned int rounds) +{ + const uint32x4_p state0 = VecLoadAligned(state + 0*4); + const uint32x4_p state1 = VecLoadAligned(state + 1*4); + const uint32x4_p state2 = VecLoadAligned(state + 2*4); + const uint32x4_p state3 = VecLoadAligned(state + 3*4); + + const uint32x4_p CTRS[3] = { + {1,0,0,0}, {2,0,0,0}, {3,0,0,0} + }; + + uint32x4_p r0_0 = state0; + uint32x4_p r0_1 = state1; + uint32x4_p r0_2 = state2; + uint32x4_p r0_3 = state3; + + uint32x4_p r1_0 = state0; + uint32x4_p r1_1 = state1; + uint32x4_p r1_2 = state2; + uint32x4_p r1_3 = VecAdd64(r0_3, CTRS[0]); + + uint32x4_p r2_0 = state0; + uint32x4_p r2_1 = state1; + uint32x4_p r2_2 = state2; + uint32x4_p r2_3 = VecAdd64(r0_3, CTRS[1]); + + uint32x4_p r3_0 = state0; + uint32x4_p r3_1 = state1; + uint32x4_p r3_2 = state2; + uint32x4_p r3_3 = VecAdd64(r0_3, CTRS[2]); + + for (int i = static_cast(rounds); i > 0; i -= 2) + { + r0_0 = VecAdd(r0_0, r0_1); + r1_0 = VecAdd(r1_0, r1_1); + r2_0 = VecAdd(r2_0, r2_1); + r3_0 = VecAdd(r3_0, r3_1); + + r0_3 = VecXor(r0_3, r0_0); + r1_3 = VecXor(r1_3, r1_0); + r2_3 = VecXor(r2_3, r2_0); + r3_3 = VecXor(r3_3, r3_0); + + r0_3 = VecRotateLeft<16>(r0_3); + r1_3 = VecRotateLeft<16>(r1_3); + r2_3 = VecRotateLeft<16>(r2_3); + r3_3 = VecRotateLeft<16>(r3_3); + + r0_2 = VecAdd(r0_2, r0_3); + r1_2 = VecAdd(r1_2, r1_3); + r2_2 = VecAdd(r2_2, r2_3); + r3_2 = VecAdd(r3_2, r3_3); + + r0_1 = VecXor(r0_1, r0_2); + r1_1 = VecXor(r1_1, r1_2); + r2_1 = VecXor(r2_1, r2_2); + r3_1 = VecXor(r3_1, r3_2); + + r0_1 = VecRotateLeft<12>(r0_1); + r1_1 = VecRotateLeft<12>(r1_1); + r2_1 = VecRotateLeft<12>(r2_1); + r3_1 = VecRotateLeft<12>(r3_1); + + r0_0 = VecAdd(r0_0, r0_1); + r1_0 = VecAdd(r1_0, r1_1); + r2_0 = VecAdd(r2_0, r2_1); + r3_0 = VecAdd(r3_0, r3_1); + + r0_3 = VecXor(r0_3, r0_0); + r1_3 = VecXor(r1_3, r1_0); + r2_3 = VecXor(r2_3, r2_0); + r3_3 = VecXor(r3_3, r3_0); + + r0_3 = VecRotateLeft<8>(r0_3); + r1_3 = VecRotateLeft<8>(r1_3); + r2_3 = VecRotateLeft<8>(r2_3); + r3_3 = VecRotateLeft<8>(r3_3); + + r0_2 = VecAdd(r0_2, r0_3); + r1_2 = VecAdd(r1_2, r1_3); + r2_2 = VecAdd(r2_2, r2_3); + r3_2 = VecAdd(r3_2, r3_3); + + r0_1 = VecXor(r0_1, r0_2); + r1_1 = VecXor(r1_1, r1_2); + r2_1 = VecXor(r2_1, r2_2); + r3_1 = VecXor(r3_1, r3_2); + + r0_1 = VecRotateLeft<7>(r0_1); + r1_1 = VecRotateLeft<7>(r1_1); + r2_1 = VecRotateLeft<7>(r2_1); + r3_1 = VecRotateLeft<7>(r3_1); + + r0_1 = Shuffle<1>(r0_1); + r0_2 = Shuffle<2>(r0_2); + r0_3 = Shuffle<3>(r0_3); + + r1_1 = Shuffle<1>(r1_1); + r1_2 = Shuffle<2>(r1_2); + r1_3 = Shuffle<3>(r1_3); + + r2_1 = Shuffle<1>(r2_1); + r2_2 = Shuffle<2>(r2_2); + r2_3 = Shuffle<3>(r2_3); + + r3_1 = Shuffle<1>(r3_1); + r3_2 = Shuffle<2>(r3_2); + r3_3 = Shuffle<3>(r3_3); + + r0_0 = VecAdd(r0_0, r0_1); + r1_0 = VecAdd(r1_0, r1_1); + r2_0 = VecAdd(r2_0, r2_1); + r3_0 = VecAdd(r3_0, r3_1); + + r0_3 = VecXor(r0_3, r0_0); + r1_3 = VecXor(r1_3, r1_0); + r2_3 = VecXor(r2_3, r2_0); + r3_3 = VecXor(r3_3, r3_0); + + r0_3 = VecRotateLeft<16>(r0_3); + r1_3 = VecRotateLeft<16>(r1_3); + r2_3 = VecRotateLeft<16>(r2_3); + r3_3 = VecRotateLeft<16>(r3_3); + + r0_2 = VecAdd(r0_2, r0_3); + r1_2 = VecAdd(r1_2, r1_3); + r2_2 = VecAdd(r2_2, r2_3); + r3_2 = VecAdd(r3_2, r3_3); + + r0_1 = VecXor(r0_1, r0_2); + r1_1 = VecXor(r1_1, r1_2); + r2_1 = VecXor(r2_1, r2_2); + r3_1 = VecXor(r3_1, r3_2); + + r0_1 = VecRotateLeft<12>(r0_1); + r1_1 = VecRotateLeft<12>(r1_1); + r2_1 = VecRotateLeft<12>(r2_1); + r3_1 = VecRotateLeft<12>(r3_1); + + r0_0 = VecAdd(r0_0, r0_1); + r1_0 = VecAdd(r1_0, r1_1); + r2_0 = VecAdd(r2_0, r2_1); + r3_0 = VecAdd(r3_0, r3_1); + + r0_3 = VecXor(r0_3, r0_0); + r1_3 = VecXor(r1_3, r1_0); + r2_3 = VecXor(r2_3, r2_0); + r3_3 = VecXor(r3_3, r3_0); + + r0_3 = VecRotateLeft<8>(r0_3); + r1_3 = VecRotateLeft<8>(r1_3); + r2_3 = VecRotateLeft<8>(r2_3); + r3_3 = VecRotateLeft<8>(r3_3); + + r0_2 = VecAdd(r0_2, r0_3); + r1_2 = VecAdd(r1_2, r1_3); + r2_2 = VecAdd(r2_2, r2_3); + r3_2 = VecAdd(r3_2, r3_3); + + r0_1 = VecXor(r0_1, r0_2); + r1_1 = VecXor(r1_1, r1_2); + r2_1 = VecXor(r2_1, r2_2); + r3_1 = VecXor(r3_1, r3_2); + + r0_1 = VecRotateLeft<7>(r0_1); + r1_1 = VecRotateLeft<7>(r1_1); + r2_1 = VecRotateLeft<7>(r2_1); + r3_1 = VecRotateLeft<7>(r3_1); + + r0_1 = Shuffle<3>(r0_1); + r0_2 = Shuffle<2>(r0_2); + r0_3 = Shuffle<1>(r0_3); + + r1_1 = Shuffle<3>(r1_1); + r1_2 = Shuffle<2>(r1_2); + r1_3 = Shuffle<1>(r1_3); + + r2_1 = Shuffle<3>(r2_1); + r2_2 = Shuffle<2>(r2_2); + r2_3 = Shuffle<1>(r2_3); + + r3_1 = Shuffle<3>(r3_1); + r3_2 = Shuffle<2>(r3_2); + r3_3 = Shuffle<1>(r3_3); + } + + r0_0 = VecAdd(r0_0, state0); + r0_1 = VecAdd(r0_1, state1); + r0_2 = VecAdd(r0_2, state2); + r0_3 = VecAdd(r0_3, state3); + + r1_0 = VecAdd(r1_0, state0); + r1_1 = VecAdd(r1_1, state1); + r1_2 = VecAdd(r1_2, state2); + r1_3 = VecAdd(r1_3, state3); + r1_3 = VecAdd64(r1_3, CTRS[0]); + + r2_0 = VecAdd(r2_0, state0); + r2_1 = VecAdd(r2_1, state1); + r2_2 = VecAdd(r2_2, state2); + r2_3 = VecAdd(r2_3, state3); + r2_3 = VecAdd64(r2_3, CTRS[1]); + + r3_0 = VecAdd(r3_0, state0); + r3_1 = VecAdd(r3_1, state1); + r3_2 = VecAdd(r3_2, state2); + r3_3 = VecAdd(r3_3, state3); + r3_3 = VecAdd64(r3_3, CTRS[2]); + + if (input) + { + r0_0 = VecXor(VecLoad32LE(input + 0*16), r0_0); + r0_1 = VecXor(VecLoad32LE(input + 1*16), r0_1); + r0_2 = VecXor(VecLoad32LE(input + 2*16), r0_2); + r0_3 = VecXor(VecLoad32LE(input + 3*16), r0_3); + } + + VecStore32LE(output + 0*16, r0_0); + VecStore32LE(output + 1*16, r0_1); + VecStore32LE(output + 2*16, r0_2); + VecStore32LE(output + 3*16, r0_3); + + if (input) + { + r1_0 = VecXor(VecLoad32LE(input + 4*16), r1_0); + r1_1 = VecXor(VecLoad32LE(input + 5*16), r1_1); + r1_2 = VecXor(VecLoad32LE(input + 6*16), r1_2); + r1_3 = VecXor(VecLoad32LE(input + 7*16), r1_3); + } + + VecStore32LE(output + 4*16, r1_0); + VecStore32LE(output + 5*16, r1_1); + VecStore32LE(output + 6*16, r1_2); + VecStore32LE(output + 7*16, r1_3); + + if (input) + { + r2_0 = VecXor(VecLoad32LE(input + 8*16), r2_0); + r2_1 = VecXor(VecLoad32LE(input + 9*16), r2_1); + r2_2 = VecXor(VecLoad32LE(input + 10*16), r2_2); + r2_3 = VecXor(VecLoad32LE(input + 11*16), r2_3); + } + + VecStore32LE(output + 8*16, r2_0); + VecStore32LE(output + 9*16, r2_1); + VecStore32LE(output + 10*16, r2_2); + VecStore32LE(output + 11*16, r2_3); + + if (input) + { + r3_0 = VecXor(VecLoad32LE(input + 12*16), r3_0); + r3_1 = VecXor(VecLoad32LE(input + 13*16), r3_1); + r3_2 = VecXor(VecLoad32LE(input + 14*16), r3_2); + r3_3 = VecXor(VecLoad32LE(input + 15*16), r3_3); + } + + VecStore32LE(output + 12*16, r3_0); + VecStore32LE(output + 13*16, r3_1); + VecStore32LE(output + 14*16, r3_2); + VecStore32LE(output + 15*16, r3_3); +} + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + +void ChaCha_OperateKeystream_ALTIVEC(const word32 *state, const byte* input, byte *output, unsigned int rounds) +{ + ChaCha_OperateKeystream_CORE(state, input, output, rounds); +} + +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/chachapoly.cpp b/extension/third_party/cryptopp/chachapoly.cpp new file mode 100644 index 00000000..93474060 --- /dev/null +++ b/extension/third_party/cryptopp/chachapoly.cpp @@ -0,0 +1,211 @@ +// chachapoly.cpp - written and placed in the public domain by Jeffrey Walton +// RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc8439 + +#include "pch.h" +#include "chachapoly.h" +#include "algparam.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was +// predicated on BlockCiphers, where the key and key schedule could be +// calculated independent of the IV being used. However, the ChaCha and +// ChaCha20Poly1305 construction combines key setup and IV. That is, both are +// needed to key or rekey the cipher. Even a simple Resync() requires us to +// regenerate the initial state for both ChaCha20 and Poly1305. +void ChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + // Derive MAC key + AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true); + AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0)); + + // Only the first 256-bits are used to key the MAC + SecByteBlock derived(NULLPTR, 32); + AccessSymmetricCipher().ProcessString(derived, derived.size()); + + // Key the Poly1305 MAC + AccessMAC().SetKey(derived, derived.size(), params); + + // Key the ChaCha20 cipher + AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true); + AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1)); +} + +void ChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(userKey && userKeyLength == 32); + m_userKey.Assign(userKey, userKeyLength); + + // ChaCha/Poly1305 initial state depends on both the key and IV. The + // IV may or may not be present during the call to SetKeyWithoutResync. + // If the IV is present, the framework will call SetKeyWithoutResync + // followed by Resynchronize which calls Resync. In this case we defer + // calculating the initial state until the call to Resynchronize. + // If the IV is not present, it avoids calling ChaCha's SetKey without + // an IV, which results in an exception. In this case the user will need + // to call Resynchronize to key ChaCha and Poly1305. + // RekeyCipherAndMac(userKey, userKeyLength, params); + CRYPTOPP_UNUSED(params); +} + +void ChaCha20Poly1305_Base::Resync(const byte *iv, size_t len) +{ + CRYPTOPP_ASSERT(iv && len == 12); + RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(), + MakeParameters(Name::IV(), ConstByteArrayParameter(iv,len))); +} + +size_t ChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len) +{ + AccessMAC().Update(data, len); + return 0; +} + +void ChaCha20Poly1305_Base::AuthenticateLastHeaderBlock() +{ + // Pad to a multiple of 16 or 0 + const byte zero[16] = {0}; + size_t pad = (16U - (m_totalHeaderLength % 16)) % 16; + AccessMAC().Update(zero, pad); +} + +void ChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock() +{ + // Pad to a multiple of 16 or 0 + const byte zero[16] = {0}; + size_t pad = (16U - (m_totalMessageLength % 16)) % 16; + AccessMAC().Update(zero, pad); +} + +void ChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) +{ + CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)]; + PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength); + PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength); + AccessMAC().Update(length, sizeof(length)); + AccessMAC().TruncatedFinal(mac, macSize); + m_state = State_KeySet; +} + +void ChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength) +{ + Resynchronize(iv, ivLength); + Update(aad, aadLength); + ProcessString(ciphertext, message, messageLength); + TruncatedFinal(mac, macSize); +} + +bool ChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength) +{ + Resynchronize(iv, ivLength); + Update(aad, aadLength); + ProcessString(message, ciphertext, ciphertextLength); + return TruncatedVerify(mac, macLength); +} + +////////////////////////////// IETF XChaCha20 draft ////////////////////////////// + +// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was +// predicated on BlockCiphers, where the key and key schedule could be +// calculated independent of the IV being used. However, the ChaCha and +// ChaCha20Poly1305 construction combines key setup and IV. That is, both are +// needed to key or rekey the cipher. Even a simple Resync() requires us to +// regenerate the initial state for both ChaCha20 and Poly1305. +void XChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + // Derive MAC key + AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true); + AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0)); + + // Only the first 256-bits are used to key the MAC + SecByteBlock derived(NULLPTR, 32); + AccessSymmetricCipher().ProcessString(derived, derived.size()); + + // Key the Poly1305 MAC + AccessMAC().SetKey(derived, derived.size(), params); + + // Key the ChaCha20 cipher + AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true); + AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1)); +} + +void XChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(userKey && userKeyLength == 32); + m_userKey.Assign(userKey, userKeyLength); + + // XChaCha20/Poly1305 initial state depends on both the key and IV. The + // IV may or may not be present during the call to SetKeyWithoutResync. + // If the IV is present, the framework will call SetKeyWithoutResync + // followed by Resynchronize which calls Resync. In this case we defer + // calculating the initial state until the call to Resynchronize. + // If the IV is not present, it avoids calling ChaCha's SetKey without + // an IV, which results in an exception. In this case the user will need + // to call Resynchronize to key ChaCha and Poly1305. + // RekeyCipherAndMac(userKey, userKeyLength, params); + CRYPTOPP_UNUSED(params); +} + +void XChaCha20Poly1305_Base::Resync(const byte *iv, size_t len) +{ + CRYPTOPP_ASSERT(iv && len == 24); + RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(), + MakeParameters(Name::IV(), ConstByteArrayParameter(iv,len))); +} + +size_t XChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len) +{ + AccessMAC().Update(data, len); + return 0; +} + +void XChaCha20Poly1305_Base::AuthenticateLastHeaderBlock() +{ + // Pad to a multiple of 16 or 0 + const byte zero[16] = {0}; + size_t pad = (16 - (m_totalHeaderLength % 16)) % 16; + AccessMAC().Update(zero, pad); +} + +void XChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock() +{ + // Pad to a multiple of 16 or 0 + const byte zero[16] = {0}; + size_t pad = (16 - (m_totalMessageLength % 16)) % 16; + AccessMAC().Update(zero, pad); +} + +void XChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) +{ + CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)]; + PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength); + PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength); + AccessMAC().Update(length, sizeof(length)); + AccessMAC().TruncatedFinal(mac, macSize); + m_state = State_KeySet; +} + +void XChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength) +{ + Resynchronize(iv, ivLength); + Update(aad, aadLength); + ProcessString(ciphertext, message, messageLength); + TruncatedFinal(mac, macSize); +} + +bool XChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength) +{ + Resynchronize(iv, ivLength); + Update(aad, aadLength); + ProcessString(message, ciphertext, ciphertextLength); + return TruncatedVerify(mac, macLength); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/chachapoly.h b/extension/third_party/cryptopp/chachapoly.h new file mode 100644 index 00000000..e480456d --- /dev/null +++ b/extension/third_party/cryptopp/chachapoly.h @@ -0,0 +1,322 @@ +// chachapoly.h - written and placed in the public domain by Jeffrey Walton +// RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc8439 + +/// \file chachapoly.h +/// \brief IETF ChaCha20/Poly1305 AEAD scheme +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 + +#ifndef CRYPTOPP_CHACHA_POLY1305_H +#define CRYPTOPP_CHACHA_POLY1305_H + +#include "cryptlib.h" +#include "authenc.h" +#include "chacha.h" +#include "poly1305.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +/// \brief IETF ChaCha20Poly1305 cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 8.1 +class ChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "ChaCha20/Poly1305";} + + virtual ~ChaCha20Poly1305_Base() {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return std::string("ChaCha20/Poly1305");} + std::string AlgorithmProvider() const + {return GetSymmetricCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return 32;} + size_t MaxKeyLength() const + {return 32;} + size_t DefaultKeyLength() const + {return 32;} + size_t GetValidKeyLength(size_t n) const + {CRYPTOPP_UNUSED(n); return 32;} + bool IsValidKeyLength(size_t n) const + {return n==32;} + unsigned int OptimalDataAlignment() const + {return GetSymmetricCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 12;} + unsigned int MinIVLength() const + {return 12;} + unsigned int MaxIVLength() const + {return 12;} + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return LWORD_MAX;} // 2^64-1 bytes + lword MaxMessageLength() const + {return W64LIT(274877906880);} // 2^38-1 blocks + lword MaxFooterLength() const + {return 0;} + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param ciphertext the cipher buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const {return false;} + unsigned int AuthenticationBlockSize() const {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + + // See comments in chachapoly.cpp + void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms); + + virtual const MessageAuthenticationCode & GetMAC() const = 0; + virtual MessageAuthenticationCode & AccessMAC() = 0; + +private: + SecByteBlock m_userKey; +}; + +/// \brief IETF ChaCha20Poly1305 cipher final implementation +/// \tparam T_IsEncryption flag indicating cipher direction +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +template +class ChaCha20Poly1305_Final : public ChaCha20Poly1305_Base +{ +public: + virtual ~ChaCha20Poly1305_Final() {} + +protected: + const SymmetricCipher & GetSymmetricCipher() + {return const_cast(this)->AccessSymmetricCipher();} + SymmetricCipher & AccessSymmetricCipher() + {return m_cipher;} + bool IsForwardTransformation() const + {return T_IsEncryption;} + + const MessageAuthenticationCode & GetMAC() const + {return const_cast(this)->AccessMAC();} + MessageAuthenticationCode & AccessMAC() + {return m_mac;} + +private: + ChaChaTLS::Encryption m_cipher; + Poly1305TLS m_mac; +}; + +/// \brief IETF ChaCha20/Poly1305 AEAD scheme +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +struct ChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation +{ + /// \brief ChaCha20Poly1305 encryption + typedef ChaCha20Poly1305_Final Encryption; + /// \brief ChaCha20Poly1305 decryption + typedef ChaCha20Poly1305_Final Decryption; +}; + +////////////////////////////// IETF XChaCha20 draft ////////////////////////////// + +/// \brief IETF XChaCha20Poly1305 cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 8.1 +class XChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "XChaCha20/Poly1305";} + + virtual ~XChaCha20Poly1305_Base() {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return std::string("XChaCha20/Poly1305");} + std::string AlgorithmProvider() const + {return GetSymmetricCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return 32;} + size_t MaxKeyLength() const + {return 32;} + size_t DefaultKeyLength() const + {return 32;} + size_t GetValidKeyLength(size_t n) const + {CRYPTOPP_UNUSED(n); return 32;} + bool IsValidKeyLength(size_t n) const + {return n==32;} + unsigned int OptimalDataAlignment() const + {return GetSymmetricCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 24;} + unsigned int MinIVLength() const + {return 24;} + unsigned int MaxIVLength() const + {return 24;} + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return LWORD_MAX;} // 2^64-1 bytes + lword MaxMessageLength() const + {return W64LIT(274877906880);} // 2^38-1 blocks + lword MaxFooterLength() const + {return 0;} + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param ciphertext the cipher buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const {return false;} + unsigned int AuthenticationBlockSize() const {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + + // See comments in chachapoly.cpp + void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms); + + virtual const MessageAuthenticationCode & GetMAC() const = 0; + virtual MessageAuthenticationCode & AccessMAC() = 0; + +private: + SecByteBlock m_userKey; +}; + +/// \brief IETF XChaCha20Poly1305 cipher final implementation +/// \tparam T_IsEncryption flag indicating cipher direction +/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines +/// XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +template +class XChaCha20Poly1305_Final : public XChaCha20Poly1305_Base +{ +public: + virtual ~XChaCha20Poly1305_Final() {} + +protected: + const SymmetricCipher & GetSymmetricCipher() + {return const_cast(this)->AccessSymmetricCipher();} + SymmetricCipher & AccessSymmetricCipher() + {return m_cipher;} + bool IsForwardTransformation() const + {return T_IsEncryption;} + + const MessageAuthenticationCode & GetMAC() const + {return const_cast(this)->AccessMAC();} + MessageAuthenticationCode & AccessMAC() + {return m_mac;} + +private: + XChaCha20::Encryption m_cipher; + Poly1305TLS m_mac; +}; + +/// \brief IETF XChaCha20/Poly1305 AEAD scheme +/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines +/// XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_XCHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +struct XChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation +{ + /// \brief XChaCha20Poly1305 encryption + typedef XChaCha20Poly1305_Final Encryption; + /// \brief XChaCha20Poly1305 decryption + typedef XChaCha20Poly1305_Final Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_CHACHA_POLY1305_H diff --git a/extension/third_party/cryptopp/cham.cpp b/extension/third_party/cryptopp/cham.cpp new file mode 100644 index 00000000..8a24a975 --- /dev/null +++ b/extension/third_party/cryptopp/cham.cpp @@ -0,0 +1,365 @@ +// cham.cpp - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "CHAM: A Family of Lightweight Block Ciphers for +// Resource-Constrained Devices" by Bonwook Koo, Dongyoung Roh, +// Hyeonjin Kim, Younghoon Jung, Dong-Geon Lee, and Daesung Kwon + +#include "pch.h" +#include "config.h" + +#include "cham.h" +#include "misc.h" +#include "cpu.h" + +// CHAM table of parameters +// +------------------------------------------------- +// +cipher n k r w k/w +// +------------------------------------------------- +// +CHAM-64/128 64 128 80 16 8 +// +CHAM-128/128 128 128 80 32 4 +// +CHAM-128/256 128 256 96 32 8 +// +------------------------------------------------- + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::rotlConstant; +using CryptoPP::rotrConstant; + +/// \brief CHAM encryption round +/// \tparam RR the round number residue +/// \tparam KW the number of key words +/// \tparam T words type +/// \param x the state array +/// \param k the subkey table +/// \param i the round number +/// \details CHAM_EncRound applies the encryption round to the plain text. +/// RR is the "round residue" and it is used modulo 4. ProcessAndXorBlock +/// may provide a fully unrolled encryption transformation, or provide +/// a transformation that loops using multiples of 4 encryption rounds. +/// \details CHAM_EncRound calculates indexes into the x[] array based +/// on the round number residue. There is no need for the assignments +/// that shift values in preparations for the next round. +/// \details CHAM_EncRound depends on the round number. The actual round +/// being executed is passed through the parameter i. If +/// ProcessAndXorBlock fully unrolled the loop then the parameter +/// i would be unnecessary. +template +inline void CHAM_EncRound(T x[4], const T k[KW], unsigned int i) +{ + CRYPTOPP_CONSTANT(IDX0 = (RR+0) % 4); + CRYPTOPP_CONSTANT(IDX1 = (RR+1) % 4); + CRYPTOPP_CONSTANT(IDX3 = (RR+3+1) % 4); + CRYPTOPP_CONSTANT(R1 = (RR % 2 == 0) ? 1 : 8); + CRYPTOPP_CONSTANT(R2 = (RR % 2 == 0) ? 8 : 1); + + // Follows conventions in the ref impl + const T kk = k[i % KW]; + const T aa = x[IDX0] ^ static_cast(i); + const T bb = rotlConstant(x[IDX1]) ^ kk; + x[IDX3] = rotlConstant(static_cast(aa + bb)); +} + +/// \brief CHAM decryption round +/// \tparam RR the round number residue +/// \tparam KW the number of key words +/// \tparam T words type +/// \param x the state array +/// \param k the subkey table +/// \param i the round number +/// \details CHAM_DecRound applies the decryption round to the cipher text. +/// RR is the "round residue" and it is used modulo 4. ProcessAndXorBlock +/// may provide a fully unrolled decryption transformation, or provide +/// a transformation that loops using multiples of 4 decryption rounds. +/// \details CHAM_DecRound calculates indexes into the x[] array based +/// on the round number residue. There is no need for the assignments +/// that shift values in preparations for the next round. +/// \details CHAM_DecRound depends on the round number. The actual round +/// being executed is passed through the parameter i. If +/// ProcessAndXorBlock fully unrolled the loop then the parameter +/// i would be unnecessary. +template +inline void CHAM_DecRound(T x[4], const T k[KW], unsigned int i) +{ + CRYPTOPP_CONSTANT(IDX0 = (RR+0) % 4); + CRYPTOPP_CONSTANT(IDX1 = (RR+1) % 4); + CRYPTOPP_CONSTANT(IDX3 = (RR+3+1) % 4); + CRYPTOPP_CONSTANT(R1 = (RR % 2 == 0) ? 8 : 1); + CRYPTOPP_CONSTANT(R2 = (RR % 2 == 0) ? 1 : 8); + + // Follows conventions in the ref impl + const T kk = k[i % KW]; + const T aa = rotrConstant(x[IDX3]); + const T bb = rotlConstant(x[IDX1]) ^ kk; + x[IDX0] = static_cast(aa - bb) ^ static_cast(i); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS +# if (CRYPTOPP_SSSE3_AVAILABLE) +extern size_t CHAM64_Enc_AdvancedProcessBlocks_SSSE3(const word16* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t CHAM64_Dec_AdvancedProcessBlocks_SSSE3(const word16* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t CHAM128_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t CHAM128_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +# endif // CRYPTOPP_SSSE3_AVAILABLE +#endif // CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + +void CHAM64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + m_kw = keyLength/sizeof(word16); + m_rk.New(2*m_kw); + + for (size_t i = 0; i < m_kw; userKey += sizeof(word32)) + { + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + const word32 rk = GetWord(false, BIG_ENDIAN_ORDER, userKey); + + const word16 rk1 = rk >> 16; + m_rk[i] = rk1 ^ rotlConstant<1>(rk1) ^ rotlConstant<8>(rk1); + m_rk[(i + m_kw) ^ 1] = rk1 ^ rotlConstant<1>(rk1) ^ rotlConstant<11>(rk1); + i++; + + const word16 rk2 = rk & 0xffff; + m_rk[i] = rk2 ^ rotlConstant<1>(rk2) ^ rotlConstant<8>(rk2); + m_rk[(i + m_kw) ^ 1] = rk2 ^ rotlConstant<1>(rk2) ^ rotlConstant<11>(rk2); + i++; + } +} + +void CHAM64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); + + const int R = 80; + for (int i = 0; i < R; i+=16) + { + CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0); + CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1); + CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2); + CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3); + CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4); + CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5); + CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6); + CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7); + CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8); + CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9); + CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10); + CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11); + CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12); + CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13); + CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14); + CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15); + } + + PutBlock oblock(xorBlock, outBlock); + oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); +} + +void CHAM64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); + + const int R = 80; + for (int i = R-1; i >=0 ; i-=16) + { + CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0); + CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1); + CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2); + CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3); + CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4); + CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5); + CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6); + CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7); + CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8); + CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9); + CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10); + CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11); + CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12); + CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13); + CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14); + CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15); + } + + PutBlock oblock(xorBlock, outBlock); + oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); +} + +std::string CHAM128::Base::AlgorithmProvider() const +{ +#if defined(CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return "SSSE3"; +#endif + return "C++"; +} + +void CHAM128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + m_kw = keyLength/sizeof(word32); + m_rk.New(2*m_kw); + + for (size_t i = 0; i < m_kw; userKey += sizeof(word32)) + { + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + const word32 rk = GetWord(false, BIG_ENDIAN_ORDER, userKey); + m_rk[i] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<8>(rk); + m_rk[(i + m_kw) ^ 1] = rk ^ rotlConstant<1>(rk) ^ rotlConstant<11>(rk); + i++; + } +} + +void CHAM128::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); + + switch (m_kw) + { + case 4: // 128-bit key + { + const int R = 80; + for (int i = 0; i < R; i+=8) + { + CHAM_EncRound<0, 8>(m_x.begin(), m_rk.begin(), i+0); + CHAM_EncRound<1, 8>(m_x.begin(), m_rk.begin(), i+1); + CHAM_EncRound<2, 8>(m_x.begin(), m_rk.begin(), i+2); + CHAM_EncRound<3, 8>(m_x.begin(), m_rk.begin(), i+3); + CHAM_EncRound<4, 8>(m_x.begin(), m_rk.begin(), i+4); + CHAM_EncRound<5, 8>(m_x.begin(), m_rk.begin(), i+5); + CHAM_EncRound<6, 8>(m_x.begin(), m_rk.begin(), i+6); + CHAM_EncRound<7, 8>(m_x.begin(), m_rk.begin(), i+7); + } + break; + } + case 8: // 256-bit key + { + const int R = 96; + for (int i = 0; i < R; i+=16) + { + CHAM_EncRound< 0, 16>(m_x.begin(), m_rk.begin(), i+0); + CHAM_EncRound< 1, 16>(m_x.begin(), m_rk.begin(), i+1); + CHAM_EncRound< 2, 16>(m_x.begin(), m_rk.begin(), i+2); + CHAM_EncRound< 3, 16>(m_x.begin(), m_rk.begin(), i+3); + CHAM_EncRound< 4, 16>(m_x.begin(), m_rk.begin(), i+4); + CHAM_EncRound< 5, 16>(m_x.begin(), m_rk.begin(), i+5); + CHAM_EncRound< 6, 16>(m_x.begin(), m_rk.begin(), i+6); + CHAM_EncRound< 7, 16>(m_x.begin(), m_rk.begin(), i+7); + CHAM_EncRound< 8, 16>(m_x.begin(), m_rk.begin(), i+8); + CHAM_EncRound< 9, 16>(m_x.begin(), m_rk.begin(), i+9); + CHAM_EncRound<10, 16>(m_x.begin(), m_rk.begin(), i+10); + CHAM_EncRound<11, 16>(m_x.begin(), m_rk.begin(), i+11); + CHAM_EncRound<12, 16>(m_x.begin(), m_rk.begin(), i+12); + CHAM_EncRound<13, 16>(m_x.begin(), m_rk.begin(), i+13); + CHAM_EncRound<14, 16>(m_x.begin(), m_rk.begin(), i+14); + CHAM_EncRound<15, 16>(m_x.begin(), m_rk.begin(), i+15); + } + break; + } + default: + CRYPTOPP_ASSERT(0); + } + + PutBlock oblock(xorBlock, outBlock); + oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); +} + +void CHAM128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); + + switch (m_kw) + { + case 4: // 128-bit key + { + const int R = 80; + for (int i = R-1; i >= 0; i-=8) + { + CHAM_DecRound<7, 8>(m_x.begin(), m_rk.begin(), i-0); + CHAM_DecRound<6, 8>(m_x.begin(), m_rk.begin(), i-1); + CHAM_DecRound<5, 8>(m_x.begin(), m_rk.begin(), i-2); + CHAM_DecRound<4, 8>(m_x.begin(), m_rk.begin(), i-3); + CHAM_DecRound<3, 8>(m_x.begin(), m_rk.begin(), i-4); + CHAM_DecRound<2, 8>(m_x.begin(), m_rk.begin(), i-5); + CHAM_DecRound<1, 8>(m_x.begin(), m_rk.begin(), i-6); + CHAM_DecRound<0, 8>(m_x.begin(), m_rk.begin(), i-7); + } + break; + } + case 8: // 256-bit key + { + const int R = 96; + for (int i = R-1; i >= 0; i-=16) + { + CHAM_DecRound<15, 16>(m_x.begin(), m_rk.begin(), i-0); + CHAM_DecRound<14, 16>(m_x.begin(), m_rk.begin(), i-1); + CHAM_DecRound<13, 16>(m_x.begin(), m_rk.begin(), i-2); + CHAM_DecRound<12, 16>(m_x.begin(), m_rk.begin(), i-3); + CHAM_DecRound<11, 16>(m_x.begin(), m_rk.begin(), i-4); + CHAM_DecRound<10, 16>(m_x.begin(), m_rk.begin(), i-5); + CHAM_DecRound< 9, 16>(m_x.begin(), m_rk.begin(), i-6); + CHAM_DecRound< 8, 16>(m_x.begin(), m_rk.begin(), i-7); + CHAM_DecRound< 7, 16>(m_x.begin(), m_rk.begin(), i-8); + CHAM_DecRound< 6, 16>(m_x.begin(), m_rk.begin(), i-9); + CHAM_DecRound< 5, 16>(m_x.begin(), m_rk.begin(), i-10); + CHAM_DecRound< 4, 16>(m_x.begin(), m_rk.begin(), i-11); + CHAM_DecRound< 3, 16>(m_x.begin(), m_rk.begin(), i-12); + CHAM_DecRound< 2, 16>(m_x.begin(), m_rk.begin(), i-13); + CHAM_DecRound< 1, 16>(m_x.begin(), m_rk.begin(), i-14); + CHAM_DecRound< 0, 16>(m_x.begin(), m_rk.begin(), i-15); + } + break; + } + default: + CRYPTOPP_ASSERT(0); + } + + PutBlock oblock(xorBlock, outBlock); + oblock(m_x[0])(m_x[1])(m_x[2])(m_x[3]); +} + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS +size_t CHAM128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + const size_t rounds = (m_kw == 4 ? 80 : 96); + return CHAM128_Enc_AdvancedProcessBlocks_SSSE3(m_rk, rounds, + inBlocks, xorBlocks, outBlocks, length, flags); + } +# endif // CRYPTOPP_SSSE3_AVAILABLE + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t CHAM128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + const size_t rounds = (m_kw == 4 ? 80 : 96); + return CHAM128_Dec_AdvancedProcessBlocks_SSSE3(m_rk, rounds, + inBlocks, xorBlocks, outBlocks, length, flags); + } +# endif // CRYPTOPP_SSSE3_AVAILABLE + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/cham.h b/extension/third_party/cryptopp/cham.h new file mode 100644 index 00000000..5100dd45 --- /dev/null +++ b/extension/third_party/cryptopp/cham.h @@ -0,0 +1,179 @@ +// cham.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "CHAM: A Family of Lightweight Block Ciphers for +// Resource-Constrained Devices" by Bonwook Koo, Dongyoung Roh, +// Hyeonjin Kim, Younghoon Jung, Dong-Geon Lee, and Daesung Kwon + +/// \file cham.h +/// \brief Classes for the CHAM block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_CHAM_H +#define CRYPTOPP_CHAM_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) +# define CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS 1 +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CHAM block cipher information +/// \since Crypto++ 8.0 +struct CHAM64_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "CHAM-64"; + } +}; + +/// \brief CHAM block cipher information +/// \since Crypto++ 8.0 +struct CHAM128_Info : public FixedBlockSize<16>, public VariableKeyLength<16,16,32,16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "CHAM-128"; + } +}; + +/// \brief CHAM 64-bit block cipher +/// \details CHAM64 provides 64-bit block size. The valid key size is 128-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa CHAM128, CHAM, +/// +/// CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE CHAM64 : public CHAM64_Info, public BlockCipherDocumentation +{ +public: + /// \brief CHAM block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + SecBlock m_rk; + mutable FixedSizeSecBlock m_x; + unsigned int m_kw; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief CHAM64 encryption + typedef BlockCipherFinal Encryption; + /// \brief CHAM64 decryption + typedef BlockCipherFinal Decryption; +}; + +/// \brief CHAM64 encryption +typedef CHAM64::Encryption CHAM64Encryption; +/// \brief CHAM64 decryption +typedef CHAM64::Decryption CHAM64Decryption; + +/// \brief CHAM 128-bit block cipher +/// \details CHAM128 provides 128-bit block size. The valid key size is 128-bit and 256-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa CHAM64, CHAM, +/// +/// CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE CHAM128 : public CHAM128_Info, public BlockCipherDocumentation +{ +public: + /// \brief CHAM block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + SecBlock m_rk; + mutable FixedSizeSecBlock m_x; + unsigned int m_kw; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief CHAM128 encryption + typedef BlockCipherFinal Encryption; + /// \brief CHAM128 decryption + typedef BlockCipherFinal Decryption; +}; + +/// \brief CHAM128 encryption +typedef CHAM128::Encryption CHAM128Encryption; +/// \brief CHAM128 decryption +typedef CHAM128::Decryption CHAM128Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_CHAM_H diff --git a/extension/third_party/cryptopp/cham_simd.cpp b/extension/third_party/cryptopp/cham_simd.cpp new file mode 100644 index 00000000..b848ba10 --- /dev/null +++ b/extension/third_party/cryptopp/cham_simd.cpp @@ -0,0 +1,478 @@ +// cham_simd.cpp - written and placed in the public domain by Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSSE3, ARM NEON and ARMv8a, and Power7 Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#include "cham.h" +#include "misc.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both simon.cpp and simon_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) +#include "adv_simd.h" +# include +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define DOUBLE_CAST(x) ((double*)(void*)(x)) +#define CONST_DOUBLE_CAST(x) ((const double*)(const void*)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char CHAM_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word16; +using CryptoPP::word32; + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +////////////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(W32) // CHAM128, 32-bit word size + +template +inline __m128i RotateLeft32(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, R), _mm_srli_epi32(val, 32-R)); +#endif +} + +template +inline __m128i RotateRight32(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 32-R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, 32-R), _mm_srli_epi32(val, R)); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline __m128i RotateLeft32<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 8); +#else + const __m128i mask = _mm_set_epi8(14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3); + return _mm_shuffle_epi8(val, mask); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline __m128i RotateRight32<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 32-8); +#else + const __m128i mask = _mm_set_epi8(12,15,14,13, 8,11,10,9, 4,7,6,5, 0,3,2,1); + return _mm_shuffle_epi8(val, mask); +#endif +} + +template +inline __m128i UnpackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + CRYPTOPP_UNUSED(c); CRYPTOPP_UNUSED(d); + CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // CHAM implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpacklo_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // CHAM implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpackhi_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // CHAM implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpacklo_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // The shuffle converts to and from little-endian for SSE. A specialized + // CHAM implementation can avoid the shuffle by framing the data for + // encryption, decryption and benchmarks. The library cannot take the + // speed-up because of the byte oriented API. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_shuffle_epi8(_mm_unpackhi_epi64(r1, r2), + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3)); +} + +template +inline __m128i UnpackXMM(const __m128i& v) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(v); CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(4,5,6,7, 4,5,6,7, 4,5,6,7, 4,5,6,7)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(8,9,10,11, 8,9,10,11, 8,9,10,11, 8,9,10,11)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& v) +{ + return _mm_shuffle_epi8(v, _mm_set_epi8(12,13,14,15, 12,13,14,15, 12,13,14,15, 12,13,14,15)); +} + +template +inline __m128i RepackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + return UnpackXMM(a, b, c, d); +} + +template +inline __m128i RepackXMM(const __m128i& v) +{ + return UnpackXMM(v); +} + +inline void CHAM128_Enc_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0); + __m128i b = UnpackXMM<1>(block0); + __m128i c = UnpackXMM<2>(block0); + __m128i d = UnpackXMM<3>(block0); + + __m128i counter = _mm_set_epi32(0,0,0,0); + __m128i increment = _mm_set_epi32(1,1,1,1); + + const unsigned int MASK = (rounds == 80 ? 7 : 15); + for (int i=0; i(rounds); i+=4) + { + __m128i k, k1, k2, t1, t2; + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i+0) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + + t1 = _mm_xor_si128(a, counter); + t2 = _mm_xor_si128(RotateLeft32<1>(b), k1); + a = RotateLeft32<8>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + + t1 = _mm_xor_si128(b, counter); + t2 = _mm_xor_si128(RotateLeft32<8>(c), k2); + b = RotateLeft32<1>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i+2) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + + t1 = _mm_xor_si128(c, counter); + t2 = _mm_xor_si128(RotateLeft32<1>(d), k1); + c = RotateLeft32<8>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + + t1 = _mm_xor_si128(d, counter); + t2 = _mm_xor_si128(RotateLeft32<8>(a), k2); + d = RotateLeft32<1>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + } + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a,b,c,d); +} + +inline void CHAM128_Dec_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0); + __m128i b = UnpackXMM<1>(block0); + __m128i c = UnpackXMM<2>(block0); + __m128i d = UnpackXMM<3>(block0); + + __m128i counter = _mm_set_epi32(rounds-1,rounds-1,rounds-1,rounds-1); + __m128i decrement = _mm_set_epi32(1,1,1,1); + + const unsigned int MASK = (rounds == 80 ? 7 : 15); + for (int i = static_cast(rounds)-1; i >= 0; i-=4) + { + __m128i k, k1, k2, t1, t2; + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i-1) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + + // Odd round + t1 = RotateRight32<1>(d); + t2 = _mm_xor_si128(RotateLeft32<8>(a), k1); + d = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + + // Even round + t1 = RotateRight32<8>(c); + t2 = _mm_xor_si128(RotateLeft32<1>(d), k2); + c = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i-3) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + + // Odd round + t1 = RotateRight32<1>(b); + t2 = _mm_xor_si128(RotateLeft32<8>(c), k1); + b = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + + // Even round + t1 = RotateRight32<8>(a); + t2 = _mm_xor_si128(RotateLeft32<1>(b), k2); + a = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + } + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a,b,c,d); +} + +inline void CHAM128_Enc_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0, block1, block2, block3); + __m128i b = UnpackXMM<1>(block0, block1, block2, block3); + __m128i c = UnpackXMM<2>(block0, block1, block2, block3); + __m128i d = UnpackXMM<3>(block0, block1, block2, block3); + + __m128i counter = _mm_set_epi32(0,0,0,0); + __m128i increment = _mm_set_epi32(1,1,1,1); + + const unsigned int MASK = (rounds == 80 ? 7 : 15); + for (int i=0; i(rounds); i+=4) + { + __m128i k, k1, k2, t1, t2; + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i+0) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + + t1 = _mm_xor_si128(a, counter); + t2 = _mm_xor_si128(RotateLeft32<1>(b), k1); + a = RotateLeft32<8>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + + t1 = _mm_xor_si128(b, counter); + t2 = _mm_xor_si128(RotateLeft32<8>(c), k2); + b = RotateLeft32<1>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i+2) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + + t1 = _mm_xor_si128(c, counter); + t2 = _mm_xor_si128(RotateLeft32<1>(d), k1); + c = RotateLeft32<8>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + + t1 = _mm_xor_si128(d, counter); + t2 = _mm_xor_si128(RotateLeft32<8>(a), k2); + d = RotateLeft32<1>(_mm_add_epi32(t1, t2)); + + counter = _mm_add_epi32(counter, increment); + } + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a,b,c,d); + block1 = RepackXMM<1>(a,b,c,d); + block2 = RepackXMM<2>(a,b,c,d); + block3 = RepackXMM<3>(a,b,c,d); +} + +inline void CHAM128_Dec_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + // Rearrange the data for vectorization. UnpackXMM includes a + // little-endian swap for SSE. Thanks to Peter Cordes for help + // with packing and unpacking. + // [A1 A2 A3 A4][B1 B2 B3 B4] ... => [A1 B1 C1 D1][A2 B2 C2 D2] ... + __m128i a = UnpackXMM<0>(block0, block1, block2, block3); + __m128i b = UnpackXMM<1>(block0, block1, block2, block3); + __m128i c = UnpackXMM<2>(block0, block1, block2, block3); + __m128i d = UnpackXMM<3>(block0, block1, block2, block3); + + __m128i counter = _mm_set_epi32(rounds-1,rounds-1,rounds-1,rounds-1); + __m128i decrement = _mm_set_epi32(1,1,1,1); + + const unsigned int MASK = (rounds == 80 ? 7 : 15); + for (int i = static_cast(rounds)-1; i >= 0; i-=4) + { + __m128i k, k1, k2, t1, t2; + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i-1) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + + // Odd round + t1 = RotateRight32<1>(d); + t2 = _mm_xor_si128(RotateLeft32<8>(a), k1); + d = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + + // Even round + t1 = RotateRight32<8>(c); + t2 = _mm_xor_si128(RotateLeft32<1>(d), k2); + c = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + k = _mm_castpd_si128(_mm_load_sd(CONST_DOUBLE_CAST(&subkeys[(i-3) & MASK]))); + + // Shuffle out two subkeys + k1 = _mm_shuffle_epi8(k, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); + k2 = _mm_shuffle_epi8(k, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); + + // Odd round + t1 = RotateRight32<1>(b); + t2 = _mm_xor_si128(RotateLeft32<8>(c), k1); + b = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + + // Even round + t1 = RotateRight32<8>(a); + t2 = _mm_xor_si128(RotateLeft32<1>(b), k2); + a = _mm_xor_si128(_mm_sub_epi32(t1, t2), counter); + + counter = _mm_sub_epi32(counter, decrement); + } + + // [A1 B1 C1 D1][A2 B2 C2 D2] ... => [A1 A2 A3 A4][B1 B2 B3 B4] ... + block0 = RepackXMM<0>(a,b,c,d); + block1 = RepackXMM<1>(a,b,c,d); + block2 = RepackXMM<2>(a,b,c,d); + block3 = RepackXMM<3>(a,b,c,d); +} + +////////////////////////////////////////////////////////////////////////// + +NAMESPACE_END // W32 + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) +size_t CHAM128_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_SSE(W32::CHAM128_Enc_Block, W32::CHAM128_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t CHAM128_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_SSE(W32::CHAM128_Dec_Block, W32::CHAM128_Dec_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SSSE3_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/channels.cpp b/extension/third_party/cryptopp/channels.cpp new file mode 100644 index 00000000..ec7a98a0 --- /dev/null +++ b/extension/third_party/cryptopp/channels.cpp @@ -0,0 +1,316 @@ +// channels.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "cryptlib.h" +#include "channels.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +void MessageSwitch::AddDefaultRoute(BufferedTransformation &destination, const std::string &channel) +{ + m_defaultRoutes.push_back(Route(&destination, channel)); +} + +void MessageSwitch::AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel) +{ + RangeRoute route(begin, end, Route(&destination, channel)); + RouteList::iterator it = upper_bound(m_routes.begin(), m_routes.end(), route); + m_routes.insert(it, route); +} + +/* +class MessageRouteIterator +{ +public: + typedef MessageSwitch::RouteList::const_iterator RouteIterator; + typedef MessageSwitch::DefaultRouteList::const_iterator DefaultIterator; + + bool m_useDefault; + RouteIterator m_itRouteCurrent, m_itRouteEnd; + DefaultIterator m_itDefaultCurrent, m_itDefaultEnd; + + MessageRouteIterator(MessageSwitch &ms, const std::string &channel) + : m_channel(channel) + { + std::pair range = cs.m_routeMap.equal_range(channel); + if (range.first == range.second) + { + m_useDefault = true; + m_itListCurrent = cs.m_defaultRoutes.begin(); + m_itListEnd = cs.m_defaultRoutes.end(); + } + else + { + m_useDefault = false; + m_itMapCurrent = range.first; + m_itMapEnd = range.second; + } + } + + bool End() const + { + return m_useDefault ? m_itListCurrent == m_itListEnd : m_itMapCurrent == m_itMapEnd; + } + + void Next() + { + if (m_useDefault) + ++m_itListCurrent; + else + ++m_itMapCurrent; + } + + BufferedTransformation & Destination() + { + return m_useDefault ? *m_itListCurrent->first : *m_itMapCurrent->second.first; + } + + const std::string & Message() + { + if (m_useDefault) + return m_itListCurrent->second.get() ? *m_itListCurrent->second.get() : m_channel; + else + return m_itMapCurrent->second.second; + } +}; + +void MessageSwitch::Put(byte inByte); +void MessageSwitch::Put(const byte *inString, unsigned int length); + +void MessageSwitch::Flush(bool completeFlush, int propagation=-1); +void MessageSwitch::MessageEnd(int propagation=-1); +void MessageSwitch::PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); +void MessageSwitch::MessageSeriesEnd(int propagation=-1); +*/ +#endif + + +// +// ChannelRouteIterator +////////////////////////// + +void ChannelRouteIterator::Reset(const std::string &channel) +{ + m_channel = channel; + std::pair range = m_cs.m_routeMap.equal_range(channel); + if (range.first == range.second) + { + m_useDefault = true; + m_itListCurrent = m_cs.m_defaultRoutes.begin(); + m_itListEnd = m_cs.m_defaultRoutes.end(); + } + else + { + m_useDefault = false; + m_itMapCurrent = range.first; + m_itMapEnd = range.second; + } +} + +bool ChannelRouteIterator::End() const +{ + return m_useDefault ? m_itListCurrent == m_itListEnd : m_itMapCurrent == m_itMapEnd; +} + +void ChannelRouteIterator::Next() +{ + if (m_useDefault) + ++m_itListCurrent; + else + ++m_itMapCurrent; +} + +BufferedTransformation & ChannelRouteIterator::Destination() +{ + return m_useDefault ? *m_itListCurrent->first : *m_itMapCurrent->second.first; +} + +const std::string & ChannelRouteIterator::Channel() +{ + if (m_useDefault) + return m_itListCurrent->second.get() ? *m_itListCurrent->second.get() : m_channel; + else + return m_itMapCurrent->second.second; +} + + +// +// ChannelSwitch +/////////////////// + +size_t ChannelSwitch::ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (m_blocked) + { + m_blocked = false; + goto WasBlocked; + } + + m_it.Reset(channel); + + while (!m_it.End()) + { +WasBlocked: + if (m_it.Destination().ChannelPut2(m_it.Channel(), begin, length, messageEnd, blocking)) + { + m_blocked = true; + return 1; + } + + m_it.Next(); + } + + return 0; +} + +void ChannelSwitch::IsolatedInitialize(const NameValuePairs& parameters) +{ + CRYPTOPP_UNUSED(parameters); + m_routeMap.clear(); + m_defaultRoutes.clear(); + m_blocked = false; +} + +bool ChannelSwitch::ChannelFlush(const std::string &channel, bool completeFlush, int propagation, bool blocking) +{ + if (m_blocked) + { + m_blocked = false; + goto WasBlocked; + } + + m_it.Reset(channel); + + while (!m_it.End()) + { + WasBlocked: + if (m_it.Destination().ChannelFlush(m_it.Channel(), completeFlush, propagation, blocking)) + { + m_blocked = true; + return true; + } + + m_it.Next(); + } + + return false; +} + +bool ChannelSwitch::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + CRYPTOPP_UNUSED(blocking); + if (m_blocked) + { + m_blocked = false; + goto WasBlocked; + } + + m_it.Reset(channel); + + while (!m_it.End()) + { + WasBlocked: + if (m_it.Destination().ChannelMessageSeriesEnd(m_it.Channel(), propagation)) + { + m_blocked = true; + return true; + } + + m_it.Next(); + } + + return false; +} + +byte * ChannelSwitch::ChannelCreatePutSpace(const std::string &channel, size_t &size) +{ + m_it.Reset(channel); + if (!m_it.End()) + { + BufferedTransformation &target = m_it.Destination(); + const std::string &ch = m_it.Channel(); + m_it.Next(); + if (m_it.End()) // there is only one target channel + return target.ChannelCreatePutSpace(ch, size); + } + size = 0; + return NULLPTR; +} + +size_t ChannelSwitch::ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking) +{ + ChannelRouteIterator it(*this); + it.Reset(channel); + + if (!it.End()) + { + BufferedTransformation &target = it.Destination(); + const std::string &targetChannel = it.Channel(); + it.Next(); + if (it.End()) // there is only one target channel + return target.ChannelPutModifiable2(targetChannel, inString, length, messageEnd, blocking); + } + + return ChannelPut2(channel, inString, length, messageEnd, blocking); +} + +void ChannelSwitch::AddDefaultRoute(BufferedTransformation &destination) +{ + m_defaultRoutes.push_back(DefaultRoute(&destination, value_ptr(NULLPTR))); +} + +void ChannelSwitch::RemoveDefaultRoute(BufferedTransformation &destination) +{ + for (DefaultRouteList::iterator it = m_defaultRoutes.begin(); it != m_defaultRoutes.end(); ++it) + if (it->first == &destination && !it->second.get()) + { + m_defaultRoutes.erase(it); + break; + } +} + +void ChannelSwitch::AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel) +{ + m_defaultRoutes.push_back(DefaultRoute(&destination, outChannel)); +} + +void ChannelSwitch::RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel) +{ + for (DefaultRouteList::iterator it = m_defaultRoutes.begin(); it != m_defaultRoutes.end(); ++it) + if (it->first == &destination && (it->second.get() && *it->second == outChannel)) + { + m_defaultRoutes.erase(it); + break; + } +} + +void ChannelSwitch::AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel) +{ + m_routeMap.insert(RouteMap::value_type(inChannel, Route(&destination, outChannel))); +} + +void ChannelSwitch::RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel) +{ + typedef ChannelSwitch::RouteMap::iterator MapIterator; + std::pair range = m_routeMap.equal_range(inChannel); + + for (MapIterator it = range.first; it != range.second; ++it) + if (it->second.first == &destination && it->second.second == outChannel) + { + m_routeMap.erase(it); + break; + } +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/channels.h b/extension/third_party/cryptopp/channels.h new file mode 100644 index 00000000..da470a2b --- /dev/null +++ b/extension/third_party/cryptopp/channels.h @@ -0,0 +1,142 @@ +// channels.h - originally written and placed in the public domain by Wei Dai + +/// \file channels.h +/// \brief Classes for multiple named channels + +#ifndef CRYPTOPP_CHANNELS_H +#define CRYPTOPP_CHANNELS_H + +#include "cryptlib.h" +#include "simple.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +/// Route input on default channel to different and/or multiple channels based on message sequence number +class MessageSwitch : public Sink +{ +public: + void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel); + void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel); + + void Put(byte inByte); + void Put(const byte *inString, unsigned int length); + + void Flush(bool completeFlush, int propagation=-1); + void MessageEnd(int propagation=-1); + void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); + void MessageSeriesEnd(int propagation=-1); + +private: + typedef std::pair Route; + struct RangeRoute + { + RangeRoute(unsigned int begin, unsigned int end, const Route &route) + : begin(begin), end(end), route(route) {} + bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;} + unsigned int begin, end; + Route route; + }; + + typedef std::list RouteList; + typedef std::list DefaultRouteList; + + RouteList m_routes; + DefaultRouteList m_defaultRoutes; + unsigned int m_nCurrentMessage; +}; +#endif + +class ChannelSwitchTypedefs +{ +public: + typedef std::pair Route; + typedef std::multimap RouteMap; + + typedef std::pair > DefaultRoute; + typedef std::list DefaultRouteList; + + // SunCC workaround: can't use const_iterator here + typedef RouteMap::iterator MapIterator; + typedef DefaultRouteList::iterator ListIterator; +}; + +class ChannelSwitch; + +class ChannelRouteIterator : public ChannelSwitchTypedefs +{ +public: + ChannelRouteIterator(ChannelSwitch &cs) : m_cs(cs), m_useDefault(false) {} + + void Reset(const std::string &channel); + bool End() const; + void Next(); + BufferedTransformation & Destination(); + const std::string & Channel(); + + ChannelSwitch& m_cs; + std::string m_channel; + bool m_useDefault; + MapIterator m_itMapCurrent, m_itMapEnd; + ListIterator m_itListCurrent, m_itListEnd; + +protected: + // Hide this to see if we break something... + ChannelRouteIterator(); +}; + +/// Route input to different and/or multiple channels based on channel ID +class CRYPTOPP_DLL ChannelSwitch : public Multichannel, public ChannelSwitchTypedefs +{ +public: + ChannelSwitch() : m_it(*this), m_blocked(false) {} + ChannelSwitch(BufferedTransformation &destination) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination); + } + ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination, outChannel); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking); + + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + void AddDefaultRoute(BufferedTransformation &destination); + void RemoveDefaultRoute(BufferedTransformation &destination); + void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + +private: + RouteMap m_routeMap; + DefaultRouteList m_defaultRoutes; + + ChannelRouteIterator m_it; + bool m_blocked; + + friend class ChannelRouteIterator; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/cmac.cpp b/extension/third_party/cryptopp/cmac.cpp new file mode 100644 index 00000000..7a71236f --- /dev/null +++ b/extension/third_party/cryptopp/cmac.cpp @@ -0,0 +1,162 @@ +// cmac.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "cmac.h" +#include "misc.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::IsPowerOf2; + +void MulU(byte *k, unsigned int len) +{ + byte carry = 0; + for (int i=len-1; i>=1; i-=2) + { + byte carry2 = k[i] >> 7; + k[i] += k[i] + carry; + carry = k[i-1] >> 7; + k[i-1] += k[i-1] + carry2; + } + +#ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS + CRYPTOPP_ASSERT(len == 16); + + if (carry) + { + k[15] ^= 0x87; + return; + } +#else + CRYPTOPP_ASSERT(IsPowerOf2(len)); + CRYPTOPP_ASSERT(len >= 8); + CRYPTOPP_ASSERT(len <= 128); + + if (carry) + { + switch (len) + { + case 8: + k[7] ^= 0x1b; + break; + case 16: + k[15] ^= 0x87; + break; + case 32: + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^256 + x^10 + x^5 + x^2 + 1 + k[30] ^= 4; + k[31] ^= 0x25; + break; + case 64: + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^512 + x^8 + x^5 + x^2 + 1 + k[62] ^= 1; + k[63] ^= 0x25; + break; + case 128: + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^1024 + x^19 + x^6 + x + 1 + k[125] ^= 8; + k[126] ^= 0x00; + k[127] ^= 0x43; + break; + default: + CRYPTOPP_ASSERT(0); + } + } +#endif // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void CMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + BlockCipher &cipher = AccessCipher(); + cipher.SetKey(key, length, params); + + unsigned int blockSize = cipher.BlockSize(); + m_reg.CleanNew(3*blockSize); + m_counter = 0; + + cipher.ProcessBlock(m_reg, m_reg+blockSize); + MulU(m_reg+blockSize, blockSize); + memcpy(m_reg+2*blockSize, m_reg+blockSize, blockSize); + MulU(m_reg+2*blockSize, blockSize); +} + +void CMAC_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !(input || length)); + if (!length) + return; + + BlockCipher &cipher = AccessCipher(); + unsigned int blockSize = cipher.BlockSize(); + + if (m_counter > 0) + { + const unsigned int len = UnsignedMin(blockSize - m_counter, length); + if (len) + { + xorbuf(m_reg+m_counter, input, len); + length -= len; + input += len; + m_counter += len; + } + + if (m_counter == blockSize && length > 0) + { + cipher.ProcessBlock(m_reg); + m_counter = 0; + } + } + + if (length > blockSize) + { + CRYPTOPP_ASSERT(m_counter == 0); + size_t leftOver = 1 + cipher.AdvancedProcessBlocks(m_reg, input, m_reg, length-1, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); + input += (length - leftOver); + length = leftOver; + } + + if (length > 0) + { + CRYPTOPP_ASSERT(m_counter + length <= blockSize); + xorbuf(m_reg+m_counter, input, length); + m_counter += (unsigned int)length; + } + + CRYPTOPP_ASSERT(m_counter > 0); +} + +void CMAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + BlockCipher &cipher = AccessCipher(); + unsigned int blockSize = cipher.BlockSize(); + + if (m_counter < blockSize) + { + m_reg[m_counter] ^= 0x80; + cipher.AdvancedProcessBlocks(m_reg, m_reg+2*blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); + } + else + cipher.AdvancedProcessBlocks(m_reg, m_reg+blockSize, m_reg, blockSize, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); + + memcpy(mac, m_reg, size); + + m_counter = 0; + memset(m_reg, 0, blockSize); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/cmac.h b/extension/third_party/cryptopp/cmac.h new file mode 100644 index 00000000..59a9f020 --- /dev/null +++ b/extension/third_party/cryptopp/cmac.h @@ -0,0 +1,76 @@ +// cmac.h - originally written and placed in the public domain by Wei Dai + +/// \file cmac.h +/// \brief Classes for CMAC message authentication code +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CMAC_H +#define CRYPTOPP_CMAC_H + +#include "seckey.h" +#include "secblock.h" + +/// \brief Enable CMAC and wide block ciphers +/// \details CMAC is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +#ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS +# define CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS 1 +#endif // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CMAC base implementation +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CMAC_Base : public MessageAuthenticationCode +{ +public: + + virtual ~CMAC_Base() {} + CMAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return GetCipher().BlockSize();} + unsigned int OptimalBlockSize() const {return GetCipher().BlockSize();} + unsigned int OptimalDataAlignment() const {return GetCipher().OptimalDataAlignment();} + std::string AlgorithmProvider() const {return GetCipher().AlgorithmProvider();} + +protected: + friend class EAX_Base; + + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + virtual BlockCipher & AccessCipher() =0; + + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CMAC message authentication code +/// \tparam T block cipher +/// \details Template parameter T should be a class derived from BlockCipherDocumentation, for example AES, with a block size of 8, 16, or 32. +/// \sa CMAC +/// \since Crypto++ 5.6.0 +template +class CMAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + /// \brief Construct a CMAC + CMAC() {} + /// \brief Construct a CMAC + /// \param key the MAC key + /// \param length the key size, in bytes + CMAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CMAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/config.h b/extension/third_party/cryptopp/config.h new file mode 100644 index 00000000..cb4d2466 --- /dev/null +++ b/extension/third_party/cryptopp/config.h @@ -0,0 +1,33 @@ +// config.h - originally written and placed in the public domain by Wei Dai + +/// \file config.h +/// \brief Library configuration file +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +/// \file config.h +/// \brief Library configuration file + +#ifndef CRYPTOPP_CONFIG_H +#define CRYPTOPP_CONFIG_H + +#include "config_align.h" +#include "config_asm.h" +#include "config_cpu.h" +#include "config_cxx.h" +#include "config_dll.h" +#include "config_int.h" +#include "config_misc.h" +#include "config_ns.h" +#include "config_os.h" +#include "config_ver.h" + +#endif // CRYPTOPP_CONFIG_H diff --git a/extension/third_party/cryptopp/config_align.h b/extension/third_party/cryptopp/config_align.h new file mode 100644 index 00000000..6a6e9e04 --- /dev/null +++ b/extension/third_party/cryptopp/config_align.h @@ -0,0 +1,72 @@ +// config_align.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_align.h +/// \brief Library configuration file +/// \details config_align.h provides defines for aligned memory +/// allocations. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_align.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_ALIGN_H +#define CRYPTOPP_CONFIG_ALIGN_H + +#include "config_asm.h" // CRYPTOPP_DISABLE_ASM +#include "config_cpu.h" // X86, X32, X64, ARM32, ARM64, etc +#include "config_cxx.h" // CRYPTOPP_CXX11_ALIGNAS +#include "config_ver.h" // Compiler versions + +// Nearly all Intel's and AMD's have SSE. Enable it independent of SSE ASM and intrinsics. +// ARM NEON and ARMv8 ASIMD only need natural alignment of an element in the vector. +// Altivec through POWER7 need vector alignment. POWER8 and POWER9 relax the requirement. +#if defined(CRYPTOPP_DISABLE_ASM) + #define CRYPTOPP_BOOL_ALIGN16 0 +#elif (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + #define CRYPTOPP_BOOL_ALIGN16 1 +#else + #define CRYPTOPP_BOOL_ALIGN16 0 +#endif + +// How to allocate 16-byte aligned memory (for SSE2) +// posix_memalign see https://forum.kde.org/viewtopic.php?p=66274 +#if defined(_MSC_VER) + #define CRYPTOPP_MM_MALLOC_AVAILABLE +#elif defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) + #define CRYPTOPP_MEMALIGN_AVAILABLE +#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #define CRYPTOPP_MALLOC_ALIGNMENT_IS_16 +#elif (defined(_GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600)) && (_POSIX_ADVISORY_INFO > 0) + #define CRYPTOPP_POSIX_MEMALIGN_AVAILABLE +#else + #define CRYPTOPP_NO_ALIGNED_ALLOC +#endif + +// Sun Studio Express 3 (December 2006) provides GCC-style attributes. +// IBM XL C/C++ alignment modifier per Optimization Guide, pp. 19-20. +// __IBM_ATTRIBUTES per XLC 12.1 AIX Compiler Manual, p. 473. +// CRYPTOPP_ALIGN_DATA may not be reliable on AIX. +#if defined(CRYPTOPP_CXX11_ALIGNAS) + #define CRYPTOPP_ALIGN_DATA(x) alignas(x) +#elif defined(_MSC_VER) + #define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x)) +#elif defined(__GNUC__) || defined(__clang__) || (__SUNPRO_CC >= 0x5100) + #define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x))) +#elif defined(__xlc__) || defined(__xlC__) + #define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x))) +#else + #define CRYPTOPP_ALIGN_DATA(x) +#endif + +#endif // CRYPTOPP_CONFIG_ALIGN_H diff --git a/extension/third_party/cryptopp/config_asm.h b/extension/third_party/cryptopp/config_asm.h new file mode 100644 index 00000000..5bd42711 --- /dev/null +++ b/extension/third_party/cryptopp/config_asm.h @@ -0,0 +1,470 @@ +// config_asm.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_asm.h +/// \brief Library configuration file +/// \details config_asm.h provides defines for instruction set +/// architectures +/// and inline assembly. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_asm.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_ASM_H +#define CRYPTOPP_CONFIG_ASM_H + +#include "config_os.h" +#include "config_cpu.h" +#include "config_ver.h" + +// Define this to disable ASM, intrinsics and built-ins. The library will be +// compiled using C++ only. The library code will not include SSE2 (and +// above), NEON, Aarch32, Aarch64, or Altivec (and above). Note the compiler +// may use higher ISAs depending on compiler options, but the library will not +// explictly use the ISAs. When disabling ASM, it is best to do it from +// config.h to ensure the library and all programs share the setting. +// #define CRYPTOPP_DISABLE_ASM 1 + +// https://github.com/weidai11/cryptopp/issues/719 +#if defined(__native_client__) +# undef CRYPTOPP_DISABLE_ASM +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Some Clang and SunCC cannot handle mixed asm with positional arguments, +// where the body is Intel style with no prefix and the templates are +// AT&T style. Define this if the Makefile misdetects the configuration. +// Also see https://bugs.llvm.org/show_bug.cgi?id=39895 . +// #define CRYPTOPP_DISABLE_MIXED_ASM 1 + +#if defined(__clang__) || (defined(__APPLE__) && defined(__GNUC__)) || defined(__SUNPRO_CC) +# undef CRYPTOPP_DISABLE_MIXED_ASM +# define CRYPTOPP_DISABLE_MIXED_ASM 1 +#endif + +// CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is no longer honored. It +// was removed at https://github.com/weidai11/cryptopp/issues/682 +// #define CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS 1 + +// ***************** IA32 CPU features ******************** + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + +// Apple Clang prior to 5.0 cannot handle SSE2 +#if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 50000) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Sun Studio 12.1 provides GCC inline assembly +// http://blogs.oracle.com/x86be/entry/gcc_style_asm_inlining_support +#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5100) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) + +#if (defined(_MSC_VER) && defined(_M_IX86)) || ((defined(__GNUC__) && (defined(__i386__)) || defined(__x86_64__))) + // C++Builder 2010 does not allow "call label" where label is defined within inline assembly + #define CRYPTOPP_X86_ASM_AVAILABLE 1 + + #if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__)) + #define CRYPTOPP_SSE2_ASM_AVAILABLE 1 + #endif + + #if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1500 || CRYPTOPP_GCC_VERSION >= 40300 || defined(__SSSE3__)) + #define CRYPTOPP_SSSE3_ASM_AVAILABLE 1 + #endif +#endif + +#if defined(_MSC_VER) && defined(_M_X64) + #define CRYPTOPP_X64_MASM_AVAILABLE 1 +#endif + +#if defined(__GNUC__) && defined(__x86_64__) + #define CRYPTOPP_X64_ASM_AVAILABLE 1 +#endif + +// 32-bit SunCC does not enable SSE2 by default. +#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__) || (__SUNPRO_CC >= 0x5100)) + #define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_SSSE3) +# if defined(__SSSE3__) || (_MSC_VER >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) + #define CRYPTOPP_SSSE3_AVAILABLE 1 +# endif +#endif + +// Intrinsics availible in GCC 4.3 (http://gcc.gnu.org/gcc-4.3/changes.html) and +// MSVC 2008 (http://msdn.microsoft.com/en-us/library/bb892950%28v=vs.90%29.aspx) +// SunCC could generate SSE4 at 12.1, but the intrinsics are missing until 12.4. +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_1__) || (CRYPTOPP_MSC_VERSION >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE41_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_2__) || (CRYPTOPP_MSC_VERSION >= 1500) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE42_AVAILABLE 1 +#endif + +// Couple to CRYPTOPP_DISABLE_AESNI, but use CRYPTOPP_CLMUL_AVAILABLE so we can selectively +// disable for misbehaving platofrms and compilers, like Solaris or some Clang. +#if defined(CRYPTOPP_DISABLE_AESNI) + #define CRYPTOPP_DISABLE_CLMUL 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) in theory. +#if !defined(CRYPTOPP_DISABLE_CLMUL) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__PCLMUL__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_CLMUL_AVAILABLE 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) +#if !defined(CRYPTOPP_DISABLE_AESNI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__AES__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_AESNI_AVAILABLE 1 +#endif + +// Requires Binutils 2.24 +#if !defined(CRYPTOPP_DISABLE_AVX) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \ + (CRYPTOPP_GCC_VERSION >= 40700) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600)) +#define CRYPTOPP_AVX_AVAILABLE 1 +#endif + +// Requires Binutils 2.24 +#if !defined(CRYPTOPP_DISABLE_AVX2) && defined(CRYPTOPP_AVX_AVAILABLE) && \ + (defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \ + (CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600)) +#define CRYPTOPP_AVX2_AVAILABLE 1 +#endif + +// Guessing at SHA for SunCC. Its not in Sun Studio 12.6. Also see +// http://stackoverflow.com/questions/45872180/which-xarch-for-sha-extensions-on-solaris +#if !defined(CRYPTOPP_DISABLE_SHANI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__SHA__) || (CRYPTOPP_MSC_VERSION >= 1900) || (__SUNPRO_CC >= 0x5160) || \ + (CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1300) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30400) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50100)) + #define CRYPTOPP_SHANI_AVAILABLE 1 +#endif + +// RDRAND uses byte codes. All we need is x86 ASM for it. +// However tie it to AES-NI since SecureKey was available with it. +#if !defined(CRYPTOPP_DISABLE_RDRAND) && defined(CRYPTOPP_AESNI_AVAILABLE) + #define CRYPTOPP_RDRAND_AVAILABLE 1 +#endif + +// RDSEED uses byte codes. All we need is x86 ASM for it. +// However tie it to AES-NI since SecureKey was available with it. +#if !defined(CRYPTOPP_DISABLE_RDSEED) && defined(CRYPTOPP_AESNI_AVAILABLE) + #define CRYPTOPP_RDSEED_AVAILABLE 1 +#endif + +// PadlockRNG uses byte codes. All we need is x86 ASM for it. +#if !defined(CRYPTOPP_DISABLE_PADLOCK) && \ + !(defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__)) && \ + defined(CRYPTOPP_X86_ASM_AVAILABLE) + #define CRYPTOPP_PADLOCK_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_RNG_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_ACE_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_ACE2_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_PHE_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_PMM_AVAILABLE 1 +#endif + +// Fixup Android and SSE, Crypto. It may be enabled based on compiler version. +// Also see https://developer.android.com/ndk/guides/abis +#if defined(__ANDROID__) || defined(ANDROID) +# if (CRYPTOPP_BOOL_X86) +# undef CRYPTOPP_SSE41_AVAILABLE +# undef CRYPTOPP_SSE42_AVAILABLE +# undef CRYPTOPP_CLMUL_AVAILABLE +# undef CRYPTOPP_AESNI_AVAILABLE +# undef CRYPTOPP_SHANI_AVAILABLE +# undef CRYPTOPP_RDRAND_AVAILABLE +# undef CRYPTOPP_RDSEED_AVAILABLE +# undef CRYPTOPP_AVX_AVAILABLE +# undef CRYPTOPP_AVX2_AVAILABLE +# endif +# if (CRYPTOPP_BOOL_X64) +# undef CRYPTOPP_CLMUL_AVAILABLE +# undef CRYPTOPP_AESNI_AVAILABLE +# undef CRYPTOPP_SHANI_AVAILABLE +# undef CRYPTOPP_RDRAND_AVAILABLE +# undef CRYPTOPP_RDSEED_AVAILABLE +# undef CRYPTOPP_AVX_AVAILABLE +# undef CRYPTOPP_AVX2_AVAILABLE +# endif +#endif + +// Fixup for SunCC 12.1-12.4. Bad code generation in AES_Encrypt and friends. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5130) +# undef CRYPTOPP_AESNI_AVAILABLE +#endif + +// Fixup for SunCC 12.1-12.6. Compiler crash on GCM_Reduce_CLMUL. +// http://github.com/weidai11/cryptopp/issues/226 +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5150) +# undef CRYPTOPP_CLMUL_AVAILABLE +#endif + +#endif // CRYPTOPP_DISABLE_ASM + +#endif // X86, X32, X64 + +// ***************** ARM CPU features ******************** + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) + +// We don't have an ARM big endian test rig. Disable +// ARM-BE ASM and instrinsics until we can test it. +#if (CRYPTOPP_BIG_ENDIAN) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) + +// Requires ACLE 1.0. -mfpu=neon or above must be present +// Requires GCC 4.3, Clang 2.8 or Visual Studio 2012 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_NEON_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_NEON) +# if defined(__arm__) || defined(__ARM_NEON) || defined(__ARM_FEATURE_NEON) || defined(_M_ARM) +# if (CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || \ + (CRYPTOPP_MSC_VERSION >= 1700) +# define CRYPTOPP_ARM_NEON_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and ASIMD. -march=armv8-a or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_ASIMD) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_NEON) || defined(__ARM_FEATURE_NEON) || defined(__ARM_FEATURE_ASIMD) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \ + (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_NEON_AVAILABLE 1 +# define CRYPTOPP_ARM_ASIMD_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and ASIMD. -march=armv8-a+crc or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_CRC32_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_CRC32) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRC32) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_CRC32_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and ASIMD. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_PMULL_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_PMULL) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_PMULL_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and AES. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_AES) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_AES_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and SHA-1, SHA-256. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_SHA1_AVAILABLE 1 +# define CRYPTOPP_ARM_SHA2_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and SHA-512, SHA-3. -march=armv8.4-a+crypto or above must be present +// Requires GCC 8.0, Clang ??? or Visual Studio 20?? +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_SHA3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_SHA3) || (CRYPTOPP_GCC_VERSION >= 80000) +# define CRYPTOPP_ARM_SHA512_AVAILABLE 1 +# define CRYPTOPP_ARM_SHA3_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and SM3, SM4. -march=armv8.4-a+crypto or above must be present +// Requires GCC 8.0, Clang ??? or Visual Studio 20?? +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_SM3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SM3) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_SM3) || (CRYPTOPP_GCC_VERSION >= 80000) +# define CRYPTOPP_ARM_SM3_AVAILABLE 1 +# define CRYPTOPP_ARM_SM4_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// Limit the include. +#if !defined(CRYPTOPP_ARM_NEON_HEADER) +# if defined(CRYPTOPP_ARM_NEON_AVAILABLE) || defined (CRYPTOPP_ARM_ASIMD_AVAILABLE) +# if !defined(_M_ARM64) +# define CRYPTOPP_ARM_NEON_HEADER 1 +# endif +# endif +#endif + +// Limit the include. +#if !defined(CRYPTOPP_ARM_ACLE_HEADER) +# if defined(__aarch32__) || defined(__aarch64__) || (__ARM_ARCH >= 8) || defined(__ARM_ACLE) +# if !defined(__ANDROID__) && !defined(ANDROID) && !defined(__APPLE__) +# define CRYPTOPP_ARM_ACLE_HEADER 1 +# endif +# endif +#endif + +// Fixup Apple Clang and PMULL. Apple defines __ARM_FEATURE_CRYPTO for Xcode 6 +// but does not provide PMULL. TODO: determine when PMULL is available. +#if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 70000) +# undef CRYPTOPP_ARM_PMULL_AVAILABLE +#endif + +// Disable for Android. Android only offers the base Aarch64 architecture. +// Also see https://developer.android.com/ndk/guides/abis +#if defined(__ANDROID__) || defined(ANDROID) +# undef CRYPTOPP_ARM_CRC32_AVAILABLE +# undef CRYPTOPP_ARM_PMULL_AVAILABLE +# undef CRYPTOPP_ARM_AES_AVAILABLE +# undef CRYPTOPP_ARM_SHA1_AVAILABLE +# undef CRYPTOPP_ARM_SHA2_AVAILABLE +# undef CRYPTOPP_ARM_SHA3_AVAILABLE +# undef CRYPTOPP_ARM_SHA512_AVAILABLE +# undef CRYPTOPP_ARM_SM3_AVAILABLE +# undef CRYPTOPP_ARM_SM4_AVAILABLE +#endif + +// Cryptogams offers an ARM asm implementations for AES and SHA. Crypto++ does +// not provide an asm implementation. The Cryptogams AES implementation is +// about 50% faster than C/C++, and SHA implementation is about 30% faster +// than C/C++. Define this to use the Cryptogams AES and SHA implementations +// on GNU Linux systems. When defined, Crypto++ will use aes_armv4.S, +// sha1_armv4.S and sha256_armv4.S. https://www.cryptopp.com/wiki/Cryptogams. +#if defined(__arm__) && defined(__linux__) +# if defined(__GNUC__) || defined(__clang__) +# define CRYPTOGAMS_ARM_AES 1 +# define CRYPTOGAMS_ARM_SHA1 1 +# define CRYPTOGAMS_ARM_SHA256 1 +# define CRYPTOGAMS_ARM_SHA512 1 +# endif +#endif + +#endif // CRYPTOPP_DISABLE_ASM + +#endif // ARM32, ARM64 + +// ***************** AltiVec and Power8 ******************** + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_ALTIVEC) + +// An old Apple G5 with GCC 4.01 has AltiVec, but its only Power4 or so. +#if !defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# if defined(_ARCH_PWR4) || defined(__ALTIVEC__) || \ + (CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40001) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) +# define CRYPTOPP_ALTIVEC_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + +// We need Power7 for unaligned loads and stores +#if !defined(CRYPTOPP_POWER7_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER7) +# if defined(_ARCH_PWR7) || (CRYPTOPP_XLC_VERSION >= 100000) || \ + (CRYPTOPP_GCC_VERSION >= 40100) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) +# define CRYPTOPP_POWER7_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_POWER7_AVAILABLE) + +// We need Power8 for in-core crypto and 64-bit vector types +#if !defined(CRYPTOPP_POWER8_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8) +# if defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000) +# define CRYPTOPP_POWER8_AVAILABLE 1 +# endif +#endif + +#if !defined(CRYPTOPP_POWER8_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8_AES) && defined(CRYPTOPP_POWER8_AVAILABLE) +# if defined(__CRYPTO__) || defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000) +//# define CRYPTOPP_POWER8_CRC_AVAILABLE 1 +# define CRYPTOPP_POWER8_AES_AVAILABLE 1 +# define CRYPTOPP_POWER8_VMULL_AVAILABLE 1 +# define CRYPTOPP_POWER8_SHA_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_POWER8_AVAILABLE) + +// Power9 for random numbers +#if !defined(CRYPTOPP_POWER9_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER9) +# if defined(_ARCH_PWR9) || (CRYPTOPP_XLC_VERSION >= 130200) || \ + (CRYPTOPP_GCC_VERSION >= 70000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 80000) +# define CRYPTOPP_POWER9_AVAILABLE 1 +# endif +#endif + +#endif // CRYPTOPP_POWER8_AVAILABLE +#endif // CRYPTOPP_POWER7_AVAILABLE +#endif // CRYPTOPP_ALTIVEC_AVAILABLE +#endif // CRYPTOPP_DISABLE_ASM +#endif // PPC32, PPC64 + +#endif // CRYPTOPP_CONFIG_ASM_H diff --git a/extension/third_party/cryptopp/config_cpu.h b/extension/third_party/cryptopp/config_cpu.h new file mode 100644 index 00000000..3eeaf234 --- /dev/null +++ b/extension/third_party/cryptopp/config_cpu.h @@ -0,0 +1,211 @@ +// config_cpu.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_cpu.h +/// \brief Library configuration file +/// \details config_cpu.h provides defines for the cpu and machine +/// architecture. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_cpu.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki, +/// Sourceforge +/// Pre-defined Compiler Macros +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_CPU_H +#define CRYPTOPP_CONFIG_CPU_H + +#include "config_ver.h" + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 32-bit x32 platform + /// \details CRYPTOPP_BOOL_X32 is defined to 1 when building the library + /// for a 32-bit x32 platform. Otherwise, the macro is not defined. + /// \details x32 is sometimes referred to as x86_32. x32 is the ILP32 data + /// model on a 64-bit cpu. Integers, longs and pointers are 32-bit but the + /// program runs on a 64-bit cpu. + /// \details The significance of x32 is, inline assembly must operate on + /// 64-bit registers, not 32-bit registers. That means, for example, + /// function prologues and epilogues must push and pop RSP, not ESP. + /// \note: Clang defines __ILP32__ on any 32-bit platform. Therefore, + /// CRYPTOPP_BOOL_X32 depends upon both __ILP32__ and __x86_64__. + /// \sa Debian X32 Port, + /// Gentoo + /// Multilib Concepts + #define CRYPTOPP_BOOL_X32 ... + /// \brief 32-bit x86 platform + /// \details CRYPTOPP_BOOL_X64 is defined to 1 when building the library + /// for a 64-bit x64 platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_X64 ... + /// \brief 32-bit x86 platform + /// \details CRYPTOPP_BOOL_X86 is defined to 1 when building the library + /// for a 32-bit x86 platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_X86 ... +#elif (defined(__ILP32__) || defined(_ILP32)) && defined(__x86_64__) + #define CRYPTOPP_BOOL_X32 1 +#elif (defined(_M_X64) || defined(__x86_64__)) + #define CRYPTOPP_BOOL_X64 1 +#elif (defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_X86_) || defined(__I86__) || defined(__INTEL__)) + #define CRYPTOPP_BOOL_X86 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief ARMv8 platform + /// \details CRYPTOPP_BOOL_ARMV8 is defined to 1 when building the library + /// for an ARMv8 platform. Otherwise, the macro is not defined. + /// \details ARMv8 includes both Aarch32 and Aarch64. Aarch32 is a 32-bit + /// execution environment on Aarch64. + #define CRYPTOPP_BOOL_ARMV8 ... + /// \brief 64-bit ARM platform + /// \details CRYPTOPP_BOOL_ARM64 is defined to 1 when building the library + /// for a 64-bit x64 platform. Otherwise, the macro is not defined. + /// \details Currently the macro indicates an ARM 64-bit architecture. + #define CRYPTOPP_BOOL_ARM64 ... + /// \brief 32-bit ARM platform + /// \details CRYPTOPP_BOOL_ARM32 is defined to 1 when building the library + /// for a 32-bit ARM platform. Otherwise, the macro is not defined. + /// \details Currently the macro indicates an ARM A-32 architecture. + #define CRYPTOPP_BOOL_ARM32 ... +#elif defined(__arm64__) || defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) + // Microsoft added ARM64 define December 2017. + #define CRYPTOPP_BOOL_ARMV8 1 +#endif +#if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) + #define CRYPTOPP_BOOL_ARM64 1 +#elif defined(__arm__) || defined(_M_ARM) + #define CRYPTOPP_BOOL_ARM32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit PowerPC platform + /// \details CRYPTOPP_BOOL_PPC64 is defined to 1 when building the library + /// for a 64-bit PowerPC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_PPC64 ... + /// \brief 32-bit PowerPC platform + /// \details CRYPTOPP_BOOL_PPC32 is defined to 1 when building the library + /// for a 32-bit PowerPC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_PPC32 ... +#elif defined(__ppc64__) || defined(__powerpc64__) || defined(__PPC64__) || defined(_ARCH_PPC64) + #define CRYPTOPP_BOOL_PPC64 1 +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC) + #define CRYPTOPP_BOOL_PPC32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit MIPS platform + /// \details CRYPTOPP_BOOL_MIPS64 is defined to 1 when building the library + /// for a 64-bit MIPS platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_MIPS64 ... + /// \brief 64-bit MIPS platform + /// \details CRYPTOPP_BOOL_MIPS32 is defined to 1 when building the library + /// for a 32-bit MIPS platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_MIPS32 ... +#elif defined(__mips64__) + #define CRYPTOPP_BOOL_MIPS64 1 +#elif defined(__mips__) + #define CRYPTOPP_BOOL_MIPS32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit SPARC platform + /// \details CRYPTOPP_BOOL_SPARC64 is defined to 1 when building the library + /// for a 64-bit SPARC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_SPARC64 ... + /// \brief 32-bit SPARC platform + /// \details CRYPTOPP_BOOL_SPARC32 is defined to 1 when building the library + /// for a 32-bit SPARC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_SPARC32 ... +#elif defined(__sparc64__) || defined(__sparc64) || defined(__sparcv9) || defined(__sparc_v9__) + #define CRYPTOPP_BOOL_SPARC64 1 +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) || defined(__sparc_v8__) + #define CRYPTOPP_BOOL_SPARC32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief L1 data cache line size + /// \details CRYPTOPP_L1_CACHE_LINE_SIZE should be a lower bound on the L1 + /// data cache line size. It is used for defense against some timing attacks. + /// \details CRYPTOPP_L1_CACHE_LINE_SIZE default value on 32-bit platforms + /// is 32, and the default value on 64-bit platforms is 64. On PowerPC the + /// default value is 128 since all PowerPC cpu's starting at PPC 970 provide + /// it. + /// \note The runtime library on some PowerPC platforms misreport the size + /// of the cache line size. The runtime library reports 64, while the cpu + /// has a cache line size of 128. + /// \sa CentOS Issue + /// 14599: sysconf(_SC_LEVEL1_DCACHE_LINESIZE) returns 0 instead of 128 + /// \since Crypto++ 5.3 + #define CRYPTOPP_L1_CACHE_LINE_SIZE ... +#else + #ifndef CRYPTOPP_L1_CACHE_LINE_SIZE + #if defined(CRYPTOPP_BOOL_X32) || defined(CRYPTOPP_BOOL_X64) || defined(CRYPTOPP_BOOL_ARMV8) || \ + defined(CRYPTOPP_BOOL_MIPS64) || defined(CRYPTOPP_BOOL_SPARC64) + #define CRYPTOPP_L1_CACHE_LINE_SIZE 64 + #elif defined(CRYPTOPP_BOOL_PPC32) || defined(CRYPTOPP_BOOL_PPC64) + // http://lists.llvm.org/pipermail/llvm-dev/2017-March/110982.html + #define CRYPTOPP_L1_CACHE_LINE_SIZE 128 + #else + // L1 cache line size is 32 on Pentium III and earlier + #define CRYPTOPP_L1_CACHE_LINE_SIZE 32 + #endif + #endif +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Initialized data section + /// \details CRYPTOPP_SECTION_INIT is added to variables to place them in the + /// initialized data section (sometimes denoted .data). The placement + /// helps avoid "uninitialized variable" warnings from Valgrind and other tools. + #define CRYPTOPP_SECTION_INIT ... +#else + // The section attribute attempts to initialize CPU flags to avoid Valgrind findings above -O1 + #if ((defined(__MACH__) && defined(__APPLE__)) && ((CRYPTOPP_LLVM_CLANG_VERSION >= 30600) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 70100) || (CRYPTOPP_GCC_VERSION >= 40300))) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("__DATA,__data"))) + #elif (defined(__ELF__) && (CRYPTOPP_GCC_VERSION >= 40300)) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon"))) + #elif defined(__ELF__) && (defined(__xlC__) || defined(__ibmxl__)) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon"))) + #else + #define CRYPTOPP_SECTION_INIT + #endif +#endif + +// How to disable CPU feature probing. We determine machine +// capabilities by performing an os/platform *query* first, +// like getauxv(). If the *query* fails, we move onto a +// cpu *probe*. The cpu *probe* tries to exeute an instruction +// and then catches a SIGILL on Linux or the exception +// EXCEPTION_ILLEGAL_INSTRUCTION on Windows. Some OSes +// fail to hangle a SIGILL gracefully, like Apple OSes. Apple +// machines corrupt memory and variables around the probe. +#if defined(__APPLE__) + #define CRYPTOPP_NO_CPU_FEATURE_PROBES 1 +#endif + +// Flavor of inline assembly language +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Microsoft style inline assembly + /// \details CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY is defined when either + /// _MSC_VER or __BORLANDC__ are defined. + #define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY ... + /// \brief GNU style inline assembly + /// \details CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY is defined when neither + /// _MSC_VER nor __BORLANDC__ are defined. + #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY ... +#elif defined(_MSC_VER) || defined(__BORLANDC__) + #define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY 1 +#else + #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY 1 +#endif + +#endif // CRYPTOPP_CONFIG_CPU_H diff --git a/extension/third_party/cryptopp/config_cxx.h b/extension/third_party/cryptopp/config_cxx.h new file mode 100644 index 00000000..7afa0759 --- /dev/null +++ b/extension/third_party/cryptopp/config_cxx.h @@ -0,0 +1,259 @@ +// config_cxx.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_cxx.h +/// \brief Library configuration file +/// \details config_cxx.h provides defines for C++ language and +/// runtime library +/// features. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_cxx.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +// Visual Studio began at VS2010, http://msdn.microsoft.com/en-us/library/hh567368%28v=vs.110%29.aspx +// and https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance +// Intel, http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler +// GCC, http://gcc.gnu.org/projects/cxx0x.html +// Clang, http://clang.llvm.org/cxx_status.html + +#ifndef CRYPTOPP_CONFIG_CXX_H +#define CRYPTOPP_CONFIG_CXX_H + +#include "config_os.h" +#include "config_cpu.h" +#include "config_ver.h" + +// https://github.com/weidai11/cryptopp/issues/960 +#include +#include + +// You may need to force include a C++ header on Android when using STLPort +// to ensure _STLPORT_VERSION is defined +#if (defined(_MSC_VER) && _MSC_VER <= 1300) || defined(__MWERKS__) || (defined(_STLPORT_VERSION) && ((_STLPORT_VERSION < 0x450) || defined(_STLP_NO_UNCAUGHT_EXCEPT_SUPPORT))) +#define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +#endif + +// Ancient Crypto++ define, dating back to C++98. +#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +# define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE 1 +# define CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION 1 +#endif + +// Compatibility with non-clang compilers. +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// Define CRYPTOPP_NO_CXX11 to avoid C++11 related features shown at the +// end of this file. Some compilers and standard C++ headers advertise C++11 +// but they are really just C++03 with some additional C++11 headers and +// non-conforming classes. Also see Issues 529. +// #define CRYPTOPP_NO_CXX11 1 + +// Define CRYPTOPP_NO_CXX17 to avoid C++17 related features shown at the end of +// this file. At the moment it should only affect std::uncaught_exceptions. +// #define CRYPTOPP_NO_CXX17 1 + +// C++11 macro version, https://stackoverflow.com/q/7223991/608639 +#if !defined(CRYPTOPP_NO_CXX11) +# if ((_MSC_VER >= 1600) || (__cplusplus >= 201103L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX11 1 +# endif +#endif + +// Hack ahead. Apple's standard library does not have C++'s unique_ptr in C++11. +// We can't test for unique_ptr directly because some of the non-Apple Clangs +// on OS X fail the same way. However, modern standard libraries have +// , so we test for it instead. Thanks to Jonathan Wakely for +// devising the clever test for modern/ancient versions. TODO: test under +// Xcode 3, where g++ is really g++. +#if defined(__APPLE__) && defined(__clang__) +# if !(defined(__has_include) && __has_include()) +# undef CRYPTOPP_CXX11 +# endif +#endif + +// C++14 macro version, https://stackoverflow.com/q/26089319/608639 +#if defined(CRYPTOPP_CXX11) && !defined(CRYPTOPP_NO_CXX14) +# if ((_MSC_VER >= 1900) || (__cplusplus >= 201402L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX14 1 +# endif +#endif + +// C++17 macro version, https://stackoverflow.com/q/38456127/608639 +#if defined(CRYPTOPP_CXX14) && !defined(CRYPTOPP_NO_CXX17) +# if ((_MSC_VER >= 1900) || (__cplusplus >= 201703L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX17 1 +# endif +#endif + +// ***************** C++11 and above ******************** + +#if defined(CRYPTOPP_CXX11) + +// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_atomic) || \ + (__INTEL_COMPILER >= 1300) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_ATOMIC 1 +#endif // atomics + +// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13. +// TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang +#if (CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 50000) || (__INTEL_COMPILER >= 1200) || \ + (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130) +// Hack ahead. New GCC compilers like GCC 6 on AIX 7.0 or earlier as well as original MinGW +// don't have the synchronization gear. However, Wakely's test used for Apple does not work +// on the GCC/AIX combination. Another twist is we need other stuff from C++11, +// like no-except destructors. Dumping preprocessors shows the following may +// apply: http://stackoverflow.com/q/14191566/608639. +# include +# if !defined(__GLIBCXX__) || defined(_GLIBCXX_HAS_GTHREADS) +# define CRYPTOPP_CXX11_SYNCHRONIZATION 1 +# endif +#endif // synchronization + +// Dynamic Initialization and Destruction with Concurrency ("Magic Statics") +// MS at VS2015 with Vista (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13. +// Microsoft's implementation only works for Vista and above, so its further +// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709 +// Clang may not support this as early as we indicate. Also see https://bugs.llvm.org/show_bug.cgi?id=47012. +#if (__cpp_threadsafe_static_init >= 200806) || \ + (CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600) || (_WIN32_WINNT >= 0x0600)) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || \ + (__INTEL_COMPILER >= 1110) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_STATIC_INIT 1 +#endif // Dynamic Initialization compilers + +// deleted functions: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1210) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_DELETED_FUNCTIONS 1 +#endif // deleted functions + +// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignas) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40800) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNAS 1 +#endif // alignas + +// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignof) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40500) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#endif // alignof + +// initializer lists: MS at VS2013 (18.00); GCC at 4.4; Clang at 3.1; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_INITIALIZER_LIST 1 +#endif // alignas + +// lambdas: MS at VS2012 (17.00); GCC at 4.9; Clang at 3.3; Intel 12.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_lambdas) || \ + (__INTEL_COMPILER >= 1200) || (CRYPTOPP_GCC_VERSION >= 40900) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_LAMBDA 1 +#endif // lambdas + +// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_noexcept) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_NOEXCEPT 1 +#endif // noexcept compilers + +// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. +#if (__cpp_variadic_templates >= 200704) || __has_feature(cxx_variadic_templates) || \ + (CRYPTOPP_MSC_VERSION >= 1800) || (__INTEL_COMPILER >= 1210) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 +#endif // variadic templates + +// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13. +// Intel has mis-supported the feature since at least ICPC 13.00 +#if (__cpp_constexpr >= 200704) || __has_feature(cxx_constexpr) || \ + (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1600) || \ + (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_CONSTEXPR 1 +#endif // constexpr compilers + +// strong typed enums: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Intel 14.0; SunCC 5.12. +// Mircorosft and Intel had partial support earlier, but we require full support. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_strong_enums) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5120) +# define CRYPTOPP_CXX11_STRONG_ENUM 1 +#endif // constexpr compilers + +// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1600) || __has_feature(cxx_nullptr) || \ + (__INTEL_COMPILER >= 1000) || (CRYPTOPP_GCC_VERSION >= 40600) || \ + (__SUNPRO_CC >= 0x5130) || defined(__IBMCPP_NULLPTR) +# define CRYPTOPP_CXX11_NULLPTR 1 +#endif // nullptr_t compilers + +#endif // CRYPTOPP_CXX11 + +// ***************** C++14 and above ******************** + +#if defined(CRYPTOPP_CXX14) + +// Extended static_assert with one argument +// Microsoft cannot handle the single argument static_assert as of VS2019 (cl.exe 19.00) +#if (__cpp_static_assert >= 201411) +# define CRYPTOPP_CXX17_STATIC_ASSERT 1 +#endif // static_assert + +#endif + +// ***************** C++17 and above ******************** + +// C++17 is available +#if defined(CRYPTOPP_CXX17) + +// C++17 uncaught_exceptions: MS at VS2015 (19.00); GCC at 6.0; Clang at 3.5; Intel 18.0. +// Clang and __EXCEPTIONS see http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html +// Also see https://github.com/weidai11/cryptopp/issues/980. I'm not sure what +// to do when the compiler defines __cpp_lib_uncaught_exceptions but the platform +// does not support std::uncaught_exceptions. What was Apple thinking??? +#if defined(__clang__) +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# if __cpp_lib_uncaught_exceptions >= 201411L +# define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1 +# endif +# endif +#elif (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1800) || \ + (CRYPTOPP_GCC_VERSION >= 60000) || (__cpp_lib_uncaught_exceptions >= 201411L) +# define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1 +#endif // uncaught_exceptions compilers + +#endif // CRYPTOPP_CXX17 + +// ***************** C++ fixups ******************** + +#if defined(CRYPTOPP_CXX11_NOEXCEPT) +# define CRYPTOPP_THROW noexcept(false) +# define CRYPTOPP_NO_THROW noexcept(true) +#else +# define CRYPTOPP_THROW +# define CRYPTOPP_NO_THROW +#endif // CRYPTOPP_CXX11_NOEXCEPT + +// Hack... C++11 nullptr_t type safety and analysis +#if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR) +# define NULLPTR nullptr +#elif !defined(NULLPTR) +# define NULLPTR NULL +#endif // CRYPTOPP_CXX11_NULLPTR + +#endif // CRYPTOPP_CONFIG_CXX_H diff --git a/extension/third_party/cryptopp/config_dll.h b/extension/third_party/cryptopp/config_dll.h new file mode 100644 index 00000000..94827616 --- /dev/null +++ b/extension/third_party/cryptopp/config_dll.h @@ -0,0 +1,178 @@ +// config_dll.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_dll.h +/// \brief Library configuration file +/// \details config_dll.h provides defines for shared objects and +/// dynamic libraries. Generally speaking the macros are used to export +/// classes and template classes from the Win32 dynamic link library. +/// When not building the Win32 dynamic link library they are mostly an extern +/// template declaration. +/// \detail In practice they are a furball coughed up by a cat and then peed +/// on by a dog. They are awful to get just right because of inconsistent +/// compiler supprt for extern templates, manual instantiation and the FIPS DLL. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_dll.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script, +/// Visual Studio, +/// and FIPS DLL +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_DLL_H +#define CRYPTOPP_CONFIG_DLL_H + +#include "config_os.h" + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_IMPORTS is set in the Visual Studio project files. + /// When the macro is set, CRYPTOPP_DLL is defined to + /// __declspec(dllimport). + /// \details This macro has no effect on Unix & Linux. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_IMPORTS ... + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_EXPORTS is set in the Visual Studio project files. + /// When the macro is set, CRYPTOPP_DLL is defined to + /// __declspec(dllexport). + /// \details This macro has no effect on Unix & Linux. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXPORTS ... + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_IS_DLL is set in the Visual Studio project files. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_IS_DLL + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_DLL_TEMPLATE_CLASS decoration should be used + /// for classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_DLL_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_STATIC_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_STATIC_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS ... + + /// \brief Override for internal linkage + /// \details CRYPTOPP_TABLE can be used to override internal linkage + /// on tables with the const qualifier. According to C++ rules + /// a decalration with const qualifier is internal linkage. + /// \note The name CRYPTOPP_TABLE was chosen because it is often used to + /// export a table, like AES or SHA constants. The name avoids collisions + /// with the DLL gear macros, like CRYPTOPP_EXPORTS and CRYPTOPP_EXTERN. + #define CRYPTOPP_TABLE extern + + /// \brief Win32 calling convention + /// \details CRYPTOPP_API sets the calling convention on Win32. + /// On Win32 CRYPTOPP_API is __cedcl. On Unix & Linux + /// CRYPTOPP_API is defined to nothing. + /// \sa Visual Studio + /// on the Crypto++ wiki + #define CRYPTOPP_API ... + +#else // CRYPTOPP_DOXYGEN_PROCESSING + +#if defined(CRYPTOPP_WIN32_AVAILABLE) + + #if defined(CRYPTOPP_EXPORTS) + # define CRYPTOPP_IS_DLL + # define CRYPTOPP_DLL __declspec(dllexport) + #elif defined(CRYPTOPP_IMPORTS) + # define CRYPTOPP_IS_DLL + # define CRYPTOPP_DLL __declspec(dllimport) + #else + # define CRYPTOPP_DLL + #endif + + // C++ makes const internal linkage + #define CRYPTOPP_TABLE extern + #define CRYPTOPP_API __cdecl + +#else // not CRYPTOPP_WIN32_AVAILABLE + + // C++ makes const internal linkage + #define CRYPTOPP_TABLE extern + #define CRYPTOPP_DLL + #define CRYPTOPP_API + +#endif // CRYPTOPP_WIN32_AVAILABLE + +#if defined(__MWERKS__) +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +# define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS +#endif + +#if defined(__MWERKS__) +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class +#else +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS) +# define CRYPTOPP_STATIC_TEMPLATE_CLASS template class +#else +# define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#endif // CRYPTOPP_CONFIG_DLL_H diff --git a/extension/third_party/cryptopp/config_int.h b/extension/third_party/cryptopp/config_int.h new file mode 100644 index 00000000..2f74480f --- /dev/null +++ b/extension/third_party/cryptopp/config_int.h @@ -0,0 +1,253 @@ +// config_int.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_int.h +/// \brief Library configuration file +/// \details config_int.h provides defines and typedefs for fixed +/// size integers. The library's choices for fixed size integers predates other +/// standard-based integers by about 5 years. After fixed sizes were +/// made standard, the library continued to use its own definitions for +/// compatibility with previous versions of the library. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_int.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_INT_H +#define CRYPTOPP_CONFIG_INT_H + +#include "config_ns.h" +#include "config_ver.h" + +/// \brief Library byte guard +/// \details CRYPTOPP_NO_GLOBAL_BYTE indicates byte is in the Crypto++ +/// namespace. +/// \details The Crypto++ byte was originally in global namespace to avoid +/// ambiguity with other byte typedefs. byte was moved to CryptoPP namespace +/// at Crypto++ 6.0 due to C++17, std::byte and potential compile problems. +/// \sa Issue 442, +/// std::byte on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +#define CRYPTOPP_NO_GLOBAL_BYTE 1 + +NAMESPACE_BEGIN(CryptoPP) + +// Signed words added at Issue 609 for early versions of and Visual Studio and +// the NaCl gear. Also see https://github.com/weidai11/cryptopp/issues/609. + +/// \brief 8-bit unsigned datatype +/// \details The Crypto++ byte was originally in global namespace to avoid +/// ambiguity with other byte typedefs. byte was moved to CryptoPP namespace +/// at Crypto++ 6.0 due to C++17, std::byte and potential compile problems. +/// \sa CRYPTOPP_NO_GLOBAL_BYTE, Issue 442, +/// std::byte on the +/// Crypto++ wiki +/// \since Crypto++ 1.0, CryptoPP namespace since Crypto++ 6.0 +typedef unsigned char byte; +/// \brief 16-bit unsigned datatype +/// \since Crypto++ 1.0 +typedef unsigned short word16; +/// \brief 32-bit unsigned datatype +/// \since Crypto++ 1.0 +typedef unsigned int word32; + +/// \brief 8-bit signed datatype +/// \details The 8-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed char sbyte; +/// \brief 16-bit signed datatype +/// \details The 32-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed short sword16; +/// \brief 32-bit signed datatype +/// \details The 32-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed int sword32; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief 64-bit unsigned datatype + /// \details The typedef for word64 varies depending on the platform. + /// On Microsoft platforms it is unsigned __int64. On Unix & Linux + /// with LP64 data model it is unsigned long. On Unix & Linux with ILP32 + /// data model it is unsigned long long. + /// \since Crypto++ 1.0 + typedef unsigned long long word64; + + /// \brief 64-bit signed datatype + /// \details The typedef for sword64 varies depending on the platform. + /// On Microsoft platforms it is signed __int64. On Unix & Linux + /// with LP64 data model it is signed long. On Unix & Linux with ILP32 + /// data model it is signed long long. + /// \since Crypto++ 8.0 + typedef signed long long sword64; + + /// \brief 128-bit unsigned datatype + /// \details The typedef for word128 varies depending on the platform. + /// word128 is only available on 64-bit machines when + /// CRYPTOPP_WORD128_AVAILABLE is defined. + /// On Unix & Linux with LP64 data model it is __uint128_t. + /// Microsoft platforms do not provide a 128-bit integer type. 32-bit platforms + /// do not provide a 128-bit integer type. + /// \since Crypto++ 5.6 + typedef __uint128_t word128; + + /// \brief Declare an unsigned word64 + /// \details W64LIT is used to portability declare or assign 64-bit literal values. + /// W64LIT will append the proper suffix to ensure the compiler accepts the literal. + /// \details Use the macro like shown below. + ///

+	///    word64 x = W64LIT(0xffffffffffffffff);
+	///  
+ /// \since Crypto++ 1.0 + #define W64LIT(x) ... + + /// \brief Declare a signed word64 + /// \details SW64LIT is used to portability declare or assign 64-bit literal values. + /// SW64LIT will append the proper suffix to ensure the compiler accepts the literal. + /// \details Use the macro like shown below. + ///
+	///    sword64 x = SW64LIT(0xffffffffffffffff);
+	///  
+ /// \since Crypto++ 8.0 + #define SW64LIT(x) ... + + /// \brief Declare ops on word64 are slow + /// \details CRYPTOPP_BOOL_SLOW_WORD64 is typically defined to 1 on platforms + /// that have a machine word smaller than 64-bits. That is, the define + /// is present on 32-bit platforms. The define is also present on platforms + /// where the cpu is slow even with a 64-bit cpu. + #define CRYPTOPP_BOOL_SLOW_WORD64 ... + +#elif defined(_MSC_VER) || defined(__BORLANDC__) + typedef signed __int64 sword64; + typedef unsigned __int64 word64; + #define SW64LIT(x) x##i64 + #define W64LIT(x) x##ui64 +#elif (_LP64 || __LP64__) + typedef signed long sword64; + typedef unsigned long word64; + #define SW64LIT(x) x##L + #define W64LIT(x) x##UL +#else + typedef signed long long sword64; + typedef unsigned long long word64; + #define SW64LIT(x) x##LL + #define W64LIT(x) x##ULL +#endif + +/// \brief Large word type +/// \details lword is a typedef for large word types. It is used for file +/// offsets and such. +typedef word64 lword; + +/// \brief Large word type max value +/// \details LWORD_MAX is the maximum value for large word types. +/// Since an lword is an unsigned type, the value is +/// 0xffffffffffffffff. W64LIT will append the proper suffix. +const lword LWORD_MAX = W64LIT(0xffffffffffffffff); + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Half word used for multiprecision integer arithmetic + /// \details hword is used for multiprecision integer arithmetic. + /// The typedef for hword varies depending on the platform. + /// On 32-bit platforms it is usually word16. On 64-bit platforms + /// it is usually word32. + /// \details Library users typically use byte, word16, word32 and word64. + /// \since Crypto++ 2.0 + typedef word32 hword; + /// \brief Full word used for multiprecision integer arithmetic + /// \details word is used for multiprecision integer arithmetic. + /// The typedef for word varies depending on the platform. + /// On 32-bit platforms it is usually word32. On 64-bit platforms + /// it is usually word64. + /// \details Library users typically use byte, word16, word32 and word64. + /// \since Crypto++ 2.0 + typedef word64 word; + /// \brief Double word used for multiprecision integer arithmetic + /// \details dword is used for multiprecision integer arithmetic. + /// The typedef for dword varies depending on the platform. + /// On 32-bit platforms it is usually word64. On 64-bit Unix & + /// Linux platforms it is usually word128. word128 is + /// not available on Microsoft platforms. word128 is only available + /// when CRYPTOPP_WORD128_AVAILABLE is defined. + /// \details Library users typically use byte, word16, word32 and word64. + /// \sa CRYPTOPP_WORD128_AVAILABLE + /// \since Crypto++ 2.0 + typedef word128 dword; + + /// \brief 128-bit word availability + /// \details CRYPTOPP_WORD128_AVAILABLE indicates a 128-bit word is + /// available from the platform. 128-bit words are usually available on + /// 64-bit platforms, but not available 32-bit platforms. + /// \details If CRYPTOPP_WORD128_AVAILABLE is not defined, then 128-bit + /// words are not available. + /// \details GCC and compatible compilers signal 128-bit word availability + /// with the preporcessor macro __SIZEOF_INT128__ >= 16. + /// \since Crypto++ 2.0 + #define CRYPTOPP_WORD128_AVAILABLE ... +#else + // define hword, word, and dword. these are used for multiprecision integer arithmetic + // Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx + #if (defined(_MSC_VER) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(__alpha__)) || (defined(__INTEL_COMPILER) && defined(__x86_64__)) || (defined(__SUNPRO_CC) && defined(__x86_64__)) + typedef word32 hword; + typedef word64 word; + #else + #define CRYPTOPP_NATIVE_DWORD_AVAILABLE 1 + #if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || defined(__x86_64__) || defined(__mips64) || defined(__sparc64__) || defined(__aarch64__) + #if ((CRYPTOPP_GCC_VERSION >= 30400) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) && (__SIZEOF_INT128__ >= 16) + // GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3 + // GCC 4.8.3 and bad uint128_t ops on PPC64/POWER7 (Issue 421) + // mode(TI) division broken on amd64 with GCC earlier than GCC 3.4 + typedef word32 hword; + typedef word64 word; + typedef __uint128_t dword; + typedef __uint128_t word128; + #define CRYPTOPP_WORD128_AVAILABLE 1 + #else + // if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif + #else + // being here means the native register size is probably 32 bits or less + #define CRYPTOPP_BOOL_SLOW_WORD64 1 + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif + #endif +#endif + +#ifndef CRYPTOPP_BOOL_SLOW_WORD64 +# define CRYPTOPP_BOOL_SLOW_WORD64 0 +#endif + +/// \brief Size of a platform word in bytes +/// \details The size of a platform word, in bytes +const unsigned int WORD_SIZE = sizeof(word); + +/// \brief Size of a platform word in bits +/// \details The size of a platform word, in bits +const unsigned int WORD_BITS = WORD_SIZE * 8; + +NAMESPACE_END + +#endif // CRYPTOPP_CONFIG_INT_H diff --git a/extension/third_party/cryptopp/config_misc.h b/extension/third_party/cryptopp/config_misc.h new file mode 100644 index 00000000..e59065a2 --- /dev/null +++ b/extension/third_party/cryptopp/config_misc.h @@ -0,0 +1,191 @@ +// config_misc.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_misc.h +/// \brief Library configuration file +/// \details config_misc.h provides miscellaneous defines. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_misc.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_MISC_H +#define CRYPTOPP_CONFIG_MISC_H + +#include "config_asm.h" +#include "config_cxx.h" +#include "config_os.h" +#include "config_ver.h" + +// Define this if running on a big-endian CPU +// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 +#if !defined(CRYPTOPP_LITTLE_ENDIAN) && !defined(CRYPTOPP_BIG_ENDIAN) && (defined(__BIG_ENDIAN__) || (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || (defined(__m68k__) || defined(__MC68K__)) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__MIPSEB__) || defined(__ARMEB__) || (defined(__MWERKS__) && !defined(__INTEL__))) +# define CRYPTOPP_BIG_ENDIAN 1 +#endif + +// Define this if running on a little-endian CPU +// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 +#if !defined(CRYPTOPP_BIG_ENDIAN) && !defined(CRYPTOPP_LITTLE_ENDIAN) +# define CRYPTOPP_LITTLE_ENDIAN 1 +#endif + +// Define this if you want to set a prefix for TestData/ and TestVectors/ +// Be sure to add the trailing slash since its simple concatenation. +// After https://github.com/weidai11/cryptopp/issues/760 the library +// should find the test vectors and data without much effort. It +// will search in "./" and "$ORIGIN/../share/cryptopp" automatically. +#ifndef CRYPTOPP_DATA_DIR +# define CRYPTOPP_DATA_DIR "" +#endif + +// Define this to disable the test suite from searching for test +// vectors and data in "./" and "$ORIGIN/../share/cryptopp". The +// library will still search in CRYPTOPP_DATA_DIR, regardless. +// Some distros may want to disable this feature. Also see +// https://github.com/weidai11/cryptopp/issues/760 +// #ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH +// # define CRYPTOPP_DISABLE_DATA_DIR_SEARCH +// #endif + +// Define this if you want or need the library's memcpy_s and memmove_s. +// See http://github.com/weidai11/cryptopp/issues/28. +// #if !defined(CRYPTOPP_WANT_SECURE_LIB) +// # define CRYPTOPP_WANT_SECURE_LIB +// #endif + +// Define this if ARMv8 shifts are slow. ARM Cortex-A53 and Cortex-A57 shift +// operation perform poorly, so NEON and ASIMD code that relies on shifts +// or rotates often performs worse than C/C++ code. Also see +// http://github.com/weidai11/cryptopp/issues/367. +#define CRYPTOPP_SLOW_ARMV8_SHIFT 1 + +// CRYPTOPP_DEBUG enables the library's CRYPTOPP_ASSERT. CRYPTOPP_ASSERT +// raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). CRYPTOPP_ASSERT +// is only in effect when CRYPTOPP_DEBUG, DEBUG or _DEBUG is defined. Unlike +// Posix assert, CRYPTOPP_ASSERT is not affected by NDEBUG (or failure to +// define it). +// Also see http://github.com/weidai11/cryptopp/issues/277, CVE-2016-7420 +#if (defined(DEBUG) || defined(_DEBUG)) && !defined(CRYPTOPP_DEBUG) +# define CRYPTOPP_DEBUG 1 +#endif + +// File system code to use when creating GZIP archive. +// http://www.gzip.org/format.txt +#if !defined(GZIP_OS_CODE) +# if defined(__macintosh__) +# define GZIP_OS_CODE 7 +# elif defined(__unix__) || defined(__linux__) +# define GZIP_OS_CODE 3 +# else +# define GZIP_OS_CODE 0 +# endif +#endif + +// Try this if your CPU has 256K internal cache or a slow multiply instruction +// and you want a (possibly) faster IDEA implementation using log tables +// #define IDEA_LARGECACHE + +// Define this if, for the linear congruential RNG, you want to use +// the original constants as specified in S.K. Park and K.W. Miller's +// CACM paper. +// #define LCRNG_ORIGINAL_NUMBERS + +// Define this if you want Integer's operator<< to honor std::showbase (and +// std::noshowbase). If defined, Integer will use a suffix of 'b', 'o', 'h' +// or '.' (the last for decimal) when std::showbase is in effect. If +// std::noshowbase is set, then the suffix is not added to the Integer. If +// not defined, existing behavior is preserved and Integer will use a suffix +// of 'b', 'o', 'h' or '.' (the last for decimal). +// #define CRYPTOPP_USE_STD_SHOWBASE + +// Define this if you want to decouple AlgorithmParameters and Integer +// The decoupling should make it easier for the linker to remove Integer +// related code for those who do not need Integer, and avoid a potential +// race during AssignIntToInteger pointer initialization. Also +// see http://github.com/weidai11/cryptopp/issues/389. +// #define CRYPTOPP_NO_ASSIGN_TO_INTEGER + +// Need GCC 4.6/Clang 1.7/Apple Clang 2.0 or above due to "GCC diagnostic {push|pop}" +#if (CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_LLVM_CLANG_VERSION >= 10700) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 20000) + #define CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE 1 +#endif + +// Portable way to suppress warnings. +// Moved from misc.h due to circular depenedencies. +#ifndef CRYPTOPP_UNUSED + #define CRYPTOPP_UNUSED(x) ((void)(x)) +#endif + +// how to disable inlining +#if defined(_MSC_VER) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __declspec(noinline) +#elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#elif defined(__GNUC__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#else +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE +#endif + +// http://stackoverflow.com/a/13867690/608639 +#if defined(CRYPTOPP_CXX11_CONSTEXPR) +# define CRYPTOPP_STATIC_CONSTEXPR static constexpr +# define CRYPTOPP_CONSTEXPR constexpr +#else +# define CRYPTOPP_STATIC_CONSTEXPR static +# define CRYPTOPP_CONSTEXPR +#endif // CRYPTOPP_CXX11_CONSTEXPR + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +# define CRYPTOPP_CONSTANT(x) static const int x +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) +# define CRYPTOPP_CONSTANT(x) enum : int { x } +#elif defined(CRYPTOPP_CXX11_CONSTEXPR) +# define CRYPTOPP_CONSTANT(x) constexpr static int x +#else +# define CRYPTOPP_CONSTANT(x) static const int x +#endif + +// Warnings +#ifdef _MSC_VER + // 4127: conditional expression is constant + // 4512: assignment operator not generated + // 4661: no suitable definition provided for explicit template instantiation request + // 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation +# pragma warning(disable: 4127 4512 4661 4910) + // _MSC_VER 1920 is VS2019 +# if _MSC_VER >= 1920 + // 5054: operator '|': deprecated between enumerations of different types +# pragma warning(disable: 5054) +# endif + // Security related, possible defects + // http://blogs.msdn.com/b/vcblog/archive/2010/12/14/off-by-default-compiler-warnings-in-visual-c.aspx +# pragma warning(once: 4191 4242 4263 4264 4266 4302 4826 4905 4906 4928) +#endif + +#ifdef __BORLANDC__ +// 8037: non-const function called for const object. needed to work around BCB2006 bug +# pragma warn -8037 +#endif + +// [GCC Bug 53431] "C++ preprocessor ignores #pragma GCC diagnostic". Clang honors it. +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunknown-pragmas" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#endif // CRYPTOPP_CONFIG_MISC_H diff --git a/extension/third_party/cryptopp/config_ns.h b/extension/third_party/cryptopp/config_ns.h new file mode 100644 index 00000000..9fa3a3cb --- /dev/null +++ b/extension/third_party/cryptopp/config_ns.h @@ -0,0 +1,76 @@ +// config_ns.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_ns.h +/// \brief Library configuration file +/// \details config_ns.h provides defines for C++ and library +/// namespaces. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_ns.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_NAMESPACE_H +#define CRYPTOPP_CONFIG_NAMESPACE_H + +// namespace support is now required +#ifdef NO_NAMESPACE +# error namespace support is now required +#endif + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING + +/// \namespace CryptoPP +/// \brief Crypto++ library namespace +/// \details Nearly all classes are located in the CryptoPP namespace. Within +/// the namespace, there are four additional namespaces. +///
    +///
  • Name - namespace for names used with NameValuePairs and documented +/// in argnames.h +///
  • NaCl - namespace for NaCl test functions like crypto_box, +/// crypto_box_open, crypto_sign, and crypto_sign_open +///
  • Donna - namespace for curve25519 library operations. The name was +/// selected due to use of Langley and Moon's curve25519-donna. +///
  • Test - namespace for testing and benchmarks classes +///
  • Weak - namespace for weak and wounded algorithms, like ARC4, MD5 +/// and Pananma +///
+/// \since Crypto++ 3.0 +namespace CryptoPP { } + +// Bring in the symbols found in the weak namespace; and fold Weak1 into Weak +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#define Weak1 Weak +// Avoid putting "CryptoPP::" in front of everything in Doxygen output +#define CryptoPP +#define NAMESPACE_BEGIN(x) +#define NAMESPACE_END +// Get Doxygen to generate better documentation for these typedefs +#define DOCUMENTED_TYPEDEF(x, y) class y : public x {} +// Make "protected" "private" so the functions and members are not documented +#define protected private + +#else +// Not Doxygen +#define NAMESPACE_BEGIN(x) namespace x { +#define NAMESPACE_END } +#define DOCUMENTED_TYPEDEF(x, y) typedef x y + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#define ANONYMOUS_NAMESPACE_BEGIN namespace { +#define ANONYMOUS_NAMESPACE_END } +#define USING_NAMESPACE(x) using namespace x; +#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x { +#define DOCUMENTED_NAMESPACE_END } + +#endif // CRYPTOPP_CONFIG_NAMESPACE_H diff --git a/extension/third_party/cryptopp/config_os.h b/extension/third_party/cryptopp/config_os.h new file mode 100644 index 00000000..da27de22 --- /dev/null +++ b/extension/third_party/cryptopp/config_os.h @@ -0,0 +1,168 @@ +// config_os.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_os.h +/// \brief Library configuration file +/// \details config_os.h provides defines for platforms and operating +/// systems. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_os.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_OS_H +#define CRYPTOPP_CONFIG_OS_H + +#include "config_ver.h" + +// It is OK to remove the hard stop below, but you are on your own. +// After building the library be sure to run self tests described +// https://www.cryptopp.com/wiki/Release_Process#Self_Tests +// Some relevant bug reports can be found at: +// * Clang: http://github.com/weidai11/cryptopp/issues/147 +#if (defined(_MSC_VER) && defined(__clang__) && !(defined( __clang_analyzer__))) +# error: "Unsupported configuration" +#endif + +// Windows platform +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#define CRYPTOPP_WIN32_AVAILABLE +#endif + +// Unix and Linux platforms +#if defined(__unix__) || defined(__MACH__) || defined(__NetBSD__) || defined(__sun) +#define CRYPTOPP_UNIX_AVAILABLE +#endif + +// BSD platforms +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#define CRYPTOPP_BSD_AVAILABLE +#endif + +// Microsoft compilers +#if defined(_MSC_VER) || defined(__fastcall) + #define CRYPTOPP_FASTCALL __fastcall +#else + #define CRYPTOPP_FASTCALL +#endif + +// Microsoft compilers +#if defined(_MSC_VER) + #define CRYPTOPP_NO_VTABLE __declspec(novtable) +#else + #define CRYPTOPP_NO_VTABLE +#endif + +// Define this if you want to disable all OS-dependent features, +// such as sockets and OS-provided random number generators +// #define NO_OS_DEPENDENCE + +// Define this to use features provided by Microsoft's CryptoAPI. +// Currently the only feature used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CRYPTOAPI + +// Define this to use features provided by Microsoft's CryptoNG API. +// CryptoNG API is available in Vista and above and its cross platform, +// including desktop apps and store apps. Currently the only feature +// used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CNGAPI + +// If the user did not make a choice, then select CryptoNG if +// targeting Windows 8 or above. +#if !defined(USE_MS_CRYPTOAPI) && !defined(USE_MS_CNGAPI) +# if !defined(_USING_V110_SDK71_) && ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || \ + (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)) +# define USE_MS_CNGAPI +# else +# define USE_MS_CRYPTOAPI +# endif +#endif + +// Begin OS features, like init priorities and random numbers +#ifndef NO_OS_DEPENDENCE + +// CRYPTOPP_INIT_PRIORITY attempts to manage initialization of C++ static objects. +// Under GCC, the library uses init_priority attribute in the range +// [CRYPTOPP_INIT_PRIORITY, CRYPTOPP_INIT_PRIORITY+100]. Under Windows, +// CRYPTOPP_INIT_PRIORITY enlists "#pragma init_seg(lib)". The platforms +// with gaps are Apple and Sun because they require linker scripts. Apple and +// Sun will use the library's Singletons to initialize and acquire resources. +// Also see http://cryptopp.com/wiki/Static_Initialization_Order_Fiasco +#ifndef CRYPTOPP_INIT_PRIORITY +# define CRYPTOPP_INIT_PRIORITY 250 +#endif + +// CRYPTOPP_USER_PRIORITY is for other libraries and user code that is using Crypto++ +// and managing C++ static object creation. It is guaranteed not to conflict with +// values used by (or would be used by) the Crypto++ library. +#ifndef CRYPTOPP_USER_PRIORITY +# define CRYPTOPP_USER_PRIORITY (CRYPTOPP_INIT_PRIORITY+101) +#endif + +// Most platforms allow us to specify when to create C++ objects. Apple and Sun do not. +#if (CRYPTOPP_INIT_PRIORITY > 0) && !(defined(NO_OS_DEPENDENCE) || defined(__APPLE__) || defined(__sun__)) +# if (CRYPTOPP_GCC_VERSION >= 30000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 800) +# define HAVE_GCC_INIT_PRIORITY 1 +# elif (CRYPTOPP_MSC_VERSION >= 1310) +# define HAVE_MSC_INIT_PRIORITY 1 +# elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__) +# define HAVE_XLC_INIT_PRIORITY 1 +# endif +#endif // CRYPTOPP_INIT_PRIORITY, NO_OS_DEPENDENCE, Apple, Sun + +#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE) +# define HIGHRES_TIMER_AVAILABLE +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define THREAD_TIMER_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define THREAD_TIMER_AVAILABLE +# endif +# endif +#endif + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +# define NONBLOCKING_RNG_AVAILABLE +# define BLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +#endif + +// Cygwin/Newlib requires _XOPEN_SOURCE=600 +#if defined(CRYPTOPP_UNIX_AVAILABLE) +# define UNIX_SIGNALS_AVAILABLE 1 +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# if ((WINVER >= 0x0A00 /*_WIN32_WINNT_WIN10*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/)) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# endif +# endif +# endif +#endif + +#endif // NO_OS_DEPENDENCE + +#endif // CRYPTOPP_CONFIG_OS_H diff --git a/extension/third_party/cryptopp/config_ver.h b/extension/third_party/cryptopp/config_ver.h new file mode 100644 index 00000000..e43edc2e --- /dev/null +++ b/extension/third_party/cryptopp/config_ver.h @@ -0,0 +1,79 @@ +// config_ver.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_ver.h +/// \brief Library configuration file +/// \details config_ver.h provides defines for library and compiler +/// versions. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_ver.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_VERSION_H +#define CRYPTOPP_CONFIG_VERSION_H + +/// \brief Library major version +/// \details CRYPTOPP_MAJOR reflects the major version of the library the +/// headers came from. It is not necessarily the version of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_MAJOR 8 +/// \brief Library minor version +/// \details CRYPTOPP_MINOR reflects the minor version of the library the +/// headers came from. It is not necessarily the version of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_MINOR 4 +/// \brief Library revision number +/// \details CRYPTOPP_REVISION reflects the revision number of the library the +/// headers came from. It is not necessarily the revision of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_REVISION 0 + +/// \brief Full library version +/// \details CRYPTOPP_VERSION reflects the version of the library the headers +/// came from. It is not necessarily the version of the library built as a +/// shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_MAJOR, CRYPTOPP_MINOR, CRYPTOPP_REVISION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 5.6 +#define CRYPTOPP_VERSION 840 + +// Compiler version macros + +#if defined(__GNUC__) +# define CRYPTOPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if defined(__xlc__) || defined(__xlC__) +# define CRYPTOPP_XLC_VERSION ((__xlC__ / 256) * 10000 + (__xlC__ % 256) * 100) +#endif + +// Apple and LLVM's Clang. Apple Clang version 7.0 roughly equals LLVM Clang version 3.7 +// Also see https://gist.github.com/yamaya/2924292 +#if defined(__clang__) && defined(__apple_build_version__) +# undef CRYPTOPP_GCC_VERSION +# define CRYPTOPP_APPLE_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#elif defined(__clang__) +# undef CRYPTOPP_GCC_VERSION +# define CRYPTOPP_LLVM_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif + +#ifdef _MSC_VER +# define CRYPTOPP_MSC_VERSION (_MSC_VER) +#endif + +#endif // CRYPTOPP_CONFIG_VERSION_H diff --git a/extension/third_party/cryptopp/cpu.cpp b/extension/third_party/cryptopp/cpu.cpp new file mode 100644 index 00000000..e8251e10 --- /dev/null +++ b/extension/third_party/cryptopp/cpu.cpp @@ -0,0 +1,1292 @@ +// cpu.cpp - originally written and placed in the public domain by Wei Dai +// modified by Jeffrey Walton and the community over the years. + +#include "pch.h" +#include "config.h" + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "cpu.h" +#include "misc.h" +#include "stdcpp.h" + +// For _xgetbv on Microsoft 32-bit and 64-bit Intel platforms +// https://github.com/weidai11/cryptopp/issues/972 +#if _MSC_VER >= 1600 && (defined(_M_IX86) || defined(_M_X64)) +# include +#endif + +#ifdef _AIX +# include +#endif + +#ifdef __linux__ +# include +#endif + +// Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/ +// CRYPTOPP_GLIBC_VERSION not used because config.h is missing +#if (((__GLIBC__ * 100) + __GLIBC_MINOR__) >= 216) +# define CRYPTOPP_GETAUXV_AVAILABLE 1 +#endif + +#if CRYPTOPP_GETAUXV_AVAILABLE +# include +#else +#ifndef AT_HWCAP +# define AT_HWCAP 16 +#endif +#ifndef AT_HWCAP2 +# define AT_HWCAP2 26 +#endif +unsigned long int getauxval(unsigned long int) { return 0; } +#endif + +#if defined(__APPLE__) +# include +#endif + +// The cpu-features header and source file are located in +// "$ANDROID_NDK_ROOT/sources/android/cpufeatures". +// setenv-android.sh will copy the header and source file +// into PWD and the makefile will build it in place. +#if defined(__ANDROID__) +# include "cpu-features.h" +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +// Visual Studio 2008 and below are missing _xgetbv and _cpuidex. +// The 32-bit versions use inline ASM below. The 64-bit versions are in x64dll.asm. +#if defined(_MSC_VER) && defined(_M_X64) +extern "C" unsigned long long __fastcall XGETBV64(unsigned int); +extern "C" unsigned long long __fastcall CPUID64(unsigned int, unsigned int, unsigned int*); +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); +} + +extern "C" +{ + static jmp_buf s_jmpNoCPUID; + static void SigIllHandler(int) + { + longjmp(s_jmpNoCPUID, 1); + } +} +#endif // CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY + +ANONYMOUS_NAMESPACE_BEGIN + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + +using CryptoPP::word32; + +inline bool IsIntel(const word32 output[4]) +{ + // This is the "GenuineIntel" string + return (output[1] /*EBX*/ == 0x756e6547) && + (output[2] /*ECX*/ == 0x6c65746e) && + (output[3] /*EDX*/ == 0x49656e69); +} + +inline bool IsAMD(const word32 output[4]) +{ + // This is the "AuthenticAMD" string. + return ((output[1] /*EBX*/ == 0x68747541) && + (output[2] /*ECX*/ == 0x444D4163) && + (output[3] /*EDX*/ == 0x69746E65)) || + // Early K5's can return "AMDisbetter!" + ((output[1] /*EBX*/ == 0x69444d41) && + (output[2] /*ECX*/ == 0x74656273) && + (output[3] /*EDX*/ == 0x21726574)); +} + +inline bool IsHygon(const word32 output[4]) +{ + // This is the "HygonGenuine" string. + return (output[1] /*EBX*/ == 0x6f677948) && + (output[2] /*ECX*/ == 0x656e6975) && + (output[3] /*EDX*/ == 0x6e65476e); +} + +inline bool IsVIA(const word32 output[4]) +{ + // This is the "CentaurHauls" string. + return ((output[1] /*EBX*/ == 0x746e6543) && + (output[2] /*ECX*/ == 0x736c7561) && + (output[3] /*EDX*/ == 0x48727561)) || + // Some non-PadLock's return "VIA VIA VIA " + ((output[1] /*EBX*/ == 0x32414956) && + (output[2] /*ECX*/ == 0x32414956) && + (output[3] /*EDX*/ == 0x32414956)); +} + +#endif // X86, X32 and X64 + +#if defined(__APPLE__) + +// http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios +class AppleMachineInfo +{ +public: + enum { PowerMac=1, Mac, iPhone, iPod, iPad, AppleTV, AppleWatch }; + enum { PowerPC=1, I386, I686, X86_64, ARM32, ARMV8, ARMV84 }; + + AppleMachineInfo() : m_device(0), m_version(0), m_arch(0) + { + struct utsname systemInfo; + systemInfo.machine[0] = '\0'; + uname(&systemInfo); + + std::string machine(systemInfo.machine); + + std::string::size_type pos = machine.find_first_of("0123456789"); + if (pos != std::string::npos) + m_version = std::atoi(machine.substr(pos).c_str()); + + if (machine.find("iPhone") != std::string::npos) + { + m_device = iPhone; + if (m_version >= 6) { m_arch = ARMV8; } + else { m_arch = ARM32; } + } + else if (machine.find("iPod") != std::string::npos) + { + m_device = iPod; + if (m_version >= 6) { m_arch = ARMV8; } + else { m_arch = ARM32; } + } + else if (machine.find("iPad") != std::string::npos) + { + m_device = iPad; + if (m_version >= 5) { m_arch = ARMV8; } + else { m_arch = ARM32; } + } + else if (machine.find("PowerMac") != std::string::npos || + machine.find("Power Macintosh") != std::string::npos) + { + m_device = PowerMac; + m_arch = PowerPC; + } + else if (machine.find("Mac") != std::string::npos || + machine.find("Macintosh") != std::string::npos) + { +#if defined(__x86_64) || defined(__amd64) + m_device = Mac; + m_arch = X86_64; +#elif defined(__i386) + m_device = Mac; + m_arch = I386; +#elif defined(__i686) + m_device = Mac; + m_arch = I686; +#else + // Should never get here + m_device = Mac; + m_arch = 0; +#endif + } + else if (machine.find("AppleTV") != std::string::npos) + { + m_device = AppleTV; + if (m_version >= 4) { m_arch = ARMV8; } + else { m_arch = ARM32; } + } + else if (machine.find("AppleWatch") != std::string::npos) + { + m_device = AppleWatch; + if (m_version >= 4) { m_arch = ARMV8; } + else { m_arch = ARM32; } + } + } + + unsigned int Device() const { + return m_device; + } + + unsigned int Version() const { + return m_version; + } + + unsigned int Arch() const { + return m_arch; + } + + bool IsARM32() const { + return m_arch == ARM32; + } + + bool IsARMv8() const { + return m_arch == ARMV8; + } + + bool IsARMv84() const { + return m_arch == ARMV84; + } + +private: + unsigned int m_device, m_version, m_arch; +}; + +void GetAppleMachineInfo(unsigned int& device, unsigned int& version, unsigned int& arch) +{ +#if CRYPTOPP_CXX11_STATIC_INIT + static const AppleMachineInfo info; +#else + using CryptoPP::Singleton; + const AppleMachineInfo& info = Singleton().Ref(); +#endif + + device = info.Device(); + version = info.Version(); + arch = info.Arch(); +} + +inline bool IsAppleMachineARM32() +{ + static unsigned int arch; + if (arch == 0) + { + unsigned int unused; + GetAppleMachineInfo(unused, unused, arch); + } + return arch == AppleMachineInfo::ARM32; +} + +inline bool IsAppleMachineARMv8() +{ + static unsigned int arch; + if (arch == 0) + { + unsigned int unused; + GetAppleMachineInfo(unused, unused, arch); + } + return arch == AppleMachineInfo::ARMV8; +} + +#endif // __APPLE__ + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +// *************************** IA-32 CPUs *************************** + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + +bool CRYPTOPP_SECTION_INIT g_x86DetectionDone = false; +bool CRYPTOPP_SECTION_INIT g_hasSSE2 = false; +bool CRYPTOPP_SECTION_INIT g_hasSSSE3 = false; +bool CRYPTOPP_SECTION_INIT g_hasSSE41 = false; +bool CRYPTOPP_SECTION_INIT g_hasSSE42 = false; +bool CRYPTOPP_SECTION_INIT g_hasAESNI = false; +bool CRYPTOPP_SECTION_INIT g_hasCLMUL = false; +bool CRYPTOPP_SECTION_INIT g_hasMOVBE = false; +bool CRYPTOPP_SECTION_INIT g_hasAVX = false; +bool CRYPTOPP_SECTION_INIT g_hasAVX2 = false; +bool CRYPTOPP_SECTION_INIT g_hasADX = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA = false; +bool CRYPTOPP_SECTION_INIT g_hasRDRAND = false; +bool CRYPTOPP_SECTION_INIT g_hasRDSEED = false; +bool CRYPTOPP_SECTION_INIT g_isP4 = false; +bool CRYPTOPP_SECTION_INIT g_hasPadlockRNG = false; +bool CRYPTOPP_SECTION_INIT g_hasPadlockACE = false; +bool CRYPTOPP_SECTION_INIT g_hasPadlockACE2 = false; +bool CRYPTOPP_SECTION_INIT g_hasPadlockPHE = false; +bool CRYPTOPP_SECTION_INIT g_hasPadlockPMM = false; +word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + +// For Solaris 11 +extern bool CPU_ProbeSSE2(); + +// xcr0 is available when xgetbv is present. +// The intrinsic is broke on GCC 8.1 and earlier. Also see +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684. +word64 XGetBV(word32 num) +{ +// Visual Studio 2010 SP1 and above, 32 and 64-bit +// https://github.com/weidai11/cryptopp/issues/972 +#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) + + return _xgetbv(num); + +// Visual Studio 2008 and below, 64-bit +#elif defined(_MSC_VER) && defined(_M_X64) + + return XGETBV64(num); + +// Visual Studio 2008 and below, 32-bit +#elif defined(_MSC_VER) && defined(_M_IX86) + + word32 a=0, d=0; + __asm { + push eax + push edx + push ecx + mov ecx, num + _emit 0x0f + _emit 0x01 + _emit 0xd0 + mov a, eax + mov d, edx + pop ecx + pop edx + pop eax + } + return (static_cast(d) << 32) | a; + +// GCC 4.4 and above +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + + word32 a=0, d=0; + __asm__ + ( + "xgetbv" : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + return (static_cast(d) << 32) | a; + +// Remainder of GCC and compatibles. +#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC) + + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71659 and + // http://www.agner.org/optimize/vectorclass/read.php?i=65 + word32 a=0, d=0; + __asm__ + ( + ".byte 0x0f, 0x01, 0xd0" "\n\t" + : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + return (static_cast(d) << 32) | a; +#else + # error "Need an xgetbv function" +#endif +} + +// No inline due to Borland/Embarcadero and Issue 498 +// cpu.cpp (131): E2211 Inline assembly not allowed in inline and template functions +bool CpuId(word32 func, word32 subfunc, word32 output[4]) +{ +// Visual Studio 2010 and above, 32 and 64-bit +#if defined(_MSC_VER) && (_MSC_VER >= 1600) + + __cpuidex((int *)output, func, subfunc); + return true; + +// Visual Studio 2008 and below, 64-bit +#elif defined(_MSC_VER) && defined(_M_X64) + + CPUID64(func, subfunc, output); + return true; + +// Visual Studio 2008 and below, 32-bit +#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__BORLANDC__) + + __try + { + // Borland/Embarcadero and Issue 500 + // Local variables for cpuid output + word32 a, b, c, d; + __asm + { + push ebx + mov eax, func + mov ecx, subfunc + cpuid + mov [a], eax + mov [b], ebx + mov [c], ecx + mov [d], edx + pop ebx + } + output[0] = a; + output[1] = b; + output[2] = c; + output[3] = d; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + + return true; + +// Linux, Unix, OS X, Solaris, Cygwin, MinGW +#else + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + +# ifndef __MINGW32__ + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask) != 0) + { + signal(SIGILL, oldHandler); + return false; + } +# endif + + if (setjmp(s_jmpNoCPUID)) + result = false; + else + { + asm volatile + ( + // save ebx in case -fPIC is being used +# if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx" +# else + "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" +# endif + : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3]) + : "a" (func), "c" (subfunc) + : "cc" + ); + } + +# ifndef __MINGW32__ + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); +# endif + + signal(SIGILL, oldHandler); + return result; +#endif +} + +void DetectX86Features() +{ + // Coverity finding CID 171239. Initialize arrays. + // Indexes: EAX=0, EBX=1, ECX=2, EDX=3 + word32 cpuid0[4]={0}, cpuid1[4]={0}, cpuid2[4]={0}; + +#if defined(CRYPTOPP_DISABLE_ASM) + // Not available + goto done; +#else + if (!CpuId(0, 0, cpuid0)) + goto done; + if (!CpuId(1, 0, cpuid1)) + goto done; +#endif + + CRYPTOPP_CONSTANT(EAX_REG = 0); + CRYPTOPP_CONSTANT(EBX_REG = 1); + CRYPTOPP_CONSTANT(ECX_REG = 2); + CRYPTOPP_CONSTANT(EDX_REG = 3); + + CRYPTOPP_CONSTANT(MMX_FLAG = (1 << 24)); // EDX + CRYPTOPP_CONSTANT(SSE_FLAG = (1 << 25)); // EDX + CRYPTOPP_CONSTANT(SSE2_FLAG = (1 << 26)); // EDX + + CRYPTOPP_CONSTANT(SSE3_FLAG = (1 << 0)); // ECX + CRYPTOPP_CONSTANT(SSSE3_FLAG = (1 << 9)); // ECX + CRYPTOPP_CONSTANT(SSE41_FLAG = (1 << 19)); // ECX + CRYPTOPP_CONSTANT(SSE42_FLAG = (1 << 20)); // ECX + CRYPTOPP_CONSTANT(MOVBE_FLAG = (1 << 22)); // ECX + CRYPTOPP_CONSTANT(AESNI_FLAG = (1 << 25)); // ECX + CRYPTOPP_CONSTANT(CLMUL_FLAG = (1 << 1)); // ECX + + CRYPTOPP_CONSTANT(XSAVE_FLAG = (1 << 26)); // ECX + CRYPTOPP_CONSTANT(OSXSAVE_FLAG = (1 << 27)); // ECX + + CRYPTOPP_CONSTANT(AVX_FLAG = (3 << 27)); // ECX + CRYPTOPP_CONSTANT(YMM_FLAG = (3 << 1)); // CR0 + + // x86_64 machines don't check some flags because SSE2 + // is part of the core instruction set architecture + CRYPTOPP_UNUSED(MMX_FLAG); CRYPTOPP_UNUSED(SSE_FLAG); + CRYPTOPP_UNUSED(SSE3_FLAG); CRYPTOPP_UNUSED(XSAVE_FLAG); + +#if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + // 64-bit core instruction set includes SSE2. Just check + // the OS enabled SSE2 support using OSXSAVE. + g_hasSSE2 = (cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0; +#else + // Check the processor supports SSE2. Then use OSXSAVE to + // signal OS support for SSE2 to avoid probes. + // Also see http://stackoverflow.com/a/22521619/608639 + // and http://github.com/weidai11/cryptopp/issues/511. + if ((cpuid1[EDX_REG] & SSE2_FLAG) == SSE2_FLAG) + g_hasSSE2 = (cpuid1[ECX_REG] & XSAVE_FLAG) != 0 && + (cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0; +#endif + + // Solaris 11 i86pc does not signal SSE support using + // OSXSAVE. We need to probe for SSE support. + if (g_hasSSE2 == false) + g_hasSSE2 = CPU_ProbeSSE2(); + + if (g_hasSSE2 == false) + goto done; + + g_hasSSSE3 = (cpuid1[ECX_REG] & SSSE3_FLAG) != 0; + g_hasSSE41 = (cpuid1[ECX_REG] & SSE41_FLAG) != 0; + g_hasSSE42 = (cpuid1[ECX_REG] & SSE42_FLAG) != 0; + g_hasMOVBE = (cpuid1[ECX_REG] & MOVBE_FLAG) != 0; + g_hasAESNI = (cpuid1[ECX_REG] & AESNI_FLAG) != 0; + g_hasCLMUL = (cpuid1[ECX_REG] & CLMUL_FLAG) != 0; + + // AVX is similar to SSE. Check if AVX is available on the cpu, then + // check if the OS enabled XSAVE/XRESTORE for the extended registers. + // https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled + if ((cpuid1[ECX_REG] & AVX_FLAG) == AVX_FLAG) + { + word64 xcr0 = XGetBV(0); + g_hasAVX = (xcr0 & YMM_FLAG) == YMM_FLAG; + } + + if (IsIntel(cpuid0)) + { + CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30)); + CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18)); + CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19)); + CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29)); + CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5)); + + g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf; + g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1); + g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0; + + if (cpuid0[EAX_REG] >= 7) + { + if (CpuId(7, 0, cpuid2)) + { + g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0; + g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0; + g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0; + g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0; + } + } + } + else if (IsAMD(cpuid0) || IsHygon(cpuid0)) + { + CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30)); + CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18)); + CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19)); + CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29)); + CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5)); + + CpuId(0x80000005, 0, cpuid2); + g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0); + g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0; + + if (cpuid0[EAX_REG] >= 7) + { + if (CpuId(7, 0, cpuid2)) + { + g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0; + g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0; + g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0; + g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0; + } + } + + // Unconditionally disable RDRAND and RDSEED on AMD cpu's with family 15h or 16h. + // See Crypto++ Issue 924, https://github.com/weidai11/cryptopp/issues/924, + // Clear RDRAND CPUID bit on AMD family 15h/16h, https://lore.kernel.org/patchwork/patch/1115413/, + // and AMD CPUID Specification, https://www.amd.com/system/files/TechDocs/25481.pdf + { + CRYPTOPP_CONSTANT(FAMILY_BASE_FLAG = (0x0f << 8)); + CRYPTOPP_CONSTANT(FAMILY_EXT_FLAG = (0xff << 20)); + + word32 family = (cpuid1[0] & FAMILY_BASE_FLAG) >> 8; + if (family == 0xf) + family += (cpuid1[0] & FAMILY_EXT_FLAG) >> 20; + if (family == 0x15 || family == 0x16) + { + g_hasRDRAND = false; + g_hasRDSEED = false; + } + } + } + else if (IsVIA(cpuid0)) + { + // Two bits: available and enabled + CRYPTOPP_CONSTANT( RNG_FLAGS = (0x3 << 2)); + CRYPTOPP_CONSTANT( ACE_FLAGS = (0x3 << 6)); + CRYPTOPP_CONSTANT(ACE2_FLAGS = (0x3 << 8)); + CRYPTOPP_CONSTANT( PHE_FLAGS = (0x3 << 10)); + CRYPTOPP_CONSTANT( PMM_FLAGS = (0x3 << 12)); + + CpuId(0xC0000000, 0, cpuid2); + word32 extendedFeatures = cpuid2[0]; + + if (extendedFeatures >= 0xC0000001) + { + CpuId(0xC0000001, 0, cpuid2); + g_hasPadlockRNG = (cpuid2[EDX_REG] & RNG_FLAGS) != 0; + g_hasPadlockACE = (cpuid2[EDX_REG] & ACE_FLAGS) != 0; + g_hasPadlockACE2 = (cpuid2[EDX_REG] & ACE2_FLAGS) != 0; + g_hasPadlockPHE = (cpuid2[EDX_REG] & PHE_FLAGS) != 0; + g_hasPadlockPMM = (cpuid2[EDX_REG] & PMM_FLAGS) != 0; + } + + if (extendedFeatures >= 0xC0000005) + { + CpuId(0xC0000005, 0, cpuid2); + g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0); + } + } + + // Keep AVX2 in sync with OS support for AVX. AVX tests both + // cpu support and OS support, while AVX2 only tests cpu support. + g_hasAVX2 &= g_hasAVX; + +done: + +#if defined(_SC_LEVEL1_DCACHE_LINESIZE) + // Glibc does not implement on some platforms. The runtime returns 0 instead of error. + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c + int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (g_cacheLineSize == 0 && cacheLineSize > 0) + g_cacheLineSize = cacheLineSize; +#endif + + if (g_cacheLineSize == 0) + g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + + *const_cast(&g_x86DetectionDone) = true; +} + +// *************************** ARM-32, Aarch32 and Aarch64 *************************** + +#elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) + +bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false; +bool CRYPTOPP_SECTION_INIT g_hasARMv7 = false; +bool CRYPTOPP_SECTION_INIT g_hasNEON = false; +bool CRYPTOPP_SECTION_INIT g_hasPMULL = false; +bool CRYPTOPP_SECTION_INIT g_hasCRC32 = false; +bool CRYPTOPP_SECTION_INIT g_hasAES = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA1 = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA3 = false; +bool CRYPTOPP_SECTION_INIT g_hasSM3 = false; +bool CRYPTOPP_SECTION_INIT g_hasSM4 = false; +word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + +// ARM does not have an unprivileged equivalent to CPUID on IA-32. We have to +// jump through some hoops to detect features on a wide array of platforms. +// Our strategy is two part. First, attempt to *Query* the OS for a feature, +// like using getauxval on Linux. If that fails, then *Probe* the cpu +// executing an instruction and an observe a SIGILL if unsupported. The probes +// are in source files where compilation options like -march=armv8-a+crc make +// intrinsics available. They are expensive when compared to a standard OS +// feature query. Always perform the feature query first. For Linux see +// http://sourceware.org/ml/libc-help/2017-08/msg00012.html +// Avoid probes on Apple platforms because Apple's signal handling for SIGILLs +// appears broken. We are trying to figure out a way to feature test without +// probes. Also see http://stackoverflow.com/a/11197770/608639 and +// http://gist.github.com/erkanyildiz/390a480f27e86f8cd6ba. + +extern bool CPU_ProbeARMv7(); +extern bool CPU_ProbeNEON(); +extern bool CPU_ProbeCRC32(); +extern bool CPU_ProbeAES(); +extern bool CPU_ProbeSHA1(); +extern bool CPU_ProbeSHA256(); +extern bool CPU_ProbeSHA512(); +extern bool CPU_ProbeSHA3(); +extern bool CPU_ProbeSM3(); +extern bool CPU_ProbeSM4(); +extern bool CPU_ProbePMULL(); + +// https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h +// https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h +#ifndef HWCAP_ARMv7 +# define HWCAP_ARMv7 (1 << 29) +#endif +#ifndef HWCAP_ASIMD +# define HWCAP_ASIMD (1 << 1) +#endif +#ifndef HWCAP_NEON +# define HWCAP_NEON (1 << 12) +#endif +#ifndef HWCAP_CRC32 +# define HWCAP_CRC32 (1 << 7) +#endif +#ifndef HWCAP2_CRC32 +# define HWCAP2_CRC32 (1 << 4) +#endif +#ifndef HWCAP_PMULL +# define HWCAP_PMULL (1 << 4) +#endif +#ifndef HWCAP2_PMULL +# define HWCAP2_PMULL (1 << 1) +#endif +#ifndef HWCAP_AES +# define HWCAP_AES (1 << 3) +#endif +#ifndef HWCAP2_AES +# define HWCAP2_AES (1 << 0) +#endif +#ifndef HWCAP_SHA1 +# define HWCAP_SHA1 (1 << 5) +#endif +#ifndef HWCAP_SHA2 +# define HWCAP_SHA2 (1 << 6) +#endif +#ifndef HWCAP2_SHA1 +# define HWCAP2_SHA1 (1 << 2) +#endif +#ifndef HWCAP2_SHA2 +# define HWCAP2_SHA2 (1 << 3) +#endif +#ifndef HWCAP_SHA3 +# define HWCAP_SHA3 (1 << 17) +#endif +#ifndef HWCAP_SM3 +# define HWCAP_SM3 (1 << 18) +#endif +#ifndef HWCAP_SM4 +# define HWCAP_SM4 (1 << 19) +#endif +#ifndef HWCAP_SHA512 +# define HWCAP_SHA512 (1 << 21) +#endif + +inline bool CPU_QueryARMv7() +{ +#if defined(__ANDROID__) && defined(__arm__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0)) + return true; +#elif defined(__linux__) && defined(__arm__) + if ((getauxval(AT_HWCAP) & HWCAP_ARMv7) != 0 || + (getauxval(AT_HWCAP) & HWCAP_NEON) != 0) + return true; +#elif defined(__APPLE__) && defined(__arm__) + // Apple hardware is ARMv7 or above. + return true; +#endif + return false; +} + +inline bool CPU_QueryNEON() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__arm__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_ASIMD) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_ASIMD) != 0) + return true; +#elif defined(__linux__) && defined(__arm__) + if ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + // Core feature set for Aarch32 and Aarch64. + return true; +#endif + return false; +} + +inline bool CPU_QueryCRC32() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_CRC32) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_CRC32) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_CRC32) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + // No compiler support. CRC intrinsics result in a failed compiled. + return false; +#endif + return false; +} + +inline bool CPU_QueryPMULL() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_PMULL) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_PMULL) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_PMULL) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_PMULL) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + // No compiler support. PMULL intrinsics result in a failed compiled. + return false; +#endif + return false; +} + +inline bool CPU_QueryAES() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_AES) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_AES) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + return IsAppleMachineARMv8(); +#endif + return false; +} + +inline bool CPU_QuerySHA1() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA1) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA1) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SHA1) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SHA1) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + return IsAppleMachineARMv8(); +#endif + return false; +} + +inline bool CPU_QuerySHA256() +{ +#if defined(__ANDROID__) && defined(__aarch64__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA2) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA2) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SHA2) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SHA2) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + return IsAppleMachineARMv8(); +#endif + return false; +} + +inline bool CPU_QuerySHA512() +{ +// Some ARMv8.4 features are disabled at the moment +#if defined(__ANDROID__) && defined(__aarch64__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA512) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA512) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SHA512) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SHA512) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) && 0 + return false; +#endif + return false; +} + +inline bool CPU_QuerySHA3() +{ +// Some ARMv8.4 features are disabled at the moment +#if defined(__ANDROID__) && defined(__aarch64__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA3) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA3) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SHA3) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SHA3) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) && 0 + return false; +#endif + return false; +} + +inline bool CPU_QuerySM3() +{ +// Some ARMv8.4 features are disabled at the moment +#if defined(__ANDROID__) && defined(__aarch64__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM3) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM3) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SM3) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SM3) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) && 0 + return false; +#endif + return false; +} + +inline bool CPU_QuerySM4() +{ +// Some ARMv8.4 features are disabled at the moment +#if defined(__ANDROID__) && defined(__aarch64__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM4) != 0)) + return true; +#elif defined(__ANDROID__) && defined(__aarch32__) && 0 + if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) && + ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM4) != 0)) + return true; +#elif defined(__linux__) && defined(__aarch64__) + if ((getauxval(AT_HWCAP) & HWCAP_SM4) != 0) + return true; +#elif defined(__linux__) && defined(__aarch32__) + if ((getauxval(AT_HWCAP2) & HWCAP2_SM4) != 0) + return true; +#elif defined(__APPLE__) && defined(__aarch64__) && 0 + return false; +#endif + return false; +} + +void DetectArmFeatures() +{ + // The CPU_ProbeXXX's return false for OSes which + // can't tolerate SIGILL-based probes + g_hasARMv7 = CPU_QueryARMv7() || CPU_ProbeARMv7(); + g_hasNEON = CPU_QueryNEON() || CPU_ProbeNEON(); + g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32(); + g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL(); + g_hasAES = CPU_QueryAES() || CPU_ProbeAES(); + g_hasSHA1 = CPU_QuerySHA1() || CPU_ProbeSHA1(); + g_hasSHA2 = CPU_QuerySHA256() || CPU_ProbeSHA256(); + g_hasSHA512 = CPU_QuerySHA512(); // || CPU_ProbeSHA512(); + g_hasSHA3 = CPU_QuerySHA3(); // || CPU_ProbeSHA3(); + g_hasSM3 = CPU_QuerySM3(); // || CPU_ProbeSM3(); + g_hasSM4 = CPU_QuerySM4(); // || CPU_ProbeSM4(); + +#if defined(_SC_LEVEL1_DCACHE_LINESIZE) + // Glibc does not implement on some platforms. The runtime returns 0 instead of error. + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c + int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (cacheLineSize > 0) + g_cacheLineSize = cacheLineSize; +#endif + + if (g_cacheLineSize == 0) + g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + + *const_cast(&g_ArmDetectionDone) = true; +} + +// *************************** PowerPC and PowerPC64 *************************** + +#elif (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +bool CRYPTOPP_SECTION_INIT g_PowerpcDetectionDone = false; +bool CRYPTOPP_SECTION_INIT g_hasAltivec = false; +bool CRYPTOPP_SECTION_INIT g_hasPower7 = false; +bool CRYPTOPP_SECTION_INIT g_hasPower8 = false; +bool CRYPTOPP_SECTION_INIT g_hasPower9 = false; +bool CRYPTOPP_SECTION_INIT g_hasAES = false; +bool CRYPTOPP_SECTION_INIT g_hasPMULL = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA256 = false; +bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false; +bool CRYPTOPP_SECTION_INIT g_hasDARN = false; +word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + +extern bool CPU_ProbeAltivec(); +extern bool CPU_ProbePower7(); +extern bool CPU_ProbePower8(); +extern bool CPU_ProbePower9(); +extern bool CPU_ProbeAES(); +extern bool CPU_ProbePMULL(); +extern bool CPU_ProbeSHA256(); +extern bool CPU_ProbeSHA512(); +extern bool CPU_ProbeDARN(); + +// AIX defines. We used to just call __power_7_andup() +// and friends but at Power9, too many compilers were +// missing __power_9_andup(). Instead we switched to +// a pattern similar to OpenSSL caps testing. +#ifndef __power_6_andup +# define __power_6_andup() __power_set(0xffffffffU<<14) +#endif +#ifndef __power_7_andup +# define __power_7_andup() __power_set(0xffffffffU<<15) +#endif +#ifndef __power_8_andup +# define __power_8_andup() __power_set(0xffffffffU<<16) +#endif +#ifndef __power_9_andup +# define __power_9_andup() __power_set(0xffffffffU<<17) +#endif + +// AIX first supported Altivec at Power6, though it +// was available much earlier for other vendors. +inline bool CPU_QueryAltivec() +{ +#if defined(__linux__) && defined(PPC_FEATURE_HAS_ALTIVEC) + if ((getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC) != 0) + return true; +#elif defined(_AIX) + if (__power_6_andup() != 0) + return true; +#elif defined(__APPLE__) && defined(__POWERPC__) + unsigned int unused, arch; + GetAppleMachineInfo(unused, unused, arch); + return arch == AppleMachineInfo::PowerMac; +#endif + return false; +} + +inline bool CPU_QueryPower7() +{ + // Power7 and ISA 2.06 +#if defined(__linux__) && defined(PPC_FEATURE_ARCH_2_06) + if ((getauxval(AT_HWCAP) & PPC_FEATURE_ARCH_2_06) != 0) + return true; +#elif defined(_AIX) + if (__power_7_andup() != 0) + return true; +#endif + return false; +} + +inline bool CPU_QueryPower8() +{ + // Power8 and ISA 2.07 provide in-core crypto. +#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_2_07) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) != 0) + return true; +#elif defined(_AIX) + if (__power_8_andup() != 0) + return true; +#endif + return false; +} + +inline bool CPU_QueryPower9() +{ + // Power9 and ISA 3.0. +#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0) + return true; +#elif defined(_AIX) + if (__power_9_andup() != 0) + return true; +#endif + return false; +} + +inline bool CPU_QueryAES() +{ + // Power8 and ISA 2.07 provide in-core crypto. Glibc + // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. +#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) + return true; +#elif defined(_AIX) + if (__power_8_andup() != 0) + return true; +#endif + return false; +} + +inline bool CPU_QueryPMULL() +{ + // Power8 and ISA 2.07 provide in-core crypto. Glibc + // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. +#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) + return true; +#elif defined(_AIX) + if (__power_8_andup() != 0) + return true; +#endif + return false; +} + +inline bool CPU_QuerySHA256() +{ + // Power8 and ISA 2.07 provide in-core crypto. Glibc + // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. +#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) + return true; +#elif defined(_AIX) + if (__power_8_andup() != 0) + return true; +#endif + return false; +} +inline bool CPU_QuerySHA512() +{ + // Power8 and ISA 2.07 provide in-core crypto. Glibc + // 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO. +#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0) + return true; +#elif defined(_AIX) + if (__power_8_andup() != 0) + return true; +#endif + return false; +} + +// Power9 random number generator +inline bool CPU_QueryDARN() +{ + // Power9 and ISA 3.0 provide DARN. +#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00) + if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0) + return true; +#elif defined(_AIX) + if (__power_9_andup() != 0) + return true; +#endif + return false; +} + +void DetectPowerpcFeatures() +{ + // GCC 10 is giving us trouble in CPU_ProbePower9() and + // CPU_ProbeDARN(). GCC is generating POWER9 instructions + // on POWER8 for ppc_power9.cpp. The compiler idiots did + // not think through the consequences of requiring us to + // use -mcpu=power9 to unlock the ISA. Epic fail. + // https://github.com/weidai11/cryptopp/issues/986 + + // The CPU_ProbeXXX's return false for OSes which + // can't tolerate SIGILL-based probes, like Apple + g_hasAltivec = CPU_QueryAltivec() || CPU_ProbeAltivec(); + g_hasPower7 = CPU_QueryPower7() || CPU_ProbePower7(); + g_hasPower8 = CPU_QueryPower8() || CPU_ProbePower8(); + g_hasPower9 = CPU_QueryPower9() || CPU_ProbePower9(); + g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL(); + g_hasAES = CPU_QueryAES() || CPU_ProbeAES(); + g_hasSHA256 = CPU_QuerySHA256() || CPU_ProbeSHA256(); + g_hasSHA512 = CPU_QuerySHA512() || CPU_ProbeSHA512(); + g_hasDARN = CPU_QueryDARN() || CPU_ProbeDARN(); + +#if defined(_AIX) && defined(SC_L1C_DLS) + // /usr/include/sys/systemcfg.h + int cacheLineSize = getsystemcfg(SC_L1C_DLS); + if (cacheLineSize > 0) + g_cacheLineSize = cacheLineSize; +#elif defined(_SC_LEVEL1_DCACHE_LINESIZE) + // Glibc does not implement on some platforms. The runtime returns 0 instead of error. + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c + int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (cacheLineSize > 0) + g_cacheLineSize = cacheLineSize; +#endif + + if (g_cacheLineSize == 0) + g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE; + + *const_cast(&g_PowerpcDetectionDone) = true; +} + +#endif +NAMESPACE_END + +// *************************** C++ Static Initialization *************************** + +ANONYMOUS_NAMESPACE_BEGIN + +class InitCpu +{ +public: + InitCpu() + { +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + CryptoPP::DetectX86Features(); +#elif CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 + CryptoPP::DetectArmFeatures(); +#elif CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 + CryptoPP::DetectPowerpcFeatures(); +#endif + } +}; + +// This is not really needed because HasSSE() and friends can dynamically initialize. +// Everything depends on CPU features so we initialize it once at load time. +// Dynamic initialization will be used if init priorities are not available. + +#if HAVE_GCC_INIT_PRIORITY + const InitCpu s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 10))) = InitCpu(); +#elif HAVE_MSC_INIT_PRIORITY + #pragma warning(disable: 4075) + #pragma init_seg(".CRT$XCU") + const InitCpu s_init; + #pragma warning(default: 4075) +#elif HAVE_XLC_INIT_PRIORITY + // XLC needs constant, not a define + #pragma priority(270) + const InitCpu s_init; +#else + const InitCpu s_init; +#endif + +ANONYMOUS_NAMESPACE_END + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/cpu.h b/extension/third_party/cryptopp/cpu.h new file mode 100644 index 00000000..41236ecc --- /dev/null +++ b/extension/third_party/cryptopp/cpu.h @@ -0,0 +1,1083 @@ +// cpu.h - originally written and placed in the public domain by Wei Dai +// updated for ARM and PowerPC by Jeffrey Walton. +// updated to split CPU_Query() and CPU_Probe() by Jeffrey Walton. + +/// \file cpu.h +/// \brief Functions for CPU features and intrinsics +/// \details The CPU functions are used in IA-32, ARM and PowerPC code paths. The +/// functions provide cpu specific feature testing on IA-32, ARM and PowerPC machines. +/// \details Feature detection uses CPUID on IA-32, like Intel and AMD. On other platforms +/// a two-part strategy is used. First, the library attempts to *Query* the OS for a feature, +/// like using Linux getauxval() or android_getCpuFeatures(). If that fails, then *Probe* +/// the cpu executing an instruction and an observe a SIGILL if unsupported. The general +/// pattern used by the library is: +///
+///    g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();
+///    g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
+///    g_hasAES  = CPU_QueryAES() || CPU_ProbeAES();
+/// 
+/// \details Generally speaking, CPU_Query() is in the source file cpu.cpp because it +/// does not require special architectural flags. CPU_Probe() is in a source file that recieves +/// architectural flags, like sse_simd.cpp, neon_simd.cpp and +/// ppc_simd.cpp. For example, compiling neon_simd.cpp on an ARM64 machine will +/// have -march=armv8-a applied during a compile to make the instruction set architecture +/// (ISA) available. +/// \details The cpu probes are expensive when compared to a standard OS feature query. The library +/// also avoids probes on Apple platforms because Apple's signal handling for SIGILLs appears to +/// corrupt memory. CPU_Probe() will unconditionally return false for Apple platforms. OpenSSL +/// experienced the same problem and moved away from SIGILL probes on Apple. + +#ifndef CRYPTOPP_CPU_H +#define CRYPTOPP_CPU_H + +#include "config.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +// Applies to both X86/X32/X64 and ARM32/ARM64 +#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) + #define NEW_LINE "\n" + #define INTEL_PREFIX ".intel_syntax;" + #define INTEL_NOPREFIX ".intel_syntax;" + #define ATT_PREFIX ".att_syntax;" + #define ATT_NOPREFIX ".att_syntax;" +#elif defined(__GNUC__) + #define NEW_LINE + #define INTEL_PREFIX ".intel_syntax prefix;" + #define INTEL_NOPREFIX ".intel_syntax noprefix;" + #define ATT_PREFIX ".att_syntax prefix;" + #define ATT_NOPREFIX ".att_syntax noprefix;" +#else + #define NEW_LINE + #define INTEL_PREFIX + #define INTEL_NOPREFIX + #define ATT_PREFIX + #define ATT_NOPREFIX +#endif + +#ifdef CRYPTOPP_GENERATE_X64_MASM + +#define CRYPTOPP_X86_ASM_AVAILABLE +#define CRYPTOPP_BOOL_X64 1 +#define CRYPTOPP_SSE2_ASM_AVAILABLE 1 +#define NAMESPACE_END + +#else + +NAMESPACE_BEGIN(CryptoPP) + +// ***************************** IA-32 ***************************** // + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_DOXYGEN_PROCESSING + +#define CRYPTOPP_CPUID_AVAILABLE 1 + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// These should not be used directly +extern CRYPTOPP_DLL bool g_x86DetectionDone; +extern CRYPTOPP_DLL bool g_hasSSE2; +extern CRYPTOPP_DLL bool g_hasSSSE3; +extern CRYPTOPP_DLL bool g_hasSSE41; +extern CRYPTOPP_DLL bool g_hasSSE42; +extern CRYPTOPP_DLL bool g_hasMOVBE; +extern CRYPTOPP_DLL bool g_hasAESNI; +extern CRYPTOPP_DLL bool g_hasCLMUL; +extern CRYPTOPP_DLL bool g_hasAVX; +extern CRYPTOPP_DLL bool g_hasAVX2; +extern CRYPTOPP_DLL bool g_hasSHA; +extern CRYPTOPP_DLL bool g_hasADX; +extern CRYPTOPP_DLL bool g_isP4; +extern CRYPTOPP_DLL bool g_hasRDRAND; +extern CRYPTOPP_DLL bool g_hasRDSEED; +extern CRYPTOPP_DLL bool g_hasPadlockRNG; +extern CRYPTOPP_DLL bool g_hasPadlockACE; +extern CRYPTOPP_DLL bool g_hasPadlockACE2; +extern CRYPTOPP_DLL bool g_hasPadlockPHE; +extern CRYPTOPP_DLL bool g_hasPadlockPMM; +extern CRYPTOPP_DLL word32 g_cacheLineSize; + +CRYPTOPP_DLL void CRYPTOPP_API DetectX86Features(); +CRYPTOPP_DLL bool CRYPTOPP_API CpuId(word32 func, word32 subfunc, word32 output[4]); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name IA-32 CPU FEATURES +//@{ + +/// \brief Determine SSE2 availability +/// \return true if SSE2 is determined to be available, false otherwise +/// \details MMX, SSE and SSE2 are core processor features for x86_64, and +/// the function return value is based on OSXSAVE. On i386 both +/// SSE2 and OSXSAVE are used for the return value. +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE2() +{ +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE2; +#else + return false; +#endif +} + +/// \brief Determine SSSE3 availability +/// \return true if SSSE3 is determined to be available, false otherwise +/// \details HasSSSE3() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSSE3() +{ +#if CRYPTOPP_SSSE3_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSSE3; +#else + return false; +#endif +} + +/// \brief Determine SSE4.1 availability +/// \return true if SSE4.1 is determined to be available, false otherwise +/// \details HasSSE41() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE41() +{ +#if CRYPTOPP_SSE41_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE41; +#else + return false; +#endif +} + +/// \brief Determine SSE4.2 availability +/// \return true if SSE4.2 is determined to be available, false otherwise +/// \details HasSSE42() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE42() +{ +#if CRYPTOPP_SSE42_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE42; +#else + return false; +#endif +} + +/// \brief Determine MOVBE availability +/// \return true if MOVBE is determined to be available, false otherwise +/// \details HasMOVBE() is a runtime check performed using CPUID +/// \since Crypto++ 8.3 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasMOVBE() +{ +#if CRYPTOPP_SSE42_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasMOVBE; +#else + return false; +#endif +} + +/// \brief Determine AES-NI availability +/// \return true if AES-NI is determined to be available, false otherwise +/// \details HasAESNI() is a runtime check performed using CPUID +/// \since Crypto++ 5.6.1 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAESNI() +{ +#if CRYPTOPP_AESNI_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAESNI; +#else + return false; +#endif +} + +/// \brief Determine Carryless Multiply availability +/// \return true if pclmulqdq is determined to be available, false otherwise +/// \details HasCLMUL() is a runtime check performed using CPUID +/// \since Crypto++ 5.6.1 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasCLMUL() +{ +#if CRYPTOPP_CLMUL_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasCLMUL; +#else + return false; +#endif +} + +/// \brief Determine SHA availability +/// \return true if SHA is determined to be available, false otherwise +/// \details HasSHA() is a runtime check performed using CPUID +/// \since Crypto++ 6.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSHA() +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSHA; +#else + return false; +#endif +} + +/// \brief Determine ADX availability +/// \return true if ADX is determined to be available, false otherwise +/// \details HasADX() is a runtime check performed using CPUID +/// \since Crypto++ 7.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasADX() +{ +#if CRYPTOPP_ADX_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasADX; +#else + return false; +#endif +} + +/// \brief Determine AVX availability +/// \return true if AVX is determined to be available, false otherwise +/// \details HasAVX() is a runtime check performed using CPUID +/// \since Crypto++ 8.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAVX() +{ +#if CRYPTOPP_AVX_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAVX; +#else + return false; +#endif +} + +/// \brief Determine AVX2 availability +/// \return true if AVX2 is determined to be available, false otherwise +/// \details HasAVX2() is a runtime check performed using CPUID +/// \since Crypto++ 8.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAVX2() +{ +#if CRYPTOPP_AVX2_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAVX2; +#else + return false; +#endif +} + +/// \brief Determine RDRAND availability +/// \return true if RDRAND is determined to be available, false otherwise +/// \details HasRDRAND() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDRAND() +{ +#if CRYPTOPP_RDRAND_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDRAND; +#else + return false; +#endif +} + +/// \brief Determine RDSEED availability +/// \return true if RDSEED is determined to be available, false otherwise +/// \details HasRDSEED() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDSEED() +{ +#if CRYPTOPP_RDSEED_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDSEED; +#else + return false; +#endif +} + +/// \brief Determine Padlock RNG availability +/// \return true if VIA Padlock RNG is determined to be available, false otherwise +/// \details HasPadlockRNG() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockRNG() +{ +#if CRYPTOPP_PADLOCK_RNG_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockRNG; +#else + return false; +#endif +} + +/// \brief Determine Padlock ACE availability +/// \return true if VIA Padlock ACE is determined to be available, false otherwise +/// \details HasPadlockACE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE() +{ +#if CRYPTOPP_PADLOCK_ACE_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE; +#else + return false; +#endif +} + +/// \brief Determine Padlock ACE2 availability +/// \return true if VIA Padlock ACE2 is determined to be available, false otherwise +/// \details HasPadlockACE2() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE2() +{ +#if CRYPTOPP_PADLOCK_ACE2_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE2; +#else + return false; +#endif +} + +/// \brief Determine Padlock PHE availability +/// \return true if VIA Padlock PHE is determined to be available, false otherwise +/// \details HasPadlockPHE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPHE() +{ +#if CRYPTOPP_PADLOCK_PHE_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPHE; +#else + return false; +#endif +} + +/// \brief Determine Padlock PMM availability +/// \return true if VIA Padlock PMM is determined to be available, false otherwise +/// \details HasPadlockPMM() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPMM() +{ +#if CRYPTOPP_PADLOCK_PMM_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPMM; +#else + return false; +#endif +} + +/// \brief Determine if the CPU is an Intel P4 +/// \return true if the CPU is a P4, false otherwise +/// \details IsP4() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool IsP4() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_isP4; +} + +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_cacheLineSize; +} +//@} + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +// ***************************** ARM-32, Aarch32 and Aarch64 ***************************** // + +#if CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_ArmDetectionDone; +extern bool g_hasARMv7; +extern bool g_hasNEON; +extern bool g_hasPMULL; +extern bool g_hasCRC32; +extern bool g_hasAES; +extern bool g_hasSHA1; +extern bool g_hasSHA2; +extern bool g_hasSHA512; +extern bool g_hasSHA3; +extern bool g_hasSM3; +extern bool g_hasSM4; +void CRYPTOPP_API DetectArmFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name ARM A-32, Aarch32 and AArch64 CPU FEATURES +//@{ + +/// \brief Determine if an ARM processor is ARMv7 or above +/// \return true if the hardware is ARMv7 or above, false otherwise. +/// \details Some AES code requires ARMv7 or above +/// \since Crypto++ 8.0 +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasARMv7() +{ + // ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64 +#if defined(__aarch32__) || defined(__aarch64__) + return true; +#else + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasARMv7; +#endif +} + +/// \brief Determine if an ARM processor has Advanced SIMD available +/// \return true if the hardware is capable of Advanced SIMD at runtime, false otherwise. +/// \details Advanced SIMD instructions are available under most ARMv7, Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mfpu=neon (32-bit) or -march=armv8-a +/// (64-bit). Also see ARM's __ARM_NEON preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasNEON() +{ + // ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64 +#if defined(__aarch32__) || defined(__aarch64__) + return true; +#else + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasNEON; +#endif +} + +/// \brief Determine if an ARM processor provides Polynomial Multiplication +/// \return true if the hardware is capable of polynomial multiplications at runtime, +/// false otherwise. +/// \details The multiplication instructions are available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, +/// you may need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasPMULL() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasPMULL; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has CRC32 available +/// \return true if the hardware is capable of CRC32 at runtime, false otherwise. +/// \details CRC32 instructions provide access to the processor's CRC-32 and CRC-32C +/// instructions. They are provided by ARM C Language Extensions 2.0 (ACLE 2.0) and +/// available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, +/// you may need to compile with -march=armv8-a+crc; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRC32 preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasCRC32() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasCRC32; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has AES available +/// \return true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasAES() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasAES; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA1 available +/// \return true if the hardware is capable of SHA1 at runtime, false otherwise. +/// \details SHA1 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA1() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA1; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA256 available +/// \return true if the hardware is capable of SHA256 at runtime, false otherwise. +/// \details SHA256 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA2() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA2; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA512 available +/// \return true if the hardware is capable of SHA512 at runtime, false otherwise. +/// \details SHA512 is part of the ARMv8.4 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.4-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA512() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA512; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA3 available +/// \return true if the hardware is capable of SHA3 at runtime, false otherwise. +/// \details SHA3 is part of the ARMv8.4 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.4-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA3() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA3; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SM3 available +/// \return true if the hardware is capable of SM3 at runtime, false otherwise. +/// \details SM3 is part of the ARMv8.4 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.4-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSM3() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSM3; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SM4 available +/// \return true if the hardware is capable of SM4 at runtime, false otherwise. +/// \details SM4 is part of the ARMv8.4 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.4-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSM4() +{ +#if defined(__aarch32__) || defined(__aarch64__) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSM4; +#else + return false; +#endif +} + +//@} + +#endif // CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 + +// ***************************** PowerPC ***************************** // + +#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_PowerpcDetectionDone; +extern bool g_hasAltivec; +extern bool g_hasPower7; +extern bool g_hasPower8; +extern bool g_hasPower9; +extern bool g_hasAES; +extern bool g_hasPMULL; +extern bool g_hasSHA256; +extern bool g_hasSHA512; +extern bool g_hasDARN; +extern word32 g_cacheLineSize; +void CRYPTOPP_API DetectPowerpcFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name POWERPC CPU FEATURES +//@{ + +/// \brief Determine if a PowerPC processor has Altivec available +/// \return true if the hardware is capable of Altivec at runtime, false otherwise. +/// \details Altivec instructions are available on modern PowerPCs. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power4; while IBM XL C/C++ compilers require +/// -qarch=pwr6 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAltivec() +{ +#if CRYPTOPP_ALTIVEC_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasAltivec; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power7 available +/// \return true if the hardware is capable of Power7 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power7; while IBM XL C/C++ compilers require +/// -qarch=pwr7 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower7() +{ +#if CRYPTOPP_POWER7_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPower7; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power8 available +/// \return true if the hardware is capable of Power8 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower8() +{ +#if CRYPTOPP_POWER8_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPower8; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power9 available +/// \return true if the hardware is capable of Power9 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power9; while IBM XL C/C++ compilers require +/// -qarch=pwr9 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower9() +{ +#if CRYPTOPP_POWER9_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPower9; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has AES available +/// \return true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAES() +{ +#if CRYPTOPP_POWER8_AES_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasAES; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Polynomial Multiply available +/// \return true if the hardware is capable of PMULL at runtime, false otherwise. +/// \details PMULL is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPMULL() +{ +#if CRYPTOPP_POWER8_VMULL_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasPMULL; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has SHA256 available +/// \return true if the hardware is capable of SHA256 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA256() +{ +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasSHA256; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has SHA512 available +/// \return true if the hardware is capable of SHA512 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA512() +{ +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_hasSHA512; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has DARN available +/// \return true if the hardware is capable of DARN at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power9; while IBM XL C/C++ compilers require +/// -qarch=pwr9 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasDARN() +{ +#if CRYPTOPP_POWER9_AVAILABLE + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + // see comments in cpu.cpp +# if defined(__ibmxl__) && defined(__linux__) + return false; +# else + return g_hasDARN; +# endif +#else + return false; +#endif +} + +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_PowerpcDetectionDone) + DetectPowerpcFeatures(); + return g_cacheLineSize; +} + +//@} + +#endif // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 + +// ***************************** L1 cache line ***************************** // + +// Non-Intel systems +#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + return CRYPTOPP_L1_CACHE_LINE_SIZE; +} +#endif // Non-Intel systems + +#endif // CRYPTOPP_GENERATE_X64_MASM + +// ***************************** Inline ASM Helper ***************************** // + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS1(x) x*newline* + #define AS2(x, y) x, y*newline* + #define AS3(x, y, z) x, y, z*newline* + #define ASS(x, y, a, b, c, d) x, y, a*64+b*16+c*4+d*newline* + #define ASL(x) label##x:*newline* + #define ASJ(x, y, z) x label##y*newline* + #define ASC(x, y) x label##y*newline* + #define AS_HEX(y) 0##y##h +#elif defined(_MSC_VER) || defined(__BORLANDC__) + #define AS1(x) __asm {x} + #define AS2(x, y) __asm {x, y} + #define AS3(x, y, z) __asm {x, y, z} + #define ASS(x, y, a, b, c, d) __asm {x, y, (a)*64+(b)*16+(c)*4+(d)} + #define ASL(x) __asm {label##x:} + #define ASJ(x, y, z) __asm {x label##y} + #define ASC(x, y) __asm {x label##y} + #define CRYPTOPP_NAKED __declspec(naked) + #define AS_HEX(y) 0x##y +#else + // define these in two steps to allow arguments to be expanded + #define GNU_AS1(x) #x ";" NEW_LINE + #define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE + #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";" NEW_LINE + #define GNU_ASL(x) "\n" #x ":" NEW_LINE +// clang 5.0.0 and apple clang 9.0.0 don't support numerical backward jumps +#if (CRYPTOPP_LLVM_CLANG_VERSION >= 50000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 90000) + #define GNU_ASJ(x, y, z) ATT_PREFIX ";" NEW_LINE #x " " #y #z ";" NEW_LINE INTEL_PREFIX ";" NEW_LINE +#else + #define GNU_ASJ(x, y, z) #x " " #y #z ";" NEW_LINE +#endif + #define AS1(x) GNU_AS1(x) + #define AS2(x, y) GNU_AS2(x, y) + #define AS3(x, y, z) GNU_AS3(x, y, z) + #define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";" + #define ASL(x) GNU_ASL(x) + #define ASJ(x, y, z) GNU_ASJ(x, y, z) + #define ASC(x, y) #x " " #y ";" + #define CRYPTOPP_NAKED + #define AS_HEX(y) 0x##y +#endif + +#define IF0(y) +#define IF1(y) y + +#ifdef CRYPTOPP_GENERATE_X64_MASM +#define ASM_MOD(x, y) ((x) MOD (y)) +#define XMMWORD_PTR XMMWORD PTR +#else +// GNU assembler doesn't seem to have mod operator +#define ASM_MOD(x, y) ((x)-((x)/(y))*(y)) +// GAS 2.15 doesn't support XMMWORD PTR. it seems necessary only for MASM +#define XMMWORD_PTR +#endif + +#if CRYPTOPP_BOOL_X86 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 esi + #define AS_REG_4 edi + #define AS_REG_5 eax + #define AS_REG_6 ebx + #define AS_REG_7 ebp + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d esi + #define AS_REG_4d edi + #define AS_REG_5d eax + #define AS_REG_6d ebx + #define AS_REG_7d ebp + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push e##x) + #define AS_POP_IF86(x) AS1(pop e##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X32 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 r8d + #define AS_REG_4 r9d + #define AS_REG_5 eax + #define AS_REG_6 r10d + #define AS_REG_7 r11d + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push r##x) + #define AS_POP_IF86(x) AS1(pop r##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X64 + #ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS_REG_1 rcx + #define AS_REG_2 rdx + #define AS_REG_3 r8 + #define AS_REG_4 r9 + #define AS_REG_5 rax + #define AS_REG_6 r10 + #define AS_REG_7 r11 + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #else + #define AS_REG_1 rdi + #define AS_REG_2 rsi + #define AS_REG_3 rdx + #define AS_REG_4 rcx + #define AS_REG_5 r8 + #define AS_REG_6 r9 + #define AS_REG_7 r10 + #define AS_REG_1d edi + #define AS_REG_2d esi + #define AS_REG_3d edx + #define AS_REG_4d ecx + #define AS_REG_5d r8d + #define AS_REG_6d r9d + #define AS_REG_7d r10d + #endif + #define WORD_SZ 8 + #define WORD_REG(x) r##x + #define WORD_PTR QWORD PTR + #define AS_PUSH_IF86(x) + #define AS_POP_IF86(x) + #define AS_JCXZ jrcxz +#endif + +// helper macro for stream cipher output +#define AS_XMM_OUTPUT4(labelPrefix, inputPtr, outputPtr, x0, x1, x2, x3, t, p0, p1, p2, p3, increment)\ + AS2( test inputPtr, inputPtr)\ + ASC( jz, labelPrefix##3)\ + AS2( test inputPtr, 15)\ + ASC( jnz, labelPrefix##7)\ + AS2( pxor xmm##x0, [inputPtr+p0*16])\ + AS2( pxor xmm##x1, [inputPtr+p1*16])\ + AS2( pxor xmm##x2, [inputPtr+p2*16])\ + AS2( pxor xmm##x3, [inputPtr+p3*16])\ + AS2( add inputPtr, increment*16)\ + ASC( jmp, labelPrefix##3)\ + ASL(labelPrefix##7)\ + AS2( movdqu xmm##t, [inputPtr+p0*16])\ + AS2( pxor xmm##x0, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p1*16])\ + AS2( pxor xmm##x1, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p2*16])\ + AS2( pxor xmm##x2, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p3*16])\ + AS2( pxor xmm##x3, xmm##t)\ + AS2( add inputPtr, increment*16)\ + ASL(labelPrefix##3)\ + AS2( test outputPtr, 15)\ + ASC( jnz, labelPrefix##8)\ + AS2( movdqa [outputPtr+p0*16], xmm##x0)\ + AS2( movdqa [outputPtr+p1*16], xmm##x1)\ + AS2( movdqa [outputPtr+p2*16], xmm##x2)\ + AS2( movdqa [outputPtr+p3*16], xmm##x3)\ + ASC( jmp, labelPrefix##9)\ + ASL(labelPrefix##8)\ + AS2( movdqu [outputPtr+p0*16], xmm##x0)\ + AS2( movdqu [outputPtr+p1*16], xmm##x1)\ + AS2( movdqu [outputPtr+p2*16], xmm##x2)\ + AS2( movdqu [outputPtr+p3*16], xmm##x3)\ + ASL(labelPrefix##9)\ + AS2( add outputPtr, increment*16) + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#endif // Not CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif // CRYPTOPP_CPU_H diff --git a/extension/third_party/cryptopp/crc.cpp b/extension/third_party/cryptopp/crc.cpp new file mode 100644 index 00000000..20addce6 --- /dev/null +++ b/extension/third_party/cryptopp/crc.cpp @@ -0,0 +1,367 @@ +// crc.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" +#include "crc.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +// crc_simd.cpp +#if (CRYPTOPP_ARM_CRC32_AVAILABLE) +extern void CRC32_Update_ARMV8(const byte *s, size_t n, word32& c); +extern void CRC32C_Update_ARMV8(const byte *s, size_t n, word32& c); +#endif + +// crc_simd.cpp +#if (CRYPTOPP_SSE42_AVAILABLE) +extern void CRC32C_Update_SSE42(const byte *s, size_t n, word32& c); +#endif + +/* Table of CRC-32's of all single byte values (made by makecrc.c) */ +const word32 CRC32::m_tab[] = { +#if (CRYPTOPP_LITTLE_ENDIAN) + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +#else + 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L, + 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L, + 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L, + 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L, + 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L, + 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L, + 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L, + 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L, + 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L, + 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L, + 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL, + 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L, + 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L, + 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L, + 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L, + 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L, + 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL, + 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L, + 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL, + 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L, + 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L, + 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L, + 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL, + 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL, + 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L, + 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL, + 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L, + 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL, + 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L, + 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L, + 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L, + 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L, + 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L, + 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL, + 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L, + 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L, + 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L, + 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L, + 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L, + 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L, + 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L, + 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L, + 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL, + 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L, + 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L, + 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L, + 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L, + 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L, + 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL, + 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L, + 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL, + 0x8def022dL +#endif +}; + +std::string CRC32::AlgorithmProvider() const +{ +#if (CRYPTOPP_ARM_CRC32_AVAILABLE) + if (HasCRC32()) + return "ARMv8"; +#endif + return "C++"; +} + +CRC32::CRC32() +{ + Reset(); +} + +void CRC32::Update(const byte *s, size_t n) +{ +#if (CRYPTOPP_ARM_CRC32_AVAILABLE) + if (HasCRC32()) + { + CRC32_Update_ARMV8(s, n, m_crc); + return; + } +#endif + + word32 crc = m_crc; + + for(; !IsAligned(s) && n > 0; n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + while (n >= 4) + { + crc ^= *(const word32 *)(void*)s; + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + n -= 4; s += 4; + } + + while (n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + m_crc = crc; +} + +void CRC32::TruncatedFinal(byte *hash, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + m_crc ^= CRC32_NEGL; + for (size_t i=0; i(s) && n > 0; n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + while (n >= 4) + { + crc ^= *(const word32 *)(void*)s; + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc); + n -= 4; s += 4; + } + + while (n--) + crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc); + + m_crc = crc; +} + +void CRC32C::TruncatedFinal(byte *hash, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + m_crc ^= CRC32_NEGL; + for (size_t i=0; i> 8) +#else +#define CRC32_INDEX(c) (c >> 24) +#define CRC32_SHIFTED(c) (c << 8) +#endif + +/// \brief CRC-32 Checksum Calculation +/// \details Uses CRC polynomial 0xEDB88320 +class CRC32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + CRC32(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + byte GetCrcByte(size_t i) const {return reinterpret_cast(&m_crc)[i];} + + std::string AlgorithmProvider() const; + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +/// \brief CRC-32C Checksum Calculation +/// \details Uses CRC polynomial 0x82F63B78 +/// \since Crypto++ 5.6.4 +class CRC32C : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + CRC32C(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32C";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + byte GetCrcByte(size_t i) const {return reinterpret_cast(&m_crc)[i];} + + std::string AlgorithmProvider() const; + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/crc_simd.cpp b/extension/third_party/cryptopp/crc_simd.cpp new file mode 100644 index 00000000..93ab9bc9 --- /dev/null +++ b/extension/third_party/cryptopp/crc_simd.cpp @@ -0,0 +1,161 @@ +// crc_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to SSE4.2 and +// ARMv8a CRC-32 and CRC-32C instructions. A separate source file +// is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "misc.h" + +#if (CRYPTOPP_SSE42_AVAILABLE) +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char CRC_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) + +bool CPU_ProbeCRC32() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_ARM_CRC32_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + word32 w=0, x=1; word16 y=2; byte z=3; + w = __crc32w(w,x); + w = __crc32h(w,y); + w = __crc32b(w,z); + w = __crc32cw(w,x); + w = __crc32ch(w,y); + w = __crc32cb(w,z); + + result = !!w; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +#else + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + word32 w=0, x=1; word16 y=2; byte z=3; + w = __crc32w(w,x); + w = __crc32h(w,y); + w = __crc32b(w,z); + w = __crc32cw(w,x); + w = __crc32ch(w,y); + w = __crc32cb(w,z); + + // Hack... GCC optimizes away the code and returns true + result = !!w; + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_CRC32_AVAILABLE +} +#endif // ARM32 or ARM64 + +#if (CRYPTOPP_ARM_CRC32_AVAILABLE) +void CRC32_Update_ARMV8(const byte *s, size_t n, word32& c) +{ + for(; !IsAligned(s) && n > 0; s++, n--) + c = __crc32b(c, *s); + + for(; n > 4; s+=4, n-=4) + c = __crc32w(c, *(const word32 *)(void*)s); + + for(; n > 0; s++, n--) + c = __crc32b(c, *s); +} + +void CRC32C_Update_ARMV8(const byte *s, size_t n, word32& c) +{ + for(; !IsAligned(s) && n > 0; s++, n--) + c = __crc32cb(c, *s); + + for(; n > 4; s+=4, n-=4) + c = __crc32cw(c, *(const word32 *)(void*)s); + + for(; n > 0; s++, n--) + c = __crc32cb(c, *s); +} +#endif + +#if (CRYPTOPP_SSE42_AVAILABLE) +void CRC32C_Update_SSE42(const byte *s, size_t n, word32& c) +{ + for(; !IsAligned(s) && n > 0; s++, n--) + c = _mm_crc32_u8(c, *s); + + for(; n > 4; s+=4, n-=4) + c = _mm_crc32_u32(c, *(const word32 *)(void*)s); + + for(; n > 0; s++, n--) + c = _mm_crc32_u8(c, *s); +} +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/cryptlib.cpp b/extension/third_party/cryptopp/cryptlib.cpp new file mode 100644 index 00000000..a7523497 --- /dev/null +++ b/extension/third_party/cryptopp/cryptlib.cpp @@ -0,0 +1,1054 @@ +// cryptlib.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4127 4189 4459) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-value" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "cryptlib.h" +#include "filters.h" +#include "algparam.h" +#include "fips140.h" +#include "argnames.h" +#include "fltrimpl.h" +#include "osrng.h" +#include "secblock.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_COMPILE_ASSERT(sizeof(byte) == 1); +CRYPTOPP_COMPILE_ASSERT(sizeof(word16) == 2); +CRYPTOPP_COMPILE_ASSERT(sizeof(word32) == 4); +CRYPTOPP_COMPILE_ASSERT(sizeof(word64) == 8); +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE +CRYPTOPP_COMPILE_ASSERT(sizeof(dword) == 2*sizeof(word)); +#endif + +BufferedTransformation & TheBitBucket() +{ + static BitBucket bitBucket; + return bitBucket; +} + +Algorithm::Algorithm(bool checkSelfTestStatus) +{ + if (checkSelfTestStatus && FIPS_140_2_ComplianceEnabled()) + { + if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_NOT_DONE && !PowerUpSelfTestInProgressOnThisThread()) + throw SelfTestFailure("Cryptographic algorithms are disabled before the power-up self tests are performed."); + + if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_FAILED) + throw SelfTestFailure("Cryptographic algorithms are disabled after a power-up self test failed."); + } +} + +void SimpleKeyingInterface::SetKey(const byte *key, size_t length, const NameValuePairs ¶ms) +{ + this->ThrowIfInvalidKeyLength(length); + this->UncheckedSetKey(key, static_cast(length), params); +} + +void SimpleKeyingInterface::SetKeyWithRounds(const byte *key, size_t length, int rounds) +{ + SetKey(key, length, MakeParameters(Name::Rounds(), rounds)); +} + +void SimpleKeyingInterface::SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength) +{ + SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, ivLength))); +} + +void SimpleKeyingInterface::ThrowIfInvalidKeyLength(size_t length) +{ + if (!IsValidKeyLength(length)) + throw InvalidKeyLength(GetAlgorithm().AlgorithmName(), length); +} + +void SimpleKeyingInterface::ThrowIfResynchronizable() +{ + if (IsResynchronizable()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": this object requires an IV"); +} + +void SimpleKeyingInterface::ThrowIfInvalidIV(const byte *iv) +{ + if (!iv && IVRequirement() == UNPREDICTABLE_RANDOM_IV) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": this object cannot use a null IV"); +} + +size_t SimpleKeyingInterface::ThrowIfInvalidIVLength(int length) +{ + size_t size = 0; + if (length < 0) + size = static_cast(IVSize()); + else if ((size_t)length < MinIVLength()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": IV length " + IntToString(length) + " is less than the minimum of " + IntToString(MinIVLength())); + else if ((size_t)length > MaxIVLength()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": IV length " + IntToString(length) + " exceeds the maximum of " + IntToString(MaxIVLength())); + else + size = static_cast(length); + + return size; +} + +const byte * SimpleKeyingInterface::GetIVAndThrowIfInvalid(const NameValuePairs ¶ms, size_t &size) +{ + ConstByteArrayParameter ivWithLength; + const byte *iv = NULLPTR; + bool found = false; + + try {found = params.GetValue(Name::IV(), ivWithLength);} + catch (const NameValuePairs::ValueTypeMismatch &) {} + + if (found) + { + iv = ivWithLength.begin(); + ThrowIfInvalidIV(iv); + size = ThrowIfInvalidIVLength(static_cast(ivWithLength.size())); + } + else if (params.GetValue(Name::IV(), iv)) + { + ThrowIfInvalidIV(iv); + size = static_cast(IVSize()); + } + else + { + ThrowIfResynchronizable(); + size = 0; + } + + return iv; +} + +void SimpleKeyingInterface::GetNextIV(RandomNumberGenerator &rng, byte *iv) +{ + rng.GenerateBlock(iv, IVSize()); +} + +size_t BlockTransformation::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const +{ + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length); + + const unsigned int blockSize = BlockSize(); + size_t inIncrement = (flags & (BT_InBlockIsCounter|BT_DontIncrementInOutPointers)) ? 0 : blockSize; + size_t xorIncrement = xorBlocks ? blockSize : 0; + size_t outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : blockSize; + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + // Coverity finding. + const bool xorFlag = xorBlocks && (flags & BT_XorInput); + while (length >= blockSize) + { + if (xorFlag) + { + // xorBlocks non-NULL and with BT_XorInput. + xorbuf(outBlocks, xorBlocks, inBlocks, blockSize); + ProcessBlock(outBlocks); + } + else + { + // xorBlocks may be non-NULL and without BT_XorInput. + ProcessAndXorBlock(inBlocks, xorBlocks, outBlocks); + } + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[blockSize-1]++; + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +unsigned int BlockTransformation::OptimalDataAlignment() const +{ + return GetAlignmentOf(); +} + +unsigned int StreamTransformation::OptimalDataAlignment() const +{ + return GetAlignmentOf(); +} + +unsigned int HashTransformation::OptimalDataAlignment() const +{ + return GetAlignmentOf(); +} + +#if 0 +void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(MinLastBlockSize() == 0); // this function should be overridden otherwise + + if (length == MandatoryBlockSize()) + ProcessData(outString, inString, length); + else if (length != 0) + throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block"); +} +#endif + +size_t StreamTransformation::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + // this function should be overridden otherwise + CRYPTOPP_ASSERT(MinLastBlockSize() == 0); + + if (inLength == MandatoryBlockSize()) + { + outLength = inLength; // squash unused warning + ProcessData(outString, inString, inLength); + } + else if (inLength != 0) + throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block"); + + return outLength; +} + +void AuthenticatedSymmetricCipher::SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) +{ + if (headerLength > MaxHeaderLength()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": header length " + IntToString(headerLength) + " exceeds the maximum of " + IntToString(MaxHeaderLength())); + + if (messageLength > MaxMessageLength()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": message length " + IntToString(messageLength) + " exceeds the maximum of " + IntToString(MaxMessageLength())); + + if (footerLength > MaxFooterLength()) + throw InvalidArgument(GetAlgorithm().AlgorithmName() + ": footer length " + IntToString(footerLength) + " exceeds the maximum of " + IntToString(MaxFooterLength())); + + UncheckedSpecifyDataLengths(headerLength, messageLength, footerLength); +} + +void AuthenticatedSymmetricCipher::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength) +{ + Resynchronize(iv, ivLength); + SpecifyDataLengths(headerLength, messageLength); + Update(header, headerLength); + ProcessString(ciphertext, message, messageLength); + TruncatedFinal(mac, macSize); +} + +bool AuthenticatedSymmetricCipher::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength) +{ + Resynchronize(iv, ivLength); + SpecifyDataLengths(headerLength, ciphertextLength); + Update(header, headerLength); + ProcessString(message, ciphertext, ciphertextLength); + return TruncatedVerify(mac, macLength); +} + +std::string AuthenticatedSymmetricCipher::AlgorithmName() const +{ + // Squash C4505 on Visual Studio 2008 and friends + return "Unknown"; +} + +unsigned int RandomNumberGenerator::GenerateBit() +{ + return GenerateByte() & 1; +} + +byte RandomNumberGenerator::GenerateByte() +{ + byte b; + GenerateBlock(&b, 1); + return b; +} + +word32 RandomNumberGenerator::GenerateWord32(word32 min, word32 max) +{ + const word32 range = max-min; + const unsigned int maxBits = BitPrecision(range); + + word32 value; + + do + { + GenerateBlock((byte *)&value, sizeof(value)); + value = Crop(value, maxBits); + } while (value > range); + + return value+min; +} + +// Stack recursion below... GenerateIntoBufferedTransformation calls GenerateBlock, +// and GenerateBlock calls GenerateIntoBufferedTransformation. Ad infinitum. Also +// see http://github.com/weidai11/cryptopp/issues/38. +// +// According to Wei, RandomNumberGenerator is an interface, and it should not +// be instantiable. Its now spilt milk, and we are going to CRYPTOPP_ASSERT it in Debug +// builds to alert the programmer and throw in Release builds. Developers have +// a reference implementation in case its needed. If a programmer +// unintentionally lands here, then they should ensure use of a +// RandomNumberGenerator pointer or reference so polymorphism can provide the +// proper runtime dispatching. + +void RandomNumberGenerator::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size); + + ArraySink s(output, size); + GenerateIntoBufferedTransformation(s, DEFAULT_CHANNEL, size); +} + +void RandomNumberGenerator::DiscardBytes(size_t n) +{ + GenerateIntoBufferedTransformation(TheBitBucket(), DEFAULT_CHANNEL, n); +} + +void RandomNumberGenerator::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length) +{ + FixedSizeSecBlock buffer; + while (length) + { + size_t len = UnsignedMin(buffer.size(), length); + GenerateBlock(buffer, len); + (void)target.ChannelPut(channel, buffer, len); + length -= len; + } +} + +size_t KeyDerivationFunction::MinDerivedKeyLength() const +{ + return 0; +} + +size_t KeyDerivationFunction::MaxDerivedKeyLength() const +{ + return static_cast(-1); +} + +void KeyDerivationFunction::ThrowIfInvalidDerivedKeyLength(size_t length) const +{ + if (!IsValidDerivedLength(length)) + throw InvalidDerivedKeyLength(GetAlgorithm().AlgorithmName(), length); +} + +void KeyDerivationFunction::SetParameters(const NameValuePairs& params) { + CRYPTOPP_UNUSED(params); +} + +/// \brief Random Number Generator that does not produce random numbers +/// \details ClassNullRNG can be used for functions that require a RandomNumberGenerator +/// but don't actually use it. The class throws NotImplemented when a generation function is called. +/// \sa NullRNG() +class ClassNullRNG : public RandomNumberGenerator +{ +public: + /// \brief The name of the generator + /// \returns the string \a NullRNGs + std::string AlgorithmName() const {return "NullRNG";} + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief An implementation that throws NotImplemented + byte GenerateByte () {} + /// \brief An implementation that throws NotImplemented + unsigned int GenerateBit () {} + /// \brief An implementation that throws NotImplemented + word32 GenerateWord32 (word32 min, word32 max) {} +#endif + + /// \brief An implementation that throws NotImplemented + void GenerateBlock(byte *output, size_t size) + { + CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); + throw NotImplemented("NullRNG: NullRNG should only be passed to functions that don't need to generate random bytes"); + } + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief An implementation that throws NotImplemented + void GenerateIntoBufferedTransformation (BufferedTransformation &target, const std::string &channel, lword length) {} + /// \brief An implementation that throws NotImplemented + void IncorporateEntropy (const byte *input, size_t length) {} + /// \brief An implementation that returns \p false + bool CanIncorporateEntropy () const {} + /// \brief An implementation that does nothing + void DiscardBytes (size_t n) {} + /// \brief An implementation that does nothing + void Shuffle (IT begin, IT end) {} + +private: + Clonable* Clone () const { return NULLPTR; } +#endif +}; + +RandomNumberGenerator & NullRNG() +{ + static ClassNullRNG s_nullRNG; + return s_nullRNG; +} + +bool HashTransformation::TruncatedVerify(const byte *digest, size_t digestLength) +{ + // Allocate at least 1 for calculated to avoid triggering diagnostics + ThrowIfInvalidTruncatedSize(digestLength); + SecByteBlock calculated(digestLength ? digestLength : 1); + TruncatedFinal(calculated, digestLength); + return VerifyBufsEqual(calculated, digest, digestLength); +} + +void HashTransformation::ThrowIfInvalidTruncatedSize(size_t size) const +{ + if (size > DigestSize()) + throw InvalidArgument("HashTransformation: can't truncate a " + IntToString(DigestSize()) + " byte digest to " + IntToString(size) + " bytes"); +} + +unsigned int BufferedTransformation::GetMaxWaitObjectCount() const +{ + const BufferedTransformation *t = AttachedTransformation(); + return t ? t->GetMaxWaitObjectCount() : 0; +} + +void BufferedTransformation::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) +{ + BufferedTransformation *t = AttachedTransformation(); + if (t) + t->GetWaitObjects(container, callStack); // reduce clutter by not adding to stack here +} + +void BufferedTransformation::Initialize(const NameValuePairs ¶meters, int propagation) +{ + CRYPTOPP_UNUSED(propagation); + CRYPTOPP_ASSERT(!AttachedTransformation()); + IsolatedInitialize(parameters); +} + +bool BufferedTransformation::Flush(bool hardFlush, int propagation, bool blocking) +{ + CRYPTOPP_UNUSED(propagation); + CRYPTOPP_ASSERT(!AttachedTransformation()); + return IsolatedFlush(hardFlush, blocking); +} + +bool BufferedTransformation::MessageSeriesEnd(int propagation, bool blocking) +{ + CRYPTOPP_UNUSED(propagation); + CRYPTOPP_ASSERT(!AttachedTransformation()); + return IsolatedMessageSeriesEnd(blocking); +} + +byte * BufferedTransformation::ChannelCreatePutSpace(const std::string &channel, size_t &size) +{ + byte* space = NULLPTR; + if (channel.empty()) + space = CreatePutSpace(size); + else + throw NoChannelSupport(AlgorithmName()); + return space; +} + +size_t BufferedTransformation::ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking) +{ + size_t size = 0; + if (channel.empty()) + size = Put2(inString, length, messageEnd, blocking); + else + throw NoChannelSupport(AlgorithmName()); + return size; +} + +size_t BufferedTransformation::ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking) +{ + size_t size = 0; + if (channel.empty()) + size = PutModifiable2(inString, length, messageEnd, blocking); + else + size = ChannelPut2(channel, inString, length, messageEnd, blocking); + return size; +} + +bool BufferedTransformation::ChannelFlush(const std::string &channel, bool hardFlush, int propagation, bool blocking) +{ + bool result = 0; + if (channel.empty()) + result = Flush(hardFlush, propagation, blocking); + else + throw NoChannelSupport(AlgorithmName()); + return result; +} + +bool BufferedTransformation::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + bool result = false; + if (channel.empty()) + result = MessageSeriesEnd(propagation, blocking); + else + throw NoChannelSupport(AlgorithmName()); + return result; +} + +lword BufferedTransformation::MaxRetrievable() const +{ + lword size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->MaxRetrievable(); + else + size = CopyTo(TheBitBucket()); + return size; +} + +bool BufferedTransformation::AnyRetrievable() const +{ + bool result = false; + if (AttachedTransformation()) + result = AttachedTransformation()->AnyRetrievable(); + else + { + byte b; + result = Peek(b) != 0; + } + return result; +} + +size_t BufferedTransformation::Get(byte &outByte) +{ + size_t size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->Get(outByte); + else + size = Get(&outByte, 1); + return size; +} + +size_t BufferedTransformation::Get(byte *outString, size_t getMax) +{ + size_t size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->Get(outString, getMax); + else + { + ArraySink arraySink(outString, getMax); + size = (size_t)TransferTo(arraySink, getMax); + } + return size; +} + +size_t BufferedTransformation::Peek(byte &outByte) const +{ + size_t size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->Peek(outByte); + else + size = Peek(&outByte, 1); + return size; +} + +size_t BufferedTransformation::Peek(byte *outString, size_t peekMax) const +{ + size_t size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->Peek(outString, peekMax); + else + { + ArraySink arraySink(outString, peekMax); + size = (size_t)CopyTo(arraySink, peekMax); + } + return size; +} + +lword BufferedTransformation::Skip(lword skipMax) +{ + lword size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->Skip(skipMax); + else + size = TransferTo(TheBitBucket(), skipMax); + return size; +} + +lword BufferedTransformation::TotalBytesRetrievable() const +{ + lword size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->TotalBytesRetrievable(); + else + size = MaxRetrievable(); + return size; +} + +unsigned int BufferedTransformation::NumberOfMessages() const +{ + unsigned int size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->NumberOfMessages(); + else + size = CopyMessagesTo(TheBitBucket()); + return size; +} + +bool BufferedTransformation::AnyMessages() const +{ + bool result = false; + if (AttachedTransformation()) + result = AttachedTransformation()->AnyMessages(); + else + result = NumberOfMessages() != 0; + return result; +} + +bool BufferedTransformation::GetNextMessage() +{ + bool result = false; + if (AttachedTransformation()) + result = AttachedTransformation()->GetNextMessage(); + else + { + CRYPTOPP_ASSERT(!AnyMessages()); + } + return result; +} + +unsigned int BufferedTransformation::SkipMessages(unsigned int count) +{ + unsigned int size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->SkipMessages(count); + else + size = TransferMessagesTo(TheBitBucket(), count); + return size; +} + +size_t BufferedTransformation::TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel, bool blocking) +{ + if (AttachedTransformation()) + return AttachedTransformation()->TransferMessagesTo2(target, messageCount, channel, blocking); + else + { + unsigned int maxMessages = messageCount; + for (messageCount=0; messageCount < maxMessages && AnyMessages(); messageCount++) + { + size_t blockedBytes; + lword transferredBytes; + + while (AnyRetrievable()) + { + // MaxRetrievable() instead of LWORD_MAX due to GH #962. If + // the target calls CreatePutSpace(), then the allocation + // size will be LWORD_MAX. That happens when target is a + // ByteQueue. Maybe ByteQueue should check the size, and if + // it is LWORD_MAX or -1, then use a default like 4096. + transferredBytes = MaxRetrievable(); + blockedBytes = TransferTo2(target, transferredBytes, channel, blocking); + if (blockedBytes > 0) + return blockedBytes; + } + + if (target.ChannelMessageEnd(channel, GetAutoSignalPropagation(), blocking)) + return 1; + + bool result = GetNextMessage(); + CRYPTOPP_UNUSED(result); CRYPTOPP_ASSERT(result); + } + return 0; + } +} + +unsigned int BufferedTransformation::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + unsigned int size = 0; + if (AttachedTransformation()) + size = AttachedTransformation()->CopyMessagesTo(target, count, channel); + return size; +} + +void BufferedTransformation::SkipAll() +{ + if (AttachedTransformation()) + AttachedTransformation()->SkipAll(); + else + { + while (SkipMessages()) {} + while (Skip()) {} + } +} + +size_t BufferedTransformation::TransferAllTo2(BufferedTransformation &target, const std::string &channel, bool blocking) +{ + if (AttachedTransformation()) + return AttachedTransformation()->TransferAllTo2(target, channel, blocking); + else + { + CRYPTOPP_ASSERT(!NumberOfMessageSeries()); + + unsigned int messageCount; + do + { + messageCount = UINT_MAX; + size_t blockedBytes = TransferMessagesTo2(target, messageCount, channel, blocking); + if (blockedBytes) + return blockedBytes; + } + while (messageCount != 0); + + lword byteCount; + do + { + byteCount = ULONG_MAX; + size_t blockedBytes = TransferTo2(target, byteCount, channel, blocking); + if (blockedBytes) + return blockedBytes; + } + while (byteCount != 0); + + return 0; + } +} + +void BufferedTransformation::CopyAllTo(BufferedTransformation &target, const std::string &channel) const +{ + if (AttachedTransformation()) + AttachedTransformation()->CopyAllTo(target, channel); + else + { + CRYPTOPP_ASSERT(!NumberOfMessageSeries()); + while (CopyMessagesTo(target, UINT_MAX, channel)) {} + } +} + +void BufferedTransformation::SetRetrievalChannel(const std::string &channel) +{ + if (AttachedTransformation()) + AttachedTransformation()->SetRetrievalChannel(channel); +} + +size_t BufferedTransformation::ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order, bool blocking) +{ + PutWord(false, order, m_buf, value); + return ChannelPut(channel, m_buf, 2, blocking); +} + +size_t BufferedTransformation::ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order, bool blocking) +{ + PutWord(false, order, m_buf, value); + return ChannelPut(channel, m_buf, 4, blocking); +} + +size_t BufferedTransformation::ChannelPutWord64(const std::string &channel, word64 value, ByteOrder order, bool blocking) +{ + PutWord(false, order, m_buf, value); + return ChannelPut(channel, m_buf, 8, blocking); +} + +size_t BufferedTransformation::PutWord16(word16 value, ByteOrder order, bool blocking) +{ + return ChannelPutWord16(DEFAULT_CHANNEL, value, order, blocking); +} + +size_t BufferedTransformation::PutWord32(word32 value, ByteOrder order, bool blocking) +{ + return ChannelPutWord32(DEFAULT_CHANNEL, value, order, blocking); +} + +size_t BufferedTransformation::PutWord64(word64 value, ByteOrder order, bool blocking) +{ + return ChannelPutWord64(DEFAULT_CHANNEL, value, order, blocking); +} + +size_t BufferedTransformation::PeekWord16(word16 &value, ByteOrder order) const +{ + byte buf[2] = {0, 0}; + size_t len = Peek(buf, 2); + + if (order == BIG_ENDIAN_ORDER) + value = word16((buf[0] << 8) | buf[1]); + else + value = word16((buf[1] << 8) | buf[0]); + + return len; +} + +size_t BufferedTransformation::PeekWord32(word32 &value, ByteOrder order) const +{ + byte buf[4] = {0, 0, 0, 0}; + size_t len = Peek(buf, 4); + + if (order == BIG_ENDIAN_ORDER) + value = word32((buf[0] << 24) | (buf[1] << 16) | + (buf[2] << 8) | (buf[3] << 0)); + else + value = word32((buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | (buf[0] << 0)); + + return len; +} + +size_t BufferedTransformation::PeekWord64(word64 &value, ByteOrder order) const +{ + byte buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + size_t len = Peek(buf, 8); + + if (order == BIG_ENDIAN_ORDER) + value = ((word64)buf[0] << 56) | ((word64)buf[1] << 48) | ((word64)buf[2] << 40) | + ((word64)buf[3] << 32) | ((word64)buf[4] << 24) | ((word64)buf[5] << 16) | + ((word64)buf[6] << 8) | (word64)buf[7]; + else + value = ((word64)buf[7] << 56) | ((word64)buf[6] << 48) | ((word64)buf[5] << 40) | + ((word64)buf[4] << 32) | ((word64)buf[3] << 24) | ((word64)buf[2] << 16) | + ((word64)buf[1] << 8) | (word64)buf[0]; + + return len; +} + +size_t BufferedTransformation::GetWord16(word16 &value, ByteOrder order) +{ + return (size_t)Skip(PeekWord16(value, order)); +} + +size_t BufferedTransformation::GetWord32(word32 &value, ByteOrder order) +{ + return (size_t)Skip(PeekWord32(value, order)); +} + +size_t BufferedTransformation::GetWord64(word64 &value, ByteOrder order) +{ + return (size_t)Skip(PeekWord64(value, order)); +} + +void BufferedTransformation::Attach(BufferedTransformation *newAttachment) +{ + if (AttachedTransformation() && AttachedTransformation()->Attachable()) + AttachedTransformation()->Attach(newAttachment); + else + Detach(newAttachment); +} + +void GeneratableCryptoMaterial::GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize) +{ + GenerateRandom(rng, MakeParameters("KeySize", (int)keySize)); +} + +class PK_DefaultEncryptionFilter : public Unflushable +{ +public: + PK_DefaultEncryptionFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment, const NameValuePairs ¶meters) + : m_rng(rng), m_encryptor(encryptor), m_parameters(parameters) + { + Detach(attachment); + } + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + FILTER_BEGIN; + m_plaintextQueue.Put(inString, length); + + if (messageEnd) + { + { + size_t plaintextLength; + if (!SafeConvert(m_plaintextQueue.CurrentSize(), plaintextLength)) + throw InvalidArgument("PK_DefaultEncryptionFilter: plaintext too long"); + size_t ciphertextLength = m_encryptor.CiphertextLength(plaintextLength); + + SecByteBlock plaintext(plaintextLength); + m_plaintextQueue.Get(plaintext, plaintextLength); + m_ciphertext.resize(ciphertextLength); + m_encryptor.Encrypt(m_rng, plaintext, plaintextLength, m_ciphertext, m_parameters); + } + + FILTER_OUTPUT(1, m_ciphertext, m_ciphertext.size(), messageEnd); + } + FILTER_END_NO_MESSAGE_END; + } + + RandomNumberGenerator &m_rng; + const PK_Encryptor &m_encryptor; + const NameValuePairs &m_parameters; + ByteQueue m_plaintextQueue; + SecByteBlock m_ciphertext; +}; + +BufferedTransformation * PK_Encryptor::CreateEncryptionFilter(RandomNumberGenerator &rng, BufferedTransformation *attachment, const NameValuePairs ¶meters) const +{ + return new PK_DefaultEncryptionFilter(rng, *this, attachment, parameters); +} + +class PK_DefaultDecryptionFilter : public Unflushable +{ +public: + PK_DefaultDecryptionFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment, const NameValuePairs ¶meters) + : m_rng(rng), m_decryptor(decryptor), m_parameters(parameters) + { + Detach(attachment); + } + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + FILTER_BEGIN; + m_ciphertextQueue.Put(inString, length); + + if (messageEnd) + { + { + size_t ciphertextLength; + if (!SafeConvert(m_ciphertextQueue.CurrentSize(), ciphertextLength)) + throw InvalidArgument("PK_DefaultDecryptionFilter: ciphertext too long"); + size_t maxPlaintextLength = m_decryptor.MaxPlaintextLength(ciphertextLength); + + SecByteBlock ciphertext(ciphertextLength); + m_ciphertextQueue.Get(ciphertext, ciphertextLength); + m_plaintext.resize(maxPlaintextLength); + m_result = m_decryptor.Decrypt(m_rng, ciphertext, ciphertextLength, m_plaintext, m_parameters); + if (!m_result.isValidCoding) + throw InvalidCiphertext(m_decryptor.AlgorithmName() + ": invalid ciphertext"); + } + + FILTER_OUTPUT(1, m_plaintext, m_result.messageLength, messageEnd); + } + FILTER_END_NO_MESSAGE_END; + } + + RandomNumberGenerator &m_rng; + const PK_Decryptor &m_decryptor; + const NameValuePairs &m_parameters; + ByteQueue m_ciphertextQueue; + SecByteBlock m_plaintext; + DecodingResult m_result; +}; + +BufferedTransformation * PK_Decryptor::CreateDecryptionFilter(RandomNumberGenerator &rng, BufferedTransformation *attachment, const NameValuePairs ¶meters) const +{ + return new PK_DefaultDecryptionFilter(rng, *this, attachment, parameters); +} + +size_t PK_Signer::Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const +{ + member_ptr m(messageAccumulator); + return SignAndRestart(rng, *m, signature, false); +} + +size_t PK_Signer::SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const +{ + member_ptr m(NewSignatureAccumulator(rng)); + m->Update(message, messageLen); + return SignAndRestart(rng, *m, signature, false); +} + +size_t PK_Signer::SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const +{ + member_ptr m(NewSignatureAccumulator(rng)); + InputRecoverableMessage(*m, recoverableMessage, recoverableMessageLength); + m->Update(nonrecoverableMessage, nonrecoverableMessageLength); + return SignAndRestart(rng, *m, signature, false); +} + +bool PK_Verifier::Verify(PK_MessageAccumulator *messageAccumulator) const +{ + member_ptr m(messageAccumulator); + return VerifyAndRestart(*m); +} + +bool PK_Verifier::VerifyMessage(const byte *message, size_t messageLen, const byte *signature, size_t signatureLen) const +{ + member_ptr m(NewVerificationAccumulator()); + InputSignature(*m, signature, signatureLen); + m->Update(message, messageLen); + return VerifyAndRestart(*m); +} + +DecodingResult PK_Verifier::Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const +{ + member_ptr m(messageAccumulator); + return RecoverAndRestart(recoveredMessage, *m); +} + +DecodingResult PK_Verifier::RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, + const byte *signature, size_t signatureLength) const +{ + member_ptr m(NewVerificationAccumulator()); + InputSignature(*m, signature, signatureLength); + m->Update(nonrecoverableMessage, nonrecoverableMessageLength); + return RecoverAndRestart(recoveredMessage, *m); +} + +void SimpleKeyAgreementDomain::GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GeneratePrivateKey(rng, privateKey); + GeneratePublicKey(rng, privateKey, publicKey); +} + +void AuthenticatedKeyAgreementDomain::GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GenerateStaticPrivateKey(rng, privateKey); + GenerateStaticPublicKey(rng, privateKey, publicKey); +} + +void AuthenticatedKeyAgreementDomain::GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const +{ + GenerateEphemeralPrivateKey(rng, privateKey); + GenerateEphemeralPublicKey(rng, privateKey, publicKey); +} + +// Allow a distro or packager to override the build-time version +// http://github.com/weidai11/cryptopp/issues/371 +#ifndef CRYPTOPP_BUILD_VERSION +# define CRYPTOPP_BUILD_VERSION CRYPTOPP_VERSION +#endif +int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT) +{ + return CRYPTOPP_BUILD_VERSION; +} + +class NullNameValuePairs : public NameValuePairs +{ +public: + NullNameValuePairs() {} // Clang complains a default ctor must be avilable + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + {CRYPTOPP_UNUSED(name); CRYPTOPP_UNUSED(valueType); CRYPTOPP_UNUSED(pValue); return false;} +}; + +#if HAVE_GCC_INIT_PRIORITY + const std::string DEFAULT_CHANNEL __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 25))) = ""; + const std::string AAD_CHANNEL __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 26))) = "AAD"; + const NullNameValuePairs s_nullNameValuePairs __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 27))); + const NameValuePairs& g_nullNameValuePairs = s_nullNameValuePairs; +#elif HAVE_MSC_INIT_PRIORITY + #pragma warning(disable: 4073) + #pragma init_seg(lib) + const std::string DEFAULT_CHANNEL = ""; + const std::string AAD_CHANNEL = "AAD"; + const NullNameValuePairs s_nullNameValuePairs; + const NameValuePairs& g_nullNameValuePairs = s_nullNameValuePairs; + #pragma warning(default: 4073) +#elif HAVE_XLC_INIT_PRIORITY + #pragma priority(260) + const std::string DEFAULT_CHANNEL = ""; + const std::string AAD_CHANNEL = "AAD"; + const NullNameValuePairs s_nullNameValuePairs; + const NameValuePairs& g_nullNameValuePairs = s_nullNameValuePairs; +#else + const std::string DEFAULT_CHANNEL = ""; + const std::string AAD_CHANNEL = "AAD"; + const simple_ptr s_pNullNameValuePairs(new NullNameValuePairs); + const NameValuePairs &g_nullNameValuePairs = *s_pNullNameValuePairs.m_p; +#endif + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/cryptlib.h b/extension/third_party/cryptopp/cryptlib.h new file mode 100644 index 00000000..d86931a7 --- /dev/null +++ b/extension/third_party/cryptopp/cryptlib.h @@ -0,0 +1,3362 @@ +// cryptlib.h - originally written and placed in the public domain by Wei Dai + +/// \file cryptlib.h +/// \brief Abstract base classes that provide a uniform interface to this library. + +/*! \mainpage Crypto++ Library 8.4 API Reference +
+
Abstract Base Classes
+ cryptlib.h +
Authenticated Encryption Modes
+ CCM, EAX, \ref GCM "GCM (2K tables)", \ref GCM "GCM (64K tables)" +
Block Ciphers
+ \ref Rijndael "AES", ARIA, Weak::ARC4, Blowfish, BTEA, \ref CHAM128 "CHAM (64/128)", Camellia, + \ref CAST128 "CAST (128/256)", DES, \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES", + \ref DES_XEX3 "DESX", GOST, HIGHT, IDEA, LEA, \ref LR "Luby-Rackoff", \ref Kalyna128 "Kalyna (128/256/512)", + MARS, RC2, RC5, RC6, \ref SAFER_K "SAFER-K", \ref SAFER_SK "SAFER-SK", SEED, Serpent, + \ref SHACAL2 "SHACAL-2", SHARK, \ref SIMECK64 "SIMECK (32/64)" SKIPJACK, SM4, Square, TEA, + \ref ThreeWay "3-Way", \ref Threefish256 "Threefish (256/512/1024)", Twofish, XTEA +
Stream Ciphers
+ \ref ChaCha "ChaCha (8/12/20)", \ref HC128 "HC-128/256", \ref Panama "Panama-LE", \ref Panama "Panama-BE", + Rabbit, Salsa20, \ref SEAL "SEAL-LE", \ref SEAL "SEAL-BE", WAKE, XSalsa20 +
Hash Functions
+ BLAKE2s, BLAKE2b, \ref Keccak "Keccak (F1600)", SHA1, SHA224, SHA256, SHA384, SHA512, + \ref SHA3 "SHA-3", SM3, Tiger, RIPEMD160, RIPEMD320, RIPEMD128, RIPEMD256, SipHash, Whirlpool, + Weak::MD2, Weak::MD4, Weak::MD5 +
Non-Cryptographic Checksums
+ CRC32, CRC32C, Adler32 +
Message Authentication Codes
+ BLAKE2b, BLAKE2s, CBC_MAC, CMAC, DMAC, \ref GCM "GCM (GMAC)", HMAC, Poly1305, TTMAC, VMAC +
Random Number Generators
+ NullRNG, LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG, + NIST Hash_DRBG and HMAC_DRBG, \ref MersenneTwister "MersenneTwister (MT19937 and MT19937-AR)", + DARN, RDRAND, RDSEED +
Key Derivation and Password-based Cryptography
+ HKDF, \ref PKCS12_PBKDF "PBKDF (PKCS #12)", \ref PKCS5_PBKDF1 "PBKDF-1 (PKCS #5)", + \ref PKCS5_PBKDF2_HMAC "PBKDF-2/HMAC (PKCS #5)" +
Public Key Cryptosystems
+ DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES +
Public Key Signature Schemes
+ DSA, DSA2, \ref ed25519 "Ed25519", GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, + RabinSS, RWSS, ESIGN +
Key Agreement
+ DH, DH2, \ref x25519 "X25519", \ref MQV_Domain "MQV", \ref HMQV_Domain "HMQV", + \ref FHMQV_Domain "FHMQV", ECDH, x25519, ECMQV, ECHMQV, ECFHMQV, XTR_DH +
Algebraic Structures
+ Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, + ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, GF2NP, GF256, GF2_32, EC2N, ECP +
Secret Sharing and Information Dispersal
+ SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery +
Compression
+ Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor +
Input Source Classes
+ StringSource, ArraySource, VectorSource, FileSource, RandomNumberSource +
Output Sink Classes
+ StringSinkTemplate, StringSink, VectorSink, ArraySink, FileSink, RandomNumberSink +
Filter Wrappers
+ StreamTransformationFilter, AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashFilter, + HashVerificationFilter, SignerFilter, SignatureVerificationFilter +
Binary to Text Encoders and Decoders
+ HexEncoder, HexDecoder, Base64Encoder, Base64Decoder, Base64URLEncoder, Base64URLDecoder, Base32Encoder, + Base32Decoder +
Wrappers for OS features
+ Timer, ThreadUserTimer + +
+ + + +

This reference manual is a work in progress. Some classes lack detailed descriptions. +

Click here to download a zip archive containing this manual. +

Thanks to Ryan Phillips for providing the Doxygen configuration file +and getting us started on the manual. +*/ + +#ifndef CRYPTOPP_CRYPTLIB_H +#define CRYPTOPP_CRYPTLIB_H + +#include "config.h" +#include "stdcpp.h" +#include "trap.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4505 4702) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// forward declarations +class Integer; +class RandomNumberGenerator; +class BufferedTransformation; + +/// \brief Specifies a direction for a cipher to operate +/// \sa BlockTransformation::IsForwardTransformation(), BlockTransformation::IsPermutation(), BlockTransformation::GetCipherDirection() +enum CipherDir { + /// \brief the cipher is performing encryption + ENCRYPTION, + /// \brief the cipher is performing decryption + DECRYPTION}; + +/// \brief Represents infinite time +const unsigned long INFINITE_TIME = ULONG_MAX; + +// VC60 workaround: using enums as template parameters causes problems +/// \brief Converts an enumeration to a type suitable for use as a template parameter +template +struct EnumToType +{ + static ENUM_TYPE ToEnum() {return static_cast(VALUE);} +}; + +/// \brief Provides the byte ordering +/// \details Big-endian and little-endian modes are supported. Bi-endian and PDP-endian modes +/// are not supported. +enum ByteOrder { + /// \brief byte order is little-endian + LITTLE_ENDIAN_ORDER = 0, + /// \brief byte order is big-endian + BIG_ENDIAN_ORDER = 1}; + +/// \brief Provides a constant for LittleEndian +typedef EnumToType LittleEndian; +/// \brief Provides a constant for BigEndian +typedef EnumToType BigEndian; + +/// \brief Base class for all exceptions thrown by the library +/// \details All library exceptions directly or indirectly inherit from the Exception class. +/// The Exception class itself inherits from std::exception. The library does not use +/// std::runtime_error derived classes. +class CRYPTOPP_DLL Exception : public std::exception +{ +public: + /// \enum ErrorType + /// \brief Error types or categories + enum ErrorType { + /// \brief A method was called which was not implemented + NOT_IMPLEMENTED, + /// \brief An invalid argument was detected + INVALID_ARGUMENT, + /// \brief BufferedTransformation received a Flush(true) signal but can't flush buffers + CANNOT_FLUSH, + /// \brief Data integerity check, such as CRC or MAC, failed + DATA_INTEGRITY_CHECK_FAILED, + /// \brief Input data was received that did not conform to expected format + INVALID_DATA_FORMAT, + /// \brief Error reading from input device or writing to output device + IO_ERROR, + /// \brief Some other error occurred not belonging to other categories + OTHER_ERROR + }; + + virtual ~Exception() throw() {} + + /// \brief Construct a new Exception + explicit Exception(ErrorType errorType, const std::string &s) : m_errorType(errorType), m_what(s) {} + + /// \brief Retrieves a C-string describing the exception + const char *what() const throw() {return (m_what.c_str());} + /// \brief Retrieves a string describing the exception + const std::string &GetWhat() const {return m_what;} + /// \brief Sets the error string for the exception + void SetWhat(const std::string &s) {m_what = s;} + /// \brief Retrieves the error type for the exception + ErrorType GetErrorType() const {return m_errorType;} + /// \brief Sets the error type for the exceptions + void SetErrorType(ErrorType errorType) {m_errorType = errorType;} + +private: + ErrorType m_errorType; + std::string m_what; +}; + +/// \brief An invalid argument was detected +class CRYPTOPP_DLL InvalidArgument : public Exception +{ +public: + /// \brief Construct an InvalidArgument + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} +}; + +/// \brief Input data was received that did not conform to expected format +class CRYPTOPP_DLL InvalidDataFormat : public Exception +{ +public: + /// \brief Construct an InvalidDataFormat + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {} +}; + +/// \brief A decryption filter encountered invalid ciphertext +class CRYPTOPP_DLL InvalidCiphertext : public InvalidDataFormat +{ +public: + /// \brief Construct an InvalidCiphertext + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {} +}; + +/// \brief A method was called which was not implemented +class CRYPTOPP_DLL NotImplemented : public Exception +{ +public: + /// \brief Construct an NotImplemented + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {} +}; + +/// \brief Flush(true) was called but it can't completely flush its buffers +class CRYPTOPP_DLL CannotFlush : public Exception +{ +public: + /// \brief Construct an CannotFlush + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {} +}; + +/// \brief The operating system reported an error +class CRYPTOPP_DLL OS_Error : public Exception +{ +public: + virtual ~OS_Error() throw() {} + + /// \brief Construct an OS_Error + /// \param errorType the error type + /// \param s the message for the exception + /// \param operation the operation for the exception + /// \param errorCode the error code + /// \details The member function what() returns s. + OS_Error(ErrorType errorType, const std::string &s, const std::string& operation, int errorCode) + : Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {} + + /// \brief Retrieve the operating system API that reported the error + const std::string & GetOperation() const {return m_operation;} + /// \brief Retrieve the error code returned by the operating system + int GetErrorCode() const {return m_errorCode;} + +protected: + std::string m_operation; + int m_errorCode; +}; + +/// \brief Returns a decoding results +struct CRYPTOPP_DLL DecodingResult +{ + /// \brief Constructs a DecodingResult + /// \details isValidCoding is initialized to false and messageLength is + /// initialized to 0. + explicit DecodingResult() : isValidCoding(false), messageLength(0) {} + /// \brief Constructs a DecodingResult + /// \param len the message length + /// \details isValidCoding is initialized to true. + explicit DecodingResult(size_t len) : isValidCoding(true), messageLength(len) {} + + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if either isValidCoding or messageLength is \a not equal, + /// false otherwise + bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;} + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if either isValidCoding or messageLength is \a not equal, + /// false otherwise + /// \details Returns !operator==(rhs). + bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);} + + /// \brief Flag to indicate the decoding is valid + bool isValidCoding; + /// \brief Recovered message length if isValidCoding is true, undefined otherwise + size_t messageLength; +}; + +/// \brief Interface for retrieving values given their names +/// \details This class is used to safely pass a variable number of arbitrarily +/// typed arguments to functions and to read values from keys and crypto parameters. +/// \details To obtain an object that implements NameValuePairs for the purpose of +/// parameter passing, use the MakeParameters() function. +/// \details To get a value from NameValuePairs, you need to know the name and the +/// type of the value. Call GetValueNames() on a NameValuePairs object to obtain a +/// list of value names that it supports. then look at the Name namespace +/// documentation to see what the type of each value is, or alternatively, call +/// GetIntValue() with the value name, and if the type is not int, a +/// ValueTypeMismatch exception will be thrown and you can get the actual type from +/// the exception object. +/// \sa NullNameValuePairs, g_nullNameValuePairs, +/// NameValuePairs on the +/// Crypto++ wiki +class NameValuePairs +{ +public: + virtual ~NameValuePairs() {} + + /// \brief Thrown when an unexpected type is encountered + /// \details Exception thrown when trying to retrieve a value using a different + /// type than expected + class CRYPTOPP_DLL ValueTypeMismatch : public InvalidArgument + { + public: + /// \brief Construct a ValueTypeMismatch + /// \param name the name of the value + /// \param stored the \a actual type of the value stored + /// \param retrieving the \a presumed type of the value retrieved + ValueTypeMismatch(const std::string &name, const std::type_info &stored, const std::type_info &retrieving) + : InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'") + , m_stored(stored), m_retrieving(retrieving) {} + + /// \brief Provides the stored type + /// \return the C++ mangled name of the type + const std::type_info & GetStoredTypeInfo() const {return m_stored;} + + /// \brief Provides the retrieveing type + /// \return the C++ mangled name of the type + const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;} + + private: + const std::type_info &m_stored; + const std::type_info &m_retrieving; + }; + + /// \brief Get a copy of this object or subobject + /// \tparam T class or type + /// \param object reference to a variable that receives the value + template + bool GetThisObject(T &object) const + { + return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object); + } + + /// \brief Get a pointer to this object + /// \tparam T class or type + /// \param ptr reference to a pointer to a variable that receives the value + template + bool GetThisPointer(T *&ptr) const + { + return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), ptr); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + bool GetValue(const char *name, T &value) const + { + return GetVoidValue(name, typeid(T), &value); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param defaultValue the default value of the class or type if it does not exist + /// \return the object or value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + T GetValueWithDefault(const char *name, T defaultValue) const + { + T value; + bool result = GetValue(name, value); + // No assert... this recovers from failure + if (result) {return value;} + return defaultValue; + } + + /// \brief Get a list of value names that can be retrieved + /// \return a list of names available to retrieve + /// \details the items in the list are delimited with a colon. + CRYPTOPP_DLL std::string GetValueNames() const + {std::string result; GetValue("ValueNames", result); return result;} + + /// \brief Get a named value with type int + /// \param name the name of the value to retrieve + /// \param value the value retrieved upon success + /// \return true if an int value was retrieved, false otherwise + /// \details GetIntValue() is used to ensure we don't accidentally try to get an + /// unsigned int or some other type when we mean int (which is the most common case) + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL bool GetIntValue(const char *name, int &value) const + {return GetValue(name, value);} + + /// \brief Get a named value with type int, with default + /// \param name the name of the value to retrieve + /// \param defaultValue the default value if the name does not exist + /// \return the value retrieved on success or the default value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + /// \brief Get a named value with type word64 + /// \param name the name of the value to retrieve + /// \param value the value retrieved upon success + /// \return true if an word64 value was retrieved, false otherwise + /// \sa GetValue(), GetValueWithDefault(), GetWord64ValueWithDefault(), GetIntValue(), + /// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL bool GetWord64Value(const char *name, word64 &value) const + {return GetValue(name, value);} + + /// \brief Get a named value with type word64, with default + /// \param name the name of the value to retrieve + /// \param defaultValue the default value if the name does not exist + /// \return the value retrieved on success or the default value + /// \sa GetValue(), GetValueWithDefault(), GetWord64Value(), GetIntValue(), + /// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredWord64Parameter() + CRYPTOPP_DLL word64 GetWord64ValueWithDefault(const char *name, word64 defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + /// \brief Ensures an expected name and type is present + /// \param name the name of the value + /// \param stored the type that was stored for the name + /// \param retrieving the type that is being retrieved for the name + /// \throw ValueTypeMismatch + /// \details ThrowIfTypeMismatch() effectively performs a type safety check. + /// stored and retrieving are C++ mangled names for the type. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL static void CRYPTOPP_API ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving) + {if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);} + + /// \brief Retrieves a required name/value pair + /// \tparam T class or type + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throw InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + void GetRequiredParameter(const char *className, const char *name, T &value) const + { + if (!GetValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Retrieves a required name/value pair + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throw InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL void GetRequiredIntParameter(const char *className, const char *name, int &value) const + { + if (!GetIntValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0; +}; + +// Doxygen cannot handle initialization +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Default channel for BufferedTransformation +/// \details DEFAULT_CHANNEL is equal to an empty string +/// \details The definition for DEFAULT_CHANNEL is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// DEFAULT_CHANNEL where the string object is NULL, then you probably have +/// a global object using DEFAULT_CHANNEL before it has been constructed. +const std::string DEFAULT_CHANNEL; + +/// \brief Channel for additional authenticated data +/// \details AAD_CHANNEL is equal to "AAD" +/// \details The definition for AAD_CHANNEL is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// AAD_CHANNEL where the string object is NULL, then you probably have a +/// global object using AAD_CHANNEL before it has been constructed. +const std::string AAD_CHANNEL; + +/// \brief An empty set of name-value pairs +/// \details The definition for g_nullNameValuePairs is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// g_nullNameValuePairs where the string object is NULL, then you probably +/// have a global object using g_nullNameValuePairs before it has been +/// constructed. +const NameValuePairs& g_nullNameValuePairs; + +#else +extern CRYPTOPP_DLL const std::string DEFAULT_CHANNEL; +extern CRYPTOPP_DLL const std::string AAD_CHANNEL; +extern CRYPTOPP_DLL const NameValuePairs& g_nullNameValuePairs; +#endif + +// Document additional name spaces which show up elsewhere in the sources. +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Namespace containing value name definitions. +/// \details Name is part of the CryptoPP namespace. +/// \details The semantics of value names, types are: +///

+///     ThisObject:ClassName (ClassName, copy of this object or a subobject)
+///     ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject)
+/// 
+DOCUMENTED_NAMESPACE_BEGIN(Name) +// more names defined in argnames.h +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing weak and wounded algorithms. +/// \details Weak is part of the CryptoPP namespace. Schemes and algorithms are moved into Weak +/// when their security level is reduced to an unacceptable level by contemporary standards. +/// \details To use an algorithm in the Weak namespace, you must \c \#define +/// CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 before including a header for a weak or wounded +/// algorithm. For example: +///
  \c \#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
+///   \c \#include 
+///   ...
+///   CryptoPP::Weak::MD5 md5;
+///   
+DOCUMENTED_NAMESPACE_BEGIN(Weak) +// weak and wounded algorithms +DOCUMENTED_NAMESPACE_END +#endif + +/// \brief Namespace containing NaCl library functions +/// \details TweetNaCl is a compact and portable reimplementation of the NaCl library. +DOCUMENTED_NAMESPACE_BEGIN(NaCl) +// crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open (and friends) +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing testing and benchmark classes. +/// \details Source files for classes in the Test namespaces include +/// test.cpp, validat#.cpp and bench#.cpp. +DOCUMENTED_NAMESPACE_BEGIN(Test) +// testing and benchmark classes +DOCUMENTED_NAMESPACE_END + +// ******************************************************** + +/// \brief Interface for cloning objects +/// \note this is \a not implemented by most classes +/// \sa ClonableImpl, NotCopyable +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Clonable +{ +public: + virtual ~Clonable() {} + + /// \brief Copies this object + /// \return a copy of this object + /// \throw NotImplemented + /// \note this is \a not implemented by most classes + /// \sa NotCopyable + virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");} // TODO: make this =0 +}; + +/// \brief Interface for all crypto algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Algorithm : public Clonable +{ +public: + virtual ~Algorithm() {} + + /// \brief Interface for all crypto algorithms + /// \param checkSelfTestStatus determines whether the object can proceed if the self + /// tests have not been run or failed. + /// \details When FIPS 140-2 compliance is enabled and checkSelfTestStatus == true, + /// this constructor throws SelfTestFailure if the self test hasn't been run or fails. + /// \details FIPS 140-2 compliance is disabled by default. It is only used by certain + /// versions of the library when the library is built as a DLL on Windows. Also see + /// CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 in config.h. + Algorithm(bool checkSelfTestStatus = true); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note AlgorithmName is not universally implemented yet. + virtual std::string AlgorithmName() const {return "unknown";} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + /// \since Crypto++ 8.0 + virtual std::string AlgorithmProvider() const {return "C++";} +}; + +/// \brief Interface for algorithms that take byte strings as keys +/// \sa FixedKeyLength(), VariableKeyLength(), SameKeyLengthAs(), SimpleKeyingInterfaceImpl() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyingInterface +{ +public: + virtual ~SimpleKeyingInterface() {} + + /// \brief Returns smallest valid key length + /// \return the minimum key length, in bytes + virtual size_t MinKeyLength() const =0; + + /// \brief Returns largest valid key length + /// \return the maximum key length, in bytes + virtual size_t MaxKeyLength() const =0; + + /// \brief Returns default key length + /// \return the default key length, in bytes + virtual size_t DefaultKeyLength() const =0; + + /// \brief Returns a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + virtual size_t GetValidKeyLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidKeyLength(size_t keylength) const + {return keylength == GetValidKeyLength(keylength);} + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param params additional initialization parameters to configure this object + virtual void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param rounds the number of rounds to apply the transformation function, + /// if applicable + /// \details SetKeyWithRounds() calls SetKey() with a NameValuePairs + /// object that only specifies rounds. rounds is an integer parameter, + /// and -1 means use the default number of rounds. + void SetKeyWithRounds(const byte *key, size_t length, int rounds); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the initialization vector to use when keying the object + /// \param ivLength the size of the iv, in bytes + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs + /// that only specifies IV. The IV is a byte buffer with size ivLength. + /// ivLength is an integer parameter, and -1 means use IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the initialization vector to use when keying the object + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs() object + /// that only specifies iv. iv is a byte buffer, and it must have + /// a size IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv) + {SetKeyWithIV(key, length, iv, IVSize());} + + /// \brief Secure IVs requirements as enumerated values. + /// \details Provides secure IV requirements as a monotonically increasing enumerated values. + /// Requirements can be compared using less than (<) and greater than (>). For example, + /// UNIQUE_IV < RANDOM_IV and UNPREDICTABLE_RANDOM_IV > RANDOM_IV. + /// \details Objects that use SimpleKeyingInterface do not support an optional IV. That is, + /// an IV must be present or it must be absent. If you wish to support an optional IV then + /// provide two classes - one with an IV and one without an IV. + /// \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs() + enum IV_Requirement { + /// \brief The IV must be unique + UNIQUE_IV = 0, + /// \brief The IV must be random and possibly predictable + RANDOM_IV, + /// \brief The IV must be random and unpredictable + UNPREDICTABLE_RANDOM_IV, + /// \brief The IV is set by the object + INTERNALLY_GENERATED_IV, + /// \brief The object does not use an IV + NOT_RESYNCHRONIZABLE + }; + + /// \brief Minimal requirement for secure IVs + /// \return the secure IV requirement of the algorithm + virtual IV_Requirement IVRequirement() const =0; + + /// \brief Determines if the object can be resynchronized + /// \return true if the object can be resynchronized (i.e. supports initialization vectors), false otherwise + /// \note If this function returns true, and no IV is passed to SetKey() and CanUseStructuredIVs()==true, + /// an IV of all 0's will be assumed. + bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;} + + /// \brief Determines if the object can use random IVs + /// \return true if the object can use random IVs (in addition to ones returned by GetNextIV), false otherwise + bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;} + + /// \brief Determines if the object can use random but possibly predictable IVs + /// \return true if the object can use random but possibly predictable IVs (in addition to ones returned by + /// GetNextIV), false otherwise + bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;} + + /// \brief Determines if the object can use structured IVs + /// \return true if the object can use structured IVs, false otherwise + /// \details CanUseStructuredIVs() indicates whether the object can use structured IVs; for example a counter + /// (in addition to ones returned by GetNextIV). + bool CanUseStructuredIVs() const {return IVRequirement() <= UNIQUE_IV;} + + /// \brief Returns length of the IV accepted by this object + /// \return the size of an IV, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + /// \details The default implementation throws NotImplemented + virtual unsigned int IVSize() const + {throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");} + + /// \brief Provides the default size of an IV + /// \return default length of IVs accepted by this object, in bytes + unsigned int DefaultIVLength() const {return IVSize();} + + /// \brief Provides the minimum size of an IV + /// \return minimal length of IVs accepted by this object, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + virtual unsigned int MinIVLength() const {return IVSize();} + + /// \brief Provides the maximum size of an IV + /// \return maximal length of IVs accepted by this object, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + virtual unsigned int MaxIVLength() const {return IVSize();} + + /// \brief Resynchronize with an IV + /// \param iv the initialization vector + /// \param ivLength the size of the initialization vector, in bytes + /// \details Resynchronize() resynchronizes with an IV provided by the caller. ivLength=-1 means use IVSize(). + /// \throw NotImplemented() if the object does not support resynchronization + virtual void Resynchronize(const byte *iv, int ivLength=-1) { + CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(ivLength); + throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization"); + } + + /// \brief Retrieves a secure IV for the next message + /// \param rng a RandomNumberGenerator to produce keying material + /// \param iv a block of bytes to receive the IV + /// \details The IV must be at least IVSize() in length. + /// \details This method should be called after you finish encrypting one message and are ready + /// to start the next one. After calling it, you must call SetKey() or Resynchronize(). + /// before using this object again. + /// \details Internally, the base class implementation calls RandomNumberGenerator's GenerateBlock() + /// \note This method is not implemented on decryption objects. + virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Sets the key for this object without performing parameter validation + /// \param key a byte buffer used to key the cipher + /// \param length the length of the byte buffer + /// \param params additional parameters passed as NameValuePairs + /// \details key must be at least DEFAULT_KEYLENGTH in length. + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) =0; + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidKeyLength(size_t length); + + /// \brief Validates the object + /// \throw InvalidArgument if the IV is present + /// \details Internally, the default implementation calls IsResynchronizable() and throws + /// InvalidArgument if the function returns true. + /// \note called when no IV is passed + void ThrowIfResynchronizable(); + + /// \brief Validates the IV + /// \param iv the IV with a length of IVSize, in bytes + /// \throw InvalidArgument on failure + /// \details Internally, the default implementation checks the iv. If iv is not NULL or nullptr, + /// then the function succeeds. If iv is NULL, then IVRequirement is checked against + /// UNPREDICTABLE_RANDOM_IV. If IVRequirement is UNPREDICTABLE_RANDOM_IV, then + /// then the function succeeds. Otherwise, an exception is thrown. + void ThrowIfInvalidIV(const byte *iv); + + /// \brief Validates the IV length + /// \param length the size of an IV, in bytes + /// \throw InvalidArgument if the IV length is invalid + size_t ThrowIfInvalidIVLength(int length); + + /// \brief Retrieves and validates the IV + /// \param params NameValuePairs with the IV supplied as a ConstByteArrayParameter + /// \param size the length of the IV, in bytes + /// \return a pointer to the first byte of the IV + /// \throw InvalidArgument if the number of rounds are invalid + const byte * GetIVAndThrowIfInvalid(const NameValuePairs ¶ms, size_t &size); + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + inline void AssertValidKeyLength(size_t length) const + {CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(IsValidKeyLength(length));} +}; + +/// \brief Interface for the data processing part of block ciphers +/// \details Classes derived from BlockTransformation are block ciphers +/// in ECB mode (for example the DES::Encryption class), which are stateless. +/// These classes should not be used directly, but only in combination with +/// a mode class (see CipherModeDocumentation in modes.h). +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockTransformation : public Algorithm +{ +public: + virtual ~BlockTransformation() {} + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \param xorBlock an optional XOR mask + /// \details ProcessAndXorBlock encrypts or decrypts inBlock, xor with xorBlock, and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. Use + /// BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \note The message can be transformed in-place, or the buffers must \a not overlap + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0; + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \details ProcessBlock encrypts or decrypts inBlock and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + /// \note The message can be transformed in-place, or the buffers must \a not overlap + void ProcessBlock(const byte *inBlock, byte *outBlock) const + {ProcessAndXorBlock(inBlock, NULLPTR, outBlock);} + + /// \brief Encrypt or decrypt a block in place + /// \param inoutBlock the input message before processing + /// \details ProcessBlock encrypts or decrypts inoutBlock in-place. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + void ProcessBlock(byte *inoutBlock) const + {ProcessAndXorBlock(inoutBlock, NULLPTR, inoutBlock);} + + /// Provides the block size of the cipher + /// \return the block size of the cipher, in bytes + virtual unsigned int BlockSize() const =0; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Determines if the transformation is a permutation + /// \return true if this is a permutation (i.e. there is an inverse transformation) + virtual bool IsPermutation() const {return true;} + + /// \brief Determines if the cipher is being operated in its forward direction + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; + + /// \brief Determines the number of blocks that can be processed in parallel + /// \return the number of blocks that can be processed in parallel, for bit-slicing implementations + /// \details Bit-slicing is often used to improve throughput and minimize timing attacks. + virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;} + + /// \brief Bit flags that control AdvancedProcessBlocks() behavior + enum FlagsForAdvancedProcessBlocks { + /// \brief inBlock is a counter + BT_InBlockIsCounter=1, + /// \brief should not modify block pointers + BT_DontIncrementInOutPointers=2, + /// \brief Xor inputs before transformation + BT_XorInput=4, + /// \brief perform the transformation in reverse + BT_ReverseDirection=8, + /// \brief Allow parallel transformations + BT_AllowParallel=16}; + + /// \brief Encrypt and xor multiple blocks using additional flags + /// \param inBlocks the input message before processing + /// \param xorBlocks an optional XOR mask + /// \param outBlocks the output message after processing + /// \param length the size of the blocks, in bytes + /// \param flags additional flags to control processing + /// \details Encrypt and xor multiple blocks according to FlagsForAdvancedProcessBlocks flags. + /// \note If BT_InBlockIsCounter is set, then the last byte of inBlocks may be modified. + virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; + + /// \brief Provides the direction of the cipher + /// \return ENCRYPTION if IsForwardTransformation() is true, DECRYPTION otherwise + /// \sa IsForwardTransformation(), IsPermutation() + inline CipherDir GetCipherDirection() const {return IsForwardTransformation() ? ENCRYPTION : DECRYPTION;} +}; + +/// \brief Interface for the data processing portion of stream ciphers +/// \sa StreamTransformationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm +{ +public: + virtual ~StreamTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + StreamTransformation& Ref() {return *this;} + + /// \brief Provides the mandatory block size of the cipher + /// \return The block size of the cipher if input must be processed in blocks, 1 otherwise + /// \details Stream ciphers and some block ciphers modes of operation return 1. Modes that + /// return 1 must be able to process a single byte at a time, like counter mode. If a + /// mode of operation or block cipher cannot stream then it must not return 1. + /// \details When filters operate the mode or cipher, ProcessData will be called with a + /// string of bytes that is determined by MandatoryBlockSize and OptimalBlockSize. When a + /// policy is set, like 16-byte strings for a 16-byte block cipher, the filter will buffer + /// bytes until the specified number of bytes is available to the object. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MandatoryBlockSize() const {return 1;} + + /// \brief Provides the input block size most efficient for this cipher + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();} + + /// \brief Provides the number of bytes used in the current block when processing at optimal block size. + /// \return the number of bytes used in the current block when processing at the optimal block size + virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Encrypt or decrypt an array of bytes + /// \param outString the output byte buffer + /// \param inString the input byte buffer + /// \param length the size of the input and output byte buffers, in bytes + /// \details ProcessData is called with a string of bytes whose size depends on MandatoryBlockSize. + /// Either inString == outString, or they must not overlap. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual void ProcessData(byte *outString, const byte *inString, size_t length) =0; + + /// \brief Encrypt or decrypt the last block of data + /// \param outString the output byte buffer + /// \param outLength the size of the output byte buffer, in bytes + /// \param inString the input byte buffer + /// \param inLength the size of the input byte buffer, in bytes + /// \return the number of bytes used in outString + /// \details ProcessLastBlock is used when the last block of data is special and requires handling + /// by the cipher. The current implementation provides an output buffer with a size + /// inLength+2*MandatoryBlockSize(). The return value allows the cipher to expand cipher + /// text during encryption or shrink plain text during decryption. + /// \details This member function is used by CBC-CTS and OCB modes. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + /// \brief Provides the size of the last block + /// \return the minimum size of the last block + /// \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last + /// block is not special. + /// \details MandatoryBlockSize() enlists one of two behaviors. First, if MandatoryBlockSize() + /// returns 1, then the cipher can be streamed and ProcessData() is called with the tail bytes. + /// Second, if MandatoryBlockSize() returns non-0, then the string of bytes is padded to + /// MandatoryBlockSize() according to the padding mode. Then, ProcessData() is called with the + /// padded string of bytes. + /// \details Some authenticated encryption modes are not expressed well with MandatoryBlockSize() + /// and MinLastBlockSize(). For example, AES/OCB uses 16-byte blocks (MandatoryBlockSize = 16) + /// and the last block requires special processing (MinLastBlockSize = 0). However, 0 is a valid + /// last block size for OCB and the special processing is custom padding, and not standard PKCS + /// padding. In response an unambiguous IsLastBlockSpecial() was added. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MinLastBlockSize() const {return 0;} + + /// \brief Determines if the last block receives special processing + /// \return true if the last block reveives special processing, false otherwise. + /// \details Some authenticated encryption modes are not expressed well with + /// MandatoryBlockSize() and MinLastBlockSize(). For example, AES/OCB uses + /// 16-byte blocks (MandatoryBlockSize = 16) and the last block requires special processing + /// (MinLastBlockSize = 0). However, 0 is a valid last block size for OCB and the special + /// processing is custom padding, and not standard PKCS padding. In response an + /// unambiguous IsLastBlockSpecial() was added. + /// \details When IsLastBlockSpecial() returns false nothing special happens. All the former + /// rules and behaviors apply. This is the default behavior of IsLastBlockSpecial(). + /// \details When IsLastBlockSpecial() returns true four things happen. First, MinLastBlockSize = 0 + /// means 0 is a valid block size that should be processed. Second, standard block cipher padding is + /// \a not \a applied. Third, the caller supplies an outString is larger than inString by + /// 2*MandatoryBlockSize(). That is, there's a reserve available when processing the last block. + /// Fourth, the cipher is responsible for finalization like custom padding. The cipher will tell + /// the library how many bytes were processed or used by returning the appropriate value from + /// ProcessLastBlock(). + /// \details The return value of ProcessLastBlock() indicates how many bytes were written to + /// outString. A filter pipelining data will send outString and up to outLength + /// to an AttachedTransformation() for additional processing. Below is an example of the code + /// used in StreamTransformationFilter::LastPut. + ///
  if (m_cipher.IsLastBlockSpecial())
+	///   {
+	///     size_t reserve = 2*m_cipher.MandatoryBlockSize();
+	///     space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length+reserve);
+	///     length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
+	///     AttachedTransformation()->Put(space, length);
+	///     return;
+	///   }
+ /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + /// \since Crypto++ 6.0 + virtual bool IsLastBlockSpecial() const {return false;} + + /// \brief Encrypt or decrypt a string of bytes + /// \param inoutString the string to process + /// \param length the size of the inoutString, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *inoutString, size_t length) + {ProcessData(inoutString, inoutString, length);} + + /// \brief Encrypt or decrypt a string of bytes + /// \param outString the output string to process + /// \param inString the input string to process + /// \param length the size of the input and output strings, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *outString, const byte *inString, size_t length) + {ProcessData(outString, inString, length);} + + /// \brief Encrypt or decrypt a byte + /// \param input the input byte to process + /// \details Internally, the base class implementation calls ProcessData() with a size of 1. + inline byte ProcessByte(byte input) + {ProcessData(&input, &input, 1); return input;} + + /// \brief Determines whether the cipher supports random access + /// \return true if the cipher supports random access, false otherwise + virtual bool IsRandomAccess() const =0; + + /// \brief Seek to an absolute position + /// \param pos position to seek + /// \throw NotImplemented + /// \details The base class implementation throws NotImplemented. The function + /// \ref CRYPTOPP_ASSERT "asserts" IsRandomAccess() in debug builds. + virtual void Seek(lword pos) + { + CRYPTOPP_UNUSED(pos); + CRYPTOPP_ASSERT(!IsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access"); + } + + /// \brief Determines whether the cipher is self-inverting + /// \return true if the cipher is self-inverting, false otherwise + /// \details IsSelfInverting determines whether this transformation is + /// self-inverting (e.g. xor with a keystream). + virtual bool IsSelfInverting() const =0; + + /// \brief Determines if the cipher is being operated in its forward direction + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; +}; + +/// \brief Interface for hash functions and data processing part of MACs +/// \details HashTransformation objects are stateful. They are created in an initial state, +/// change state as Update() is called, and return to the initial +/// state when Final() is called. This interface allows a large message to +/// be hashed in pieces by calling Update() on each piece followed by +/// calling Final(). +/// \sa HashFilter(), HashVerificationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HashTransformation : public Algorithm +{ +public: + virtual ~HashTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + HashTransformation& Ref() {return *this;} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + virtual void Update(const byte *input, size_t length) =0; + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL or nullptr. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + virtual byte * CreateUpdateSpace(size_t &size) {size=0; return NULLPTR;} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \details Final() restarts the hash for a new message. + /// \pre COUNTOF(digest) <= DigestSize() or COUNTOF(digest) <= HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual void Final(byte *digest) + {TruncatedFinal(digest, DigestSize());} + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + virtual void Restart() + {TruncatedFinal(NULLPTR, 0);} + + /// Provides the digest size of the hash + /// \return the digest size of the hash. + virtual unsigned int DigestSize() const =0; + + /// Provides the tag size of the hash + /// \return the tag size of the hash. + /// \details Same as DigestSize(). + unsigned int TagSize() const {return DigestSize();} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + virtual unsigned int BlockSize() const {return 0;} + + /// \brief Provides the input block size most efficient for this hash. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \details Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return 1;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Final() separately + /// \details CalculateDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void CalculateDigest(byte *digest, const byte *input, size_t length) + {Update(input, length); Final(digest);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if the existing hash's size exceeds DigestSize() + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details Verify() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool Verify(const byte *digest) + {return TruncatedVerify(digest, DigestSize());} + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if the existing hash's size exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Verify() separately + /// \details VerifyDigest() performs a bitwise compare on the buffers using VerifyBufsEqual(), + /// which is a constant time comparison function. + /// \details VerifyDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual bool VerifyDigest(const byte *digest, const byte *input, size_t length) + {Update(input, length); return Verify(digest);} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + /// \pre COUNTOF(digest) <= DigestSize() or COUNTOF(digest) <= HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void TruncatedFinal(byte *digest, size_t digestSize) =0; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the length of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and CalculateDigest() separately. + /// \details CalculateTruncatedDigest() restarts the hash for the next message. + /// \pre digestSize <= DigestSize() or digestSize <= HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void CalculateTruncatedDigest(byte *digest, size_t digestSize, const byte *input, size_t length) + {Update(input, length); TruncatedFinal(digest, digestSize);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if digestLength exceeds DigestSize() + /// \details TruncatedVerify() is a truncated version of Verify(). It can operate on a + /// buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details TruncatedVerify() restarts the hash for the next message. + /// \pre digestLength <= DigestSize() or digestLength <= HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool TruncatedVerify(const byte *digest, size_t digestLength); + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if digestLength exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and TruncatedVerify() separately. + /// \details VerifyTruncatedDigest() is a truncated version of VerifyDigest(). It can operate + /// on a buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details VerifyTruncatedDigest() restarts the hash for the next message. + /// \pre digestLength <= DigestSize() or digestLength <= HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool VerifyTruncatedDigest(const byte *digest, size_t digestLength, const byte *input, size_t length) + {Update(input, length); return TruncatedVerify(digest, digestLength);} + +protected: + /// \brief Validates a truncated digest size + /// \param size the requested digest size + /// \throw InvalidArgument if the algorithm's digest size cannot be truncated to the requested size + /// \details Throws an exception when the truncated digest size is greater than DigestSize() + void ThrowIfInvalidTruncatedSize(size_t size) const; +}; + +/// \brief Interface for one direction (encryption or decryption) of a block cipher +/// \details These objects usually should not be used directly. See BlockTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockCipher : public SimpleKeyingInterface, public BlockTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for one direction (encryption or decryption) of a stream cipher or cipher mode +/// \details These objects usually should not be used directly. See StreamTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SymmetricCipher : public SimpleKeyingInterface, public StreamTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for message authentication codes +/// \details These objects usually should not be used directly. See HashTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE MessageAuthenticationCode : public SimpleKeyingInterface, public HashTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipher() provides the interface for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. The +/// StreamTransformation() part of this interface is used to encrypt or decrypt the data. The +/// MessageAuthenticationCode() part of the interface is used to input additional authenticated +/// data (AAD), which is MAC'ed but not encrypted. The MessageAuthenticationCode() part is also +/// used to generate and verify the MAC. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes implement AuthenticatedSymmetricCipher() and the motivation for +/// the API, like calling AAD a "header", can be found in Bellare, Rogaway and +/// Wagner's The EAX Mode of +/// Operation. The EAX paper suggested a basic API to help standardize AEAD schemes in +/// software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipher : public MessageAuthenticationCode, public StreamTransformation +{ +public: + virtual ~AuthenticatedSymmetricCipher() {} + + /// \brief Exception thrown when the object is in the wrong state for the operation + /// \details this indicates that a member function was called in the wrong state, for example trying to encrypt + /// a message before having set the key or IV + class BadState : public Exception + { + public: + explicit BadState(const std::string &name, const char *message) : Exception(OTHER_ERROR, name + ": " + message) {} + explicit BadState(const std::string &name, const char *function, const char *state) : Exception(OTHER_ERROR, name + ": " + function + " was called before " + state) {} + }; + + /// \brief Provides the maximum length of AAD that can be input + /// \return the maximum length of AAD that can be input before the encrypted data + virtual lword MaxHeaderLength() const =0; + + /// \brief Provides the maximum length of encrypted data + /// \return the maximum length of encrypted data + virtual lword MaxMessageLength() const =0; + + /// \brief Provides the the maximum length of AAD + /// \return the maximum length of AAD that can be input after the encrypted data + virtual lword MaxFooterLength() const {return 0;} + + /// \brief Determines if data lengths must be specified prior to inputting data + /// \return true if the data lengths are required before inputting data, false otherwise + /// \details if this function returns true, SpecifyDataLengths() must be called before attempting to input data. + /// This is the case for some schemes, such as CCM. + /// \sa SpecifyDataLengths() + virtual bool NeedsPrespecifiedDataLengths() const {return false;} + + /// \brief Prescribes the data lengths + /// \param headerLength size of data before message is input, in bytes + /// \param messageLength size of the message, in bytes + /// \param footerLength size of data after message is input, in bytes + /// \details SpecifyDataLengths() only needs to be called if NeedsPrespecifiedDataLengths() returns true. + /// If true, then headerLength will be validated against MaxHeaderLength(), + /// messageLength will be validated against MaxMessageLength(), and + /// footerLength will be validated against MaxFooterLength(). + /// \sa NeedsPrespecifiedDataLengths() + void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0); + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param header the AAD buffer + /// \param headerLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param header the AAD buffer + /// \param headerLength the size of the AAD buffer, in bytes + /// \param ciphertext the ciphertext buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + virtual std::string AlgorithmName() const; + +protected: + const Algorithm & GetAlgorithm() const + {return *static_cast(this);} + virtual void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) + {CRYPTOPP_UNUSED(headerLength); CRYPTOPP_UNUSED(messageLength); CRYPTOPP_UNUSED(footerLength);} +}; + +/// \brief Interface for random number generators +/// \details The library provides a number of random number generators, from software based +/// to hardware based generators. +/// \details All generated values are uniformly distributed over the range specified. +/// \since Crypto++ 3.1 +/// \sa RandomNumberGenerator +/// on the Crypto++ wiki +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomNumberGenerator : public Algorithm +{ +public: + virtual ~RandomNumberGenerator() {} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throw NotImplemented + /// \details A generator may or may not accept additional entropy. Call CanIncorporateEntropy() + /// to test for the ability to use additional entropy. + /// \details If a derived class does not override IncorporateEntropy(), then the base class + /// throws NotImplemented. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + throw NotImplemented("RandomNumberGenerator: IncorporateEntropy not implemented"); + } + + /// \brief Determines if a generator can accept additional entropy + /// \return true if IncorporateEntropy() is implemented + virtual bool CanIncorporateEntropy() const {return false;} + + /// \brief Generate new random byte and return it + /// \return a random 8-bit byte + /// \details Default implementation calls GenerateBlock() with one byte. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual byte GenerateByte(); + + /// \brief Generate new random bit and return it + /// \return a random bit + /// \details The default implementation calls GenerateByte() and return its lowest bit. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual unsigned int GenerateBit(); + + /// \brief Generate a random 32 bit word in the range min to max, inclusive + /// \param min the lower bound of the range + /// \param max the upper bound of the range + /// \return a random 32-bit word + /// \details The default implementation calls Crop() on the difference between max and + /// min, and then returns the result added to min. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate random bytes into a BufferedTransformation + /// \param target the BufferedTransformation object which receives the bytes + /// \param channel the channel on which the bytes should be pumped + /// \param length the number of bytes to generate + /// \details The default implementation calls GenerateBlock() and pumps the result into + /// the DEFAULT_CHANNEL of the target. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + virtual void DiscardBytes(size_t n); + + /// \brief Randomly shuffle the specified array + /// \param begin an iterator to the first element in the array + /// \param end an iterator beyond the last element in the array + /// \details The resulting permutation is uniformly distributed. + template void Shuffle(IT begin, IT end) + { + // TODO: What happens if there are more than 2^32 elements? + for (; begin != end; ++begin) + std::iter_swap(begin, begin + GenerateWord32(0, static_cast(end-begin-1))); + } +}; + +/// \brief Interface for key derivation functions +/// \since Crypto++ 7.0 +/// \sa KeyDerivationFunction +/// on the Crypto++ wiki +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyDerivationFunction : public Algorithm +{ +public: + virtual ~KeyDerivationFunction() {} + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + virtual std::string AlgorithmName() const =0; + + /// \brief Determine minimum number of bytes + /// \return Minimum number of bytes which can be derived + virtual size_t MinDerivedKeyLength() const; + + /// \brief Determine maximum number of bytes + /// \return Maximum number of bytes which can be derived + virtual size_t MaxDerivedKeyLength() const; + + /// \brief Returns a valid key length for the derivation function + /// \param keylength the size of the derived key, in bytes + /// \return the valid key length, in bytes + virtual size_t GetValidDerivedLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if the derived keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidDerivedLength(size_t keylength) const { + return keylength == GetValidDerivedLength(keylength); + } + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param params additional initialization parameters to configure this object + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a secret seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details the number of iterations performed by DeriveKey() may be 1. For example, a + /// scheme like HKDF does not use the iteration count so it returns 1. + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params = g_nullNameValuePairs) const =0; + + /// \brief Set or change parameters + /// \param params additional initialization parameters to configure this object + /// \details SetParameters() is useful for setting common parameters when an object is + /// reused. Some derivation function classes may choose to implement it. + virtual void SetParameters(const NameValuePairs& params); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Validates the derived key length + /// \param length the size of the derived key material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidDerivedKeyLength(size_t length) const; +}; + +/// \brief Interface for password based key derivation functions +/// \since Crypto++ 7.0 +struct PasswordBasedKeyDerivationFunction : public KeyDerivationFunction +{ +}; + +/// \brief Random Number Generator that does not produce random numbers +/// \return reference that can be passed to functions that require a RandomNumberGenerator +/// \details NullRNG() returns a reference that can be passed to functions that require a +/// RandomNumberGenerator but don't actually use it. The NullRNG() throws NotImplemented +/// when a generation function is called. +/// \sa ClassNullRNG, PK_SignatureScheme::IsProbabilistic() +CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG(); + +class WaitObjectContainer; +class CallStack; + +/// \brief Interface for objects that can be waited on. +class CRYPTOPP_NO_VTABLE Waitable +{ +public: + virtual ~Waitable() {} + + /// \brief Maximum number of wait objects that this object can return + /// \return the maximum number of wait objects + virtual unsigned int GetMaxWaitObjectCount() const =0; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects. + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects() is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0; + + /// \brief Wait on this object + /// \return true if the wait succeeded, false otherwise + /// \details Wait() is the same as creating an empty container, calling GetWaitObjects(), and then calling + /// Wait() on the container. + bool Wait(unsigned long milliseconds, CallStack const& callStack); +}; + +/// \brief Interface for buffered transformations +/// \details BufferedTransformation is a generalization of BlockTransformation, +/// StreamTransformation and HashTransformation. +/// \details A buffered transformation is an object that takes a stream of bytes as input (this may +/// be done in stages), does some computation on them, and then places the result into an internal +/// buffer for later retrieval. Any partial result already in the output buffer is not modified +/// by further input. +/// \details If a method takes a "blocking" parameter, and you pass false for it, then the method +/// will return before all input has been processed if the input cannot be processed without waiting +/// (for network buffers to become available, for example). In this case the method will return true +/// or a non-zero integer value. When this happens you must continue to call the method with the same +/// parameters until it returns false or zero, before calling any other method on it or attached +/// BufferedTransformation. The integer return value in this case is approximately +/// the number of bytes left to be processed, and can be used to implement a progress bar. +/// \details For functions that take a "propagation" parameter, propagation != 0 means pass on +/// the signal to attached BufferedTransformation objects, with propagation decremented at each +/// step until it reaches 0. -1 means unlimited propagation. +/// \details \a All of the retrieval functions, like Get() and GetWord32(), return the actual +/// number of bytes retrieved, which is the lesser of the request number and MaxRetrievable(). +/// \details \a Most of the input functions, like Put() and PutWord32(), return the number of +/// bytes remaining to be processed. A 0 value means all bytes were processed, and a non-0 value +/// means bytes remain to be processed. +/// \nosubgrouping +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BufferedTransformation : public Algorithm, public Waitable +{ +public: + virtual ~BufferedTransformation() {} + + /// \brief Construct a BufferedTransformation + BufferedTransformation() : Algorithm(false) {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + BufferedTransformation& Ref() {return *this;} + + /// \name INPUT + //@{ + + /// \brief Input a byte for processing + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Put(byte) calls Put(byte*, size_t). + size_t Put(byte inByte, bool blocking=true) + {return Put(&inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Internally, Put() calls Put2(). + size_t Put(const byte *inString, size_t length, bool blocking=true) + {return Put2(inString, length, 0, blocking);} + + /// Input a 16-bit word for processing. + /// \param value the 16-bit value to be processed + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// Input a 32-bit word for processing. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// Input a 64-bit word for processing. + /// \param value the 64-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord64(word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \return byte pointer to the space to input data + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + virtual byte * CreatePutSpace(size_t &size) + {size=0; return NULLPTR;} + + /// \brief Determines whether input can be modified by the callee + /// \return true if input can be modified, false otherwise + /// \details The base class implementation returns false. + virtual bool CanModifyInput() const + {return false;} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + size_t PutModifiable(byte *inString, size_t length, bool blocking=true) + {return PutModifiable2(inString, length, 0, blocking);} + + /// \brief Signals the end of messages to the object + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool MessageEnd(int propagation=-1, bool blocking=true) + {return !!Put2(NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutMessageEnd() calls Put2() with a modified propagation to + /// ensure all attached transformations finish processing the message. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t PutMessageEnd(const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Derived classes must implement Put2(). + virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) =0; + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutModifiable2() calls Put2(). + virtual size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return Put2(inString, length, messageEnd, blocking);} + + /// \brief Exception thrown by objects that have \a not implemented nonblocking input processing + /// \details BlockingInputOnly inherits from NotImplemented + struct BlockingInputOnly : public NotImplemented + {BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}}; + //@} + + /// \name WAITING + //@{ + /// \brief Retrieves the maximum number of waitable objects + unsigned int GetMaxWaitObjectCount() const; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + //@} // WAITING + + /// \name SIGNALS + //@{ + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs to initialize this object + /// \throw NotImplemented + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details IsolatedInitialize() does not call Initialize() on attached transformations. If initialization + /// should be propagated, then use the Initialize() function. + /// \details If a derived class does not override IsolatedInitialize(), then the base class throws + /// NotImplemented. + virtual void IsolatedInitialize(const NameValuePairs ¶meters) { + CRYPTOPP_UNUSED(parameters); + throw NotImplemented("BufferedTransformation: this object can't be reinitialized"); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the flush was successful, false otherwise + /// \note hardFlush must be used with care + virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0; + + /// \brief Marks the end of a series of messages, without signal propagation + /// \param blocking specifies whether the object should block when completing the processing on + /// the current series of messages + /// \return true if the message was successful, false otherwise + virtual bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); return false;} + + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the flush was successful, false otherwise + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 + /// means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and + /// output everything, even if there may not be enough data to complete the + /// action. For example, hard flushing a HexDecoder would cause an error if + /// you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can + /// only be done at "synchronization points". These synchronization points + /// are positions in the data stream that are created by hard flushes on the + /// corresponding reverse filters, in this example ZlibCompressor. This is + /// useful when zlib compressed data is moved across a network in packets + /// and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + /// \brief Set propagation of automatically generated and transferred signals + /// \param propagation then new value + /// \details Setting propagation to 0 means do not automatically generate signals. Setting + /// propagation to -1 means unlimited propagation. + virtual void SetAutoSignalPropagation(int propagation) + {CRYPTOPP_UNUSED(propagation);} + + /// \brief Retrieve automatic signal propagation value + /// \return the number of attached transformations the signal is propagated to. 0 indicates + /// the signal is only witnessed by this object + virtual int GetAutoSignalPropagation() const {return 0;} +public: + + /// \name RETRIEVAL OF ONE MESSAGE + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + /// \details The number of bytes available are dependent on the source. If an exact value is + /// available, then the exact value is returned. The exact value can include 0 if the source + /// is exhausted. + /// \details Some stream-based sources do not allow seeking() on the underlying stream, such + /// as some FileSource(). If the stream does not allow seeking() then MaxRetrievable() + /// returns LWORD_MAX to indicate there are still bytes to be retrieved. + virtual lword MaxRetrievable() const; + + /// \brief Determines whether bytes are ready for retrieval + /// \return true if bytes are available for retrieval, false otherwise + virtual bool AnyRetrievable() const; + + /// \brief Retrieve a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte &outByte); + + /// \brief Retrieve a block of bytes + /// \param outString a block of bytes + /// \param getMax the number of bytes to Get + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte *outString, size_t getMax); + + /// \brief Peek a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Get() to detect short reads. + virtual size_t Peek(byte &outByte) const; + + /// \brief Peek a block of bytes + /// \param outString a block of bytes + /// \param peekMax the number of bytes to Peek + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Peek() to detect short reads. + virtual size_t Peek(byte *outString, size_t peekMax) const; + + /// \brief Retrieve a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord16() to detect short reads. + size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Retrieve a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord32() to detect short reads. + size_t GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Retrieve a 64-bit word + /// \param value the 64-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord64() to detect short reads. + /// \since Crypto++ 8.3 + size_t GetWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Peek a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord16() to detect short reads. + size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// \brief Peek a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord32() to detect short reads. + size_t PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// \brief Peek a 64-bit word + /// \param value the 64-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord64() to detect short reads. + /// \since Crypto++ 8.3 + size_t PeekWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// move transferMax bytes of the buffered output to target as input + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param transferMax the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes transferred during the call. + /// \details TransferTo removes bytes from this object and moves them to the destination. + /// \details The function always returns transferMax. If an accurate count is needed, then use TransferTo2(). + lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferTo2(target, transferMax, channel); return transferMax;} + + /// \brief Discard skipMax bytes from the output buffer + /// \param skipMax the number of bytes to discard + /// \details Skip() discards bytes from the output buffer, which is the AttachedTransformation(), if present. + /// The function always returns the parameter skipMax. + /// \details If you want to skip bytes from a Source, then perform the following. + ///
  StringSource ss(str, false, new Redirector(TheBitBucket()));
+		///   ss.Pump(10);    // Skip 10 bytes from Source
+		///   ss.Detach(new FilterChain(...));
+		///   ss.PumpAll();
+		/// 
+ virtual lword Skip(lword skipMax=LWORD_MAX); + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes are not removed from this object. + /// \details The function always returns copyMax. If an accurate count is needed, then use CopyRangeTo2(). + lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {return CopyRangeTo(target, 0, copyMax, channel);} + + /// \brief Copy bytes from this object using an index to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param position the 0-based index of the byte stream to begin the copying + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes remain in this + /// object. Copying begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details The function returns the new position in the stream after transferring the bytes starting at the index. + lword CopyRangeTo(BufferedTransformation &target, lword position, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {lword i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;} + //@} + + /// \name RETRIEVAL OF MULTIPLE MESSAGES + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + virtual lword TotalBytesRetrievable() const; + + /// \brief Provides the number of meesages processed by this object + /// \return the number of meesages processed by this object + /// \details NumberOfMessages returns number of times MessageEnd() has been + /// received minus messages retrieved or skipped + virtual unsigned int NumberOfMessages() const; + + /// \brief Determines if any messages are available for retrieval + /// \return true if NumberOfMessages() > 0, false otherwise + /// \details AnyMessages returns true if NumberOfMessages() > 0 + virtual bool AnyMessages() const; + + /// \brief Start retrieving the next message + /// \return true if a message is ready for retrieval + /// \details GetNextMessage() returns true if a message is ready for retrieval; false + /// if no more messages exist or this message is not completely retrieved. + virtual bool GetNextMessage(); + + /// \brief Skip a number of meessages + /// \param count number of messages to skip + /// \return 0 if the requested number of messages was skipped, non-0 otherwise + /// \details SkipMessages() skips count number of messages. If there is an AttachedTransformation() + /// then SkipMessages() is called on the attached transformation. If there is no attached + /// transformation, then count number of messages are sent to TheBitBucket() using TransferMessagesTo(). + virtual unsigned int SkipMessages(unsigned int count=UINT_MAX); + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. TransferMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully transferred. + unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferMessagesTo2(target, count, channel); return count;} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to copy + /// \param channel the channel on which the copy should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details CopyMessagesTo copies messages from this object to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. CopyMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully copied. + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Skip all messages in the series + virtual void SkipAll(); + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// Internally TransferAllTo() calls TransferAllTo2(). + void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) + {TransferAllTo2(target, channel);} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details CopyAllTo copies messages from this object and copies them to the destination. + void CopyAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Retrieve the next message in a series + /// \return true if a message was retreved, false otherwise + /// \details Internally, the base class implementation returns false. + virtual bool GetNextMessageSeries() {return false;} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessageSeries() const {return 0;} + //@} + + /// \name NON-BLOCKING TRANSFER OF OUTPUT + //@{ + + // upon return, byteCount contains number of bytes that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param byteCount the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the transfer block (i.e., bytes not transferred) + /// \details TransferTo2() removes bytes from this object and moves them to the destination. + /// Transfer begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, + /// byteCount is the requested size of the transfer. When the call returns, byteCount is + /// the number of bytes that were transferred. + virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) =0; + + // upon return, begin contains the start position of data yet to be finished copying, + // and returns the number of bytes left in the current transfer block + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param begin the 0-based index of the first byte to copy in the stream + /// \param end the 0-based index of the last byte to copy in the stream + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the copy block (i.e., bytes not copied) + /// \details CopyRangeTo2 copies bytes from this object to the destination. The bytes are not + /// removed from this object. Copying begins at the index position in the current stream, and + /// not from an absolute position in the stream. + /// \details begin is an \a IN and \a OUT parameter. When the call is made, begin is the + /// starting position of the copy. When the call returns, begin is the position of the first + /// byte that was \a not copied (which may be different than end). begin can be used for + /// subsequent calls to CopyRangeTo2(). + virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0; + + // upon return, messageCount contains number of messages that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param messageCount the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// \details messageCount is an \a IN and \a OUT parameter. When the call is made, messageCount is the + /// the number of messages requested to be transferred. When the call returns, messageCount is the + /// number of messages actually transferred. + size_t TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + + // returns the number of bytes left in the current transfer block + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + size_t TransferAllTo2(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + //@} + + /// \name CHANNELS + //@{ + /// \brief Exception thrown when a filter does not support named channels + struct NoChannelSupport : public NotImplemented + {NoChannelSupport(const std::string &name) : NotImplemented(name + ": this object doesn't support multiple channels") {}}; + /// \brief Exception thrown when a filter does not recognize a named channel + struct InvalidChannelName : public InvalidArgument + {InvalidChannelName(const std::string &name, const std::string &channel) : InvalidArgument(name + ": unexpected channel name \"" + channel + "\"") {}}; + + /// \brief Input a byte for processing on a channel + /// \param channel the channel to process the data. + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true) + {return ChannelPut(channel, &inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, const byte *inString, size_t length, bool blocking=true) + {return ChannelPut2(channel, inString, length, 0, blocking);} + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutModifiable(const std::string &channel, byte *inString, size_t length, bool blocking=true) + {return ChannelPutModifiable2(channel, inString, length, 0, blocking);} + + /// \brief Input a 16-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 16-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Input a 32-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Input a 64-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 64-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord64(const std::string &channel, word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Signal the end of a message + /// \param channel the channel to process the data. + /// \param propagation the number of attached transformations the ChannelMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return !!ChannelPut2(channel, NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the ChannelPutMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t ChannelPutMessageEnd(const std::string &channel, const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param channel the channel to process the data + /// \param size the requested size of the buffer + /// \return a pointer to a memory block with length size + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of + /// an ArraySink(), the pointer to the array is returned and the size is remaining size. + virtual byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages on a channel + /// \param channel the channel to signal the end of a series of messages + /// \param propagation the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + /// \brief Sets the default retrieval channel + /// \param channel the channel to signal the end of a series of messages + /// \note this function may not be implemented in all objects that should support it. + virtual void SetRetrievalChannel(const std::string &channel); + //@} + + /// \name ATTACHMENT + /// \details Some BufferedTransformation objects (e.g. Filter objects) allow other BufferedTransformation objects to be + /// attached. When this is done, the first object instead of buffering its output, sends that output to the attached + /// object as input. The entire attachment chain is deleted when the anchor object is destructed. + + //@{ + /// \brief Determines whether the object allows attachment + /// \return true if the object allows an attachment, false otherwise + /// \details Sources and Filters will returns true, while Sinks and other objects will return false. + virtual bool Attachable() {return false;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual BufferedTransformation *AttachedTransformation() {CRYPTOPP_ASSERT(!Attachable()); return NULLPTR;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual const BufferedTransformation *AttachedTransformation() const + {return const_cast(this)->AttachedTransformation();} + + /// \brief Delete the current attachment chain and attach a new one + /// \param newAttachment the new BufferedTransformation to attach + /// \throw NotImplemented + /// \details Detach() deletes the current attachment chain and replace it with an optional newAttachment + /// \details If a derived class does not override Detach(), then the base class throws + /// NotImplemented. + virtual void Detach(BufferedTransformation *newAttachment = NULLPTR) { + CRYPTOPP_UNUSED(newAttachment); CRYPTOPP_ASSERT(!Attachable()); + throw NotImplemented("BufferedTransformation: this object is not attachable"); + } + + /// \brief Add newAttachment to the end of attachment chain + /// \param newAttachment the attachment to add to the end of the chain + virtual void Attach(BufferedTransformation *newAttachment); + //@} + +protected: + /// \brief Decrements the propagation count while clamping at 0 + /// \return the decremented propagation or 0 + static int DecrementPropagation(int propagation) + {return propagation != 0 ? propagation - 1 : 0;} + +private: + // for ChannelPutWord16, ChannelPutWord32 and ChannelPutWord64, + // to ensure the buffer isn't deallocated before non-blocking + // operation completes + byte m_buf[8]; +}; + +/// \brief An input discarding BufferedTransformation +/// \return a reference to a BufferedTransformation object that discards all input +CRYPTOPP_DLL BufferedTransformation & TheBitBucket(); + +/// \brief Interface for crypto material +/// \details CryptoMaterial() is an interface for crypto material, such as +/// public keys, private keys and crypto parameters. Derived classes generally +/// do not offer public methods such as GenerateRandom() and +/// GenerateRandomWithKeySize(). +/// \sa GeneratableCryptoMaterial() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoMaterial : public NameValuePairs +{ +public: + /// Exception thrown when invalid crypto material is detected + class CRYPTOPP_DLL InvalidMaterial : public InvalidDataFormat + { + public: + explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {} + }; + + virtual ~CryptoMaterial() {} + + /// \brief Assign values to this object + /// \details This function can be used to create a public key from a private key. + virtual void AssignFrom(const NameValuePairs &source) =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \sa ThrowIfInvalid() + virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \throw InvalidMaterial + /// \details Internally, ThrowIfInvalid() calls Validate() and throws InvalidMaterial() if validation fails. + /// \sa Validate() + virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const + {if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");} + + /// \brief Saves a key to a BufferedTransformation + /// \param bt the destination BufferedTransformation + /// \throw NotImplemented + /// \details Save() writes the material to a BufferedTransformation. + /// \details If the material is a key, then the key is written with ASN.1 DER encoding. The key + /// includes an object identifier with an algorthm id, like a subjectPublicKeyInfo. + /// \details A "raw" key without the "key info" can be saved using a key's DEREncode() method. + /// \details If a derived class does not override Save(), then the base class throws + /// NotImplemented(). + virtual void Save(BufferedTransformation &bt) const + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support saving");} + + /// \brief Loads a key from a BufferedTransformation + /// \param bt the source BufferedTransformation + /// \throw KeyingErr + /// \details Load() attempts to read material from a BufferedTransformation. If the + /// material is a key that was generated outside the library, then the following + /// usually applies: + ///
    + ///
  • the key should be ASN.1 BER encoded + ///
  • the key should be a "key info" + ///
+ /// \details "key info" means the key should have an object identifier with an algorthm id, + /// like a subjectPublicKeyInfo. + /// \details To read a "raw" key without the "key info", then call the key's BERDecode() method. + /// \note Load() generally does not check that the key is valid. Call Validate(), if needed. + virtual void Load(BufferedTransformation &bt) + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support loading");} + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + virtual bool SupportsPrecomputation() const {return false;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throw NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(unsigned int precomputationStorage) { + CRYPTOPP_UNUSED(precomputationStorage); CRYPTOPP_ASSERT(!SupportsPrecomputation()); + throw NotImplemented("CryptoMaterial: this object does not support precomputation"); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Perform a quick sanity check + /// \details DoQuickSanityCheck() is for internal library use, and it should not be called by library users. + void DoQuickSanityCheck() const {ThrowIfInvalid(NullRNG(), 0);} + +#if defined(__SUNPRO_CC) + // Sun Studio 11/CC 5.8 workaround: it generates incorrect code + // when casting to an empty virtual base class. JW, 2018: It is + // still a problem in Sun Studio 12.6/CC 5.15 on i386. Just enable + // it everywhere in case it affects SPARC (which we don't test). + char m_sunCCworkaround; +#endif +}; + +/// \brief Interface for crypto material +/// \details GeneratableCryptoMaterial() is an interface for crypto material, +/// such as private keys and crypto parameters. Derived classes offer public +/// methods such as GenerateRandom() and GenerateRandomWithKeySize(). +/// \sa CryptoMaterial() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GeneratableCryptoMaterial : virtual public CryptoMaterial +{ +public: + virtual ~GeneratableCryptoMaterial() {} + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param params additional initialization parameters + /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details If a derived class does not override GenerateRandom(), then the base class throws + /// NotImplemented. + virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(params); + throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation"); + } + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param keySize the size of the key, in bits + /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details GenerateRandomWithKeySize calls GenerateRandom() with a NameValuePairs + /// object with only "KeySize" + void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize); +}; + +/// \brief Interface for public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKey : virtual public CryptoMaterial +{ +}; + +/// \brief Interface for private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKey : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for crypto prameters +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoParameters : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for certificates +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Certificate : virtual public CryptoMaterial +{ +}; + +/// \brief Interface for asymmetric algorithms +/// \details BERDecode() and DEREncode() were removed under Issue 569 +/// and Commit 9b174e84de7a. Programs should use AccessMaterial().Load(bt) +/// or AccessMaterial().Save(bt) instead. +/// \sa Issue 569 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AsymmetricAlgorithm : public Algorithm +{ +public: + virtual ~AsymmetricAlgorithm() {} + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a reference to the crypto material + virtual CryptoMaterial & AccessMaterial() =0; + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a const reference to the crypto material + virtual const CryptoMaterial & GetMaterial() const =0; + +#if 0 + /// \brief Loads this object from a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of BERDecode() changed to Load() at Issue 569. + /// \deprecated for backwards compatibility, calls AccessMaterial().Load(bt) + void BERDecode(BufferedTransformation &bt) + {AccessMaterial().Load(bt);} + + /// \brief Saves this object to a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of DEREncode() changed to Save() at Issue 569. + /// \deprecated for backwards compatibility, calls GetMaterial().Save(bt) + void DEREncode(BufferedTransformation &bt) const + {GetMaterial().Save(bt);} +#endif +}; + +/// \brief Interface for asymmetric algorithms using public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PublicKeyAlgorithm() {} + + // VC60 workaround: no co-variant return type + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + CryptoMaterial & AccessMaterial() + {return AccessPublicKey();} + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + const CryptoMaterial & GetMaterial() const + {return GetPublicKey();} + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + virtual PublicKey & AccessPublicKey() =0; + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + virtual const PublicKey & GetPublicKey() const + {return const_cast(this)->AccessPublicKey();} +}; + +/// \brief Interface for asymmetric algorithms using private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PrivateKeyAlgorithm() {} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + CryptoMaterial & AccessMaterial() {return AccessPrivateKey();} + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + const CryptoMaterial & GetMaterial() const {return GetPrivateKey();} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + virtual PrivateKey & AccessPrivateKey() =0; + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + virtual const PrivateKey & GetPrivateKey() const {return const_cast(this)->AccessPrivateKey();} +}; + +/// \brief Interface for key agreement algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyAgreementAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~KeyAgreementAlgorithm() {} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();} + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + virtual CryptoParameters & AccessCryptoParameters() =0; + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + virtual const CryptoParameters & GetCryptoParameters() const {return const_cast(this)->AccessCryptoParameters();} +}; + +/// \brief Interface for public-key encryptors and decryptors +/// \details This class provides an interface common to encryptors and decryptors +/// for querying their plaintext and ciphertext lengths. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_CryptoSystem +{ +public: + virtual ~PK_CryptoSystem() {} + + /// \brief Provides the maximum length of plaintext for a given ciphertext length + /// \return the maximum size of the plaintext, in bytes + /// \details This function returns 0 if ciphertextLength is not valid (too long or too short). + virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0; + + /// \brief Calculate the length of ciphertext given length of plaintext + /// \return the maximum size of the ciphertext, in bytes + /// \details This function returns 0 if plaintextLength is not valid (too long). + virtual size_t CiphertextLength(size_t plaintextLength) const =0; + + /// \brief Determines whether this object supports the use of a named parameter + /// \param name the name of the parameter + /// \return true if the parameter name is supported, false otherwise + /// \details Some possible parameter names: EncodingParameters(), KeyDerivationParameters() + /// and others Parameters listed in argnames.h + virtual bool ParameterSupported(const char *name) const =0; + + /// \brief Provides the fixed ciphertext length, if one exists + /// \return the fixed ciphertext length if one exists, otherwise 0 + /// \details "Fixed" here means length of ciphertext does not depend on length of plaintext. + /// In this case, it usually does depend on the key length. + virtual size_t FixedCiphertextLength() const {return 0;} + + /// \brief Provides the maximum plaintext length given a fixed ciphertext length + /// \return maximum plaintext length given the fixed ciphertext length, if one exists, + /// otherwise return 0. + /// \details FixedMaxPlaintextLength(0 returns the maximum plaintext length given the fixed ciphertext + /// length, if one exists, otherwise return 0. + virtual size_t FixedMaxPlaintextLength() const {return 0;} +}; + +/// \brief Interface for public-key encryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Encryptor : public PK_CryptoSystem, public PublicKeyAlgorithm +{ +public: + /// \brief Exception thrown when trying to encrypt plaintext of invalid length + class CRYPTOPP_DLL InvalidPlaintextLength : public Exception + { + public: + InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {} + }; + + /// \brief Encrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param plaintext the plaintext byte buffer + /// \param plaintextLength the size of the plaintext byte buffer + /// \param ciphertext a byte buffer to hold the encrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \pre CiphertextLength(plaintextLength) != 0 ensures the plaintext isn't too large + /// \pre COUNTOF(ciphertext) == CiphertextLength(plaintextLength) ensures the output + /// byte buffer is large enough. + /// \sa PK_Decryptor + virtual void Encrypt(RandomNumberGenerator &rng, + const byte *plaintext, size_t plaintextLength, + byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new encryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \details \p attachment can be \p NULL. The caller is responsible for deleting the returned pointer. + /// Encoding parameters should be passed in the "EP" channel. + virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Interface for public-key decryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Decryptor : public PK_CryptoSystem, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Decryptor() {} + + /// \brief Decrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param ciphertextLength the size of the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + virtual DecodingResult Decrypt(RandomNumberGenerator &rng, + const byte *ciphertext, size_t ciphertextLength, + byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new decryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the newly created decryption filter + /// \note the caller is responsible for deleting the returned pointer + virtual BufferedTransformation * CreateDecryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; + + /// \brief Decrypt a fixed size ciphertext + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *ciphertext, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + {return Decrypt(rng, ciphertext, FixedCiphertextLength(), plaintext, parameters);} +}; + +/// \brief Interface for public-key signers and verifiers +/// \details This class provides an interface common to signers and verifiers for querying scheme properties +/// \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme +{ +public: + /// \brief Exception throw when the private or public key has a length that can't be used + /// \details InvalidKeyLength() may be thrown by any function in this class if the private + /// or public key has a length that can't be used + class CRYPTOPP_DLL InvalidKeyLength : public Exception + { + public: + InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {} + }; + + /// \brief Exception throw when the private or public key is too short to sign or verify + /// \details KeyTooShort() may be thrown by any function in this class if the private or public + /// key is too short to sign or verify anything + class CRYPTOPP_DLL KeyTooShort : public InvalidKeyLength + { + public: + KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {} + }; + + virtual ~PK_SignatureScheme() {} + + /// \brief Provides the signature length if it only depends on the key + /// \return the signature length if it only depends on the key, in bytes + /// \details SignatureLength() returns the signature length if it only depends on the key, otherwise 0. + virtual size_t SignatureLength() const =0; + + /// \brief Provides the maximum signature length produced given the length of the recoverable message part + /// \param recoverablePartLength the length of the recoverable message part, in bytes + /// \return the maximum signature length produced for a given length of recoverable message part, in bytes + /// \details MaxSignatureLength() returns the maximum signature length produced given the length of the + /// recoverable message part. + virtual size_t MaxSignatureLength(size_t recoverablePartLength = 0) const + {CRYPTOPP_UNUSED(recoverablePartLength); return SignatureLength();} + + /// \brief Provides the length of longest message that can be recovered + /// \return the length of longest message that can be recovered, in bytes + /// \details MaxRecoverableLength() returns the length of longest message that can be recovered, or 0 if + /// this signature scheme does not support message recovery. + virtual size_t MaxRecoverableLength() const =0; + + /// \brief Provides the length of longest message that can be recovered from a signature of given length + /// \param signatureLength the length of the signature, in bytes + /// \return the length of longest message that can be recovered from a signature of given length, in bytes + /// \details MaxRecoverableLengthFromSignatureLength() returns the length of longest message that can be + /// recovered from a signature of given length, or 0 if this signature scheme does not support message + /// recovery. + virtual size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const =0; + + /// \brief Determines whether a signature scheme requires a random number generator + /// \return true if the signature scheme requires a RandomNumberGenerator() to sign + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + virtual bool IsProbabilistic() const =0; + + /// \brief Determines whether the non-recoverable message part can be signed + /// \return true if the non-recoverable message part can be signed + virtual bool AllowNonrecoverablePart() const =0; + + /// \brief Determines whether the signature must be input before the message + /// \return true if the signature must be input before the message during verifcation + /// \details if SignatureUpfront() returns true, then you must input the signature before the message + /// during verification. Otherwise you can input the signature at anytime. + virtual bool SignatureUpfront() const {return false;} + + /// \brief Determines whether the recoverable part must be input before the non-recoverable part + /// \return true if the recoverable part must be input before the non-recoverable part during signing + /// \details RecoverablePartFirst() determines whether you must input the recoverable part before the + /// non-recoverable part during signing + virtual bool RecoverablePartFirst() const =0; +}; + +/// \brief Interface for accumulating messages to be signed or verified +/// \details Only Update() should be called from the PK_MessageAccumulator() class. No other functions +/// inherited from HashTransformation, like DigestSize() and TruncatedFinal(), should be called. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulator : public HashTransformation +{ +public: + /// \warning DigestSize() should not be called on PK_MessageAccumulator + unsigned int DigestSize() const + {throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");} + + /// \warning TruncatedFinal() should not be called on PK_MessageAccumulator + void TruncatedFinal(byte *digest, size_t digestSize) + { + CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(digestSize); + throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called"); + } +}; + +/// \brief Interface for public-key signers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Signer : public PK_SignatureScheme, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Signer() {} + + /// \brief Create a new HashTransformation to accumulate the message to be signed + /// \param rng a RandomNumberGenerator derived class + /// \return a pointer to a PK_MessageAccumulator + /// \details NewSignatureAccumulator() can be used with all signing methods. Sign() will autimatically delete the + /// accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const =0; + + /// \brief Input a recoverable message to an accumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const =0; + + /// \brief Sign and delete the messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \details Sign() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const; + + /// \brief Sign and restart messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \param restart flag indicating whether the messageAccumulator should be restarted + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0; + + /// \brief Sign a message + /// \param rng a RandomNumberGenerator derived class + /// \param message a pointer to the message + /// \param messageLen the size of the message to be signed + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const; + + /// \brief Sign a recoverable message + /// \param rng a RandomNumberGenerator derived class + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength(recoverableMessageLength) + virtual size_t SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const; +}; + +/// \brief Interface for public-key signature verifiers +/// \details The Recover* functions throw NotImplemented if the signature scheme does not support +/// message recovery. +/// \details The Verify* functions throw InvalidDataFormat if the scheme does support message +/// recovery and the signature contains a non-empty recoverable message part. The +/// Recover* functions should be used in that case. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Verifier : public PK_SignatureScheme, public PublicKeyAlgorithm +{ +public: + virtual ~PK_Verifier() {} + + /// \brief Create a new HashTransformation to accumulate the message to be verified + /// \return a pointer to a PK_MessageAccumulator + /// \details NewVerificationAccumulator() can be used with all verification methods. Verify() will autimatically delete + /// the accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0; + + /// \brief Input signature into a message accumulator + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const =0; + + /// \brief Check whether messageAccumulator contains a valid signature and message + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details Verify() deletes the messageAccumulator, even if an exception is thrown. + virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details VerifyAndRestart() restarts the messageAccumulator + virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Check whether input signature is a valid signature for input message + /// \param message a pointer to the message to be verified + /// \param messageLen the size of the message + /// \param signature a pointer to the signature over the message + /// \param signatureLen the size of the signature + /// \return true if the signature is valid, false otherwise + virtual bool VerifyMessage(const byte *message, size_t messageLen, + const byte *signature, size_t signatureLen) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details Recover() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details RecoverAndRestart() restarts the messageAccumulator + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer for the recovered message + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + /// \return the result of the verification operation + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, + const byte *signature, size_t signatureLength) const; +}; + +/// \brief Interface for domains of simple key agreement protocols +/// \details A key agreement domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~SimpleKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the private key + /// \return size of private keys in this domain + virtual unsigned int PrivateKeyLength() const =0; + + /// \brief Provides the size of the public key + /// \return size of public keys in this domain + virtual unsigned int PublicKeyLength() const =0; + + /// \brief Generate private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateKeyPair() is equivalent to calling GeneratePrivateKey() and then GeneratePublicKey(). + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param privateKey a byte buffer with your private key in this domain + /// \param otherPublicKey a byte buffer with the other party's public key in this domain + /// \param validateOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's public key is validated by default. If you have previously validated the + /// static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(otherPublicKey) == PublicKeyLength() + virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0; +}; + +/// \brief Interface for domains of authenticated key agreement protocols +/// \details In an authenticated key agreement protocol, each party has two +/// key pairs. The long-lived key pair is called the static key pair, +/// and the short-lived key pair is called the ephemeral key pair. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~AuthenticatedKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + virtual unsigned int StaticPrivateKeyLength() const =0; + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + virtual unsigned int StaticPublicKeyLength() const =0; + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a static private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateStaticKeyPair() is equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey(). + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Provides the size of ephemeral private key + /// \return the size of ephemeral private key in this domain + virtual unsigned int EphemeralPrivateKeyLength() const =0; + + /// \brief Provides the size of ephemeral public key + /// \return the size of ephemeral public key in this domain + virtual unsigned int EphemeralPublicKeyLength() const =0; + + /// \brief Generate ephemeral private key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateEphemeralKeyLength() + virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate ephemeral public key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicEphemeralKeyLength() + virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateEphemeralKeyPair() is equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey() + virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param staticPrivateKey a byte buffer with your static private key in this domain + /// \param ephemeralPrivateKey a byte buffer with your ephemeral private key in this domain + /// \param staticOtherPublicKey a byte buffer with the other party's static public key in this domain + /// \param ephemeralOtherPublicKey a byte buffer with the other party's ephemeral public key in this domain + /// \param validateStaticOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's ephemeral public key is validated by default. If you have previously validated + /// the static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + virtual bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const =0; +}; + +// interface for password authenticated key agreement protocols, not implemented yet +#if 0 +/// \brief Interface for protocol sessions +/*! The methods should be called in the following order: + + InitializeSession(rng, parameters); // or call initialize method in derived class + while (true) + { + if (OutgoingMessageAvailable()) + { + length = GetOutgoingMessageLength(); + GetOutgoingMessage(message); + ; // send outgoing message + } + + if (LastMessageProcessed()) + break; + + ; // receive incoming message + ProcessIncomingMessage(message); + } + ; // call methods in derived class to obtain result of protocol session +*/ +class ProtocolSession +{ +public: + /// Exception thrown when an invalid protocol message is processed + class ProtocolError : public Exception + { + public: + ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {} + }; + + /// Exception thrown when a function is called unexpectedly + /*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */ + class UnexpectedMethodCall : public Exception + { + public: + UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {} + }; + + virtual ~ProtocolSession() {} + + ProtocolSession() : m_rng(NULLPTR), m_throwOnProtocolError(true), m_validState(false) {} + + virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs ¶meters) =0; + + bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;} + void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;} + + bool HasValidState() const {return m_validState;} + + virtual bool OutgoingMessageAvailable() const =0; + virtual unsigned int GetOutgoingMessageLength() const =0; + virtual void GetOutgoingMessage(byte *message) =0; + + virtual bool LastMessageProcessed() const =0; + virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0; + +protected: + void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const; + void CheckAndHandleInvalidState() const; + void SetValidState(bool valid) {m_validState = valid;} + + RandomNumberGenerator *m_rng; + +private: + bool m_throwOnProtocolError, m_validState; +}; + +class KeyAgreementSession : public ProtocolSession +{ +public: + virtual ~KeyAgreementSession() {} + + virtual unsigned int GetAgreedValueLength() const =0; + virtual void GetAgreedValue(byte *agreedValue) const =0; +}; + +class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementSession() {} + + void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng, + const byte *myId, unsigned int myIdLength, + const byte *counterPartyId, unsigned int counterPartyIdLength, + const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength); +}; + +/// \brief Password based key agreement domain +/// \since Crypto++ 3.0 +class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementDomain() {} + + /// return whether the domain parameters stored in this object are valid + virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} + + virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0; + virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0; + + enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8}; + + virtual bool IsValidRole(unsigned int role) =0; + virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0; +}; +#endif + +/// \brief Exception thrown when an ASN.1 BER decoing error is encountered +class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument +{ +public: + BERDecodeErr() : InvalidArgument("BER decode error") {} + BERDecodeErr(const std::string &s) : InvalidArgument(s) {} +}; + +/// \brief Interface for encoding and decoding ASN1 objects +/// \details Each class that derives from ASN1Object should provide a serialization format +/// that controls subobject layout. Most of the time the serialization format is +/// taken from a standard, like P1363 or an RFC. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1Object +{ +public: + virtual ~ASN1Object() {} + + /// \brief Decode this object from a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER) + virtual void BERDecode(BufferedTransformation &bt) =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Distinguished Encoding Rules (DER) + virtual void DEREncode(BufferedTransformation &bt) const =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER). + /// \details This may be useful if DEREncode() would be too inefficient. + virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);} +}; + +/// \brief Specifies the build-time version of the library +/// \return integer representing the build-time version +/// \details LibraryVersion can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, LibraryVersion() +/// records the version of the shared object that was built by the third party. +/// The LibraryVersion() record resides in cryptlib.o on Unix compatibles +/// and cryptlib.obj on Windows. It does not change when an app links +/// to the library. +/// \details LibraryVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// 
+/// \sa HeaderVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { + int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT); +} // C linkage + +/// \brief Specifies the runtime version of the library +/// \return integer representing the runtime version +/// \details HeaderVersion() can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, HeaderVersion() +/// records the version of the headers used by the app when the app is compiled. +/// \details HeaderVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// 
+/// \sa LibraryVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { +inline int HeaderVersion() +{ + return CRYPTOPP_VERSION; +} +} // C linkage + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/cryptoppLibLink.h b/extension/third_party/cryptopp/cryptoppLibLink.h new file mode 100644 index 00000000..7d4a68a7 --- /dev/null +++ b/extension/third_party/cryptopp/cryptoppLibLink.h @@ -0,0 +1,22 @@ +#ifndef _CRYPTOPPLIBLINK_H_ +#define _CRYPTOPPLIBLINK_H_ + +#ifdef _DLL +#ifndef CRYPTOPP_IMPORTS +#define CRYPTOPP_IMPORTS +#endif +#endif + +#if defined(CRYPTOPP_IMPORTS) +#include "dll.h" +#else + #ifdef _WIN32 + #ifdef _DEBUG + #pragma comment( lib, "Cryptopp_lib_debug.lib" ) + #else + #pragma comment( lib, "Cryptopp_lib_release.lib" ) + #endif + #endif +#endif + +#endif /* !_CRYPTOPPLIBLINK_H_ */ diff --git a/extension/third_party/cryptopp/darn.cpp b/extension/third_party/cryptopp/darn.cpp new file mode 100644 index 00000000..88d5de56 --- /dev/null +++ b/extension/third_party/cryptopp/darn.cpp @@ -0,0 +1,236 @@ +// darn.cpp - written and placed in public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" +#include "cryptlib.h" +#include "secblock.h" +#include "darn.h" +#include "cpu.h" + +// At the moment only GCC 7.0 (and above) seems to support __builtin_darn() +// and __builtin_darn_32(). Clang 7.0 does not provide them, but it does +// support assembly instructions. XLC is unknown, but there are no hits when +// searching IBM's site. To cover more platforms we provide GCC inline +// assembly like we do with RDRAND and RDSEED. Platforms that don't support +// GCC inline assembly or the builtin will fail the compile. + +// Inline assembler available in GCC 3.2 or above. For practical +// purposes we check for GCC 4.0 or above. GCC imposters claim +// to be GCC 4.2.1 so it will capture them, too. We exclude the +// Apple machines because they are not Power9 and use a slightly +// different syntax in their assembler. +#if ((__GNUC__ >= 4) || defined(__IBM_GCC_ASM)) && !defined(__APPLE__) +# define GCC_DARN_ASM_AVAILABLE 1 +#endif + +// warning C4702: unreachable code +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702) +#endif + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +// *************************** 32-bit *************************** // + +#if (CRYPTOPP_BOOL_PPC32) + +// Fills 4 bytes, buffer must be aligned +inline void DARN32(void* output) +{ + CRYPTOPP_ASSERT(IsAlignedOn(output, GetAlignmentOf())); + word32* ptr = reinterpret_cast(output); + +#if defined(GCC_DARN_ASM_AVAILABLE) + // This is "darn r3, 0". When L=0 a 32-bit conditioned word + // is returned. On failure 0xffffffffffffffff is returned. + // The Power manual recommends only checking the low 32-bit + // word for this case. See Power ISA 3.0 specification, p. 78. + do + { + __asm__ __volatile__ ( + #if (CRYPTOPP_BIG_ENDIAN) + ".byte 0x7c, 0x60, 0x05, 0xe6 \n\t" // r3 = darn 3, 0 + "mr %0, 3 \n\t" // val = r3 + #else + ".byte 0xe6, 0x05, 0x60, 0x7c \n\t" // r3 = darn 3, 0 + "mr %0, 3 \n\t" // val = r3 + #endif + : "=r" (*ptr) : : "r3" + ); + } while (*ptr == 0xFFFFFFFFu); +#elif defined(_ARCH_PWR9) + // This is probably going to break some platforms. + // We will deal with them as we encounter them. + *ptr = __builtin_darn_32(); +#elif defined(__APPLE__) + // Nop. Apple G4 and G5 machines are too old. They will + // avoid this code path because HasPower9() returns false. + CRYPTOPP_ASSERT(0); +#else + // Catch other compile breaks + int XXX[-1]; +#endif +} +#endif // PPC32 + +// *************************** 64-bit *************************** // + +#if (CRYPTOPP_BOOL_PPC64) + +// Fills 8 bytes, buffer must be aligned +inline void DARN64(void* output) +{ + CRYPTOPP_ASSERT(IsAlignedOn(output, GetAlignmentOf())); + word64* ptr = reinterpret_cast(output); + +#if defined(GCC_DARN_ASM_AVAILABLE) + // This is "darn r3, 1". When L=1 a 64-bit conditioned word + // is returned. On failure 0xffffffffffffffff is returned. + // See Power ISA 3.0 specification, p. 78. + do + { + __asm__ __volatile__ ( + #if (CRYPTOPP_BIG_ENDIAN) + ".byte 0x7c, 0x61, 0x05, 0xe6 \n\t" // r3 = darn 3, 1 + "mr %0, 3 \n\t" // val = r3 + #else + ".byte 0xe6, 0x05, 0x61, 0x7c \n\t" // r3 = darn 3, 1 + "mr %0, 3 \n\t" // val = r3 + #endif + : "=r" (*ptr) : : "r3" + ); + } while (*ptr == 0xFFFFFFFFFFFFFFFFull); +#elif defined(_ARCH_PWR9) + // This is probably going to break some platforms. + // We will deal with them as we encounter them. + *ptr = __builtin_darn(); +#elif defined(__APPLE__) + // Nop. Apple G4 and G5 machines are too old. They will + // avoid this code path because HasPower9() returns false. + CRYPTOPP_ASSERT(0); +#else + // Catch other compile breaks + int XXX[-1]; +#endif +} +#endif // PPC64 + +// ************************ Standard C++ ************************ // + +DARN::DARN() +{ + if (!HasDARN()) + throw DARN_Err("HasDARN"); + + // Scratch buffer in case user buffers are unaligned. + m_temp.New(8); +} + +void DARN::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_ASSERT((output && size) || !(output || size)); + if (size == 0) return; + size_t i = 0; + +#if (CRYPTOPP_BOOL_PPC64) + + // Check alignment + i = reinterpret_cast(output) & 0x7; + if (i != 0) + { + DARN64(m_temp); + std::memcpy(output, m_temp, i); + + output += i; + size -= i; + } + + // Output is aligned + for (i = 0; i < size/8; i++) + DARN64(output+i*8); + + output += i*8; + size -= i*8; + + if (size) + { + DARN64(m_temp); + std::memcpy(output, m_temp, size); + } + +#elif (CRYPTOPP_BOOL_PPC32) + + // Check alignment + i = reinterpret_cast(output) & 0x3; + if (i != 0) + { + DARN32(m_temp); + std::memcpy(output, m_temp, i); + + output += i; + size -= i; + } + + // Output is aligned + for (i = 0; i < size/4; i++) + DARN32(output+i*4); + + output += i*4; + size -= i*4; + + if (size) + { + DARN32(m_temp); + std::memcpy(output, m_temp, size); + } + +#else + // No suitable compiler found + CRYPTOPP_UNUSED(output); + throw NotImplemented("DARN: failed to find a suitable implementation"); +#endif +} + +void DARN::DiscardBytes(size_t n) +{ + // RoundUpToMultipleOf is used because a full word is read, and its cheaper + // to discard full words. There's no sense in dealing with tail bytes. + FixedSizeSecBlock discard; + n = RoundUpToMultipleOf(n, sizeof(word64)); + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} + +#else // not PPC32 or PPC64 + +DARN::DARN() +{ + throw DARN_Err("HasDARN"); +} + +void DARN::GenerateBlock(byte *output, size_t size) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); +} + +void DARN::DiscardBytes(size_t n) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(n); +} + +#endif // PPC32 or PPC64 + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/darn.h b/extension/third_party/cryptopp/darn.h new file mode 100644 index 00000000..8965fd04 --- /dev/null +++ b/extension/third_party/cryptopp/darn.h @@ -0,0 +1,95 @@ +// darn.h - written and placed in public domain by Jeffrey Walton +// DARN requires POWER9/ISA 3.0. + +// At the moment only GCC 7.0 (and above) seems to support __builtin_darn() +// and __builtin_darn_32(). However, GCC generates incorrect code. Clang 7.0 +// does not provide them, but it does support assembly instructions. XLC is +// unknown, but there are no hits when searching IBM's site. To cover more +// platforms we provide GCC inline assembly like we do with RDRAND and RDSEED. +// Platforms that don't support GCC inline assembly or the builtin will fail +// to compile. Also see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91481 and +// https://gcc.gnu.org/onlinedocs/gcc/Basic-PowerPC-Built-in-Functions-Available-on-ISA-3_002e0.html + +/// \file darn.h +/// \brief Classes for DARN RNG +/// \sa Power +/// ISA Version 3.0B +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_DARN_H +#define CRYPTOPP_DARN_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a DARN generator encounters +/// a generator related error. +/// \since Crypto++ 8.0 +class DARN_Err : public Exception +{ +public: + DARN_Err(const std::string &operation) + : Exception(OTHER_ERROR, "DARN: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using DARN instruction +/// \details DARN() provides access to Power9's random number generator. The +/// Crypto++ implementation provides conditioned random numbers from the +/// generator as opposed to raw random numbers. According to Power ISA 3.0B +/// manual, a conditioned random number has been processed by hardware to +/// reduce bias. A raw random number is unconditioned noise source output. +/// \details According to Power ISA 3.0B manual, the random number generator +/// provided by the darn instruction is NIST SP800-90B and SP800-90C +/// compliant to the extent possible given the completeness of the standards +/// at the time the hardware is designed. The random number generator provides +/// a minimum of 0.5 bits of entropy per bit. +/// \par Wraps +/// darn instruction +/// \sa Power +/// ISA Version 3.0B, MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 8.0 +class DARN : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "DARN"; } + + virtual ~DARN() {} + + /// \brief Construct a DARN generator + /// \throw DARN_Err if the random number generator is not available + DARN(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "Power9"; + } + +private: + SecBlock > m_temp; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_DARN_H diff --git a/extension/third_party/cryptopp/datatest.cpp b/extension/third_party/cryptopp/datatest.cpp new file mode 100644 index 00000000..8509fb74 --- /dev/null +++ b/extension/third_party/cryptopp/datatest.cpp @@ -0,0 +1,1012 @@ +// datatest.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#define CRYPTOPP_DEFAULT_NO_DLL +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "factory.h" +#include "integer.h" +#include "filters.h" +#include "randpool.h" +#include "files.h" +#include "trunhash.h" +#include "queue.h" +#include "smartptr.h" +#include "validate.h" +#include "stdcpp.h" +#include "misc.h" +#include "hex.h" +#include "trap.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +#ifdef _MSC_VER +# define STRTOUL64 _strtoui64 +#else +# define STRTOUL64 strtoull +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +typedef std::map TestData; +static bool s_thorough = false; + +class TestFailure : public Exception +{ +public: + TestFailure() : Exception(OTHER_ERROR, "Validation test failed") {} +}; + +static const TestData *s_currentTestData = NULLPTR; + +std::string TrimSpace(std::string str) +{ + if (str.empty()) return ""; + + const std::string whitespace(" \r\t\n"); + std::string::size_type beg = str.find_first_not_of(whitespace); + std::string::size_type end = str.find_last_not_of(whitespace); + + if (beg != std::string::npos && end != std::string::npos) + return str.substr(beg, end+1); + else if (beg != std::string::npos) + return str.substr(beg); + else + return ""; +} + +std::string TrimComment(std::string str) +{ + if (str.empty()) return ""; + + std::string::size_type first = str.find("#"); + + if (first != std::string::npos) + return TrimSpace(str.substr(0, first)); + else + return TrimSpace(str); +} + +static void OutputTestData(const TestData &v) +{ + std::cerr << "\n"; + for (TestData::const_iterator i = v.begin(); i != v.end(); ++i) + { + std::cerr << i->first << ": " << i->second << std::endl; + } +} + +static void SignalTestFailure() +{ + OutputTestData(*s_currentTestData); + throw TestFailure(); +} + +static void SignalUnknownAlgorithmError(const std::string& algType) +{ + OutputTestData(*s_currentTestData); + throw Exception(Exception::OTHER_ERROR, "Unknown algorithm " + algType + " during validation test"); +} + +static void SignalTestError(const char* msg = NULLPTR) +{ + OutputTestData(*s_currentTestData); + + if (msg) + throw Exception(Exception::OTHER_ERROR, msg); + else + throw Exception(Exception::OTHER_ERROR, "Unexpected error during validation test"); +} + +bool DataExists(const TestData &data, const char *name) +{ + TestData::const_iterator i = data.find(name); + return (i != data.end()); +} + +const std::string & GetRequiredDatum(const TestData &data, const char *name) +{ + TestData::const_iterator i = data.find(name); + if (i == data.end()) + { + std::string msg("Required datum \"" + std::string(name) + "\" missing"); + SignalTestError(msg.c_str()); + } + return i->second; +} + +void RandomizedTransfer(BufferedTransformation &source, BufferedTransformation &target, bool finish, const std::string &channel=DEFAULT_CHANNEL) +{ + while (source.MaxRetrievable() > (finish ? 0 : 4096)) + { + byte buf[4096+64]; + size_t start = Test::GlobalRNG().GenerateWord32(0, 63); + size_t len = Test::GlobalRNG().GenerateWord32(1, UnsignedMin(4096U, 3*source.MaxRetrievable()/2)); + len = source.Get(buf+start, len); + target.ChannelPut(channel, buf+start, len); + } +} + +void PutDecodedDatumInto(const TestData &data, const char *name, BufferedTransformation &target) +{ + std::string s1 = GetRequiredDatum(data, name), s2; + ByteQueue q; + + while (!s1.empty()) + { + while (s1[0] == ' ') + { + s1 = s1.substr(1); + if (s1.empty()) + goto end; // avoid invalid read if s1 is empty + } + + int repeat = 1; + if (s1[0] == 'r') + { + s1 = s1.erase(0, 1); + repeat = ::atoi(s1.c_str()); + s1 = s1.substr(s1.find(' ')+1); + } + + // Convert word32 or word64 to little endian order. Some algorithm test vectors are + // presented in the format. We probably should have named them word32le and word64le. + if (s1.length() >= 6 && (s1.substr(0,6) == "word32" || s1.substr(0,6) == "word64")) + { + std::istringstream iss(s1.substr(6)); + if (s1.substr(0,6) == "word64") + { + word64 value; + while (iss >> std::skipws >> std::hex >> value) + { + value = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, value); + q.Put(reinterpret_cast(&value), 8); + } + } + else + { + word32 value; + while (iss >> std::skipws >> std::hex >> value) + { + value = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, value); + q.Put(reinterpret_cast(&value), 4); + } + } + goto end; + } + + s2.clear(); + if (s1[0] == '\"') + { + s2 = s1.substr(1, s1.find('\"', 1)-1); + s1 = s1.substr(s2.length() + 2); + } + else if (s1.substr(0, 2) == "0x") + { + std::string::size_type pos = s1.find(' '); + StringSource(s1.substr(2, pos), true, new HexDecoder(new StringSink(s2))); + s1 = s1.substr(STDMIN(pos, s1.length())); + } + else + { + std::string::size_type pos = s1.find(' '); + StringSource(s1.substr(0, pos), true, new HexDecoder(new StringSink(s2))); + s1 = s1.substr(STDMIN(pos, s1.length())); + } + + while (repeat--) + { + q.Put(ConstBytePtr(s2), BytePtrSize(s2)); + RandomizedTransfer(q, target, false); + } + } + +end: + RandomizedTransfer(q, target, true); +} + +std::string GetDecodedDatum(const TestData &data, const char *name) +{ + std::string s; + PutDecodedDatumInto(data, name, StringSink(s).Ref()); + return s; +} + +std::string GetOptionalDecodedDatum(const TestData &data, const char *name) +{ + std::string s; + if (DataExists(data, name)) + PutDecodedDatumInto(data, name, StringSink(s).Ref()); + return s; +} + +class TestDataNameValuePairs : public NameValuePairs +{ +public: + TestDataNameValuePairs(const TestData &data) : m_data(data) {} + + virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + TestData::const_iterator i = m_data.find(name); + if (i == m_data.end()) + { + if (std::string(name) == Name::DigestSize() && valueType == typeid(int)) + { + i = m_data.find("MAC"); + if (i == m_data.end()) + i = m_data.find("Digest"); + if (i == m_data.end()) + return false; + + m_temp.clear(); + PutDecodedDatumInto(m_data, i->first.c_str(), StringSink(m_temp).Ref()); + *reinterpret_cast(pValue) = (int)m_temp.size(); + return true; + } + else + return false; + } + + const std::string &value = i->second; + + if (valueType == typeid(int)) + *reinterpret_cast(pValue) = atoi(value.c_str()); + else if (valueType == typeid(word64)) + { + std::string x(value.empty() ? "0" : value); + const char* beg = &x[0]; + char* end = &x[0] + value.size(); + + errno = 0; + *reinterpret_cast(pValue) = STRTOUL64(beg, &end, 0); + if (errno != 0) + return false; + } + else if (valueType == typeid(Integer)) + *reinterpret_cast(pValue) = Integer((std::string(value) + "h").c_str()); + else if (valueType == typeid(ConstByteArrayParameter)) + { + m_temp.clear(); + PutDecodedDatumInto(m_data, name, StringSink(m_temp).Ref()); + reinterpret_cast(pValue)->Assign(ConstBytePtr(m_temp), BytePtrSize(m_temp), false); + } + else + throw ValueTypeMismatch(name, typeid(std::string), valueType); + + return true; + } + +private: + const TestData &m_data; + mutable std::string m_temp; +}; + +void TestKeyPairValidAndConsistent(CryptoMaterial &pub, const CryptoMaterial &priv) +{ + if (!pub.Validate(Test::GlobalRNG(), 2U+!!s_thorough)) + SignalTestFailure(); + if (!priv.Validate(Test::GlobalRNG(), 2U+!!s_thorough)) + SignalTestFailure(); + + ByteQueue bq1, bq2; + pub.Save(bq1); + pub.AssignFrom(priv); + pub.Save(bq2); + if (bq1 != bq2) + SignalTestFailure(); +} + +void TestSignatureScheme(TestData &v) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + member_ptr signer(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + member_ptr verifier(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + + // Code coverage + (void)signer->AlgorithmName(); + (void)verifier->AlgorithmName(); + (void)signer->AlgorithmProvider(); + (void)verifier->AlgorithmProvider(); + + TestDataNameValuePairs pairs(v); + + if (test == "GenerateKey") + { + signer->AccessPrivateKey().GenerateRandom(Test::GlobalRNG(), pairs); + verifier->AccessPublicKey().AssignFrom(signer->AccessPrivateKey()); + } + else + { + std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); + + if (keyFormat == "DER") + verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); + else if (keyFormat == "Component") + verifier->AccessMaterial().AssignFrom(pairs); + + if (test == "Verify" || test == "NotVerify") + { + SignatureVerificationFilter verifierFilter(*verifier, NULLPTR, SignatureVerificationFilter::SIGNATURE_AT_BEGIN); + PutDecodedDatumInto(v, "Signature", verifierFilter); + PutDecodedDatumInto(v, "Message", verifierFilter); + verifierFilter.MessageEnd(); + if (verifierFilter.GetLastResult() == (test == "NotVerify")) + SignalTestFailure(); + return; + } + else if (test == "PublicKeyValid") + { + if (!verifier->GetMaterial().Validate(Test::GlobalRNG(), 3)) + SignalTestFailure(); + return; + } + + if (keyFormat == "DER") + signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); + else if (keyFormat == "Component") + signer->AccessMaterial().AssignFrom(pairs); + } + + if (test == "GenerateKey" || test == "KeyPairValidAndConsistent") + { + TestKeyPairValidAndConsistent(verifier->AccessMaterial(), signer->GetMaterial()); + SignatureVerificationFilter verifierFilter(*verifier, NULLPTR, SignatureVerificationFilter::THROW_EXCEPTION); + const byte msg[3] = {'a', 'b', 'c'}; + verifierFilter.Put(msg, sizeof(msg)); + StringSource ss(msg, sizeof(msg), true, new SignerFilter(Test::GlobalRNG(), *signer, new Redirector(verifierFilter))); + } + else if (test == "Sign") + { + SignerFilter f(Test::GlobalRNG(), *signer, new HexEncoder(new FileSink(std::cout))); + StringSource ss(GetDecodedDatum(v, "Message"), true, new Redirector(f)); + SignalTestFailure(); + } + else if (test == "DeterministicSign") + { + // This test is specialized for RFC 6979. The RFC is a drop-in replacement + // for DSA and ECDSA, and access to the seed or secret is not needed. If + // additional deterministic signatures are added, then the test harness will + // likely need to be extended. + std::string signature; + SignerFilter f(Test::GlobalRNG(), *signer, new StringSink(signature)); + StringSource ss(GetDecodedDatum(v, "Message"), true, new Redirector(f)); + + if (GetDecodedDatum(v, "Signature") != signature) + SignalTestFailure(); + + return; + } + else + { + std::string msg("Unknown signature test \"" + test + "\""); + SignalTestError(msg.c_str()); + CRYPTOPP_ASSERT(false); + } +} + +void TestAsymmetricCipher(TestData &v) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + member_ptr encryptor(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + member_ptr decryptor(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + + // Code coverage + (void)encryptor->AlgorithmName(); + (void)decryptor->AlgorithmName(); + (void)encryptor->AlgorithmProvider(); + (void)decryptor->AlgorithmProvider(); + + std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); + + if (keyFormat == "DER") + { + decryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); + encryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); + } + else if (keyFormat == "Component") + { + TestDataNameValuePairs pairs(v); + decryptor->AccessMaterial().AssignFrom(pairs); + encryptor->AccessMaterial().AssignFrom(pairs); + } + + if (test == "DecryptMatch") + { + std::string decrypted, expected = GetDecodedDatum(v, "Plaintext"); + StringSource ss(GetDecodedDatum(v, "Ciphertext"), true, new PK_DecryptorFilter(Test::GlobalRNG(), *decryptor, new StringSink(decrypted))); + if (decrypted != expected) + SignalTestFailure(); + } + else if (test == "KeyPairValidAndConsistent") + { + TestKeyPairValidAndConsistent(encryptor->AccessMaterial(), decryptor->GetMaterial()); + } + else + { + std::string msg("Unknown asymmetric cipher test \"" + test + "\""); + SignalTestError(msg.c_str()); + CRYPTOPP_ASSERT(false); + } +} + +void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + std::string key = GetDecodedDatum(v, "Key"); + std::string plaintext = GetDecodedDatum(v, "Plaintext"); + + TestDataNameValuePairs testDataPairs(v); + CombinedNameValuePairs pairs(overrideParameters, testDataPairs); + + if (test == "Encrypt" || test == "EncryptXorDigest" || test == "Resync" || test == "EncryptionMCT" || test == "DecryptionMCT") + { + static member_ptr encryptor, decryptor; + static std::string lastName; + + if (name != lastName) + { + encryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + decryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + lastName = name; + + // Code coverage + (void)encryptor->AlgorithmName(); + (void)decryptor->AlgorithmName(); + (void)encryptor->AlgorithmProvider(); + (void)decryptor->AlgorithmProvider(); + (void)encryptor->MinKeyLength(); + (void)decryptor->MinKeyLength(); + (void)encryptor->MaxKeyLength(); + (void)decryptor->MaxKeyLength(); + (void)encryptor->DefaultKeyLength(); + (void)decryptor->DefaultKeyLength(); + } + + // Most block ciphers don't specify BlockPaddingScheme. Kalyna uses it in test vectors. + // 0 is NoPadding, 1 is ZerosPadding, 2 is PkcsPadding, 3 is OneAndZerosPadding, etc + // Note: The machinery is wired such that paddingScheme is effectively latched. An + // old paddingScheme may be unintentionally used in a subsequent test. + int paddingScheme = pairs.GetIntValueWithDefault(Name::BlockPaddingScheme(), 0); + + ConstByteArrayParameter iv; + if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) + SignalTestFailure(); + + if (test == "Resync") + { + encryptor->Resynchronize(iv.begin(), (int)iv.size()); + decryptor->Resynchronize(iv.begin(), (int)iv.size()); + } + else + { + encryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + decryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + } + + word64 seek64 = pairs.GetWord64ValueWithDefault("Seek64", 0); + if (seek64) + { + encryptor->Seek(seek64); + decryptor->Seek(seek64); + } + else + { + int seek = pairs.GetIntValueWithDefault("Seek", 0); + if (seek) + { + encryptor->Seek(seek); + decryptor->Seek(seek); + } + } + + // If a per-test vector parameter was set for a test, like BlockPadding, + // BlockSize or Tweak, then it becomes latched in testDataPairs. The old + // value is used in subsequent tests, and it could cause a self test + // failure in the next test. The behavior surfaced under Kalyna and + // Threefish. The Kalyna test vectors use NO_PADDING for all tests excpet + // one. For Threefish, using (and not using) a Tweak caused problems as + // we marched through test vectors. For BlockPadding, BlockSize or Tweak, + // unlatch them now, after the key has been set and NameValuePairs have + // been processed. Also note we only unlatch from testDataPairs. If + // overrideParameters are specified, the caller is responsible for + // managing the parameter. + v.erase("Tweak"); v.erase("InitialBlock"); v.erase("BlockSize"); v.erase("BlockPaddingScheme"); + + std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest; + if (test == "EncryptionMCT" || test == "DecryptionMCT") + { + SymmetricCipher *cipher = encryptor.get(); + std::string buf(plaintext), keybuf(key); + + if (test == "DecryptionMCT") + { + cipher = decryptor.get(); + ciphertext = GetDecodedDatum(v, "Ciphertext"); + buf.assign(ciphertext.begin(), ciphertext.end()); + } + + for (int i=0; i<400; i++) + { + encrypted.reserve(10000 * plaintext.size()); + for (int j=0; j<10000; j++) + { + cipher->ProcessString(BytePtr(buf), BytePtrSize(buf)); + encrypted.append(buf.begin(), buf.end()); + } + + encrypted.erase(0, encrypted.size() - keybuf.size()); + xorbuf(BytePtr(keybuf), BytePtr(encrypted), BytePtrSize(keybuf)); + cipher->SetKey(BytePtr(keybuf), BytePtrSize(keybuf)); + } + + encrypted.assign(buf.begin(), buf.end()); + ciphertext = GetDecodedDatum(v, test == "EncryptionMCT" ? "Ciphertext" : "Plaintext"); + if (encrypted != ciphertext) + { + std::cout << "\nincorrectly encrypted: "; + StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); + xx.Pump(256); xx.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + return; + } + + StreamTransformationFilter encFilter(*encryptor, new StringSink(encrypted), + static_cast(paddingScheme)); + + StringStore pstore(plaintext); + RandomizedTransfer(pstore, encFilter, true); + encFilter.MessageEnd(); + + if (test != "EncryptXorDigest") + { + ciphertext = GetDecodedDatum(v, "Ciphertext"); + } + else + { + ciphertextXorDigest = GetDecodedDatum(v, "CiphertextXorDigest"); + xorDigest.append(encrypted, 0, 64); + for (size_t i=64; i(xorDigest[i%64] ^ encrypted[i]); + } + if (test != "EncryptXorDigest" ? encrypted != ciphertext : xorDigest != ciphertextXorDigest) + { + std::cout << "\nincorrectly encrypted: "; + StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); + xx.Pump(2048); xx.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + + std::string decrypted; + StreamTransformationFilter decFilter(*decryptor, new StringSink(decrypted), + static_cast(paddingScheme)); + + StringStore cstore(encrypted); + RandomizedTransfer(cstore, decFilter, true); + decFilter.MessageEnd(); + + if (decrypted != plaintext) + { + std::cout << "\nincorrectly decrypted: "; + StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout))); + xx.Pump(256); xx.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + } + else + { + std::string msg("Unknown symmetric cipher test \"" + test + "\""); + SignalTestError(msg.c_str()); + } +} + +void TestAuthenticatedSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) +{ + std::string type = GetRequiredDatum(v, "AlgorithmType"); + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + std::string key = GetDecodedDatum(v, "Key"); + + std::string plaintext = GetOptionalDecodedDatum(v, "Plaintext"); + std::string ciphertext = GetOptionalDecodedDatum(v, "Ciphertext"); + std::string header = GetOptionalDecodedDatum(v, "Header"); + std::string footer = GetOptionalDecodedDatum(v, "Footer"); + std::string mac = GetOptionalDecodedDatum(v, "MAC"); + + TestDataNameValuePairs testDataPairs(v); + CombinedNameValuePairs pairs(overrideParameters, testDataPairs); + + if (test == "Encrypt" || test == "EncryptXorDigest" || test == "NotVerify") + { + member_ptr encryptor, decryptor; + encryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + decryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + encryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + decryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + + // Code coverage + (void)encryptor->AlgorithmName(); + (void)decryptor->AlgorithmName(); + + std::string encrypted, decrypted; + AuthenticatedEncryptionFilter ef(*encryptor, new StringSink(encrypted)); + bool macAtBegin = !mac.empty() && !Test::GlobalRNG().GenerateBit(); // test both ways randomly + AuthenticatedDecryptionFilter df(*decryptor, new StringSink(decrypted), macAtBegin ? AuthenticatedDecryptionFilter::MAC_AT_BEGIN : 0); + + if (encryptor->NeedsPrespecifiedDataLengths()) + { + encryptor->SpecifyDataLengths(header.size(), plaintext.size(), footer.size()); + decryptor->SpecifyDataLengths(header.size(), plaintext.size(), footer.size()); + } + + StringStore sh(header), sp(plaintext), sc(ciphertext), sf(footer), sm(mac); + + if (macAtBegin) + RandomizedTransfer(sm, df, true); + sh.CopyTo(df, LWORD_MAX, AAD_CHANNEL); + RandomizedTransfer(sc, df, true); + sf.CopyTo(df, LWORD_MAX, AAD_CHANNEL); + if (!macAtBegin) + RandomizedTransfer(sm, df, true); + df.MessageEnd(); + + RandomizedTransfer(sh, ef, true, AAD_CHANNEL); + RandomizedTransfer(sp, ef, true); + RandomizedTransfer(sf, ef, true, AAD_CHANNEL); + ef.MessageEnd(); + + if (test == "Encrypt" && encrypted != ciphertext+mac) + { + std::cout << "\nincorrectly encrypted: "; + StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); + xx.Pump(2048); xx.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + if (test == "Encrypt" && decrypted != plaintext) + { + std::cout << "\nincorrectly decrypted: "; + StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout))); + xx.Pump(256); xx.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + + if (ciphertext.size()+mac.size()-plaintext.size() != encryptor->DigestSize()) + { + std::cout << "\nbad MAC size\n"; + SignalTestFailure(); + } + if (df.GetLastResult() != (test == "Encrypt")) + { + std::cout << "\nMAC incorrectly verified\n"; + SignalTestFailure(); + } + } + else + { + std::string msg("Unknown authenticated symmetric cipher test \"" + test + "\""); + SignalTestError(msg.c_str()); + } +} + +void TestDigestOrMAC(TestData &v, bool testDigest) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + const char *digestName = testDigest ? "Digest" : "MAC"; + + member_ptr mac; + member_ptr hash; + HashTransformation *pHash = NULLPTR; + + TestDataNameValuePairs pairs(v); + + if (testDigest) + { + hash.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + pHash = hash.get(); + + // Code coverage + (void)hash->AlgorithmName(); + (void)hash->AlgorithmProvider(); + } + else + { + mac.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + pHash = mac.get(); + std::string key = GetDecodedDatum(v, "Key"); + mac->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + + // Code coverage + (void)mac->AlgorithmName(); + (void)mac->AlgorithmProvider(); + } + + if (test == "Verify" || test == "VerifyTruncated" || test == "NotVerify") + { + int digestSize = -1; + if (test == "VerifyTruncated") + digestSize = pairs.GetIntValueWithDefault(Name::DigestSize(), digestSize); + HashVerificationFilter verifierFilter(*pHash, NULLPTR, HashVerificationFilter::HASH_AT_BEGIN, digestSize); + PutDecodedDatumInto(v, digestName, verifierFilter); + PutDecodedDatumInto(v, "Message", verifierFilter); + verifierFilter.MessageEnd(); + if (verifierFilter.GetLastResult() == (test == "NotVerify")) + SignalTestFailure(); + } + else + { + std::string msg("Unknown digest or mac test \"" + test + "\""); + SignalTestError(msg.c_str()); + } +} + +void TestKeyDerivationFunction(TestData &v) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + if(test == "Skip") return; + CRYPTOPP_ASSERT(test == "Verify"); + + std::string secret = GetDecodedDatum(v, "Secret"); + std::string expected = GetDecodedDatum(v, "DerivedKey"); + + TestDataNameValuePairs pairs(v); + + member_ptr kdf; + kdf.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + + std::string calculated; calculated.resize(expected.size()); + kdf->DeriveKey(BytePtr(calculated), BytePtrSize(calculated), BytePtr(secret), BytePtrSize(secret), pairs); + + if(calculated != expected) + { + std::cerr << "Calculated: "; + StringSource(calculated, true, new HexEncoder(new FileSink(std::cerr))); + std::cerr << std::endl; + + SignalTestFailure(); + } +} + +inline char FirstChar(const std::string& str) { + if (str.empty()) return 0; + return str[0]; +} + +inline char LastChar(const std::string& str) { + if (str.empty()) return 0; + return str[str.length()-1]; +} + +// GetField parses the name/value pairs. The tricky part is the insertion operator +// because Unix&Linux uses LF, OS X uses CR, and Windows uses CRLF. If this function +// is modified, then run 'cryptest.exe tv rsa_pkcs1_1_5' as a test. Its the parser +// file from hell. If it can be parsed without error, then things are likely OK. +// For istream.fail() see https://stackoverflow.com/q/34395801/608639. +bool GetField(std::istream &is, std::string &name, std::string &value) +{ + std::string line; + name.clear(); value.clear(); + + // ***** Name ***** + while (is >> std::ws && std::getline(is, line)) + { + // Eat whitespace and comments gracefully + if (line.empty() || line[0] == '#') + continue; + + std::string::size_type pos = line.find(':'); + if (pos == std::string::npos) + SignalTestError("Unable to parse name/value pair"); + + name = TrimSpace(line.substr(0, pos)); + line = TrimSpace(line.substr(pos + 1)); + + // Empty name is bad + if (name.empty()) + return false; + + // Empty value is ok + if (line.empty()) + return true; + + break; + } + + // ***** Value ***** + bool continueLine = true; + + do + { + // Trim leading and trailing whitespace, including OS X and Windows + // new lines. Don't parse comments here because there may be a line + // continuation at the end. + line = TrimSpace(line); + + continueLine = false; + if (line.empty()) + continue; + + // Early out for immediate line continuation + if (line[0] == '\\') { + continueLine = true; + continue; + } + // Check end of line. It must be last character + if (LastChar(line) == '\\') { + continueLine = true; + line.erase(line.end()-1); + line = TrimSpace(line); + } + + // Re-trim after parsing + line = TrimComment(line); + + if (line.empty()) + continue; + + // Finally... the value + value += line; + + if (continueLine) + value += ' '; + } + while (continueLine && is >> std::ws && std::getline(is, line)); + + return true; +} + +void OutputPair(const NameValuePairs &v, const char *name) +{ + Integer x; + bool b = v.GetValue(name, x); + CRYPTOPP_UNUSED(b); CRYPTOPP_ASSERT(b); + std::cout << name << ": \\\n "; + x.Encode(HexEncoder(new FileSink(std::cout), false, 64, "\\\n ").Ref(), x.MinEncodedSize()); + std::cout << std::endl; +} + +void OutputNameValuePairs(const NameValuePairs &v) +{ + std::string names = v.GetValueNames(); + std::string::size_type i = 0; + while (i < names.size()) + { + std::string::size_type j = names.find_first_of (';', i); + + if (j == std::string::npos) + return; + else + { + std::string name = names.substr(i, j-i); + if (name.find(':') == std::string::npos) + OutputPair(v, name.c_str()); + } + + i = j + 1; + } +} + +void TestDataFile(std::string filename, const NameValuePairs &overrideParameters, unsigned int &totalTests, unsigned int &failedTests) +{ + filename = DataDir(filename); + std::ifstream file(filename.c_str()); + if (!file.good()) + throw Exception(Exception::OTHER_ERROR, "Can not open file " + filename + " for reading"); + + TestData v; + s_currentTestData = &v; + std::string name, value, lastAlgName; + + while (file) + { + if (!GetField(file, name, value)) + break; + + if (name == "AlgorithmType") + v.clear(); + + // Can't assert value. Plaintext is sometimes empty. + // CRYPTOPP_ASSERT(!value.empty()); + v[name] = value; + + if (name == "Test" && (s_thorough || v["SlowTest"] != "1")) + { + bool failed = true; + std::string algType = GetRequiredDatum(v, "AlgorithmType"); + + if (lastAlgName != GetRequiredDatum(v, "Name")) + { + lastAlgName = GetRequiredDatum(v, "Name"); + std::cout << "\nTesting " << algType.c_str() << " algorithm " << lastAlgName.c_str() << ".\n"; + } + + try + { + if (algType == "Signature") + TestSignatureScheme(v); + else if (algType == "SymmetricCipher") + TestSymmetricCipher(v, overrideParameters); + else if (algType == "AuthenticatedSymmetricCipher") + TestAuthenticatedSymmetricCipher(v, overrideParameters); + else if (algType == "AsymmetricCipher") + TestAsymmetricCipher(v); + else if (algType == "MessageDigest") + TestDigestOrMAC(v, true); + else if (algType == "MAC") + TestDigestOrMAC(v, false); + else if (algType == "KDF") + TestKeyDerivationFunction(v); + else if (algType == "FileList") + TestDataFile(GetRequiredDatum(v, "Test"), g_nullNameValuePairs, totalTests, failedTests); + else + SignalUnknownAlgorithmError(algType); + failed = false; + } + catch (const TestFailure &) + { + std::cout << "\nTest FAILED.\n"; + } + catch (const CryptoPP::Exception &e) + { + std::cout << "\nCryptoPP::Exception caught: " << e.what() << std::endl; + } + catch (const std::exception &e) + { + std::cout << "\nstd::exception caught: " << e.what() << std::endl; + } + + if (failed) + { + std::cout << "Skipping to next test.\n"; + failedTests++; + } + else + std::cout << "." << std::flush; + + totalTests++; + } + } +} + +bool RunTestDataFile(const char *filename, const NameValuePairs &overrideParameters, bool thorough) +{ + s_thorough = thorough; + unsigned int totalTests = 0, failedTests = 0; + TestDataFile((filename ? filename : ""), overrideParameters, totalTests, failedTests); + + std::cout << std::dec << "\nTests complete. Total tests = " << totalTests << ". Failed tests = " << failedTests << "." << std::endl; + if (failedTests != 0) + std::cout << "SOME TESTS FAILED!\n"; + + CRYPTOPP_ASSERT(failedTests == 0); + return failedTests == 0; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/default.cpp b/extension/third_party/cryptopp/default.cpp new file mode 100644 index 00000000..ab1890b5 --- /dev/null +++ b/extension/third_party/cryptopp/default.cpp @@ -0,0 +1,307 @@ +// default.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4127 4189) +#endif + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" +#include "default.h" +#include "queue.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +// The purpose of this function Mash() is to take an arbitrary length input +// string and *deterministicly* produce an arbitrary length output string such +// that (1) it looks random, (2) no information about the input is +// deducible from it, and (3) it contains as much entropy as it can hold, or +// the amount of entropy in the input string, whichever is smaller. + +template +static void Mash(const byte *in, size_t inLen, byte *out, size_t outLen, int iterations) +{ + if (BytePrecision(outLen) > 2) + throw InvalidArgument("Mash: output legnth too large"); + + size_t bufSize = RoundUpToMultipleOf(outLen, (size_t)H::DIGESTSIZE); + byte b[2]; + SecByteBlock buf(bufSize); + SecByteBlock outBuf(bufSize); + H hash; + + unsigned int i; + for(i=0; i> 8); + b[1] = (byte) i; + hash.Update(b, 2); + hash.Update(in, inLen); + hash.Final(outBuf+i); + } + + while (iterations-- > 1) + { + memcpy(buf, outBuf, bufSize); + for (i=0; i> 8); + b[1] = (byte) i; + hash.Update(b, 2); + hash.Update(buf, bufSize); + hash.Final(outBuf+i); + } + } + + memcpy(out, outBuf, outLen); +} + +template +static void GenerateKeyIV(const byte *passphrase, size_t passphraseLength, const byte *salt, size_t saltLength, unsigned int iterations, byte *key, byte *IV) +{ + // UBsan. User supplied params, may be NULL + SecByteBlock temp(passphraseLength+saltLength); + if (passphrase != NULLPTR) + memcpy(temp, passphrase, passphraseLength); + if (salt != NULLPTR) + memcpy(temp+passphraseLength, salt, saltLength); + + // OK. Derived params, cannot be NULL + SecByteBlock keyIV(Info::KEYLENGTH+Info::BLOCKSIZE); + Mash(temp, passphraseLength + saltLength, keyIV, Info::KEYLENGTH+Info::BLOCKSIZE, iterations); + memcpy(key, keyIV, Info::KEYLENGTH); + memcpy(IV, keyIV+Info::KEYLENGTH, Info::BLOCKSIZE); +} + +// ******************************************************** + +template +DataEncryptor::DataEncryptor(const char *passphrase, BufferedTransformation *attachment) + : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase((const byte *)passphrase, strlen(passphrase)) +{ + CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= DIGESTSIZE); + CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); +} + +template +DataEncryptor::DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) + : ProxyFilter(NULLPTR, 0, 0, attachment), m_passphrase(passphrase, passphraseLength) +{ + CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); + CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); +} + +template +void DataEncryptor::FirstPut(const byte *) +{ + SecByteBlock salt(DIGESTSIZE), keyCheck(DIGESTSIZE); + H hash; + + // use hash(passphrase | time | clock) as salt + hash.Update(m_passphrase, m_passphrase.size()); + time_t t=time(NULLPTR); + hash.Update((byte *)&t, sizeof(t)); + clock_t c=clock(); + hash.Update((byte *)&c, sizeof(c)); + hash.Final(salt); + + // use hash(passphrase | salt) as key check + hash.Update(m_passphrase, m_passphrase.size()); + hash.Update(salt, SALTLENGTH); + hash.Final(keyCheck); + + AttachedTransformation()->Put(salt, SALTLENGTH); + + // mash passphrase and salt together into key and IV + SecByteBlock key(KEYLENGTH); + SecByteBlock IV(BLOCKSIZE); + GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV); + + m_cipher.SetKeyWithIV(key, key.size(), IV); + SetFilter(new StreamTransformationFilter(m_cipher)); + + m_filter->Put(keyCheck, BLOCKSIZE); +} + +template +void DataEncryptor::LastPut(const byte *inString, size_t length) +{ + CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + m_filter->MessageEnd(); +} + +// ******************************************************** + +template +DataDecryptor::DataDecryptor(const char *p, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULLPTR, SALTLENGTH+BLOCKSIZE, 0, attachment) + , m_state(WAITING_FOR_KEYCHECK) + , m_passphrase((const byte *)p, strlen(p)) + , m_throwException(throwException) +{ + CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); + CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); +} + +template +DataDecryptor::DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULLPTR, SALTLENGTH+BLOCKSIZE, 0, attachment) + , m_state(WAITING_FOR_KEYCHECK) + , m_passphrase(passphrase, passphraseLength) + , m_throwException(throwException) +{ + CRYPTOPP_COMPILE_ASSERT((int)SALTLENGTH <= (int)DIGESTSIZE); + CRYPTOPP_COMPILE_ASSERT((int)BLOCKSIZE <= (int)DIGESTSIZE); +} + +template +void DataDecryptor::FirstPut(const byte *inString) +{ + CheckKey(inString, inString+SALTLENGTH); +} + +template +void DataDecryptor::LastPut(const byte *inString, size_t length) +{ + CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + if (m_filter.get() == NULLPTR) + { + m_state = KEY_BAD; + if (m_throwException) + throw KeyBadErr(); + } + else + { + m_filter->MessageEnd(); + m_state = WAITING_FOR_KEYCHECK; + } +} + +template +void DataDecryptor::CheckKey(const byte *salt, const byte *keyCheck) +{ + SecByteBlock check(STDMAX((unsigned int)2*BLOCKSIZE, (unsigned int)DIGESTSIZE)); + + H hash; + hash.Update(m_passphrase, m_passphrase.size()); + hash.Update(salt, SALTLENGTH); + hash.Final(check); + + SecByteBlock key(KEYLENGTH); + SecByteBlock IV(BLOCKSIZE); + GenerateKeyIV(m_passphrase, m_passphrase.size(), salt, SALTLENGTH, ITERATIONS, key, IV); + + m_cipher.SetKeyWithIV(key, key.size(), IV); + member_ptr decryptor(new StreamTransformationFilter(m_cipher)); + + decryptor->Put(keyCheck, BLOCKSIZE); + decryptor->ForceNextPut(); + decryptor->Get(check+BLOCKSIZE, BLOCKSIZE); + + SetFilter(decryptor.release()); + + if (!VerifyBufsEqual(check, check+BLOCKSIZE, BLOCKSIZE)) + { + m_state = KEY_BAD; + if (m_throwException) + throw KeyBadErr(); + } + else + m_state = KEY_GOOD; +} + +// ******************************************************** + +template +static MAC* NewDataEncryptorMAC(const byte *passphrase, size_t passphraseLength) +{ + size_t macKeyLength = MAC::StaticGetValidKeyLength(16); + SecByteBlock macKey(macKeyLength); + // since the MAC is encrypted there is no reason to mash the passphrase for many iterations + Mash(passphrase, passphraseLength, macKey, macKeyLength, 1); + return new MAC(macKey, macKeyLength); +} + +template +DataEncryptorWithMAC::DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment) + : ProxyFilter(NULLPTR, 0, 0, attachment) + , m_mac(NewDataEncryptorMAC((const byte *)passphrase, strlen(passphrase))) +{ + SetFilter(new HashFilter(*m_mac, new DataEncryptor(passphrase), true)); +} + +template +DataEncryptorWithMAC::DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment) + : ProxyFilter(NULLPTR, 0, 0, attachment) + , m_mac(NewDataEncryptorMAC(passphrase, passphraseLength)) +{ + SetFilter(new HashFilter(*m_mac, new DataEncryptor(passphrase, passphraseLength), true)); +} + +template +void DataEncryptorWithMAC::LastPut(const byte *inString, size_t length) +{ + CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + m_filter->MessageEnd(); +} + +// ******************************************************** + +template +DataDecryptorWithMAC::DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULLPTR, 0, 0, attachment) + , m_mac(NewDataEncryptorMAC((const byte *)passphrase, strlen(passphrase))) + , m_throwException(throwException) +{ + SetFilter(new DataDecryptor(passphrase, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException)); +} + +template +DataDecryptorWithMAC::DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment, bool throwException) + : ProxyFilter(NULLPTR, 0, 0, attachment) + , m_mac(NewDataEncryptorMAC(passphrase, passphraseLength)) + , m_throwException(throwException) +{ + SetFilter(new DataDecryptor(passphrase, passphraseLength, m_hashVerifier=new HashVerificationFilter(*m_mac, NULLPTR, HashVerificationFilter::PUT_MESSAGE), throwException)); +} + +template +typename DataDecryptor::State DataDecryptorWithMAC::CurrentState() const +{ + return static_cast *>(m_filter.get())->CurrentState(); +} + +template +bool DataDecryptorWithMAC::CheckLastMAC() const +{ + return m_hashVerifier->GetLastResult(); +} + +template +void DataDecryptorWithMAC::LastPut(const byte *inString, size_t length) +{ + CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + m_filter->MessageEnd(); + if (m_throwException && !CheckLastMAC()) + throw MACBadErr(); +} + +template struct DataParametersInfo; +template struct DataParametersInfo; + +template class DataEncryptor; +template class DataDecryptor; +template class DataEncryptor; +template class DataDecryptor; +template class DataEncryptorWithMAC; +template class DataDecryptorWithMAC; +template class DataEncryptorWithMAC; +template class DataDecryptorWithMAC; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/default.h b/extension/third_party/cryptopp/default.h new file mode 100644 index 00000000..da9cfb8d --- /dev/null +++ b/extension/third_party/cryptopp/default.h @@ -0,0 +1,310 @@ +// default.h - originally written and placed in the public domain by Wei Dai + +/// \file default.h +/// \brief Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC + +#ifndef CRYPTOPP_DEFAULT_H +#define CRYPTOPP_DEFAULT_H + +#include "sha.h" +#include "hmac.h" +#include "aes.h" +#include "des.h" +#include "modes.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Legacy block cipher for LegacyEncryptor, LegacyDecryptor, LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef DES_EDE2 LegacyBlockCipher; +/// \brief Legacy hash for use with LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef SHA1 LegacyHashModule; +/// \brief Legacy HMAC for use withLegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef HMAC LegacyMAC; + +/// \brief Default block cipher for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef AES DefaultBlockCipher; +/// \brief Default hash for use with DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef SHA256 DefaultHashModule; +/// \brief Default HMAC for use withDefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef HMAC DefaultMAC; + +/// \brief Exception thrown when LegacyDecryptorWithMAC or DefaultDecryptorWithMAC decryption error is encountered +class DataDecryptorErr : public Exception +{ +public: + DataDecryptorErr(const std::string &s) + : Exception(DATA_INTEGRITY_CHECK_FAILED, s) {} +}; + +/// \brief Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class KeyBadErr : public DataDecryptorErr +{ + public: KeyBadErr() + : DataDecryptorErr("DataDecryptor: cannot decrypt message with this passphrase") {} +}; + +/// \brief Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class MACBadErr : public DataDecryptorErr +{ + public: MACBadErr() + : DataDecryptorErr("DataDecryptorWithMAC: MAC check failed") {} +}; + +/// \brief Algorithm information for password-based encryptors and decryptors +template +struct DataParametersInfo +{ + CRYPTOPP_CONSTANT(BLOCKSIZE = BlockSize); + CRYPTOPP_CONSTANT(KEYLENGTH = KeyLength); + CRYPTOPP_CONSTANT(SALTLENGTH = SaltSize); + CRYPTOPP_CONSTANT(DIGESTSIZE = DigestSize); + CRYPTOPP_CONSTANT(ITERATIONS = Iterations); +}; + +typedef DataParametersInfo LegacyParametersInfo; +typedef DataParametersInfo DefaultParametersInfo; + +/// \brief Password-based Encryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataEncryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Construct a DataEncryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Construct a DataEncryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *); + void LastPut(const byte *inString, size_t length); + +private: + SecByteBlock m_passphrase; + typename CBC_Mode::Encryption m_cipher; +}; + +/// \brief Password-based Decryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataDecryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD}; + State CurrentState() const {return m_state;} + +protected: + void FirstPut(const byte *inString); + void LastPut(const byte *inString, size_t length); + + State m_state; + +private: + void CheckKey(const byte *salt, const byte *keyCheck); + + SecByteBlock m_passphrase; + typename CBC_Mode::Decryption m_cipher; + member_ptr m_decryptor; + bool m_throwException; + +}; + +/// \brief Password-based encryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataEncryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataEncryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + +}; + +/// \brief Password-based decryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataDecryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataDecryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifiying whether an Exception should be thrown on error + DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + typename DataDecryptor::State CurrentState() const; + bool CheckLastMAC() const; + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + HashVerificationFilter *m_hashVerifier; + bool m_throwException; +}; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Password-based encryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptorWithMAC : public DataDecryptorWithMAC {}; +/// \brief Password-based encryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptorWithMAC : public DataDecryptorWithMAC {}; +#else +typedef DataEncryptor LegacyEncryptor; +typedef DataDecryptor LegacyDecryptor; + +typedef DataEncryptor DefaultEncryptor; +typedef DataDecryptor DefaultDecryptor; + +typedef DataEncryptorWithMAC LegacyEncryptorWithMAC; +typedef DataDecryptorWithMAC LegacyDecryptorWithMAC; + +typedef DataEncryptorWithMAC DefaultEncryptorWithMAC; +typedef DataDecryptorWithMAC DefaultDecryptorWithMAC; +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/des.cpp b/extension/third_party/cryptopp/des.cpp new file mode 100644 index 00000000..2a130aa4 --- /dev/null +++ b/extension/third_party/cryptopp/des.cpp @@ -0,0 +1,465 @@ +// des.cpp - modified by Wei Dai from Phil Karn's des.c +// The original code and all modifications are in the public domain. + +/* + * This is a major rewrite of my old public domain DES code written + * circa 1987, which in turn borrowed heavily from Jim Gillogly's 1977 + * public domain code. I pretty much kept my key scheduling code, but + * the actual encrypt/decrypt routines are taken from from Richard + * Outerbridge's DES code as printed in Schneier's "Applied Cryptography." + * + * This code is in the public domain. I would appreciate bug reports and + * enhancements. + * + * Phil Karn KA9Q, karn@unix.ka9q.ampr.org, August 1994. + */ + +#include "pch.h" +#include "misc.h" +#include "des.h" + +NAMESPACE_BEGIN(CryptoPP) + +typedef BlockGetAndPut Block; + +// Richard Outerbridge's initial permutation algorithm +/* +inline void IPERM(word32 &left, word32 &right) +{ + word32 work; + + work = ((left >> 4) ^ right) & 0x0f0f0f0f; + right ^= work; + left ^= work << 4; + work = ((left >> 16) ^ right) & 0xffff; + right ^= work; + left ^= work << 16; + work = ((right >> 2) ^ left) & 0x33333333; + left ^= work; + right ^= (work << 2); + work = ((right >> 8) ^ left) & 0xff00ff; + left ^= work; + right ^= (work << 8); + right = rotl(right, 1); + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = rotl(left, 1); +} +inline void FPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotr(right, 1); + work = (left ^ right) & 0xaaaaaaaa; + left ^= work; + right ^= work; + left = rotr(left, 1); + work = ((left >> 8) ^ right) & 0xff00ff; + right ^= work; + left ^= work << 8; + work = ((left >> 2) ^ right) & 0x33333333; + right ^= work; + left ^= work << 2; + work = ((right >> 16) ^ left) & 0xffff; + left ^= work; + right ^= work << 16; + work = ((right >> 4) ^ left) & 0x0f0f0f0f; + left ^= work; + right ^= work << 4; +} +*/ + +// Wei Dai's modification to Richard Outerbridge's initial permutation +// algorithm, this one is faster if you have access to rotate instructions +// (like in MSVC) +static inline void IPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotlConstant<4>(right); + work = (left ^ right) & 0xf0f0f0f0; + left ^= work; + right = rotrConstant<20>(right^work); + work = (left ^ right) & 0xffff0000; + left ^= work; + right = rotrConstant<18>(right^work); + work = (left ^ right) & 0x33333333; + left ^= work; + right = rotrConstant<6>(right^work); + work = (left ^ right) & 0x00ff00ff; + left ^= work; + right = rotlConstant<9>(right^work); + work = (left ^ right) & 0xaaaaaaaa; + left = rotlConstant<1>(left^work); + right ^= work; +} + +static inline void FPERM(word32 &left, word32 &right) +{ + word32 work; + + right = rotrConstant<1>(right); + work = (left ^ right) & 0xaaaaaaaa; + right ^= work; + left = rotrConstant<9>(left^work); + work = (left ^ right) & 0x00ff00ff; + right ^= work; + left = rotlConstant<6>(left^work); + work = (left ^ right) & 0x33333333; + right ^= work; + left = rotlConstant<18>(left^work); + work = (left ^ right) & 0xffff0000; + right ^= work; + left = rotlConstant<20>(left^work); + work = (left ^ right) & 0xf0f0f0f0; + right ^= work; + left = rotrConstant<4>(left^work); +} + +void DES::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + RawSetKey(GetCipherDirection(), userKey); +} + +#ifndef CRYPTOPP_IMPORTS + +/* Tables defined in the Data Encryption Standard documents + * Three of these tables, the initial permutation, the final + * permutation and the expansion operator, are regular enough that + * for speed, we hard-code them. They're here for reference only. + * Also, the S and P boxes are used by a separate program, gensp.c, + * to build the combined SP box, Spbox[]. They're also here just + * for reference. + */ +#ifdef notdef +/* initial permutation IP */ +static byte ip[] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +/* final permutation IP^-1 */ +static byte fp[] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; +/* expansion operation matrix */ +static byte ei[] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; +/* The (in)famous S-boxes */ +static byte sbox[8][64] = { + /* S1 */ + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + + /* S2 */ + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + + /* S3 */ + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + + /* S4 */ + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + + /* S5 */ + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + + /* S6 */ + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + + /* S7 */ + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + + /* S8 */ + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 +}; + +/* 32-bit permutation function P used on the output of the S-boxes */ +namespace { + const byte p32i[] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 + }; +} +#endif + +/* permuted choice table (key) */ +namespace { + const byte pc1[] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 + }; +} + +/* number left rotations of pc1 */ +namespace { + const byte totrot[] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 + }; +} + +/* permuted choice key (table) */ +namespace { + const byte pc2[] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + }; +} + +/* End of DES-defined tables */ + +/* bit 0 is left-most in byte */ +namespace { + const int bytebit[] = { + 0200,0100,040,020,010,04,02,01 + }; +} + +/* Set key (initialize key schedule array) */ +void RawDES::RawSetKey(CipherDir dir, const byte *key) +{ +#if (_MSC_VER >= 1600) || (__cplusplus >= 201103L) +# define REGISTER /* Define to nothing for C++11 and above */ +#else +# define REGISTER register +#endif + + SecByteBlock buffer(56+56+8); + byte *const pc1m=buffer; /* place to modify pc1 into */ + byte *const pcr=pc1m+56; /* place to rotate pc1 into */ + byte *const ks=pcr+56; + REGISTER int i,j,l; + int m; + + for (j=0; j<56; j++) { /* convert pc1 to bits of key */ + l=pc1[j]-1; /* integer bit location */ + m = l & 07; /* find bit */ + pc1m[j]=(key[l>>3] & /* find which key byte l is in */ + bytebit[m]) /* and which bit of that byte */ + ? 1 : 0; /* and store 1-bit result */ + } + for (i=0; i<16; i++) { /* key chunk for each iteration */ + memset(ks,0,8); /* Clear key schedule */ + for (j=0; j<56; j++) /* rotate pc1 the right amount */ + pcr[j] = pc1m[(l=j+totrot[i])<(j<28? 28 : 56) ? l: l-28]; + /* rotate left and right halves independently */ + for (j=0; j<48; j++){ /* select bits individually */ + /* check bit that goes to ks[j] */ + if (pcr[pc2[j]-1]){ + /* mask it in if it's there */ + l= j % 6; + ks[j/6] |= bytebit[l] >> 2; + } + } + /* Now convert to odd/even interleaved form for use in F */ + k[2*i] = ((word32)ks[0] << 24) + | ((word32)ks[2] << 16) + | ((word32)ks[4] << 8) + | ((word32)ks[6]); + k[2*i+1] = ((word32)ks[1] << 24) + | ((word32)ks[3] << 16) + | ((word32)ks[5] << 8) + | ((word32)ks[7]); + } + + if (dir==DECRYPTION) // reverse key schedule order + for (i=0; i<16; i+=2) + { + std::swap(k[i], k[32-2-i]); + std::swap(k[i+1], k[32-1-i]); + } +} + +void RawDES::RawProcessBlock(word32 &l_, word32 &r_) const +{ + word32 l = l_, r = r_; + const word32 *kptr=k; + + for (unsigned i=0; i<8; i++) + { + word32 work = rotrConstant<4>(r) ^ kptr[4 * i + 0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrConstant<4>(l) ^ kptr[4 * i + 2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + l_ = l; r_ = r; +} + +void DES_EDE2::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + m_des1.RawSetKey(GetCipherDirection(), userKey); + m_des2.RawSetKey(ReverseCipherDir(GetCipherDirection()), userKey+8); +} + +void DES_EDE2::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + m_des1.RawProcessBlock(l, r); + m_des2.RawProcessBlock(r, l); + m_des1.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +void DES_EDE3::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + m_des1.RawSetKey(GetCipherDirection(), userKey + (IsForwardTransformation() ? 0 : 16)); + m_des2.RawSetKey(ReverseCipherDir(GetCipherDirection()), userKey + 8); + m_des3.RawSetKey(GetCipherDirection(), userKey + (IsForwardTransformation() ? 16 : 0)); +} + +void DES_EDE3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + m_des1.RawProcessBlock(l, r); + m_des2.RawProcessBlock(r, l); + m_des3.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +#endif // #ifndef CRYPTOPP_IMPORTS + +static inline bool CheckParity(byte b) +{ + unsigned int a = b ^ (b >> 4); + return ((a ^ (a>>1) ^ (a>>2) ^ (a>>3)) & 1) == 1; +} + +bool DES::CheckKeyParityBits(const byte *key) +{ + for (unsigned int i=0; i<8; i++) + if (!CheckParity(key[i])) + return false; + return true; +} + +void DES::CorrectKeyParityBits(byte *key) +{ + for (unsigned int i=0; i<8; i++) + if (!CheckParity(key[i])) + key[i] ^= 1; +} + +// Encrypt or decrypt a block of data in ECB mode +void DES::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 l,r; + Block::Get(inBlock)(l)(r); + IPERM(l,r); + RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xorBlock, outBlock)(r)(l); +} + +void DES_XEX3::Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + if (!m_des.get()) + m_des.reset(new DES::Encryption); + + memcpy(m_x1, key + (IsForwardTransformation() ? 0 : 16), BLOCKSIZE); + m_des->RawSetKey(GetCipherDirection(), key + 8); + memcpy(m_x3, key + (IsForwardTransformation() ? 16 : 0), BLOCKSIZE); +} + +void DES_XEX3::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + xorbuf(outBlock, inBlock, m_x1, BLOCKSIZE); + m_des->ProcessAndXorBlock(outBlock, xorBlock, outBlock); + xorbuf(outBlock, m_x3, BLOCKSIZE); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/des.h b/extension/third_party/cryptopp/des.h new file mode 100644 index 00000000..ece7b378 --- /dev/null +++ b/extension/third_party/cryptopp/des.h @@ -0,0 +1,163 @@ +// des.h - originally written and placed in the public domain by Wei Dai + +/// \file des.h +/// \brief Classes for DES, 2-key Triple-DES, 3-key Triple-DES and DESX + +#ifndef CRYPTOPP_DES_H +#define CRYPTOPP_DES_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DES block cipher base class +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RawDES +{ +public: + void RawSetKey(CipherDir direction, const byte *userKey); + void RawProcessBlock(word32 &l, word32 &r) const; + +protected: + static const word32 Spbox[8][64]; + + FixedSizeSecBlock k; +}; + +/// \brief DES block cipher information +/// \since Crypto++ 1.0 +struct DES_Info : public FixedBlockSize<8>, public FixedKeyLength<8> +{ + // disable DES in DLL version by not exporting this function + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES";} +}; + +/// \brief DES block cipher +/// \details The DES implementation in Crypto++ ignores the parity bits +/// (the least significant bits of each byte) in the key. However you can use CheckKeyParityBits() +/// and CorrectKeyParityBits() to check or correct the parity bits if you wish. +/// \sa DES +/// \since Crypto++ 1.0 +class DES : public DES_Info, public BlockCipherDocumentation +{ + /// \brief DES block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl, public RawDES + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + /// check DES key parity bits + static bool CheckKeyParityBits(const byte *key); + /// correct DES key parity bits + static void CorrectKeyParityBits(byte *key); + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 2-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE2";} +}; + +/// \brief 2-key TripleDES block cipher +/// \sa DES-EDE2 +/// \since Crypto++ 1.0 +class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE2 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 3-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE3";} +}; + +/// \brief 3-key TripleDES block cipher +/// \sa DES-EDE3 +/// \since Crypto++ 1.0 +class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE3 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2, m_des3; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief DESX block cipher information +/// \since Crypto++ 3.2 +struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES-XEX3";} +}; + +/// \brief DESX block cipher +/// \sa DES-XEX3, AKA DESX +/// \since Crypto++ 3.2 +class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation +{ + /// \brief DES_XEX3 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_x1, m_x3; + // VS2005 workaround: calling modules compiled with /clr gets unresolved external symbol DES::Base::ProcessAndXorBlock + // if we use DES::Encryption here directly without value_ptr. + value_ptr m_des; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef DES::Encryption DESEncryption; +typedef DES::Decryption DESDecryption; + +typedef DES_EDE2::Encryption DES_EDE2_Encryption; +typedef DES_EDE2::Decryption DES_EDE2_Decryption; + +typedef DES_EDE3::Encryption DES_EDE3_Encryption; +typedef DES_EDE3::Decryption DES_EDE3_Decryption; + +typedef DES_XEX3::Encryption DES_XEX3_Encryption; +typedef DES_XEX3::Decryption DES_XEX3_Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dessp.cpp b/extension/third_party/cryptopp/dessp.cpp new file mode 100644 index 00000000..46ca7aaf --- /dev/null +++ b/extension/third_party/cryptopp/dessp.cpp @@ -0,0 +1,88 @@ +// This file is mostly generated by Phil Karn's gensp.c + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "des.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 RawDES::Spbox[8][64] = { +{ +0x01010400,0x00000000,0x00010000,0x01010404, 0x01010004,0x00010404,0x00000004,0x00010000, +0x00000400,0x01010400,0x01010404,0x00000400, 0x01000404,0x01010004,0x01000000,0x00000004, +0x00000404,0x01000400,0x01000400,0x00010400, 0x00010400,0x01010000,0x01010000,0x01000404, +0x00010004,0x01000004,0x01000004,0x00010004, 0x00000000,0x00000404,0x00010404,0x01000000, +0x00010000,0x01010404,0x00000004,0x01010000, 0x01010400,0x01000000,0x01000000,0x00000400, +0x01010004,0x00010000,0x00010400,0x01000004, 0x00000400,0x00000004,0x01000404,0x00010404, +0x01010404,0x00010004,0x01010000,0x01000404, 0x01000004,0x00000404,0x00010404,0x01010400, +0x00000404,0x01000400,0x01000400,0x00000000, 0x00010004,0x00010400,0x00000000,0x01010004}, +{ +0x80108020,0x80008000,0x00008000,0x00108020, 0x00100000,0x00000020,0x80100020,0x80008020, +0x80000020,0x80108020,0x80108000,0x80000000, 0x80008000,0x00100000,0x00000020,0x80100020, +0x00108000,0x00100020,0x80008020,0x00000000, 0x80000000,0x00008000,0x00108020,0x80100000, +0x00100020,0x80000020,0x00000000,0x00108000, 0x00008020,0x80108000,0x80100000,0x00008020, +0x00000000,0x00108020,0x80100020,0x00100000, 0x80008020,0x80100000,0x80108000,0x00008000, +0x80100000,0x80008000,0x00000020,0x80108020, 0x00108020,0x00000020,0x00008000,0x80000000, +0x00008020,0x80108000,0x00100000,0x80000020, 0x00100020,0x80008020,0x80000020,0x00100020, +0x00108000,0x00000000,0x80008000,0x00008020, 0x80000000,0x80100020,0x80108020,0x00108000}, +{ +0x00000208,0x08020200,0x00000000,0x08020008, 0x08000200,0x00000000,0x00020208,0x08000200, +0x00020008,0x08000008,0x08000008,0x00020000, 0x08020208,0x00020008,0x08020000,0x00000208, +0x08000000,0x00000008,0x08020200,0x00000200, 0x00020200,0x08020000,0x08020008,0x00020208, +0x08000208,0x00020200,0x00020000,0x08000208, 0x00000008,0x08020208,0x00000200,0x08000000, +0x08020200,0x08000000,0x00020008,0x00000208, 0x00020000,0x08020200,0x08000200,0x00000000, +0x00000200,0x00020008,0x08020208,0x08000200, 0x08000008,0x00000200,0x00000000,0x08020008, +0x08000208,0x00020000,0x08000000,0x08020208, 0x00000008,0x00020208,0x00020200,0x08000008, +0x08020000,0x08000208,0x00000208,0x08020000, 0x00020208,0x00000008,0x08020008,0x00020200}, +{ +0x00802001,0x00002081,0x00002081,0x00000080, 0x00802080,0x00800081,0x00800001,0x00002001, +0x00000000,0x00802000,0x00802000,0x00802081, 0x00000081,0x00000000,0x00800080,0x00800001, +0x00000001,0x00002000,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002001,0x00002080, +0x00800081,0x00000001,0x00002080,0x00800080, 0x00002000,0x00802080,0x00802081,0x00000081, +0x00800080,0x00800001,0x00802000,0x00802081, 0x00000081,0x00000000,0x00000000,0x00802000, +0x00002080,0x00800080,0x00800081,0x00000001, 0x00802001,0x00002081,0x00002081,0x00000080, +0x00802081,0x00000081,0x00000001,0x00002000, 0x00800001,0x00002001,0x00802080,0x00800081, +0x00002001,0x00002080,0x00800000,0x00802001, 0x00000080,0x00800000,0x00002000,0x00802080}, +{ +0x00000100,0x02080100,0x02080000,0x42000100, 0x00080000,0x00000100,0x40000000,0x02080000, +0x40080100,0x00080000,0x02000100,0x40080100, 0x42000100,0x42080000,0x00080100,0x40000000, +0x02000000,0x40080000,0x40080000,0x00000000, 0x40000100,0x42080100,0x42080100,0x02000100, +0x42080000,0x40000100,0x00000000,0x42000000, 0x02080100,0x02000000,0x42000000,0x00080100, +0x00080000,0x42000100,0x00000100,0x02000000, 0x40000000,0x02080000,0x42000100,0x40080100, +0x02000100,0x40000000,0x42080000,0x02080100, 0x40080100,0x00000100,0x02000000,0x42080000, +0x42080100,0x00080100,0x42000000,0x42080100, 0x02080000,0x00000000,0x40080000,0x42000000, +0x00080100,0x02000100,0x40000100,0x00080000, 0x00000000,0x40080000,0x02080100,0x40000100}, +{ +0x20000010,0x20400000,0x00004000,0x20404010, 0x20400000,0x00000010,0x20404010,0x00400000, +0x20004000,0x00404010,0x00400000,0x20000010, 0x00400010,0x20004000,0x20000000,0x00004010, +0x00000000,0x00400010,0x20004010,0x00004000, 0x00404000,0x20004010,0x00000010,0x20400010, +0x20400010,0x00000000,0x00404010,0x20404000, 0x00004010,0x00404000,0x20404000,0x20000000, +0x20004000,0x00000010,0x20400010,0x00404000, 0x20404010,0x00400000,0x00004010,0x20000010, +0x00400000,0x20004000,0x20000000,0x00004010, 0x20000010,0x20404010,0x00404000,0x20400000, +0x00404010,0x20404000,0x00000000,0x20400010, 0x00000010,0x00004000,0x20400000,0x00404010, +0x00004000,0x00400010,0x20004010,0x00000000, 0x20404000,0x20000000,0x00400010,0x20004010}, +{ +0x00200000,0x04200002,0x04000802,0x00000000, 0x00000800,0x04000802,0x00200802,0x04200800, +0x04200802,0x00200000,0x00000000,0x04000002, 0x00000002,0x04000000,0x04200002,0x00000802, +0x04000800,0x00200802,0x00200002,0x04000800, 0x04000002,0x04200000,0x04200800,0x00200002, +0x04200000,0x00000800,0x00000802,0x04200802, 0x00200800,0x00000002,0x04000000,0x00200800, +0x04000000,0x00200800,0x00200000,0x04000802, 0x04000802,0x04200002,0x04200002,0x00000002, +0x00200002,0x04000000,0x04000800,0x00200000, 0x04200800,0x00000802,0x00200802,0x04200800, +0x00000802,0x04000002,0x04200802,0x04200000, 0x00200800,0x00000000,0x00000002,0x04200802, +0x00000000,0x00200802,0x04200000,0x00000800, 0x04000002,0x04000800,0x00000800,0x00200002}, +{ +0x10001040,0x00001000,0x00040000,0x10041040, 0x10000000,0x10001040,0x00000040,0x10000000, +0x00040040,0x10040000,0x10041040,0x00041000, 0x10041000,0x00041040,0x00001000,0x00000040, +0x10040000,0x10000040,0x10001000,0x00001040, 0x00041000,0x00040040,0x10040040,0x10041000, +0x00001040,0x00000000,0x00000000,0x10040040, 0x10000040,0x10001000,0x00041040,0x00040000, +0x00041040,0x00040000,0x10041000,0x00001000, 0x00000040,0x10040040,0x00001000,0x00041040, +0x10001000,0x00000040,0x10000040,0x10040000, 0x10040040,0x10000000,0x00040000,0x10001040, +0x00000000,0x10041040,0x00040040,0x10000040, 0x10040000,0x10001000,0x10001040,0x00000000, +0x10041040,0x00041000,0x00041000,0x00001040, 0x00001040,0x00040040,0x10000000,0x10041000} +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dh.cpp b/extension/third_party/cryptopp/dh.cpp new file mode 100644 index 00000000..5a0e7d1d --- /dev/null +++ b/extension/third_party/cryptopp/dh.cpp @@ -0,0 +1,21 @@ +// dh.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "dh.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void DH_TestInstantiations() +{ + DH dh1; + DH dh2(NullRNG(), 10); +} +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dh.h b/extension/third_party/cryptopp/dh.h new file mode 100644 index 00000000..4f462e48 --- /dev/null +++ b/extension/third_party/cryptopp/dh.h @@ -0,0 +1,275 @@ +// dh.h - originally written and placed in the public domain by Wei Dai + +/// \file dh.h +/// \brief Classes for Diffie-Hellman key exchange + +#ifndef CRYPTOPP_DH_H +#define CRYPTOPP_DH_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Diffie-Hellman domain +/// \tparam GROUP_PARAMETERS group parameters +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \details For COFACTOR_OPTION, see CofactorMultiplicationOption. +/// \sa DL_SimpleKeyAgreementDomainBase +/// \since Crypto++ 1.0 +template +class DH_Domain : public DL_SimpleKeyAgreementDomainBase +{ + typedef DL_SimpleKeyAgreementDomainBase Base; + +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef DL_KeyAgreementAlgorithm_DH DH_Algorithm; + typedef DH_Domain Domain; + + virtual ~DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + /// \param params group parameters and options + DH_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a Diffie-Hellman domain + /// \param bt BufferedTransformation with group parameters and options + DH_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Generate a public key from a private key in this domain + /// \param rng RandomNumberGenerator derived class + /// \param privateKey byte buffer with the previously generated private key + /// \param publicKey byte buffer for the generated public key in this domain + /// \details If using a FIPS 140-2 validated library on Windows, then this class will perform + /// a self test to ensure the key pair is pairwise consistent. Non-FIPS and non-Windows + /// builds of the library do not provide FIPS validated cryptography, so the code should be + /// removed by the optimizer. + /// \pre COUNTOF(publicKey) == PublicKeyLength() + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + Base::GeneratePublicKey(rng, privateKey, publicKey); + + if (FIPS_140_2_ComplianceEnabled()) + { + SecByteBlock privateKey2(this->PrivateKeyLength()); + this->GeneratePrivateKey(rng, privateKey2); + + SecByteBlock publicKey2(this->PublicKeyLength()); + Base::GeneratePublicKey(rng, privateKey2, publicKey2); + + SecByteBlock agreedValue(this->AgreedValueLength()), agreedValue2(this->AgreedValueLength()); + bool agreed1 = this->Agree(agreedValue, privateKey, publicKey2); + bool agreed2 = this->Agree(agreedValue2, privateKey2, publicKey); + + if (!agreed1 || !agreed2 || agreedValue != agreedValue2) + throw SelfTestFailure(this->AlgorithmName() + ": pairwise consistency test failed"); + } + } + + static std::string CRYPTOPP_API StaticAlgorithmName() + {return GroupParameters::StaticAlgorithmNamePrefix() + DH_Algorithm::StaticAlgorithmName();} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + DL_GroupParameters & AccessAbstractGroupParameters() + {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DH_Domain; + +/// \brief Diffie-Hellman in GF(p) +/// \details DH() class is a typedef of DH_Domain(). The documentation that follows +/// does not exist. Rather the documentation was created in response to Issue +/// 328, Diffie-Hellman example code not compiling. +/// \details Generally speaking, a DH() object is ephemeral and is intended to execute one instance of the Diffie-Hellman protocol. The +/// private and public key parts are not intended to be set or persisted. Rather, a new set of domain parameters are generated each +/// time an object is created. +/// \details Once a DH() object is created, once can retrieve the ephemeral public key for the other party with code similar to the +/// following. +///
   AutoSeededRandomPool prng;
+///   Integer p, q, g;
+///   PrimeAndGenerator pg;
+///
+///   pg.Generate(1, prng, 512, 511);
+///   p = pg.Prime();
+///   q = pg.SubPrime();
+///   g = pg.Generator();
+///
+///   DH dh(p, q, g);
+///   SecByteBlock t1(dh.PrivateKeyLength()), t2(dh.PublicKeyLength());
+///   dh.GenerateKeyPair(prng, t1, t2);
+///   Integer k1(t1, t1.size()), k2(t2, t2.size());
+///
+///   cout << "Private key:\n";
+///   cout << hex << k1 << endl;
+///
+///   cout << "Public key:\n";
+///   cout << hex << k2 << endl;
+/// +/// \details Output of the program above will be similar to the following. +///
   $ ./cryptest.exe
+///   Private key:
+///   72b45a42371545e9d4880f48589aefh
+///   Public key:
+///   45fdb13f97b1840626f0250cec1dba4a23b894100b51fb5d2dd13693d789948f8bfc88f9200014b2
+///   ba8dd8a6debc471c69ef1e2326c61184a2eca88ec866346bh
+/// \sa Diffie-Hellman on the Crypto++ wiki and +/// Diffie-Hellman in GF(p) with key validation +/// \since Crypto++ 1.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +struct DH : public DH_Domain +{ + typedef DH_Domain GroupParameters; + typedef GroupParameters::Element Element; + + virtual ~DH() {} + + /// \brief Create an uninitialized Diffie-Hellman object + DH() : DH_Domain() {} + + /// \brief Initialize a Diffie-Hellman object + /// \param bt BufferedTransformation with group parameters and options + DH(BufferedTransformation &bt) : DH_Domain(bt) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param params group parameters and options + DH(const GroupParameters ¶ms) : DH_Domain(params) {} + + /// \brief Create a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + DH(RandomNumberGenerator &rng, unsigned int modulusBits) : DH_Domain(rng, modulusBits) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + DH(const Integer &p, const Integer &g) : DH_Domain(p, g) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + DH(const Integer &p, const Integer &q, const Integer &g) : DH_Domain(p, q, g) {} + + /// \brief Creates a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {AccessGroupParameters().Initialize(rng, modulusBits);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + void Initialize(const Integer &p, const Integer &g) + {AccessGroupParameters().Initialize(p, g);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {AccessGroupParameters().Initialize(p, q, g);} +}; +#else +// The real DH class is a typedef. +typedef DH_Domain DH; +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dh2.cpp b/extension/third_party/cryptopp/dh2.cpp new file mode 100644 index 00000000..4c062d4e --- /dev/null +++ b/extension/third_party/cryptopp/dh2.cpp @@ -0,0 +1,69 @@ +// dh2.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "cryptlib.h" +#include "misc.h" +#include "dh2.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +struct NullCryptoParameters : public CryptoParameters +{ + void AssignFrom(const NameValuePairs &source) { + CRYPTOPP_UNUSED(source); + } + bool Validate(RandomNumberGenerator &rng, unsigned int level) const { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level); + return false; + } + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const { + CRYPTOPP_UNUSED(name); CRYPTOPP_UNUSED(valueType); CRYPTOPP_UNUSED(pValue); + return false; + } +}; + +struct NullSimpleKeyAgreementDomain : public TwoBases +{ + CryptoParameters & AccessCryptoParameters() { + return *this; + } + unsigned int AgreedValueLength() const { + return 1; + } + unsigned int PrivateKeyLength() const { + return 1; + } + unsigned int PublicKeyLength() const { + return 1; + } + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(privateKey); + } + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(privateKey); CRYPTOPP_UNUSED(publicKey); + } + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const { + CRYPTOPP_UNUSED(agreedValue); CRYPTOPP_UNUSED(privateKey); + CRYPTOPP_UNUSED(otherPublicKey); CRYPTOPP_UNUSED(validateOtherPublicKey); + return false; + } +}; + +void DH2_TestInstantiations() +{ + NullSimpleKeyAgreementDomain dom; + DH2 dh(dom); +} +#endif + +bool DH2::Agree(byte *agreedValue, + const byte *staticSecretKey, const byte *ephemeralSecretKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey) const +{ + return d1.Agree(agreedValue, staticSecretKey, staticOtherPublicKey, validateStaticOtherPublicKey) + && d2.Agree(agreedValue+d1.AgreedValueLength(), ephemeralSecretKey, ephemeralOtherPublicKey, true); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/dh2.h b/extension/third_party/cryptopp/dh2.h new file mode 100644 index 00000000..b86161d7 --- /dev/null +++ b/extension/third_party/cryptopp/dh2.h @@ -0,0 +1,70 @@ +// dh2.h - originally written and placed in the public domain by Wei Dai + +/// \file dh2.h +/// \brief Classes for Unified Diffie-Hellman key exchange +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_DH2_H +#define CRYPTOPP_DH2_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Unified Diffie-Hellman in GF(p) +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \sa AuthenticatedKeyAgreementDomain, Unified Diffie-Hellman +/// \since Crypto++ 3.0 +class DH2 : public AuthenticatedKeyAgreementDomain +{ +public: + virtual ~DH2() {} + + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &domain) + : d1(domain), d2(domain) {} + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &staticDomain, SimpleKeyAgreementDomain &ephemeralDomain) + : d1(staticDomain), d2(ephemeralDomain) {} + + CryptoParameters & AccessCryptoParameters() {return d1.AccessCryptoParameters();} + + unsigned int AgreedValueLength() const + {return d1.AgreedValueLength() + d2.AgreedValueLength();} + + unsigned int StaticPrivateKeyLength() const + {return d1.PrivateKeyLength();} + unsigned int StaticPublicKeyLength() const + {return d1.PublicKeyLength();} + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d1.GeneratePrivateKey(rng, privateKey);} + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d1.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d1.GenerateKeyPair(rng, privateKey, publicKey);} + + unsigned int EphemeralPrivateKeyLength() const + {return d2.PrivateKeyLength();} + unsigned int EphemeralPublicKeyLength() const + {return d2.PublicKeyLength();} + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d2.GeneratePrivateKey(rng, privateKey);} + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d2.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d2.GenerateKeyPair(rng, privateKey, publicKey);} + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const; + +protected: + SimpleKeyAgreementDomain &d1, &d2; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dll.cpp b/extension/third_party/cryptopp/dll.cpp new file mode 100644 index 00000000..df301f66 --- /dev/null +++ b/extension/third_party/cryptopp/dll.cpp @@ -0,0 +1,169 @@ +// dll.cpp - originally written and placed in the public domain by Wei Dai + +#define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#define CRYPTOPP_DEFAULT_NO_DLL + +#include "dll.h" +#include "config.h" +#include "iterhash.h" +#include "pkcspad.h" +#include "emsa2.h" + +#if defined(CRYPTOPP_MSC_VERSION) +// Cast from FARPROC to funcptr with args, http://stackoverflow.com/q/4192058/608639 +# pragma warning(disable: 4191) +#endif + +#if defined(CRYPTOPP_EXPORTS) && defined(CRYPTOPP_WIN32_AVAILABLE) +# include +#endif + +#ifndef CRYPTOPP_IMPORTS + +NAMESPACE_BEGIN(CryptoPP) + +// Guarding based on DLL due to Clang, http://github.com/weidai11/cryptopp/issues/300 +#if defined(CRYPTOPP_IS_DLL) +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40}; +template<> const unsigned int PKCS_DigestDecoration::length = sizeof(PKCS_DigestDecoration::decoration); + +// http://github.com/weidai11/cryptopp/issues/517. OIDs and encoded prefixes found at +// http://www.ietf.org/archive/id/draft-jivsov-openpgp-sha3-01.txt +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x31,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x08,0x05, 0x00,0x04,0x20}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x41,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x09,0x05, 0x00,0x04,0x30}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x51,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x0a,0x05, 0x00,0x04,0x40}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte EMSA2HashId::id = 0x33; +template<> const byte EMSA2HashId::id = 0x38; +template<> const byte EMSA2HashId::id = 0x34; +template<> const byte EMSA2HashId::id = 0x36; +template<> const byte EMSA2HashId::id = 0x35; + +#endif // CRYPTOPP_IS_DLL + +NAMESPACE_END + +#endif + +#ifdef CRYPTOPP_EXPORTS + +USING_NAMESPACE(CryptoPP) + +using std::set_new_handler; + +static PNew s_pNew = NULLPTR; +static PDelete s_pDelete = NULLPTR; + +static void * New (size_t size) +{ + void *p; + while ((p = malloc(size)) == NULLPTR) + CallNewHandler(); + + return p; +} + +static void SetNewAndDeleteFunctionPointers() +{ + void *p = NULLPTR; + HMODULE hModule = NULLPTR; + MEMORY_BASIC_INFORMATION mbi; + + while (true) + { + VirtualQuery(p, &mbi, sizeof(mbi)); + + if (p >= (char *)mbi.BaseAddress + mbi.RegionSize) + break; + + p = (char *)mbi.BaseAddress + mbi.RegionSize; + + if (!mbi.AllocationBase || mbi.AllocationBase == hModule) + continue; + + hModule = HMODULE(mbi.AllocationBase); + PGetNewAndDelete pGetNewAndDelete = (PGetNewAndDelete)GetProcAddress(hModule, "GetNewAndDeleteForCryptoPP"); + if (pGetNewAndDelete) + { + pGetNewAndDelete(s_pNew, s_pDelete); + return; + } + + PSetNewAndDelete pSetNewAndDelete = (PSetNewAndDelete)GetProcAddress(hModule, "SetNewAndDeleteFromCryptoPP"); + if (pSetNewAndDelete) + { + s_pNew = &New; + s_pDelete = &free; + pSetNewAndDelete(s_pNew, s_pDelete, &set_new_handler); + return; + } + } + + // try getting these directly using mangled names of new and delete operators + + hModule = GetModuleHandle("msvcrtd"); + if (!hModule) + hModule = GetModuleHandle("msvcrt"); + if (hModule) + { + // 32-bit versions + s_pNew = (PNew)GetProcAddress(hModule, "??2@YAPAXI@Z"); + s_pDelete = (PDelete)GetProcAddress(hModule, "??3@YAXPAX@Z"); + if (s_pNew && s_pDelete) + return; + + // 64-bit versions + s_pNew = (PNew)GetProcAddress(hModule, "??2@YAPEAX_K@Z"); + s_pDelete = (PDelete)GetProcAddress(hModule, "??3@YAXPEAX@Z"); + if (s_pNew && s_pDelete) + return; + } + + OutputDebugStringA("Crypto++ DLL was not able to obtain new and delete function pointers.\n"); + throw 0; +} + +// Cast from FARPROC to funcptr with args +#pragma warning(default: 4191) + +void * operator new (size_t size) +{ + if (!s_pNew) + SetNewAndDeleteFunctionPointers(); + + return s_pNew(size); +} + +void operator delete (void * p) +{ + s_pDelete(p); +} + +void * operator new [] (size_t size) +{ + return operator new (size); +} + +void operator delete [] (void * p) +{ + operator delete (p); +} + +#endif // CRYPTOPP_EXPORTS diff --git a/extension/third_party/cryptopp/dll.h b/extension/third_party/cryptopp/dll.h new file mode 100644 index 00000000..f923026c --- /dev/null +++ b/extension/third_party/cryptopp/dll.h @@ -0,0 +1,71 @@ +// dll.h - originally written and placed in the public domain by Wei Dai + +/// \file dll.h +/// \brief Functions and definitions required for building the FIPS-140 DLL on Windows + +#ifndef CRYPTOPP_DLL_H +#define CRYPTOPP_DLL_H + +#if !defined(CRYPTOPP_IMPORTS) && !defined(CRYPTOPP_EXPORTS) && !defined(CRYPTOPP_DEFAULT_NO_DLL) +#ifdef CRYPTOPP_CONFIG_H +#error To use the DLL version of Crypto++, this file must be included before any other Crypto++ header files. +#endif +#define CRYPTOPP_IMPORTS +#endif + +#include "aes.h" +#include "cbcmac.h" +#include "ccm.h" +#include "cmac.h" +#include "channels.h" +#include "des.h" +#include "dh.h" +#include "dsa.h" +#include "ec2n.h" +#include "eccrypto.h" +#include "ecp.h" +#include "files.h" +#include "fips140.h" +#include "gcm.h" +#include "hex.h" +#include "hmac.h" +#include "modes.h" +#include "mqueue.h" +#include "nbtheory.h" +#include "osrng.h" +#include "pkcspad.h" +#include "pssr.h" +#include "randpool.h" +#include "rsa.h" +#include "rw.h" +#include "sha.h" +#include "skipjack.h" + +#ifdef CRYPTOPP_IMPORTS + +#ifdef _DLL +// cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain() +#ifdef CRYPTOPP_DEBUG +# pragma comment(lib, "msvcrtd") +# pragma comment(lib, "cryptopp") +#else +# pragma comment(lib, "msvcrt") +# pragma comment(lib, "cryptopp") +#endif +#endif + +#endif // #ifdef CRYPTOPP_IMPORTS + +#include // for new_handler + +NAMESPACE_BEGIN(CryptoPP) + +typedef void * (CRYPTOPP_API * PNew)(size_t); +typedef void (CRYPTOPP_API * PDelete)(void *); +typedef void (CRYPTOPP_API * PGetNewAndDelete)(PNew &, PDelete &); +typedef std::new_handler (CRYPTOPP_API * PSetNewHandler)(std::new_handler); +typedef void (CRYPTOPP_API * PSetNewAndDelete)(PNew, PDelete, PSetNewHandler); + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dlltest.cpp b/extension/third_party/cryptopp/dlltest.cpp new file mode 100644 index 00000000..addced55 --- /dev/null +++ b/extension/third_party/cryptopp/dlltest.cpp @@ -0,0 +1,212 @@ +#ifndef CRYPTOPP_DLL_ONLY +# define CRYPTOPP_DEFAULT_NO_DLL +#endif + +#include "dll.h" +#include "cryptlib.h" +#include "filters.h" +#include "pkcspad.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +USING_NAMESPACE(CryptoPP) + +void FIPS140_SampleApplication() +{ + if (!FIPS_140_2_ComplianceEnabled()) + { + std::cerr << "FIPS 140-2 compliance was turned off at compile time.\n"; + abort(); + } + + // check self test status + if (GetPowerUpSelfTestStatus() != POWER_UP_SELF_TEST_PASSED) + { + std::cerr << "Automatic power-up self test failed.\n"; + abort(); + } + std::cout << "0. Automatic power-up self test passed.\n"; + + // simulate a power-up self test error + SimulatePowerUpSelfTestFailure(); + try + { + // trying to use a crypto algorithm after power-up self test error will result in an exception + AES::Encryption aes; + + // should not be here + std::cerr << "Use of AES failed to cause an exception after power-up self test error.\n"; + abort(); + } + catch (SelfTestFailure &e) + { + std::cout << "1. Caught expected exception when simulating self test failure. Exception message follows: "; + std::cout << e.what() << std::endl; + } + + // clear the self test error state and redo power-up self test + DoDllPowerUpSelfTest(); + if (GetPowerUpSelfTestStatus() != POWER_UP_SELF_TEST_PASSED) + { + std::cerr << "Re-do power-up self test failed.\n"; + abort(); + } + std::cout << "2. Re-do power-up self test passed.\n"; + + // encrypt and decrypt + const byte key[] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + const byte iv[] = {0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef}; + const byte plaintext[] = { // "Now is the time for all " without tailing 0 + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20}; + byte ciphertext[24]; + byte decrypted[24]; + + CFB_FIPS_Mode::Encryption encryption_DES_EDE3_CFB; + encryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv); + encryption_DES_EDE3_CFB.ProcessString(ciphertext, plaintext, 24); + + CFB_FIPS_Mode::Decryption decryption_DES_EDE3_CFB; + decryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv); + decryption_DES_EDE3_CFB.ProcessString(decrypted, ciphertext, 24); + + if (memcmp(plaintext, decrypted, 24) != 0) + { + std::cerr << "DES-EDE3-CFB Encryption/decryption failed.\n"; + abort(); + } + std::cout << "3. DES-EDE3-CFB Encryption/decryption succeeded.\n"; + + // hash + const byte message[] = {'a', 'b', 'c'}; + const byte expectedDigest[] = {0xA9,0x99,0x3E,0x36,0x47,0x06,0x81,0x6A,0xBA,0x3E,0x25,0x71,0x78,0x50,0xC2,0x6C,0x9C,0xD0,0xD8,0x9D}; + byte digest[20]; + + SHA1 sha; + sha.Update(message, 3); + sha.Final(digest); + + if (memcmp(digest, expectedDigest, 20) != 0) + { + std::cerr << "SHA-1 hash failed.\n"; + abort(); + } + std::cout << "4. SHA-1 hash succeeded.\n"; + + // create auto-seeded X9.17 RNG object, if available +#ifdef OS_RNG_AVAILABLE + AutoSeededX917RNG rng; +#else + // this is used to allow this function to compile on platforms that don't have auto-seeded RNGs + RandomNumberGenerator &rng(NullRNG()); +#endif + + // generate DSA key + DSA::PrivateKey dsaPrivateKey; + dsaPrivateKey.GenerateRandomWithKeySize(rng, 1024); + DSA::PublicKey dsaPublicKey; + dsaPublicKey.AssignFrom(dsaPrivateKey); + if (!dsaPrivateKey.Validate(rng, 3) || !dsaPublicKey.Validate(rng, 3)) + { + std::cerr << "DSA key generation failed.\n"; + abort(); + } + std::cout << "5. DSA key generation succeeded.\n"; + + // encode DSA key + std::string encodedDsaPublicKey, encodedDsaPrivateKey; + dsaPublicKey.DEREncode(StringSink(encodedDsaPublicKey).Ref()); + dsaPrivateKey.DEREncode(StringSink(encodedDsaPrivateKey).Ref()); + + // decode DSA key + DSA::PrivateKey decodedDsaPrivateKey; + decodedDsaPrivateKey.BERDecode(StringStore(encodedDsaPrivateKey).Ref()); + DSA::PublicKey decodedDsaPublicKey; + decodedDsaPublicKey.BERDecode(StringStore(encodedDsaPublicKey).Ref()); + + if (!decodedDsaPrivateKey.Validate(rng, 3) || !decodedDsaPublicKey.Validate(rng, 3)) + { + std::cerr << "DSA key encode/decode failed.\n"; + abort(); + } + std::cout << "6. DSA key encode/decode succeeded.\n"; + + // sign and verify + byte signature[40]; + DSA::Signer signer(dsaPrivateKey); + CRYPTOPP_ASSERT(signer.SignatureLength() == 40); + signer.SignMessage(rng, message, 3, signature); + + DSA::Verifier verifier(dsaPublicKey); + if (!verifier.VerifyMessage(message, 3, signature, sizeof(signature))) + { + std::cerr << "DSA signature and verification failed.\n"; + abort(); + } + std::cout << "7. DSA signature and verification succeeded.\n"; + + + // try to verify an invalid signature + signature[0] ^= 1; + if (verifier.VerifyMessage(message, 3, signature, sizeof(signature))) + { + std::cerr << "DSA signature verification failed to detect bad signature.\n"; + abort(); + } + std::cout << "8. DSA signature verification successfully detected bad signature.\n"; + + // try to use an invalid key length + try + { + ECB_Mode::Encryption encryption_DES_EDE3_ECB; + encryption_DES_EDE3_ECB.SetKey(key, 5); + + // should not be here + std::cerr << "DES-EDE3 implementation did not detect use of invalid key length.\n"; + abort(); + } + catch (InvalidArgument &e) + { + std::cout << "9. Caught expected exception when using invalid key length. Exception message follows: "; + std::cout << e.what() << std::endl; + } + + std::cout << "\nFIPS 140-2 Sample Application completed normally.\n"; +} + +#ifdef CRYPTOPP_IMPORTS + +static PNew s_pNew = NULLPTR; +static PDelete s_pDelete = NULLPTR; + +extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(PNew pNew, PDelete pDelete, PSetNewHandler pSetNewHandler) +{ + (void)(pSetNewHandler); + s_pNew = pNew; + s_pDelete = pDelete; +} + +void * __cdecl operator new (size_t size) +{ + return s_pNew(size); +} + +void __cdecl operator delete (void * p) +{ + s_pDelete(p); +} + +#endif + +#ifdef CRYPTOPP_DLL_ONLY + +int __cdecl main() +{ + FIPS140_SampleApplication(); + return 0; +} + +#endif diff --git a/extension/third_party/cryptopp/dmac.h b/extension/third_party/cryptopp/dmac.h new file mode 100644 index 00000000..9d911708 --- /dev/null +++ b/extension/third_party/cryptopp/dmac.h @@ -0,0 +1,114 @@ +// dmac.h - originally written and placed in the public domain by Wei Dai + +/// \file dmac.h +/// \brief Classes for DMAC message authentication code + +#ifndef CRYPTOPP_DMAC_H +#define CRYPTOPP_DMAC_H + +#include "cbcmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DMAC message authentication code base class +/// \tparam T class derived from BlockCipherDocumentation +/// \since Crypto++ 3.1 +template +class CRYPTOPP_NO_VTABLE DMAC_Base : public SameKeyLengthAs, public MessageAuthenticationCode +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE); + static std::string StaticAlgorithmName() {return std::string("DMAC(") + T::StaticAlgorithmName() + ")";} + + virtual~DMAC_Base() {} + DMAC_Base() : m_subkeylength(0), m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + + std::string AlgorithmProvider() const; + +private: + byte *GenerateSubKeys(const byte *key, size_t keylength); + + size_t m_subkeylength; + SecByteBlock m_subkeys; + CBC_MAC m_mac1; + typename T::Encryption m_f2; + unsigned int m_counter; +}; + +template +std::string DMAC_Base::AlgorithmProvider() const +{ + return m_f2.AlgorithmProvider(); +} + +/// \brief DMAC message authentication code +/// \tparam T class derived from BlockCipherDocumentation +/// \sa CBC MAC for Real-Time Data Sources (08.15.1997) +/// by Erez Petrank and Charles Rackoff +/// \since Crypto++ 3.1 +template +class DMAC : public MessageAuthenticationCodeFinal > +{ +public: + /// \brief Construct a DMAC + DMAC() {} + + /// \brief Construct a DMAC + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + DMAC(const byte *key, size_t length=DMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} +}; + +template +void DMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_subkeylength = T::StaticGetValidKeyLength(T::BLOCKSIZE); + m_subkeys.resize(2*UnsignedMin((unsigned int)T::BLOCKSIZE, m_subkeylength)); + m_mac1.SetKey(GenerateSubKeys(key, length), m_subkeylength, params); + m_f2.SetKey(m_subkeys+m_subkeys.size()/2, m_subkeylength, params); + m_counter = 0; + m_subkeys.resize(0); +} + +template +void DMAC_Base::Update(const byte *input, size_t length) +{ + m_mac1.Update(input, length); + m_counter = (unsigned int)((m_counter + length) % T::BLOCKSIZE); +} + +template +void DMAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte pad[T::BLOCKSIZE]; + byte padByte = byte(T::BLOCKSIZE-m_counter); + memset(pad, padByte, padByte); + m_mac1.Update(pad, padByte); + m_mac1.TruncatedFinal(mac, size); + m_f2.ProcessBlock(mac); + + m_counter = 0; // reset for next message +} + +template +byte *DMAC_Base::GenerateSubKeys(const byte *key, size_t keylength) +{ + typename T::Encryption cipher(key, keylength); + memset(m_subkeys, 0, m_subkeys.size()); + cipher.ProcessBlock(m_subkeys); + m_subkeys[m_subkeys.size()/2 + T::BLOCKSIZE - 1] = 1; + cipher.ProcessBlock(m_subkeys+m_subkeys.size()/2); + return m_subkeys; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/donna.h b/extension/third_party/cryptopp/donna.h new file mode 100644 index 00000000..2f336538 --- /dev/null +++ b/extension/third_party/cryptopp/donna.h @@ -0,0 +1,178 @@ +// donna.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// The curve25519 and ed25519 source files multiplex different repos and +// architectures using namespaces. The repos are Andrew Moon's +// curve25519-donna and ed25519-donna. The architectures are 32-bit, 64-bit +// and SSE. For example, 32-bit x25519 uses symbols from Donna::X25519 and +// Donna::Arch32. + +// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]", +// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658 + +/// \file donna.h +/// \details Functions for curve25519 and ed25519 operations +/// \details This header provides the entry points into Andrew Moon's +/// curve25519 and ed25519 curve functions. The Crypto++ classes x25519 +/// and ed25519 use the functions. The functions are in the Donna +/// namespace and are curve25519_mult(), ed25519_publickey(), +/// ed25519_sign() and ed25519_sign_open(). +/// \details At the moment the hash function for signing is fixed at +/// SHA512. + +#ifndef CRYPTOPP_DONNA_H +#define CRYPTOPP_DONNA_H + +#include "cryptlib.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +//***************************** curve25519 *****************************// + +/// \brief Generate a public key +/// \param publicKey byte array for the public key +/// \param secretKey byte array with the private key +/// \return 0 on success, non-0 otherwise +/// \details curve25519_mult() generates a public key from an existing +/// secret key. Internally curve25519_mult() performs a scalar +/// multiplication using the base point and writes the result to +/// pubkey. +int curve25519_mult(byte publicKey[32], const byte secretKey[32]); + +/// \brief Generate a shared key +/// \param sharedKey byte array for the shared secret +/// \param secretKey byte array with the private key +/// \param othersKey byte array with the peer's public key +/// \return 0 on success, non-0 otherwise +/// \details curve25519_mult() generates a shared key from an existing +/// secret key and the other party's public key. Internally +/// curve25519_mult() performs a scalar multiplication using the two keys +/// and writes the result to sharedKey. +int curve25519_mult(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]); + +//******************************* ed25519 *******************************// + +/// \brief Creates a public key from a secret key +/// \param publicKey byte array for the public key +/// \param secretKey byte array with the private key +/// \return 0 on success, non-0 otherwise +/// \details ed25519_publickey() generates a public key from a secret key. +/// Internally ed25519_publickey() performs a scalar multiplication +/// using the secret key and then writes the result to publicKey. +int ed25519_publickey(byte publicKey[32], const byte secretKey[32]); + +/// \brief Creates a signature on a message +/// \param message byte array with the message +/// \param messageLength size of the message, in bytes +/// \param publicKey byte array with the public key +/// \param secretKey byte array with the private key +/// \param signature byte array for the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign() generates a signature on a message using +/// the public and private keys. The various buffers can be exact +/// sizes, and do not require extra space like when using the +/// NaCl library functions. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int ed25519_sign(const byte* message, size_t messageLength, const byte secretKey[32], const byte publicKey[32], byte signature[64]); + +/// \brief Creates a signature on a message +/// \param stream std::istream derived class +/// \param publicKey byte array with the public key +/// \param secretKey byte array with the private key +/// \param signature byte array for the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign() generates a signature on a message using +/// the public and private keys. The various buffers can be exact +/// sizes, and do not require extra space like when using the +/// NaCl library functions. +/// \details This ed25519_sign() overload handles large streams. It +/// was added for signing and verifying files that are too large +/// for a memory allocation. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int ed25519_sign(std::istream& stream, const byte secretKey[32], const byte publicKey[32], byte signature[64]); + +/// \brief Verifies a signature on a message +/// \param message byte array with the message +/// \param messageLength size of the message, in bytes +/// \param publicKey byte array with the public key +/// \param signature byte array with the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign_open() verifies a signature on a message using +/// the public key. The various buffers can be exact sizes, and do not +/// require extra space like when using the NaCl library functions. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int +ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64]); + +/// \brief Verifies a signature on a message +/// \param stream std::istream derived class +/// \param publicKey byte array with the public key +/// \param signature byte array with the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign_open() verifies a signature on a message using +/// the public key. The various buffers can be exact sizes, and do not +/// require extra space like when using the NaCl library functions. +/// \details This ed25519_sign_open() overload handles large streams. It +/// was added for signing and verifying files that are too large +/// for a memory allocation. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int +ed25519_sign_open(std::istream& stream, const byte publicKey[32], const byte signature[64]); + +//****************************** Internal ******************************// + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +// CRYPTOPP_WORD128_AVAILABLE mostly depends upon GCC support for +// __SIZEOF_INT128__. If __SIZEOF_INT128__ is not available then Moon +// provides routines for MSC and GCC. It should cover most platforms, +// but there are gaps like MS ARM64 and XLC. We tried to enable the +// 64-bit path for SunCC from 12.5 but we got the dreaded compile +// error "The operand ___LCM cannot be assigned to". + +#if defined(CRYPTOPP_WORD128_AVAILABLE) || \ + (defined(_MSC_VER) && defined(_M_X64)) +# define CRYPTOPP_CURVE25519_64BIT 1 +#else +# define CRYPTOPP_CURVE25519_32BIT 1 +#endif + +// Benchmarking on a modern 64-bit Core i5-6400 @2.7 GHz shows SSE2 on Linux +// is not profitable. Here are the numbers in milliseconds/operation: +// +// * Langley, C++, 0.050 +// * Moon, C++: 0.040 +// * Moon, SSE2: 0.061 +// * Moon, native: 0.045 +// +// However, a modern 64-bit Core i5-3200 @2.5 GHz shows SSE2 is profitable +// for MS compilers. Here are the numbers in milliseconds/operation: +// +// * x86, no SSE2, 0.294 +// * x86, SSE2, 0.097 +// * x64, no SSE2, 0.081 +// * x64, SSE2, 0.071 + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) && defined(_MSC_VER) +# define CRYPTOPP_CURVE25519_SSE2 1 +#endif + +#if (CRYPTOPP_CURVE25519_SSE2) + extern int curve25519_mult_SSE2(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]); +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DONNA_H diff --git a/extension/third_party/cryptopp/donna_32.cpp b/extension/third_party/cryptopp/donna_32.cpp new file mode 100644 index 00000000..51f0ae0c --- /dev/null +++ b/extension/third_party/cryptopp/donna_32.cpp @@ -0,0 +1,2102 @@ +// donna_32.cpp - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// The curve25519 and ed25519 source files multiplex different repos and +// architectures using namespaces. The repos are Andrew Moon's +// curve25519-donna and ed25519-donna. The architectures are 32-bit, 64-bit +// and SSE. For example, 32-bit x25519 uses symbols from Donna::X25519 and +// Donna::Arch32. + +// A fair amount of duplication happens below, but we could not directly +// use curve25519 for both x25519 and ed25519. A close examination reveals +// slight differences in the implementation. For example, look at the +// two curve25519_sub functions. + +// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]", +// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658 + +#include "pch.h" + +#include "config.h" +#include "donna.h" +#include "secblock.h" +#include "sha.h" +#include "misc.h" +#include "cpu.h" + +#include +#include + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char DONNA32_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +// Can't use GetAlignmentOf() because of C++11 and constexpr +// Can use 'const unsigned int' because of MSVC 2013 +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# define ALIGN_SPEC 16 +#else +# define ALIGN_SPEC 4 +#endif + +ANONYMOUS_NAMESPACE_END + +#if defined(CRYPTOPP_CURVE25519_32BIT) + +#include "donna_32.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::GetWord; +using CryptoPP::PutWord; +using CryptoPP::LITTLE_ENDIAN_ORDER; + +inline word32 U8TO32_LE(const byte* p) +{ + return GetWord(false, LITTLE_ENDIAN_ORDER, p); +} + +inline void U32TO8_LE(byte* p, word32 w) +{ + PutWord(false, LITTLE_ENDIAN_ORDER, p, w); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(X25519) +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::sword32; +using CryptoPP::word64; +using CryptoPP::sword64; + +using CryptoPP::GetBlock; +using CryptoPP::LittleEndian; + +// Bring in all the symbols from the 32-bit header +using namespace CryptoPP::Donna::Arch32; + +/* out = in */ +inline void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; out[1] = in[1]; + out[2] = in[2]; out[3] = in[3]; + out[4] = in[4]; out[5] = in[5]; + out[6] = in[6]; out[7] = in[7]; + out[8] = in[8]; out[9] = in[9]; +} + +/* out = a + b */ +inline void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; out[9] = a[9] + b[9]; +} + +/* out = a - b */ +inline void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = 0x7ffffda + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = 0x3fffffe + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = 0x7fffffe + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = 0x3fffffe + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = 0x7fffffe + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = 0x3fffffe + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = 0x7fffffe + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = 0x3fffffe + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = 0x7fffffe + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = 0x3fffffe + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = in * scalar */ +inline void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const word32 scalar) { + word64 a; + word32 c; + a = mul32x32_64(in[0], scalar); out[0] = (word32)a & reduce_mask_26; c = (word32)(a >> 26); + a = mul32x32_64(in[1], scalar) + c; out[1] = (word32)a & reduce_mask_25; c = (word32)(a >> 25); + a = mul32x32_64(in[2], scalar) + c; out[2] = (word32)a & reduce_mask_26; c = (word32)(a >> 26); + a = mul32x32_64(in[3], scalar) + c; out[3] = (word32)a & reduce_mask_25; c = (word32)(a >> 25); + a = mul32x32_64(in[4], scalar) + c; out[4] = (word32)a & reduce_mask_26; c = (word32)(a >> 26); + a = mul32x32_64(in[5], scalar) + c; out[5] = (word32)a & reduce_mask_25; c = (word32)(a >> 25); + a = mul32x32_64(in[6], scalar) + c; out[6] = (word32)a & reduce_mask_26; c = (word32)(a >> 26); + a = mul32x32_64(in[7], scalar) + c; out[7] = (word32)a & reduce_mask_25; c = (word32)(a >> 25); + a = mul32x32_64(in[8], scalar) + c; out[8] = (word32)a & reduce_mask_26; c = (word32)(a >> 26); + a = mul32x32_64(in[9], scalar) + c; out[9] = (word32)a & reduce_mask_25; c = (word32)(a >> 25); + out[0] += c * 19; +} + +/* out = a * b */ +inline void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + word32 p; + + r0 = b[0]; r1 = b[1]; r2 = b[2]; r3 = b[3]; r4 = b[4]; + r5 = b[5]; r6 = b[6]; r7 = b[7]; r8 = b[8]; r9 = b[9]; + + s0 = a[0]; s1 = a[1]; s2 = a[2]; s3 = a[3]; s4 = a[4]; + s5 = a[5]; s6 = a[6]; s7 = a[7]; s8 = a[8]; s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; r3 *= 2; r5 *= 2; r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; r5 *= 2; r7 *= 2; r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; + out[5] = r5; out[6] = r6; out[7] = r7; out[8] = r8; out[9] = r9; +} + +/* out = in * in */ +inline void +curve25519_square(bignum25519 out, const bignum25519 in) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 d6,d7,d8,d9; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + word32 p; + + r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4]; + r5 = in[5]; r6 = in[6]; r7 = in[7]; r8 = in[8]; r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; d7 = r7 * 2 * 19; + d8 = r8 * 19; d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; + out[5] = r5; out[6] = r6; out[7] = r7; out[8] = r8; out[9] = r9; +} + +/* out = in^(2 * count) */ +void +curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 d6,d7,d8,d9; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + word32 p; + + r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4]; + r5 = in[5]; r6 = in[6]; r7 = in[7]; r8 = in[8]; r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; d7 = r7 * 2 * 19; + d8 = r8 * 19; d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; + out[5] = r5; out[6] = r6; out[7] = r7; out[8] = r8; out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void +curve25519_expand(bignum25519 out, const byte in[32]) { + word32 x0,x1,x2,x3,x4,x5,x6,x7; + GetBlock block(in); + block(x0)(x1)(x2)(x3)(x4)(x5)(x6)(x7); + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((word64)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((word64)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((word64)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((word64)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((word64)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((word64)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a little-endian, 32-byte array */ +void +curve25519_contract(byte out[32], const bignum25519 in) { + bignum25519 f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (1 << 26) - 19; + f[1] += (1 << 25) - 1; + f[2] += (1 << 26) - 1; + f[3] += (1 << 25) - 1; + f[4] += (1 << 26) - 1; + f[5] += (1 << 25) - 1; + f[6] += (1 << 26) - 1; + f[7] += (1 << 25) - 1; + f[8] += (1 << 26) - 1; + f[9] += (1 << 25) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; + f[2] <<= 3; + f[3] <<= 5; + f[4] <<= 6; + f[6] <<= 1; + f[7] <<= 3; + f[8] <<= 4; + f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (byte)( f[i] & 0xff); \ + out[s+1] = (byte)((f[i] >> 8) & 0xff); \ + out[s+2] = (byte)((f[i] >> 16) & 0xff); \ + out[s+3] = (byte)((f[i] >> 24) & 0xff); + + out[0] = out[16] = 0; + F(0,0); F(1,3); + F(2,6); F(3,9); + F(4,12); F(5,16); + F(6,19); F(7,22); + F(8,25); F(9,28); + #undef F +} + +inline void +curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, word32 iswap) { + const word32 swap = (word32)(-(sword32)iswap); + word32 x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; + + x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; + x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; + x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; + x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; + x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; + x5 = swap & (x[5] ^ qpx[5]); x[5] ^= x5; qpx[5] ^= x5; + x6 = swap & (x[6] ^ qpx[6]); x[6] ^= x6; qpx[6] ^= x6; + x7 = swap & (x[7] ^ qpx[7]); x[7] ^= x7; qpx[7] ^= x7; + x8 = swap & (x[8] ^ qpx[8]); x[8] ^= x8; qpx[8] ^= x8; + x9 = swap & (x[9] ^ qpx[9]); x[9] ^= x9; qpx[9] ^= x9; +} + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + ALIGN(ALIGN_SPEC) bignum25519 t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void +curve25519_recip(bignum25519 out, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 a, t0, b; + + /* 2 */ curve25519_square(a, z); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square(t0, a); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul(out, b, a); +} + +ANONYMOUS_NAMESPACE_END +NAMESPACE_END // X25519 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//******************************* ed25519 *******************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Ed25519) +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::sword32; +using CryptoPP::word64; +using CryptoPP::sword64; + +using CryptoPP::GetBlock; +using CryptoPP::LittleEndian; + +using CryptoPP::SHA512; + +// Bring in all the symbols from the 32-bit header +using namespace CryptoPP::Donna::Arch32; + +/* out = in */ +inline void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; out[1] = in[1]; + out[2] = in[2]; out[3] = in[3]; + out[4] = in[4]; out[5] = in[5]; + out[6] = in[6]; out[7] = in[7]; + out[8] = in[8]; out[9] = in[9]; +} + +/* out = a + b */ +inline void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; out[9] = a[9] + b[9]; +} + +inline void +curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +inline void +curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a - b */ +inline void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 + a[4] - b[4] + c; + out[5] = twoP13579 + a[5] - b[5] ; + out[6] = twoP2468 + a[6] - b[6] ; + out[7] = twoP13579 + a[7] - b[7] ; + out[8] = twoP2468 + a[8] - b[8] ; + out[9] = twoP13579 + a[9] - b[9] ; +} + +/* out = a - b, where a is the result of a basic op (add,sub) */ +inline void +curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +inline void +curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 c; + out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = -a */ +inline void +curve25519_neg(bignum25519 out, const bignum25519 a) { + word32 c; + out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26; + out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25; + out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26; + out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25; + out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26; + out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25; + out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26; + out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25; + out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26; + out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25; + out[0] += 19 * c; +} + +/* out = a * b */ +void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 s0,s1,s2,s3,s4,s5,s6,s7,s8,s9; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + word32 p; + + r0 = b[0]; r1 = b[1]; + r2 = b[2]; r3 = b[3]; + r4 = b[4]; r5 = b[5]; + r6 = b[6]; r7 = b[7]; + r8 = b[8]; r9 = b[9]; + + s0 = a[0]; s1 = a[1]; + s2 = a[2]; s3 = a[3]; + s4 = a[4]; s5 = a[5]; + s6 = a[6]; s7 = a[7]; + s8 = a[8]; s9 = a[9]; + + m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0); + m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0); + m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0); + m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0); + m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0); + + r1 *= 2; r3 *= 2; + r5 *= 2; r7 *= 2; + + m0 = mul32x32_64(r0, s0); + m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0); + m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0); + m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0); + m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0); + + r1 *= 19; r2 *= 19; + r3 = (r3 / 2) * 19; + r4 *= 19; + r5 = (r5 / 2) * 19; + r6 *= 19; + r7 = (r7 / 2) * 19; + r8 *= 19; r9 *= 19; + + m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9)); + m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9)); + m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9)); + m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9)); + + r3 *= 2; r5 *= 2; + r7 *= 2; r9 *= 2; + + m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9)); + m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9)); + m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9)); + m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9)); + m8 += (mul32x32_64(r9, s9)); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; out[5] = r5; + out[6] = r6; out[7] = r7; + out[8] = r8; out[9] = r9; +} + +/* out = in*in */ +void +curve25519_square(bignum25519 out, const bignum25519 in) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 d6,d7,d8,d9; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + word32 p; + + r0 = in[0]; r1 = in[1]; + r2 = in[2]; r3 = in[3]; + r4 = in[4]; r5 = in[5]; + r6 = in[6]; r7 = in[7]; + r8 = in[8]; r9 = in[9]; + + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; out[5] = r5; + out[6] = r6; out[7] = r7; + out[8] = r8; out[9] = r9; +} + +/* out = in ^ (2 * count) */ +void +curve25519_square_times(bignum25519 out, const bignum25519 in, int count) { + word32 r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + word32 d6,d7,d8,d9,p; + word64 m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c; + + r0 = in[0]; r1 = in[1]; + r2 = in[2]; r3 = in[3]; + r4 = in[4]; r5 = in[5]; + r6 = in[6]; r7 = in[7]; + r8 = in[8]; r9 = in[9]; + + do { + m0 = mul32x32_64(r0, r0); + r0 *= 2; + m1 = mul32x32_64(r0, r1); + m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2); + r1 *= 2; + m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 ); + m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2); + r2 *= 2; + m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3); + m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2); + r3 *= 2; + m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 ); + m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 ); + m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2); + + d6 = r6 * 19; + d7 = r7 * 2 * 19; + d8 = r8 * 19; + d9 = r9 * 2 * 19; + + m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19)); + m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2)); + m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 )); + m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 )); + m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 )); + m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2)); + m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 )); + m7 += (mul32x32_64(d9, r8 )); + m8 += (mul32x32_64(d9, r9 )); + + r0 = (word32)m0 & reduce_mask_26; c = (m0 >> 26); + m1 += c; r1 = (word32)m1 & reduce_mask_25; c = (m1 >> 25); + m2 += c; r2 = (word32)m2 & reduce_mask_26; c = (m2 >> 26); + m3 += c; r3 = (word32)m3 & reduce_mask_25; c = (m3 >> 25); + m4 += c; r4 = (word32)m4 & reduce_mask_26; c = (m4 >> 26); + m5 += c; r5 = (word32)m5 & reduce_mask_25; c = (m5 >> 25); + m6 += c; r6 = (word32)m6 & reduce_mask_26; c = (m6 >> 26); + m7 += c; r7 = (word32)m7 & reduce_mask_25; c = (m7 >> 25); + m8 += c; r8 = (word32)m8 & reduce_mask_26; c = (m8 >> 26); + m9 += c; r9 = (word32)m9 & reduce_mask_25; p = (word32)(m9 >> 25); + m0 = r0 + mul32x32_64(p,19); r0 = (word32)m0 & reduce_mask_26; p = (word32)(m0 >> 26); + r1 += p; + } while (--count); + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; out[5] = r5; + out[6] = r6; out[7] = r7; + out[8] = r8; out[9] = r9; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +void +curve25519_expand(bignum25519 out, const byte in[32]) { + word32 x0,x1,x2,x3,x4,x5,x6,x7; + GetBlock block(in); + block(x0)(x1)(x2)(x3)(x4)(x5)(x6)(x7); + + out[0] = ( x0 ) & 0x3ffffff; + out[1] = ((((word64)x1 << 32) | x0) >> 26) & 0x1ffffff; + out[2] = ((((word64)x2 << 32) | x1) >> 19) & 0x3ffffff; + out[3] = ((((word64)x3 << 32) | x2) >> 13) & 0x1ffffff; + out[4] = (( x3) >> 6) & 0x3ffffff; + out[5] = ( x4 ) & 0x1ffffff; + out[6] = ((((word64)x5 << 32) | x4) >> 25) & 0x3ffffff; + out[7] = ((((word64)x6 << 32) | x5) >> 19) & 0x1ffffff; + out[8] = ((((word64)x7 << 32) | x6) >> 12) & 0x3ffffff; + out[9] = (( x7) >> 6) & 0x1ffffff; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +void +curve25519_contract(byte out[32], const bignum25519 in) { + bignum25519 f; + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (reduce_mask_26 + 1) - 19; + f[1] += (reduce_mask_25 + 1) - 1; + f[2] += (reduce_mask_26 + 1) - 1; + f[3] += (reduce_mask_25 + 1) - 1; + f[4] += (reduce_mask_26 + 1) - 1; + f[5] += (reduce_mask_25 + 1) - 1; + f[6] += (reduce_mask_26 + 1) - 1; + f[7] += (reduce_mask_25 + 1) - 1; + f[8] += (reduce_mask_26 + 1) - 1; + f[9] += (reduce_mask_25 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + f[1] <<= 2; f[2] <<= 3; + f[3] <<= 5; f[4] <<= 6; + f[6] <<= 1; f[7] <<= 3; + f[8] <<= 4; f[9] <<= 6; + + #define F(i, s) \ + out[s+0] |= (byte)( f[i] & 0xff); \ + out[s+1] = (byte)((f[i] >> 8) & 0xff); \ + out[s+2] = (byte)((f[i] >> 16) & 0xff); \ + out[s+3] = (byte)((f[i] >> 24) & 0xff); + + out[0] = out[16] = 0; + F(0,0); F(1,3); + F(2,6); F(3,9); + F(4,12); F(5,16); + F(6,19); F(7,22); + F(8,25); F(9,28); + #undef F +} + +/* out = (flag) ? in : out */ +inline void +curve25519_move_conditional_bytes(byte out[96], const byte in[96], word32 flag) +{ + // TODO: enable this code path once we can test and benchmark it. + // It is about 48 insns shorter, it avoids punning which may be UB, + // and it is guaranteed constant time. +#if defined(__GNUC__) && defined(__i686__) && 0 + const word32 iter = 96/sizeof(word32); + word32* outl = reinterpret_cast(out); + const word32* inl = reinterpret_cast(in); + word32 idx=0, val; + + __asm__ __volatile__ ( + ".att_syntax ;\n" + "cmpl $0, %[flag] ;\n" // compare, set ZERO flag + "movl %[iter], %%ecx ;\n" // load iteration count + "1: ;\n" + " movl (%[idx],%[out]), %[val] ;\n" // val = out[idx] + " cmovnzl (%[idx],%[in]), %[val] ;\n" // copy in[idx] to val if NZ + " movl %[val], (%[idx],%[out]) ;\n" // out[idx] = val + " leal 4(%[idx]), %[idx] ;\n" // increment index + " loopnz 1b ;\n" // does not affect flags + : [out] "+S" (outl), [in] "+D" (inl), + [idx] "+b" (idx), [val] "=r" (val) + : [flag] "g" (flag), [iter] "I" (iter) + : "ecx", "memory", "cc" + ); +#else + const word32 nb = flag - 1, b = ~nb; + const word32 *inl = (const word32 *)in; + word32 *outl = (word32 *)out; + outl[0] = (outl[0] & nb) | (inl[0] & b); + outl[1] = (outl[1] & nb) | (inl[1] & b); + outl[2] = (outl[2] & nb) | (inl[2] & b); + outl[3] = (outl[3] & nb) | (inl[3] & b); + outl[4] = (outl[4] & nb) | (inl[4] & b); + outl[5] = (outl[5] & nb) | (inl[5] & b); + outl[6] = (outl[6] & nb) | (inl[6] & b); + outl[7] = (outl[7] & nb) | (inl[7] & b); + outl[8] = (outl[8] & nb) | (inl[8] & b); + outl[9] = (outl[9] & nb) | (inl[9] & b); + outl[10] = (outl[10] & nb) | (inl[10] & b); + outl[11] = (outl[11] & nb) | (inl[11] & b); + outl[12] = (outl[12] & nb) | (inl[12] & b); + outl[13] = (outl[13] & nb) | (inl[13] & b); + outl[14] = (outl[14] & nb) | (inl[14] & b); + outl[15] = (outl[15] & nb) | (inl[15] & b); + outl[16] = (outl[16] & nb) | (inl[16] & b); + outl[17] = (outl[17] & nb) | (inl[17] & b); + outl[18] = (outl[18] & nb) | (inl[18] & b); + outl[19] = (outl[19] & nb) | (inl[19] & b); + outl[20] = (outl[20] & nb) | (inl[20] & b); + outl[21] = (outl[21] & nb) | (inl[21] & b); + outl[22] = (outl[22] & nb) | (inl[22] & b); + outl[23] = (outl[23] & nb) | (inl[23] & b); +#endif +} + +/* if (iswap) swap(a, b) */ +inline void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, word32 iswap) { + const word32 swap = (word32)(-(sword32)iswap); + word32 x0,x1,x2,x3,x4,x5,x6,x7,x8,x9; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; + x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5; + x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6; + x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7; + x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8; + x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9; +} + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + ALIGN(ALIGN_SPEC) bignum25519 t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void +curve25519_recip(bignum25519 out, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 a,t0,b; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void +curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 b,c,t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul(two252m3, b, z); +} + +inline void +ed25519_hash(byte *hash, const byte *in, size_t inlen) { + SHA512().CalculateDigest(hash, in, inlen); +} + +inline void +ed25519_extsk(hash_512bits extsk, const byte sk[32]) { + ed25519_hash(extsk, sk, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; +} + +void +UpdateFromStream(HashTransformation& hash, std::istream& stream) +{ + SecByteBlock block(4096); + while (stream.read((char*)block.begin(), block.size())) + hash.Update(block, block.size()); + + std::streamsize rem = stream.gcount(); + if (rem) + hash.Update(block, (size_t)rem); + + block.SetMark(0); +} + +void +ed25519_hram(hash_512bits hram, const byte RS[64], const byte pk[32], const byte *m, size_t mlen) { + SHA512 hash; + hash.Update(RS, 32); + hash.Update(pk, 32); + hash.Update(m, mlen); + hash.Final(hram); +} + +void +ed25519_hram(hash_512bits hram, const byte RS[64], const byte pk[32], std::istream& stream) { + SHA512 hash; + hash.Update(RS, 32); + hash.Update(pk, 32); + UpdateFromStream(hash, stream); + hash.Final(hram); +} + +inline bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 31; +} + +/* see HAC, Alg. 14.42 Step 4 */ +void +reduce256_modm(bignum256modm r) { + bignum256modm t; + bignum256modm_element_t b = 0, pb, mask; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b; + pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b; + pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b; + pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b; + pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16)); + + /* keep r if r was smaller than m */ + mask = b - 1; + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); + r[5] ^= mask & (r[5] ^ t[5]); + r[6] ^= mask & (r[6] ^ t[6]); + r[7] ^= mask & (r[7] ^ t[7]); + r[8] ^= mask & (r[8] ^ t[8]); +} + +/* Barrett reduction, see HAC, Alg. 14.42 */ +void +barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3, r2; + word64 c; + bignum256modm_element_t f, b, pb; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 + */ + c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30; + c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]); + f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]); + f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]); + f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]); + f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]); + f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]); + f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]); + f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]); + f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30; + c += mul32x32_64(modm_mu[8], q1[8]); + f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) + r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) + */ + c = mul32x32_64(modm_m[0], q3[0]); + r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]); + r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]); + r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]); + r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]); + r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]); + r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]); + r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]); + r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30; + c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]); + r2[8] = (bignum256modm_element_t)(c & 0xffffff); + + /* r = r1 - r2 + if (r < 0) r += (1 << 264) */ + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b; + pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b; + pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b; + pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b; + pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24)); + + reduce256_modm(r); + reduce256_modm(r); +} + +/* addition modulo m */ +void +add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c; + + c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30; + c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30; + c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30; + c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30; + c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30; + c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30; + c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30; + c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30; + c += x[8] + y[8]; r[8] = c; + + reduce256_modm(r); +} + +/* multiplication modulo m */ +void +mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm r1, q1; + word64 c; + bignum256modm_element_t f; + + c = mul32x32_64(x[0], y[0]); + f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]); + f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]); + f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]); + f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]); + f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]); + f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]); + f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]); + f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30; + c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]); + f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]); + f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]); + f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]); + f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]); + f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]); + f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]); + f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]); + f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[8], y[8]); + f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff; + + barrett_reduce256_modm(r, q1, r1); +} + +void +expand256_modm(bignum256modm out, const byte *in, size_t len) { + byte work[64] = {0}; + bignum256modm_element_t x[16]; + bignum256modm q1; + + memcpy(work, in, len); + x[0] = U8TO32_LE(work + 0); + x[1] = U8TO32_LE(work + 4); + x[2] = U8TO32_LE(work + 8); + x[3] = U8TO32_LE(work + 12); + x[4] = U8TO32_LE(work + 16); + x[5] = U8TO32_LE(work + 20); + x[6] = U8TO32_LE(work + 24); + x[7] = U8TO32_LE(work + 28); + x[8] = U8TO32_LE(work + 32); + x[9] = U8TO32_LE(work + 36); + x[10] = U8TO32_LE(work + 40); + x[11] = U8TO32_LE(work + 44); + x[12] = U8TO32_LE(work + 48); + x[13] = U8TO32_LE(work + 52); + x[14] = U8TO32_LE(work + 56); + x[15] = U8TO32_LE(work + 60); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff; + + /* 8*31 = 248 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits = 9 30 bit elements */ + q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff; + q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff; + q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff; + q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff; + q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff; + q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff; + q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff; + q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff; + q1[8] = ((x[15] >> 8) ); + + barrett_reduce256_modm(out, q1, out); +} + +void +expand_raw256_modm(bignum256modm out, const byte in[32]) { + bignum256modm_element_t x[8]; + + x[0] = U8TO32_LE(in + 0); + x[1] = U8TO32_LE(in + 4); + x[2] = U8TO32_LE(in + 8); + x[3] = U8TO32_LE(in + 12); + x[4] = U8TO32_LE(in + 16); + x[5] = U8TO32_LE(in + 20); + x[6] = U8TO32_LE(in + 24); + x[7] = U8TO32_LE(in + 28); + + out[0] = ( x[0]) & 0x3fffffff; + out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff; + out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff; + out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff; + out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff; + out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff; + out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff; + out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff; + out[8] = ((x[ 7] >> 16) ) & 0x0000ffff; +} + +void +contract256_modm(byte out[32], const bignum256modm in) { + U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30)); + U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28)); + U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26)); + U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24)); + U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22)); + U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20)); + U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18)); + U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16)); +} + +void +contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry; + signed char *quads = r; + bignum256modm_element_t i, j, v; + + for (i = 0; i < 8; i += 2) { + v = in[i]; + for (j = 0; j < 7; j++) { + *quads++ = (v & 15); + v >>= 4; + } + v |= (in[i+1] << 2); + for (j = 0; j < 8; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + + v = in[8]; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + *quads++ = (v & 15); v >>= 4; + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +void +contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i,j,k,b; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v; + + /* first put the binary expansion into r */ + for (i = 0; i < 8; i++) { + v = s[i]; + for (j = 0; j < 30; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[8]; + for (j = 0; j < 16; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} + +inline void +ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +inline void +ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +void +ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +void +ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { + bignum25519 a,b,c,d,t,u; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_sub(t, q->y, q->x); + curve25519_add(u, q->y, q->x); + curve25519_mul(a, a, t); + curve25519_mul(b, b, u); + curve25519_mul(c, p->t, q->t); + curve25519_mul(c, c, ge25519_ec2d); + curve25519_mul(d, p->z, q->z); + curve25519_add(d, d, d); + curve25519_sub(r->x, b, a); + curve25519_add(r->y, b, a); + curve25519_add_after_basic(r->z, d, c); + curve25519_sub_after_basic(r->t, d, c); +} + +void +ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 a,b,c; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +void +ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, byte signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +void +ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, byte signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +void +ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +void +ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +void +ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { + ge25519_p1p1 t; + ge25519_add_p1p1(&t, p, q); + ge25519_p1p1_to_full(r, &t); +} + +void +ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + bignum25519 a,b,c,e,f,g,h; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +void +ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + bignum25519 a,b,c,x,y,z,t; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + +void +ge25519_pack(byte r[32], const ge25519 *p) { + bignum25519 tx, ty, zi; + byte parity[32]; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +int +ed25519_verify(const byte *x, const byte *y, size_t len) { + size_t differentbits = 0; + while (len--) + differentbits |= (*x++ ^ *y++); + return (int) (1 & ((differentbits - 1) >> 8)); +} + +int +ge25519_unpack_negative_vartime(ge25519 *r, const byte p[32]) { + const byte zero[32] = {0}; + const bignum25519 one = {1}; + byte parity = p[31] >> 7; + byte check[32]; + bignum25519 t, root, num, den, d3; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + +/* computes [s1]p1 + [s2]basepoint */ +void +ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; + ge25519 d1; + ge25519_p1p1 t; + sword32 i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (byte)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (byte)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} + +#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) + +word32 +ge25519_windowb_equal(word32 b, word32 c) { + return ((b ^ c) - 1) >> 31; +} + +void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const byte table[256][96], word32 pos, signed char b) { + bignum25519 neg; + word32 sign = (word32)((byte)b >> 7); + word32 mask = ~(sign - 1); + word32 u = (b + mask) ^ mask; + word32 i; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + byte packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + for (i = 0; i < 8; i++) + curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ + +/* computes [s]basepoint */ +void +ge25519_scalarmult_base_niels(ge25519 *r, const byte basepoint_table[256][96], const bignum256modm s) { + signed char b[64]; + word32 i; + ge25519_niels t; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memset(r->z, 0, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} + +ANONYMOUS_NAMESPACE_END +NAMESPACE_END // Ed25519 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//***************************** curve25519 *****************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +int curve25519_mult_CXX(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) +{ + using namespace CryptoPP::Donna::X25519; + + FixedSizeSecBlock e; + for (size_t i = 0; i < 32; ++i) + e[i] = secretKey[i]; + e[0] &= 0xf8; e[31] &= 0x7f; e[31] |= 0x40; + + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx; + bignum25519 q, qx, qpqx, qqx, zzz, zmone; + size_t bit, lastbit; + + curve25519_expand(q, othersKey); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for (int i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (e[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, (word32)(bit ^ lastbit)); + curve25519_swap_conditional(nqz, nqpqz, (word32)(bit ^ lastbit)); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for (int i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(sharedKey, nqz); + + return 0; +} + +int curve25519_mult(byte publicKey[32], const byte secretKey[32]) +{ + using namespace CryptoPP::Donna::X25519; + +#if (CRYPTOPP_CURVE25519_SSE2) + if (HasSSE2()) + return curve25519_mult_SSE2(publicKey, secretKey, basePoint); + else +#endif + + return curve25519_mult_CXX(publicKey, secretKey, basePoint); +} + +int curve25519_mult(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) +{ +#if (CRYPTOPP_CURVE25519_SSE2) + if (HasSSE2()) + return curve25519_mult_SSE2(sharedKey, secretKey, othersKey); + else +#endif + + return curve25519_mult_CXX(sharedKey, secretKey, othersKey); +} + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//******************************* ed25519 *******************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +int +ed25519_publickey_CXX(byte publicKey[32], const byte secretKey[32]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm a; + ALIGN(ALIGN_SPEC) ge25519 A; + hash_512bits extsk; + + /* A = aB */ + ed25519_extsk(extsk, secretKey); + expand256_modm(a, extsk, 32); + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(publicKey, &A); + + return 0; +} + +int +ed25519_publickey(byte publicKey[32], const byte secretKey[32]) +{ + return ed25519_publickey_CXX(publicKey, secretKey); +} + +int +ed25519_sign_CXX(std::istream& stream, const byte sk[32], const byte pk[32], byte RS[64]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm r, S, a; + ALIGN(ALIGN_SPEC) ge25519 R; + hash_512bits extsk, hashr, hram; + + // Unfortunately we need to read the stream twice. The fisrt time calculates + // 'r = H(aExt[32..64], m)'. The second time calculates 'S = H(R,A,m)'. There + // is a data dependency due to hashing 'RS' with 'R = [r]B' that does not + // allow us to read the stream once. + std::streampos where = stream.tellg(); + + ed25519_extsk(extsk, sk); + + /* r = H(aExt[32..64], m) */ + SHA512 hash; + hash.Update(extsk + 32, 32); + UpdateFromStream(hash, stream); + hash.Final(hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + // Reset stream for the second digest + stream.clear(); + stream.seekg(where); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, stream); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); + + return 0; +} + +int +ed25519_sign_CXX(const byte *m, size_t mlen, const byte sk[32], const byte pk[32], byte RS[64]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm r, S, a; + ALIGN(ALIGN_SPEC) ge25519 R; + hash_512bits extsk, hashr, hram; + + ed25519_extsk(extsk, sk); + + /* r = H(aExt[32..64], m) */ + SHA512 hash; + hash.Update(extsk + 32, 32); + hash.Update(m, mlen); + hash.Final(hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); + + return 0; +} + +int +ed25519_sign(std::istream& stream, const byte secretKey[32], const byte publicKey[32], + byte signature[64]) +{ + return ed25519_sign_CXX(stream, secretKey, publicKey, signature); +} + +int +ed25519_sign(const byte* message, size_t messageLength, const byte secretKey[32], + const byte publicKey[32], byte signature[64]) +{ + return ed25519_sign_CXX(message, messageLength, secretKey, publicKey, signature); +} + +int +ed25519_sign_open_CXX(std::istream& stream, const byte pk[32], const byte RS[64]) { + + using namespace CryptoPP::Donna::Ed25519; + + ALIGN(ALIGN_SPEC) ge25519 R, A; + hash_512bits hash; + bignum256modm hram, S; + byte checkR[32]; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, stream); + expand256_modm(hram, hash, 64); + + /* S */ + expand256_modm(S, RS + 32, 32); + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int +ed25519_sign_open_CXX(const byte *m, size_t mlen, const byte pk[32], const byte RS[64]) { + + using namespace CryptoPP::Donna::Ed25519; + + ALIGN(ALIGN_SPEC) ge25519 R, A; + hash_512bits hash; + bignum256modm hram, S; + byte checkR[32]; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, m, mlen); + expand256_modm(hram, hash, 64); + + /* S */ + expand256_modm(S, RS + 32, 32); + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int +ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64]) +{ + return ed25519_sign_open_CXX(message, messageLength, publicKey, signature); +} + +int +ed25519_sign_open(std::istream& stream, const byte publicKey[32], const byte signature[64]) +{ + return ed25519_sign_open_CXX(stream, publicKey, signature); +} + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_CURVE25519_32BIT diff --git a/extension/third_party/cryptopp/donna_32.h b/extension/third_party/cryptopp/donna_32.h new file mode 100644 index 00000000..dc9b91e5 --- /dev/null +++ b/extension/third_party/cryptopp/donna_32.h @@ -0,0 +1,411 @@ +// donna_32.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_32_H +#define CRYPTOPP_DONNA_32_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Arch32) + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; + +// ******************** x25519 Agreement ************************* // + +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) +#define mul32x32_64(a,b) (((word64)(a))*(b)) + +typedef word32 bignum25519[10]; + +const byte basePoint[32] = {9}; +const word32 reduce_mask_25 = (1 << 25) - 1; +const word32 reduce_mask_26 = (1 << 26) - 1; + +// ****************** ed25519 Signatures *********************** // + +typedef byte hash_512bits[64]; + +const int bignum256modm_bits_per_limb = 30; +const int bignum256modm_limb_size = 9; +typedef word32 bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[9]; + +struct ge25519 { + bignum25519 x, y, z, t; +}; + +struct ge25519_p1p1 { + bignum25519 x, y, z, t; +}; + +struct ge25519_niels { + bignum25519 ysubx, xaddy, t2d; +}; + +struct ge25519_pniels { + bignum25519 ysubx, xaddy, z, t2d; +}; + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +// *************** ed25519-donna-32bit-tables.h *************** // + +ALIGN(16) const ge25519 ge25519_basepoint = { + {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, + {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, + {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, + {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} +}; + +ALIGN(16) const bignum25519 ge25519_ecd = { + 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 +}; + +ALIGN(16) const bignum25519 ge25519_ec2d = { + 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 +}; + +ALIGN(16) const bignum25519 ge25519_sqrtneg1 = { + 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 +}; + +ALIGN(16) const ge25519_niels ge25519_niels_sliding_multiples[32] = { + {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, + {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, + {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, + {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, + {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, + {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, + {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, + {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, + {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, + {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, + {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, + {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, + {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, + {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, + {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, + {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, + {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, + {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, + {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, + {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, + {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, + {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, + {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, + {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, + {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, + {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, + {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, + {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, + {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, + {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, + {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, + {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} +}; + +// *************** modm-donna-32bit.h *************** // + +const bignum256modm modm_m = { + 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, + 0x00000014, 0x00000000, 0x00000000, 0x00000000, + 0x00001000 +}; + +const bignum256modm modm_mu = { + 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, + 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x000fffff +}; + +/* multiples of p */ +const word32 twoP0 = 0x07ffffda; +const word32 twoP13579 = 0x03fffffe; +const word32 twoP2468 = 0x07fffffe; +const word32 fourP0 = 0x0fffffb4; +const word32 fourP13579 = 0x07fffffc; +const word32 fourP2468 = 0x0ffffffc; + +// *************** ed25519-donna-basepoint-table.h *************** // + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; + +NAMESPACE_END // Arch32 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_32_H diff --git a/extension/third_party/cryptopp/donna_64.cpp b/extension/third_party/cryptopp/donna_64.cpp new file mode 100644 index 00000000..ef07a5ab --- /dev/null +++ b/extension/third_party/cryptopp/donna_64.cpp @@ -0,0 +1,1815 @@ +// donna_64.cpp - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// The curve25519 and ed25519 source files multiplex different repos and +// architectures using namespaces. The repos are Andrew Moon's +// curve25519-donna and ed25519-donna. The architectures are 32-bit, 64-bit +// and SSE. For example, 32-bit x25519 uses symbols from Donna::X25519 and +// Donna::Arch32. + +// A fair amount of duplication happens below, but we could not directly +// use curve25519 for both x25519 and ed25519. A close examination reveals +// slight differences in the implementation. For example, look at the +// two curve25519_sub functions. + +// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]", +// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658 + +#include "pch.h" + +#include "config.h" +#include "donna.h" +#include "secblock.h" +#include "sha.h" +#include "misc.h" +#include "cpu.h" + +#include +#include + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char DONNA64_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +// Can't use GetAlignmentOf() because of C++11 and constexpr +// Can use 'const unsigned int' because of MSVC 2013 +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# define ALIGN_SPEC 16 +#else +# define ALIGN_SPEC 8 +#endif + +ANONYMOUS_NAMESPACE_END + +#if defined(CRYPTOPP_CURVE25519_64BIT) + +#include "donna_64.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word64; +using CryptoPP::GetWord; +using CryptoPP::PutWord; +using CryptoPP::LITTLE_ENDIAN_ORDER; + +inline word64 U8TO64_LE(const byte* p) +{ + return GetWord(false, LITTLE_ENDIAN_ORDER, p); +} + +inline void U64TO8_LE(byte* p, word64 w) +{ + PutWord(false, LITTLE_ENDIAN_ORDER, p, w); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(X25519) +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::sword32; +using CryptoPP::word64; +using CryptoPP::sword64; + +using CryptoPP::GetBlock; +using CryptoPP::LittleEndian; + +// Bring in all the symbols from the 64-bit header +using namespace CryptoPP::Donna::Arch64; + +/* out = in */ +inline void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; out[1] = in[1]; + out[2] = in[2]; out[3] = in[3]; + out[4] = in[4]; +} + +/* out = a + b */ +inline void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +/* out = a - b */ +inline void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + two54m152 - b[0]; + out[1] = a[1] + two54m8 - b[1]; + out[2] = a[2] + two54m8 - b[2]; + out[3] = a[3] + two54m8 - b[3]; + out[4] = a[4] + two54m8 - b[4]; +} + +/* out = (in * scalar) */ +inline void +curve25519_scalar_product(bignum25519 out, const bignum25519 in, const word64 scalar) { + word128 a; + word64 c; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + a = ((word128) in[0]) * scalar; out[0] = (word64)a & reduce_mask_51; c = (word64)(a >> 51); + a = ((word128) in[1]) * scalar + c; out[1] = (word64)a & reduce_mask_51; c = (word64)(a >> 51); + a = ((word128) in[2]) * scalar + c; out[2] = (word64)a & reduce_mask_51; c = (word64)(a >> 51); + a = ((word128) in[3]) * scalar + c; out[3] = (word64)a & reduce_mask_51; c = (word64)(a >> 51); + a = ((word128) in[4]) * scalar + c; out[4] = (word64)a & reduce_mask_51; c = (word64)(a >> 51); + out[0] += c * 19; +#else + mul64x64_128(a, in[0], scalar) out[0] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[1], scalar) add128_64(a, c) out[1] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[2], scalar) add128_64(a, c) out[2] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[3], scalar) add128_64(a, c) out[3] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + mul64x64_128(a, in[4], scalar) add128_64(a, c) out[4] = lo128(a) & reduce_mask_51; shr128(c, a, 51); + out[0] += c * 19; +#endif +} + +/* out = a * b */ +inline void +curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = b[0]; r1 = b[1]; r2 = b[2]; r3 = b[3]; r4 = b[4]; + s0 = a[0]; s1 = a[1]; s2 = a[2]; s3 = a[3]; s4 = a[4]; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * s0; + t[1] = ((word128) r0) * s1 + ((word128) r1) * s0; + t[2] = ((word128) r0) * s2 + ((word128) r2) * s0 + ((word128) r1) * s1; + t[3] = ((word128) r0) * s3 + ((word128) r3) * s0 + ((word128) r1) * s2 + ((word128) r2) * s1; + t[4] = ((word128) r0) * s4 + ((word128) r4) * s0 + ((word128) r3) * s1 + ((word128) r1) * s3 + ((word128) r2) * s2; +#else + mul64x64_128(t[0], r0, s0) + mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) + mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) + mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) + mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) +#endif + + r1 *= 19; r2 *= 19; r3 *= 19; r4 *= 19; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] += ((word128) r4) * s1 + ((word128) r1) * s4 + ((word128) r2) * s3 + ((word128) r3) * s2; + t[1] += ((word128) r4) * s2 + ((word128) r2) * s4 + ((word128) r3) * s3; + t[2] += ((word128) r4) * s3 + ((word128) r3) * s4; + t[3] += ((word128) r4) * s4; +#else + mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) + mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) + mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) + mul64x64_128(mul, r4, s4) add128(t[3], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; +} + +/* out = in^(2 * count) */ +inline void +curve25519_square_times(bignum25519 out, const bignum25519 in, word64 count) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,c; + word64 d0,d1,d2,d4,d419; + + r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4]; + + do { + d0 = r0 * 2; d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; d4 = d419 * 2; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 )); + t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19)); + t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 )); + t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 )); + t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + } while(--count); + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; +} + +inline void +curve25519_square(bignum25519 out, const bignum25519 in) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,c; + word64 d0,d1,d2,d4,d419; + + r0 = in[0]; r1 = in[1]; r2 = in[2]; r3 = in[3]; r4 = in[4]; + + d0 = r0 * 2; d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; d4 = d419 * 2; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 )); + t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19)); + t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 )); + t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 )); + t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +inline void +curve25519_expand(bignum25519 out, const byte *in) { + word64 x0,x1,x2,x3; + GetBlock block(in); + block(x0)(x1)(x2)(x3); + + out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); + out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); + out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); + out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); + out[4] = x3 & reduce_mask_51; /* ignore the top bit */ +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +inline void +curve25519_contract(byte *out, const bignum25519 input) { + word64 t[5]; + word64 f, i; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + #define curve25519_contract_carry() \ + t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ + t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ + t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ + t[4] += t[3] >> 51; t[3] &= reduce_mask_51; + + #define curve25519_contract_carry_full() curve25519_contract_carry() \ + t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; + + #define curve25519_contract_carry_final() curve25519_contract_carry() \ + t[4] &= reduce_mask_51; + + curve25519_contract_carry_full() + curve25519_contract_carry_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + t[0] += 19; + curve25519_contract_carry_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + t[0] += 0x8000000000000 - 19; + t[1] += 0x8000000000000 - 1; + t[2] += 0x8000000000000 - 1; + t[3] += 0x8000000000000 - 1; + t[4] += 0x8000000000000 - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + curve25519_contract_carry_final() + + #define write51full(n,shift) \ + f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ + for (i = 0; i < 8; i++, f >>= 8) *out++ = (byte)f; + #define write51(n) write51full(n,13*n) + + write51(0) + write51(1) + write51(2) + write51(3) + + #undef curve25519_contract_carry + #undef curve25519_contract_carry_full + #undef curve25519_contract_carry_final + #undef write51full + #undef write51 +} + +/* + * Swap the contents of [qx] and [qpx] iff @swap is non-zero + */ +inline void +curve25519_swap_conditional(bignum25519 x, bignum25519 qpx, word64 iswap) { + const word64 swap = (word64)(-(sword64)iswap); + word64 x0,x1,x2,x3,x4; + + x0 = swap & (x[0] ^ qpx[0]); x[0] ^= x0; qpx[0] ^= x0; + x1 = swap & (x[1] ^ qpx[1]); x[1] ^= x1; qpx[1] ^= x1; + x2 = swap & (x[2] ^ qpx[2]); x[2] ^= x2; qpx[2] ^= x2; + x3 = swap & (x[3] ^ qpx[3]); x[3] ^= x3; qpx[3] ^= x3; + x4 = swap & (x[4] ^ qpx[4]); x[4] ^= x4; qpx[4] ^= x4; +} + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + ALIGN(ALIGN_SPEC) bignum25519 t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void +curve25519_recip(bignum25519 out, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 a, t0, b; + + /* 2 */ curve25519_square(a, z); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square(t0, a); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul(out, b, a); +} + +ANONYMOUS_NAMESPACE_END +NAMESPACE_END // X25519 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//******************************* ed25519 *******************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Ed25519) +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::sword32; +using CryptoPP::word64; +using CryptoPP::sword64; + +using CryptoPP::GetBlock; +using CryptoPP::LittleEndian; + +using CryptoPP::SHA512; + +// Bring in all the symbols from the 64-bit header +using namespace CryptoPP::Donna::Arch64; + +/* out = in */ +inline void +curve25519_copy(bignum25519 out, const bignum25519 in) { + out[0] = in[0]; out[1] = in[1]; + out[2] = in[2]; out[3] = in[3]; + out[4] = in[4]; +} + +/* out = a + b */ +inline void +curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +/* out = a + b, where a and/or b are the result of a basic op (add,sub) */ +inline void +curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; +} + +inline void +curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word64 c; + out[0] = a[0] + b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = a[1] + b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = a[2] + b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = a[3] + b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = a[4] + b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* out = a - b */ +inline void +curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + twoP0 - b[0]; + out[1] = a[1] + twoP1234 - b[1]; + out[2] = a[2] + twoP1234 - b[2]; + out[3] = a[3] + twoP1234 - b[3]; + out[4] = a[4] + twoP1234 - b[4]; +} + +/* out = a - b, where a and/or b are the result of a basic op (add,sub) */ +inline void +curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) { + out[0] = a[0] + fourP0 - b[0]; + out[1] = a[1] + fourP1234 - b[1]; + out[2] = a[2] + fourP1234 - b[2]; + out[3] = a[3] + fourP1234 - b[3]; + out[4] = a[4] + fourP1234 - b[4]; +} + +inline void +curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) { + word64 c; + out[0] = a[0] + fourP0 - b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = a[1] + fourP1234 - b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = a[2] + fourP1234 - b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = a[3] + fourP1234 - b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = a[4] + fourP1234 - b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* out = -a */ +inline void +curve25519_neg(bignum25519 out, const bignum25519 a) { + word64 c; + out[0] = twoP0 - a[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51; + out[1] = twoP1234 - a[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51; + out[2] = twoP1234 - a[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51; + out[3] = twoP1234 - a[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51; + out[4] = twoP1234 - a[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51; + out[0] += c * 19; +} + +/* out = a * b */ +inline void +curve25519_mul(bignum25519 out, const bignum25519 in2, const bignum25519 in) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = in[0]; r1 = in[1]; + r2 = in[2]; r3 = in[3]; + r4 = in[4]; + + s0 = in2[0]; s1 = in2[1]; + s2 = in2[2]; s3 = in2[3]; + s4 = in2[4]; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * s0; + t[1] = ((word128) r0) * s1 + ((word128) r1) * s0; + t[2] = ((word128) r0) * s2 + ((word128) r2) * s0 + ((word128) r1) * s1; + t[3] = ((word128) r0) * s3 + ((word128) r3) * s0 + ((word128) r1) * s2 + ((word128) r2) * s1; + t[4] = ((word128) r0) * s4 + ((word128) r4) * s0 + ((word128) r3) * s1 + ((word128) r1) * s3 + ((word128) r2) * s2; +#else + mul64x64_128(t[0], r0, s0) + mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul) + mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul) + mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul) + mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul) +#endif + + r1 *= 19; r2 *= 19; + r3 *= 19; r4 *= 19; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] += ((word128) r4) * s1 + ((word128) r1) * s4 + ((word128) r2) * s3 + ((word128) r3) * s2; + t[1] += ((word128) r4) * s2 + ((word128) r2) * s4 + ((word128) r3) * s3; + t[2] += ((word128) r4) * s3 + ((word128) r3) * s4; + t[3] += ((word128) r4) * s4; +#else + mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul) + mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul) + mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul) + mul64x64_128(mul, r4, s4) add128(t[3], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; +} + +void +curve25519_mul_noinline(bignum25519 out, const bignum25519 in2, const bignum25519 in) { + curve25519_mul(out, in2, in); +} + +/* out = in^(2 * count) */ +void +curve25519_square_times(bignum25519 out, const bignum25519 in, word64 count) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,c; + word64 d0,d1,d2,d4,d419; + + r0 = in[0]; r1 = in[1]; + r2 = in[2]; r3 = in[3]; + r4 = in[4]; + + do { + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 )); + t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19)); + t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 )); + t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 )); + t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; + r1 = lo128(t[1]) & reduce_mask_51; shl128(c, t[0], 13); r1 += c; + r2 = lo128(t[2]) & reduce_mask_51; shl128(c, t[1], 13); r2 += c; + r3 = lo128(t[3]) & reduce_mask_51; shl128(c, t[2], 13); r3 += c; + r4 = lo128(t[4]) & reduce_mask_51; shl128(c, t[3], 13); r4 += c; + shl128(c, t[4], 13); r0 += c * 19; + c = r0 >> 51; r0 &= reduce_mask_51; + r1 += c ; c = r1 >> 51; r1 &= reduce_mask_51; + r2 += c ; c = r2 >> 51; r2 &= reduce_mask_51; + r3 += c ; c = r3 >> 51; r3 &= reduce_mask_51; + r4 += c ; c = r4 >> 51; r4 &= reduce_mask_51; + r0 += c * 19; + } while(--count); + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; +} + +inline void +curve25519_square(bignum25519 out, const bignum25519 in) { +#if !defined(CRYPTOPP_WORD128_AVAILABLE) + word128 mul; +#endif + word128 t[5]; + word64 r0,r1,r2,r3,r4,c; + word64 d0,d1,d2,d4,d419; + + r0 = in[0]; r1 = in[1]; + r2 = in[2]; r3 = in[3]; + r4 = in[4]; + + d0 = r0 * 2; d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + t[0] = ((word128) r0) * r0 + ((word128) d4) * r1 + (((word128) d2) * (r3 )); + t[1] = ((word128) d0) * r1 + ((word128) d4) * r2 + (((word128) r3) * (r3 * 19)); + t[2] = ((word128) d0) * r2 + ((word128) r1) * r1 + (((word128) d4) * (r3 )); + t[3] = ((word128) d0) * r3 + ((word128) d1) * r2 + (((word128) r4) * (d419 )); + t[4] = ((word128) d0) * r4 + ((word128) d1) * r3 + (((word128) r2) * (r2 )); +#else + mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul) + mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul) + mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul) + mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul) + mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul) +#endif + + r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51); + add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51); + add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51); + add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51); + add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51; + r1 += c; + + out[0] = r0; out[1] = r1; + out[2] = r2; out[3] = r3; + out[4] = r4; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +inline void +curve25519_expand(bignum25519 out, const byte *in) { + word64 x0,x1,x2,x3; + GetBlock block(in); + block(x0)(x1)(x2)(x3); + + out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13); + out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26); + out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39); + out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12); + out[4] = x3 & reduce_mask_51; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +inline void +curve25519_contract(byte *out, const bignum25519 input) { + word64 t[5]; + word64 f, i; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + #define curve25519_contract_carry() \ + t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \ + t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \ + t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \ + t[4] += t[3] >> 51; t[3] &= reduce_mask_51; + + #define curve25519_contract_carry_full() curve25519_contract_carry() \ + t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51; + + #define curve25519_contract_carry_final() curve25519_contract_carry() \ + t[4] &= reduce_mask_51; + + curve25519_contract_carry_full() + curve25519_contract_carry_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + t[0] += 19; + curve25519_contract_carry_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + t[0] += (reduce_mask_51 + 1) - 19; + t[1] += (reduce_mask_51 + 1) - 1; + t[2] += (reduce_mask_51 + 1) - 1; + t[3] += (reduce_mask_51 + 1) - 1; + t[4] += (reduce_mask_51 + 1) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + curve25519_contract_carry_final() + + #define write51full(n,shift) \ + f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \ + for (i = 0; i < 8; i++, f >>= 8) *out++ = (byte)f; + #define write51(n) write51full(n,13*n) + write51(0) + write51(1) + write51(2) + write51(3) +} + +#if !defined(ED25519_GCC_64BIT_CHOOSE) + +/* out = (flag) ? in : out */ +inline void +curve25519_move_conditional_bytes(byte out[96], const byte in[96], word64 flag) +{ + // TODO: enable this code path once we can test and benchmark it. + // It is about 24 insns shorter, it avoids punning which may be UB, + // and it is guaranteed constant time. +#if defined(__GNUC__) && defined(__x86_64__) && 0 + const word32 iter = 96/sizeof(word64); + word64* outq = reinterpret_cast(out); + const word64* inq = reinterpret_cast(in); + word64 idx=0, val; + + __asm__ __volatile__ ( + ".att_syntax ;\n" + "cmpq $0, %[flag] ;\n" // compare, set ZERO flag + "movq %[iter], %%rcx ;\n" // load iteration count + "1: ;\n" + " movq (%[idx],%[out]), %[val] ;\n" // val = out[idx] + " cmovnzq (%[idx],%[in]), %[val] ;\n" // copy in[idx] to val if NZ + " movq %[val], (%[idx],%[out]) ;\n" // out[idx] = val + " leaq 8(%[idx]), %[idx] ;\n" // increment index + " loopnz 1b ;\n" // does not affect flags + : [out] "+S" (outq), [in] "+D" (inq), + [idx] "+b" (idx), [val] "=r" (val) + : [flag] "g" (flag), [iter] "I" (iter) + : "rcx", "memory", "cc" + ); +#else + const word64 nb = flag - 1, b = ~nb; + const word64 *inq = (const word64 *)(const void*)in; + word64 *outq = (word64 *)(void *)out; + outq[0] = (outq[0] & nb) | (inq[0] & b); + outq[1] = (outq[1] & nb) | (inq[1] & b); + outq[2] = (outq[2] & nb) | (inq[2] & b); + outq[3] = (outq[3] & nb) | (inq[3] & b); + outq[4] = (outq[4] & nb) | (inq[4] & b); + outq[5] = (outq[5] & nb) | (inq[5] & b); + outq[6] = (outq[6] & nb) | (inq[6] & b); + outq[7] = (outq[7] & nb) | (inq[7] & b); + outq[8] = (outq[8] & nb) | (inq[8] & b); + outq[9] = (outq[9] & nb) | (inq[9] & b); + outq[10] = (outq[10] & nb) | (inq[10] & b); + outq[11] = (outq[11] & nb) | (inq[11] & b); +#endif +} + +/* if (iswap) swap(a, b) */ +inline void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, word64 iswap) { + const word64 swap = (word64)(-(sword64)iswap); + word64 x0,x1,x2,x3,x4; + + x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0; + x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1; + x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2; + x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3; + x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4; +} + +#endif /* ED25519_GCC_64BIT_CHOOSE */ + +// ************************************************************************************ + +inline void +ed25519_hash(byte *hash, const byte *in, size_t inlen) { + SHA512().CalculateDigest(hash, in, inlen); +} + +inline void +ed25519_extsk(hash_512bits extsk, const byte sk[32]) { + ed25519_hash(extsk, sk, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; +} + +void +UpdateFromStream(HashTransformation& hash, std::istream& stream) +{ + SecByteBlock block(4096); + while (stream.read((char*)block.begin(), block.size())) + hash.Update(block, block.size()); + + std::streamsize rem = stream.gcount(); + if (rem) + hash.Update(block, rem); + + block.SetMark(0); +} + +void +ed25519_hram(hash_512bits hram, const byte RS[64], const byte pk[32], const byte *m, size_t mlen) { + SHA512 hash; + hash.Update(RS, 32); + hash.Update(pk, 32); + hash.Update(m, mlen); + hash.Final(hram); +} + +void +ed25519_hram(hash_512bits hram, const byte RS[64], const byte pk[32], std::istream& stream) { + SHA512 hash; + hash.Update(RS, 32); + hash.Update(pk, 32); + UpdateFromStream(hash, stream); + hash.Final(hram); +} + +bignum256modm_element_t +lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) { + return (a - b) >> 63; +} + +void +reduce256_modm(bignum256modm r) { + bignum256modm t; + bignum256modm_element_t b = 0, pb, mask; + + /* t = r - m */ + pb = 0; + pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b; + pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b; + pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b; + pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b; + pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32)); + + /* keep r if r was smaller than m */ + mask = b - 1; + + r[0] ^= mask & (r[0] ^ t[0]); + r[1] ^= mask & (r[1] ^ t[1]); + r[2] ^= mask & (r[2] ^ t[2]); + r[3] ^= mask & (r[3] ^ t[3]); + r[4] ^= mask & (r[4] ^ t[4]); +} + +void +barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) { + bignum256modm q3, r2; + word128 c, mul; + bignum256modm_element_t f, b, pb; + + /* q1 = x >> 248 = 264 bits = 5 56 bit elements + q2 = mu * q1 + q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */ + mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56); + mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul) + f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul) + f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul) + f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul) + f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56); + mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f) + f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56); + q3[4] |= (f << 16); + + mul64x64_128(c, modm_m[0], q3[0]) + r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul) + r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul) + r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul) + r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul) + r2[4] = lo128(c) & 0x0000ffffffffff; + + pb = 0; + pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b; + pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b; + pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b; + pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b; + pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40)); + + reduce256_modm(r); + reduce256_modm(r); +} + +void +add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm_element_t c; + + c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56; + c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56; + c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56; + c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56; + c += x[4] + y[4]; r[4] = c; + + reduce256_modm(r); +} + +void +mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) { + bignum256modm q1, r1; + word128 c, mul; + bignum256modm_element_t f; + + mul64x64_128(c, x[0], y[0]) + f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul) + f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul) + f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul) + f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56); + mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul) + f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul) + f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul) + f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul) + f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + mul64x64_128(c, x[4], y[4]) add128_64(c, f) + f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56); + q1[4] |= (f << 32); + + barrett_reduce256_modm(r, q1, r1); +} + +void +expand256_modm(bignum256modm out, const byte *in, size_t len) { + byte work[64] = {0}; + bignum256modm_element_t x[16]; + bignum256modm q1; + + memcpy(work, in, len); + x[0] = U8TO64_LE(work + 0); + x[1] = U8TO64_LE(work + 8); + x[2] = U8TO64_LE(work + 16); + x[3] = U8TO64_LE(work + 24); + x[4] = U8TO64_LE(work + 32); + x[5] = U8TO64_LE(work + 40); + x[6] = U8TO64_LE(work + 48); + x[7] = U8TO64_LE(work + 56); + + /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */ + out[0] = ( x[0]) & 0xffffffffffffff; + out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; + out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; + out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; + out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff; + + /* under 252 bits, no need to reduce */ + if (len < 32) + return; + + /* q1 = x >> 248 = 264 bits */ + q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff; + q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff; + q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff; + q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff; + q1[4] = ((x[ 7] >> 24) ); + + barrett_reduce256_modm(out, q1, out); +} + +void +expand_raw256_modm(bignum256modm out, const byte in[32]) { + bignum256modm_element_t x[4]; + + x[0] = U8TO64_LE(in + 0); + x[1] = U8TO64_LE(in + 8); + x[2] = U8TO64_LE(in + 16); + x[3] = U8TO64_LE(in + 24); + + out[0] = ( x[0]) & 0xffffffffffffff; + out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff; + out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff; + out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff; + out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff; +} + +void +contract256_modm(byte out[32], const bignum256modm in) { + U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56)); + U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48)); + U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40)); + U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32)); +} + +void +contract256_window4_modm(signed char r[64], const bignum256modm in) { + char carry; + signed char *quads = r; + bignum256modm_element_t i, j, v, m; + + for (i = 0; i < 5; i++) { + v = in[i]; + m = (i == 4) ? 8 : 14; + for (j = 0; j < m; j++) { + *quads++ = (v & 15); + v >>= 4; + } + } + + /* making it signed */ + carry = 0; + for(i = 0; i < 63; i++) { + r[i] += carry; + r[i+1] += (r[i] >> 4); + r[i] &= 15; + carry = (r[i] >> 3); + r[i] -= (carry << 4); + } + r[63] += carry; +} + +void +contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) { + int i,j,k,b; + int m = (1 << (windowsize - 1)) - 1, soplen = 256; + signed char *bits = r; + bignum256modm_element_t v; + + /* first put the binary expansion into r */ + for (i = 0; i < 4; i++) { + v = s[i]; + for (j = 0; j < 56; j++, v >>= 1) + *bits++ = (v & 1); + } + v = s[4]; + for (j = 0; j < 32; j++, v >>= 1) + *bits++ = (v & 1); + + /* Making it sliding window */ + for (j = 0; j < soplen; j++) { + if (!r[j]) + continue; + + for (b = 1; (b < (soplen - j)) && (b <= 6); b++) { + if ((r[j] + (r[j + b] << b)) <= m) { + r[j] += r[j + b] << b; + r[j + b] = 0; + } else if ((r[j] - (r[j + b] << b)) >= -m) { + r[j] -= r[j + b] << b; + for (k = j + b; k < soplen; k++) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else if (r[j + b]) { + break; + } + } + } +} + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + ALIGN(ALIGN_SPEC) bignum25519 t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void +curve25519_recip(bignum25519 out, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 a,t0,b; + + /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a); +} + +/* + * z^((p-5)/8) = z^(2^252 - 3) + */ +void +curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) { + ALIGN(ALIGN_SPEC) bignum25519 b,c,t0; + + /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */ + /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */ + /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */ + /* 22 */ curve25519_square_times(t0, c, 1); + /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2); + /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z); +} + +inline void +ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); +} + +inline void +ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) { + curve25519_mul(r->x, p->x, p->t); + curve25519_mul(r->y, p->y, p->z); + curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +} + +void +ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) { + curve25519_sub(p->ysubx, r->y, r->x); + curve25519_add(p->xaddy, r->y, r->x); + curve25519_copy(p->z, r->z); + curve25519_mul(p->t2d, r->t, ge25519_ec2d); +} + +void +ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) { + bignum25519 a,b,c,d,t,u; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_sub(t, q->y, q->x); + curve25519_add(u, q->y, q->x); + curve25519_mul(a, a, t); + curve25519_mul(b, b, u); + curve25519_mul(c, p->t, q->t); + curve25519_mul(c, c, ge25519_ec2d); + curve25519_mul(d, p->z, q->z); + curve25519_add(d, d, d); + curve25519_sub(r->x, b, a); + curve25519_add(r->y, b, a); + curve25519_add_after_basic(r->z, d, c); + curve25519_sub_after_basic(r->t, d, c); +} + +void +ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) { + bignum25519 a,b,c; + + curve25519_square(a, p->x); + curve25519_square(b, p->y); + curve25519_square(c, p->z); + curve25519_add_reduce(c, c, c); + curve25519_add(r->x, p->x, p->y); + curve25519_square(r->x, r->x); + curve25519_add(r->y, b, a); + curve25519_sub(r->z, b, a); + curve25519_sub_after_basic(r->x, r->x, r->y); + curve25519_sub_after_basic(r->t, c, r->z); +} + +void +ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, byte signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_add_reduce(r->t, p->z, p->z); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +void +ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, byte signbit) { + const bignum25519 *qb = (const bignum25519 *)q; + bignum25519 *rb = (bignum25519 *)r; + bignum25519 a,b,c; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */ + curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */ + curve25519_add(r->y, r->x, a); + curve25519_sub(r->x, r->x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(r->t, p->z, q->z); + curve25519_add_reduce(r->t, r->t, r->t); + curve25519_copy(r->z, r->t); + curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */ + curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */ +} + +void +ge25519_double_partial(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_partial(r, &t); +} + +void +ge25519_double(ge25519 *r, const ge25519 *p) { + ge25519_p1p1 t; + ge25519_double_p1p1(&t, p); + ge25519_p1p1_to_full(r, &t); +} + +void +ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) { + ge25519_p1p1 t; + ge25519_add_p1p1(&t, p, q); + ge25519_p1p1_to_full(r, &t); +} + +void +ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) { + bignum25519 a,b,c,e,f,g,h; + + curve25519_sub(a, r->y, r->x); + curve25519_add(b, r->y, r->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(e, b, q->xaddy); + curve25519_add(h, e, a); + curve25519_sub(e, e, a); + curve25519_mul(c, r->t, q->t2d); + curve25519_add(f, r->z, r->z); + curve25519_add_after_basic(g, f, c); + curve25519_sub_after_basic(f, f, c); + curve25519_mul(r->x, e, f); + curve25519_mul(r->y, h, g); + curve25519_mul(r->z, g, f); + curve25519_mul(r->t, e, h); +} + +void +ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) { + bignum25519 a,b,c,x,y,z,t; + + curve25519_sub(a, p->y, p->x); + curve25519_add(b, p->y, p->x); + curve25519_mul(a, a, q->ysubx); + curve25519_mul(x, b, q->xaddy); + curve25519_add(y, x, a); + curve25519_sub(x, x, a); + curve25519_mul(c, p->t, q->t2d); + curve25519_mul(t, p->z, q->z); + curve25519_add(t, t, t); + curve25519_add_after_basic(z, t, c); + curve25519_sub_after_basic(t, t, c); + curve25519_mul(r->xaddy, x, t); + curve25519_mul(r->ysubx, y, z); + curve25519_mul(r->z, z, t); + curve25519_mul(r->t2d, x, y); + curve25519_copy(y, r->ysubx); + curve25519_sub(r->ysubx, r->ysubx, r->xaddy); + curve25519_add(r->xaddy, r->xaddy, y); + curve25519_mul(r->t2d, r->t2d, ge25519_ec2d); +} + +void +ge25519_pack(byte r[32], const ge25519 *p) { + bignum25519 tx, ty, zi; + byte parity[32]; + curve25519_recip(zi, p->z); + curve25519_mul(tx, p->x, zi); + curve25519_mul(ty, p->y, zi); + curve25519_contract(r, ty); + curve25519_contract(parity, tx); + r[31] ^= ((parity[0] & 1) << 7); +} + +int +ed25519_verify(const byte *x, const byte *y, size_t len) { + size_t differentbits = 0; + while (len--) + differentbits |= (*x++ ^ *y++); + return (int) (1 & ((differentbits - 1) >> 8)); +} + +int +ge25519_unpack_negative_vartime(ge25519 *r, const byte p[32]) { + const byte zero[32] = {0}; + const bignum25519 one = {1}; + byte parity = p[31] >> 7; + byte check[32]; + bignum25519 t, root, num, den, d3; + + curve25519_expand(r->y, p); + curve25519_copy(r->z, one); + curve25519_square(num, r->y); /* x = y^2 */ + curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */ + curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */ + curve25519_add(den, den, r->z); /* den = dy^2 + 1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + curve25519_square(t, den); + curve25519_mul(d3, t, den); + curve25519_square(r->x, d3); + curve25519_mul(r->x, r->x, den); + curve25519_mul(r->x, r->x, num); + curve25519_pow_two252m3(r->x, r->x); + + /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */ + curve25519_mul(r->x, r->x, d3); + curve25519_mul(r->x, r->x, num); + + /* 3. Check if either of the roots works: */ + curve25519_square(t, r->x); + curve25519_mul(t, t, den); + curve25519_sub_reduce(root, t, num); + curve25519_contract(check, root); + if (!ed25519_verify(check, zero, 32)) { + curve25519_add_reduce(t, t, num); + curve25519_contract(check, t); + if (!ed25519_verify(check, zero, 32)) + return 0; + curve25519_mul(r->x, r->x, ge25519_sqrtneg1); + } + + curve25519_contract(check, r->x); + if ((check[0] & 1) == parity) { + curve25519_copy(t, r->x); + curve25519_neg(r->x, t); + } + curve25519_mul(r->t, r->x, r->y); + return 1; +} + +/* computes [s1]p1 + [s2]basepoint */ +void +ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) { + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[S1_TABLE_SIZE]; + ge25519 d1; + ge25519_p1p1 t; + sword32 i; + + contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE); + contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE); + + ge25519_double(&d1, p1); + ge25519_full_to_pniels(pre1, p1); + for (i = 0; i < S1_TABLE_SIZE - 1; i++) + ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]); + + /* set neutral */ + memset(r, 0, sizeof(ge25519)); + r->y[0] = 1; + r->z[0] = 1; + + i = 255; + while ((i >= 0) && !(slide1[i] | slide2[i])) + i--; + + for (; i >= 0; i--) { + ge25519_double_p1p1(&t, r); + + if (slide1[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (byte)slide1[i] >> 7); + } + + if (slide2[i]) { + ge25519_p1p1_to_full(r, &t); + ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (byte)slide2[i] >> 7); + } + + ge25519_p1p1_to_partial(r, &t); + } +} + +#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS) + +word32 +ge25519_windowb_equal(word32 b, word32 c) { + return ((b ^ c) - 1) >> 31; +} + +void +ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const byte table[256][96], word32 pos, signed char b) { + bignum25519 neg; + word32 sign = (word32)((byte)b >> 7); + word32 mask = ~(sign - 1); + word32 u = (b + mask) ^ mask; + word32 i; + + /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */ + byte packed[96] = {0}; + packed[0] = 1; + packed[32] = 1; + + for (i = 0; i < 8; i++) + curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1)); + + /* expand in to t */ + curve25519_expand(t->ysubx, packed + 0); + curve25519_expand(t->xaddy, packed + 32); + curve25519_expand(t->t2d , packed + 64); + + /* adjust for sign */ + curve25519_swap_conditional(t->ysubx, t->xaddy, sign); + curve25519_neg(neg, t->t2d); + curve25519_swap_conditional(t->t2d, neg, sign); +} + +#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */ + +/* computes [s]basepoint */ +void +ge25519_scalarmult_base_niels(ge25519 *r, const byte basepoint_table[256][96], const bignum256modm s) { + signed char b[64]; + word32 i; + ge25519_niels t; + + contract256_window4_modm(b, s); + + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]); + curve25519_sub_reduce(r->x, t.xaddy, t.ysubx); + curve25519_add_reduce(r->y, t.xaddy, t.ysubx); + memset(r->z, 0, sizeof(bignum25519)); + curve25519_copy(r->t, t.t2d); + r->z[0] = 2; + for (i = 3; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double_partial(r, r); + ge25519_double(r, r); + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]); + curve25519_mul(t.t2d, t.t2d, ge25519_ecd); + ge25519_nielsadd2(r, &t); + for(i = 2; i < 64; i += 2) { + ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]); + ge25519_nielsadd2(r, &t); + } +} + +ANONYMOUS_NAMESPACE_END +NAMESPACE_END // Ed25519 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//***************************** curve25519 *****************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +int curve25519_mult_CXX(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) +{ + using namespace CryptoPP::Donna::X25519; + + FixedSizeSecBlock e; + for (size_t i = 0;i < 32;++i) + e[i] = secretKey[i]; + e[0] &= 0xf8; e[31] &= 0x7f; e[31] |= 0x40; + + bignum25519 nqpqx = {1}, nqpqz = {0}, nqz = {1}, nqx; + bignum25519 q, qx, qpqx, qqx, zzz, zmone; + size_t bit, lastbit; + + curve25519_expand(q, othersKey); + curve25519_copy(nqx, q); + + /* bit 255 is always 0, and bit 254 is always 1, so skip bit 255 and + start pre-swapped on bit 254 */ + lastbit = 1; + + /* we are doing bits 254..3 in the loop, but are swapping in bits 253..2 */ + for (int i = 253; i >= 2; i--) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_add(qpqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_mul(nqpqx, qpqx, nqz); + curve25519_mul(nqpqz, qx, nqpqz); + curve25519_add(qqx, nqpqx, nqpqz); + curve25519_sub(nqpqz, nqpqx, nqpqz); + curve25519_square(nqpqz, nqpqz); + curve25519_square(nqpqx, qqx); + curve25519_mul(nqpqz, nqpqz, q); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + + bit = (e[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, bit ^ lastbit); + curve25519_swap_conditional(nqz, nqpqz, bit ^ lastbit); + lastbit = bit; + } + + /* the final 3 bits are always zero, so we only need to double */ + for (int i = 0; i < 3; i++) { + curve25519_add(qx, nqx, nqz); + curve25519_sub(nqz, nqx, nqz); + curve25519_square(qx, qx); + curve25519_square(nqz, nqz); + curve25519_mul(nqx, qx, nqz); + curve25519_sub(nqz, qx, nqz); + curve25519_scalar_product(zzz, nqz, 121665); + curve25519_add(zzz, zzz, qx); + curve25519_mul(nqz, nqz, zzz); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(sharedKey, nqz); + + return 0; +} + +int curve25519_mult(byte publicKey[32], const byte secretKey[32]) +{ + using namespace CryptoPP::Donna::X25519; + +#if (CRYPTOPP_CURVE25519_SSE2) + if (HasSSE2()) + return curve25519_mult_SSE2(publicKey, secretKey, basePoint); + else +#endif + + return curve25519_mult_CXX(publicKey, secretKey, basePoint); +} + +int curve25519_mult(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) +{ +#if (CRYPTOPP_CURVE25519_SSE2) + if (HasSSE2()) + return curve25519_mult_SSE2(sharedKey, secretKey, othersKey); + else +#endif + + return curve25519_mult_CXX(sharedKey, secretKey, othersKey); +} + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +//******************************* ed25519 *******************************// + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +int +ed25519_publickey_CXX(byte publicKey[32], const byte secretKey[32]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm a; + ALIGN(ALIGN_SPEC) ge25519 A; + hash_512bits extsk; + + /* A = aB */ + ed25519_extsk(extsk, secretKey); + expand256_modm(a, extsk, 32); + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(publicKey, &A); + + return 0; +} + +int +ed25519_publickey(byte publicKey[32], const byte secretKey[32]) +{ + return ed25519_publickey_CXX(publicKey, secretKey); +} + +int +ed25519_sign_CXX(std::istream& stream, const byte sk[32], const byte pk[32], byte RS[64]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm r, S, a; + ALIGN(ALIGN_SPEC) ge25519 R; + hash_512bits extsk, hashr, hram; + + // Unfortunately we need to read the stream twice. The fisrt time calculates + // 'r = H(aExt[32..64], m)'. The second time calculates 'S = H(R,A,m)'. There + // is a data dependency due to hashing 'RS' with 'R = [r]B' that does not + // allow us to read the stream once. + std::streampos where = stream.tellg(); + + ed25519_extsk(extsk, sk); + + /* r = H(aExt[32..64], m) */ + SHA512 hash; + hash.Update(extsk + 32, 32); + UpdateFromStream(hash, stream); + hash.Final(hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + // Reset stream for the second digest + stream.clear(); + stream.seekg(where); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, stream); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); + return 0; +} + +int +ed25519_sign_CXX(const byte *m, size_t mlen, const byte sk[32], const byte pk[32], byte RS[64]) +{ + using namespace CryptoPP::Donna::Ed25519; + + bignum256modm r, S, a; + ALIGN(ALIGN_SPEC) ge25519 R; + hash_512bits extsk, hashr, hram; + + ed25519_extsk(extsk, sk); + + /* r = H(aExt[32..64], m) */ + SHA512 hash; + hash.Update(extsk + 32, 32); + hash.Update(m, mlen); + hash.Final(hashr); + expand256_modm(r, hashr, 64); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + ge25519_pack(RS, &R); + + /* S = H(R,A,m).. */ + ed25519_hram(hram, RS, pk, m, mlen); + expand256_modm(S, hram, 64); + + /* S = H(R,A,m)a */ + expand256_modm(a, extsk, 32); + mul256_modm(S, S, a); + + /* S = (r + H(R,A,m)a) */ + add256_modm(S, S, r); + + /* S = (r + H(R,A,m)a) mod L */ + contract256_modm(RS + 32, S); + return 0; +} + +int +ed25519_sign(std::istream& stream, const byte secretKey[32], const byte publicKey[32], + byte signature[64]) +{ + return ed25519_sign_CXX(stream, secretKey, publicKey, signature); +} + +int +ed25519_sign(const byte* message, size_t messageLength, const byte secretKey[32], + const byte publicKey[32], byte signature[64]) +{ + return ed25519_sign_CXX(message, messageLength, secretKey, publicKey, signature); +} + +int +ed25519_sign_open_CXX(const byte *m, size_t mlen, const byte pk[32], const byte RS[64]) { + + using namespace CryptoPP::Donna::Ed25519; + + ALIGN(ALIGN_SPEC) ge25519 R, A; + hash_512bits hash; + bignum256modm hram, S; + byte checkR[32]; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, m, mlen); + expand256_modm(hram, hash, 64); + + /* S */ + expand256_modm(S, RS + 32, 32); + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int +ed25519_sign_open_CXX(std::istream& stream, const byte pk[32], const byte RS[64]) { + + using namespace CryptoPP::Donna::Ed25519; + + ALIGN(ALIGN_SPEC) ge25519 R, A; + hash_512bits hash; + bignum256modm hram, S; + byte checkR[32]; + + if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk)) + return -1; + + /* hram = H(R,A,m) */ + ed25519_hram(hash, RS, pk, stream); + expand256_modm(hram, hash, 64); + + /* S */ + expand256_modm(S, RS + 32, 32); + + /* SB - H(R,A,m)A */ + ge25519_double_scalarmult_vartime(&R, &A, hram, S); + ge25519_pack(checkR, &R); + + /* check that R = SB - H(R,A,m)A */ + return ed25519_verify(RS, checkR, 32) ? 0 : -1; +} + +int +ed25519_sign_open(std::istream& stream, const byte publicKey[32], const byte signature[64]) +{ + return ed25519_sign_open_CXX(stream, publicKey, signature); +} + +int +ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64]) +{ + return ed25519_sign_open_CXX(message, messageLength, publicKey, signature); +} + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_CURVE25519_64BIT diff --git a/extension/third_party/cryptopp/donna_64.h b/extension/third_party/cryptopp/donna_64.h new file mode 100644 index 00000000..d98ad640 --- /dev/null +++ b/extension/third_party/cryptopp/donna_64.h @@ -0,0 +1,457 @@ +// donna_64.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_64_H +#define CRYPTOPP_DONNA_64_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" + +#if defined(_MSC_VER) +# include +# pragma intrinsic(_umul128) +# pragma intrinsic(__shiftright128) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Arch64) + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; + +// ******************** x25519 Agreement ************************* // + +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) +typedef word64 bignum25519[5]; + +const byte basePoint[32] = {9}; +const word64 reduce_mask_40 = ((word64)1 << 40) - 1; +const word64 reduce_mask_51 = ((word64)1 << 51) - 1; +const word64 reduce_mask_52 = ((word64)1 << 52) - 1; +const word64 reduce_mask_56 = ((word64)1 << 56) - 1; + +const word64 two54m152 = (((word64)1) << 54) - 152; +const word64 two54m8 = (((word64)1) << 54) - 8; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) +using CryptoPP::word128; +# define lo128(a) ((word64)a) +# define hi128(a) ((word64)(a >> 64)) +# define add128(a,b) a += b; +# define add128_64(a,b) a += (word64)b; +# define mul64x64_128(out,a,b) out = (word128)a * b; +# define shr128(out,in,shift) out = (word64)(in >> (shift)); +# define shl128(out,in,shift) out = (word64)((in << shift) >> 64); + +#elif defined(_MSC_VER) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); +# define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); +# define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); +# define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) +# define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) +# define add128(a,b) { word64 p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } +# define add128_64(a,b) { word64 p = a.lo; a.lo += b; a.hi += (a.lo < p); } +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) + +#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); +# define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; +# define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; +# define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) +# define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) +# define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); +# define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) + +#else +// https://groups.google.com/forum/#!forum/cryptopp-users +# error "Unsupported platform" +#endif + +// ****************** ed25519 Signatures *********************** // + +typedef byte hash_512bits[64]; + +const int bignum256modm_bits_per_limb = 56; +const int bignum256modm_limb_size = 5; +typedef word64 bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[5]; + +/* multiples of p */ +const word64 twoP0 = 0x0fffffffffffda; +const word64 twoP1234 = 0x0ffffffffffffe; +const word64 fourP0 = 0x1fffffffffffb4; +const word64 fourP1234 = 0x1ffffffffffffc; + +struct ge25519 { + bignum25519 x, y, z, t; +}; + +struct ge25519_p1p1 { + bignum25519 x, y, z, t; +}; + +struct ge25519_niels { + bignum25519 ysubx, xaddy, t2d; +}; + +struct ge25519_pniels { + bignum25519 ysubx, xaddy, z, t2d; +}; + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +// *************** ed25519-donna-64bit-tables.h *************** // + +const ge25519 ge25519_basepoint = { + {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, + {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, + {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, + {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} +}; + +const bignum25519 ge25519_ecd = { + 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff +}; + +const bignum25519 ge25519_ec2d = { + 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff +}; + +const bignum25519 ge25519_sqrtneg1 = { + 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d +}; + +const ge25519_niels ge25519_niels_sliding_multiples[32] = { + {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, + {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, + {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, + {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}}, + {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}}, + {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}}, + {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}}, + {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}}, + {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}}, + {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}}, + {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}}, + {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}}, + {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}}, + {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}}, + {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}}, + {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}}, + {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}}, + {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}}, + {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}}, + {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}}, + {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}}, + {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}}, + {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}}, + {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}}, + {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}}, + {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}}, + {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}}, + {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}}, + {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}}, + {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}}, + {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}}, + {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}} +}; + +// ****************** modm-donna-64bit.h *********************** // + +const bignum256modm modm_m = { + 0x12631a5cf5d3ed, 0xf9dea2f79cd658, + 0x000000000014de, 0x00000000000000, + 0x00000010000000 +}; + +const bignum256modm modm_mu = { + 0x9ce5a30a2c131b, 0x215d086329a7ed, + 0xffffffffeb2106, 0xffffffffffffff, + 0x00000fffffffff +}; + +// *************** ed25519-donna-basepoint-table.h *************** // + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; + +NAMESPACE_END // Arch64 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_64_H diff --git a/extension/third_party/cryptopp/donna_sse.cpp b/extension/third_party/cryptopp/donna_sse.cpp new file mode 100644 index 00000000..2da9a6f7 --- /dev/null +++ b/extension/third_party/cryptopp/donna_sse.cpp @@ -0,0 +1,1123 @@ +// donna_sse.cpp - written and placed in public domain by Jeffrey Walton +// This is a integration of Andrew Moon's public domain code. +// Also see https://github.com/floodyberry/curve25519-donna. + +// This is a integration of Andrew Moon's public domain code. The port was +// clean, but it has one potential problem. The original code is C and relies +// upon unions. Accessing the inactive union member is undefined behavior in +// C++. That means copying the array into packedelem8.u is OK; but then using +// packedelem8.v in a calcualtion is UB. Fortunately most (all?) compilers +// take pity on C++ developers and compile the code. We will have to keep an +// eye on things or rewrite significant portions of this code. + +// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]", +// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658 + +#include "pch.h" + +#include "config.h" +#include "donna.h" +#include "secblock.h" +#include "misc.h" + +// The data is aligned, but Clang issues warning based on type +// and not the actual alignment of the variable and data. +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wcast-align" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char DONNA_SSE_FNAME[] = __FILE__; + +#if (CRYPTOPP_CURVE25519_SSE2) + +#include "donna_sse.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::sword32; +using CryptoPP::word64; +using CryptoPP::sword64; +using CryptoPP::GetBlock; +using CryptoPP::LittleEndian; + +// Bring in all the symbols from the SSE header +using namespace CryptoPP::Donna::ArchSSE; + +/* Copy a bignum to another: out = in */ +inline void +curve25519_copy(bignum25519 out, const bignum25519 in) { + xmmi x0,x1,x2; + x0 = _mm_load_si128((xmmi*)in + 0); + x1 = _mm_load_si128((xmmi*)in + 1); + x2 = _mm_load_si128((xmmi*)in + 2); + _mm_store_si128((xmmi*)out + 0, x0); + _mm_store_si128((xmmi*)out + 1, x1); + _mm_store_si128((xmmi*)out + 2, x2); +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +inline void +curve25519_expand(bignum25519 out, const byte in[32]) { + word32 x0,x1,x2,x3,x4,x5,x6,x7; + + x0 = *(word32 *)(in + 0); + x1 = *(word32 *)(in + 4); + x2 = *(word32 *)(in + 8); + x3 = *(word32 *)(in + 12); + x4 = *(word32 *)(in + 16); + x5 = *(word32 *)(in + 20); + x6 = *(word32 *)(in + 24); + x7 = *(word32 *)(in + 28); + + out[0] = ( x0 ) & reduce_mask_26; + out[1] = ((((word64)x1 << 32) | x0) >> 26) & reduce_mask_25; + out[2] = ((((word64)x2 << 32) | x1) >> 19) & reduce_mask_26; + out[3] = ((((word64)x3 << 32) | x2) >> 13) & reduce_mask_25; + out[4] = (( x3) >> 6) & reduce_mask_26; + out[5] = ( x4 ) & reduce_mask_25; + out[6] = ((((word64)x5 << 32) | x4) >> 25) & reduce_mask_26; + out[7] = ((((word64)x6 << 32) | x5) >> 19) & reduce_mask_25; + out[8] = ((((word64)x7 << 32) | x6) >> 12) & reduce_mask_26; + out[9] = (( x7) >> 6) & reduce_mask_25; /* ignore the top bit */ + + out[10] = 0; + out[11] = 0; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +inline void +curve25519_contract(byte out[32], const bignum25519 in) { + ALIGN(16) bignum25519 f; + + curve25519_copy(f, in); + + #define carry_pass() \ + f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \ + f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \ + f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \ + f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \ + f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \ + f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \ + f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \ + f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \ + f[9] += f[8] >> 26; f[8] &= reduce_mask_26; + + #define carry_pass_full() \ + carry_pass() \ + f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25; + + #define carry_pass_final() \ + carry_pass() \ + f[9] &= reduce_mask_25; + + carry_pass_full() + carry_pass_full() + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + f[0] += 19; + carry_pass_full() + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + f[0] += (1 << 26) - 19; + f[1] += (1 << 25) - 1; + f[2] += (1 << 26) - 1; + f[3] += (1 << 25) - 1; + f[4] += (1 << 26) - 1; + f[5] += (1 << 25) - 1; + f[6] += (1 << 26) - 1; + f[7] += (1 << 25) - 1; + f[8] += (1 << 26) - 1; + f[9] += (1 << 25) - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + carry_pass_final() + + #undef carry_pass + #undef carry_full + #undef carry_final + + *(word32 *)(out + 0) = ((f[0] ) | (f[1] << 26)); + *(word32 *)(out + 4) = ((f[1] >> 6) | (f[2] << 19)); + *(word32 *)(out + 8) = ((f[2] >> 13) | (f[3] << 13)); + *(word32 *)(out + 12) = ((f[3] >> 19) | (f[4] << 6)); + *(word32 *)(out + 16) = ((f[5] ) | (f[6] << 25)); + *(word32 *)(out + 20) = ((f[6] >> 7) | (f[7] << 19)); + *(word32 *)(out + 24) = ((f[7] >> 13) | (f[8] << 12)); + *(word32 *)(out + 28) = ((f[8] >> 20) | (f[9] << 6)); +} + +/* + * Maybe swap the contents of two felem arrays (@a and @b), each 5 elements + * long. Perform the swap iff @swap is non-zero. + */ +inline void +curve25519_swap_conditional(bignum25519 a, bignum25519 b, word32 iswap) { + const word32 swap = (word32)(-(sword32)iswap); + xmmi a0,a1,a2,b0,b1,b2,x0,x1,x2; + xmmi mask = _mm_cvtsi32_si128(swap); + mask = _mm_shuffle_epi32(mask, 0); + a0 = _mm_load_si128((xmmi *)a + 0); + a1 = _mm_load_si128((xmmi *)a + 1); + a2 = _mm_load_si128((xmmi *)a + 2); + b0 = _mm_load_si128((xmmi *)b + 0); + b1 = _mm_load_si128((xmmi *)b + 1); + b2 = _mm_load_si128((xmmi *)b + 2); + b0 = _mm_xor_si128(a0, b0); + b1 = _mm_xor_si128(a1, b1); + b2 = _mm_xor_si128(a2, b2); + x0 = _mm_and_si128(b0, mask); + x1 = _mm_and_si128(b1, mask); + x2 = _mm_and_si128(b2, mask); + x0 = _mm_xor_si128(x0, a0); + x1 = _mm_xor_si128(x1, a1); + x2 = _mm_xor_si128(x2, a2); + a0 = _mm_xor_si128(x0, b0); + a1 = _mm_xor_si128(x1, b1); + a2 = _mm_xor_si128(x2, b2); + _mm_store_si128((xmmi *)a + 0, x0); + _mm_store_si128((xmmi *)a + 1, x1); + _mm_store_si128((xmmi *)a + 2, x2); + _mm_store_si128((xmmi *)b + 0, a0); + _mm_store_si128((xmmi *)b + 1, a1); + _mm_store_si128((xmmi *)b + 2, a2); +} + +/* interleave two bignums */ +inline void +curve25519_tangle32(packedelem32 *out, const bignum25519 x, const bignum25519 z) { + xmmi x0,x1,x2,z0,z1,z2; + + x0 = _mm_load_si128((xmmi *)(x + 0)); + x1 = _mm_load_si128((xmmi *)(x + 4)); + x2 = _mm_load_si128((xmmi *)(x + 8)); + z0 = _mm_load_si128((xmmi *)(z + 0)); + z1 = _mm_load_si128((xmmi *)(z + 4)); + z2 = _mm_load_si128((xmmi *)(z + 8)); + + out[0].v = _mm_unpacklo_epi32(x0, z0); + out[1].v = _mm_unpackhi_epi32(x0, z0); + out[2].v = _mm_unpacklo_epi32(x1, z1); + out[3].v = _mm_unpackhi_epi32(x1, z1); + out[4].v = _mm_unpacklo_epi32(x2, z2); +} + +/* split a packed bignum in to it's two parts */ +inline void +curve25519_untangle64(bignum25519 x, bignum25519 z, const packedelem64 *in) { + _mm_store_si128((xmmi *)(x + 0), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[0].v, in[1].v), _mm_unpacklo_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(x + 4), _mm_unpacklo_epi64(_mm_unpacklo_epi32(in[4].v, in[5].v), _mm_unpacklo_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(x + 8), _mm_unpacklo_epi32(in[8].v, in[9].v) ); + _mm_store_si128((xmmi *)(z + 0), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[0].v, in[1].v), _mm_unpackhi_epi32(in[2].v, in[3].v))); + _mm_store_si128((xmmi *)(z + 4), _mm_unpacklo_epi64(_mm_unpackhi_epi32(in[4].v, in[5].v), _mm_unpackhi_epi32(in[6].v, in[7].v))); + _mm_store_si128((xmmi *)(z + 8), _mm_unpackhi_epi32(in[8].v, in[9].v) ); +} + +/* add two packed bignums */ +inline void +curve25519_add_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + out[0].v = _mm_add_epi32(r[0].v, s[0].v); + out[1].v = _mm_add_epi32(r[1].v, s[1].v); + out[2].v = _mm_add_epi32(r[2].v, s[2].v); + out[3].v = _mm_add_epi32(r[3].v, s[3].v); + out[4].v = _mm_add_epi32(r[4].v, s[4].v); +} + +/* subtract two packed bignums */ +inline void +curve25519_sub_packed32(packedelem32 *out, const packedelem32 *r, const packedelem32 *s) { + xmmi r0,r1,r2,r3,r4; + xmmi s0,s1,s2,s3; + xmmi c1,c2; + + r0 = _mm_add_epi32(r[0].v, packed32zeromodp0.v); + r1 = _mm_add_epi32(r[1].v, packed32zeromodp1.v); + r2 = _mm_add_epi32(r[2].v, packed32zeromodp1.v); + r3 = _mm_add_epi32(r[3].v, packed32zeromodp1.v); + r4 = _mm_add_epi32(r[4].v, packed32zeromodp1.v); + r0 = _mm_sub_epi32(r0, s[0].v); /* 00 11 */ + r1 = _mm_sub_epi32(r1, s[1].v); /* 22 33 */ + r2 = _mm_sub_epi32(r2, s[2].v); /* 44 55 */ + r3 = _mm_sub_epi32(r3, s[3].v); /* 66 77 */ + r4 = _mm_sub_epi32(r4, s[4].v); /* 88 99 */ + + s0 = _mm_unpacklo_epi64(r0, r2); /* 00 44 */ + s1 = _mm_unpackhi_epi64(r0, r2); /* 11 55 */ + s2 = _mm_unpacklo_epi64(r1, r3); /* 22 66 */ + s3 = _mm_unpackhi_epi64(r1, r3); /* 33 77 */ + + c1 = _mm_srli_epi32(s0, 26); c2 = _mm_srli_epi32(s2, 26); s0 = _mm_and_si128(s0, packedmask26262626.v); s2 = _mm_and_si128(s2, packedmask26262626.v); s1 = _mm_add_epi32(s1, c1); s3 = _mm_add_epi32(s3, c2); + c1 = _mm_srli_epi32(s1, 25); c2 = _mm_srli_epi32(s3, 25); s1 = _mm_and_si128(s1, packedmask25252525.v); s3 = _mm_and_si128(s3, packedmask25252525.v); s2 = _mm_add_epi32(s2, c1); r4 = _mm_add_epi32(r4, _mm_srli_si128(c2, 8)); s0 = _mm_add_epi32(s0, _mm_slli_si128(c2, 8)); + + out[0].v = _mm_unpacklo_epi64(s0, s1); /* 00 11 */ + out[1].v = _mm_unpacklo_epi64(s2, s3); /* 22 33 */ + out[2].v = _mm_unpackhi_epi64(s0, s1); /* 44 55 */ + out[3].v = _mm_unpackhi_epi64(s2, s3); /* 66 77 */ + out[4].v = r4; /* 88 99 */ +} + +/* multiply two packed bignums */ +inline void +curve25519_mul_packed64(packedelem64 *out, const packedelem64 *r, const packedelem64 *s) { + xmmi r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r1_2,r3_2,r5_2,r7_2,r9_2; + xmmi c1,c2; + + out[0].v = _mm_mul_epu32(r[0].v, s[0].v); + out[1].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[1].v), _mm_mul_epu32(r[1].v, s[0].v)); + r1_2 = _mm_slli_epi32(r[1].v, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[1].v), _mm_mul_epu32(r[2].v, s[0].v))); + out[3].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[1].v), _mm_mul_epu32(r[3].v, s[0].v)))); + r3_2 = _mm_slli_epi32(r[3].v, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[1].v), _mm_mul_epu32(r[4].v, s[0].v))))); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[1].v), _mm_mul_epu32(r[5].v, s[0].v)))))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[1].v), _mm_mul_epu32(r[6].v, s[0].v))))))); + out[7].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[1].v), _mm_mul_epu32(r[7].v , s[0].v)))))))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r1_2 , s[7].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2 , s[5].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2 , s[3].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2 , s[1].v), _mm_mul_epu32(r[8].v, s[0].v))))))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r[0].v, s[9].v), _mm_add_epi64(_mm_mul_epu32(r[1].v, s[8].v), _mm_add_epi64(_mm_mul_epu32(r[2].v, s[7].v), _mm_add_epi64(_mm_mul_epu32(r[3].v, s[6].v), _mm_add_epi64(_mm_mul_epu32(r[4].v, s[5].v), _mm_add_epi64(_mm_mul_epu32(r[5].v, s[4].v), _mm_add_epi64(_mm_mul_epu32(r[6].v, s[3].v), _mm_add_epi64(_mm_mul_epu32(r[7].v, s[2].v), _mm_add_epi64(_mm_mul_epu32(r[8].v, s[1].v), _mm_mul_epu32(r[9].v, s[0].v)))))))))); + + r1 = _mm_mul_epu32(r[1].v, packednineteen.v); + r2 = _mm_mul_epu32(r[2].v, packednineteen.v); + r1_2 = _mm_slli_epi32(r1, 1); + r3 = _mm_mul_epu32(r[3].v, packednineteen.v); + r4 = _mm_mul_epu32(r[4].v, packednineteen.v); + r3_2 = _mm_slli_epi32(r3, 1); + r5 = _mm_mul_epu32(r[5].v, packednineteen.v); + r6 = _mm_mul_epu32(r[6].v, packednineteen.v); + r5_2 = _mm_slli_epi32(r5, 1); + r7 = _mm_mul_epu32(r[7].v, packednineteen.v); + r8 = _mm_mul_epu32(r[8].v, packednineteen.v); + r7_2 = _mm_slli_epi32(r7, 1); + r9 = _mm_mul_epu32(r[9].v, packednineteen.v); + r9_2 = _mm_slli_epi32(r9, 1); + + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[1].v), _mm_add_epi64(_mm_mul_epu32(r8, s[2].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r6, s[4].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r4, s[6].v), _mm_add_epi64(_mm_mul_epu32(r3_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r2, s[8].v), _mm_mul_epu32(r1_2, s[9].v)))))))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[2].v), _mm_add_epi64(_mm_mul_epu32(r8, s[3].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r6, s[5].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r4, s[7].v), _mm_add_epi64(_mm_mul_epu32(r3 , s[8].v), _mm_mul_epu32(r2, s[9].v))))))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[3].v), _mm_add_epi64(_mm_mul_epu32(r8, s[4].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r6, s[6].v), _mm_add_epi64(_mm_mul_epu32(r5_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r4, s[8].v), _mm_mul_epu32(r3_2, s[9].v)))))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[4].v), _mm_add_epi64(_mm_mul_epu32(r8, s[5].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r6, s[7].v), _mm_add_epi64(_mm_mul_epu32(r5 , s[8].v), _mm_mul_epu32(r4, s[9].v))))))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[5].v), _mm_add_epi64(_mm_mul_epu32(r8, s[6].v), _mm_add_epi64(_mm_mul_epu32(r7_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r6, s[8].v), _mm_mul_epu32(r5_2, s[9].v)))))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[6].v), _mm_add_epi64(_mm_mul_epu32(r8, s[7].v), _mm_add_epi64(_mm_mul_epu32(r7 , s[8].v), _mm_mul_epu32(r6, s[9].v))))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(r9_2, s[7].v), _mm_add_epi64(_mm_mul_epu32(r8, s[8].v), _mm_mul_epu32(r7_2, s[9].v)))); + out[7].v = _mm_add_epi64(out[7].v, _mm_add_epi64(_mm_mul_epu32(r9 , s[8].v), _mm_mul_epu32(r8, s[9].v))); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(r9_2, s[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* multiply a bignum */ +void +curve25519_mul(bignum25519 out, const bignum25519 r, const bignum25519 s) { + xmmi m01,m23,m45,m67,m89; + xmmi m0123,m4567; + xmmi s0123,s4567; + xmmi s01,s23,s45,s67,s89; + xmmi s12,s34,s56,s78,s9; + xmmi r0,r2,r4,r6,r8; + xmmi r1,r3,r5,r7,r9; + xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; + xmmi c1,c2,c3; + + s0123 = _mm_load_si128((xmmi*)s + 0); + s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); + s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); + s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); + s4567 = _mm_load_si128((xmmi*)s + 1); + s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); + s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); + s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); + s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); + s89 = _mm_load_si128((xmmi*)s + 2); + s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); + s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); + s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); + + r0 = _mm_load_si128((xmmi*)r + 0); + r1 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(1,1,1,1)); + r1 = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_top64bitmask.v)); + r2 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(2,2,2,2)); + r3 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(3,3,3,3)); + r3 = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_top64bitmask.v)); + r0 = _mm_shuffle_epi32(r0, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_load_si128((xmmi*)r + 1); + r5 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(1,1,1,1)); + r5 = _mm_add_epi64(r5, _mm_and_si128(r5, sse2_top64bitmask.v)); + r6 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(3,3,3,3)); + r7 = _mm_add_epi64(r7, _mm_and_si128(r7, sse2_top64bitmask.v)); + r4 = _mm_shuffle_epi32(r4, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_load_si128((xmmi*)r + 2); + r9 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,1,3,1)); + r9 = _mm_add_epi64(r9, _mm_and_si128(r9, sse2_top64bitmask.v)); + r8 = _mm_shuffle_epi32(r8, _MM_SHUFFLE(3,0,3,0)); + + m01 = _mm_mul_epu32(r1,s01); + m23 = _mm_mul_epu32(r1,s23); + m45 = _mm_mul_epu32(r1,s45); + m67 = _mm_mul_epu32(r1,s67); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r3,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r3,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r3,s45)); + m89 = _mm_mul_epu32(r1,s89); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r5,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r5,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r3,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r7,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r5,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r7,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r9,s01)); + + /* shift up */ + m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); + m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); + m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); + m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); + m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r0,s01)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r0,s23)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r0,s45)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r0,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r2,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r2,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r4,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r0,s89)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r4,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r2,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r2,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r6,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r4,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r6,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r8,s01)); + + r219 = _mm_mul_epu32(r2, packednineteen.v); + r419 = _mm_mul_epu32(r4, packednineteen.v); + r619 = _mm_mul_epu32(r6, packednineteen.v); + r819 = _mm_mul_epu32(r8, packednineteen.v); + r119 = _mm_shuffle_epi32(r1,_MM_SHUFFLE(0,0,2,2)); r119 = _mm_mul_epu32(r119, packednineteen.v); + r319 = _mm_shuffle_epi32(r3,_MM_SHUFFLE(0,0,2,2)); r319 = _mm_mul_epu32(r319, packednineteen.v); + r519 = _mm_shuffle_epi32(r5,_MM_SHUFFLE(0,0,2,2)); r519 = _mm_mul_epu32(r519, packednineteen.v); + r719 = _mm_shuffle_epi32(r7,_MM_SHUFFLE(0,0,2,2)); r719 = _mm_mul_epu32(r719, packednineteen.v); + r919 = _mm_shuffle_epi32(r9,_MM_SHUFFLE(0,0,2,2)); r919 = _mm_mul_epu32(r919, packednineteen.v); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r919,s12)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r919,s34)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r919,s56)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r919,s78)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r719,s34)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r719,s56)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r719,s78)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r719,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r519,s56)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r519,s78)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r519,s9)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r819,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r319,s78)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r319,s9)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r619,s89)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r919,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r819,s23)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r819,s45)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r819,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r619,s45)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r619,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r419,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r419,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r219,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r119,s9)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + m0123 = _mm_unpacklo_epi32(r0, r1); + m4567 = _mm_unpackhi_epi32(r0, r1); + m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); + m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); + m89 = _mm_unpackhi_epi32(r4, r5); + + _mm_store_si128((xmmi*)out + 0, m0123); + _mm_store_si128((xmmi*)out + 1, m4567); + _mm_store_si128((xmmi*)out + 2, m89); +} + +typedef struct bignum25519mulprecomp_t { + xmmi r0,r2,r4,r6,r8; + xmmi r1,r3,r5,r7,r9; + xmmi r119,r219,r319,r419,r519,r619,r719,r819,r919; +} bignum25519mulprecomp; + +/* precompute a constant to multiply by */ +inline void +curve25519_mul_precompute(bignum25519mulprecomp *pre, const bignum25519 r) { + pre->r0 = _mm_load_si128((xmmi*)r + 0); + pre->r1 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(1,1,1,1)); + pre->r1 = _mm_add_epi64(pre->r1, _mm_and_si128(pre->r1, sse2_top64bitmask.v)); + pre->r2 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(2,2,2,2)); + pre->r3 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(3,3,3,3)); + pre->r3 = _mm_add_epi64(pre->r3, _mm_and_si128(pre->r3, sse2_top64bitmask.v)); + pre->r0 = _mm_shuffle_epi32(pre->r0, _MM_SHUFFLE(0,0,0,0)); + pre->r4 = _mm_load_si128((xmmi*)r + 1); + pre->r5 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(1,1,1,1)); + pre->r5 = _mm_add_epi64(pre->r5, _mm_and_si128(pre->r5, sse2_top64bitmask.v)); + pre->r6 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(2,2,2,2)); + pre->r7 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(3,3,3,3)); + pre->r7 = _mm_add_epi64(pre->r7, _mm_and_si128(pre->r7, sse2_top64bitmask.v)); + pre->r4 = _mm_shuffle_epi32(pre->r4, _MM_SHUFFLE(0,0,0,0)); + pre->r8 = _mm_load_si128((xmmi*)r + 2); + pre->r9 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,1,3,1)); + pre->r9 = _mm_add_epi64(pre->r9, _mm_and_si128(pre->r9, sse2_top64bitmask.v)); + pre->r8 = _mm_shuffle_epi32(pre->r8, _MM_SHUFFLE(3,0,3,0)); + + pre->r219 = _mm_mul_epu32(pre->r2, packednineteen.v); + pre->r419 = _mm_mul_epu32(pre->r4, packednineteen.v); + pre->r619 = _mm_mul_epu32(pre->r6, packednineteen.v); + pre->r819 = _mm_mul_epu32(pre->r8, packednineteen.v); + pre->r119 = _mm_shuffle_epi32(pre->r1,_MM_SHUFFLE(0,0,2,2)); pre->r119 = _mm_mul_epu32(pre->r119, packednineteen.v); + pre->r319 = _mm_shuffle_epi32(pre->r3,_MM_SHUFFLE(0,0,2,2)); pre->r319 = _mm_mul_epu32(pre->r319, packednineteen.v); + pre->r519 = _mm_shuffle_epi32(pre->r5,_MM_SHUFFLE(0,0,2,2)); pre->r519 = _mm_mul_epu32(pre->r519, packednineteen.v); + pre->r719 = _mm_shuffle_epi32(pre->r7,_MM_SHUFFLE(0,0,2,2)); pre->r719 = _mm_mul_epu32(pre->r719, packednineteen.v); + pre->r919 = _mm_shuffle_epi32(pre->r9,_MM_SHUFFLE(0,0,2,2)); pre->r919 = _mm_mul_epu32(pre->r919, packednineteen.v); +} + + +/* multiply a bignum by a pre-computed constant */ +inline void +curve25519_mul_precomputed(bignum25519 out, const bignum25519 s, const bignum25519mulprecomp *r) { + xmmi m01,m23,m45,m67,m89; + xmmi m0123,m4567; + xmmi s0123,s4567; + xmmi s01,s23,s45,s67,s89; + xmmi s12,s34,s56,s78,s9; + xmmi r0,r1,r2,r3,r4,r5; + xmmi c1,c2,c3; + + s0123 = _mm_load_si128((xmmi*)s + 0); + s01 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,1,2,0)); + s12 = _mm_shuffle_epi32(s0123, _MM_SHUFFLE(2,2,1,1)); + s23 = _mm_shuffle_epi32(s0123,_MM_SHUFFLE(3,3,2,2)); + s4567 = _mm_load_si128((xmmi*)s + 1); + s34 = _mm_unpacklo_epi64(_mm_srli_si128(s0123,12),s4567); + s45 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,1,2,0)); + s56 = _mm_shuffle_epi32(s4567, _MM_SHUFFLE(2,2,1,1)); + s67 = _mm_shuffle_epi32(s4567,_MM_SHUFFLE(3,3,2,2)); + s89 = _mm_load_si128((xmmi*)s + 2); + s78 = _mm_unpacklo_epi64(_mm_srli_si128(s4567,12),s89); + s89 = _mm_shuffle_epi32(s89,_MM_SHUFFLE(3,1,2,0)); + s9 = _mm_shuffle_epi32(s89, _MM_SHUFFLE(3,3,2,2)); + + m01 = _mm_mul_epu32(r->r1,s01); + m23 = _mm_mul_epu32(r->r1,s23); + m45 = _mm_mul_epu32(r->r1,s45); + m67 = _mm_mul_epu32(r->r1,s67); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r3,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r3,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r3,s45)); + m89 = _mm_mul_epu32(r->r1,s89); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r5,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r5,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r3,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r7,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r5,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r7,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r9,s01)); + + /* shift up */ + m89 = _mm_unpackhi_epi64(m67,_mm_slli_si128(m89,8)); + m67 = _mm_unpackhi_epi64(m45,_mm_slli_si128(m67,8)); + m45 = _mm_unpackhi_epi64(m23,_mm_slli_si128(m45,8)); + m23 = _mm_unpackhi_epi64(m01,_mm_slli_si128(m23,8)); + m01 = _mm_unpackhi_epi64(_mm_setzero_si128(),_mm_slli_si128(m01,8)); + + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r0,s01)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r0,s23)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r0,s45)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r0,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r2,s01)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r2,s23)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r4,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r0,s89)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r4,s01)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r2,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r2,s67)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r6,s01)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r4,s45)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r6,s23)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r8,s01)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r919,s12)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r919,s34)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r919,s56)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r919,s78)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r719,s34)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r719,s56)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r719,s78)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r719,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r519,s56)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r519,s78)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r519,s9)); + m67 = _mm_add_epi64(m67,_mm_mul_epu32(r->r819,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r319,s78)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r319,s9)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r619,s89)); + m89 = _mm_add_epi64(m89,_mm_mul_epu32(r->r919,s9)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r819,s23)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r819,s45)); + m45 = _mm_add_epi64(m45,_mm_mul_epu32(r->r819,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r619,s45)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r619,s67)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r419,s67)); + m23 = _mm_add_epi64(m23,_mm_mul_epu32(r->r419,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r219,s89)); + m01 = _mm_add_epi64(m01,_mm_mul_epu32(r->r119,s9)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + m0123 = _mm_unpacklo_epi32(r0, r1); + m4567 = _mm_unpackhi_epi32(r0, r1); + m0123 = _mm_unpacklo_epi64(m0123, _mm_unpacklo_epi32(r2, r3)); + m4567 = _mm_unpacklo_epi64(m4567, _mm_unpackhi_epi32(r2, r3)); + m89 = _mm_unpackhi_epi32(r4, r5); + + _mm_store_si128((xmmi*)out + 0, m0123); + _mm_store_si128((xmmi*)out + 1, m4567); + _mm_store_si128((xmmi*)out + 2, m89); +} + +/* square a bignum 'count' times */ +#define curve25519_square(r,x) curve25519_square_times(r,x,1) + +void +curve25519_square_times(bignum25519 r, const bignum25519 in, int count) { + xmmi m01,m23,m45,m67,m89; + xmmi r0,r1,r2,r3,r4,r5,r6,r7,r8,r9; + xmmi r0a,r1a,r2a,r3a,r7a,r9a; + xmmi r0123,r4567; + xmmi r01,r23,r45,r67,r6x,r89,r8x; + xmmi r12,r34,r56,r78,r9x; + xmmi r5619; + xmmi c1,c2,c3; + + r0123 = _mm_load_si128((xmmi*)in + 0); + r01 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,1,2,0)); + r23 = _mm_shuffle_epi32(r0123,_MM_SHUFFLE(3,3,2,2)); + r4567 = _mm_load_si128((xmmi*)in + 1); + r45 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,1,2,0)); + r67 = _mm_shuffle_epi32(r4567,_MM_SHUFFLE(3,3,2,2)); + r89 = _mm_load_si128((xmmi*)in + 2); + r89 = _mm_shuffle_epi32(r89,_MM_SHUFFLE(3,1,2,0)); + + do { + r12 = _mm_unpackhi_epi64(r01, _mm_slli_si128(r23, 8)); + r0 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(0,0,0,0)); + r0 = _mm_add_epi64(r0, _mm_and_si128(r0, sse2_top64bitmask.v)); + r0a = _mm_shuffle_epi32(r0,_MM_SHUFFLE(3,2,1,2)); + r1 = _mm_shuffle_epi32(r01, _MM_SHUFFLE(2,2,2,2)); + r2 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(0,0,0,0)); + r2 = _mm_add_epi64(r2, _mm_and_si128(r2, sse2_top64bitmask.v)); + r2a = _mm_shuffle_epi32(r2,_MM_SHUFFLE(3,2,1,2)); + r3 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,2,2,2)); + r34 = _mm_unpackhi_epi64(r23, _mm_slli_si128(r45, 8)); + r4 = _mm_shuffle_epi32(r45, _MM_SHUFFLE(0,0,0,0)); + r4 = _mm_add_epi64(r4, _mm_and_si128(r4, sse2_top64bitmask.v)); + r56 = _mm_unpackhi_epi64(r45, _mm_slli_si128(r67, 8)); + r5619 = _mm_mul_epu32(r56, packednineteen.v); + r5 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(1,1,1,0)); + r6 = _mm_shuffle_epi32(r5619, _MM_SHUFFLE(3,2,3,2)); + r78 = _mm_unpackhi_epi64(r67, _mm_slli_si128(r89, 8)); + r6x = _mm_unpacklo_epi64(r67, _mm_setzero_si128()); + r7 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,2,2,2)); + r7 = _mm_mul_epu32(r7, packed3819.v); + r7a = _mm_shuffle_epi32(r7, _MM_SHUFFLE(3,3,3,2)); + r8x = _mm_unpacklo_epi64(r89, _mm_setzero_si128()); + r8 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(0,0,0,0)); + r8 = _mm_mul_epu32(r8, packednineteen.v); + r9 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(2,2,2,2)); + r9x = _mm_slli_epi32(_mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,3,2)), 1); + r9 = _mm_mul_epu32(r9, packed3819.v); + r9a = _mm_shuffle_epi32(r9, _MM_SHUFFLE(2,2,2,2)); + + m01 = _mm_mul_epu32(r01, r0); + m23 = _mm_mul_epu32(r23, r0a); + m45 = _mm_mul_epu32(r45, r0a); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r23, r2)); + r23 = _mm_slli_epi32(r23, 1); + m67 = _mm_mul_epu32(r67, r0a); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r45, r2a)); + m89 = _mm_mul_epu32(r89, r0a); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r67, r2a)); + r67 = _mm_slli_epi32(r67, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r45, r4)); + r45 = _mm_slli_epi32(r45, 1); + + r1 = _mm_slli_epi32(r1, 1); + r3 = _mm_slli_epi32(r3, 1); + r1a = _mm_add_epi64(r1, _mm_and_si128(r1, sse2_bot64bitmask.v)); + r3a = _mm_add_epi64(r3, _mm_and_si128(r3, sse2_bot64bitmask.v)); + + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r12, r1)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r34, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r56, r1a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r34, r3)); + r34 = _mm_slli_epi32(r34, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r78, r1a)); + r78 = _mm_slli_epi32(r78, 1); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r56, r3a)); + r56 = _mm_slli_epi32(r56, 1); + + m01 = _mm_add_epi64(m01, _mm_mul_epu32(_mm_slli_epi32(r12, 1), r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r34, r7)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r34, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r56, r5)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r56, r7)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r56, r9)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r23, r8)); + m01 = _mm_add_epi64(m01, _mm_mul_epu32(r45, r6)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r45, r8)); + m23 = _mm_add_epi64(m23, _mm_mul_epu32(r6x, r6)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r78, r7a)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r78, r9)); + m45 = _mm_add_epi64(m45, _mm_mul_epu32(r67, r8)); + m67 = _mm_add_epi64(m67, _mm_mul_epu32(r8x, r8)); + m89 = _mm_add_epi64(m89, _mm_mul_epu32(r9x, r9a)); + + r0 = _mm_unpacklo_epi64(m01, m45); + r1 = _mm_unpackhi_epi64(m01, m45); + r2 = _mm_unpacklo_epi64(m23, m67); + r3 = _mm_unpackhi_epi64(m23, m67); + r4 = _mm_unpacklo_epi64(m89, m89); + r5 = _mm_unpackhi_epi64(m89, m89); + + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + c1 = _mm_srli_epi64(r1, 25); c2 = _mm_srli_epi64(r3, 25); r1 = _mm_and_si128(r1, packedmask25.v); r3 = _mm_and_si128(r3, packedmask25.v); r2 = _mm_add_epi64(r2, c1); r4 = _mm_add_epi64(r4, c2); c3 = _mm_slli_si128(c2, 8); + c1 = _mm_srli_epi64(r4, 26); r4 = _mm_and_si128(r4, packedmask26.v); r5 = _mm_add_epi64(r5, c1); + c1 = _mm_srli_epi64(r5, 25); r5 = _mm_and_si128(r5, packedmask25.v); r0 = _mm_add_epi64(r0, _mm_unpackhi_epi64(_mm_mul_epu32(c1, packednineteen.v), c3)); + c1 = _mm_srli_epi64(r0, 26); c2 = _mm_srli_epi64(r2, 26); r0 = _mm_and_si128(r0, packedmask26.v); r2 = _mm_and_si128(r2, packedmask26.v); r1 = _mm_add_epi64(r1, c1); r3 = _mm_add_epi64(r3, c2); + + r01 = _mm_unpacklo_epi64(r0, r1); + r45 = _mm_unpackhi_epi64(r0, r1); + r23 = _mm_unpacklo_epi64(r2, r3); + r67 = _mm_unpackhi_epi64(r2, r3); + r89 = _mm_unpackhi_epi64(r4, r5); + } while (--count); + + r0123 = _mm_shuffle_epi32(r23, _MM_SHUFFLE(2,0,3,3)); + r4567 = _mm_shuffle_epi32(r67, _MM_SHUFFLE(2,0,3,3)); + r0123 = _mm_or_si128(r0123, _mm_shuffle_epi32(r01, _MM_SHUFFLE(3,3,2,0))); + r4567 = _mm_or_si128(r4567, _mm_shuffle_epi32(r45, _MM_SHUFFLE(3,3,2,0))); + r89 = _mm_shuffle_epi32(r89, _MM_SHUFFLE(3,3,2,0)); + + _mm_store_si128((xmmi*)r + 0, r0123); + _mm_store_si128((xmmi*)r + 1, r4567); + _mm_store_si128((xmmi*)r + 2, r89); +} + +/* square two packed bignums */ +inline void +curve25519_square_packed64(packedelem64 *out, const packedelem64 *r) { + xmmi r0,r1,r2,r3; + xmmi r1_2,r3_2,r4_2,r5_2,r6_2,r7_2; + xmmi d5,d6,d7,d8,d9; + xmmi c1,c2; + + r0 = r[0].v; + r1 = r[1].v; + r2 = r[2].v; + r3 = r[3].v; + + out[0].v = _mm_mul_epu32(r0, r0); + r0 = _mm_slli_epi32(r0, 1); + out[1].v = _mm_mul_epu32(r0, r1); + r1_2 = _mm_slli_epi32(r1, 1); + out[2].v = _mm_add_epi64(_mm_mul_epu32(r0, r2 ), _mm_mul_epu32(r1, r1_2)); + r1 = r1_2; + out[3].v = _mm_add_epi64(_mm_mul_epu32(r0, r3 ), _mm_mul_epu32(r1, r2 )); + r3_2 = _mm_slli_epi32(r3, 1); + out[4].v = _mm_add_epi64(_mm_mul_epu32(r0, r[4].v), _mm_add_epi64(_mm_mul_epu32(r1, r3_2 ), _mm_mul_epu32(r2, r2))); + r2 = _mm_slli_epi32(r2, 1); + out[5].v = _mm_add_epi64(_mm_mul_epu32(r0, r[5].v), _mm_add_epi64(_mm_mul_epu32(r1, r[4].v), _mm_mul_epu32(r2, r3))); + r5_2 = _mm_slli_epi32(r[5].v, 1); + out[6].v = _mm_add_epi64(_mm_mul_epu32(r0, r[6].v), _mm_add_epi64(_mm_mul_epu32(r1, r5_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[4].v), _mm_mul_epu32(r3, r3_2 )))); + r3 = r3_2; + out[7].v = _mm_add_epi64(_mm_mul_epu32(r0, r[7].v), _mm_add_epi64(_mm_mul_epu32(r1, r[6].v), _mm_add_epi64(_mm_mul_epu32(r2, r[5].v), _mm_mul_epu32(r3, r[4].v)))); + r7_2 = _mm_slli_epi32(r[7].v, 1); + out[8].v = _mm_add_epi64(_mm_mul_epu32(r0, r[8].v), _mm_add_epi64(_mm_mul_epu32(r1, r7_2 ), _mm_add_epi64(_mm_mul_epu32(r2, r[6].v), _mm_add_epi64(_mm_mul_epu32(r3, r5_2 ), _mm_mul_epu32(r[4].v, r[4].v))))); + out[9].v = _mm_add_epi64(_mm_mul_epu32(r0, r[9].v), _mm_add_epi64(_mm_mul_epu32(r1, r[8].v), _mm_add_epi64(_mm_mul_epu32(r2, r[7].v), _mm_add_epi64(_mm_mul_epu32(r3, r[6].v), _mm_mul_epu32(r[4].v, r5_2 ))))); + + d5 = _mm_mul_epu32(r[5].v, packedthirtyeight.v); + d6 = _mm_mul_epu32(r[6].v, packednineteen.v); + d7 = _mm_mul_epu32(r[7].v, packedthirtyeight.v); + d8 = _mm_mul_epu32(r[8].v, packednineteen.v); + d9 = _mm_mul_epu32(r[9].v, packedthirtyeight.v); + + r4_2 = _mm_slli_epi32(r[4].v, 1); + r6_2 = _mm_slli_epi32(r[6].v, 1); + out[0].v = _mm_add_epi64(out[0].v, _mm_add_epi64(_mm_mul_epu32(d9, r1 ), _mm_add_epi64(_mm_mul_epu32(d8, r2 ), _mm_add_epi64(_mm_mul_epu32(d7, r3 ), _mm_add_epi64(_mm_mul_epu32(d6, r4_2), _mm_mul_epu32(d5, r[5].v)))))); + out[1].v = _mm_add_epi64(out[1].v, _mm_add_epi64(_mm_mul_epu32(d9, _mm_srli_epi32(r2, 1)), _mm_add_epi64(_mm_mul_epu32(d8, r3 ), _mm_add_epi64(_mm_mul_epu32(d7, r[4].v), _mm_mul_epu32(d6, r5_2 ))))); + out[2].v = _mm_add_epi64(out[2].v, _mm_add_epi64(_mm_mul_epu32(d9, r3 ), _mm_add_epi64(_mm_mul_epu32(d8, r4_2), _mm_add_epi64(_mm_mul_epu32(d7, r5_2 ), _mm_mul_epu32(d6, r[6].v))))); + out[3].v = _mm_add_epi64(out[3].v, _mm_add_epi64(_mm_mul_epu32(d9, r[4].v ), _mm_add_epi64(_mm_mul_epu32(d8, r5_2), _mm_mul_epu32(d7, r[6].v)))); + out[4].v = _mm_add_epi64(out[4].v, _mm_add_epi64(_mm_mul_epu32(d9, r5_2 ), _mm_add_epi64(_mm_mul_epu32(d8, r6_2), _mm_mul_epu32(d7, r[7].v)))); + out[5].v = _mm_add_epi64(out[5].v, _mm_add_epi64(_mm_mul_epu32(d9, r[6].v ), _mm_mul_epu32(d8, r7_2 ))); + out[6].v = _mm_add_epi64(out[6].v, _mm_add_epi64(_mm_mul_epu32(d9, r7_2 ), _mm_mul_epu32(d8, r[8].v))); + out[7].v = _mm_add_epi64(out[7].v, _mm_mul_epu32(d9, r[8].v)); + out[8].v = _mm_add_epi64(out[8].v, _mm_mul_epu32(d9, r[9].v)); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* make [nqx+nqz,nqpqx+nqpqz], [nqpqx-nqpqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ +inline void +curve25519_make_nqpq(packedelem64 *primex, packedelem64 *primez, const packedelem32 *pqx, const packedelem32 *pqz) { + primex[0].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(1,1,0,0)); + primex[1].v = _mm_shuffle_epi32(pqx[0].v, _MM_SHUFFLE(3,3,2,2)); + primex[2].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(1,1,0,0)); + primex[3].v = _mm_shuffle_epi32(pqx[1].v, _MM_SHUFFLE(3,3,2,2)); + primex[4].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(1,1,0,0)); + primex[5].v = _mm_shuffle_epi32(pqx[2].v, _MM_SHUFFLE(3,3,2,2)); + primex[6].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(1,1,0,0)); + primex[7].v = _mm_shuffle_epi32(pqx[3].v, _MM_SHUFFLE(3,3,2,2)); + primex[8].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(1,1,0,0)); + primex[9].v = _mm_shuffle_epi32(pqx[4].v, _MM_SHUFFLE(3,3,2,2)); + primez[0].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(0,0,1,1)); + primez[1].v = _mm_shuffle_epi32(pqz[0].v, _MM_SHUFFLE(2,2,3,3)); + primez[2].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(0,0,1,1)); + primez[3].v = _mm_shuffle_epi32(pqz[1].v, _MM_SHUFFLE(2,2,3,3)); + primez[4].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(0,0,1,1)); + primez[5].v = _mm_shuffle_epi32(pqz[2].v, _MM_SHUFFLE(2,2,3,3)); + primez[6].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(0,0,1,1)); + primez[7].v = _mm_shuffle_epi32(pqz[3].v, _MM_SHUFFLE(2,2,3,3)); + primez[8].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(0,0,1,1)); + primez[9].v = _mm_shuffle_epi32(pqz[4].v, _MM_SHUFFLE(2,2,3,3)); +} + +/* make [nqx+nqz,nqx-nqz] from [nqx+nqz,nqpqx+nqpqz], [nqx-nqz,nqpqx-nqpqz] */ +inline void +curve25519_make_nq(packedelem64 *nq, const packedelem32 *pqx, const packedelem32 *pqz) { + nq[0].v = _mm_unpacklo_epi64(pqx[0].v, pqz[0].v); + nq[1].v = _mm_unpackhi_epi64(pqx[0].v, pqz[0].v); + nq[2].v = _mm_unpacklo_epi64(pqx[1].v, pqz[1].v); + nq[3].v = _mm_unpackhi_epi64(pqx[1].v, pqz[1].v); + nq[4].v = _mm_unpacklo_epi64(pqx[2].v, pqz[2].v); + nq[5].v = _mm_unpackhi_epi64(pqx[2].v, pqz[2].v); + nq[6].v = _mm_unpacklo_epi64(pqx[3].v, pqz[3].v); + nq[7].v = _mm_unpackhi_epi64(pqx[3].v, pqz[3].v); + nq[8].v = _mm_unpacklo_epi64(pqx[4].v, pqz[4].v); + nq[9].v = _mm_unpackhi_epi64(pqx[4].v, pqz[4].v); +} + +/* compute [nqx+nqz,nqx-nqz] from nqx, nqz */ +inline void +curve25519_compute_nq(packedelem64 *nq, const bignum25519 nqx, const bignum25519 nqz) { + xmmi x0,x1,x2; + xmmi z0,z1,z2; + xmmi a0,a1,a2; + xmmi s0,s1,s2; + xmmi r0,r1; + xmmi c1,c2; + x0 = _mm_load_si128((xmmi*)nqx + 0); + x1 = _mm_load_si128((xmmi*)nqx + 1); + x2 = _mm_load_si128((xmmi*)nqx + 2); + z0 = _mm_load_si128((xmmi*)nqz + 0); + z1 = _mm_load_si128((xmmi*)nqz + 1); + z2 = _mm_load_si128((xmmi*)nqz + 2); + a0 = _mm_add_epi32(x0, z0); + a1 = _mm_add_epi32(x1, z1); + a2 = _mm_add_epi32(x2, z2); + s0 = _mm_add_epi32(x0, packed2p0.v); + s1 = _mm_add_epi32(x1, packed2p1.v); + s2 = _mm_add_epi32(x2, packed2p2.v); + s0 = _mm_sub_epi32(s0, z0); + s1 = _mm_sub_epi32(s1, z1); + s2 = _mm_sub_epi32(s2, z2); + r0 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(2,2,0,0)), sse2_bot32bitmask.v); + r1 = _mm_and_si128(_mm_shuffle_epi32(s0, _MM_SHUFFLE(3,3,1,1)), sse2_bot32bitmask.v); + c1 = _mm_srli_epi32(r0, 26); + c2 = _mm_srli_epi32(r1, 25); + r0 = _mm_and_si128(r0, packedmask26.v); + r1 = _mm_and_si128(r1, packedmask25.v); + r0 = _mm_add_epi32(r0, _mm_slli_si128(c2, 8)); + r1 = _mm_add_epi32(r1, c1); + s0 = _mm_unpacklo_epi64(_mm_unpacklo_epi32(r0, r1), _mm_unpackhi_epi32(r0, r1)); + s1 = _mm_add_epi32(s1, _mm_srli_si128(c2, 8)); + nq[0].v = _mm_unpacklo_epi64(a0, s0); + nq[2].v = _mm_unpackhi_epi64(a0, s0); + nq[4].v = _mm_unpacklo_epi64(a1, s1); + nq[6].v = _mm_unpackhi_epi64(a1, s1); + nq[8].v = _mm_unpacklo_epi64(a2, s2); + nq[1].v = _mm_shuffle_epi32(nq[0].v, _MM_SHUFFLE(3,3,1,1)); + nq[3].v = _mm_shuffle_epi32(nq[2].v, _MM_SHUFFLE(3,3,1,1)); + nq[5].v = _mm_shuffle_epi32(nq[4].v, _MM_SHUFFLE(3,3,1,1)); + nq[7].v = _mm_shuffle_epi32(nq[6].v, _MM_SHUFFLE(3,3,1,1)); + nq[9].v = _mm_shuffle_epi32(nq[8].v, _MM_SHUFFLE(3,3,1,1)); +} + + +/* compute [x+z,x-z] from [x,z] */ +inline void +curve25519_addsub_packed64(packedelem64 *r) { + packed32bignum25519 x,z,add,sub; + + x[0].v = _mm_unpacklo_epi64(r[0].v, r[1].v); + z[0].v = _mm_unpackhi_epi64(r[0].v, r[1].v); + x[1].v = _mm_unpacklo_epi64(r[2].v, r[3].v); + z[1].v = _mm_unpackhi_epi64(r[2].v, r[3].v); + x[2].v = _mm_unpacklo_epi64(r[4].v, r[5].v); + z[2].v = _mm_unpackhi_epi64(r[4].v, r[5].v); + x[3].v = _mm_unpacklo_epi64(r[6].v, r[7].v); + z[3].v = _mm_unpackhi_epi64(r[6].v, r[7].v); + x[4].v = _mm_unpacklo_epi64(r[8].v, r[9].v); + z[4].v = _mm_unpackhi_epi64(r[8].v, r[9].v); + + curve25519_add_packed32(add, x, z); + curve25519_sub_packed32(sub, x, z); + + r[0].v = _mm_unpacklo_epi64(add[0].v, sub[0].v); + r[1].v = _mm_unpackhi_epi64(add[0].v, sub[0].v); + r[2].v = _mm_unpacklo_epi64(add[1].v, sub[1].v); + r[3].v = _mm_unpackhi_epi64(add[1].v, sub[1].v); + r[4].v = _mm_unpacklo_epi64(add[2].v, sub[2].v); + r[5].v = _mm_unpackhi_epi64(add[2].v, sub[2].v); + r[6].v = _mm_unpacklo_epi64(add[3].v, sub[3].v); + r[7].v = _mm_unpackhi_epi64(add[3].v, sub[3].v); + r[8].v = _mm_unpacklo_epi64(add[4].v, sub[4].v); + r[9].v = _mm_unpackhi_epi64(add[4].v, sub[4].v); +} + +/* compute [x,z] * [121666,121665] */ +inline void +curve25519_121665_packed64(packedelem64 *out, const packedelem64 *in) { + xmmi c1,c2; + + out[0].v = _mm_mul_epu32(in[0].v, packed121666121665.v); + out[1].v = _mm_mul_epu32(in[1].v, packed121666121665.v); + out[2].v = _mm_mul_epu32(in[2].v, packed121666121665.v); + out[3].v = _mm_mul_epu32(in[3].v, packed121666121665.v); + out[4].v = _mm_mul_epu32(in[4].v, packed121666121665.v); + out[5].v = _mm_mul_epu32(in[5].v, packed121666121665.v); + out[6].v = _mm_mul_epu32(in[6].v, packed121666121665.v); + out[7].v = _mm_mul_epu32(in[7].v, packed121666121665.v); + out[8].v = _mm_mul_epu32(in[8].v, packed121666121665.v); + out[9].v = _mm_mul_epu32(in[9].v, packed121666121665.v); + + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); + c1 = _mm_srli_epi64(out[1].v, 25); c2 = _mm_srli_epi64(out[5].v, 25); out[1].v = _mm_and_si128(out[1].v, packedmask25.v); out[5].v = _mm_and_si128(out[5].v, packedmask25.v); out[2].v = _mm_add_epi64(out[2].v, c1); out[6].v = _mm_add_epi64(out[6].v, c2); + c1 = _mm_srli_epi64(out[2].v, 26); c2 = _mm_srli_epi64(out[6].v, 26); out[2].v = _mm_and_si128(out[2].v, packedmask26.v); out[6].v = _mm_and_si128(out[6].v, packedmask26.v); out[3].v = _mm_add_epi64(out[3].v, c1); out[7].v = _mm_add_epi64(out[7].v, c2); + c1 = _mm_srli_epi64(out[3].v, 25); c2 = _mm_srli_epi64(out[7].v, 25); out[3].v = _mm_and_si128(out[3].v, packedmask25.v); out[7].v = _mm_and_si128(out[7].v, packedmask25.v); out[4].v = _mm_add_epi64(out[4].v, c1); out[8].v = _mm_add_epi64(out[8].v, c2); + c2 = _mm_srli_epi64(out[8].v, 26); out[8].v = _mm_and_si128(out[8].v, packedmask26.v); out[9].v = _mm_add_epi64(out[9].v, c2); + c2 = _mm_srli_epi64(out[9].v, 25); out[9].v = _mm_and_si128(out[9].v, packedmask25.v); out[0].v = _mm_add_epi64(out[0].v, _mm_mul_epu32(c2, packednineteen.v)); + c1 = _mm_srli_epi64(out[0].v, 26); c2 = _mm_srli_epi64(out[4].v, 26); out[0].v = _mm_and_si128(out[0].v, packedmask26.v); out[4].v = _mm_and_si128(out[4].v, packedmask26.v); out[1].v = _mm_add_epi64(out[1].v, c1); out[5].v = _mm_add_epi64(out[5].v, c2); +} + +/* compute [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ +inline void +curve25519_final_nq(packedelem64 *nq, const packedelem64 *sq, const packedelem64 *sq121665) { + packed32bignum25519 x, z, sub; + packed64bignum25519 t, nqa, nqb; + + x[0].v = _mm_or_si128(_mm_unpacklo_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[0].v, sq121665[1].v), 4)); + z[0].v = _mm_or_si128(_mm_unpackhi_epi64(sq[0].v, sq[1].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[0].v, sq121665[1].v), 4)); + x[1].v = _mm_or_si128(_mm_unpacklo_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[2].v, sq121665[3].v), 4)); + z[1].v = _mm_or_si128(_mm_unpackhi_epi64(sq[2].v, sq[3].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[2].v, sq121665[3].v), 4)); + x[2].v = _mm_or_si128(_mm_unpacklo_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[4].v, sq121665[5].v), 4)); + z[2].v = _mm_or_si128(_mm_unpackhi_epi64(sq[4].v, sq[5].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[4].v, sq121665[5].v), 4)); + x[3].v = _mm_or_si128(_mm_unpacklo_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[6].v, sq121665[7].v), 4)); + z[3].v = _mm_or_si128(_mm_unpackhi_epi64(sq[6].v, sq[7].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[6].v, sq121665[7].v), 4)); + x[4].v = _mm_or_si128(_mm_unpacklo_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpacklo_epi64(sq121665[8].v, sq121665[9].v), 4)); + z[4].v = _mm_or_si128(_mm_unpackhi_epi64(sq[8].v, sq[9].v), _mm_slli_si128(_mm_unpackhi_epi64(sq121665[8].v, sq121665[9].v), 4)); + + curve25519_sub_packed32(sub, x, z); + + t[0].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(1,1,0,0)); + t[1].v = _mm_shuffle_epi32(sub[0].v, _MM_SHUFFLE(3,3,2,2)); + t[2].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(1,1,0,0)); + t[3].v = _mm_shuffle_epi32(sub[1].v, _MM_SHUFFLE(3,3,2,2)); + t[4].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(1,1,0,0)); + t[5].v = _mm_shuffle_epi32(sub[2].v, _MM_SHUFFLE(3,3,2,2)); + t[6].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(1,1,0,0)); + t[7].v = _mm_shuffle_epi32(sub[3].v, _MM_SHUFFLE(3,3,2,2)); + t[8].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(1,1,0,0)); + t[9].v = _mm_shuffle_epi32(sub[4].v, _MM_SHUFFLE(3,3,2,2)); + + nqa[0].v = _mm_unpacklo_epi64(sq[0].v, t[0].v); + nqb[0].v = _mm_unpackhi_epi64(sq[0].v, t[0].v); + nqa[1].v = _mm_unpacklo_epi64(sq[1].v, t[1].v); + nqb[1].v = _mm_unpackhi_epi64(sq[1].v, t[1].v); + nqa[2].v = _mm_unpacklo_epi64(sq[2].v, t[2].v); + nqb[2].v = _mm_unpackhi_epi64(sq[2].v, t[2].v); + nqa[3].v = _mm_unpacklo_epi64(sq[3].v, t[3].v); + nqb[3].v = _mm_unpackhi_epi64(sq[3].v, t[3].v); + nqa[4].v = _mm_unpacklo_epi64(sq[4].v, t[4].v); + nqb[4].v = _mm_unpackhi_epi64(sq[4].v, t[4].v); + nqa[5].v = _mm_unpacklo_epi64(sq[5].v, t[5].v); + nqb[5].v = _mm_unpackhi_epi64(sq[5].v, t[5].v); + nqa[6].v = _mm_unpacklo_epi64(sq[6].v, t[6].v); + nqb[6].v = _mm_unpackhi_epi64(sq[6].v, t[6].v); + nqa[7].v = _mm_unpacklo_epi64(sq[7].v, t[7].v); + nqb[7].v = _mm_unpackhi_epi64(sq[7].v, t[7].v); + nqa[8].v = _mm_unpacklo_epi64(sq[8].v, t[8].v); + nqb[8].v = _mm_unpackhi_epi64(sq[8].v, t[8].v); + nqa[9].v = _mm_unpacklo_epi64(sq[9].v, t[9].v); + nqb[9].v = _mm_unpackhi_epi64(sq[9].v, t[9].v); + + curve25519_mul_packed64(nq, nqa, nqb); +} + +/* + * In: b = 2^5 - 2^0 + * Out: b = 2^250 - 2^0 + */ +void +curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) { + ALIGN(16) bignum25519 t0,c; + + /* 2^5 - 2^0 */ /* b */ + /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5); + /* 2^10 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10); + /* 2^20 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20); + /* 2^40 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10); + /* 2^50 - 2^0 */ curve25519_mul(b, t0, b); + /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50); + /* 2^100 - 2^0 */ curve25519_mul(c, t0, b); + /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100); + /* 2^200 - 2^0 */ curve25519_mul(t0, t0, c); + /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50); + /* 2^250 - 2^0 */ curve25519_mul(b, t0, b); +} + +/* + * z^(p - 2) = z(2^255 - 21) + */ +void +curve25519_recip(bignum25519 out, const bignum25519 z) { + ALIGN(16) bignum25519 a, t0, b; + + /* 2 */ curve25519_square(a, z); /* a = 2 */ + /* 8 */ curve25519_square_times(t0, a, 2); + /* 9 */ curve25519_mul(b, t0, z); /* b = 9 */ + /* 11 */ curve25519_mul(a, b, a); /* a = 11 */ + /* 22 */ curve25519_square(t0, a); + /* 2^5 - 2^0 = 31 */ curve25519_mul(b, t0, b); + /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b); + /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5); + /* 2^255 - 21 */ curve25519_mul(out, b, a); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +int curve25519_mult_SSE2(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]) +{ + FixedSizeSecBlock e; + for (size_t i = 0;i < 32;++i) + e[i] = secretKey[i]; + e[0] &= 0xf8; e[31] &= 0x7f; e[31] |= 0x40; + + ALIGN(16) bignum25519 nqx = {1}, nqpqz = {1}, nqz = {0}, nqpqx, zmone; + packed32bignum25519 qx, qz, pqz, pqx; + packed64bignum25519 nq, sq, sqscalar, prime, primex, primez, nqpq; + bignum25519mulprecomp preq; + size_t bit=0; + + curve25519_expand(nqpqx, othersKey); + curve25519_mul_precompute(&preq, nqpqx); + + /* do bits 254..3 */ + for (size_t i = 254, lastbit=0; i >= 3; i--) { + bit = (e[i/8] >> (i & 7)) & 1; + curve25519_swap_conditional(nqx, nqpqx, (word32)(bit ^ lastbit)); + curve25519_swap_conditional(nqz, nqpqz, (word32)(bit ^ lastbit)); + lastbit = bit; + + curve25519_tangle32(qx, nqx, nqpqx); /* qx = [nqx,nqpqx] */ + curve25519_tangle32(qz, nqz, nqpqz); /* qz = [nqz,nqpqz] */ + + curve25519_add_packed32(pqx, qx, qz); /* pqx = [nqx+nqz,nqpqx+nqpqz] */ + curve25519_sub_packed32(pqz, qx, qz); /* pqz = [nqx-nqz,nqpqx-nqpqz] */ + + curve25519_make_nqpq(primex, primez, pqx, pqz); /* primex = [nqx+nqz,nqpqx+nqpqz], primez = [nqpqx-nqpqz,nqx-nqz] */ + curve25519_mul_packed64(prime, primex, primez); /* prime = [nqx+nqz,nqpqx+nqpqz] * [nqpqx-nqpqz,nqx-nqz] */ + curve25519_addsub_packed64(prime); /* prime = [prime.x+prime.z,prime.x-prime.z] */ + curve25519_square_packed64(nqpq, prime); /* nqpq = prime^2 */ + curve25519_untangle64(nqpqx, nqpqz, nqpq); + curve25519_mul_precomputed(nqpqz, nqpqz, &preq); /* nqpqz = nqpqz * q */ + + /* (((sq.x-sq.z)*121665)+sq.x) * (sq.x-sq.z) is equivalent to (sq.x*121666-sq.z*121665) * (sq.x-sq.z) */ + curve25519_make_nq(nq, pqx, pqz); /* nq = [nqx+nqz,nqx-nqz] */ + curve25519_square_packed64(sq, nq); /* sq = nq^2 */ + curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ + curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ + curve25519_untangle64(nqx, nqz, nq); + }; + + /* it's possible to get rid of this swap with the swap in the above loop + at the bottom instead of the top, but compilers seem to optimize better this way */ + curve25519_swap_conditional(nqx, nqpqx, (word32)bit); + curve25519_swap_conditional(nqz, nqpqz, (word32)bit); + + /* do bits 2..0 */ + for (size_t i = 0; i < 3; i++) { + curve25519_compute_nq(nq, nqx, nqz); + curve25519_square_packed64(sq, nq); /* sq = nq^2 */ + curve25519_121665_packed64(sqscalar, sq); /* sqscalar = sq * [121666,121665] */ + curve25519_final_nq(nq, sq, sqscalar); /* nq = [sq.x,sqscalar.x-sqscalar.z] * [sq.z,sq.x-sq.z] */ + curve25519_untangle64(nqx, nqz, nq); + } + + curve25519_recip(zmone, nqz); + curve25519_mul(nqz, nqx, zmone); + curve25519_contract(sharedKey, nqz); + + return 0; +} + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_CURVE25519_SSE2 diff --git a/extension/third_party/cryptopp/donna_sse.h b/extension/third_party/cryptopp/donna_sse.h new file mode 100644 index 00000000..298a9141 --- /dev/null +++ b/extension/third_party/cryptopp/donna_sse.h @@ -0,0 +1,86 @@ +// donna_sse.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_SSE_H +#define CRYPTOPP_DONNA_SSE_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(ArchSSE) + +using CryptoPP::byte; +using CryptoPP::word32; + +typedef __m128i xmmi; +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) + +typedef union packedelem8_t { + byte u[16]; + xmmi v; +} packedelem8; + +typedef union packedelem32_t { + word32 u[4]; + xmmi v; +} packedelem32; + +typedef union packedelem64_t { + word64 u[2]; + xmmi v; +} packedelem64; + +/* 10 elements + an extra 2 to fit in 3 xmm registers */ +typedef word32 bignum25519[12]; +typedef packedelem32 packed32bignum25519[5]; +typedef packedelem64 packed64bignum25519[10]; + +const word32 reduce_mask_26 = (1 << 26) - 1; +const word32 reduce_mask_25 = (1 << 25) - 1; + +const packedelem32 sse2_bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; +const packedelem32 sse2_top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; +const packedelem32 sse2_top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; +const packedelem32 sse2_bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; + +/* reduction masks */ +const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; +const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; +const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; +const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; +const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; + +/* multipliers */ +const packedelem64 packednineteen = {{19, 19}}; +const packedelem64 packednineteenone = {{19, 1}}; +const packedelem64 packedthirtyeight = {{38, 38}}; +const packedelem64 packed3819 = {{19*2,19}}; +const packedelem64 packed9638 = {{19*4,19*2}}; + +/* 121666,121665 */ +const packedelem64 packed121666121665 = {{121666, 121665}}; + +/* 2*(2^255 - 19) = 0 mod p */ +const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; +const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; +const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; + +const packedelem32 packed32zeromodp0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; +const packedelem32 packed32zeromodp1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; + +NAMESPACE_END // ArchSSE +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_SSE_H diff --git a/extension/third_party/cryptopp/drbg.h b/extension/third_party/cryptopp/drbg.h new file mode 100644 index 00000000..306c735b --- /dev/null +++ b/extension/third_party/cryptopp/drbg.h @@ -0,0 +1,718 @@ +// drbg.h - written and placed in public domain by Jeffrey Walton. + +/// \file drbg.h +/// \brief Classes for NIST DRBGs from SP 800-90A +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NIST_DRBG_H +#define CRYPTOPP_NIST_DRBG_H + +#include "cryptlib.h" +#include "secblock.h" +#include "hmac.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Interface for NIST DRBGs from SP 800-90A +/// \details NIST_DRBG is the base class interface for NIST DRBGs from SP 800-90A Rev 1 (June 2015) +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +class NIST_DRBG : public RandomNumberGenerator +{ +public: + /// \brief Exception thrown when a NIST DRBG encounters an error + class Err : public Exception + { + public: + explicit Err(const std::string &c, const std::string &m) + : Exception(OTHER_ERROR, c + ": " + m) {} + }; + +public: + virtual ~NIST_DRBG() {} + + /// \brief Determines if a generator can accept additional entropy + /// \return true + /// \details All NIST_DRBG return true + virtual bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details NIST instantiation and reseed requirements demand the generator is constructed + /// with at least MINIMUM_ENTROPY entropy. The byte array for input must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *input, size_t length)=0; + + /// \brief Update RNG state with additional unpredictable values + /// \param entropy the entropy to add to the generator + /// \param entropyLength the size of the input buffer + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST + /// instantiation and reseed requirements demand the generator is constructed with at least + /// MINIMUM_ENTROPY entropy. The byte array for entropy must meet + /// NIST SP 800-90B or + ///! SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throw NIST_DRBG::Err if a reseed is required + /// \throw NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + virtual void GenerateBlock(byte *output, size_t size)=0; + + /// \brief Generate random array of bytes + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throw NIST_DRBG::Err if a reseed is required + /// \throw NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + /// \details GenerateBlock() is an overload provided to match NIST requirements. The byte + /// array for additional input is optional. If present the additional randomness + /// is mixed before generating the output bytes. + virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0; + + /// \brief Provides the security strength + /// \return The security strength of the generator, in bytes + /// \details The equivalent class constant is SECURITY_STRENGTH + virtual unsigned int SecurityStrength() const=0; + + /// \brief Provides the seed length + /// \return The seed size of the generator, in bytes + /// \details The equivalent class constant is SEED_LENGTH. The size is + /// used to maintain internal state of V and C. + virtual unsigned int SeedLength() const=0; + + /// \brief Provides the minimum entropy size + /// \return The minimum entropy size required by the generator, in bytes + /// \details The equivalent class constant is MINIMUM_ENTROPY. All NIST DRBGs must + /// be instaniated with at least MINIMUM_ENTROPY bytes of entropy. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual unsigned int MinEntropyLength() const=0; + + /// \brief Provides the maximum entropy size + /// \return The maximum entropy size that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_ENTROPY. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. MAXIMUM_ENTROPY has been reduced from + /// 235 to INT_MAX to fit the underlying C++ datatype. + virtual unsigned int MaxEntropyLength() const=0; + + /// \brief Provides the minimum nonce size + /// \return The minimum nonce size recommended for the generator, in bytes + /// \details The equivalent class constant is MINIMUM_NONCE. If a nonce is not + /// required then MINIMUM_NONCE is 0. Hash_DRBG does not require a + /// nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MinNonceLength() const=0; + + /// \brief Provides the maximum nonce size + /// \return The maximum nonce that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_NONCE. MAXIMUM_NONCE + /// has been reduced from 235 to INT_MAX to fit the underlying C++ datatype. + /// If a nonce is not required then MINIMUM_NONCE is 0. Hash_DRBG does not + /// require a nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MaxNonceLength() const=0; + + /// \brief Provides the maximum size of a request to GenerateBlock + /// \return The the maximum size of a request to GenerateBlock(), in bytes + /// \details The equivalent class constant is MAXIMUM_BYTES_PER_REQUEST + virtual unsigned int MaxBytesPerRequest() const=0; + + /// \brief Provides the maximum number of requests before a reseed + /// \return The the maximum number of requests before a reseed, in bytes + /// \details The equivalent class constant is MAXIMUM_REQUESTS_BEFORE_RESEED. + /// MAXIMUM_REQUESTS_BEFORE_RESEED has been reduced from 248 to INT_MAX + /// to fit the underlying C++ datatype. + virtual unsigned int MaxRequestBeforeReseed() const=0; + +protected: + virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength, + const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0; + + virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; +}; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief Hash_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST Hash DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto +/// 248 requests before a reseed. However, Hash_DRBG limits it to INT_MAX due +/// to the limited data range of an int. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class Hash_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH); + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH); + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH); + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0); + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0); + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0); + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536); + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX); + + static std::string StaticAlgorithmName() { return std::string("Hash_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a Hash DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   Hash_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// 
+ Hash_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH), m_reseed(0) + { + if (m_c.data()) // GCC analyzer warning + std::memset(m_c.data(), 0x00, m_c.size()); + if (m_v.data()) // GCC analyzer warning + std::memset(m_v.data(), 0x00, m_v.size()); + + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return Hash_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return Hash_Generate(additional, additionaLength, output, size);} + + std::string AlgorithmProvider() const + {/*Hack*/HASH hash; return hash.AlgorithmProvider();} + +protected: + // 10.1.1.2 Instantiation of Hash_DRBG (p.39) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) + void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) + void Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen); + +private: + HASH m_hash; + SecByteBlock m_c, m_v, m_temp; + word64 m_reseed; +}; + +// typedef Hash_DRBG Hash_SHA1_DRBG; +// typedef Hash_DRBG Hash_SHA256_DRBG; +// typedef Hash_DRBG Hash_SHA384_DRBG; +// typedef Hash_DRBG Hash_SHA512_DRBG; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief HMAC_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST HMAC DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 248 requests +/// before a reseed. However, HMAC_DRBG limits it to INT_MAX due to the limited data range of an int. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class HMAC_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH); + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH); + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH); + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0); + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0); + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0); + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536); + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX); + + static std::string StaticAlgorithmName() { return std::string("HMAC_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a HMAC DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   HMAC_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// 
+ HMAC_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE), m_reseed(0) + { + if (m_k.data()) // GCC analyzer warning + std::memset(m_k, 0x00, m_k.size()); + if (m_v.data()) // GCC analyzer warning + std::memset(m_v, 0x00, m_v.size()); + + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return HMAC_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return HMAC_Generate(additional, additionaLength, output, size);} + + std::string AlgorithmProvider() const + {/*Hack*/HASH hash; return hash.AlgorithmProvider();} + +protected: + // 10.1.2.3 Instantiation of HMAC_DRBG (p.45) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) + void HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) + void HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3); + +private: + HMAC m_hmac; + SecByteBlock m_k, m_v; + word64 m_reseed; +}; + +// typedef HMAC_DRBG HMAC_SHA1_DRBG; +// typedef HMAC_DRBG HMAC_SHA256_DRBG; +// typedef HMAC_DRBG HMAC_SHA384_DRBG; +// typedef HMAC_DRBG HMAC_SHA512_DRBG; + +// ************************************************************* + +// 10.1.1.2 Instantiation of Hash_DRBG (p.39) +template +void Hash_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + const byte zero = 0; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULLPTR, 0, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) +template +void Hash_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + const byte zero = 0, one = 1; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) +template +void Hash_DRBG::Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("Hash_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + { + const byte two = 2; + m_temp.New(HASH::DIGESTSIZE); + + m_hash.Update(&two, 1); + m_hash.Update(m_v, m_v.size()); + m_hash.Update(additional, additionaLength); + m_hash.Final(m_temp); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + int carry=0, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + while (j>=0) + { + carry = m_v[i] + m_temp[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + while (i>=0) + { + carry = m_v[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + } + + // Step 3 + { + m_temp.Assign(m_v); + while (size) + { + m_hash.Update(m_temp, m_temp.size()); + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + m_hash.TruncatedFinal(output, count); + + IncrementCounterByOne(m_temp, static_cast(m_temp.size())); + size -= count; output += count; + } + } + + // Steps 4-7 + { + const byte three = 3; + m_temp.New(HASH::DIGESTSIZE); + + m_hash.Update(&three, 1); + m_hash.Update(m_v, m_v.size()); + m_hash.Final(m_temp); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed)); + int carry=0, k=sizeof(m_reseed)-1, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + + while (k>=0) + { + carry = m_v[i] + m_c[i] + m_temp[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry; + m_v[i] = static_cast(carry); + i--; j--; k--; carry >>= 8; + } + + while (j>=0) + { + carry = m_v[i] + m_c[i] + m_temp[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + + while (i>=0) + { + carry = m_v[i] + m_c[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + } + + m_reseed++; +} + +// 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) +template +void Hash_DRBG::Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen) +{ + byte counter = 1; + word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8)); + + while (outlen) + { + m_hash.Update(&counter, 1); + m_hash.Update(reinterpret_cast(&bits), 4); + + if (input1 && inlen1) + m_hash.Update(input1, inlen1); + if (input2 && inlen2) + m_hash.Update(input2, inlen2); + if (input3 && inlen3) + m_hash.Update(input3, inlen3); + if (input4 && inlen4) + m_hash.Update(input4, inlen4); + + size_t count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE); + m_hash.TruncatedFinal(output, count); + + output += count; outlen -= count; + counter++; + } +} + +// ************************************************************* + +// 10.1.2.3 Instantiation of HMAC_DRBG (p.45) +template +void HMAC_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + std::fill(m_k.begin(), m_k.begin()+m_k.size(), byte(0)); + std::fill(m_v.begin(), m_v.begin()+m_v.size(), byte(1)); + + HMAC_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + m_reseed = 1; +} + +// 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) +template +void HMAC_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + HMAC_Update(entropy, entropyLength, additional, additionaLength, NULLPTR, 0); + m_reseed = 1; +} + +// 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) +template +void HMAC_DRBG::HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("HMAC_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + + // Step 3 + m_hmac.SetKey(m_k, m_k.size()); + + while (size) + { + m_hmac.Update(m_v, m_v.size()); + m_hmac.TruncatedFinal(m_v, m_v.size()); + + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + memcpy(output, m_v, count); + size -= count; output += count; + } + + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + m_reseed++; +} + +// 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) +template +void HMAC_DRBG::HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3) +{ + const byte zero = 0, one = 1; + + // Step 1 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + m_hmac.Update(&zero, 1); + + if (input1 && inlen1) + m_hmac.Update(input1, inlen1); + if (input2 && inlen2) + m_hmac.Update(input2, inlen2); + if (input3 && inlen3) + m_hmac.Update(input3, inlen3); + + m_hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 2 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + + m_hmac.TruncatedFinal(m_v, m_v.size()); + + // Step 3 + if ((inlen1 | inlen2 | inlen3) == 0) + return; + + // Step 4 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + m_hmac.Update(&one, 1); + + if (input1 && inlen1) + m_hmac.Update(input1, inlen1); + if (input2 && inlen2) + m_hmac.Update(input2, inlen2); + if (input3 && inlen3) + m_hmac.Update(input3, inlen3); + + m_hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 5 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + + m_hmac.TruncatedFinal(m_v, m_v.size()); +} + +NAMESPACE_END + +#endif // CRYPTOPP_NIST_DRBG_H diff --git a/extension/third_party/cryptopp/dsa.cpp b/extension/third_party/cryptopp/dsa.cpp new file mode 100644 index 00000000..6bc187a9 --- /dev/null +++ b/extension/third_party/cryptopp/dsa.cpp @@ -0,0 +1,66 @@ +// dsa.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "dsa.h" +#include "asn.h" +#include "integer.h" +#include "filters.h" +#include "nbtheory.h" + +NAMESPACE_BEGIN(CryptoPP) + +size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFormat toFormat, const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat) +{ + Integer r, s; + StringStore store(signature, signatureLen); + ArraySink sink(buffer, bufferSize); + + switch (fromFormat) + { + case DSA_P1363: + r.Decode(store, signatureLen/2); + s.Decode(store, signatureLen/2); + break; + case DSA_DER: + { + BERSequenceDecoder seq(store); + r.BERDecode(seq); + s.BERDecode(seq); + seq.MessageEnd(); + break; + } + case DSA_OPENPGP: + r.OpenPGPDecode(store); + s.OpenPGPDecode(store); + break; + } + + switch (toFormat) + { + case DSA_P1363: + r.Encode(sink, bufferSize/2); + s.Encode(sink, bufferSize/2); + break; + case DSA_DER: + { + DERSequenceEncoder seq(sink); + r.DEREncode(seq); + s.DEREncode(seq); + seq.MessageEnd(); + break; + } + case DSA_OPENPGP: + r.OpenPGPEncode(sink); + s.OpenPGPEncode(sink); + break; + } + + return (size_t)sink.TotalPutLength(); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/dsa.h b/extension/third_party/cryptopp/dsa.h new file mode 100644 index 00000000..01e5fecd --- /dev/null +++ b/extension/third_party/cryptopp/dsa.h @@ -0,0 +1,53 @@ +// dsa.h - originally written and placed in the public domain by Wei Dai + +/// \file dsa.h +/// \brief Classes for the DSA signature algorithm + +#ifndef CRYPTOPP_DSA_H +#define CRYPTOPP_DSA_H + +#include "cryptlib.h" +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DSA Signature Format +/// \details The DSA signature format used by Crypto++ is as defined by IEEE P1363. +/// OpenSSL, Java and .Net use the DER format, and OpenPGP uses the OpenPGP format. +/// \sa DSAConvertSignatureFormat +/// on the Crypto++ wiki. +/// \since Crypto++ 1.0 +enum DSASignatureFormat { + /// \brief Crypto++ native signature encoding format + DSA_P1363, + /// \brief signature encoding format used by OpenSSL, Java and .Net + DSA_DER, + /// \brief OpenPGP signature encoding format + DSA_OPENPGP +}; + +/// \brief Converts between signature encoding formats +/// \param buffer byte buffer for the converted signature encoding +/// \param bufferSize the length of the converted signature encoding buffer +/// \param toFormat the source signature format +/// \param signature byte buffer for the existing signature encoding +/// \param signatureLen the length of the existing signature encoding buffer +/// \param fromFormat the source signature format +/// \return the number of bytes written during encoding +/// \details This function converts between these formats, and returns length +/// of signature in the target format. If toFormat == DSA_P1363, then +/// bufferSize must equal publicKey.SignatureLength() or +/// verifier.SignatureLength(). +/// \details If the destination buffer is too small then the output of the +/// encoded r and s will be truncated. Be sure to provide +/// an adequately sized buffer and check the return value for the number of +/// bytes written. +/// \sa DSAConvertSignatureFormat +/// on the Crypto++ wiki. +/// \since Crypto++ 1.0 +size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFormat toFormat, + const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat); + +NAMESPACE_END + +#endif // CRYPTOPP_DSA_H diff --git a/extension/third_party/cryptopp/eax.cpp b/extension/third_party/cryptopp/eax.cpp new file mode 100644 index 00000000..90b9d90b --- /dev/null +++ b/extension/third_party/cryptopp/eax.cpp @@ -0,0 +1,59 @@ +// eax.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "eax.h" + +NAMESPACE_BEGIN(CryptoPP) + +void EAX_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + AccessMAC().SetKey(userKey, keylength, params); + m_buffer.New(2*AccessMAC().TagSize()); +} + +void EAX_Base::Resync(const byte *iv, size_t len) +{ + MessageAuthenticationCode &mac = AccessMAC(); + unsigned int blockSize = mac.TagSize(); + + memset(m_buffer, 0, blockSize); + mac.Update(m_buffer, blockSize); + mac.CalculateDigest(m_buffer+blockSize, iv, len); + + m_buffer[blockSize-1] = 1; + mac.Update(m_buffer, blockSize); + + m_ctr.SetCipherWithIV(AccessMAC().AccessCipher(), m_buffer+blockSize, blockSize); +} + +size_t EAX_Base::AuthenticateBlocks(const byte *data, size_t len) +{ + AccessMAC().Update(data, len); + return 0; +} + +void EAX_Base::AuthenticateLastHeaderBlock() +{ + CRYPTOPP_ASSERT(m_bufferedDataLength == 0); + MessageAuthenticationCode &mac = AccessMAC(); + const unsigned int blockSize = mac.TagSize(); + + mac.Final(m_buffer); + xorbuf(m_buffer+blockSize, m_buffer, blockSize); + + memset(m_buffer, 0, blockSize); + m_buffer[blockSize-1] = 2; + mac.Update(m_buffer, blockSize); +} + +void EAX_Base::AuthenticateLastFooterBlock(byte *tag, size_t macSize) +{ + CRYPTOPP_ASSERT(m_bufferedDataLength == 0); + MessageAuthenticationCode &mac = AccessMAC(); + unsigned int blockSize = mac.TagSize(); + + mac.TruncatedFinal(m_buffer, macSize); + xorbuf(tag, m_buffer, m_buffer+blockSize, macSize); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/eax.h b/extension/third_party/cryptopp/eax.h new file mode 100644 index 00000000..9d4edfaa --- /dev/null +++ b/extension/third_party/cryptopp/eax.h @@ -0,0 +1,112 @@ +// eax.h - originally written and placed in the public domain by Wei Dai + +/// \file eax.h +/// \brief EAX block cipher mode of operation + +#ifndef CRYPTOPP_EAX_H +#define CRYPTOPP_EAX_H + +#include "authenc.h" +#include "modes.h" +#include "cmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EAX block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetMAC().GetCipher().AlgorithmName() + std::string("/EAX");} + std::string AlgorithmProvider() const + {return GetMAC().GetCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetMAC().MinKeyLength();} + size_t MaxKeyLength() const + {return GetMAC().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetMAC().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetMAC().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetMAC().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const + {return GetMAC().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return GetMAC().TagSize();} + unsigned int MinIVLength() const + {return 0;} + unsigned int MaxIVLength() const + {return UINT_MAX;} + unsigned int DigestSize() const + {return GetMAC().TagSize();} + lword MaxHeaderLength() const + {return LWORD_MAX;} + lword MaxMessageLength() const + {return LWORD_MAX;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + const CMAC_Base & GetMAC() const {return const_cast(this)->AccessMAC();} + virtual CMAC_Base & AccessMAC() =0; + + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief EAX block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class EAX_Final : public EAX_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/EAX");} + std::string AlgorithmProvider() const + {return m_cmac.AlgorithmProvider();} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + CMAC_Base & AccessMAC() {return m_cmac;} + CMAC m_cmac; +}; + +#ifdef EAX // EAX is defined to 11 on GCC 3.4.3, OpenSolaris 8.11 +#undef EAX +#endif + +/// \brief EAX block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \details \p EAX provides the \p Encryption and \p Decryption typedef. See EAX_Base +/// and EAX_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa EAX Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct EAX : public AuthenticatedSymmetricCipherDocumentation +{ + typedef EAX_Final Encryption; + typedef EAX_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ec2n.cpp b/extension/third_party/cryptopp/ec2n.cpp new file mode 100644 index 00000000..87aed853 --- /dev/null +++ b/extension/third_party/cryptopp/ec2n.cpp @@ -0,0 +1,320 @@ +// ec2n.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "ec2n.h" +#include "asn.h" +#include "integer.h" +#include "filters.h" +#include "algebra.cpp" +#include "eprecomp.cpp" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::EC2N; + +#if defined(HAVE_GCC_INIT_PRIORITY) + #define INIT_ATTRIBUTE __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 51))) + const EC2N::Point g_identity INIT_ATTRIBUTE = EC2N::Point(); +#elif defined(HAVE_MSC_INIT_PRIORITY) + #pragma warning(disable: 4075) + #pragma init_seg(".CRT$XCU") + const EC2N::Point g_identity; + #pragma warning(default: 4075) +#elif defined(HAVE_XLC_INIT_PRIORITY) + #pragma priority(290) + const EC2N::Point g_identity; +#endif + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +EC2N::EC2N(BufferedTransformation &bt) + : m_field(BERDecodeGF2NP(bt)) +{ + BERSequenceDecoder seq(bt); + m_field->BERDecodeElement(seq, m_a); + m_field->BERDecodeElement(seq, m_b); + // skip optional seed + if (!seq.EndReached()) + { + SecByteBlock seed; + unsigned int unused; + BERDecodeBitString(seq, seed, unused); + } + seq.MessageEnd(); +} + +void EC2N::DEREncode(BufferedTransformation &bt) const +{ + m_field->DEREncode(bt); + DERSequenceEncoder seq(bt); + m_field->DEREncodeElement(seq, m_a); + m_field->DEREncodeElement(seq, m_b); + seq.MessageEnd(); +} + +bool EC2N::DecodePoint(EC2N::Point &P, const byte *encodedPoint, size_t encodedPointLen) const +{ + StringStore store(encodedPoint, encodedPointLen); + return DecodePoint(P, store, encodedPointLen); +} + +bool EC2N::DecodePoint(EC2N::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const +{ + byte type; + if (encodedPointLen < 1 || !bt.Get(type)) + return false; + + switch (type) + { + case 0: + P.identity = true; + return true; + case 2: + case 3: + { + if (encodedPointLen != EncodedPointSize(true)) + return false; + + P.identity = false; + P.x.Decode(bt, m_field->MaxElementByteLength()); + + if (P.x.IsZero()) + { + P.y = m_field->SquareRoot(m_b); + return true; + } + + FieldElement z = m_field->Square(P.x); + CRYPTOPP_ASSERT(P.x == m_field->SquareRoot(z)); + P.y = m_field->Divide(m_field->Add(m_field->Multiply(z, m_field->Add(P.x, m_a)), m_b), z); + CRYPTOPP_ASSERT(P.x == m_field->Subtract(m_field->Divide(m_field->Subtract(m_field->Multiply(P.y, z), m_b), z), m_a)); + z = m_field->SolveQuadraticEquation(P.y); + CRYPTOPP_ASSERT(m_field->Add(m_field->Square(z), z) == P.y); + z.SetCoefficient(0, type & 1); + + P.y = m_field->Multiply(z, P.x); + return true; + } + case 4: + { + if (encodedPointLen != EncodedPointSize(false)) + return false; + + unsigned int len = m_field->MaxElementByteLength(); + P.identity = false; + P.x.Decode(bt, len); + P.y.Decode(bt, len); + return true; + } + default: + return false; + } +} + +void EC2N::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + if (P.identity) + NullStore().TransferTo(bt, EncodedPointSize(compressed)); + else if (compressed) + { + bt.Put((byte)(2U + (!P.x ? 0U : m_field->Divide(P.y, P.x).GetBit(0)))); + P.x.Encode(bt, m_field->MaxElementByteLength()); + } + else + { + unsigned int len = m_field->MaxElementByteLength(); + bt.Put(4); // uncompressed + P.x.Encode(bt, len); + P.y.Encode(bt, len); + } +} + +void EC2N::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const +{ + ArraySink sink(encodedPoint, EncodedPointSize(compressed)); + EncodePoint(sink, P, compressed); + CRYPTOPP_ASSERT(sink.TotalPutLength() == EncodedPointSize(compressed)); +} + +EC2N::Point EC2N::BERDecodePoint(BufferedTransformation &bt) const +{ + SecByteBlock str; + BERDecodeOctetString(bt, str); + Point P; + if (!DecodePoint(P, str, str.size())) + BERDecodeError(); + return P; +} + +void EC2N::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + SecByteBlock str(EncodedPointSize(compressed)); + EncodePoint(str, P, compressed); + DEREncodeOctetString(bt, str); +} + +bool EC2N::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng); + bool pass = !!m_b; + pass = pass && m_a.CoefficientCount() <= m_field->MaxElementBitLength(); + pass = pass && m_b.CoefficientCount() <= m_field->MaxElementBitLength(); + + if (level >= 1) + pass = pass && m_field->GetModulus().IsIrreducible(); + + return pass; +} + +bool EC2N::VerifyPoint(const Point &P) const +{ + const FieldElement &x = P.x, &y = P.y; + return P.identity || + (x.CoefficientCount() <= m_field->MaxElementBitLength() + && y.CoefficientCount() <= m_field->MaxElementBitLength() + && !(((x+m_a)*x*x+m_b-(x+y)*y)%m_field->GetModulus())); +} + +bool EC2N::Equal(const Point &P, const Point &Q) const +{ + if (P.identity && Q.identity) + return true; + + if (P.identity && !Q.identity) + return false; + + if (!P.identity && Q.identity) + return false; + + return (m_field->Equal(P.x,Q.x) && m_field->Equal(P.y,Q.y)); +} + +const EC2N::Point& EC2N::Identity() const +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_identity; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const EC2N::Point g_identity; + return g_identity; +#else + return Singleton().Ref(); +#endif +} + +const EC2N::Point& EC2N::Inverse(const Point &P) const +{ + if (P.identity) + return P; + else + { + m_R.identity = false; + m_R.y = m_field->Add(P.x, P.y); + m_R.x = P.x; + return m_R; + } +} + +const EC2N::Point& EC2N::Add(const Point &P, const Point &Q) const +{ + if (P.identity) return Q; + if (Q.identity) return P; + if (Equal(P, Q)) return Double(P); + if (m_field->Equal(P.x, Q.x) && m_field->Equal(P.y, m_field->Add(Q.x, Q.y))) return Identity(); + + FieldElement t = m_field->Add(P.y, Q.y); + t = m_field->Divide(t, m_field->Add(P.x, Q.x)); + FieldElement x = m_field->Square(t); + m_field->Accumulate(x, t); + m_field->Accumulate(x, Q.x); + m_field->Accumulate(x, m_a); + m_R.y = m_field->Add(P.y, m_field->Multiply(t, x)); + m_field->Accumulate(x, P.x); + m_field->Accumulate(m_R.y, x); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +const EC2N::Point& EC2N::Double(const Point &P) const +{ + if (P.identity) return P; + if (!m_field->IsUnit(P.x)) return Identity(); + + FieldElement t = m_field->Divide(P.y, P.x); + m_field->Accumulate(t, P.x); + m_R.y = m_field->Square(P.x); + m_R.x = m_field->Square(t); + m_field->Accumulate(m_R.x, t); + m_field->Accumulate(m_R.x, m_a); + m_field->Accumulate(m_R.y, m_field->Multiply(t, m_R.x)); + m_field->Accumulate(m_R.y, m_R.x); + + m_R.identity = false; + return m_R; +} + +// ******************************************************** + +#if 0 +EcPrecomputation& EcPrecomputation::operator=(const EcPrecomputation &rhs) +{ + m_ec = rhs.m_ec; + m_ep = rhs.m_ep; + m_ep.m_group = m_ec.get(); + return *this; +} + +void EcPrecomputation::SetCurveAndBase(const EC2N &ec, const EC2N::Point &base) +{ + m_ec.reset(new EC2N(ec)); + m_ep.SetGroupAndBase(*m_ec, base); +} + +void EcPrecomputation::Precompute(unsigned int maxExpBits, unsigned int storage) +{ + m_ep.Precompute(maxExpBits, storage); +} + +void EcPrecomputation::Load(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(seq, version, INTEGER, 1, 1); + m_ep.m_exponentBase.BERDecode(seq); + m_ep.m_windowSize = m_ep.m_exponentBase.BitCount() - 1; + m_ep.m_bases.clear(); + while (!seq.EndReached()) + m_ep.m_bases.push_back(m_ec->BERDecodePoint(seq)); + seq.MessageEnd(); +} + +void EcPrecomputation::Save(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned(seq, 1); // version + m_ep.m_exponentBase.DEREncode(seq); + for (unsigned i=0; iDEREncodePoint(seq, m_ep.m_bases[i]); + seq.MessageEnd(); +} + +EC2N::Point EcPrecomputation::Exponentiate(const Integer &exponent) const +{ + return m_ep.Exponentiate(exponent); +} + +EC2N::Point EcPrecomputation::CascadeExponentiate(const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const +{ + return m_ep.CascadeExponentiate(exponent, static_cast &>(pc2).m_ep, exponent2); +} +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ec2n.h b/extension/third_party/cryptopp/ec2n.h new file mode 100644 index 00000000..b05377bb --- /dev/null +++ b/extension/third_party/cryptopp/ec2n.h @@ -0,0 +1,136 @@ +// ec2n.h - originally written and placed in the public domain by Wei Dai + +/// \file ec2n.h +/// \brief Classes for Elliptic Curves over binary fields + +#ifndef CRYPTOPP_EC2N_H +#define CRYPTOPP_EC2N_H + +#include "cryptlib.h" +#include "gf2n.h" +#include "integer.h" +#include "algebra.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(2^n) +class CRYPTOPP_DLL EC2N : public AbstractGroup, public EncodedPoint +{ +public: + typedef GF2NP Field; + typedef Field::Element FieldElement; + typedef EC2NPoint Point; + + virtual ~EC2N() {} + + /// \brief Construct an EC2N + EC2N() {} + + /// \brief Construct an EC2N + /// \param field Field, GF2NP derived class + /// \param a Field::Element + /// \param b Field::Element + EC2N(const Field &field, const Field::Element &a, const Field::Element &b) + : m_field(field), m_a(a), m_b(b) {} + + /// \brief Construct an EC2N from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the the fields fieldID and curve of the sequence ECParameters + EC2N(BufferedTransformation &bt); + + /// \brief Encode the fields fieldID and curve of the sequence ECParameters + /// \param bt BufferedTransformation derived object + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*m_field->MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return Integer::Power2(m_field->MaxElementBitLength());} + const Field & GetField() const {return *m_field;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const EC2N &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_field; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief EC2N precomputation specialization +/// \details Implementation of DL_GroupPrecomputation +/// \sa DL_GroupPrecomputation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef EC2N EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + const AbstractGroup & GetGroup() const {return m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec.BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec.DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const EC2N &ec) {m_ec = ec;} + + /// \brief Get the elliptic curve + /// \return EC2N curve + /// \details GetCurve() is not inherited + const EC2N & GetCurve() const {return m_ec;} + +private: + EC2N m_ec; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/eccrypto.cpp b/extension/third_party/cryptopp/eccrypto.cpp new file mode 100644 index 00000000..9a0914c0 --- /dev/null +++ b/extension/third_party/cryptopp/eccrypto.cpp @@ -0,0 +1,840 @@ +// eccrypto.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4505) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "eccrypto.h" +#include "integer.h" +#include "nbtheory.h" +#include "filters.h" +#include "argnames.h" +#include "smartptr.h" +#include "oids.h" +#include "asn.h" +#include "hex.h" +#include "ec2n.h" +#include "misc.h" + +#include +#include + +// Squash MS LNK4221 and libtool warnings +#ifndef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +extern const char ECCRYPTO_FNAME[] = __FILE__; +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +static void ECDSA_TestInstantiations() +{ + ECDSA::Signer t1; + ECDSA::Verifier t2(t1); + ECNR::Signer t3; + ECNR::Verifier t4(t3); + ECIES::Encryptor t5; + ECIES::Decryptor t6; + ECDH::Domain t7; + ECMQV::Domain t8; +} +#endif +#endif + +ANONYMOUS_NAMESPACE_BEGIN +inline Integer ConvertToInteger(const PolynomialMod2 &x) +{ + unsigned int l = x.ByteCount(); + SecByteBlock temp(l); + x.Encode(temp, l); + return Integer(temp, l); +} + +inline Integer ConvertToInteger(const Integer &x) +{ + return x; +} + +inline bool CheckMOVCondition(const Integer &q, const Integer &r) +{ + // see "Updated standards for validating elliptic curves", http://eprint.iacr.org/2007/343 + Integer t = 1; + unsigned int n = q.IsEven() ? 1 : q.BitCount(), m = r.BitCount(); + + for (unsigned int i=n; DiscreteLogWorkFactor(i) struct EcRecommendedParameters; + +template<> struct EcRecommendedParameters +{ + EcRecommendedParameters(const OID &oid, unsigned int t2, unsigned int t3, unsigned int t4, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), a(a), b(b), g(g), n(n), h(h), t0(0), t1(0), t2(t2), t3(t3), t4(t4) {} + EcRecommendedParameters(const OID &oid, unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), a(a), b(b), g(g), n(n), h(h), t0(t0), t1(t1), t2(t2), t3(t3), t4(t4) {} + EC2N *NewEC() const + { + StringSource ssA(a, true, new HexDecoder); + StringSource ssB(b, true, new HexDecoder); + if (t0 == 0) + { + if (t2 == 233 && t3 == 74 && t4 == 0) + return new EC2N(GF2NT233(233, 74, 0), EC2N::FieldElement(ssA, (size_t)ssA.MaxRetrievable()), EC2N::FieldElement(ssB, (size_t)ssB.MaxRetrievable())); + else + return new EC2N(GF2NT(t2, t3, t4), EC2N::FieldElement(ssA, (size_t)ssA.MaxRetrievable()), EC2N::FieldElement(ssB, (size_t)ssB.MaxRetrievable())); + } + else + return new EC2N(GF2NPP(t0, t1, t2, t3, t4), EC2N::FieldElement(ssA, (size_t)ssA.MaxRetrievable()), EC2N::FieldElement(ssB, (size_t)ssB.MaxRetrievable())); + }; + + OID oid; + const char *a, *b, *g, *n; + unsigned int h, t0, t1, t2, t3, t4; +}; + +template<> struct EcRecommendedParameters +{ + EcRecommendedParameters(const OID &oid, const char *p, const char *a, const char *b, const char *g, const char *n, unsigned int h) + : oid(oid), p(p), a(a), b(b), g(g), n(n), h(h) {} + ECP *NewEC() const + { + StringSource ssP(p, true, new HexDecoder); + StringSource ssA(a, true, new HexDecoder); + StringSource ssB(b, true, new HexDecoder); + return new ECP(Integer(ssP, (size_t)ssP.MaxRetrievable()), ECP::FieldElement(ssA, (size_t)ssA.MaxRetrievable()), ECP::FieldElement(ssB, (size_t)ssB.MaxRetrievable())); + }; + + OID oid; + const char *p, *a, *b, *g, *n; + unsigned int h; +}; + +struct OIDLessThan +{ + template + inline bool operator()(const EcRecommendedParameters& a, const OID& b) {return a.oid < b;} + template + inline bool operator()(const OID& a, const EcRecommendedParameters& b) {return a < b.oid;} + template + inline bool operator()(const EcRecommendedParameters& a, const EcRecommendedParameters& b) {return a.oid < b.oid;} +}; + +static void GetRecommendedParameters(const EcRecommendedParameters *&begin, const EcRecommendedParameters *&end) +{ + // this array must be sorted by OID + static const EcRecommendedParameters rec[] = { + EcRecommendedParameters(ASN1::sect163k1(), + 163, 7, 6, 3, 0, + "000000000000000000000000000000000000000001", + "000000000000000000000000000000000000000001", + "0402FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE80289070FB05D38FF58321F2E800536D538CCDAA3D9", + "04000000000000000000020108A2E0CC0D99F8A5EF", + 2), + EcRecommendedParameters(ASN1::sect163r1(), + 163, 7, 6, 3, 0, + "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", + "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", + "040369979697AB43897789566789567F787A7876A65400435EDB42EFAFB2989D51FEFCE3C80988F41FF883", + "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", + 2), + EcRecommendedParameters(ASN1::sect239k1(), + 239, 158, 0, + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "0429A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", + "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", + 4), + EcRecommendedParameters(ASN1::sect113r1(), + 113, 9, 0, + "003088250CA6E7C7FE649CE85820F7", + "00E8BEE4D3E2260744188BE0E9C723", + "04009D73616F35F4AB1407D73562C10F00A52830277958EE84D1315ED31886", + "0100000000000000D9CCEC8A39E56F", + 2), + EcRecommendedParameters(ASN1::sect113r2(), + 113, 9, 0, + "00689918DBEC7E5A0DD6DFC0AA55C7", + "0095E9A9EC9B297BD4BF36E059184F", + "0401A57A6A7B26CA5EF52FCDB816479700B3ADC94ED1FE674C06E695BABA1D", + "010000000000000108789B2496AF93", + 2), + EcRecommendedParameters(ASN1::sect163r2(), + 163, 7, 6, 3, 0, + "000000000000000000000000000000000000000001", + "020A601907B8C953CA1481EB10512F78744A3205FD", + "0403F0EBA16286A2D57EA0991168D4994637E8343E3600D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", + "040000000000000000000292FE77E70C12A4234C33", + 2), + EcRecommendedParameters(ASN1::sect283k1(), + 283, 12, 7, 5, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000001", + "040503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC245849283601CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", + 4), + EcRecommendedParameters(ASN1::sect283r1(), + 283, 12, 7, 5, 0, + "000000000000000000000000000000000000000000000000000000000000000000000001", + "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", + "0405F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B1205303676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", + 2), + EcRecommendedParameters(ASN1::sect131r1(), + 131, 8, 3, 2, 0, + "07A11B09A76B562144418FF3FF8C2570B8", + "0217C05610884B63B9C6C7291678F9D341", + "040081BAF91FDF9833C40F9C181343638399078C6E7EA38C001F73C8134B1B4EF9E150", + "0400000000000000023123953A9464B54D", + 2), + EcRecommendedParameters(ASN1::sect131r2(), + 131, 8, 3, 2, 0, + "03E5A88919D7CAFCBF415F07C2176573B2", + "04B8266A46C55657AC734CE38F018F2192", + "040356DCD8F2F95031AD652D23951BB366A80648F06D867940A5366D9E265DE9EB240F", + "0400000000000000016954A233049BA98F", + 2), + EcRecommendedParameters(ASN1::sect193r1(), + 193, 15, 0, + "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", + "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", + "0401F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E10025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", + "01000000000000000000000000C7F34A778F443ACC920EBA49", + 2), + EcRecommendedParameters(ASN1::sect193r2(), + 193, 15, 0, + "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", + "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", + "0400D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", + "010000000000000000000000015AAB561B005413CCD4EE99D5", + 2), + EcRecommendedParameters(ASN1::sect233k1(), + 233, 74, 0, + "000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000001", + "04017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD612601DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", + "8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", + 4), + EcRecommendedParameters(ASN1::sect233r1(), + 233, 74, 0, + "000000000000000000000000000000000000000000000000000000000001", + "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", + "0400FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", + "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", + 2), + EcRecommendedParameters(ASN1::sect409k1(), + 409, 87, 0, + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "040060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE902374601E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", + 4), + EcRecommendedParameters(ASN1::sect409r1(), + 409, 87, 0, + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", + "04015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A70061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", + "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", + 2), + EcRecommendedParameters(ASN1::sect571k1(), + 571, 10, 5, 2, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "04026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C89720349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", + "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", + 4), + EcRecommendedParameters(ASN1::sect571r1(), + 571, 10, 5, 2, 0, + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", + "040303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", + 2), + }; + begin = rec; + end = rec + sizeof(rec)/sizeof(rec[0]); +} + +// See https://www.cryptopp.com/wiki/SM2 for details on sm2p256v1 and sm2encrypt_recommendedParameters +static void GetRecommendedParameters(const EcRecommendedParameters *&begin, const EcRecommendedParameters *&end) +{ + // this array must be sorted by OID + static const EcRecommendedParameters rec[] = { + EcRecommendedParameters(ASN1::sm2p256v1(), + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF", + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC", + "28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93", + "04" "32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7" + "BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0", + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123", + 1), + EcRecommendedParameters(ASN1::sm2encrypt_recommendedParameters(), + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF", + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC", + "28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93", + "04" "32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7" + "BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0", + "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123", + 1), + EcRecommendedParameters(ASN1::secp192r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "04188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + 1), + EcRecommendedParameters(ASN1::secp256r1(), + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + 1), + EcRecommendedParameters(ASN1::brainpoolP160r1(), + "E95E4A5F737059DC60DFC7AD95B3D8139515620F", + "340E7BE2A280EB74E2BE61BADA745D97E8F7C300", + "1E589A8595423412134FAA2DBDEC95C8D8675E58", + "04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321", + "E95E4A5F737059DC60DF5991D45029409E60FC09", + 1), + EcRecommendedParameters(ASN1::brainpoolP192r1(), + "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", + "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", + "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", + "04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", + "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", + 1), + EcRecommendedParameters(ASN1::brainpoolP224r1(), + "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", + "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", + "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", + "040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", + "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", + 1), + EcRecommendedParameters(ASN1::brainpoolP256r1(), + "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", + "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", + "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", + "048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", + "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", + 1), + EcRecommendedParameters(ASN1::brainpoolP320r1(), + "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", + "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", + "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", + "0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", + "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", + 1), + EcRecommendedParameters(ASN1::brainpoolP384r1(), + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", + "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", + "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", + "041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", + 1), + EcRecommendedParameters(ASN1::brainpoolP512r1(), + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", + "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", + "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", + "0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", + 1), + EcRecommendedParameters(ASN1::secp112r1(), + "DB7C2ABF62E35E668076BEAD208B", + "DB7C2ABF62E35E668076BEAD2088", + "659EF8BA043916EEDE8911702B22", + "0409487239995A5EE76B55F9C2F098A89CE5AF8724C0A23E0E0FF77500", + "DB7C2ABF62E35E7628DFAC6561C5", + 1), + EcRecommendedParameters(ASN1::secp112r2(), + "DB7C2ABF62E35E668076BEAD208B", + "6127C24C05F38A0AAAF65C0EF02C", + "51DEF1815DB5ED74FCC34C85D709", + "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97", + "36DF0AAFD8B8D7597CA10520D04B", + 4), + EcRecommendedParameters(ASN1::secp160r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "044A96B5688EF573284664698968C38BB913CBFC8223A628553168947D59DCC912042351377AC5FB32", + "0100000000000000000001F4C8F927AED3CA752257", + 1), + EcRecommendedParameters(ASN1::secp160k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0000000000000000000000000000000000000000", + "0000000000000000000000000000000000000007", + "043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE", + "0100000000000000000001B8FA16DFAB9ACA16B6B3", + 1), + EcRecommendedParameters(ASN1::secp256k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000007", + "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + 1), + EcRecommendedParameters(ASN1::secp128r1(), + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", + "E87579C11079F43DD824993C2CEE5ED3", + "04161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83", + "FFFFFFFE0000000075A30D1B9038A115", + 1), + EcRecommendedParameters(ASN1::secp128r2(), + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "D6031998D1B3BBFEBF59CC9BBFF9AEE1", + "5EEEFCA380D02919DC2C6558BB6D8A5D", + "047B6AA5D85E572983E6FB32A7CDEBC14027B6916A894D3AEE7106FE805FC34B44", + "3FFFFFFF7FFFFFFFBE0024720613B5A3", + 4), + EcRecommendedParameters(ASN1::secp160r2(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", + "B4E134D3FB59EB8BAB57274904664D5AF50388BA", + "0452DCB034293A117E1F4FF11B30F7199D3144CE6DFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", + "0100000000000000000000351EE786A818F3A1A16B", + 1), + EcRecommendedParameters(ASN1::secp192k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", + "000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000003", + "04DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", + 1), + EcRecommendedParameters(ASN1::secp224k1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", + "00000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000005", + "04A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", + "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", + 1), + EcRecommendedParameters(ASN1::secp224r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + 1), + EcRecommendedParameters(ASN1::secp384r1(), + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + 1), + EcRecommendedParameters(ASN1::secp521r1(), + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + 1), + }; + begin = rec; + end = rec + sizeof(rec)/sizeof(rec[0]); +} + +template OID DL_GroupParameters_EC::GetNextRecommendedParametersOID(const OID &oid) +{ + const EcRecommendedParameters *begin, *end; + GetRecommendedParameters(begin, end); + const EcRecommendedParameters *it = std::upper_bound(begin, end, oid, OIDLessThan()); + return (it == end ? OID() : it->oid); +} + +template void DL_GroupParameters_EC::Initialize(const OID &oid) +{ + const EcRecommendedParameters *begin, *end; + GetRecommendedParameters(begin, end); + const EcRecommendedParameters *it = std::lower_bound(begin, end, oid, OIDLessThan()); + if (it == end || it->oid != oid) + throw UnknownOID(); + + const EcRecommendedParameters ¶m = *it; + m_oid = oid; + member_ptr ec(param.NewEC()); + this->m_groupPrecomputation.SetCurve(*ec); + + StringSource ssG(param.g, true, new HexDecoder); + Element G; + bool result = GetCurve().DecodePoint(G, ssG, (size_t)ssG.MaxRetrievable()); + this->SetSubgroupGenerator(G); + + // TODO: this fails in practice. Should it throw? + CRYPTOPP_UNUSED(result); CRYPTOPP_ASSERT(result); + + StringSource ssN(param.n, true, new HexDecoder); + m_n.Decode(ssN, (size_t)ssN.MaxRetrievable()); + m_k = param.h; +} + +template +bool DL_GroupParameters_EC::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (strcmp(name, Name::GroupOID()) == 0) + { + if (m_oid.Empty()) + return false; + + this->ThrowIfTypeMismatch(name, typeid(OID), valueType); + *reinterpret_cast(pValue) = m_oid; + return true; + } + else + return GetValueHelper >(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Curve); +} + +template +void DL_GroupParameters_EC::AssignFrom(const NameValuePairs &source) +{ + OID oid; + if (source.GetValue(Name::GroupOID(), oid)) + Initialize(oid); + else + { + EllipticCurve ec; + Point G; + Integer n; + + source.GetRequiredParameter("DL_GroupParameters_EC", Name::Curve(), ec); + source.GetRequiredParameter("DL_GroupParameters_EC", Name::SubgroupGenerator(), G); + source.GetRequiredParameter("DL_GroupParameters_EC", Name::SubgroupOrder(), n); + Integer k = source.GetValueWithDefault(Name::Cofactor(), Integer::Zero()); + + Initialize(ec, G, n, k); + } +} + +template +void DL_GroupParameters_EC::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + try + { + CRYPTOPP_UNUSED(rng); + AssignFrom(alg); + } + catch (InvalidArgument &) + { + throw NotImplemented("DL_GroupParameters_EC: curve generation is not implemented yet"); + } +} + +template +void DL_GroupParameters_EC::BERDecode(BufferedTransformation &bt) +{ + byte b; + if (!bt.Peek(b)) + BERDecodeError(); + if (b == OBJECT_IDENTIFIER) + Initialize(OID(bt)); + else + { + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(seq, version, INTEGER, 1, 1); // check version + EllipticCurve ec(seq); + Point G = ec.BERDecodePoint(seq); + Integer n(seq); + Integer k; + bool cofactorPresent = !seq.EndReached(); + if (cofactorPresent) + k.BERDecode(seq); + else + k = Integer::Zero(); + seq.MessageEnd(); + + Initialize(ec, G, n, k); + } +} + +template +void DL_GroupParameters_EC::DEREncode(BufferedTransformation &bt) const +{ + if (m_encodeAsOID && !m_oid.Empty()) + m_oid.DEREncode(bt); + else + { + DERSequenceEncoder seq(bt); + DEREncodeUnsigned(seq, 1); // version + GetCurve().DEREncode(seq); + GetCurve().DEREncodePoint(seq, this->GetSubgroupGenerator(), m_compress); + m_n.DEREncode(seq); + if (m_k.NotZero()) + m_k.DEREncode(seq); + seq.MessageEnd(); + } +} + +template +Integer DL_GroupParameters_EC::GetCofactor() const +{ + if (!m_k) + { + Integer q = GetCurve().FieldSize(); + Integer qSqrt = q.SquareRoot(); + m_k = (q+2*qSqrt+1)/m_n; + } + + return m_k; +} + +template +Integer DL_GroupParameters_EC::ConvertElementToInteger(const Element &element) const +{ + return ConvertToInteger(element.x); +} + +template +bool DL_GroupParameters_EC::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = GetCurve().ValidateParameters(rng, level); + CRYPTOPP_ASSERT(pass); + + Integer q = GetCurve().FieldSize(); + pass = pass && m_n!=q; + CRYPTOPP_ASSERT(pass); + + if (level >= 2) + { + Integer qSqrt = q.SquareRoot(); + pass = pass && m_n>4*qSqrt; + CRYPTOPP_ASSERT(pass); + pass = pass && VerifyPrime(rng, m_n, level-2); + CRYPTOPP_ASSERT(pass); + pass = pass && (m_k.IsZero() || m_k == (q+2*qSqrt+1)/m_n); + CRYPTOPP_ASSERT(pass); + pass = pass && CheckMOVCondition(q, m_n); + CRYPTOPP_ASSERT(pass); + } + + return pass; +} + +template +bool DL_GroupParameters_EC::ValidateElement(unsigned int level, const Element &g, const DL_FixedBasePrecomputation *gpc) const +{ + bool pass = !IsIdentity(g); + CRYPTOPP_ASSERT(pass); + pass = pass && GetCurve().VerifyPoint(g); + CRYPTOPP_ASSERT(pass); + + if (level >= 1) + { + if (gpc) + { + pass = pass && gpc->Exponentiate(this->GetGroupPrecomputation(), Integer::One()) == g; + CRYPTOPP_ASSERT(pass); + } + } + if (level >= 2 && pass) + { + const Integer &q = GetSubgroupOrder(); + Element gq = gpc ? gpc->Exponentiate(this->GetGroupPrecomputation(), q) : this->ExponentiateElement(g, q); + pass = pass && IsIdentity(gq); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +template +void DL_GroupParameters_EC::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + GetCurve().SimultaneousMultiply(results, base, exponents, exponentsCount); +} + +template +typename DL_GroupParameters_EC::Element DL_GroupParameters_EC::MultiplyElements(const Element &a, const Element &b) const +{ + return GetCurve().Add(a, b); +} + +template +typename DL_GroupParameters_EC::Element DL_GroupParameters_EC::CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const +{ + return GetCurve().CascadeMultiply(exponent1, element1, exponent2, element2); +} + +template +OID DL_GroupParameters_EC::GetAlgorithmID() const +{ + return ASN1::id_ecPublicKey(); +} + +std::ostream& operator<<(std::ostream& os, const DL_GroupParameters_EC::Element& obj) +{ + std::ostringstream oss; + oss << "(" << std::hex << obj.x << ", " << std::hex << obj.y << ")"; + return os << oss.str(); +} + +// ****************************************************************** + +template +void DL_PublicKey_EC::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) +{ + CRYPTOPP_UNUSED(parametersPresent); + + typename EC::Point P; + if (!this->GetGroupParameters().GetCurve().DecodePoint(P, bt, size)) + BERDecodeError(); + this->SetPublicElement(P); +} + +template +void DL_PublicKey_EC::DEREncodePublicKey(BufferedTransformation &bt) const +{ + this->GetGroupParameters().GetCurve().EncodePoint(bt, this->GetPublicElement(), this->GetGroupParameters().GetPointCompression()); +} + +// ****************************************************************** + +template +void DL_PrivateKey_EC::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) +{ + CRYPTOPP_UNUSED(size); + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(seq, version, INTEGER, 1, 1); // check version + + BERGeneralDecoder dec(seq, OCTET_STRING); + if (!dec.IsDefiniteLength()) + BERDecodeError(); + Integer x; + x.Decode(dec, (size_t)dec.RemainingLength()); + dec.MessageEnd(); + if (!parametersPresent && seq.PeekByte() != (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + BERDecodeError(); + if (!seq.EndReached() && seq.PeekByte() == (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + { + BERGeneralDecoder parameters(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 0); + this->AccessGroupParameters().BERDecode(parameters); + parameters.MessageEnd(); + } + if (!seq.EndReached()) + { + // skip over the public element + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERGeneralDecoder publicKey(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + BERDecodeBitString(publicKey, subjectPublicKey, unusedBits); + publicKey.MessageEnd(); + Element Q; + if (!(unusedBits == 0 && this->GetGroupParameters().GetCurve().DecodePoint(Q, subjectPublicKey, subjectPublicKey.size()))) + BERDecodeError(); + } + seq.MessageEnd(); + + this->SetPrivateExponent(x); +} + +template +void DL_PrivateKey_EC::DEREncodePrivateKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + DEREncodeUnsigned(privateKey, 1); // version + // SEC 1 ver 1.0 says privateKey (m_d) has the same length as order of the curve + // this will be changed to order of base point in a future version + this->GetPrivateExponent().DEREncodeAsOctetString(privateKey, this->GetGroupParameters().GetSubgroupOrder().ByteCount()); + privateKey.MessageEnd(); +} + +// ****************************************************************** + +template +void DL_PublicKey_ECGDSA::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) +{ + CRYPTOPP_UNUSED(parametersPresent); + + typename EC::Point P; + if (!this->GetGroupParameters().GetCurve().DecodePoint(P, bt, size)) + BERDecodeError(); + this->SetPublicElement(P); +} + +template +void DL_PublicKey_ECGDSA::DEREncodePublicKey(BufferedTransformation &bt) const +{ + this->GetGroupParameters().GetCurve().EncodePoint(bt, this->GetPublicElement(), this->GetGroupParameters().GetPointCompression()); +} + +// ****************************************************************** + +template +void DL_PrivateKey_ECGDSA::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) +{ + CRYPTOPP_UNUSED(size); + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(seq, version, INTEGER, 1, 1); // check version + + BERGeneralDecoder dec(seq, OCTET_STRING); + if (!dec.IsDefiniteLength()) + BERDecodeError(); + Integer x; + x.Decode(dec, (size_t)dec.RemainingLength()); + dec.MessageEnd(); + if (!parametersPresent && seq.PeekByte() != (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + BERDecodeError(); + if (!seq.EndReached() && seq.PeekByte() == (CONTEXT_SPECIFIC | CONSTRUCTED | 0)) + { + BERGeneralDecoder parameters(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 0); + this->AccessGroupParameters().BERDecode(parameters); + parameters.MessageEnd(); + } + if (!seq.EndReached()) + { + // skip over the public element + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERGeneralDecoder publicKey(seq, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + BERDecodeBitString(publicKey, subjectPublicKey, unusedBits); + publicKey.MessageEnd(); + Element Q; + if (!(unusedBits == 0 && this->GetGroupParameters().GetCurve().DecodePoint(Q, subjectPublicKey, subjectPublicKey.size()))) + BERDecodeError(); + } + seq.MessageEnd(); + + this->SetPrivateExponent(x); +} + +template +void DL_PrivateKey_ECGDSA::DEREncodePrivateKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + DEREncodeUnsigned(privateKey, 1); // version + // SEC 1 ver 1.0 says privateKey (m_d) has the same length as order of the curve + // this will be changed to order of base point in a future version + this->GetPrivateExponent().DEREncodeAsOctetString(privateKey, this->GetGroupParameters().GetSubgroupOrder().ByteCount()); + privateKey.MessageEnd(); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/eccrypto.h b/extension/third_party/cryptopp/eccrypto.h new file mode 100644 index 00000000..7fce9cfa --- /dev/null +++ b/extension/third_party/cryptopp/eccrypto.h @@ -0,0 +1,667 @@ +// eccrypto.h - originally written and placed in the public domain by Wei Dai +// deterministic signatures added by by Douglas Roark + +/// \file eccrypto.h +/// \brief Classes and functions for Elliptic Curves over prime and binary fields + +#ifndef CRYPTOPP_ECCRYPTO_H +#define CRYPTOPP_ECCRYPTO_H + +#include "config.h" +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "hmac.h" +#include "sha.h" +#include "gfpcrypt.h" +#include "dh.h" +#include "mqv.h" +#include "hmqv.h" +#include "fhmqv.h" +#include "ecp.h" +#include "ec2n.h" + +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve Parameters +/// \tparam EC elliptic curve field +/// \details This class corresponds to the ASN.1 sequence of the same name +/// in ANSI X9.62 and SEC 1. EC is currently defined for ECP and EC2N. +template +class DL_GroupParameters_EC : public DL_GroupParametersImpl > +{ + typedef DL_GroupParameters_EC ThisClass; + +public: + typedef EC EllipticCurve; + typedef typename EllipticCurve::Point Point; + typedef Point Element; + typedef IncompatibleCofactorMultiplication DefaultCofactorOption; + + virtual ~DL_GroupParameters_EC() {} + + /// \brief Construct an EC GroupParameters + DL_GroupParameters_EC() : m_compress(false), m_encodeAsOID(true) {} + + /// \brief Construct an EC GroupParameters + /// \param oid the OID of a curve + DL_GroupParameters_EC(const OID &oid) + : m_compress(false), m_encodeAsOID(true) {Initialize(oid);} + + /// \brief Construct an EC GroupParameters + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + DL_GroupParameters_EC(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + : m_compress(false), m_encodeAsOID(true) {Initialize(ec, G, n, k);} + + /// \brief Construct an EC GroupParameters + /// \param bt BufferedTransformation with group parameters + DL_GroupParameters_EC(BufferedTransformation &bt) + : m_compress(false), m_encodeAsOID(true) {BERDecode(bt);} + + /// \brief Initialize an EC GroupParameters using {EC,G,n,k} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + { + this->m_groupPrecomputation.SetCurve(ec); + this->SetSubgroupGenerator(G); + m_n = n; + m_k = k; + } + + /// \brief Initialize a DL_GroupParameters_EC {EC,G,n,k} + /// \param oid the OID of a curve + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const OID &oid); + + // NameValuePairs + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GeneratibleCryptoMaterial interface + /// this implementation doesn't actually generate a curve, it just initializes the parameters with existing values + /*! parameters: (Curve, SubgroupGenerator, SubgroupOrder, Cofactor (optional)), or (GroupOID) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // DL_GroupParameters + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;} + const Integer & GetSubgroupOrder() const {return m_n;} + Integer GetCofactor() const; + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const; + bool FastSubgroupCheckAvailable() const {return false;} + void EncodeElement(bool reversible, const Element &element, byte *encoded) const + { + if (reversible) + GetCurve().EncodePoint(encoded, element, m_compress); + else + element.x.Encode(encoded, GetEncodedElementSize(false)); + } + virtual unsigned int GetEncodedElementSize(bool reversible) const + { + if (reversible) + return GetCurve().EncodedPointSize(m_compress); + else + return GetCurve().GetField().MaxElementByteLength(); + } + Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const + { + Point result; + if (!GetCurve().DecodePoint(result, encoded, GetEncodedElementSize(true))) + throw DL_BadElement(); + if (checkForGroupMembership && !ValidateElement(1, result, NULLPTR)) + throw DL_BadElement(); + return result; + } + Integer ConvertElementToInteger(const Element &element) const; + Integer GetMaxExponent() const {return GetSubgroupOrder()-1;} + bool IsIdentity(const Element &element) const {return element.identity;} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "EC";} + + // ASN1Key + OID GetAlgorithmID() const; + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + + // non-inherited + + // enumerate OIDs for recommended parameters, use OID() to get first one + static OID CRYPTOPP_API GetNextRecommendedParametersOID(const OID &oid); + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void SetPointCompression(bool compress) {m_compress = compress;} + bool GetPointCompression() const {return m_compress;} + + void SetEncodeAsOID(bool encodeAsOID) {m_encodeAsOID = encodeAsOID;} + bool GetEncodeAsOID() const {return m_encodeAsOID;} + + const EllipticCurve& GetCurve() const {return this->m_groupPrecomputation.GetCurve();} + + bool operator==(const ThisClass &rhs) const + {return this->m_groupPrecomputation.GetCurve() == rhs.m_groupPrecomputation.GetCurve() && this->m_gpc.GetBase(this->m_groupPrecomputation) == rhs.m_gpc.GetBase(rhs.m_groupPrecomputation);} + +protected: + unsigned int FieldElementLength() const {return GetCurve().GetField().MaxElementByteLength();} + unsigned int ExponentLength() const {return m_n.ByteCount();} + + OID m_oid; // set if parameters loaded from a recommended curve + Integer m_n; // order of base point + mutable Integer m_k; // cofactor + mutable bool m_compress, m_encodeAsOID; // presentation details +}; + +inline std::ostream& operator<<(std::ostream& os, const DL_GroupParameters_EC::Element& obj); + +/// \brief Elliptic Curve Discrete Log (DL) public key +/// \tparam EC elliptic curve field +template +class DL_PublicKey_EC : public DL_PublicKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_EC() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve Discrete Log (DL) private key +/// \tparam EC elliptic curve field +template +class DL_PrivateKey_EC : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_EC(); + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + {this->AccessGroupParameters() = params; this->SetPrivateExponent(x);} + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPrivateExponent(x);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey_EC::~DL_PrivateKey_EC() {} + +/// \brief Elliptic Curve Diffie-Hellman +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Diffie-Hellman, AKA ECDH +/// \since Crypto++ 3.0 +template ::DefaultCofactorOption> +struct ECDH +{ + typedef DH_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Menezes-Qu-Vanstone, AKA ECMQV +template ::DefaultCofactorOption> +struct ECMQV +{ + typedef MQV_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECHMQV +{ + typedef HMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECHMQV160; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECHMQV256; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECHMQV384; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECHMQV512; + +/// \brief Fully Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECFHMQV +{ + typedef FHMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECFHMQV160; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECFHMQV256; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECFHMQV384; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECFHMQV512; + +/// \brief Elliptic Curve Discrete Log (DL) keys +/// \tparam EC elliptic curve field +template +struct DL_Keys_EC +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_EC PrivateKey; +}; + +// Forward declaration; documented below +template +struct ECDSA; + +/// \brief Elliptic Curve DSA keys +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +struct DL_Keys_ECDSA +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA > PrivateKey; +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm based on RFC 6979 +/// \tparam EC elliptic curve field +/// \sa RFC 6979, Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECDSA_RFC6979 : public DL_Algorithm_DSA_RFC6979 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA-RFC6979";} +}; + +/// \brief Elliptic Curve NR (ECNR) signature algorithm +/// \tparam EC elliptic curve field +template +class DL_Algorithm_ECNR : public DL_Algorithm_NR +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECNR";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa ECDSA +/// \since Crypto++ 3.2 +template +struct ECDSA : public DL_SS, DL_Algorithm_ECDSA, DL_SignatureMessageEncodingMethod_DSA, H> +{ +}; + +/// \brief Elliptic Curve DSA (ECDSA) deterministic signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +struct ECDSA_RFC6979 : public DL_SS< + DL_Keys_ECDSA, + DL_Algorithm_ECDSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + ECDSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECDSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// \brief Elliptic Curve NR (ECNR) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +template +struct ECNR : public DL_SS, DL_Algorithm_ECNR, DL_SignatureMessageEncodingMethod_NR, H> +{ +}; + +// ****************************************** + +template +class DL_PublicKey_ECGDSA; +template +class DL_PrivateKey_ECGDSA; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PrivateKey_ECGDSA : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_ECGDSA() {} + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + { + this->AccessGroupParameters() = params; + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=params.GetSubgroupOrder()-1); + } + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + { + this->AccessGroupParameters().Initialize(ec, G, n); + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=this->AccessGroupParameters().GetSubgroupOrder()-1); + } + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + virtual void MakePublicKey(DL_PublicKey_ECGDSA &pub) const + { + const DL_GroupParameters& params = this->GetAbstractGroupParameters(); + pub.AccessAbstractGroupParameters().AssignFrom(params); + const Integer &xInv = this->GetPrivateExponent().InverseMod(params.GetSubgroupOrder()); + pub.SetPublicElement(params.ExponentiateBase(xInv)); + CRYPTOPP_ASSERT(xInv.NotZero()); + } + + virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper, + DL_PrivateKey_ECGDSA >(this, name, valueType, pValue).Assignable(); + } + + virtual void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper, + DL_PrivateKey_ECGDSA >(this, source); + } + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PublicKey_ECGDSA : public DL_PublicKeyImpl > +{ + typedef DL_PublicKey_ECGDSA ThisClass; + +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_ECGDSA() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + virtual void AssignFrom(const NameValuePairs &source) + { + DL_PrivateKey_ECGDSA *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } + } + + // DL_PublicKey + virtual void SetPublicElement(const Element &y) + {this->AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA keys for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +struct DL_Keys_ECGDSA +{ + typedef DL_PublicKey_ECGDSA PublicKey; + typedef DL_PrivateKey_ECGDSA PrivateKey; +}; + +/// \brief Elliptic Curve German DSA signature algorithm +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECGDSA : public DL_Algorithm_GDSA_ISO15946 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECGDSA";} +}; + +/// \brief Elliptic Curve German Digital Signature Algorithm signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf The Digital Signature Scheme +/// ECGDSA (October 24, 2006) +/// \since Crypto++ 6.0 +template +struct ECGDSA : public DL_SS< + DL_Keys_ECGDSA, + DL_Algorithm_ECGDSA, + DL_SignatureMessageEncodingMethod_DSA, + H> +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECGDSA-ISO15946/") + H::StaticAlgorithmName();} +}; + +// ****************************************** + +/// \brief Elliptic Curve Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details ECIES is an Elliptic Curve based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation +/// Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the +/// security provided by the MAC. The hash is also used in the key derivation function as a PRF. +/// \details Below is an example of constructing a Crypto++ 4.2 compatible ECIES encryptor and decryptor. +///
+///     AutoSeededRandomPool prng;
+///     DL_PrivateKey_EC key;
+///     key.Initialize(prng, ASN1::secp160r1());
+///
+///     ECIES::Decryptor decryptor(key);
+///     ECIES::Encryptor encryptor(decryptor);
+/// 
+/// \sa DLIES, Elliptic Curve Integrated Encryption Scheme (ECIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct ECIES + : public DL_ES< + DL_Keys_EC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + ECIES > +{ + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES";} +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eccrypto.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/ecp.cpp b/extension/third_party/cryptopp/ecp.cpp new file mode 100644 index 00000000..643ba70a --- /dev/null +++ b/extension/third_party/cryptopp/ecp.cpp @@ -0,0 +1,506 @@ +// ecp.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "ecp.h" +#include "asn.h" +#include "integer.h" +#include "nbtheory.h" +#include "modarith.h" +#include "filters.h" +#include "algebra.cpp" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::ECP; +using CryptoPP::Integer; +using CryptoPP::ModularArithmetic; + +#if defined(HAVE_GCC_INIT_PRIORITY) + #define INIT_ATTRIBUTE __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 50))) + const ECP::Point g_identity INIT_ATTRIBUTE = ECP::Point(); +#elif defined(HAVE_MSC_INIT_PRIORITY) + #pragma warning(disable: 4075) + #pragma init_seg(".CRT$XCU") + const ECP::Point g_identity; + #pragma warning(default: 4075) +#elif defined(HAVE_XLC_INIT_PRIORITY) + #pragma priority(290) + const ECP::Point g_identity; +#endif + +inline ECP::Point ToMontgomery(const ModularArithmetic &mr, const ECP::Point &P) +{ + return P.identity ? P : ECP::Point(mr.ConvertIn(P.x), mr.ConvertIn(P.y)); +} + +inline ECP::Point FromMontgomery(const ModularArithmetic &mr, const ECP::Point &P) +{ + return P.identity ? P : ECP::Point(mr.ConvertOut(P.x), mr.ConvertOut(P.y)); +} + +inline Integer IdentityToInteger(bool val) +{ + return val ? Integer::One() : Integer::Zero(); +} + +struct ProjectivePoint +{ + ProjectivePoint() {} + ProjectivePoint(const Integer &x, const Integer &y, const Integer &z) + : x(x), y(y), z(z) {} + + Integer x, y, z; +}; + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +ECP::ECP(const ECP &ecp, bool convertToMontgomeryRepresentation) +{ + if (convertToMontgomeryRepresentation && !ecp.GetField().IsMontgomeryRepresentation()) + { + m_fieldPtr.reset(new MontgomeryRepresentation(ecp.GetField().GetModulus())); + m_a = GetField().ConvertIn(ecp.m_a); + m_b = GetField().ConvertIn(ecp.m_b); + } + else + operator=(ecp); +} + +ECP::ECP(BufferedTransformation &bt) + : m_fieldPtr(new Field(bt)) +{ + BERSequenceDecoder seq(bt); + GetField().BERDecodeElement(seq, m_a); + GetField().BERDecodeElement(seq, m_b); + // skip optional seed + if (!seq.EndReached()) + { + SecByteBlock seed; + unsigned int unused; + BERDecodeBitString(seq, seed, unused); + } + seq.MessageEnd(); +} + +void ECP::DEREncode(BufferedTransformation &bt) const +{ + GetField().DEREncode(bt); + DERSequenceEncoder seq(bt); + GetField().DEREncodeElement(seq, m_a); + GetField().DEREncodeElement(seq, m_b); + seq.MessageEnd(); +} + +bool ECP::DecodePoint(ECP::Point &P, const byte *encodedPoint, size_t encodedPointLen) const +{ + StringStore store(encodedPoint, encodedPointLen); + return DecodePoint(P, store, encodedPointLen); +} + +bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const +{ + byte type; + if (encodedPointLen < 1 || !bt.Get(type)) + return false; + + switch (type) + { + case 0: + P.identity = true; + return true; + case 2: + case 3: + { + if (encodedPointLen != EncodedPointSize(true)) + return false; + + Integer p = FieldSize(); + + P.identity = false; + P.x.Decode(bt, GetField().MaxElementByteLength()); + P.y = ((P.x*P.x+m_a)*P.x+m_b) % p; + + if (Jacobi(P.y, p) !=1) + return false; + + P.y = ModularSquareRoot(P.y, p); + + if ((type & 1) != P.y.GetBit(0)) + P.y = p-P.y; + + return true; + } + case 4: + { + if (encodedPointLen != EncodedPointSize(false)) + return false; + + unsigned int len = GetField().MaxElementByteLength(); + P.identity = false; + P.x.Decode(bt, len); + P.y.Decode(bt, len); + return true; + } + default: + return false; + } +} + +void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + if (P.identity) + NullStore().TransferTo(bt, EncodedPointSize(compressed)); + else if (compressed) + { + bt.Put((byte)(2U + P.y.GetBit(0))); + P.x.Encode(bt, GetField().MaxElementByteLength()); + } + else + { + unsigned int len = GetField().MaxElementByteLength(); + bt.Put(4U); // uncompressed + P.x.Encode(bt, len); + P.y.Encode(bt, len); + } +} + +void ECP::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const +{ + ArraySink sink(encodedPoint, EncodedPointSize(compressed)); + EncodePoint(sink, P, compressed); + CRYPTOPP_ASSERT(sink.TotalPutLength() == EncodedPointSize(compressed)); +} + +ECP::Point ECP::BERDecodePoint(BufferedTransformation &bt) const +{ + SecByteBlock str; + BERDecodeOctetString(bt, str); + Point P; + if (!DecodePoint(P, str, str.size())) + BERDecodeError(); + return P; +} + +void ECP::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const +{ + SecByteBlock str(EncodedPointSize(compressed)); + EncodePoint(str, P, compressed); + DEREncodeOctetString(bt, str); +} + +bool ECP::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const +{ + Integer p = FieldSize(); + + bool pass = p.IsOdd(); + pass = pass && !m_a.IsNegative() && m_a

= 1) + pass = pass && ((4*m_a*m_a*m_a+27*m_b*m_b)%p).IsPositive(); + + if (level >= 2) + pass = pass && VerifyPrime(rng, p); + + return pass; +} + +bool ECP::VerifyPoint(const Point &P) const +{ + const FieldElement &x = P.x, &y = P.y; + Integer p = FieldSize(); + return P.identity || + (!x.IsNegative() && x

().Ref(); +#endif +} + +const ECP::Point& ECP::Inverse(const Point &P) const +{ + if (P.identity) + return P; + else + { + m_R.identity = false; + m_R.x = P.x; + m_R.y = GetField().Inverse(P.y); + return m_R; + } +} + +const ECP::Point& ECP::Add(const Point &P, const Point &Q) const +{ + if (P.identity) return Q; + if (Q.identity) return P; + if (GetField().Equal(P.x, Q.x)) + return GetField().Equal(P.y, Q.y) ? Double(P) : Identity(); + + FieldElement t = GetField().Subtract(Q.y, P.y); + t = GetField().Divide(t, GetField().Subtract(Q.x, P.x)); + FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), Q.x); + m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +const ECP::Point& ECP::Double(const Point &P) const +{ + if (P.identity || P.y==GetField().Identity()) return Identity(); + + FieldElement t = GetField().Square(P.x); + t = GetField().Add(GetField().Add(GetField().Double(t), t), m_a); + t = GetField().Divide(t, GetField().Double(P.y)); + FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), P.x); + m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y); + + m_R.x.swap(x); + m_R.identity = false; + return m_R; +} + +template void ParallelInvert(const AbstractRing &ring, Iterator begin, Iterator end) +{ + size_t n = end-begin; + if (n == 1) + *begin = ring.MultiplicativeInverse(*begin); + else if (n > 1) + { + std::vector vec((n+1)/2); + unsigned int i; + Iterator it; + + for (i=0, it=begin; i::iterator it) : it(it) {} + Integer& operator*() {return it->z;} + int operator-(ZIterator it2) {return int(it-it2.it);} + ZIterator operator+(int i) {return ZIterator(it+i);} + ZIterator& operator+=(int i) {it+=i; return *this;} + std::vector::iterator it; +}; + +ECP::Point ECP::ScalarMultiply(const Point &P, const Integer &k) const +{ + Element result; + if (k.BitCount() <= 5) + AbstractGroup::SimultaneousMultiply(&result, P, &k, 1); + else + ECP::SimultaneousMultiply(&result, P, &k, 1); + return result; +} + +void ECP::SimultaneousMultiply(ECP::Point *results, const ECP::Point &P, const Integer *expBegin, unsigned int expCount) const +{ + if (!GetField().IsMontgomeryRepresentation()) + { + ECP ecpmr(*this, true); + const ModularArithmetic &mr = ecpmr.GetField(); + ecpmr.SimultaneousMultiply(results, ToMontgomery(mr, P), expBegin, expCount); + for (unsigned int i=0; i bases; + std::vector exponents; + exponents.reserve(expCount); + std::vector > baseIndices(expCount); + std::vector > negateBase(expCount); + std::vector > exponentWindows(expCount); + unsigned int i; + + for (i=0; iNotNegative()); + exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 5)); + exponents[i].FindNextWindow(); + } + + unsigned int expBitPosition = 0; + bool notDone = true; + + while (notDone) + { + notDone = false; + bool baseAdded = false; + for (i=0; i > finalCascade; + for (i=0; i::CascadeScalarMultiply(P, k1, Q, k2); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ecp.h b/extension/third_party/cryptopp/ecp.h new file mode 100644 index 00000000..a5bdcd94 --- /dev/null +++ b/extension/third_party/cryptopp/ecp.h @@ -0,0 +1,167 @@ +// ecp.h - originally written and placed in the public domain by Wei Dai + +/// \file ecp.h +/// \brief Classes for Elliptic Curves over prime fields + +#ifndef CRYPTOPP_ECP_H +#define CRYPTOPP_ECP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(p), where p is prime +class CRYPTOPP_DLL ECP : public AbstractGroup, public EncodedPoint +{ +public: + typedef ModularArithmetic Field; + typedef Integer FieldElement; + typedef ECPPoint Point; + + virtual ~ECP() {} + + /// \brief Construct an ECP + ECP() {} + + /// \brief Construct an ECP + /// \param ecp the other ECP object + /// \param convertToMontgomeryRepresentation flag indicating if the curve + /// should be converted to a MontgomeryRepresentation. + /// \details Prior to Crypto++ 8.3 the default value for + /// convertToMontgomeryRepresentation was false. it was changed due to + /// two audit tools finding, "Signature-compatible with a copy constructor". + /// \sa ModularArithmetic, MontgomeryRepresentation + ECP(const ECP &ecp, bool convertToMontgomeryRepresentation); + + /// \brief Construct an ECP + /// \param modulus the prime modulus + /// \param a Field::Element + /// \param b Field::Element + ECP(const Integer &modulus, const FieldElement &a, const FieldElement &b) + : m_fieldPtr(new Field(modulus)), m_a(a.IsNegative() ? modulus+a : a), m_b(b) {} + + /// \brief Construct an ECP from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the the fields + /// fieldID and curve of the sequence ECParameters + ECP(BufferedTransformation &bt); + + /// \brief DER Encode + /// \param bt BufferedTransformation derived object + /// \details DEREncode encode the fields fieldID and curve of the sequence + /// ECParameters + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Compare two points + /// \param P the first point + /// \param Q the second point + /// \return true if equal, false otherwise + bool Equal(const Point &P, const Point &Q) const; + + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + Point ScalarMultiply(const Point &P, const Integer &k) const; + Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const; + void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*GetField().MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return GetField().GetModulus();} + const Field & GetField() const {return *m_fieldPtr;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const ECP &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_fieldPtr; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief ECP precomputation specialization +/// \details Implementation of DL_GroupPrecomputation with input and output +/// conversions for Montgomery modular multiplication. +/// \sa DL_GroupPrecomputation, ModularArithmetic, MontgomeryRepresentation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef ECP EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));}; + Element ConvertOut(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));} + const AbstractGroup & GetGroup() const {return *m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec->BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec->DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const ECP &ec) + { + m_ec.reset(new ECP(ec, true)); + m_ecOriginal = ec; + } + + /// \brief Get the elliptic curve + /// \return ECP curve + /// \details GetCurve() is not inherited + const ECP & GetCurve() const {return *m_ecOriginal;} + +private: + value_ptr m_ec, m_ecOriginal; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/ecpoint.h b/extension/third_party/cryptopp/ecpoint.h new file mode 100644 index 00000000..1fe3820f --- /dev/null +++ b/extension/third_party/cryptopp/ecpoint.h @@ -0,0 +1,146 @@ +// ecpoint.h - written and placed in the public domain by Jeffrey Walton +// Data structures moved from ecp.h and ec2n.h. Added EncodedPoint interface + +/// \file ecpoint.h +/// \brief Classes for Elliptic Curve points +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_ECPOINT_H +#define CRYPTOPP_ECPOINT_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "gf2n.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptical Curve Point over GF(p), where p is prime +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL ECPPoint +{ + virtual ~ECPPoint() {} + + /// \brief Construct an ECPPoint + /// \details identity is set to true + ECPPoint() : identity(true) {} + + /// \brief Construct an ECPPoint from coordinates + /// \details identity is set to false + ECPPoint(const Integer &x, const Integer &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \return true if the points are equal, false otherwise + bool operator==(const ECPPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \return true if this point is less than other, false otherwise + bool operator< (const ECPPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Elliptical Curve Point over GF(2^n) +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL EC2NPoint +{ + virtual ~EC2NPoint() {} + + /// \brief Construct an EC2NPoint + /// \details identity is set to true + EC2NPoint() : identity(true) {} + + /// \brief Construct an EC2NPoint from coordinates + /// \details identity is set to false + EC2NPoint(const PolynomialMod2 &x, const PolynomialMod2 &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \return true if the points are equal, false otherwise + bool operator==(const EC2NPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \return true if this point is less than other, false otherwise + bool operator< (const EC2NPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Abstract class for encoding and decoding ellicptic curve points +/// \tparam Point ellicptic curve point +/// \details EncodedPoint is an interface for encoding and decoding elliptic curve points. +/// The template parameter Point should be a class like ECP or EC2N. +/// \since Crypto++ 6.0 +template +class EncodedPoint +{ +public: + virtual ~EncodedPoint() {} + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param bt source BufferedTransformation + /// \param len number of bytes to read from the BufferedTransformation + /// \return true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const =0; + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array with the encoded point + /// \param len the size of the array + /// \return true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const =0; + + /// \brief Verifies points on elliptic curve + /// \param P point to verify + /// \return true if the point is valid, false otherwise + virtual bool VerifyPoint(const Point &P) const =0; + + /// \brief Determines encoded point size + /// \param compressed flag indicating if the point is compressed + /// \return the minimum number of bytes required to encode the point + virtual unsigned int EncodedPointSize(bool compressed = false) const =0; + + /// \brief Encodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array for the encoded point + /// \param compressed flag indicating if the point is compressed + /// \details encodedPoint must be at least EncodedPointSize() in length + virtual void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const =0; + + /// \brief Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; + + /// \brief BER Decodes an elliptic curve point + /// \param bt source BufferedTransformation + /// \return the decoded elliptic curve point + virtual Point BERDecodePoint(BufferedTransformation &bt) const =0; + + /// \brief DER Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_ECPOINT_H diff --git a/extension/third_party/cryptopp/elgamal.cpp b/extension/third_party/cryptopp/elgamal.cpp new file mode 100644 index 00000000..9871c538 --- /dev/null +++ b/extension/third_party/cryptopp/elgamal.cpp @@ -0,0 +1,22 @@ +// elgamal.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "elgamal.h" +#include "asn.h" +#include "nbtheory.h" + +// Squash MS LNK4221 and libtool warnings +extern const char ELGAMAL_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ElGamal_TestInstantiations() +{ + ElGamalEncryptor test1(1, 1, 1); + ElGamalDecryptor test2(NullRNG(), 123); + ElGamalEncryptor test3(test2); +} +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/elgamal.h b/extension/third_party/cryptopp/elgamal.h new file mode 100644 index 00000000..8c37769d --- /dev/null +++ b/extension/third_party/cryptopp/elgamal.h @@ -0,0 +1,304 @@ +// elgamal.h - originally written and placed in the public domain by Wei Dai + +/// \file elgamal.h +/// \brief Classes and functions for ElGamal key agreement and encryption schemes + +#ifndef CRYPTOPP_ELGAMAL_H +#define CRYPTOPP_ELGAMAL_H + +#include "cryptlib.h" +#include "modexppc.h" +#include "integer.h" +#include "gfpcrypt.h" +#include "pubkey.h" +#include "misc.h" +#include "oids.h" +#include "dsa.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ElGamal key agreement and encryption schemes base class +/// \since Crypto++ 1.0 +class CRYPTOPP_NO_VTABLE ElGamalBase : + public DL_KeyAgreementAlgorithm_DH, + public DL_KeyDerivationAlgorithm, + public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~ElGamalBase() {} + + void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const + { + CRYPTOPP_UNUSED(groupParams); CRYPTOPP_UNUSED(ephemeralPublicKey); + CRYPTOPP_UNUSED(derivationParams); + agreedElement.Encode(derivedKey, derivedLength); + } + + size_t GetSymmetricKeyLength(size_t plainTextLength) const + { + CRYPTOPP_UNUSED(plainTextLength); + return GetGroupParameters().GetModulus().ByteCount(); + } + + size_t GetSymmetricCiphertextLength(size_t plainTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (plainTextLength <= GetMaxSymmetricPlaintextLength(len)) + return len; + else + return 0; + } + + size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + CRYPTOPP_ASSERT(len >= 3); + + if (cipherTextLength == len) + return STDMIN(255U, len-3); + else + return 0; + } + + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + SecByteBlock block(modulusLen-1); + rng.GenerateBlock(block, modulusLen-2-plainTextLength); + memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength); + block[modulusLen-2] = (byte)plainTextLength; + + a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen); + } + + DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + if (cipherTextLength != modulusLen) + return DecodingResult(); + + Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p); + + m.Encode(plainText, 1); + unsigned int plainTextLength = plainText[0]; + if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen)) + return DecodingResult(); + m >>= 8; + m.Encode(plainText, plainTextLength); + return DecodingResult(plainTextLength); + } + + virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0; +}; + +/// \brief ElGamal key agreement and encryption schemes default implementation +/// \tparam BASE Base class implementation +/// \tparam SCHEME_OPTIONS Scheme options +/// \tparam KEY ElGamal key classes +/// \since Crypto++ 1.0 +template +class ElGamalObjectImpl : + public DL_ObjectImplBase, + public ElGamalBase +{ +public: + virtual ~ElGamalObjectImpl() {} + + size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());} + size_t FixedCiphertextLength() const {return this->CiphertextLength(0);} + + const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();} + + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const + {return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);} + +protected: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const {return *this;} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const {return *this;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;} +}; + +/// \brief ElGamal Public Key adapter +/// \tparam BASE PublicKey derived class +/// \details DL_PublicKey_ElGamal provides an override for GetAlgorithmID() +/// to utilize 1.3.14.7.2.1.1. Prior to DL_PublicKey_ElGamal, the ElGamal +/// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 8.3 +template +struct DL_PublicKey_ElGamal : public BASE +{ + virtual ~DL_PublicKey_ElGamal() {} + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() + /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal + /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). + /// If you need to Load an ElGamal key with the wrong OID then + /// see ElGamal on + /// the Crypto++ wiki. + /// \sa Issue 876, + /// Issue 567 + virtual OID GetAlgorithmID() const { + return ASN1::elGamal(); + } +}; + +/// \brief ElGamal Private Key adapter +/// \tparam BASE PrivateKey derived class +/// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() +/// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal +/// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 8.3 +template +struct DL_PrivateKey_ElGamal : public BASE +{ + virtual ~DL_PrivateKey_ElGamal() {} + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() + /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal + /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). + /// If you need to Load an ElGamal key with the wrong OID then + /// see ElGamal on + /// the Crypto++ wiki. + /// \sa Issue 876, + /// Issue 567 + virtual OID GetAlgorithmID() const { + return ASN1::elGamal(); + } + + /// \brief Check the key for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///

    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other + /// operations correctly + ///
  • 2 - ensure this object will function correctly, and perform + /// reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may + /// take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can + /// be used for level 0. Level 1 may not check for weak keys and such. + /// Levels 2 and 3 are recommended. + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + // Validate() formerly used DL_PrivateKey_GFP implementation through + // inheritance. However, it would reject keys from other libraries + // like BouncyCastle. The failure was x < q. According to ElGamal's + // paper and the HAC, the private key is selected in over [1,p-1], + // Later Tsiounis and Yung showed the lower limit as [1,q-1] in + // "On the Security of EIGamal Based Encryption". As such, Crypto++ + // will generate a key in the range [1,q-1], but accept a key + // in [1,p-1]. Thanks to JPM for finding the reference. Also see + // https://github.com/weidai11/cryptopp/commit/a5a684d92986. + + CRYPTOPP_ASSERT(this->GetAbstractGroupParameters().Validate(rng, level)); + bool pass = this->GetAbstractGroupParameters().Validate(rng, level); + + const Integer &p = this->GetGroupParameters().GetModulus(); + const Integer &q = this->GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = this->GetPrivateExponent(); + + // Changed to x < p-1 based on ElGamal's paper and the HAC. + CRYPTOPP_ASSERT(x.IsPositive()); + CRYPTOPP_ASSERT(x < p-1); + pass = pass && x.IsPositive() && x < p-1; + + if (level >= 1) + { + // Minimum security level due to Tsiounis and Yung. + CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One()); + pass = pass && Integer::Gcd(x, q) == Integer::One(); + } + return pass; + } +}; + +/// \brief ElGamal key agreement and encryption schemes keys +/// \details ElGamalKeys provide the algorithm implementation ElGamal key +/// agreement and encryption schemes. +/// \details The ElGamalKeys class used DL_PrivateKey_GFP_OldFormat +/// and DL_PublicKey_GFP_OldFormat for the PrivateKey and +/// PublicKey from about Crypto++ 1.0 through Crypto++ 5.6.5. At +/// Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and +/// X509 encodings. +/// \details The ElGamalKeys class [mistakenly] used the OID for DSA from +/// about Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was +/// fixed and now uses ElGamal encryption, which is 1.3.14.7.2.1.1. +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 1.0 +struct ElGamalKeys +{ + /// \brief Implements DL_GroupParameters interface + typedef DL_CryptoKeys_GFP::GroupParameters GroupParameters; + /// \brief Implements DL_PrivateKey interface + typedef DL_PrivateKey_ElGamal PrivateKey; + /// \brief Implements DL_PublicKey interface + typedef DL_PublicKey_ElGamal PublicKey; +}; + +/// \brief ElGamal encryption scheme with non-standard padding +/// \details ElGamal provide the algorithm implementation ElGamal key +/// agreement and encryption schemes. +/// \details The ElGamal class [mistakenly] used the OID for DSA from about +/// Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was fixed +/// and now uses ElGamal encryption, which is 1.3.14.7.2.1.1. +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 1.0 +struct ElGamal +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + typedef SchemeOptions::PrivateKey PrivateKey; + typedef SchemeOptions::PublicKey PublicKey; + + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";} + + /// \brief Implements DL_GroupParameters interface + typedef SchemeOptions::GroupParameters GroupParameters; + /// \brief Implements PK_Encryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PublicKey> > Encryptor; + /// \brief Implements PK_Encryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor; +}; + +typedef ElGamal::Encryptor ElGamalEncryptor; +typedef ElGamal::Decryptor ElGamalDecryptor; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/emsa2.cpp b/extension/third_party/cryptopp/emsa2.cpp new file mode 100644 index 00000000..dd5173dd --- /dev/null +++ b/extension/third_party/cryptopp/emsa2.cpp @@ -0,0 +1,44 @@ +// emsa2.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "emsa2.h" + +#ifndef CRYPTOPP_IMPORTS + +NAMESPACE_BEGIN(CryptoPP) + +// Inclusion based on DLL due to Clang, http://github.com/weidai11/cryptopp/issues/300 +#ifndef CRYPTOPP_IS_DLL +template<> const byte EMSA2HashId::id = 0x33; +template<> const byte EMSA2HashId::id = 0x38; +template<> const byte EMSA2HashId::id = 0x34; +template<> const byte EMSA2HashId::id = 0x36; +template<> const byte EMSA2HashId::id = 0x35; +#endif + +void EMSA2Pad::ComputeMessageRepresentative(RandomNumberGenerator& /*rng*/, + const byte* recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength), CRYPTOPP_UNUSED(representativeBitLength); + CRYPTOPP_ASSERT(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize())); + + if (representativeBitLength % 8 != 7) + throw PK_SignatureScheme::InvalidKeyLength("EMSA2: EMSA2 requires a key length that is a multiple of 8"); + + size_t digestSize = hash.DigestSize(); + size_t representativeByteLength = BitsToBytes(representativeBitLength); + + representative[0] = messageEmpty ? 0x4b : 0x6b; + memset(representative+1, 0xbb, representativeByteLength-digestSize-4); // pad with 0xbb + byte *afterP2 = representative+representativeByteLength-digestSize-3; + afterP2[0] = 0xba; + hash.Final(afterP2+1); + representative[representativeByteLength-2] = *hashIdentifier.first; + representative[representativeByteLength-1] = 0xcc; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/emsa2.h b/extension/third_party/cryptopp/emsa2.h new file mode 100644 index 00000000..0db5ea34 --- /dev/null +++ b/extension/third_party/cryptopp/emsa2.h @@ -0,0 +1,101 @@ +// emsa2.h - originally written and placed in the public domain by Wei Dai + +/// \file emsa2.h +/// \brief Classes and functions for various padding schemes used in public key algorithms + +#ifndef CRYPTOPP_EMSA2_H +#define CRYPTOPP_EMSA2_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" +#include "misc.h" + +#ifdef CRYPTOPP_IS_DLL +# include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EMSA2 hash identifier +/// \tparam H HashTransformation derived class +/// \since Crypto++ 5.0 +template class EMSA2HashId +{ +public: + static const byte id; +}; + +/// \brief EMSA2 padding method +/// \tparam BASE Message encoding method +/// \since Crypto++ 5.0 +template +class EMSA2HashIdLookup : public BASE +{ +public: + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(&EMSA2HashId::id, 1); + } + }; + }; +}; + +// EMSA2HashId can be instantiated with the following classes. +// SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, Whirlpool + +#ifdef CRYPTOPP_IS_DLL +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +#endif + +/// \brief EMSA2 padding method +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL EMSA2Pad : public EMSA2HashIdLookup +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA2";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); return 8*digestLength + 31;} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +// EMSA2, for use with RWSS and RSA_ISO +// Only the following hash functions are supported by this signature standard: +// \dontinclude emsa2.h +// \skip EMSA2HashId can be instantiated +// \until end of list + +/// \brief EMSA2/P1363 padding method +/// \details Use with RWSS and RSA_ISO +/// \since Crypto++ 5.0 +struct P1363_EMSA2 : public SignatureStandard +{ + typedef EMSA2Pad SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/eprecomp.cpp b/extension/third_party/cryptopp/eprecomp.cpp new file mode 100644 index 00000000..75103089 --- /dev/null +++ b/extension/third_party/cryptopp/eprecomp.cpp @@ -0,0 +1,114 @@ +// eprecomp.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "eprecomp.h" +#include "integer.h" +#include "algebra.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +template void DL_FixedBasePrecomputationImpl::SetBase(const DL_GroupPrecomputation &group, const Element &i_base) +{ + m_base = group.NeedConversions() ? group.ConvertIn(i_base) : i_base; + + if (m_bases.empty() || !(m_base == m_bases[0])) + { + m_bases.resize(1); + m_bases[0] = m_base; + } + + if (group.NeedConversions()) + m_base = i_base; +} + +template void DL_FixedBasePrecomputationImpl::Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) +{ + CRYPTOPP_ASSERT(m_bases.size() > 0); + CRYPTOPP_ASSERT(storage <= maxExpBits); + + if (storage > 1) + { + m_windowSize = (maxExpBits+storage-1)/storage; + m_exponentBase = Integer::Power2(m_windowSize); + } + + m_bases.resize(storage); + for (unsigned i=1; i void DL_FixedBasePrecomputationImpl::Load(const DL_GroupPrecomputation &group, BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + word32 version; + BERDecodeUnsigned(seq, version, INTEGER, 1, 1); + m_exponentBase.BERDecode(seq); + m_windowSize = m_exponentBase.BitCount() - 1; + m_bases.clear(); + while (!seq.EndReached()) + m_bases.push_back(group.BERDecodeElement(seq)); + if (!m_bases.empty() && group.NeedConversions()) + m_base = group.ConvertOut(m_bases[0]); + seq.MessageEnd(); +} + +template void DL_FixedBasePrecomputationImpl::Save(const DL_GroupPrecomputation &group, BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + DEREncodeUnsigned(seq, 1); // version + m_exponentBase.DEREncode(seq); + for (unsigned i=0; i void DL_FixedBasePrecomputationImpl::PrepareCascade(const DL_GroupPrecomputation &i_group, std::vector > &eb, const Integer &exponent) const +{ + const AbstractGroup &group = i_group.GetGroup(); + + Integer r, q, e = exponent; + bool fastNegate = group.InversionIsFast() && m_windowSize > 1; + unsigned int i; + + for (i=0; i+1(group.Inverse(m_bases[i]), m_exponentBase - r)); + } + else + eb.push_back(BaseAndExponent(m_bases[i], r)); + } + eb.push_back(BaseAndExponent(m_bases[i], e)); +} + +template T DL_FixedBasePrecomputationImpl::Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const +{ + std::vector > eb; // array of segments of the exponent and precalculated bases + eb.reserve(m_bases.size()); + PrepareCascade(group, eb, exponent); + return group.ConvertOut(GeneralCascadeMultiplication(group.GetGroup(), eb.begin(), eb.end())); +} + +template T + DL_FixedBasePrecomputationImpl::CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, + const DL_FixedBasePrecomputation &i_pc2, const Integer &exponent2) const +{ + std::vector > eb; // array of segments of the exponent and precalculated bases + const DL_FixedBasePrecomputationImpl &pc2 = static_cast &>(i_pc2); + eb.reserve(m_bases.size() + pc2.m_bases.size()); + PrepareCascade(group, eb, exponent); + pc2.PrepareCascade(group, eb, exponent2); + return group.ConvertOut(GeneralCascadeMultiplication(group.GetGroup(), eb.begin(), eb.end())); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/eprecomp.h b/extension/third_party/cryptopp/eprecomp.h new file mode 100644 index 00000000..d91d41d3 --- /dev/null +++ b/extension/third_party/cryptopp/eprecomp.h @@ -0,0 +1,162 @@ +// eprecomp.h - originally written and placed in the public domain by Wei Dai + +/// \file eprecomp.h +/// \brief Classes for precomputation in a group + +#ifndef CRYPTOPP_EPRECOMP_H +#define CRYPTOPP_EPRECOMP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DL_GroupPrecomputation interface +/// \tparam T Field element +template +class DL_GroupPrecomputation +{ +public: + typedef T Element; + + virtual ~DL_GroupPrecomputation() {} + + /// \brief Determines if elements needs conversion + /// \return true if the element needs conversion, false otherwise + /// \details NeedConversions determines if an element must convert between representations. + virtual bool NeedConversions() const {return false;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \return an element converted to an alternate representation for internal use + /// \details ConvertIn is used when an element must convert between representations. + virtual Element ConvertIn(const Element &v) const {return v;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \return an element converted from an alternate representation + virtual Element ConvertOut(const Element &v) const {return v;} + + /// \brief Retrieves AbstractGroup interface + /// \return GetGroup() returns the AbstractGroup interface + virtual const AbstractGroup & GetGroup() const =0; + + /// \brief Decodes element in DER format + /// \param bt BufferedTransformation object + /// \return element in the group + virtual Element BERDecodeElement(BufferedTransformation &bt) const =0; + + /// \brief Encodes element in DER format + /// \param bt BufferedTransformation object + /// \param P Element to encode + virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0; +}; + +/// \brief DL_FixedBasePrecomputation interface +/// \tparam T Field element +template +class DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputation() {} + + /// \brief Determines whether this object is initialized + /// \return true if this object is initialized, false otherwise + virtual bool IsInitialized() const =0; + + /// \brief Set the base element + /// \param group the group + /// \param base element in the group + virtual void SetBase(const DL_GroupPrecomputation &group, const Element &base) =0; + + /// \brief Get the base element + /// \param group the group + /// \return base element in the group + virtual const Element & GetBase(const DL_GroupPrecomputation &group) const =0; + + /// \brief Perform precomputation + /// \param group the group + /// \param maxExpBits used to calculate the exponent base + /// \param storage the suggested number of objects for the precompute table + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) =0; + + /// \brief Retrieve previously saved precomputation + /// \param group the the group + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) =0; + + /// \brief Save precomputation for later use + /// \param group the the group + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const =0; + + /// \brief Exponentiates an element + /// \param group the group + /// \param exponent the exponent + /// \return the result of the exponentiation + virtual Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const =0; + + /// \brief Exponentiates an element + /// \param pc1 the first the group precomputation + /// \param exponent1 the first exponent + /// \param pc2 the second the group precomputation + /// \param exponent2 the first exponent2 + /// \return the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const =0; +}; + +/// \brief DL_FixedBasePrecomputation adapter class +/// \tparam T Field element +template +class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputationImpl() {} + + DL_FixedBasePrecomputationImpl() : m_windowSize(0) {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const + {return !m_bases.empty();} + void SetBase(const DL_GroupPrecomputation &group, const Element &base); + const Element & GetBase(const DL_GroupPrecomputation &group) const + {return group.NeedConversions() ? m_base : m_bases[0];} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage); + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation); + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const; + Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const; + +private: + void PrepareCascade(const DL_GroupPrecomputation &group, std::vector > &eb, const Integer &exponent) const; + + Element m_base; + unsigned int m_windowSize; + Integer m_exponentBase; // what base to represent the exponent in + std::vector m_bases; // precalculated bases +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eprecomp.cpp" +#endif + +#endif diff --git a/extension/third_party/cryptopp/esign.cpp b/extension/third_party/cryptopp/esign.cpp new file mode 100644 index 00000000..7c69a684 --- /dev/null +++ b/extension/third_party/cryptopp/esign.cpp @@ -0,0 +1,233 @@ +// esign.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +// TODO: fix the C4589 warnings +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4589) +#endif + +#include "esign.h" +#include "modarith.h" +#include "integer.h" +#include "nbtheory.h" +#include "algparam.h" +#include "sha.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ESIGN_TestInstantiations() +{ + ESIGN::Verifier x1(1, 1); + ESIGN::Signer x2(NullRNG(), 1); + ESIGN::Verifier x3(x2); + ESIGN::Verifier x4(x2.GetKey()); + ESIGN::Verifier x5(x3); + ESIGN::Signer x6 = x2; + + x6 = x2; + x3 = ESIGN::Verifier(x2); + x4 = x2.GetKey(); +} +#endif + +void ESIGNFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_e.BERDecode(seq); + seq.MessageEnd(); +} + +void ESIGNFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + seq.MessageEnd(); +} + +Integer ESIGNFunction::ApplyFunction(const Integer &x) const +{ + DoQuickSanityCheck(); + return STDMIN(a_exp_b_mod_c(x, m_e, m_n) >> (2*GetK()+2), MaxImage()); +} + +bool ESIGNFunction::Validate(RandomNumberGenerator& rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(level); + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + CRYPTOPP_ASSERT(pass); + pass = pass && m_e >= 8 && m_e < m_n; + CRYPTOPP_ASSERT(pass); + return pass; +} + +bool ESIGNFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void ESIGNFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** + +void InvertibleESIGNFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶m) +{ + int modulusSize = 1023*2; + param.GetIntValue("ModulusSize", modulusSize) || param.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 24) + throw InvalidArgument("InvertibleESIGNFunction: specified modulus size is too small"); + + if (modulusSize % 3 != 0) + throw InvalidArgument("InvertibleESIGNFunction: modulus size must be divisible by 3"); + + m_e = param.GetValueWithDefault("PublicExponent", Integer(32)); + + if (m_e < 8) + throw InvalidArgument("InvertibleESIGNFunction: public exponents less than 8 may not be secure"); + + // VC70 workaround: putting these after primeParam causes overlapped stack allocation + ConstByteArrayParameter seedParam; + SecByteBlock seed; + + const Integer minP = Integer(204) << (modulusSize/3-8); + const Integer maxP = Integer::Power2(modulusSize/3)-1; + AlgorithmParameters primeParam = MakeParameters("Min", minP)("Max", maxP)("RandomNumberType", Integer::PRIME); + + if (param.GetValue("Seed", seedParam)) + { + seed.resize(seedParam.size() + 4); + memcpy(seed + 4, seedParam.begin(), seedParam.size()); + + PutWord(false, BIG_ENDIAN_ORDER, seed, (word32)0); + m_p.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("Seed", ConstByteArrayParameter(seed)))); + PutWord(false, BIG_ENDIAN_ORDER, seed, (word32)1); + m_q.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("Seed", ConstByteArrayParameter(seed)))); + } + else + { + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + } + + m_n = m_p * m_p * m_q; + + CRYPTOPP_ASSERT(m_n.BitCount() == (unsigned int)modulusSize); +} + +void InvertibleESIGNFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder privateKey(bt); + m_n.BERDecode(privateKey); + m_e.BERDecode(privateKey); + m_p.BERDecode(privateKey); + m_q.BERDecode(privateKey); + privateKey.MessageEnd(); +} + +void InvertibleESIGNFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + m_n.DEREncode(privateKey); + m_e.DEREncode(privateKey); + m_p.DEREncode(privateKey); + m_q.DEREncode(privateKey); + privateKey.MessageEnd(); +} + +Integer InvertibleESIGNFunction::CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + DoQuickSanityCheck(); + + Integer pq = m_p * m_q; + Integer p2 = m_p * m_p; + Integer r, z, re, a, w0, w1; + + do + { + r.Randomize(rng, Integer::Zero(), pq); + z = x << (2*GetK()+2); + re = a_exp_b_mod_c(r, m_e, m_n); + a = (z - re) % m_n; + Integer::Divide(w1, w0, a, pq); + if (w1.NotZero()) + { + ++w0; + w1 = pq - w1; + } + } + while ((w1 >> (2*GetK()+1)).IsPositive()); + + ModularArithmetic modp(m_p); + Integer t = modp.Divide(w0 * r % m_p, m_e * re % m_p); + Integer s = r + t*pq; + CRYPTOPP_ASSERT(s < m_n); +#if 0 + using namespace std; + cout << "f = " << x << endl; + cout << "r = " << r << endl; + cout << "z = " << z << endl; + cout << "a = " << a << endl; + cout << "w0 = " << w0 << endl; + cout << "w1 = " << w1 << endl; + cout << "t = " << t << endl; + cout << "s = " << s << endl; +#endif + return s; +} + +bool InvertibleESIGNFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = ESIGNFunction::Validate(rng, level); + CRYPTOPP_ASSERT(pass); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_p.BitCount() == m_q.BitCount(); + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && m_p * m_p * m_q == m_n; + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool InvertibleESIGNFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + ; +} + +void InvertibleESIGNFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + ; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/esign.h b/extension/third_party/cryptopp/esign.h new file mode 100644 index 00000000..274c1810 --- /dev/null +++ b/extension/third_party/cryptopp/esign.h @@ -0,0 +1,169 @@ +// esign.h - originally written and placed in the public domain by Wei Dai + +/// \file esign.h +/// \brief Classes providing ESIGN signature schemes as defined in IEEE P1363a +/// \since Crypto++ 5.0 + +#ifndef CRYPTOPP_ESIGN_H +#define CRYPTOPP_ESIGN_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ESIGN trapdoor function using the public key +/// \since Crypto++ 5.0 +class ESIGNFunction : public TrapdoorFunction, public ASN1CryptoMaterial +{ + typedef ESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return Integer::Power2(GetK());} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + // Covertiy finding on overflow. The library allows small values for research purposes. + unsigned int GetK() const {return SaturatingSubtract(m_n.BitCount()/3, 1U);} + + Integer m_n, m_e; +}; + +/// \brief ESIGN trapdoor function using the private key +/// \since Crypto++ 5.0 +class InvertibleESIGNFunction : public ESIGNFunction, public RandomizedTrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN private key with {n,e,p,q} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q) + {m_n = n; m_e = e; m_p = p; m_q = q;} + + /// \brief Create a ESIGN private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulud, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + // Squash Visual Studio C4250 warning + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + // Squash Visual Studio C4250 warning + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + +protected: + Integer m_p, m_q; +}; + +/// \brief EMSA5 padding method +/// \tparam T Mask Generation Function +/// \since Crypto++ 5.0 +template +class EMSA5Pad : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EMSA5";} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const + { + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + SecByteBlock digest(hash.DigestSize()); + hash.Final(digest); + size_t representativeByteLength = BitsToBytes(representativeBitLength); + T mgf; + mgf.GenerateAndMask(hash, representative, representativeByteLength, digest, digest.size(), false); + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); + } +}; + +/// \brief EMSA5 padding method, for use with ESIGN +/// \since Crypto++ 5.0 +struct P1363_EMSA5 : public SignatureStandard +{ + typedef EMSA5Pad SignatureMessageEncodingMethod; +}; + +/// \brief ESIGN keys +/// \since Crypto++ 5.0 +struct ESIGN_Keys +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ESIGN";} + typedef ESIGNFunction PublicKey; + typedef InvertibleESIGNFunction PrivateKey; +}; + +/// \brief ESIGN signature scheme, IEEE P1363a +/// \tparam H HashTransformation derived class +/// \tparam STANDARD Signature encoding method +/// \since Crypto++ 5.0 +template +struct ESIGN : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/factory.h b/extension/third_party/cryptopp/factory.h new file mode 100644 index 00000000..d3d36e3c --- /dev/null +++ b/extension/third_party/cryptopp/factory.h @@ -0,0 +1,179 @@ +// factory.h - originally written and placed in the public domain by Wei Dai + +/// \file factory.h +/// \brief Classes and functions for registering and locating library objects + +#ifndef CRYPTOPP_OBJFACT_H +#define CRYPTOPP_OBJFACT_H + +#include "cryptlib.h" +#include "misc.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Object factory interface for registering objects +/// \tparam AbstractClass Base class interface of the object +template +class ObjectFactory +{ +public: + virtual ~ObjectFactory () {} + virtual AbstractClass * CreateObject() const =0; +}; + +/// \brief Object factory for registering objects +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +template +class DefaultObjectFactory : public ObjectFactory +{ +public: + AbstractClass * CreateObject() const + { + return new ConcreteClass; + } +}; + +/// \brief Object factory registry +/// \tparam AbstractClass Base class interface of the object +/// \tparam instance unique identifier +template +class ObjectFactoryRegistry +{ +public: + class FactoryNotFound : public Exception + { + public: + FactoryNotFound(const char *name) : Exception(OTHER_ERROR, std::string("ObjectFactoryRegistry: could not find factory for algorithm ") + name) {} + }; + + ~ObjectFactoryRegistry() + { + for (typename Map::iterator i = m_map.begin(); i != m_map.end(); ++i) + { + delete (ObjectFactory *)i->second; + i->second = NULLPTR; + } + } + + void RegisterFactory(const std::string &name, ObjectFactory *factory) + { + m_map[name] = factory; + } + + const ObjectFactory * GetFactory(const char *name) const + { + typename Map::const_iterator i = m_map.find(name); + return i == m_map.end() ? NULLPTR : (ObjectFactory *)i->second; + } + + AbstractClass *CreateObject(const char *name) const + { + const ObjectFactory *factory = GetFactory(name); + if (!factory) + throw FactoryNotFound(name); + return factory->CreateObject(); + } + + // Return a vector containing the factory names. This is easier than returning an iterator. + // from Andrew Pitonyak + std::vector GetFactoryNames() const + { + std::vector names; + typename Map::const_iterator iter; + for (iter = m_map.begin(); iter != m_map.end(); ++iter) + names.push_back(iter->first); + return names; + } + + CRYPTOPP_NOINLINE static ObjectFactoryRegistry & Registry(CRYPTOPP_NOINLINE_DOTDOTDOT); + +private: + // use void * instead of ObjectFactory * to save code size + typedef std::map Map; + Map m_map; +}; + +template +ObjectFactoryRegistry & ObjectFactoryRegistry::Registry(CRYPTOPP_NOINLINE_DOTDOTDOT) +{ + static ObjectFactoryRegistry s_registry; + return s_registry; +} + +/// \brief Object factory registry helper +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +/// \tparam instance unique identifier +template +struct RegisterDefaultFactoryFor +{ + RegisterDefaultFactoryFor(const char *name=NULLPTR) + { + // BCB2006 workaround + std::string n = name ? std::string(name) : std::string(ConcreteClass::StaticAlgorithmName()); + ObjectFactoryRegistry::Registry(). + RegisterFactory(n, new DefaultObjectFactory); + } +}; + +/// \fn RegisterAsymmetricCipherDefaultFactories +/// \brief Register asymmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAsymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSignatureSchemeDefaultFactories +/// \brief Register signature schemes +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSignatureSchemeDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSymmetricCipherDefaultFactories +/// \brief Register symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterAuthenticatedSymmetricCipherDefaultFactories +/// \brief Register authenticated symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAuthenticatedSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/fhmqv.h b/extension/third_party/cryptopp/fhmqv.h new file mode 100644 index 00000000..e247e1f2 --- /dev/null +++ b/extension/third_party/cryptopp/fhmqv.h @@ -0,0 +1,408 @@ +// fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal +// Shamelessly based upon Wei Dai's MQV source files + +#ifndef CRYPTOPP_FHMQV_H +#define CRYPTOPP_FHMQV_H + +/// \file fhmqv.h +/// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class FHMQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef FHMQV_Domain Domain; + + virtual ~FHMQV_Domain() {} + + /// \brief Construct a FHMQV domain + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) {} + + /// \brief Construct a FHMQV domain + /// \param params group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + /// \brief Construct a FHMQV domain + /// \param bt BufferedTransformation with group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 is passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const + {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + this->GetMaterial().DoQuickSanityCheck(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = ephemeralOtherPublicKey; + xxs = EphemeralPublicKeyLength(); + YY = ephemeralPrivateKey + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = staticOtherPublicKey; + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = ephemeralPrivateKey + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = ephemeralOtherPublicKey; + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = staticOtherPublicKey; + bbs = StaticPublicKeyLength(); + } + + Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true); + + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + SecByteBlock dd(len), ee(len); + + Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + Integer d(dd.BytePtr(), dd.SizeInBytes()); + + Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes()); + Integer e(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t1 = params.ExponentiateElement(B, e); + Element t2 = m_groupParameters.MultiplyElements(Y, t1); + + sigma = params.ExponentiateElement(t2, s_A); + } + + Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + CRYPTOPP_ASSERT(0); + return false; + } + return true; + } + +protected: + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, const byte* e2, size_t e2len, + const byte* s1, size_t s1len, const byte* s2, size_t s2len, + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + //SecByteBlock sbb(x.MinEncodedSize()); + //x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false)); + GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } + + hash.Update(e1, e1len); + hash.Update(e2, e2len); + hash.Update(s1, s1len); + hash.Update(s2, s2len); + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole { RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const{return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef FHMQV_Domain FHMQV; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/files.cpp b/extension/third_party/cryptopp/files.cpp new file mode 100644 index 00000000..79ea6418 --- /dev/null +++ b/extension/third_party/cryptopp/files.cpp @@ -0,0 +1,302 @@ +// files.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "files.h" + +#include +#include +#include + +ANONYMOUS_NAMESPACE_BEGIN + +/// \brief Disable badbit, failbit and eof exceptions +/// \sa https://github.com/weidai11/cryptopp/pull/968 and +/// https://www.cplusplus.com/reference/ios/ios/exceptions +class IosExceptionMask +{ +public: + IosExceptionMask(std::istream& stream) : m_stream(stream) { + m_mask = m_stream.exceptions(); + m_stream.exceptions(static_cast(0)); + } + + IosExceptionMask(std::istream& stream, std::ios::iostate newMask) : m_stream(stream) { + m_mask = m_stream.exceptions(); + m_stream.exceptions(newMask); + } + + ~IosExceptionMask() { + m_stream.exceptions(m_mask); + } + +private: + std::istream& m_stream; + std::ios::iostate m_mask; +}; + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void Files_TestInstantiations() +{ + FileStore f0; + FileSource f1; + FileSink f2; +} +#endif + +void FileStore::StoreInitialize(const NameValuePairs ¶meters) +{ + m_waiting = false; + m_stream = NULLPTR; + m_file.release(); + + const char *fileName = NULLPTR; +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + const wchar_t *fileNameWide = NULLPTR; + if (!parameters.GetValue(Name::InputFileNameWide(), fileNameWide)) +#endif + if (!parameters.GetValue(Name::InputFileName(), fileName)) + { + parameters.GetValue(Name::InputStreamPointer(), m_stream); + return; + } + + std::ios::openmode binary = parameters.GetValueWithDefault(Name::InputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0); + m_file.reset(new std::ifstream); +#ifdef CRYPTOPP_UNIX_AVAILABLE + std::string narrowed; + if (fileNameWide) + fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); +#endif +#if _MSC_VER >= 1400 + if (fileNameWide) + { + m_file->open(fileNameWide, std::ios::in | binary); + if (!*m_file) + throw OpenErr(StringNarrow(fileNameWide, false)); + } +#endif + if (fileName) + { + m_file->open(fileName, std::ios::in | binary); + if (!*m_file) + throw OpenErr(fileName); + } + m_stream = m_file.get(); +} + +lword FileStore::MaxRetrievable() const +{ + if (!m_stream) + return 0; + + // Disable badbit, failbit and eof exceptions + IosExceptionMask guard(*m_stream); + + // Clear error bits due to seekg(). Also see + // https://github.com/weidai11/cryptopp/pull/968 + std::streampos current = m_stream->tellg(); + std::streampos end = m_stream->seekg(0, std::ios::end).tellg(); + m_stream->clear(); + m_stream->seekg(current); + m_stream->clear(); + + // Return max for a non-seekable stream + // https://www.cplusplus.com/reference/istream/istream/tellg + if (end == static_cast(-1)) + return LWORD_MAX; + + return end-current; +} + +size_t FileStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + if (!m_stream) + { + transferBytes = 0; + return 0; + } + + lword size=transferBytes; + transferBytes = 0; + + if (m_waiting) + goto output; + + while (size && m_stream->good()) + { + { + size_t spaceSize = 1024; + m_space = HelpCreatePutSpace(target, channel, 1, UnsignedMin(size_t(SIZE_MAX), size), spaceSize); + + m_stream->read((char *)m_space, (unsigned int)STDMIN(size, (lword)spaceSize)); + } + m_len = (size_t)m_stream->gcount(); + size_t blockedBytes; +output: + blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking); + m_waiting = blockedBytes > 0; + if (m_waiting) + return blockedBytes; + size -= m_len; + transferBytes += m_len; + } + + if (!m_stream->good() && !m_stream->eof()) + throw ReadErr(); + + return 0; +} + +size_t FileStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + if (!m_stream) + return 0; + + if (begin == 0 && end == 1) + { + int result = m_stream->peek(); + if (result == std::char_traits::eof()) + return 0; + else + { + size_t blockedBytes = target.ChannelPut(channel, byte(result), blocking); + begin += 1-blockedBytes; + return blockedBytes; + } + } + + // TODO: figure out what happens on cin + std::streampos current = m_stream->tellg(); + std::streampos endPosition = m_stream->seekg(0, std::ios::end).tellg(); + std::streampos newPosition = current + static_cast(begin); + + if (newPosition >= endPosition) + { + m_stream->seekg(current); + return 0; // don't try to seek beyond the end of file + } + m_stream->seekg(newPosition); + try + { + CRYPTOPP_ASSERT(!m_waiting); + lword copyMax = end-begin; + size_t blockedBytes = const_cast(this)->TransferTo2(target, copyMax, channel, blocking); + begin += copyMax; + if (blockedBytes) + { + const_cast(this)->m_waiting = false; + return blockedBytes; + } + } + catch(...) + { + m_stream->clear(); + m_stream->seekg(current); + throw; + } + m_stream->clear(); + m_stream->seekg(current); + + return 0; +} + +lword FileStore::Skip(lword skipMax) +{ + if (!m_stream) + return 0; + + lword oldPos = m_stream->tellg(); + std::istream::off_type offset; + if (!SafeConvert(skipMax, offset)) + throw InvalidArgument("FileStore: maximum seek offset exceeded"); + m_stream->seekg(offset, std::ios::cur); + return (lword)m_stream->tellg() - oldPos; +} + +void FileSink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_stream = NULLPTR; + m_file.release(); + + const char *fileName = NULLPTR; +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + const wchar_t *fileNameWide = NULLPTR; + if (!parameters.GetValue(Name::OutputFileNameWide(), fileNameWide)) +#endif + if (!parameters.GetValue(Name::OutputFileName(), fileName)) + { + parameters.GetValue(Name::OutputStreamPointer(), m_stream); + return; + } + + std::ios::openmode binary = parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0); + m_file.reset(new std::ofstream); +#ifdef CRYPTOPP_UNIX_AVAILABLE + std::string narrowed; + if (fileNameWide) + fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); +#elif (CRYPTOPP_MSC_VERSION >= 1400) + if (fileNameWide) + { + m_file->open(fileNameWide, std::ios::out | std::ios::trunc | binary); + if (!*m_file) + throw OpenErr(StringNarrow(fileNameWide, false)); + } +#endif + if (fileName) + { + m_file->open(fileName, std::ios::out | std::ios::trunc | binary); + if (!*m_file) + throw OpenErr(fileName); + } + m_stream = m_file.get(); +} + +bool FileSink::IsolatedFlush(bool hardFlush, bool blocking) +{ + CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking); + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + m_stream->flush(); + if (!m_stream->good()) + throw WriteErr(); + + return false; +} + +size_t FileSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + CRYPTOPP_UNUSED(blocking); + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + while (length > 0) + { + std::streamsize size; + if (!SafeConvert(length, size)) + size = ((std::numeric_limits::max)()); + m_stream->write((const char *)inString, size); + inString += size; + length -= (size_t)size; + } + + if (messageEnd) + m_stream->flush(); + + if (!m_stream->good()) + throw WriteErr(); + + return 0; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/files.h b/extension/third_party/cryptopp/files.h new file mode 100644 index 00000000..8ff5dc85 --- /dev/null +++ b/extension/third_party/cryptopp/files.h @@ -0,0 +1,181 @@ +// files.h - originally written and placed in the public domain by Wei Dai + +/// \file files.h +/// \brief Classes providing file-based library services +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_FILES_H +#define CRYPTOPP_FILES_H + +#include "cryptlib.h" +#include "filters.h" +#include "argnames.h" +#include "smartptr.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileStore : public Store, private FilterPutSpaceHelper, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}}; + /// \brief Exception thrown when file-based read error is encountered + class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}}; + + /// \brief Construct a FileStore + FileStore() : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) {} + + /// \brief Construct a FileStore + /// \param in an existing stream + FileStore(std::istream &in) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileStore + /// \param filename the narrow name of the file to open + FileStore(const char *filename) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputFileName(), filename ? filename : ""));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 + /// \brief Construct a FileStore + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileStore(const wchar_t *filename) + {StoreInitialize(MakeParameters(Name::InputFileNameWide(), filename));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::istream* GetStream() {return m_stream;} + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + const std::istream* GetStream() const {return m_stream;} + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + /// \details All retrieval functions return the actual number of bytes retrieved, which is + /// the lesser of the request number and MaxRetrievable() + lword MaxRetrievable() const; + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + lword Skip(lword skipMax=ULONG_MAX); + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + member_ptr m_file; + std::istream *m_stream; + byte *m_space; + size_t m_len; + bool m_waiting; +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileSource : public SourceTemplate +{ +public: + typedef FileStore::Err Err; + typedef FileStore::OpenErr OpenErr; + typedef FileStore::ReadErr ReadErr; + + /// \brief Construct a FileSource + FileSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a FileSource + /// \param in an existing stream + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileSource + /// \param filename the narrow name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(), filename)(Name::InputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || _MSC_VER >= 1400 + /// \brief Construct a FileSource + /// \param filename the Unicode name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSource(const wchar_t *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileNameWide(), filename)(Name::InputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::istream* GetStream() {return m_store.GetStream();} +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Sink interface +class CRYPTOPP_DLL FileSink : public Sink, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}}; + /// \brief Exception thrown when file-based write error is encountered + class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}}; + + /// \brief Construct a FileSink + FileSink() : m_stream(NULLPTR) {} + + /// \brief Construct a FileSink + /// \param out an existing stream + FileSink(std::ostream &out) + {IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(), &out));} + + /// \brief Construct a FileSink + /// \param filename the narrow name of the file to open + /// \param binary flag indicating if the file is binary + FileSink(const char *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileName(), filename)(Name::OutputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + /// \brief Construct a FileSink + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSink(const wchar_t *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileNameWide(), filename)(Name::OutputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::ostream* GetStream() {return m_stream;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +private: + member_ptr m_file; + std::ostream *m_stream; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/filters.cpp b/extension/third_party/cryptopp/filters.cpp new file mode 100644 index 00000000..4fff2a2f --- /dev/null +++ b/extension/third_party/cryptopp/filters.cpp @@ -0,0 +1,1270 @@ +// filters.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100 4189 4355) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunused-value" +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "filters.h" +#include "mqueue.h" +#include "fltrimpl.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +Filter::Filter(BufferedTransformation *attachment) + : m_attachment(attachment), m_inputPosition(0), m_continueAt(0) +{ +} + +BufferedTransformation * Filter::NewDefaultAttachment() const +{ + return new MessageQueue; +} + +BufferedTransformation * Filter::AttachedTransformation() +{ + if (m_attachment.get() == NULLPTR) + m_attachment.reset(NewDefaultAttachment()); + return m_attachment.get(); +} + +const BufferedTransformation *Filter::AttachedTransformation() const +{ + if (m_attachment.get() == NULLPTR) + const_cast(this)->m_attachment.reset(NewDefaultAttachment()); + return m_attachment.get(); +} + +void Filter::Detach(BufferedTransformation *newOut) +{ + m_attachment.reset(newOut); +} + +void Filter::Insert(Filter *filter) +{ + filter->m_attachment.reset(m_attachment.release()); + m_attachment.reset(filter); +} + +size_t Filter::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + return AttachedTransformation()->CopyRangeTo2(target, begin, end, channel, blocking); +} + +size_t Filter::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + return AttachedTransformation()->TransferTo2(target, transferBytes, channel, blocking); +} + +void Filter::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_inputPosition = m_continueAt = 0; + IsolatedInitialize(parameters); + PropagateInitialize(parameters, propagation); +} + +bool Filter::Flush(bool hardFlush, int propagation, bool blocking) +{ + switch (m_continueAt) + { + case 0: + if (IsolatedFlush(hardFlush, blocking)) + return true; + // fall through + case 1: + if (OutputFlush(1, hardFlush, propagation, blocking)) + return true; + // fall through + default: ; + } + return false; +} + +bool Filter::MessageSeriesEnd(int propagation, bool blocking) +{ + switch (m_continueAt) + { + case 0: + if (IsolatedMessageSeriesEnd(blocking)) + return true; + // fall through + case 1: + if (ShouldPropagateMessageSeriesEnd() && OutputMessageSeriesEnd(1, propagation, blocking)) + return true; + // fall through + default: ; + } + return false; +} + +void Filter::PropagateInitialize(const NameValuePairs ¶meters, int propagation) +{ + if (propagation) + AttachedTransformation()->Initialize(parameters, propagation-1); +} + +size_t Filter::OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel) +{ + if (messageEnd) + messageEnd--; + size_t result = AttachedTransformation()->ChannelPutModifiable2(channel, inString, length, messageEnd, blocking); + m_continueAt = result ? outputSite : 0; + return result; +} + +size_t Filter::Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel) +{ + if (messageEnd) + messageEnd--; + size_t result = AttachedTransformation()->ChannelPut2(channel, inString, length, messageEnd, blocking); + m_continueAt = result ? outputSite : 0; + return result; +} + +bool Filter::OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel) +{ + if (propagation && AttachedTransformation()->ChannelFlush(channel, hardFlush, propagation-1, blocking)) + { + m_continueAt = outputSite; + return true; + } + m_continueAt = 0; + return false; +} + +bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel) +{ + if (propagation && AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation-1, blocking)) + { + m_continueAt = outputSite; + return true; + } + m_continueAt = 0; + return false; +} + +// ************************************************************* + +void MeterFilter::ResetMeter() +{ + m_currentMessageBytes = m_totalBytes = m_currentSeriesMessages = m_totalMessages = m_totalMessageSeries = 0; + m_rangesToSkip.clear(); +} + +void MeterFilter::AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow) +{ + MessageRange r = {message, position, size}; + m_rangesToSkip.push_back(r); + if (sortNow) + std::sort(m_rangesToSkip.begin(), m_rangesToSkip.end()); +} + +size_t MeterFilter::PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable) +{ + if (!m_transparent) + return 0; + + size_t t; + FILTER_BEGIN; + + m_begin = begin; + m_length = length; + + while (m_length > 0 || messageEnd) + { + if (m_length > 0 && !m_rangesToSkip.empty() && m_rangesToSkip.front().message == m_totalMessages && m_currentMessageBytes + m_length > m_rangesToSkip.front().position) + { + FILTER_OUTPUT_MAYBE_MODIFIABLE(1, m_begin, t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position, m_currentMessageBytes), false, modifiable); + + CRYPTOPP_ASSERT(t < m_length); + m_begin = PtrAdd(m_begin, t); + m_length -= t; + m_currentMessageBytes += t; + m_totalBytes += t; + + if (m_currentMessageBytes + m_length < m_rangesToSkip.front().position + m_rangesToSkip.front().size) + t = m_length; + else + { + t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position + m_rangesToSkip.front().size, m_currentMessageBytes); + CRYPTOPP_ASSERT(t <= m_length); + m_rangesToSkip.pop_front(); + } + + m_begin = PtrAdd(m_begin, t); + m_length -= t; + m_currentMessageBytes += t; + m_totalBytes += t; + } + else + { + FILTER_OUTPUT_MAYBE_MODIFIABLE(2, m_begin, m_length, messageEnd, modifiable); + + m_currentMessageBytes += m_length; + m_totalBytes += m_length; + m_length = 0; + + if (messageEnd) + { + m_currentMessageBytes = 0; + m_currentSeriesMessages++; + m_totalMessages++; + messageEnd = false; + } + } + } + + FILTER_END_NO_MESSAGE_END; +} + +size_t MeterFilter::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + return PutMaybeModifiable(const_cast(begin), length, messageEnd, blocking, false); +} + +size_t MeterFilter::PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking) +{ + return PutMaybeModifiable(begin, length, messageEnd, blocking, true); +} + +bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking) +{ + CRYPTOPP_UNUSED(blocking); + m_currentMessageBytes = 0; + m_currentSeriesMessages = 0; + m_totalMessageSeries++; + return false; +} + +// ************************************************************* + +void FilterWithBufferedInput::BlockQueue::ResetQueue(size_t blockSize, size_t maxBlocks) +{ + m_buffer.New(blockSize * maxBlocks); + m_blockSize = blockSize; + m_maxBlocks = maxBlocks; + m_size = 0; + m_begin = m_buffer; +} + +byte *FilterWithBufferedInput::BlockQueue::GetBlock() +{ + if (m_size >= m_blockSize) + { + byte *ptr = m_begin; + if ((m_begin = PtrAdd(m_begin, m_blockSize)) == m_buffer.end()) + m_begin = m_buffer; + m_size -= m_blockSize; + return ptr; + } + else + return NULLPTR; +} + +byte *FilterWithBufferedInput::BlockQueue::GetContigousBlocks(size_t &numberOfBytes) +{ + numberOfBytes = STDMIN(numberOfBytes, STDMIN(PtrDiff(m_buffer.end(), m_begin), m_size)); + byte *ptr = m_begin; + m_begin = PtrAdd(m_begin, numberOfBytes); + m_size -= numberOfBytes; + if (m_size == 0 || m_begin == m_buffer.end()) + m_begin = m_buffer; + return ptr; +} + +size_t FilterWithBufferedInput::BlockQueue::GetAll(byte *outString) +{ + // Avoid passing NULL pointer to memcpy + if (!outString) return 0; + + size_t size = m_size; + size_t numberOfBytes = m_maxBlocks*m_blockSize; + const byte *ptr = GetContigousBlocks(numberOfBytes); + memcpy(outString, ptr, numberOfBytes); + memcpy(PtrAdd(outString, numberOfBytes), m_begin, m_size); + m_size = 0; + return size; +} + +void FilterWithBufferedInput::BlockQueue::Put(const byte *inString, size_t length) +{ + // Avoid passing NULL pointer to memcpy + if (!inString || !length) return; + + CRYPTOPP_ASSERT(m_size + length <= m_buffer.size()); + byte *end = (m_size < static_cast(PtrDiff(m_buffer.end(), m_begin)) ? + PtrAdd(m_begin, m_size) : PtrAdd(m_begin, m_size - m_buffer.size())); + size_t len = STDMIN(length, size_t(m_buffer.end()-end)); + memcpy(end, inString, len); + if (len < length) + memcpy(m_buffer, PtrAdd(inString, len), length-len); + m_size += length; +} + +FilterWithBufferedInput::FilterWithBufferedInput(BufferedTransformation *attachment) + : Filter(attachment), m_firstSize(SIZE_MAX), m_blockSize(0), m_lastSize(SIZE_MAX), m_firstInputDone(false) +{ +} + +FilterWithBufferedInput::FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment) + : Filter(attachment), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize), m_firstInputDone(false) +{ + if (m_firstSize == SIZE_MAX || m_blockSize < 1 || m_lastSize == SIZE_MAX) + throw InvalidArgument("FilterWithBufferedInput: invalid buffer size"); + + m_queue.ResetQueue(1, m_firstSize); +} + +void FilterWithBufferedInput::IsolatedInitialize(const NameValuePairs ¶meters) +{ + InitializeDerivedAndReturnNewSizes(parameters, m_firstSize, m_blockSize, m_lastSize); + if (m_firstSize == SIZE_MAX || m_blockSize < 1 || m_lastSize == SIZE_MAX) + throw InvalidArgument("FilterWithBufferedInput: invalid buffer size"); + m_queue.ResetQueue(1, m_firstSize); + m_firstInputDone = false; +} + +bool FilterWithBufferedInput::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("FilterWithBufferedInput"); + + if (hardFlush) + ForceNextPut(); + FlushDerived(); + + return false; +} + +size_t FilterWithBufferedInput::PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable) +{ + if (!blocking) + throw BlockingInputOnly("FilterWithBufferedInput"); + + if (length != 0) + { + size_t newLength = m_queue.CurrentSize() + length; + + if (!m_firstInputDone && newLength >= m_firstSize) + { + size_t len = m_firstSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + FirstPut(m_queue.GetContigousBlocks(m_firstSize)); + CRYPTOPP_ASSERT(m_queue.CurrentSize() == 0); + m_queue.ResetQueue(m_blockSize, (2*m_blockSize+m_lastSize-2)/m_blockSize); + + inString = PtrAdd(inString, len); + newLength -= m_firstSize; + m_firstInputDone = true; + } + + if (m_firstInputDone) + { + if (m_blockSize == 1) + { + while (newLength > m_lastSize && m_queue.CurrentSize() > 0) + { + size_t len = newLength - m_lastSize; + byte *ptr = m_queue.GetContigousBlocks(len); + NextPutModifiable(ptr, len); + newLength -= len; + } + + if (newLength > m_lastSize) + { + size_t len = newLength - m_lastSize; + NextPutMaybeModifiable(inString, len, modifiable); + inString = PtrAdd(inString, len); + newLength -= len; + } + } + else + { + while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize) + { + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0) + { + CRYPTOPP_ASSERT(m_queue.CurrentSize() < m_blockSize); + size_t len = m_blockSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + inString = PtrAdd(inString, len); + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + if (newLength >= m_blockSize + m_lastSize) + { + size_t len = RoundDownToMultipleOf(newLength - m_lastSize, m_blockSize); + NextPutMaybeModifiable(inString, len, modifiable); + inString = PtrAdd(inString, len); + newLength -= len; + } + } + } + + m_queue.Put(inString, newLength - m_queue.CurrentSize()); + } + + if (messageEnd) + { + if (!m_firstInputDone && m_firstSize==0) + FirstPut(NULLPTR); + + SecByteBlock temp(m_queue.CurrentSize()); + m_queue.GetAll(temp); + LastPut(temp, temp.size()); + + m_firstInputDone = false; + m_queue.ResetQueue(1, m_firstSize); + + // Cast to void to suppress Coverity finding + (void)Output(1, NULLPTR, 0, messageEnd, blocking); + } + return 0; +} + +void FilterWithBufferedInput::ForceNextPut() +{ + if (!m_firstInputDone) + return; + + if (m_blockSize > 1) + { + while (m_queue.CurrentSize() >= m_blockSize) + NextPutModifiable(m_queue.GetBlock(), m_blockSize); + } + else + { + size_t len; + while ((len = m_queue.CurrentSize()) > 0) + NextPutModifiable(m_queue.GetContigousBlocks(len), len); + } +} + +void FilterWithBufferedInput::NextPutMultiple(const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(m_blockSize > 1); // m_blockSize = 1 should always override this function + while (length > 0) + { + CRYPTOPP_ASSERT(length >= m_blockSize); + NextPutSingle(inString); + inString = PtrAdd(inString, m_blockSize); + length -= m_blockSize; + } +} + +// ************************************************************* + +void Redirector::Initialize(const NameValuePairs ¶meters, int propagation) +{ + m_target = parameters.GetValueWithDefault("RedirectionTargetPointer", (BufferedTransformation*)NULLPTR); + m_behavior = parameters.GetIntValueWithDefault("RedirectionBehavior", PASS_EVERYTHING); + + if (m_target && GetPassSignals()) + m_target->Initialize(parameters, propagation); +} + +// ************************************************************* + +ProxyFilter::ProxyFilter(BufferedTransformation *filter, size_t firstSize, size_t lastSize, BufferedTransformation *attachment) + : FilterWithBufferedInput(firstSize, 1, lastSize, attachment), m_filter(filter) +{ + if (m_filter.get()) + m_filter->Attach(new OutputProxy(*this, false)); +} + +bool ProxyFilter::IsolatedFlush(bool hardFlush, bool blocking) +{ + return m_filter.get() ? m_filter->Flush(hardFlush, -1, blocking) : false; +} + +void ProxyFilter::SetFilter(Filter *filter) +{ + m_filter.reset(filter); + if (filter) + { + OutputProxy *proxy; + member_ptr temp(proxy = new OutputProxy(*this, false)); + m_filter->TransferAllTo(*proxy); + m_filter->Attach(temp.release()); + } +} + +void ProxyFilter::NextPutMultiple(const byte *s, size_t len) +{ + if (m_filter.get()) + m_filter->Put(s, len); +} + +void ProxyFilter::NextPutModifiable(byte *s, size_t len) +{ + if (m_filter.get()) + m_filter->PutModifiable(s, len); +} + +// ************************************************************* + +void RandomNumberSink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("RandomNumberSink", "RandomNumberGeneratorPointer", m_rng); +} + +size_t RandomNumberSink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + m_rng->IncorporateEntropy(begin, length); + return 0; +} + +size_t ArraySink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + + // Avoid passing NULL pointer to memcpy. Using memmove due to + // Valgrind finding on overlapping buffers. + size_t copied = 0; + if (m_buf && begin) + { + copied = STDMIN(length, SaturatingSubtract(m_size, m_total)); + memmove(PtrAdd(m_buf, m_total), begin, copied); + } + m_total += copied; + return length - copied; +} + +byte * ArraySink::CreatePutSpace(size_t &size) +{ + size = SaturatingSubtract(m_size, m_total); + return PtrAdd(m_buf, m_total); +} + +void ArraySink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + ByteArrayParameter array; + if (!parameters.GetValue(Name::OutputBuffer(), array)) + throw InvalidArgument("ArraySink: missing OutputBuffer argument"); + m_buf = array.begin(); + m_size = array.size(); +} + +size_t ArrayXorSink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + + // Avoid passing NULL pointer to xorbuf + size_t copied = 0; + if (m_buf && begin) + { + copied = STDMIN(length, SaturatingSubtract(m_size, m_total)); + xorbuf(PtrAdd(m_buf, m_total), begin, copied); + } + m_total += copied; + return length - copied; +} + +// ************************************************************* + +StreamTransformationFilter::StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding) + : FilterWithBufferedInput(attachment), m_cipher(c), m_padding(DEFAULT_PADDING) +{ + CRYPTOPP_ASSERT(c.MinLastBlockSize() == 0 || c.MinLastBlockSize() > c.MandatoryBlockSize()); + + const bool authenticatedFilter = dynamic_cast(&c) != NULLPTR; + if (authenticatedFilter) + throw InvalidArgument("StreamTransformationFilter: please use AuthenticatedEncryptionFilter and AuthenticatedDecryptionFilter for AuthenticatedSymmetricCipher"); + + // InitializeDerivedAndReturnNewSizes may override some of these + m_mandatoryBlockSize = m_cipher.MandatoryBlockSize(); + m_optimalBufferSize = m_cipher.OptimalBlockSize(); + m_isSpecial = m_cipher.IsLastBlockSpecial() && m_mandatoryBlockSize > 1; + m_reservedBufferSize = STDMAX(2*m_mandatoryBlockSize, m_optimalBufferSize); + + FilterWithBufferedInput::IsolatedInitialize( + MakeParameters + (Name::BlockPaddingScheme(), padding)); +} + +StreamTransformationFilter::StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding, bool authenticated) + : FilterWithBufferedInput(attachment), m_cipher(c), m_padding(DEFAULT_PADDING) +{ + const bool authenticatedFilter = dynamic_cast(&c) != NULLPTR; + if (!authenticatedFilter) + { + CRYPTOPP_ASSERT(c.MinLastBlockSize() == 0 || c.MinLastBlockSize() > c.MandatoryBlockSize()); + } + + if (authenticatedFilter && !authenticated) + throw InvalidArgument("StreamTransformationFilter: please use AuthenticatedEncryptionFilter and AuthenticatedDecryptionFilter for AuthenticatedSymmetricCipher"); + + // InitializeDerivedAndReturnNewSizes may override some of these + m_mandatoryBlockSize = m_cipher.MandatoryBlockSize(); + m_optimalBufferSize = m_cipher.OptimalBlockSize(); + m_isSpecial = m_cipher.IsLastBlockSpecial() && m_mandatoryBlockSize > 1; + m_reservedBufferSize = STDMAX(2*m_mandatoryBlockSize, m_optimalBufferSize); + + FilterWithBufferedInput::IsolatedInitialize( + MakeParameters + (Name::BlockPaddingScheme(), padding)); +} + +size_t StreamTransformationFilter::LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding) +{ + if (c.MinLastBlockSize() > 0) + return c.MinLastBlockSize(); + else if (c.MandatoryBlockSize() > 1 && !c.IsForwardTransformation() && padding != NO_PADDING && padding != ZEROS_PADDING) + return c.MandatoryBlockSize(); + + return 0; +} + +void StreamTransformationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) +{ + BlockPaddingScheme padding = parameters.GetValueWithDefault(Name::BlockPaddingScheme(), DEFAULT_PADDING); + bool isBlockCipher = (m_mandatoryBlockSize > 1 && m_cipher.MinLastBlockSize() == 0); + + if (padding == DEFAULT_PADDING) + m_padding = isBlockCipher ? PKCS_PADDING : NO_PADDING; + else + m_padding = padding; + + if (!isBlockCipher) + { + if (m_padding == PKCS_PADDING) + throw InvalidArgument("StreamTransformationFilter: PKCS_PADDING cannot be used with " + m_cipher.AlgorithmName()); + else if (m_padding == W3C_PADDING) + throw InvalidArgument("StreamTransformationFilter: W3C_PADDING cannot be used with " + m_cipher.AlgorithmName()); + else if (m_padding == ONE_AND_ZEROS_PADDING) + throw InvalidArgument("StreamTransformationFilter: ONE_AND_ZEROS_PADDING cannot be used with " + m_cipher.AlgorithmName()); + } + + firstSize = 0; + blockSize = m_mandatoryBlockSize; + lastSize = LastBlockSize(m_cipher, m_padding); +} + +void StreamTransformationFilter::FirstPut(const byte* inString) +{ + CRYPTOPP_UNUSED(inString); + m_optimalBufferSize = STDMAX(m_optimalBufferSize, RoundDownToMultipleOf(4096U, m_optimalBufferSize)); +} + +void StreamTransformationFilter::NextPutMultiple(const byte *inString, size_t length) +{ + if (!length) + {return;} + + const size_t s = m_cipher.MandatoryBlockSize(); + do + { + size_t len = m_optimalBufferSize; + byte *space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, s, length, len); + if (len < length) + { + if (len == m_optimalBufferSize) + len -= m_cipher.GetOptimalBlockSizeUsed(); + len = RoundDownToMultipleOf(len, s); + } + else + len = length; + m_cipher.ProcessString(space, inString, len); + AttachedTransformation()->PutModifiable(space, len); + inString = PtrAdd(inString, len); + length -= len; + } + while (length > 0); +} + +void StreamTransformationFilter::NextPutModifiable(byte *inString, size_t length) +{ + m_cipher.ProcessString(inString, length); + AttachedTransformation()->PutModifiable(inString, length); +} + +void StreamTransformationFilter::LastPut(const byte *inString, size_t length) +{ + // This block is new to StreamTransformationFilter. It is somewhat of a hack and was + // added for OCB mode; see GitHub Issue 515. The rub with OCB is, its a block cipher + // and the last block size can be 0. However, "last block = 0" is not the 0 predicated + // in the original code. In the orginal code 0 means "nothing special" so + // DEFAULT_PADDING is applied. OCB's 0 literally means a final block size can be 0 or + // non-0; and no padding is needed in either case because OCB has its own scheme (see + // handling of P_* and A_*). + // Stream ciphers have policy objects to convey how to operate the cipher. The Crypto++ + // framework operates well when MinLastBlockSize() is 1. However, it did not appear to + // cover the OCB case either because we can't stream OCB. It needs full block sizes. In + // response we hacked a IsLastBlockSpecial(). When true StreamTransformationFilter + // defers to the mode for processing of the last block. + // The behavior supplied when IsLastBlockSpecial() will likely have to evolve to capture + // more complex cases from different authenc modes. I suspect it will have to change + // from a simple bool to something that conveys more information, like "last block + // no padding" or "custom padding applied by cipher". + // In some respect we have already hit the need for more information. For example, OCB + // calculates the checksum on the cipher text at the same time, so we don't need the + // disjoint behavior of calling "EncryptBlock" followed by a separate "AuthenticateBlock". + // Additional information may allow us to avoid the two separate calls. + if (m_isSpecial) + { + const size_t leftOver = length % m_mandatoryBlockSize; + byte* space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, m_reservedBufferSize); + length -= leftOver; + + if (length) + { + // Process full blocks + m_cipher.ProcessData(space, inString, length); + AttachedTransformation()->Put(space, length); + inString = PtrAdd(inString, length); + } + + if (leftOver) + { + // Process final partial block + length = m_cipher.ProcessLastBlock(space, m_reservedBufferSize, inString, leftOver); + AttachedTransformation()->Put(space, length); + } + else + { + // Process final empty block + length = m_cipher.ProcessLastBlock(space, m_reservedBufferSize, NULLPTR, 0); + AttachedTransformation()->Put(space, length); + } + + return; + } + + switch (m_padding) + { + case NO_PADDING: + case ZEROS_PADDING: + if (length > 0) + { + const size_t minLastBlockSize = m_cipher.MinLastBlockSize(); + const bool isForwardTransformation = m_cipher.IsForwardTransformation(); + + if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize)) + { + // do padding + size_t blockSize = STDMAX(minLastBlockSize, (size_t)m_mandatoryBlockSize); + byte* space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, blockSize); + if (inString) {memcpy(space, inString, length);} + memset(PtrAdd(space, length), 0, blockSize - length); + size_t used = m_cipher.ProcessLastBlock(space, blockSize, space, blockSize); + AttachedTransformation()->Put(space, used); + } + else + { + if (minLastBlockSize == 0) + { + if (isForwardTransformation) + throw InvalidDataFormat("StreamTransformationFilter: plaintext length is not a multiple of block size and NO_PADDING is specified"); + else + throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size"); + } + + byte* space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, m_optimalBufferSize); + size_t used = m_cipher.ProcessLastBlock(space, length, inString, length); + AttachedTransformation()->Put(space, used); + } + } + break; + + case PKCS_PADDING: + case W3C_PADDING: + case ONE_AND_ZEROS_PADDING: + unsigned int s; + byte* space; + s = m_mandatoryBlockSize; + CRYPTOPP_ASSERT(s > 1); + space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, s, m_optimalBufferSize); + if (m_cipher.IsForwardTransformation()) + { + CRYPTOPP_ASSERT(length < s); + if (inString) {memcpy(space, inString, length);} + if (m_padding == PKCS_PADDING) + { + CRYPTOPP_ASSERT(s < 256); + byte pad = static_cast(s-length); + memset(PtrAdd(space, length), pad, s-length); + } + else if (m_padding == W3C_PADDING) + { + CRYPTOPP_ASSERT(s < 256); + memset(PtrAdd(space, length), 0, s-length-1); + space[s-1] = static_cast(s-length); + } + else + { + space[length] = 0x80; + memset(PtrAdd(space, length+1), 0, s-length-1); + } + m_cipher.ProcessData(space, space, s); + AttachedTransformation()->Put(space, s); + } + else + { + if (length != s) + throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size"); + m_cipher.ProcessData(space, inString, s); + if (m_padding == PKCS_PADDING) + { + byte pad = space[s-1]; + if (pad < 1 || pad > s || FindIfNot(PtrAdd(space, s-pad), PtrAdd(space, s), pad) != PtrAdd(space, s)) + throw InvalidCiphertext("StreamTransformationFilter: invalid PKCS #7 block padding found"); + length = s-pad; + } + else if (m_padding == W3C_PADDING) + { + byte pad = space[s - 1]; + if (pad < 1 || pad > s) + throw InvalidCiphertext("StreamTransformationFilter: invalid W3C block padding found"); + length = s - pad; + } + else + { + while (length > 1 && space[length-1] == 0) + --length; + if (space[--length] != 0x80) + throw InvalidCiphertext("StreamTransformationFilter: invalid ones-and-zeros padding found"); + } + AttachedTransformation()->Put(space, length); + } + break; + + default: + CRYPTOPP_ASSERT(false); + } +} + +// ************************************************************* + +HashFilter::HashFilter(HashTransformation &hm, BufferedTransformation *attachment, bool putMessage, int truncatedDigestSize, const std::string &messagePutChannel, const std::string &hashPutChannel) + : m_hashModule(hm), m_putMessage(putMessage), m_digestSize(0), m_space(NULLPTR) + , m_messagePutChannel(messagePutChannel), m_hashPutChannel(hashPutChannel) +{ + m_digestSize = truncatedDigestSize < 0 ? m_hashModule.DigestSize() : truncatedDigestSize; + Detach(attachment); +} + +void HashFilter::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false); + int s = parameters.GetIntValueWithDefault(Name::TruncatedDigestSize(), -1); + m_digestSize = s < 0 ? m_hashModule.DigestSize() : s; +} + +size_t HashFilter::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + if (m_putMessage) + FILTER_OUTPUT3(1, 0, inString, length, 0, m_messagePutChannel); + if (inString && length) + m_hashModule.Update(inString, length); + if (messageEnd) + { + { + size_t size; + m_space = HelpCreatePutSpace(*AttachedTransformation(), m_hashPutChannel, m_digestSize, m_digestSize, size = m_digestSize); + m_hashModule.TruncatedFinal(m_space, m_digestSize); + } + FILTER_OUTPUT3(2, 0, m_space, m_digestSize, messageEnd, m_hashPutChannel); + } + FILTER_END_NO_MESSAGE_END; +} + +// ************************************************************* + +HashVerificationFilter::HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment, word32 flags, int truncatedDigestSize) + : FilterWithBufferedInput(attachment) + , m_hashModule(hm), m_flags(0), m_digestSize(0), m_verified(false) +{ + FilterWithBufferedInput::IsolatedInitialize( + MakeParameters + (Name::HashVerificationFilterFlags(), flags) + (Name::TruncatedDigestSize(), truncatedDigestSize)); +} + +void HashVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) +{ + m_flags = parameters.GetValueWithDefault(Name::HashVerificationFilterFlags(), (word32)DEFAULT_FLAGS); + int s = parameters.GetIntValueWithDefault(Name::TruncatedDigestSize(), -1); + m_digestSize = s < 0 ? m_hashModule.DigestSize() : s; + m_verified = false; + firstSize = m_flags & HASH_AT_BEGIN ? m_digestSize : 0; + blockSize = 1; + lastSize = m_flags & HASH_AT_BEGIN ? 0 : m_digestSize; +} + +void HashVerificationFilter::FirstPut(const byte *inString) +{ + if (m_flags & HASH_AT_BEGIN) + { + m_expectedHash.New(m_digestSize); + if (inString) {memcpy(m_expectedHash, inString, m_expectedHash.size());} + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, m_expectedHash.size()); + } +} + +void HashVerificationFilter::NextPutMultiple(const byte *inString, size_t length) +{ + m_hashModule.Update(inString, length); + if (m_flags & PUT_MESSAGE) + AttachedTransformation()->Put(inString, length); +} + +void HashVerificationFilter::LastPut(const byte *inString, size_t length) +{ + if (m_flags & HASH_AT_BEGIN) + { + CRYPTOPP_ASSERT(length == 0); + m_verified = m_hashModule.TruncatedVerify(m_expectedHash, m_digestSize); + } + else + { + m_verified = (length==m_digestSize && m_hashModule.TruncatedVerify(inString, length)); + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, length); + } + + if (m_flags & PUT_RESULT) + AttachedTransformation()->Put(m_verified); + + if ((m_flags & THROW_EXCEPTION) && !m_verified) + throw HashVerificationFailed(); +} + +// ************************************************************* + +AuthenticatedEncryptionFilter::AuthenticatedEncryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment, + bool putAAD, int truncatedDigestSize, const std::string &macChannel, BlockPaddingScheme padding) + : StreamTransformationFilter(c, attachment, padding, true) + , m_hf(c, new OutputProxy(*this, false), putAAD, truncatedDigestSize, AAD_CHANNEL, macChannel) +{ + CRYPTOPP_ASSERT(c.IsForwardTransformation()); +} + +void AuthenticatedEncryptionFilter::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_hf.IsolatedInitialize(parameters); + StreamTransformationFilter::IsolatedInitialize(parameters); +} + +byte * AuthenticatedEncryptionFilter::ChannelCreatePutSpace(const std::string &channel, size_t &size) +{ + if (channel.empty()) + return StreamTransformationFilter::CreatePutSpace(size); + + if (channel == AAD_CHANNEL) + return m_hf.CreatePutSpace(size); + + throw InvalidChannelName("AuthenticatedEncryptionFilter", channel); +} + +size_t AuthenticatedEncryptionFilter::ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (channel.empty()) + return StreamTransformationFilter::Put2(begin, length, messageEnd, blocking); + + if (channel == AAD_CHANNEL) + return m_hf.Put2(begin, length, 0, blocking); + + throw InvalidChannelName("AuthenticatedEncryptionFilter", channel); +} + +void AuthenticatedEncryptionFilter::LastPut(const byte *inString, size_t length) +{ + StreamTransformationFilter::LastPut(inString, length); + m_hf.MessageEnd(); +} + +// ************************************************************* + +AuthenticatedDecryptionFilter::AuthenticatedDecryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment, word32 flags, int truncatedDigestSize, BlockPaddingScheme padding) + : FilterWithBufferedInput(attachment) + , m_hashVerifier(c, new OutputProxy(*this, false)) + , m_streamFilter(c, new OutputProxy(*this, false), padding, true) +{ + CRYPTOPP_ASSERT(!c.IsForwardTransformation() || c.IsSelfInverting()); + FilterWithBufferedInput::IsolatedInitialize( + MakeParameters + (Name::BlockPaddingScheme(), padding) + (Name::AuthenticatedDecryptionFilterFlags(), flags) + (Name::TruncatedDigestSize(), truncatedDigestSize)); +} + +void AuthenticatedDecryptionFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) +{ + word32 flags = parameters.GetValueWithDefault(Name::AuthenticatedDecryptionFilterFlags(), (word32)DEFAULT_FLAGS); + + m_hashVerifier.Initialize(CombinedNameValuePairs(parameters, MakeParameters(Name::HashVerificationFilterFlags(), flags))); + m_streamFilter.Initialize(parameters); + + firstSize = m_hashVerifier.m_firstSize; + blockSize = 1; + lastSize = m_hashVerifier.m_lastSize; +} + +byte * AuthenticatedDecryptionFilter::ChannelCreatePutSpace(const std::string &channel, size_t &size) +{ + if (channel.empty()) + return m_streamFilter.CreatePutSpace(size); + + if (channel == AAD_CHANNEL) + return m_hashVerifier.CreatePutSpace(size); + + throw InvalidChannelName("AuthenticatedDecryptionFilter", channel); +} + +size_t AuthenticatedDecryptionFilter::ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (channel.empty()) + { + if (m_lastSize > 0) + m_hashVerifier.ForceNextPut(); + return FilterWithBufferedInput::Put2(begin, length, messageEnd, blocking); + } + + if (channel == AAD_CHANNEL) + return m_hashVerifier.Put2(begin, length, 0, blocking); + + throw InvalidChannelName("AuthenticatedDecryptionFilter", channel); +} + +void AuthenticatedDecryptionFilter::FirstPut(const byte *inString) +{ + m_hashVerifier.Put(inString, m_firstSize); +} + +void AuthenticatedDecryptionFilter::NextPutMultiple(const byte *inString, size_t length) +{ + m_streamFilter.Put(inString, length); +} + +void AuthenticatedDecryptionFilter::LastPut(const byte *inString, size_t length) +{ + m_streamFilter.MessageEnd(); + m_hashVerifier.PutMessageEnd(inString, length); +} + +// ************************************************************* + +void SignerFilter::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false); + m_messageAccumulator.reset(m_signer.NewSignatureAccumulator(m_rng)); +} + +size_t SignerFilter::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + FILTER_BEGIN; + m_messageAccumulator->Update(inString, length); + if (m_putMessage) + FILTER_OUTPUT(1, inString, length, 0); + if (messageEnd) + { + m_buf.New(m_signer.SignatureLength()); + m_signer.Sign(m_rng, m_messageAccumulator.release(), m_buf); + FILTER_OUTPUT(2, m_buf, m_buf.size(), messageEnd); + m_messageAccumulator.reset(m_signer.NewSignatureAccumulator(m_rng)); + } + FILTER_END_NO_MESSAGE_END; +} + +SignatureVerificationFilter::SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment, word32 flags) + : FilterWithBufferedInput(attachment) + , m_verifier(verifier), m_flags(0), m_verified(0) +{ + FilterWithBufferedInput::IsolatedInitialize( + MakeParameters + (Name::SignatureVerificationFilterFlags(), flags)); +} + +void SignatureVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) +{ + m_flags = parameters.GetValueWithDefault(Name::SignatureVerificationFilterFlags(), (word32)DEFAULT_FLAGS); + m_messageAccumulator.reset(m_verifier.NewVerificationAccumulator()); + size_t size = m_verifier.SignatureLength(); + CRYPTOPP_ASSERT(size != 0); // TODO: handle recoverable signature scheme + m_verified = false; + firstSize = m_flags & SIGNATURE_AT_BEGIN ? size : 0; + blockSize = 1; + lastSize = m_flags & SIGNATURE_AT_BEGIN ? 0 : size; +} + +void SignatureVerificationFilter::FirstPut(const byte *inString) +{ + if (m_flags & SIGNATURE_AT_BEGIN) + { + if (m_verifier.SignatureUpfront()) + m_verifier.InputSignature(*m_messageAccumulator, inString, m_verifier.SignatureLength()); + else + { + m_signature.New(m_verifier.SignatureLength()); + if (inString) {memcpy(m_signature, inString, m_signature.size());} + } + + if (m_flags & PUT_SIGNATURE) + AttachedTransformation()->Put(inString, m_signature.size()); + } + else + { + CRYPTOPP_ASSERT(!m_verifier.SignatureUpfront()); + } +} + +void SignatureVerificationFilter::NextPutMultiple(const byte *inString, size_t length) +{ + m_messageAccumulator->Update(inString, length); + if (m_flags & PUT_MESSAGE) + AttachedTransformation()->Put(inString, length); +} + +void SignatureVerificationFilter::LastPut(const byte *inString, size_t length) +{ + if (m_flags & SIGNATURE_AT_BEGIN) + { + CRYPTOPP_ASSERT(length == 0); + m_verifier.InputSignature(*m_messageAccumulator, m_signature, m_signature.size()); + m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator); + } + else + { + m_verifier.InputSignature(*m_messageAccumulator, inString, length); + m_verified = m_verifier.VerifyAndRestart(*m_messageAccumulator); + if (m_flags & PUT_SIGNATURE) + AttachedTransformation()->Put(inString, length); + } + + if (m_flags & PUT_RESULT) + AttachedTransformation()->Put(m_verified); + + if ((m_flags & THROW_EXCEPTION) && !m_verified) + throw SignatureVerificationFailed(); +} + +// ************************************************************* + +size_t Source::PumpAll2(bool blocking) +{ + unsigned int messageCount = UINT_MAX; + do { + RETURN_IF_NONZERO(PumpMessages2(messageCount, blocking)); + } while(messageCount == UINT_MAX); + + return 0; +} + +bool Store::GetNextMessage() +{ + if (!m_messageEnd && !AnyRetrievable()) + { + m_messageEnd=true; + return true; + } + else + return false; +} + +unsigned int Store::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + if (m_messageEnd || count == 0) + return 0; + else + { + CopyTo(target, ULONG_MAX, channel); + if (GetAutoSignalPropagation()) + target.ChannelMessageEnd(channel, GetAutoSignalPropagation()-1); + return 1; + } +} + +void StringStore::StoreInitialize(const NameValuePairs ¶meters) +{ + ConstByteArrayParameter array; + if (!parameters.GetValue(Name::InputBuffer(), array)) + throw InvalidArgument("StringStore: missing InputBuffer argument"); + m_store = array.begin(); + m_length = array.size(); + m_count = 0; +} + +size_t StringStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + lword position = 0; + size_t blockedBytes = CopyRangeTo2(target, position, transferBytes, channel, blocking); + m_count += static_cast(position); + transferBytes = position; + return blockedBytes; +} + +size_t StringStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + size_t i = UnsignedMin(m_length, m_count+begin); + size_t len = UnsignedMin(m_length-i, end-begin); + size_t blockedBytes = target.ChannelPut2(channel, PtrAdd(m_store, i), len, 0, blocking); + if (!blockedBytes) + begin = PtrAdd(begin, len); + return blockedBytes; +} + +void RandomNumberStore::StoreInitialize(const NameValuePairs ¶meters) +{ + parameters.GetRequiredParameter("RandomNumberStore", "RandomNumberGeneratorPointer", m_rng); + int length; + parameters.GetRequiredIntParameter("RandomNumberStore", "RandomNumberStoreSize", length); + m_length = length; +} + +size_t RandomNumberStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + if (!blocking) + throw NotImplemented("RandomNumberStore: nonblocking transfer is not implemented by this object"); + + transferBytes = UnsignedMin(transferBytes, m_length - m_count); + m_rng->GenerateIntoBufferedTransformation(target, channel, transferBytes); + m_count += transferBytes; + + return 0; +} + +size_t NullStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + static const byte nullBytes[128] = {0}; + while (begin < end) + { + size_t len = (size_t)STDMIN(end-begin, lword(128)); + size_t blockedBytes = target.ChannelPut2(channel, nullBytes, len, 0, blocking); + if (blockedBytes) + return blockedBytes; + begin = PtrAdd(begin, len); + } + return 0; +} + +size_t NullStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + lword begin = 0; + size_t blockedBytes = NullStore::CopyRangeTo2(target, begin, transferBytes, channel, blocking); + transferBytes = begin; m_size -= begin; + return blockedBytes; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/filters.h b/extension/third_party/cryptopp/filters.h new file mode 100644 index 00000000..a334bd76 --- /dev/null +++ b/extension/third_party/cryptopp/filters.h @@ -0,0 +1,1529 @@ +// filters.h - originally written and placed in the public domain by Wei Dai + +/// \file filters.h +/// \brief Implementation of BufferedTransformation's attachment interface. + +#ifndef CRYPTOPP_FILTERS_H +#define CRYPTOPP_FILTERS_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275 4514) +#endif + +#include "cryptlib.h" +#include "simple.h" +#include "secblock.h" +#include "misc.h" +#include "smartptr.h" +#include "queue.h" +#include "algparam.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Filter is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Filter : public BufferedTransformation, public NotCopyable +{ +public: + virtual ~Filter() {} + + /// \name ATTACHMENT + //@{ + + /// \brief Construct a Filter + /// \param attachment an optional attached transformation + /// \details attachment can be NULL. + Filter(BufferedTransformation *attachment = NULLPTR); + + /// \brief Determine if attachable + /// \return true if the object allows attached transformations, false otherwise. + /// \note Source and Filter offer attached transformations; while Sink does not. + bool Attachable() {return true;} + + /// \brief Retrieve attached transformation + /// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise. + BufferedTransformation *AttachedTransformation(); + + /// \brief Retrieve attached transformation + /// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise. + const BufferedTransformation *AttachedTransformation() const; + + /// \brief Replace an attached transformation + /// \param newAttachment an optional attached transformation + /// \details newAttachment can be a single filter, a chain of filters or NULL. + /// Pass NULL to remove an existing BufferedTransformation or chain of filters + void Detach(BufferedTransformation *newAttachment = NULLPTR); + + //@} + + /// \name RETRIEVAL OF ONE MESSAGE + //@{ + + // BufferedTransformation in cryptlib.h + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + //@} + + /// \name SIGNALS + //@{ + + // BufferedTransformation in cryptlib.h + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + //@} + +protected: + virtual BufferedTransformation * NewDefaultAttachment() const; + void Insert(Filter *nextFilter); // insert filter after this one + + virtual bool ShouldPropagateMessageEnd() const {return true;} + virtual bool ShouldPropagateMessageSeriesEnd() const {return true;} + + void PropagateInitialize(const NameValuePairs ¶meters, int propagation); + + /// \brief Forward processed data on to attached transformation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Output multiple bytes that may be modified by callee. + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Signals the end of messages to the object + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the MessageEnd signal was successful, false otherwise. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the Flush signal was successful, false otherwise. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the MessageEnd signal was successful, false otherwise. + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + +private: + member_ptr m_attachment; + +protected: + size_t m_inputPosition; + int m_continueAt; +}; + +/// \brief Create a working space in a BufferedTransformation +struct CRYPTOPP_DLL FilterPutSpaceHelper +{ + virtual ~FilterPutSpaceHelper() {} + + /// \brief Create a working space in a BufferedTransformation + /// \param target BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param desiredSize preferred size of the allocation, in bytes + /// \param bufferSize actual size of the allocation, in bytes + /// \pre desiredSize >= minSize and bufferSize >= minSize. + /// \details bufferSize is an IN and OUT parameter. If HelpCreatePutSpace() returns a non-NULL value, then + /// bufferSize is valid and provides the size of the working space created for the caller. + /// \details Internally, HelpCreatePutSpace() calls \ref BufferedTransformation::ChannelCreatePutSpace + /// "ChannelCreatePutSpace()" using desiredSize. If the target returns desiredSize with a size less + /// than minSize (i.e., the request could not be fulfilled), then an internal SecByteBlock + /// called m_tempSpace is resized and used for the caller. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) + { + CRYPTOPP_ASSERT(desiredSize >= minSize && bufferSize >= minSize); + if (m_tempSpace.size() < minSize) + { + byte *result = target.ChannelCreatePutSpace(channel, desiredSize); + if (desiredSize >= minSize) + { + bufferSize = desiredSize; + return result; + } + m_tempSpace.New(bufferSize); + } + + bufferSize = m_tempSpace.size(); + return m_tempSpace.begin(); + } + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \return pointer to the created space + /// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments. + /// \details The filter will delete the space. The caller does not need to delete the space. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);} + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param bufferSize the actual size of the allocation, in bytes + /// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments. + /// \details The filter will delete the space. The caller does not need to delete the space. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t bufferSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);} + + /// \brief Temporay working space + SecByteBlock m_tempSpace; +}; + +/// \brief Measure how many bytes and messages pass through the filter +/// \details measure how many bytes and messages pass through the filter. The filter also serves as valve by +/// maintaining a list of ranges to skip during processing. +class CRYPTOPP_DLL MeterFilter : public Bufferless +{ +public: + virtual ~MeterFilter() {} + + /// \brief Construct a MeterFilter + /// \param attachment an optional attached transformation + /// \param transparent flag indicating if the filter should function transparently + /// \details attachment can be NULL. The filter is transparent by default. If the filter is + /// transparent, then PutMaybeModifiable() does not process a request and always returns 0. + MeterFilter(BufferedTransformation *attachment=NULLPTR, bool transparent=true) + : m_transparent(transparent), m_currentMessageBytes(0), m_totalBytes(0) + , m_currentSeriesMessages(0), m_totalMessages(0), m_totalMessageSeries(0) + , m_begin(NULLPTR), m_length(0) {Detach(attachment); ResetMeter();} + + /// \brief Set or change the transparent mode of this object + /// \param transparent the new transparent mode + void SetTransparent(bool transparent) {m_transparent = transparent;} + + /// \brief Adds a range to skip during processing + /// \param message the message to apply the range + /// \param position the 0-based index in the current stream + /// \param size the length of the range + /// \param sortNow flag indicating whether the range should be sorted + /// \details Internally, MeterFilter maitains a deque of ranges to skip. As messages are processed, + /// ranges of bytes are skipped according to the list of ranges. + void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true); + + /// \brief Resets the meter + /// \details ResetMeter() reinitializes the meter by setting counters to 0 and removing previous + /// skip ranges. + void ResetMeter(); + + // BufferedTransformation in cryptlib.h + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); ResetMeter();} + + /// \brief Number of bytes in the current message + /// \return GetCurrentMessageBytes() returns the number of bytes in the current message + lword GetCurrentMessageBytes() const {return m_currentMessageBytes;} + + /// \brief Number of bytes processed by the filter + /// \return GetTotalBytes() returns the number of bytes processed by the filter + lword GetTotalBytes() const {return m_totalBytes;} + + /// \brief Message number in the series + /// \return GetCurrentSeriesMessages() returns the message number in the series + unsigned int GetCurrentSeriesMessages() const {return m_currentSeriesMessages;} + + /// \brief Number of messages in the message series + /// \return GetTotalMessages() returns the number of messages in the message series + unsigned int GetTotalMessages() const {return m_totalMessages;} + + /// \brief Number of messages processed by the filter + /// \return GetTotalMessageSeries() returns the number of messages processed by the filter + unsigned int GetTotalMessageSeries() const {return m_totalMessageSeries;} + + // BufferedTransformation in cryptlib.h + byte * CreatePutSpace(size_t &size) {return AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedMessageSeriesEnd(bool blocking); + +private: + size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable); + bool ShouldPropagateMessageEnd() const {return m_transparent;} + bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;} + + struct MessageRange + { + inline bool operator<(const MessageRange &b) const // BCB2006 workaround: this has to be a member function + {return message < b.message || (message == b.message && position < b.position);} + unsigned int message; lword position; lword size; + }; + + bool m_transparent; + lword m_currentMessageBytes, m_totalBytes; + unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries; + std::deque m_rangesToSkip; + byte *m_begin; + size_t m_length; +}; + +/// \brief A transparent MeterFilter +/// \sa MeterFilter, OpaqueFilter +class CRYPTOPP_DLL TransparentFilter : public MeterFilter +{ +public: + /// \brief Construct a TransparentFilter + /// \param attachment an optional attached transformation + TransparentFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, true) {} +}; + +/// \brief A non-transparent MeterFilter +/// \sa MeterFilter, TransparentFilter +class CRYPTOPP_DLL OpaqueFilter : public MeterFilter +{ +public: + /// \brief Construct an OpaqueFilter + /// \param attachment an optional attached transformation + OpaqueFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, false) {} +}; + +/// \brief Divides an input stream into discrete blocks +/// \details FilterWithBufferedInput divides the input stream into a first block, a number of +/// middle blocks, and a last block. First and last blocks are optional, and middle blocks may +/// be a stream instead (i.e. blockSize == 1). +/// \sa AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashVerificationFilter, +/// SignatureVerificationFilter, StreamTransformationFilter +class CRYPTOPP_DLL FilterWithBufferedInput : public Filter +{ +public: + virtual ~FilterWithBufferedInput() {} + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param attachment an attached transformation + FilterWithBufferedInput(BufferedTransformation *attachment); + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param firstSize the size of the first block + /// \param blockSize the size of middle blocks + /// \param lastSize the size of the last block + /// \param attachment an attached transformation + /// \details firstSize and lastSize may be 0. blockSize must be at least 1. + FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(const_cast(inString), length, messageEnd, blocking, false); + } + + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(inString, length, messageEnd, blocking, true); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the Flush was successful, false otherwise + /// \details IsolatedFlush() calls ForceNextPut() if hardFlush is true + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Flushes data buffered by this object + /// \details The input buffer may contain more than blockSize bytes if lastSize != 0. + /// ForceNextPut() forces a call to NextPut() if this is the case. + void ForceNextPut(); + +protected: + virtual bool DidFirstPut() const {return m_firstInputDone;} + virtual size_t GetFirstPutSize() const {return m_firstSize;} + virtual size_t GetBlockPutSize() const {return m_blockSize;} + virtual size_t GetLastPutSize() const {return m_lastSize;} + + virtual void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_UNUSED(firstSize); CRYPTOPP_UNUSED(blockSize); CRYPTOPP_UNUSED(lastSize); InitializeDerived(parameters);} + virtual void InitializeDerived(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + // FirstPut() is called if (firstSize != 0 and totalLength >= firstSize) + // or (firstSize == 0 and (totalLength > 0 or a MessageEnd() is received)). + // inString is m_firstSize in length. + virtual void FirstPut(const byte *inString) =0; + // NextPut() is called if totalLength >= firstSize+blockSize+lastSize + virtual void NextPutSingle(const byte *inString) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_ASSERT(false);} + // Same as NextPut() except length can be a multiple of blockSize + // Either NextPut() or NextPutMultiple() must be overridden + virtual void NextPutMultiple(const byte *inString, size_t length); + // Same as NextPutMultiple(), but inString can be modified + virtual void NextPutModifiable(byte *inString, size_t length) + {NextPutMultiple(inString, length);} + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ virtual void LastPut(const byte *inString, size_t length) =0; + virtual void FlushDerived() {} + +protected: + size_t PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable); + void NextPutMaybeModifiable(byte *inString, size_t length, bool modifiable) + { + if (modifiable) NextPutModifiable(inString, length); + else NextPutMultiple(inString, length); + } + + // This function should no longer be used, put this here to cause a compiler error + // if someone tries to override NextPut(). + virtual int NextPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(false); return 0;} + + class BlockQueue + { + public: + void ResetQueue(size_t blockSize, size_t maxBlocks); + byte *GetBlock(); + byte *GetContigousBlocks(size_t &numberOfBytes); + size_t GetAll(byte *outString); + void Put(const byte *inString, size_t length); + size_t CurrentSize() const {return m_size;} + size_t MaxSize() const {return m_buffer.size();} + + private: + SecByteBlock m_buffer; + size_t m_blockSize, m_maxBlocks, m_size; + byte *m_begin; + }; + + size_t m_firstSize, m_blockSize, m_lastSize; + bool m_firstInputDone; + BlockQueue m_queue; +}; + +/// \brief A filter that buffers input using a ByteQueue +/// \details FilterWithInputQueue will buffer input using a ByteQueue. When the filter receives +/// a \ref BufferedTransformation::MessageEnd() "MessageEnd()" signal it will pass the data +/// on to its attached transformation. +class CRYPTOPP_DLL FilterWithInputQueue : public Filter +{ +public: + virtual ~FilterWithInputQueue() {} + + /// \brief Construct a FilterWithInputQueue + /// \param attachment an optional attached transformation + FilterWithInputQueue(BufferedTransformation *attachment=NULLPTR) : Filter(attachment) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("FilterWithInputQueue"); + + m_inQueue.Put(inString, length); + if (messageEnd) + { + IsolatedMessageEnd(blocking); + Output(0, NULLPTR, 0, messageEnd, blocking); + } + return 0; + } + +protected: + virtual bool IsolatedMessageEnd(bool blocking) =0; + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_inQueue.Clear();} + + ByteQueue m_inQueue; +}; + +/// \struct BlockPaddingSchemeDef +/// \brief Padding schemes used for block ciphers +/// \since Crypto++ 5.0 +struct BlockPaddingSchemeDef +{ + /// \enum BlockPaddingScheme + /// \brief Padding schemes used for block ciphers. + /// \details DEFAULT_PADDING means PKCS_PADDING if cipher.MandatoryBlockSize() > 1 && + /// cipher.MinLastBlockSize() == 0, which holds for ECB or CBC mode. Otherwise, + /// NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS. + /// \sa Block Cipher Padding for + /// additional details. + /// \since Crypto++ 5.0 + enum BlockPaddingScheme { + /// \brief No padding added to a block + /// \since Crypto++ 5.0 + NO_PADDING, + /// \brief 0's padding added to a block + /// \since Crypto++ 5.0 + ZEROS_PADDING, + /// \brief PKCS padding added to a block + /// \since Crypto++ 5.0 + PKCS_PADDING, + /// \brief 1 and 0's padding added to a block + /// \since Crypto++ 5.0 + ONE_AND_ZEROS_PADDING, + /// \brief W3C padding added to a block + /// \sa XML + /// Encryption Syntax and Processing + /// \since Crypto++ 6.0 + W3C_PADDING, + /// \brief Default padding scheme + /// \since Crypto++ 5.0 + DEFAULT_PADDING + }; +}; + +/// \brief Filter wrapper for StreamTransformation +/// \details StreamTransformationFilter() is a filter wrapper for StreamTransformation(). It is used when +/// pipelining data for stream ciphers and confidentiality-only block ciphers. The filter will optionally +/// handle padding and unpadding when needed. If you are using an authenticated encryption mode of operation, +/// then use AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL StreamTransformationFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef, private FilterPutSpaceHelper +{ +public: + virtual ~StreamTransformationFilter() {} + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details This contructor creates a StreamTransformationFilter() for stream ciphers and + /// confidentiality-only block cipher modes of operation. If you are using an authenticated + /// encryption mode of operation, then use either AuthenticatedEncryptionFilter() or + /// AuthenticatedDecryptionFilter(). + /// \sa AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment = NULLPTR, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_cipher.AlgorithmName();} + +protected: + + friend class AuthenticatedEncryptionFilter; + friend class AuthenticatedDecryptionFilter; + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \param authenticated flag indicating whether the filter should allow authenticated encryption schemes + /// \details This constructor is used for authenticated encryption mode of operation and by + /// AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter(). + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding, bool authenticated); + + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void NextPutModifiable(byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + + static size_t LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding); + + StreamTransformation &m_cipher; + BlockPaddingScheme m_padding; + unsigned int m_mandatoryBlockSize; + unsigned int m_optimalBufferSize; + unsigned int m_reservedBufferSize; + bool m_isSpecial; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL HashFilter : public Bufferless, private FilterPutSpaceHelper +{ +public: + virtual ~HashFilter() {} + + /// \brief Construct a HashFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param messagePutChannel the channel on which the message should be output + /// \param hashPutChannel the channel on which the digest should be output + HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, bool putMessage=false, int truncatedDigestSize=-1, const std::string &messagePutChannel=DEFAULT_CHANNEL, const std::string &hashPutChannel=DEFAULT_CHANNEL); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return m_hashModule.CreateUpdateSpace(size);} + +private: + HashTransformation &m_hashModule; + bool m_putMessage; + unsigned int m_digestSize; + byte *m_space; + std::string m_messagePutChannel, m_hashPutChannel; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL HashVerificationFilter : public FilterWithBufferedInput +{ +public: + virtual ~HashVerificationFilter() {} + + /// \brief Exception thrown when a data integrity check failure is encountered + class HashVerificationFailed : public Exception + { + public: + HashVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "HashVerificationFilter: message hash or MAC not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The hash is at the end of the message (i.e., concatenation of message+hash) + HASH_AT_END=0, + /// \brief The hash is at the beginning of the message (i.e., concatenation of hash+message) + HASH_AT_BEGIN=1, + /// \brief The message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief The hash should be passed to an attached transformation + PUT_HASH=4, + /// \brief The result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using HASH_AT_BEGIN and PUT_RESULT + DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT + }; + + /// \brief Construct a HashVerificationFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + friend class AuthenticatedDecryptionFilter; + + HashTransformation &m_hashModule; + word32 m_flags; + unsigned int m_digestSize; + bool m_verified; + SecByteBlock m_expectedHash; +}; + +/// \brief Filter wrapper for encrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedEncryptionFilter() is a wrapper for encrypting with +/// AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when needed. +/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier +/// had a bug where a FileSource() would cause an exception, but a StringSource() +/// was OK. Also see Issue 817 and Commit ff110c6e183e. +/// \sa AuthenticatedSymmetricCipher, AuthenticatedDecryptionFilter, EAX, CCM, GCM, +/// and AadSource on the +/// Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedEncryptionFilter : public StreamTransformationFilter +{ +public: + virtual ~AuthenticatedEncryptionFilter() {} + + /// \brief Construct a AuthenticatedEncryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param putAAD flag indicating whether the AAD should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param macChannel the channel on which the MAC should be output + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedEncryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, bool putAAD=false, int truncatedDigestSize=-1, const std::string &macChannel=DEFAULT_CHANNEL, BlockPaddingScheme padding = DEFAULT_PADDING); + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + +protected: + HashFilter m_hf; +}; + +/// \brief Filter wrapper for decrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedDecryptionFilter() is a wrapper for decrypting with +/// AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when +/// needed. +/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier +/// had a bug where a FileSource() would cause an exception, but a StringSource() +/// was OK. Also see Issue 817 and Commit ff110c6e183e. +/// \sa AuthenticatedSymmetricCipher, AuthenticatedEncryptionFilter, EAX, CCM, GCM, +/// and AadSource on the +/// Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedDecryptionFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef +{ +public: + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The MAC is at the end of the message (i.e., concatenation of message+mac) + MAC_AT_END=0, + /// \brief The MAC is at the beginning of the message (i.e., concatenation of mac+message) + MAC_AT_BEGIN=1, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using THROW_EXCEPTION + DEFAULT_FLAGS = THROW_EXCEPTION + }; + + virtual ~AuthenticatedDecryptionFilter() {} + + /// \brief Construct a AuthenticatedDecryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details Additional authenticated data should be given in channel "AAD". + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedDecryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_hashVerifier.AlgorithmName();} + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + { return ChannelPut2(channel, begin, length, messageEnd, blocking); } + /// \brief Get verifier result + /// \return true if the digest on the previosus message was valid, false otherwise + bool GetLastResult() const {return m_hashVerifier.GetLastResult();} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + + HashVerificationFilter m_hashVerifier; + StreamTransformationFilter m_streamFilter; +}; + +/// \brief Filter wrapper for PK_Signer +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignerFilter : public Unflushable +{ +public: + virtual ~SignerFilter() {} + + /// \brief Construct a SignerFilter + /// \param rng a RandomNumberGenerator derived class + /// \param signer a PK_Signer derived class + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULLPTR, bool putMessage=false) + : m_rng(rng), m_signer(signer), m_messageAccumulator(signer.NewSignatureAccumulator(rng)), m_putMessage(putMessage) {Detach(attachment);} + + std::string AlgorithmName() const {return m_signer.AlgorithmName();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator &m_rng; + const PK_Signer &m_signer; + member_ptr m_messageAccumulator; + bool m_putMessage; + SecByteBlock m_buf; +}; + +/// \brief Filter wrapper for PK_Verifier +/// \details This filter was formerly named VerifierFilter. The name changed at Crypto++ 5.0. +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignatureVerificationFilter : public FilterWithBufferedInput +{ +public: + /// \brief Exception thrown when an invalid signature is encountered + class SignatureVerificationFailed : public Exception + { + public: + SignatureVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "VerifierFilter: digital signature not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The signature is at the end of the message (i.e., concatenation of message+signature) + SIGNATURE_AT_END=0, + /// \brief The signature is at the beginning of the message (i.e., concatenation of signature+message) + SIGNATURE_AT_BEGIN=1, + /// \brief The message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief The signature should be passed to an attached transformation + PUT_SIGNATURE=4, + /// \brief The result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using SIGNATURE_AT_BEGIN and PUT_RESULT + DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT + }; + + virtual ~SignatureVerificationFilter() {} + + /// \brief Construct a SignatureVerificationFilter + /// \param verifier a PK_Verifier derived class + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS); + + std::string AlgorithmName() const {return m_verifier.AlgorithmName();} + + /// \brief Retrieves the result of the last verification + /// \return true if the signature on the previosus message was valid, false otherwise + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + const PK_Verifier &m_verifier; + member_ptr m_messageAccumulator; + word32 m_flags; + SecByteBlock m_signature; + bool m_verified; +}; + +/// \brief Redirect input to another BufferedTransformation without owning it +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL Redirector : public CustomSignalPropagation +{ +public: + /// \enum Behavior + /// \brief Controls signal propagation behavior + enum Behavior + { + /// \brief Pass data only + DATA_ONLY = 0x00, + /// \brief Pass signals + PASS_SIGNALS = 0x01, + /// \brief Pass wait events + PASS_WAIT_OBJECTS = 0x02, + /// \brief Pass everything + /// \details PASS_EVERYTHING is default + PASS_EVERYTHING = PASS_SIGNALS | PASS_WAIT_OBJECTS + }; + + virtual ~Redirector() {} + + /// \brief Construct a Redirector + Redirector() : m_target(NULLPTR), m_behavior(PASS_EVERYTHING) {} + + /// \brief Construct a Redirector + /// \param target the destination BufferedTransformation + /// \param behavior Behavior "flags" specifying signal propagation + Redirector(BufferedTransformation &target, Behavior behavior=PASS_EVERYTHING) + : m_target(&target), m_behavior(behavior) {} + + /// \brief Redirect input to another BufferedTransformation + /// \param target the destination BufferedTransformation + void Redirect(BufferedTransformation &target) {m_target = ⌖} + /// \brief Stop redirecting input + void StopRedirection() {m_target = NULLPTR;} + + /// \brief Retrieve signal propagation behavior + /// \return the current signal propagation behavior + Behavior GetBehavior() {return static_cast(m_behavior);} + /// \brief Set signal propagation behavior + /// \param behavior the new signal propagation behavior + void SetBehavior(Behavior behavior) {m_behavior=behavior;} + /// \brief Retrieve signal propagation behavior + /// \return true if the Redirector passes signals, false otherwise. + bool GetPassSignals() const {return (m_behavior & PASS_SIGNALS) != 0;} + /// \brief Set signal propagation behavior + /// \param pass flag indicating if the Redirector should pass signals + void SetPassSignals(bool pass) { if (pass) m_behavior |= PASS_SIGNALS; else m_behavior &= ~static_cast(PASS_SIGNALS); } + /// \brief Retrieve signal propagation behavior + /// \return true if the Redirector passes wait objects, false otherwise. + bool GetPassWaitObjects() const {return (m_behavior & PASS_WAIT_OBJECTS) != 0;} + /// \brief Set signal propagation behavior + /// \param pass flag indicating if the Redirector should pass wait objects + void SetPassWaitObjects(bool pass) { if (pass) m_behavior |= PASS_WAIT_OBJECTS; else m_behavior &= ~static_cast(PASS_WAIT_OBJECTS); } + + bool CanModifyInput() const + {return m_target ? m_target->CanModifyInput() : false;} + + void Initialize(const NameValuePairs ¶meters, int propagation); + byte * CreatePutSpace(size_t &size) + { + if (m_target) + return m_target->CreatePutSpace(size); + else + { + size = 0; + return NULLPTR; + } + } + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->Put2(inString, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + { + if (m_target) + return m_target->ChannelCreatePutSpace(channel, size); + else + { + size = 0; + return NULLPTR; + } + } + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPut2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPutModifiable2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + + unsigned int GetMaxWaitObjectCount() const + { return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; } + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) + { if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container, callStack); } + +private: + BufferedTransformation *m_target; + word32 m_behavior; +}; + +/// \brief Filter class that is a proxy for a sink +/// \details Used By ProxyFilter +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL OutputProxy : public CustomSignalPropagation +{ +public: + virtual ~OutputProxy() {} + + /// \brief Construct an OutputProxy + /// \param owner the owning transformation + /// \param passSignal flag indicating if signals should be passed + OutputProxy(BufferedTransformation &owner, bool passSignal) : m_owner(owner), m_passSignal(passSignal) {} + + /// \brief Retrieve passSignal flag + /// \return flag indicating if signals should be passed + bool GetPassSignal() const {return m_passSignal;} + /// \brief Set passSignal flag + /// \param passSignal flag indicating if signals should be passed + void SetPassSignal(bool passSignal) {m_passSignal = passSignal;} + + byte * CreatePutSpace(size_t &size) + {return m_owner.AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->Put2(inString, length, m_passSignal ? messageEnd : 0, blocking);} + size_t PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->PutModifiable2(begin, length, m_passSignal ? messageEnd : 0, blocking);} + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) + {if (m_passSignal) m_owner.AttachedTransformation()->Initialize(parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {return m_owner.AttachedTransformation()->ChannelCreatePutSpace(channel, size);} + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + +private: + BufferedTransformation &m_owner; + bool m_passSignal; +}; + +/// \brief Base class for Filter classes that are proxies for a chain of other filters +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ProxyFilter : public FilterWithBufferedInput +{ +public: + virtual ~ProxyFilter() {} + + /// \brief Construct a ProxyFilter + /// \param filter an output filter + /// \param firstSize the first Put size + /// \param lastSize the last Put size + /// \param attachment an attached transformation + ProxyFilter(BufferedTransformation *filter, size_t firstSize, size_t lastSize, BufferedTransformation *attachment); + + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Sets the OutputProxy filter + /// \param filter an OutputProxy filter + void SetFilter(Filter *filter); + void NextPutMultiple(const byte *s, size_t len); + void NextPutModifiable(byte *inString, size_t length); + +protected: + member_ptr m_filter; +}; + +/// \brief Proxy filter that doesn't modify the underlying filter's input or output +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL SimpleProxyFilter : public ProxyFilter +{ +public: + /// \brief Construct a SimpleProxyFilter + /// \param filter an output filter + /// \param attachment an attached transformation + SimpleProxyFilter(BufferedTransformation *filter, BufferedTransformation *attachment) + : ProxyFilter(filter, 0, 0, attachment) {} + + void FirstPut(const byte * inString) + {CRYPTOPP_UNUSED(inString);} + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString), CRYPTOPP_UNUSED(length); m_filter->MessageEnd();} +}; + +/// \brief Filter wrapper for PK_Encryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Encryptor::CreateEncryptionFilter. +/// This class provides symmetry with VerifierFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_EncryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_EncryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param encryptor a PK_Encryptor derived class + /// \param attachment an optional attached transformation + PK_EncryptorFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(encryptor.CreateEncryptionFilter(rng), attachment) {} +}; + +/// \brief Filter wrapper for PK_Decryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Decryptor::CreateDecryptionFilter. +/// This class provides symmetry with SignerFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_DecryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_DecryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param decryptor a PK_Decryptor derived class + /// \param attachment an optional attached transformation + PK_DecryptorFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(decryptor.CreateDecryptionFilter(rng), attachment) {} +}; + +/// \brief Append input to a string object +/// \tparam T std::basic_string type +/// \details StringSinkTemplate is a StringSinkTemplate typedef +/// \since Crypto++ 5.0 +template +class StringSinkTemplate : public Bufferless +{ +public: + typedef typename T::value_type value_type; + virtual ~StringSinkTemplate() {} + + /// \brief Construct a StringSinkTemplate + /// \param output std::basic_string or std::vector type + StringSinkTemplate(T &output) + : m_output(&output) {CRYPTOPP_ASSERT(sizeof(value_type)==1);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {if (!parameters.GetValue("OutputStringPointer", m_output)) throw InvalidArgument("StringSink: OutputStringPointer not specified");} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + if (length > 0) + { + typename T::size_type size = m_output->size(); + if (length < size && size + length > m_output->capacity()) + m_output->reserve(2*size); + m_output->insert(m_output->end(), (const value_type *)inString, (const value_type *)inString+length); + } + return 0; + } + +private: + T *m_output; +}; + +/// \brief Append input to a string object +/// \details StringSink is a typedef for StringSinkTemplate. +/// \sa ArraySink, ArrayXorSink +/// \since Crypto++ 4.0 +DOCUMENTED_TYPEDEF(StringSinkTemplate, StringSink); +CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate; + +/// \brief Append input to a std::vector object +/// \details VectorSink is a typedef for StringSinkTemplate >. +/// \since Crypto++ 8.0 +DOCUMENTED_TYPEDEF(StringSinkTemplate >, VectorSink); +CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate >; + +/// \brief Incorporates input into RNG as additional entropy +/// \since Crypto++ 4.0 +class RandomNumberSink : public Bufferless +{ +public: + virtual ~RandomNumberSink() {} + + /// \brief Construct a RandomNumberSink + RandomNumberSink() + : m_rng(NULLPTR) {} + + /// \brief Construct a RandomNumberSink + /// \param rng a RandomNumberGenerator derived class + RandomNumberSink(RandomNumberGenerator &rng) + : m_rng(&rng) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator *m_rng; +}; + +/// \brief Copy input to a memory buffer +/// \details ArraySink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipleline, ArraySink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArrayXorSink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArraySink : public Bufferless +{ +public: + virtual ~ArraySink() {} + + /// \brief Construct an ArraySink + /// \param parameters a set of NameValuePairs to initialize this object + /// \details Name::OutputBuffer() is a mandatory parameter using this constructor. + ArraySink(const NameValuePairs ¶meters = g_nullNameValuePairs) + : m_buf(NULLPTR), m_size(0), m_total(0) {IsolatedInitialize(parameters);} + + /// \brief Construct an ArraySink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArraySink(byte *buf, size_t size) + : m_buf(buf), m_size(size), m_total(0) {} + + /// \brief Provides the size remaining in the Sink + /// \return size remaining in the Sink, in bytes + size_t AvailableSize() {return SaturatingSubtract(m_size, m_total);} + + /// \brief Provides the number of bytes written to the Sink + /// \return number of bytes written to the Sink, in bytes + lword TotalPutLength() {return m_total;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +protected: + byte *m_buf; + size_t m_size; + lword m_total; +}; + +/// \brief Xor input to a memory buffer +/// \details ArrayXorSink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipleline, ArrayXorSink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArraySink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArrayXorSink : public ArraySink +{ +public: + virtual ~ArrayXorSink() {} + + /// \brief Construct an ArrayXorSink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArrayXorSink(byte *buf, size_t size) + : ArraySink(buf, size) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return BufferedTransformation::CreatePutSpace(size);} +}; + +/// \brief String-based implementation of Store interface +/// \since Crypto++ 4.0 +class StringStore : public Store +{ +public: + /// \brief Construct a StringStore + /// \param string pointer to a C-String + StringStore(const char *string = NULLPTR) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringStore + /// \param string pointer to a memory buffer + /// \param length size of the memory buffer + StringStore(const byte *string, size_t length) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringStore + /// \tparam T std::basic_string type + /// \param string reference to a std::basic_string type + template StringStore(const T &string) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + CRYPTOPP_DLL size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + CRYPTOPP_DLL size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + CRYPTOPP_DLL void StoreInitialize(const NameValuePairs ¶meters); + + const byte *m_store; + size_t m_length, m_count; +}; + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberStore : public Store +{ +public: + virtual ~RandomNumberStore() {} + + RandomNumberStore() + : m_rng(NULLPTR), m_length(0), m_count(0) {} + + RandomNumberStore(RandomNumberGenerator &rng, lword length) + : m_rng(&rng), m_length(length), m_count(0) {} + + bool AnyRetrievable() const {return MaxRetrievable() != 0;} + lword MaxRetrievable() const {return m_length-m_count;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + { + CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); + throw NotImplemented("RandomNumberStore: CopyRangeTo2() is not supported by this store"); + } + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + RandomNumberGenerator *m_rng; + lword m_length, m_count; +}; + +/// \brief Empty store +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL NullStore : public Store +{ +public: + NullStore(lword size = ULONG_MAX) : m_size(size) {} + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + lword MaxRetrievable() const {return m_size;} + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + lword m_size; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Source is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +/// \sa Store and SourceTemplate +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Source : public InputRejecting +{ +public: + virtual ~Source() {} + + /// \brief Construct a Source + /// \param attachment an optional attached transformation + Source(BufferedTransformation *attachment = NULLPTR) + {Source::Detach(attachment);} + + /// \name PIPELINE + //@{ + + /// \brief Pump data to attached transformation + /// \param pumpMax the maximum number of bytes to pump + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Internally, Pump() calls Pump2(). + /// \note pumpMax is a lword, which is a 64-bit value that typically uses + /// LWORD_MAX. The default argument is SIZE_MAX, and it can be + /// 32-bits or 64-bits. + /// \sa Pump2, PumpAll, AnyRetrievable, MaxRetrievable + lword Pump(lword pumpMax=SIZE_MAX) + {Pump2(pumpMax); return pumpMax;} + + /// \brief Pump messages to attached transformation + /// \param count the maximum number of messages to pump + /// \return TODO + /// \details Internally, PumpMessages() calls PumpMessages2(). + unsigned int PumpMessages(unsigned int count=UINT_MAX) + {PumpMessages2(count); return count;} + + /// \brief Pump all data to attached transformation + /// \details Pumps all data to the attached transformation and signal the end of the current + /// message. To avoid the MessageEnd() signal call \ref Pump "Pump(LWORD_MAX)" or \ref Pump2 + /// "Pump2(LWORD_MAX, bool)". + /// \details Internally, PumpAll() calls PumpAll2(), which calls PumpMessages(). + /// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable + void PumpAll() + {PumpAll2();} + + /// \brief Pump data to attached transformation + /// \param byteCount the maximum number of bytes to pump + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, byteCount is the + /// requested size of the pump. When the call returns, byteCount is the number of bytes that + /// were pumped. + /// \sa Pump, PumpAll, AnyRetrievable, MaxRetrievable + virtual size_t Pump2(lword &byteCount, bool blocking=true) =0; + + /// \brief Pump messages to attached transformation + /// \param messageCount the maximum number of messages to pump + /// \param blocking specifies whether the object should block when processing input + /// \details messageCount is an IN and OUT parameter. + virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) =0; + + /// \brief Pump all data to attached transformation + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable + virtual size_t PumpAll2(bool blocking=true); + + /// \brief Determines if the Source is exhausted + /// \return true if the source has been exhausted + virtual bool SourceExhausted() const =0; + + //@} + +protected: + void SourceInitialize(bool pumpAll, const NameValuePairs ¶meters) + { + IsolatedInitialize(parameters); + if (pumpAll) + PumpAll(); + } +}; + +/// \brief Transform a Store into a Source +/// \tparam T the class or type +/// \since Crypto++ 5.0 +template +class SourceTemplate : public Source +{ +public: + virtual ~SourceTemplate() {} + + /// \brief Construct a SourceTemplate + /// \param attachment an attached transformation + SourceTemplate(BufferedTransformation *attachment) + : Source(attachment) {} + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_store.IsolatedInitialize(parameters);} + size_t Pump2(lword &byteCount, bool blocking=true) + {return m_store.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);} + size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) + {return m_store.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);} + size_t PumpAll2(bool blocking=true) + {return m_store.TransferAllTo2(*AttachedTransformation(), DEFAULT_CHANNEL, blocking);} + bool SourceExhausted() const + {return !m_store.AnyRetrievable() && !m_store.AnyMessages();} + void SetAutoSignalPropagation(int propagation) + {m_store.SetAutoSignalPropagation(propagation);} + int GetAutoSignalPropagation() const + {return m_store.GetAutoSignalPropagation();} + +protected: + T m_store; +}; + +/// \brief String-based implementation of the Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL StringSource : public SourceTemplate +{ +public: + /// \brief Construct a StringSource + /// \param attachment an optional attached transformation + StringSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a StringSource + /// \param string C-String + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringSource + /// \param string binary byte array + /// \param length size of the byte array + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringSource + /// \param string std::string + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} +}; + +/// \brief Pointer-based implementation of the Source interface +/// \details ArraySource is a typedef for StringSource. Use the third constructor for an array source. +/// The third constructor takes a pointer and length. +/// \since Crypto++ 5.6.0 +DOCUMENTED_TYPEDEF(StringSource, ArraySource); + +/// \brief std::vector-based implementation of the Source interface +/// \since Crypto++ 8.0 +class CRYPTOPP_DLL VectorSource : public SourceTemplate +{ +public: + /// \brief Construct a VectorSource + /// \param attachment an optional attached transformation + VectorSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a VectorSource + /// \param vec vector of bytes + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + VectorSource(const std::vector &vec, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(vec)));} +}; + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberSource : public SourceTemplate +{ +public: + RandomNumberSource(RandomNumberGenerator &rng, int length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) + {SourceInitialize(pumpAll, MakeParameters("RandomNumberGeneratorPointer", &rng)("RandomNumberStoreSize", length));} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/fips140.cpp b/extension/third_party/cryptopp/fips140.cpp new file mode 100644 index 00000000..4e137443 --- /dev/null +++ b/extension/third_party/cryptopp/fips140.cpp @@ -0,0 +1,84 @@ +// fips140.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "fips140.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +// Define this to 1 to turn on FIPS 140-2 compliance features, including additional tests during +// startup, random number generation, and key generation. These tests may affect performance. +#ifndef CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +#define CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 0 +#endif + +#if (CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 && !defined(OS_RNG_AVAILABLE)) +#error FIPS 140-2 compliance requires the availability of OS provided RNG. +#endif + +PowerUpSelfTestStatus g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_NOT_DONE; + +bool FIPS_140_2_ComplianceEnabled() +{ + return CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2; +} + +void SimulatePowerUpSelfTestFailure() +{ + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_FAILED; +} + +PowerUpSelfTestStatus CRYPTOPP_API GetPowerUpSelfTestStatus() +{ + return g_powerUpSelfTestStatus; +} + +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +// One variable for all threads for compatibility. Previously this +// was a ThreadLocalStorage variable, which is per-thread. Also see +// https://github.com/weidai11/cryptopp/issues/208 +static bool s_inProgress = false; +#endif + +bool PowerUpSelfTestInProgressOnThisThread() +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + return s_inProgress; +#else + return false; +#endif +} + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + s_inProgress = inProgress; +#else + CRYPTOPP_UNUSED(inProgress); +#endif +} + +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + EncryptionPairwiseConsistencyTest(encryptor, decryptor); +#else + CRYPTOPP_UNUSED(encryptor), CRYPTOPP_UNUSED(decryptor); +#endif +} + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier) +{ +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 + SignaturePairwiseConsistencyTest(signer, verifier); +#else + CRYPTOPP_UNUSED(signer), CRYPTOPP_UNUSED(verifier); +#endif +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/fips140.h b/extension/third_party/cryptopp/fips140.h new file mode 100644 index 00000000..499e8680 --- /dev/null +++ b/extension/third_party/cryptopp/fips140.h @@ -0,0 +1,112 @@ +// fips140.h - originally written and placed in the public domain by Wei Dai + +/// \file fips140.h +/// \brief Classes and functions for the FIPS 140-2 validated library +/// \details The FIPS validated library is only available on Windows as a DLL. Once compiled, +/// the library is always in FIPS mode contingent upon successful execution of +/// DoPowerUpSelfTest() or DoDllPowerUpSelfTest(). +/// \sa Visual Studio and +/// config.h on the Crypto++ wiki. + +#ifndef CRYPTOPP_FIPS140_H +#define CRYPTOPP_FIPS140_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// Exception thrown when a crypto algorithm is used after a self test fails +/// \details The self tests for an algorithm are performed by Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +class CRYPTOPP_DLL SelfTestFailure : public Exception +{ +public: + explicit SelfTestFailure(const std::string &s) : Exception(OTHER_ERROR, s) {} +}; + +/// \brief Determines whether the library provides FIPS validated cryptography +/// \return true if FIPS 140-2 validated features were enabled at compile time. +/// \details true if FIPS 140-2 validated features were enabled at compile time, +/// false otherwise. +/// \note FIPS mode is enabled at compile time. A program or other module cannot +/// arbitrarily enter or exit the mode. +CRYPTOPP_DLL bool CRYPTOPP_API FIPS_140_2_ComplianceEnabled(); + +/// \brief Status of the power-up self test +enum PowerUpSelfTestStatus { + + /// \brief The self tests have not been performed. + POWER_UP_SELF_TEST_NOT_DONE, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), but the result was failure. + POWER_UP_SELF_TEST_FAILED, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), and the result was success. + POWER_UP_SELF_TEST_PASSED +}; + +/// \brief Performs the power-up self test +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \details Performs the power-up self test, and sets the self test status to +/// POWER_UP_SELF_TEST_PASSED or POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleMac); + +/// \brief Performs the power-up self test on the DLL +/// \details Performs the power-up self test using the filename of this DLL and the +/// embedded module MAC, and sets the self test status to POWER_UP_SELF_TEST_PASSED or +/// POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algortihm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoDllPowerUpSelfTest(); + +/// \brief Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED +/// \details Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED to simulate failure. +CRYPTOPP_DLL void CRYPTOPP_API SimulatePowerUpSelfTestFailure(); + +/// \brief Provides the current power-up self test status +/// \return the current power-up self test status +CRYPTOPP_DLL PowerUpSelfTestStatus CRYPTOPP_API GetPowerUpSelfTestStatus(); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +typedef PowerUpSelfTestStatus (CRYPTOPP_API * PGetPowerUpSelfTestStatus)(); +#endif + +/// \brief Class object that calculates the MAC on the module +/// \return the MAC for the module +CRYPTOPP_DLL MessageAuthenticationCode * CRYPTOPP_API NewIntegrityCheckingMAC(); + +/// \brief Verifies the MAC on the module +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \param pActualMac the actual MAC of the components calculated by the integrity check +/// \param pMacFileLocation the offest of the MAC in the PE/PE+ module +/// \return true if the MAC is valid, false otherwise +CRYPTOPP_DLL bool CRYPTOPP_API IntegrityCheckModule(const char *moduleFilename, const byte *expectedModuleMac, SecByteBlock *pActualMac = NULLPTR, unsigned long *pMacFileLocation = NULLPTR); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// this is used by Algorithm constructor to allow Algorithm objects to be constructed for the self test +bool PowerUpSelfTestInProgressOnThisThread(); + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress); + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); +#endif + +/// \brief The placeholder used prior to embedding the actual MAC in the module. +/// \details After the DLL is built but before it is MAC'd, the string CRYPTOPP_DUMMY_DLL_MAC +/// is used as a placeholder for the actual MAC. A post-build step is performed which calculates +/// the MAC of the DLL and embeds it in the module. The actual MAC is written by the +/// cryptest.exe program using the mac_dll subcommand. +#define CRYPTOPP_DUMMY_DLL_MAC "MAC_51f34b8db820ae8" + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/fipsalgt.cpp b/extension/third_party/cryptopp/fipsalgt.cpp new file mode 100644 index 00000000..db0fc538 --- /dev/null +++ b/extension/third_party/cryptopp/fipsalgt.cpp @@ -0,0 +1,1293 @@ +// fipsalgt.cpp - originally written and placed in the public domain by Wei Dai + +// This file implements the various algorithm tests needed to pass FIPS 140 validation. +// They're preserved here (commented out) in case Crypto++ needs to be revalidated. + +#if 0 +#ifndef CRYPTOPP_IMPORTS +#define CRYPTOPP_DEFAULT_NO_DLL +#endif + +#include "dll.h" +#include "cryptlib.h" +#include "smartptr.h" +#include "filters.h" +#include "oids.h" + +USING_NAMESPACE(CryptoPP) + +class LineBreakParser : public AutoSignaling > +{ +public: + LineBreakParser(BufferedTransformation *attachment=NULLPTR, byte lineEnd='\n') + : m_lineEnd(lineEnd) {Detach(attachment);} + + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("LineBreakParser"); + + unsigned int i, last = 0; + for (i=0; iPut2(begin+last, i-last, GetAutoSignalPropagation(), blocking); + last = i+1; + } + } + if (last != i) + AttachedTransformation()->Put2(begin+last, i-last, 0, blocking); + + if (messageEnd && GetAutoSignalPropagation()) + { + AttachedTransformation()->MessageEnd(GetAutoSignalPropagation()-1, blocking); + AttachedTransformation()->MessageSeriesEnd(GetAutoSignalPropagation()-1, blocking); + } + + return 0; + } + +private: + byte m_lineEnd; +}; + +class TestDataParser : public Unflushable +{ +public: + enum DataType {OTHER, COUNT, KEY_T, IV, INPUT, OUTPUT}; + + TestDataParser(std::string algorithm, std::string test, std::string mode, unsigned int feedbackSize, bool encrypt, BufferedTransformation *attachment) + : m_algorithm(algorithm), m_test(test), m_mode(mode), m_feedbackSize(feedbackSize) + , m_firstLine(true), m_blankLineTransition(0) + { + Detach(attachment); + + m_typeToName[COUNT] = "COUNT"; + + m_nameToType["COUNT"] = COUNT; + m_nameToType["KEY"] = KEY_T; + m_nameToType["KEYs"] = KEY_T; + m_nameToType["key"] = KEY_T; + m_nameToType["Key"] = KEY_T; + m_nameToType["IV"] = IV; + m_nameToType["IV1"] = IV; + m_nameToType["CV"] = IV; + m_nameToType["CV1"] = IV; + m_nameToType["IB"] = IV; + m_nameToType["TEXT"] = INPUT; + m_nameToType["RESULT"] = OUTPUT; + m_nameToType["Msg"] = INPUT; + m_nameToType["Seed"] = INPUT; + m_nameToType["V"] = INPUT; + m_nameToType["DT"] = IV; + SetEncrypt(encrypt); + + if (m_algorithm == "DSA" || m_algorithm == "ECDSA") + { + if (m_test == "PKV") + m_trigger = "Qy"; + else if (m_test == "KeyPair") + m_trigger = "N"; + else if (m_test == "SigGen") + m_trigger = "Msg"; + else if (m_test == "SigVer") + m_trigger = "S"; + else if (m_test == "PQGGen") + m_trigger = "N"; + else if (m_test == "PQGVer") + m_trigger = "H"; + } + else if (m_algorithm == "HMAC") + m_trigger = "Msg"; + else if (m_algorithm == "SHA") + m_trigger = (m_test == "MONTE") ? "Seed" : "Msg"; + else if (m_algorithm == "RNG") + m_trigger = "V"; + else if (m_algorithm == "RSA") + m_trigger = (m_test == "Ver") ? "S" : "Msg"; + } + + void SetEncrypt(bool encrypt) + { + m_encrypt = encrypt; + if (encrypt) + { + m_nameToType["PLAINTEXT"] = INPUT; + m_nameToType["CIPHERTEXT"] = OUTPUT; + m_nameToType["PT"] = INPUT; + m_nameToType["CT"] = OUTPUT; + } + else + { + m_nameToType["PLAINTEXT"] = OUTPUT; + m_nameToType["CIPHERTEXT"] = INPUT; + m_nameToType["PT"] = OUTPUT; + m_nameToType["CT"] = INPUT; + } + + if (m_algorithm == "AES" || m_algorithm == "TDES") + { + if (encrypt) + { + m_trigger = "PLAINTEXT"; + m_typeToName[OUTPUT] = "CIPHERTEXT"; + } + else + { + m_trigger = "CIPHERTEXT"; + m_typeToName[OUTPUT] = "PLAINTEXT"; + } + m_count = 0; + } + } + +protected: + void OutputData(std::string &output, const std::string &key, const std::string &data) + { + output += key; + output += "= "; + output += data; + output += "\n"; + } + + void OutputData(std::string &output, const std::string &key, int data) + { + OutputData(output, key, IntToString(data)); + } + + void OutputData(std::string &output, const std::string &key, const SecByteBlock &data) + { + output += key; + output += "= "; + HexEncoder(new StringSink(output), false).Put(data, data.size()); + output += "\n"; + } + + void OutputData(std::string &output, const std::string &key, const Integer &data, int size=-1) + { + SecByteBlock s(size < 0 ? data.MinEncodedSize() : size); + data.Encode(s, s.size()); + OutputData(output, key, s); + } + + void OutputData(std::string &output, const std::string &key, const PolynomialMod2 &data, int size=-1) + { + SecByteBlock s(size < 0 ? data.MinEncodedSize() : size); + data.Encode(s, s.size()); + OutputData(output, key, s); + } + + void OutputData(std::string &output, DataType t, const std::string &data) + { + if (m_algorithm == "SKIPJACK") + { + if (m_test == "KAT") + { + if (t == OUTPUT) + output = m_line + data + "\n"; + } + else + { + if (t != COUNT) + { + output += m_typeToName[t]; + output += "="; + } + output += data; + output += t == OUTPUT ? "\n" : " "; + } + } + else if (m_algorithm == "TDES" && t == KEY_T && m_typeToName[KEY_T].empty()) + { + output += "KEY1 = "; + output += data.substr(0, 16); + output += "\nKEY2 = "; + output += data.size() > 16 ? data.substr(16, 16) : data.substr(0, 16); + output += "\nKEY3 = "; + output += data.size() > 32 ? data.substr(32, 16) : data.substr(0, 16); + output += "\n"; + } + else + { + output += m_typeToName[t]; + output += " = "; + output += data; + output += "\n"; + } + } + + void OutputData(std::string &output, DataType t, int i) + { + OutputData(output, t, IntToString(i)); + } + + void OutputData(std::string &output, DataType t, const SecByteBlock &data) + { + std::string hexData; + StringSource(data.begin(), data.size(), true, new HexEncoder(new StringSink(hexData), false)); + OutputData(output, t, hexData); + } + + void OutputGivenData(std::string &output, DataType t, bool optional = false) + { + if (m_data.find(m_typeToName[t]) == m_data.end()) + { + if (optional) + return; + throw Exception(Exception::OTHER_ERROR, "TestDataParser: key not found: " + m_typeToName[t]); + } + + OutputData(output, t, m_data[m_typeToName[t]]); + } + + template + BlockCipher * NewBT(T *) + { + if (!m_encrypt && (m_mode == "ECB" || m_mode == "CBC")) + return new typename T::Decryption; + else + return new typename T::Encryption; + } + + template + SymmetricCipher * NewMode(T *, BlockCipher &bt, const byte *iv) + { + if (!m_encrypt) + return new typename T::Decryption(bt, iv, m_feedbackSize/8); + else + return new typename T::Encryption(bt, iv, m_feedbackSize/8); + } + + static inline void Xor(SecByteBlock &z, const SecByteBlock &x, const SecByteBlock &y) + { + CRYPTOPP_ASSERT(x.size() == y.size()); + z.resize(x.size()); + xorbuf(z, x, y, x.size()); + } + + SecByteBlock UpdateKey(SecByteBlock key, const SecByteBlock *text) + { + unsigned int innerCount = (m_algorithm == "AES") ? 1000 : 10000; + int keySize = key.size(), blockSize = text[0].size(); + SecByteBlock x(keySize); + for (int k=0; k + void EC_KeyPair(string &output, int n, const OID &oid) + { + DL_GroupParameters_EC params(oid); + for (int i=0; i priv; + DL_PublicKey_EC pub; + priv.Initialize(m_rng, params); + priv.MakePublicKey(pub); + + OutputData(output, "d ", priv.GetPrivateExponent()); + OutputData(output, "Qx ", pub.GetPublicElement().x, params.GetCurve().GetField().MaxElementByteLength()); + OutputData(output, "Qy ", pub.GetPublicElement().y, params.GetCurve().GetField().MaxElementByteLength()); + } + } + + template + void EC_SigGen(string &output, const OID &oid) + { + DL_GroupParameters_EC params(oid); + typename ECDSA::PrivateKey priv; + typename ECDSA::PublicKey pub; + priv.Initialize(m_rng, params); + priv.MakePublicKey(pub); + + typename ECDSA::Signer signer(priv); + SecByteBlock sig(signer.SignatureLength()); + StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, signer, new ArraySink(sig, sig.size())))); + SecByteBlock R(sig, sig.size()/2), S(sig+sig.size()/2, sig.size()/2); + + OutputData(output, "Qx ", pub.GetPublicElement().x, params.GetCurve().GetField().MaxElementByteLength()); + OutputData(output, "Qy ", pub.GetPublicElement().y, params.GetCurve().GetField().MaxElementByteLength()); + OutputData(output, "R ", R); + OutputData(output, "S ", S); + } + + template + void EC_SigVer(string &output, const OID &oid) + { + SecByteBlock x(DecodeHex(m_data["Qx"])); + SecByteBlock y(DecodeHex(m_data["Qy"])); + Integer r((m_data["R"]+"h").c_str()); + Integer s((m_data["S"]+"h").c_str()); + + typename EC::FieldElement Qx(x, x.size()); + typename EC::FieldElement Qy(y, y.size()); + typename EC::Element Q(Qx, Qy); + + DL_GroupParameters_EC params(oid); + typename ECDSA::PublicKey pub; + pub.Initialize(params, Q); + typename ECDSA::Verifier verifier(pub); + + SecByteBlock sig(verifier.SignatureLength()); + r.Encode(sig, sig.size()/2); + s.Encode(sig+sig.size()/2, sig.size()/2); + + SignatureVerificationFilter filter(verifier); + filter.Put(sig, sig.size()); + StringSource(m_data["Msg"], true, new HexDecoder(new Redirector(filter, Redirector::DATA_ONLY))); + filter.MessageEnd(); + byte b; + filter.Get(b); + OutputData(output, "Result ", b ? "P" : "F"); + } + + template + static bool EC_PKV(RandomNumberGenerator &rng, const SecByteBlock &x, const SecByteBlock &y, const OID &oid) + { + typename EC::FieldElement Qx(x, x.size()); + typename EC::FieldElement Qy(y, y.size()); + typename EC::Element Q(Qx, Qy); + + DL_GroupParameters_EC params(oid); + typename ECDSA::PublicKey pub; + pub.Initialize(params, Q); + return pub.Validate(rng, 3); + } + + template + Result * CreateRSA2(const std::string &standard) + { + if (typeid(Result) == typeid(PK_Verifier)) + { + if (standard == "R") + return (Result *) new typename RSASS_ISO::Verifier; + else if (standard == "P") + return (Result *) new typename RSASS::Verifier; + else if (standard == "1") + return (Result *) new typename RSASS::Verifier; + } + else if (typeid(Result) == typeid(PK_Signer)) + { + if (standard == "R") + return (Result *) new typename RSASS_ISO::Signer; + else if (standard == "P") + return (Result *) new typename RSASS::Signer; + else if (standard == "1") + return (Result *) new typename RSASS::Signer; + } + + return NULLPTR; + } + + template + Result * CreateRSA(const std::string &standard, const std::string &hash) + { + if (hash == "1") + return CreateRSA2(standard); + else if (hash == "224") + return CreateRSA2(standard); + else if (hash == "256") + return CreateRSA2(standard); + else if (hash == "384") + return CreateRSA2(standard); + else if (hash == "512") + return CreateRSA2(standard); + else + return NULLPTR; + } + + virtual void DoTest() + { + std::string output; + + if (m_algorithm == "DSA") + { + if (m_test == "KeyPair") + { + DL_GroupParameters_DSA pqg; + int modLen = atol(m_bracketString.substr(6).c_str()); + pqg.GenerateRandomWithKeySize(m_rng, modLen); + + OutputData(output, "P ", pqg.GetModulus()); + OutputData(output, "Q ", pqg.GetSubgroupOrder()); + OutputData(output, "G ", pqg.GetSubgroupGenerator()); + + int n = atol(m_data["N"].c_str()); + for (int i=0; iPut((byte *)output.data(), output.size()); + output.resize(0); + } + } + else if (m_test == "PQGGen") + { + int n = atol(m_data["N"].c_str()); + for (int i=0; iPut((byte *)output.data(), output.size()); + output.resize(0); + } + } + else if (m_test == "SigGen") + { + std::string &encodedKey = m_data["PrivKey"]; + int modLen = atol(m_bracketString.substr(6).c_str()); + DSA::PrivateKey priv; + + if (!encodedKey.empty()) + { + StringStore s(encodedKey); + priv.BERDecode(s); + if (priv.GetGroupParameters().GetModulus().BitCount() != modLen) + encodedKey.clear(); + } + + if (encodedKey.empty()) + { + priv.Initialize(m_rng, modLen); + StringSink s(encodedKey); + priv.DEREncode(s); + OutputData(output, "P ", priv.GetGroupParameters().GetModulus()); + OutputData(output, "Q ", priv.GetGroupParameters().GetSubgroupOrder()); + OutputData(output, "G ", priv.GetGroupParameters().GetSubgroupGenerator()); + } + + DSA::Signer signer(priv); + DSA::Verifier pub(signer); + OutputData(output, "Msg ", m_data["Msg"]); + OutputData(output, "Y ", pub.GetKey().GetPublicElement()); + + SecByteBlock sig(signer.SignatureLength()); + StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, signer, new ArraySink(sig, sig.size())))); + SecByteBlock R(sig, sig.size()/2), S(sig+sig.size()/2, sig.size()/2); + OutputData(output, "R ", R); + OutputData(output, "S ", S); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + else if (m_test == "SigVer") + { + Integer p((m_data["P"] + "h").c_str()); + Integer q((m_data["Q"] + "h").c_str()); + Integer g((m_data["G"] + "h").c_str()); + Integer y((m_data["Y"] + "h").c_str()); + DSA::Verifier verifier(p, q, g, y); + + HexDecoder filter(new SignatureVerificationFilter(verifier)); + StringSource(m_data["R"], true, new Redirector(filter, Redirector::DATA_ONLY)); + StringSource(m_data["S"], true, new Redirector(filter, Redirector::DATA_ONLY)); + StringSource(m_data["Msg"], true, new Redirector(filter, Redirector::DATA_ONLY)); + filter.MessageEnd(); + byte b; + filter.Get(b); + OutputData(output, "Result ", b ? "P" : "F"); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + else if (m_test == "PQGVer") + { + Integer p((m_data["P"] + "h").c_str()); + Integer q((m_data["Q"] + "h").c_str()); + Integer g((m_data["G"] + "h").c_str()); + Integer h((m_data["H"] + "h").c_str()); + int c = atol(m_data["c"].c_str()); + SecByteBlock seed(m_data["Seed"].size()/2); + StringSource(m_data["Seed"], true, new HexDecoder(new ArraySink(seed, seed.size()))); + + Integer p1, q1; + bool result = DSA::GeneratePrimes(seed, seed.size()*8, c, p1, 1024, q1, true); + result = result && (p1 == p && q1 == q); + result = result && g == a_exp_b_mod_c(h, (p-1)/q, p); + + OutputData(output, "Result ", result ? "P" : "F"); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + + return; + } + + if (m_algorithm == "ECDSA") + { + std::map name2oid; + name2oid["P-192"] = ASN1::secp192r1(); + name2oid["P-224"] = ASN1::secp224r1(); + name2oid["P-256"] = ASN1::secp256r1(); + name2oid["P-384"] = ASN1::secp384r1(); + name2oid["P-521"] = ASN1::secp521r1(); + name2oid["K-163"] = ASN1::sect163k1(); + name2oid["K-233"] = ASN1::sect233k1(); + name2oid["K-283"] = ASN1::sect283k1(); + name2oid["K-409"] = ASN1::sect409k1(); + name2oid["K-571"] = ASN1::sect571k1(); + name2oid["B-163"] = ASN1::sect163r2(); + name2oid["B-233"] = ASN1::sect233r1(); + name2oid["B-283"] = ASN1::sect283r1(); + name2oid["B-409"] = ASN1::sect409r1(); + name2oid["B-571"] = ASN1::sect571r1(); + + if (m_test == "PKV") + { + bool pass; + if (m_bracketString[0] == 'P') + pass = EC_PKV(m_rng, DecodeHex(m_data["Qx"]), DecodeHex(m_data["Qy"]), name2oid[m_bracketString]); + else + pass = EC_PKV(m_rng, DecodeHex(m_data["Qx"]), DecodeHex(m_data["Qy"]), name2oid[m_bracketString]); + + OutputData(output, "Result ", pass ? "P" : "F"); + } + else if (m_test == "KeyPair") + { + if (m_bracketString[0] == 'P') + EC_KeyPair(output, atol(m_data["N"].c_str()), name2oid[m_bracketString]); + else + EC_KeyPair(output, atol(m_data["N"].c_str()), name2oid[m_bracketString]); + } + else if (m_test == "SigGen") + { + if (m_bracketString[0] == 'P') + EC_SigGen(output, name2oid[m_bracketString]); + else + EC_SigGen(output, name2oid[m_bracketString]); + } + else if (m_test == "SigVer") + { + if (m_bracketString[0] == 'P') + EC_SigVer(output, name2oid[m_bracketString]); + else + EC_SigVer(output, name2oid[m_bracketString]); + } + + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + return; + } + + if (m_algorithm == "RSA") + { + std::string shaAlg = m_data["SHAAlg"].substr(3); + + if (m_test == "Ver") + { + Integer n((m_data["n"] + "h").c_str()); + Integer e((m_data["e"] + "h").c_str()); + RSA::PublicKey pub; + pub.Initialize(n, e); + + member_ptr pV(CreateRSA(m_mode, shaAlg)); + pV->AccessMaterial().AssignFrom(pub); + + HexDecoder filter(new SignatureVerificationFilter(*pV)); + for (unsigned int i=m_data["S"].size(); iSignatureLength()*2; i++) + filter.Put('0'); + StringSource(m_data["S"], true, new Redirector(filter, Redirector::DATA_ONLY)); + StringSource(m_data["Msg"], true, new Redirector(filter, Redirector::DATA_ONLY)); + filter.MessageEnd(); + byte b; + filter.Get(b); + OutputData(output, "Result ", b ? "P" : "F"); + } + else + { + CRYPTOPP_ASSERT(m_test == "Gen"); + int modLen = atol(m_bracketString.substr(6).c_str()); + std::string &encodedKey = m_data["PrivKey"]; + RSA::PrivateKey priv; + + if (!encodedKey.empty()) + { + StringStore s(encodedKey); + priv.BERDecode(s); + if (priv.GetModulus().BitCount() != modLen) + encodedKey.clear(); + } + + if (encodedKey.empty()) + { + priv.Initialize(m_rng, modLen); + StringSink s(encodedKey); + priv.DEREncode(s); + OutputData(output, "n ", priv.GetModulus()); + OutputData(output, "e ", priv.GetPublicExponent(), modLen/8); + } + + member_ptr pS(CreateRSA(m_mode, shaAlg)); + pS->AccessMaterial().AssignFrom(priv); + + SecByteBlock sig(pS->SignatureLength()); + StringSource(m_data["Msg"], true, new HexDecoder(new SignerFilter(m_rng, *pS, new ArraySink(sig, sig.size())))); + OutputData(output, "SHAAlg ", m_data["SHAAlg"]); + OutputData(output, "Msg ", m_data["Msg"]); + OutputData(output, "S ", sig); + } + + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + return; + } + + if (m_algorithm == "SHA") + { + member_ptr pHF; + + if (m_mode == "1") + pHF.reset(new SHA1); + else if (m_mode == "224") + pHF.reset(new SHA224); + else if (m_mode == "256") + pHF.reset(new SHA256); + else if (m_mode == "384") + pHF.reset(new SHA384); + else if (m_mode == "512") + pHF.reset(new SHA512); + + if (m_test == "MONTE") + { + SecByteBlock seed = m_data2[INPUT]; + SecByteBlock MD[1003]; + int i,j; + + for (j=0; j<100; j++) + { + MD[0] = MD[1] = MD[2] = seed; + for (i=3; i<1003; i++) + { + SecByteBlock Mi = MD[i-3] + MD[i-2] + MD[i-1]; + MD[i].resize(pHF->DigestSize()); + pHF->CalculateDigest(MD[i], Mi, Mi.size()); + } + seed = MD[1002]; + OutputData(output, "COUNT ", j); + OutputData(output, "MD ", seed); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + } + else + { + SecByteBlock tag(pHF->DigestSize()); + SecByteBlock &msg(m_data2[INPUT]); + int len = atol(m_data["Len"].c_str()); + StringSource(msg.begin(), len/8, true, new HashFilter(*pHF, new ArraySink(tag, tag.size()))); + OutputData(output, "MD ", tag); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + return; + } + + SecByteBlock &key = m_data2[KEY_T]; + + if (m_algorithm == "TDES") + { + if (!m_data["KEY1"].empty()) + { + const std::string keys[3] = {m_data["KEY1"], m_data["KEY2"], m_data["KEY3"]}; + key.resize(24); + HexDecoder hexDec(new ArraySink(key, key.size())); + for (int i=0; i<3; i++) + hexDec.Put((byte *)keys[i].data(), keys[i].size()); + + if (keys[0] == keys[2]) + { + if (keys[0] == keys[1]) + key.resize(8); + else + key.resize(16); + } + else + key.resize(24); + } + } + + if (m_algorithm == "RNG") + { + key.resize(24); + StringSource(m_data["Key1"] + m_data["Key2"] + m_data["Key3"], true, new HexDecoder(new ArraySink(key, key.size()))); + + SecByteBlock seed(m_data2[INPUT]), dt(m_data2[IV]), r(8); + X917RNG rng(new DES_EDE3::Encryption(key, key.size()), seed, dt); + + if (m_test == "MCT") + { + for (int i=0; i<10000; i++) + rng.GenerateBlock(r, r.size()); + } + else + { + rng.GenerateBlock(r, r.size()); + } + + OutputData(output, "R ", r); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + return; + } + + if (m_algorithm == "HMAC") + { + member_ptr pMAC; + + if (m_bracketString == "L=20") + pMAC.reset(new HMAC); + else if (m_bracketString == "L=28") + pMAC.reset(new HMAC); + else if (m_bracketString == "L=32") + pMAC.reset(new HMAC); + else if (m_bracketString == "L=48") + pMAC.reset(new HMAC); + else if (m_bracketString == "L=64") + pMAC.reset(new HMAC); + else + throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected HMAC bracket string: " + m_bracketString); + + pMAC->SetKey(key, key.size()); + int Tlen = atol(m_data["Tlen"].c_str()); + SecByteBlock tag(Tlen); + StringSource(m_data["Msg"], true, new HexDecoder(new HashFilter(*pMAC, new ArraySink(tag, Tlen), false, Tlen))); + OutputData(output, "Mac ", tag); + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + return; + } + + member_ptr pBT; + if (m_algorithm == "DES") + pBT.reset(NewBT((DES*)0)); + else if (m_algorithm == "TDES") + { + if (key.size() == 8) + pBT.reset(NewBT((DES*)0)); + else if (key.size() == 16) + pBT.reset(NewBT((DES_EDE2*)0)); + else + pBT.reset(NewBT((DES_EDE3*)0)); + } + else if (m_algorithm == "SKIPJACK") + pBT.reset(NewBT((SKIPJACK*)0)); + else if (m_algorithm == "AES") + pBT.reset(NewBT((AES*)0)); + else + throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected algorithm: " + m_algorithm); + + if (!pBT->IsValidKeyLength(key.size())) + key.CleanNew(pBT->DefaultKeyLength()); // for Scbcvrct + pBT->SetKey(key.data(), key.size()); + + SecByteBlock &iv = m_data2[IV]; + if (iv.empty()) + iv.CleanNew(pBT->BlockSize()); + + member_ptr pCipher; + unsigned int K = m_feedbackSize; + + if (m_mode == "ECB") + pCipher.reset(NewMode((ECB_Mode_ExternalCipher*)0, *pBT, iv)); + else if (m_mode == "CBC") + pCipher.reset(NewMode((CBC_Mode_ExternalCipher*)0, *pBT, iv)); + else if (m_mode == "CFB") + pCipher.reset(NewMode((CFB_Mode_ExternalCipher*)0, *pBT, iv)); + else if (m_mode == "OFB") + pCipher.reset(NewMode((OFB_Mode_ExternalCipher*)0, *pBT, iv)); + else + throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected mode: " + m_mode); + + bool encrypt = m_encrypt; + + if (m_test == "MONTE") + { + SecByteBlock KEY[401]; + KEY[0] = key; + int keySize = key.size(); + int blockSize = pBT->BlockSize(); + + std::vector IB(10001), OB(10001), PT(10001), CT(10001), RESULT(10001), TXT(10001), CV(10001); + PT[0] = GetData("PLAINTEXT"); + CT[0] = GetData("CIPHERTEXT"); + CV[0] = IB[0] = iv; + TXT[0] = GetData("TEXT"); + + int outerCount = (m_algorithm == "AES") ? 100 : 400; + int innerCount = (m_algorithm == "AES") ? 1000 : 10000; + + for (int i=0; iSetKey(KEY[i], keySize); + + for (int j=0; jProcessBlock(IB[j], CT[j]); + PT[j+1] = CT[j]; + } + else + { + IB[j] = CT[j]; + PT[j].resize(blockSize); + pBT->ProcessBlock(IB[j], PT[j]); + CT[j+1] = PT[j]; + } + } + else if (m_mode == "OFB") + { + OB[j].resize(blockSize); + pBT->ProcessBlock(IB[j], OB[j]); + Xor(RESULT[j], OB[j], TXT[j]); + TXT[j+1] = IB[j]; + IB[j+1] = OB[j]; + } + else if (m_mode == "CBC") + { + if (encrypt) + { + Xor(IB[j], PT[j], CV[j]); + CT[j].resize(blockSize); + pBT->ProcessBlock(IB[j], CT[j]); + PT[j+1] = CV[j]; + CV[j+1] = CT[j]; + } + else + { + IB[j] = CT[j]; + OB[j].resize(blockSize); + pBT->ProcessBlock(IB[j], OB[j]); + Xor(PT[j], OB[j], CV[j]); + CV[j+1] = CT[j]; + CT[j+1] = PT[j]; + } + } + else if (m_mode == "CFB") + { + if (encrypt) + { + OB[j].resize(blockSize); + pBT->ProcessBlock(IB[j], OB[j]); + AssignLeftMostBits(CT[j], OB[j], K); + Xor(CT[j], CT[j], PT[j]); + AssignLeftMostBits(PT[j+1], IB[j], K); + IB[j+1].resize(blockSize); + memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); + memcpy(IB[j+1]+blockSize-K/8, CT[j], K/8); + } + else + { + OB[j].resize(blockSize); + pBT->ProcessBlock(IB[j], OB[j]); + AssignLeftMostBits(PT[j], OB[j], K); + Xor(PT[j], PT[j], CT[j]); + IB[j+1].resize(blockSize); + memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); + memcpy(IB[j+1]+blockSize-K/8, CT[j], K/8); + AssignLeftMostBits(CT[j+1], OB[j], K); + } + } + else + throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected mode: " + m_mode); + } + + OutputData(output, COUNT, IntToString(i)); + OutputData(output, KEY_T, KEY[i]); + if (m_mode == "CBC") + OutputData(output, IV, CV[0]); + if (m_mode == "OFB" || m_mode == "CFB") + OutputData(output, IV, IB[0]); + if (m_mode == "ECB" || m_mode == "CBC" || m_mode == "CFB") + { + if (encrypt) + { + OutputData(output, INPUT, PT[0]); + OutputData(output, OUTPUT, CT[innerCount-1]); + KEY[i+1] = UpdateKey(KEY[i], &CT[0]); + } + else + { + OutputData(output, INPUT, CT[0]); + OutputData(output, OUTPUT, PT[innerCount-1]); + KEY[i+1] = UpdateKey(KEY[i], &PT[0]); + } + PT[0] = PT[innerCount]; + IB[0] = IB[innerCount]; + CV[0] = CV[innerCount]; + CT[0] = CT[innerCount]; + } + else if (m_mode == "OFB") + { + OutputData(output, INPUT, TXT[0]); + OutputData(output, OUTPUT, RESULT[innerCount-1]); + KEY[i+1] = UpdateKey(KEY[i], &RESULT[0]); + Xor(TXT[0], TXT[0], IB[innerCount-1]); + IB[0] = OB[innerCount-1]; + } + output += "\n"; + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + } + } + else if (m_test == "MCT") + { + SecByteBlock KEY[101]; + KEY[0] = key; + int keySize = key.size(); + int blockSize = pBT->BlockSize(); + + SecByteBlock ivs[101], inputs[1001], outputs[1001]; + ivs[0] = iv; + inputs[0] = m_data2[INPUT]; + + for (int i=0; i<100; i++) + { + pCipher->SetKey(KEY[i], keySize, MakeParameters(Name::IV(), (const byte *)ivs[i])(Name::FeedbackSize(), (int)K/8, false)); + + for (int j=0; j<1000; j++) + { + outputs[j] = inputs[j]; + pCipher->ProcessString(outputs[j], outputs[j].size()); + if (K==8 && m_mode == "CFB") + { + if (j<16) + inputs[j+1].Assign(ivs[i]+j, 1); + else + inputs[j+1] = outputs[j-16]; + } + else if (m_mode == "ECB") + inputs[j+1] = outputs[j]; + else if (j == 0) + inputs[j+1] = ivs[i]; + else + inputs[j+1] = outputs[j-1]; + } + + if (m_algorithm == "AES") + OutputData(output, COUNT, m_count++); + OutputData(output, KEY_T, KEY[i]); + if (m_mode != "ECB") + OutputData(output, IV, ivs[i]); + OutputData(output, INPUT, inputs[0]); + OutputData(output, OUTPUT, outputs[999]); + output += "\n"; + AttachedTransformation()->Put((byte *)output.data(), output.size()); + output.resize(0); + + KEY[i+1] = UpdateKey(KEY[i], outputs); + ivs[i+1].CleanNew(pCipher->IVSize()); + ivs[i+1] = UpdateKey(ivs[i+1], outputs); + if (K==8 && m_mode == "CFB") + inputs[0] = outputs[999-16]; + else if (m_mode == "ECB") + inputs[0] = outputs[999]; + else + inputs[0] = outputs[998]; + } + } + else + { + CRYPTOPP_ASSERT(m_test == "KAT"); + + SecByteBlock &input = m_data2[INPUT]; + SecByteBlock result(input.size()); + member_ptr pFilter(new StreamTransformationFilter(*pCipher, new ArraySink(result, result.size()), StreamTransformationFilter::NO_PADDING)); + StringSource(input.data(), input.size(), true, pFilter.release()); + + OutputGivenData(output, COUNT, true); + OutputData(output, KEY_T, key); + OutputGivenData(output, IV, true); + OutputGivenData(output, INPUT); + OutputData(output, OUTPUT, result); + output += "\n"; + AttachedTransformation()->Put((byte *)output.data(), output.size()); + } + } + + std::vector Tokenize(const std::string &line) + { + std::vector result; + std::string s; + for (unsigned int i=0; i") + { + CRYPTOPP_ASSERT(m_test == "sha"); + m_bracketString = m_line.substr(2, m_line.size()-4); + m_line = m_line.substr(0, 13) + "Hashes") + copyLine = true; + + if (m_line == "Put((byte *)m_line.data(), m_line.size(), blocking); + return false; + } + + std::vector tokens = Tokenize(m_line); + + if (m_algorithm == "DSA" && m_test == "sha") + { + for (unsigned int i = 0; i < tokens.size(); i++) + { + if (tokens[i] == "^") + DoTest(); + else if (tokens[i] != "") + m_compactString.push_back(atol(tokens[i].c_str())); + } + } + else + { + if (!m_line.empty() && ((m_algorithm == "RSA" && m_test != "Gen") || m_algorithm == "RNG" || m_algorithm == "HMAC" || m_algorithm == "SHA" || (m_algorithm == "ECDSA" && m_test != "KeyPair") || (m_algorithm == "DSA" && (m_test == "PQGVer" || m_test == "SigVer")))) + { + // copy input to output + std::string output = m_line + '\n'; + AttachedTransformation()->Put((byte *)output.data(), output.size()); + } + + for (unsigned int i = 0; i < tokens.size(); i++) + { + if (m_firstLine && m_algorithm != "DSA") + { + if (tokens[i] == "Encrypt" || tokens[i] == "OFB") + SetEncrypt(true); + else if (tokens[i] == "Decrypt") + SetEncrypt(false); + else if (tokens[i] == "Modes") + m_test = "MONTE"; + } + else + { + if (tokens[i] != "=") + continue; + + if (i == 0) + throw Exception(Exception::OTHER_ERROR, "TestDataParser: unexpected data: " + m_line); + + const std::string &key = tokens[i-1]; + std::string &data = m_data[key]; + data = (tokens.size() > i+1) ? tokens[i+1] : ""; + DataType t = m_nameToType[key]; + m_typeToName[t] = key; + m_data2[t] = DecodeHex(data); + + if (key == m_trigger || (t == OUTPUT && !m_data2[INPUT].empty() && !isspace(m_line[0]))) + DoTest(); + } + } + } + + m_firstLine = false; + + return false; + } + + inline const SecByteBlock & GetData(const std::string &key) + { + return m_data2[m_nameToType[key]]; + } + + static SecByteBlock DecodeHex(const std::string &data) + { + SecByteBlock data2(data.size() / 2); + StringSource(data, true, new HexDecoder(new ArraySink(data2, data2.size()))); + return data2; + } + + std::string m_algorithm, m_test, m_mode, m_line, m_bracketString, m_trigger; + unsigned int m_feedbackSize, m_blankLineTransition; + bool m_encrypt, m_firstLine; + + typedef std::map NameToTypeMap; + NameToTypeMap m_nameToType; + typedef std::map TypeToNameMap; + TypeToNameMap m_typeToName; + + typedef std::map Map; + Map m_data; // raw data + typedef std::map Map2; + Map2 m_data2; + int m_count; + + AutoSeededX917RNG m_rng; + std::vector m_compactString; +}; + +int FIPS_140_AlgorithmTest(int argc, char **argv) +{ + argc--; + argv++; + + std::string algorithm = argv[1]; + std::string pathname = argv[2]; + unsigned int i = pathname.find_last_of("\\/"); + std::string filename = pathname.substr(i == std::string::npos ? 0 : i+1); + std::string dirname = pathname.substr(0, i); + + if (algorithm == "auto") + { + string algTable[] = {"AES", "ECDSA", "DSA", "HMAC", "RNG", "RSA", "TDES", "SKIPJACK", "SHA"}; // order is important here + for (i=0; i 3) + { + std::string outDir = argv[3]; + + if (outDir == "auto") + { + if (dirname.substr(dirname.size()-3) == "req") + outDir = dirname.substr(0, dirname.size()-3) + "resp"; + } + + if (*outDir.rbegin() != '\\' && *outDir.rbegin() != '/') + outDir += '/'; + std::string outPathname = outDir + filename.substr(0, filename.size() - 3) + "rsp"; + pSink = new FileSink(outPathname.c_str(), false); + } + else + pSink = new FileSink(cout); + + FileSource(pathname.c_str(), true, new LineBreakParser(new TestDataParser(algorithm, test, mode, feedbackSize, encrypt, pSink)), false); + } + catch (...) + { + cout << "file: " << filename << endl; + throw; + } + return 0; +} + +extern int (*AdhocTest)(int argc, char *argv[]); +static int s_i = (AdhocTest = &FIPS_140_AlgorithmTest, 0); +#endif diff --git a/extension/third_party/cryptopp/fipstest.cpp b/extension/third_party/cryptopp/fipstest.cpp new file mode 100644 index 00000000..3e609f88 --- /dev/null +++ b/extension/third_party/cryptopp/fipstest.cpp @@ -0,0 +1,652 @@ +// fipstest.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#define CRYPTOPP_DEFAULT_NO_DLL +#include "dll.h" +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" +#include "pkcspad.h" +#include "misc.h" + +// Simply disable CRYPTOPP_WIN32_AVAILABLE for Windows Phone and Windows Store apps +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if defined(WINAPI_FAMILY) +# if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# undef CRYPTOPP_WIN32_AVAILABLE +# endif +# endif +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif + +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# ifdef _M_IX86 +# define _CRT_DEBUGGER_HOOK _crt_debugger_hook +# else +# define _CRT_DEBUGGER_HOOK __crt_debugger_hook +# endif +# if _MSC_VER < 1900 +extern "C" {_CRTIMP void __cdecl _CRT_DEBUGGER_HOOK(int);} +# else +extern "C" {void __cdecl _CRT_DEBUGGER_HOOK(int); } +# endif +#endif +#endif // CRYPTOPP_WIN32_AVAILABLE + +#include +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100 4702) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +extern PowerUpSelfTestStatus g_powerUpSelfTestStatus; +SecByteBlock g_actualMac; +unsigned long g_macFileLocation = 0; + +// $ grep -iIR baseaddress *.*proj +// cryptdll.vcxproj: 0x42900000 +// cryptdll.vcxproj: 0x42900000 +// cryptdll.vcxproj: 0x42900000 +// cryptdll.vcxproj: 0x42900000 +const void* g_BaseAddressOfMAC = reinterpret_cast(0x42900000); + +// use a random dummy string here, to be searched/replaced later with the real MAC +static const byte s_moduleMac[CryptoPP::HMAC::DIGESTSIZE] = CRYPTOPP_DUMMY_DLL_MAC; +CRYPTOPP_COMPILE_ASSERT(sizeof(s_moduleMac) == CryptoPP::SHA1::DIGESTSIZE); + +#ifdef CRYPTOPP_WIN32_AVAILABLE +static HMODULE s_hModule = NULLPTR; +#endif + +const byte * CRYPTOPP_API GetActualMacAndLocation(unsigned int &macSize, unsigned int &fileLocation) +{ + macSize = (unsigned int)g_actualMac.size(); + fileLocation = g_macFileLocation; + return g_actualMac; +} + +void KnownAnswerTest(RandomNumberGenerator &rng, const char *output) +{ + EqualityComparisonFilter comparison; + + RandomNumberStore(rng, strlen(output)/2).TransferAllTo(comparison, "0"); + StringSource(output, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +template +void X917RNG_KnownAnswerTest( + const char *key, + const char *seed, + const char *deterministicTimeVector, + const char *output) +{ +#ifdef OS_RNG_AVAILABLE + std::string decodedKey, decodedSeed, decodedDeterministicTimeVector; + StringSource(key, true, new HexDecoder(new StringSink(decodedKey))); + StringSource(seed, true, new HexDecoder(new StringSink(decodedSeed))); + StringSource(deterministicTimeVector, true, new HexDecoder(new StringSink(decodedDeterministicTimeVector))); + + AutoSeededX917RNG rng(false, false); + rng.Reseed((const byte *)decodedKey.data(), decodedKey.size(), (const byte *)decodedSeed.data(), (const byte *)decodedDeterministicTimeVector.data()); + KnownAnswerTest(rng, output); +#else + throw 0; +#endif +} + +void KnownAnswerTest(StreamTransformation &encryption, StreamTransformation &decryption, const char *plaintext, const char *ciphertext) +{ + EqualityComparisonFilter comparison; + + StringSource(plaintext, true, new HexDecoder(new StreamTransformationFilter(encryption, new ChannelSwitch(comparison, "0"), StreamTransformationFilter::NO_PADDING))); + StringSource(ciphertext, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + StringSource(ciphertext, true, new HexDecoder(new StreamTransformationFilter(decryption, new ChannelSwitch(comparison, "0"), StreamTransformationFilter::NO_PADDING))); + StringSource(plaintext, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +template +void SymmetricEncryptionKnownAnswerTest( + const char *key, + const char *hexIV, + const char *plaintext, + const char *ecb, + const char *cbc, + const char *cfb, + const char *ofb, + const char *ctr) +{ + std::string decodedKey; + StringSource(key, true, new HexDecoder(new StringSink(decodedKey))); + + typename CIPHER::Encryption encryption((const byte *)decodedKey.data(), decodedKey.size()); + typename CIPHER::Decryption decryption((const byte *)decodedKey.data(), decodedKey.size()); + + SecByteBlock iv(encryption.BlockSize()); + StringSource(hexIV, true, new HexDecoder(new ArraySink(iv, iv.size()))); + + if (ecb) + KnownAnswerTest(ECB_Mode_ExternalCipher::Encryption(encryption).Ref(), ECB_Mode_ExternalCipher::Decryption(decryption).Ref(), plaintext, ecb); + if (cbc) + KnownAnswerTest(CBC_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CBC_Mode_ExternalCipher::Decryption(decryption, iv).Ref(), plaintext, cbc); + if (cfb) + KnownAnswerTest(CFB_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CFB_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, cfb); + if (ofb) + KnownAnswerTest(OFB_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), OFB_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, ofb); + if (ctr) + KnownAnswerTest(CTR_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), CTR_Mode_ExternalCipher::Decryption(encryption, iv).Ref(), plaintext, ctr); +} + +void KnownAnswerTest(HashTransformation &hash, const char *message, const char *digest) +{ + EqualityComparisonFilter comparison; + StringSource(digest, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + StringSource(message, true, new HashFilter(hash, new ChannelSwitch(comparison, "0"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +template +void SecureHashKnownAnswerTest(const char *message, const char *digest) +{ + HASH hash; + KnownAnswerTest(hash, message, digest); +} + +template +void MAC_KnownAnswerTest(const char *key, const char *message, const char *digest) +{ + std::string decodedKey; + StringSource(key, true, new HexDecoder(new StringSink(decodedKey))); + + MAC mac((const byte *)decodedKey.data(), decodedKey.size()); + KnownAnswerTest(mac, message, digest); +} + +template +void SignatureKnownAnswerTest(const char *key, const char *message, const char *signature) +{ + typename SCHEME::Signer signer(StringSource(key, true, new HexDecoder).Ref()); + typename SCHEME::Verifier verifier(signer); + + RandomPool rng; + EqualityComparisonFilter comparison; + + StringSource(message, true, new SignerFilter(rng, signer, new ChannelSwitch(comparison, "0"))); + StringSource(signature, true, new HexDecoder(new ChannelSwitch(comparison, "1"))); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); + + SignatureVerificationFilter verifierFilter(verifier, NULLPTR, SignatureVerificationFilter::SIGNATURE_AT_BEGIN | SignatureVerificationFilter::THROW_EXCEPTION); + StringSource(signature, true, new HexDecoder(new Redirector(verifierFilter, Redirector::DATA_ONLY))); + StringSource(message, true, new Redirector(verifierFilter)); +} + +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor) +{ + try + { + RandomPool rng; + const char *testMessage ="test message"; + std::string ciphertext, decrypted; + + StringSource( + testMessage, + true, + new PK_EncryptorFilter( + rng, + encryptor, + new StringSink(ciphertext))); + + if (ciphertext == testMessage) + throw 0; + + StringSource( + ciphertext, + true, + new PK_DecryptorFilter( + rng, + decryptor, + new StringSink(decrypted))); + + if (decrypted != testMessage) + throw 0; + } + catch (...) + { + throw SelfTestFailure(encryptor.AlgorithmName() + ": pairwise consistency test failed"); + } +} + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier) +{ + try + { + RandomPool rng; + + StringSource( + "test message", + true, + new SignerFilter( + rng, + signer, + new SignatureVerificationFilter(verifier, NULLPTR, SignatureVerificationFilter::THROW_EXCEPTION), + true)); + } + catch (...) + { + throw SelfTestFailure(signer.AlgorithmName() + ": pairwise consistency test failed"); + } +} + +template +void SignaturePairwiseConsistencyTest(const char *key) +{ + typename SCHEME::Signer signer(StringSource(key, true, new HexDecoder).Ref()); + typename SCHEME::Verifier verifier(signer); + + SignaturePairwiseConsistencyTest(signer, verifier); +} + +MessageAuthenticationCode * NewIntegrityCheckingMAC() +{ + byte key[] = {0x47, 0x1E, 0x33, 0x96, 0x65, 0xB1, 0x6A, 0xED, 0x0B, 0xF8, 0x6B, 0xFD, 0x01, 0x65, 0x05, 0xCC}; + return new HMAC(key, sizeof(key)); +} + +bool IntegrityCheckModule(const char *moduleFilename, const byte *expectedModuleMac, SecByteBlock *pActualMac, unsigned long *pMacFileLocation) +{ + member_ptr mac(NewIntegrityCheckingMAC()); + unsigned int macSize = mac->DigestSize(); + + SecByteBlock tempMac; + SecByteBlock &actualMac = pActualMac ? *pActualMac : tempMac; + actualMac.resize(macSize); + + unsigned long tempLocation = 0; + unsigned long &macFileLocation = pMacFileLocation ? *pMacFileLocation : tempLocation; + macFileLocation = 0; + + MeterFilter verifier(new HashFilter(*mac, new ArraySink(actualMac, actualMac.size()))); +// MeterFilter verifier(new FileSink("c:\\dt.tmp")); + std::ifstream moduleStream; + +#ifdef CRYPTOPP_WIN32_AVAILABLE + HMODULE h = NULLPTR; + { + const size_t FIPS_MODULE_MAX_PATH = 2*MAX_PATH; + char moduleFilenameBuf[FIPS_MODULE_MAX_PATH] = ""; + if (moduleFilename == NULLPTR) + { +#if (_MSC_VER >= 1400 && !defined(_STLPORT_VERSION)) // ifstream doesn't support wide filename on other compilers + wchar_t wideModuleFilename[FIPS_MODULE_MAX_PATH]; + if (GetModuleFileNameW(s_hModule, wideModuleFilename, FIPS_MODULE_MAX_PATH) > 0) + { + moduleStream.open(wideModuleFilename, std::ios::in | std::ios::binary); + h = GetModuleHandleW(wideModuleFilename); + } + else +#endif + { + GetModuleFileNameA(s_hModule, moduleFilenameBuf, FIPS_MODULE_MAX_PATH); + moduleFilename = moduleFilenameBuf; + } + } +#endif + if (moduleFilename != NULLPTR) + { + moduleStream.open(moduleFilename, std::ios::in | std::ios::binary); +#ifdef CRYPTOPP_WIN32_AVAILABLE + h = GetModuleHandleA(moduleFilename); + moduleFilename = NULLPTR; + } +#endif + } + +#ifdef CRYPTOPP_WIN32_AVAILABLE + if (h == g_BaseAddressOfMAC) + { + std::ostringstream oss; + oss << "Crypto++ DLL loaded at base address " << std::hex << h << ".\n"; + OutputDebugStringA(oss.str().c_str()); + } + else + { + std::ostringstream oss; + oss << "Crypto++ DLL integrity check may fail. Expected module base address is "; + oss << std::hex << g_BaseAddressOfMAC << ", but module loaded at " << h << ".\n"; + OutputDebugStringA(oss.str().c_str()); + } +#endif + + if (!moduleStream) + { +#ifdef CRYPTOPP_WIN32_AVAILABLE + OutputDebugStringA("Crypto++ DLL integrity check failed. Cannot open file for reading."); +#endif + return false; + } + FileStore file(moduleStream); + +#ifdef CRYPTOPP_WIN32_AVAILABLE + // try to hash from memory first + const byte *memBase = (const byte *)h; + const IMAGE_DOS_HEADER *ph = (IMAGE_DOS_HEADER *)memBase; + const IMAGE_NT_HEADERS *phnt = (IMAGE_NT_HEADERS *)(memBase + ph->e_lfanew); + const IMAGE_SECTION_HEADER *phs = IMAGE_FIRST_SECTION(phnt); + DWORD nSections = phnt->FileHeader.NumberOfSections; + size_t currentFilePos = 0; + + size_t checksumPos = (byte *)&phnt->OptionalHeader.CheckSum - memBase; + size_t checksumSize = sizeof(phnt->OptionalHeader.CheckSum); + size_t certificateTableDirectoryPos = (byte *)&phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] - memBase; + size_t certificateTableDirectorySize = sizeof(phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]); + size_t certificateTablePos = phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress; + size_t certificateTableSize = phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + + verifier.AddRangeToSkip(0, checksumPos, checksumSize); + verifier.AddRangeToSkip(0, certificateTableDirectoryPos, certificateTableDirectorySize); + verifier.AddRangeToSkip(0, certificateTablePos, certificateTableSize); + + while (nSections--) + { + switch (phs->Characteristics) + { + default: + break; + case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: + case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: + unsigned int sectionSize = STDMIN(phs->SizeOfRawData, phs->Misc.VirtualSize); + const byte *sectionMemStart = memBase + phs->VirtualAddress; + unsigned int sectionFileStart = phs->PointerToRawData; + size_t subSectionStart = 0, nextSubSectionStart; + + do + { + const byte *subSectionMemStart = sectionMemStart + subSectionStart; + size_t subSectionFileStart = sectionFileStart + subSectionStart; + size_t subSectionSize = sectionSize - subSectionStart; + nextSubSectionStart = 0; + + unsigned int entriesToReadFromDisk[] = {IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT}; + for (unsigned int i=0; iOptionalHeader.DataDirectory[entriesToReadFromDisk[i]]; + const byte *entryMemStart = memBase + entry.VirtualAddress; + if (subSectionMemStart <= entryMemStart && entryMemStart < subSectionMemStart + subSectionSize) + { + subSectionSize = entryMemStart - subSectionMemStart; + nextSubSectionStart = entryMemStart - sectionMemStart + entry.Size; + } + } + + // Visual Studio 2019 is MSC_VER == 1920 + // https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nds +#if (_MSC_VER >= 1400 && _MSC_VER < 1920) && (defined(_M_IX86) || defined(_M_X64)) + // first byte of _CRT_DEBUGGER_HOOK gets modified in memory by the debugger invisibly, so read it from file + if (IsDebuggerPresent()) + { + if (subSectionMemStart <= (byte *)&_CRT_DEBUGGER_HOOK && (byte *)&_CRT_DEBUGGER_HOOK < subSectionMemStart + subSectionSize) + { + subSectionSize = (byte *)&_CRT_DEBUGGER_HOOK - subSectionMemStart; + nextSubSectionStart = (byte *)&_CRT_DEBUGGER_HOOK - sectionMemStart + 1; + } + } +#endif + + if (subSectionMemStart <= expectedModuleMac && expectedModuleMac < subSectionMemStart + subSectionSize) + { + // found stored MAC + macFileLocation = (unsigned long)(subSectionFileStart + (expectedModuleMac - subSectionMemStart)); + verifier.AddRangeToSkip(0, macFileLocation, macSize); + } + + file.TransferTo(verifier, subSectionFileStart - currentFilePos); + verifier.Put(subSectionMemStart, subSectionSize); + file.Skip(subSectionSize); + currentFilePos = subSectionFileStart + subSectionSize; + subSectionStart = nextSubSectionStart; + } while (nextSubSectionStart != 0); + } + phs++; + } +#endif + file.TransferAllTo(verifier); + +#ifdef CRYPTOPP_WIN32_AVAILABLE + // if that fails (could be caused by debug breakpoints or DLL base relocation modifying image in memory), + // hash from disk instead + if (!VerifyBufsEqual(expectedModuleMac, actualMac, macSize)) + { + OutputDebugStringA("Crypto++ DLL in-memory integrity check failed. This may be caused by debug breakpoints or DLL relocation.\n"); + moduleStream.clear(); + moduleStream.seekg(0); + verifier.Initialize(MakeParameters(Name::OutputBuffer(), ByteArrayParameter(actualMac, (unsigned int)actualMac.size()))); +// verifier.Initialize(MakeParameters(Name::OutputFileName(), (const char *)"c:\\dt2.tmp")); + verifier.AddRangeToSkip(0, checksumPos, checksumSize); + verifier.AddRangeToSkip(0, certificateTableDirectoryPos, certificateTableDirectorySize); + verifier.AddRangeToSkip(0, certificateTablePos, certificateTableSize); + verifier.AddRangeToSkip(0, macFileLocation, macSize); + FileStore(moduleStream).TransferAllTo(verifier); + } +#endif + + if (VerifyBufsEqual(expectedModuleMac, actualMac, macSize)) + return true; + +#ifdef CRYPTOPP_WIN32_AVAILABLE + std::string hexMac; + HexEncoder(new StringSink(hexMac)).PutMessageEnd(actualMac, actualMac.size()); + OutputDebugStringA((("Crypto++ DLL integrity check failed. Actual MAC is: " + hexMac) + ".\n").c_str()); +#endif + return false; +} + +void DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleMac) +{ + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_NOT_DONE; + SetPowerUpSelfTestInProgressOnThisThread(true); + + try + { + if (FIPS_140_2_ComplianceEnabled() || expectedModuleMac != NULLPTR) + { + if (!IntegrityCheckModule(moduleFilename, expectedModuleMac, &g_actualMac, &g_macFileLocation)) + throw 0; // throw here so we break in the debugger, this will be caught right away + } + + // algorithm tests + + X917RNG_KnownAnswerTest( + "2b7e151628aed2a6abf7158809cf4f3c", // key + "000102030405060708090a0b0c0d0e0f", // seed + "00000000000000000000000000000001", // time vector + "D176EDD27493B0395F4D10546232B0693DC7061C03C3A554F09CECF6F6B46D945A"); // output + + SymmetricEncryptionKnownAnswerTest( + "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E", + "C141B5FCCD28DC8A", + "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68", + "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4", + "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9", + "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B", + "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62", + "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371"); + + SymmetricEncryptionKnownAnswerTest( + "1555E5531C3A169B2D65", + "6EC9795701F49864", + "00AFA48E9621E52E8CBDA312660184EDDB1F33D9DACDA8DA", + "DBEC73562EFCAEB56204EB8AE9557EBF77473FBB52D17CD1", + "0C7B0B74E21F99B8F2C8DF37879F6C044967F42A796DCA8B", + "79FDDA9724E36CC2E023E9A5C717A8A8A7FDA465CADCBF63", + "79FDDA9724E36CC26CACBD83C1ABC06EAF5B249BE5B1E040", + "79FDDA9724E36CC211B0AEC607B95A96BCDA318440B82F49"); + + SymmetricEncryptionKnownAnswerTest( + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", // plaintext + "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4", // ecb + "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7", // cbc + "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6", // cfb + "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e", // ofb + NULLPTR); + + SymmetricEncryptionKnownAnswerTest( + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + NULLPTR, + NULLPTR, + NULLPTR, + NULLPTR, + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"); // ctr + + + SecureHashKnownAnswerTest( + "abc", + "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + SecureHashKnownAnswerTest( + "abc", + "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"); + + SecureHashKnownAnswerTest( + "abc", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + SecureHashKnownAnswerTest( + "abc", + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"); + + SecureHashKnownAnswerTest( + "abc", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); + + MAC_KnownAnswerTest >( + "303132333435363738393a3b3c3d3e3f40414243", + "Sample #2", + "0922d3405faa3d194f82a45830737d5cc6c75d24"); + + const char *keyRSA1 = + "30820150020100300d06092a864886f70d01010105000482013a3082013602010002400a66791dc6988168de7ab77419bb7fb0" + "c001c62710270075142942e19a8d8c51d053b3e3782a1de5dc5af4ebe99468170114a1dfe67cdc9a9af55d655620bbab0203010001" + "02400123c5b61ba36edb1d3679904199a89ea80c09b9122e1400c09adcf7784676d01d23356a7d44d6bd8bd50e94bfc723fa" + "87d8862b75177691c11d757692df8881022033d48445c859e52340de704bcdda065fbb4058d740bd1d67d29e9c146c11cf61" + "0220335e8408866b0fd38dc7002d3f972c67389a65d5d8306566d5c4f2a5aa52628b0220045ec90071525325d3d46db79695e9af" + "acc4523964360e02b119baa366316241022015eb327360c7b60d12e5e2d16bdcd97981d17fba6b70db13b20b436e24eada590220" + "2ca6366d72781dfa24d34a9a24cbc2ae927a9958af426563ff63fb11658a461d"; + + const char *keyRSA2 = + "30820273020100300D06092A864886F70D01010105000482025D3082025902010002818100D40AF9" + "A2B713034249E5780056D70FC7DE75D76E44565AA6A6B8ED9646F3C19F9E254D72D7DE6E49DB2264" + "0C1D05AB9E2A5F901D8F3FE1F7AE02CEE2ECCE54A40ABAE55A004692752E70725AEEE7CDEA67628A" + "82A9239B4AB660C2BC56D9F01E90CBAAB9BF0FC8E17173CEFC5709A29391A7DDF3E0B758691AAF30" + "725B292F4F020111027F18C0BA087D082C45D75D3594E0767E4820818EB35612B80CEAB8C880ACA5" + "44B6876DFFEF85A576C0D45B551AFAA1FD63209CD745DF75C5A0F0B580296EA466CD0338207E4752" + "FF4E7DB724D8AE18CE5CF4153BB94C27869FBB50E64F02546E4B02997A0B8623E64017CC770759C6" + "695DB649EEFD829D688D441BCC4E7348F1024100EF86DD7AF3F32CDE8A9F6564E43A559A0C9F8BAD" + "36CC25330548B347AC158A345631FA90F7B873C36EFFAE2F7823227A3F580B5DD18304D5932751E7" + "43E9234F024100E2A039854B55688740E32A51DF4AF88613D91A371CF8DDD95D780A89D7CF2119A9" + "54F1AC0F3DCDB2F6959926E6D9D37D8BC07A4C634DE6F16315BD5F0DAC340102407ECEEDB9903572" + "1B76909F174BA6698DCA72953D957B22C0A871C8531EDE3A1BB52984A719BC010D1CA57A555DB83F" + "6DE54CBAB932AEC652F38D497A6F3F30CF024100854F30E4FF232E6DADB2CD99926855F484255AB7" + "01FBCDCB27EC426F33A7046972AA700ADBCA008763DF87440F52F4E070531AC385B55AAC1C2AE7DD" + "8F9278F1024100C313F4AF9E4A9DE1253C21080CE524251560C111550772FD08690F13FBE658342E" + "BD2D41C9DCB12374E871B1839E26CAE252E1AE3DAAD5F1EE1F42B4D0EE7581"; + + SignatureKnownAnswerTest >( + keyRSA1, + "Everyone gets Friday off.", + "0610761F95FFD1B8F29DA34212947EC2AA0E358866A722F03CC3C41487ADC604A48FF54F5C6BEDB9FB7BD59F82D6E55D8F3174BA361B2214B2D74E8825E04E81"); + + SignatureKnownAnswerTest >( + keyRSA2, + "test", + "32F6BA41C8930DE71EE67F2627172CC539EDE04267FDE03AC295E3C50311F26C3B275D3AF513AC96" + "8EE493BAB7DA3A754661D1A7C4A0D1A2B7EE8B313AACD8CB8BFBC5C15EFB0EF15C86A9334A1E87AD" + "291EB961B5CA0E84930429B28780816AA94F96FC2367B71E2D2E4866FA966795B147F00600E5207E" + "2F189C883B37477C"); + + SignaturePairwiseConsistencyTest( + "3082014A0201003082012B06072A8648CE3804013082011E02818100F468699A6F6EBCC0120D3B34C8E007F125EC7D81F763B8D0F33869AE3BD6B9F2ECCC7DF34DF84C0307449E9B85D30D57194BCCEB310F48141914DD13A077AAF9B624A6CBE666BBA1D7EBEA95B5BA6F54417FD5D4E4220C601E071D316A24EA814E8B0122DBF47EE8AEEFD319EBB01DD95683F10DBB4FEB023F8262A07EAEB7FD02150082AD4E034DA6EEACDFDAE68C36F2BAD614F9E53B02818071AAF73361A26081529F7D84078ADAFCA48E031DB54AD57FB1A833ADBD8672328AABAA0C756247998D7A5B10DACA359D231332CE8120B483A784FE07D46EEBFF0D7D374A10691F78653E6DC29E27CCB1B174923960DFE5B959B919B2C3816C19251832AFD8E35D810E598F82877ABF7D40A041565168BD7F0E21E3FE2A8D8C1C0416021426EBA66E846E755169F84A1DA981D86502405DDF"); + + SignaturePairwiseConsistencyTest >( + "302D020100301006072A8648CE3D020106052B8104000404163014020101040F0070337065E1E196980A9D00E37211"); + + SignaturePairwiseConsistencyTest >( + "3039020100301306072A8648CE3D020106082A8648CE3D030101041F301D02010104182BB8A13C8B867010BD9471D9E81FDB01ABD0538C64D6249A"); + + SignaturePairwiseConsistencyTest >(keyRSA1); + } + catch (...) + { + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_FAILED; + goto done; + } + + g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_PASSED; + +done: + SetPowerUpSelfTestInProgressOnThisThread(false); + return; +} + +#ifdef CRYPTOPP_WIN32_AVAILABLE + +void DoDllPowerUpSelfTest() +{ + CryptoPP::DoPowerUpSelfTest(NULLPTR, s_moduleMac); +} + +#else + +void DoDllPowerUpSelfTest() +{ + throw NotImplemented("DoDllPowerUpSelfTest() only available on Windows"); +} + +#endif // #ifdef CRYPTOPP_WIN32_AVAILABLE + +NAMESPACE_END + +#ifdef CRYPTOPP_WIN32_AVAILABLE + +// DllMain needs to be in the global namespace +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD dwReason, + LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + CryptoPP::s_hModule = (HMODULE)hModule; + CryptoPP::DoDllPowerUpSelfTest(); + } + return TRUE; +} + +#endif // #ifdef CRYPTOPP_WIN32_AVAILABLE + +#endif // #ifndef CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/fltrimpl.h b/extension/third_party/cryptopp/fltrimpl.h new file mode 100644 index 00000000..4fc4224b --- /dev/null +++ b/extension/third_party/cryptopp/fltrimpl.h @@ -0,0 +1,87 @@ +#ifndef CRYPTOPP_FLTRIMPL_H +#define CRYPTOPP_FLTRIMPL_H + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4100) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-value" +#endif + +#define FILTER_BEGIN \ + switch (m_continueAt) \ + { \ + case 0: \ + m_inputPosition = 0; + +#define FILTER_END_NO_MESSAGE_END_NO_RETURN \ + break; \ + default: \ + CRYPTOPP_ASSERT(false); \ + } + +#define FILTER_END_NO_MESSAGE_END \ + FILTER_END_NO_MESSAGE_END_NO_RETURN \ + return 0; + +/* +#define FILTER_END \ + case -1: \ + if (messageEnd && Output(-1, NULLPTR, 0, messageEnd, blocking)) \ + return 1; \ + FILTER_END_NO_MESSAGE_END +*/ + +#define FILTER_OUTPUT3(site, statement, output, length, messageEnd, channel) \ + {\ + case site: \ + statement; \ + if (Output(site, output, length, messageEnd, blocking, channel)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT2(site, statement, output, length, messageEnd) \ + FILTER_OUTPUT3(site, statement, output, length, messageEnd, DEFAULT_CHANNEL) + +#define FILTER_OUTPUT(site, output, length, messageEnd) \ + FILTER_OUTPUT2(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT_BYTE(site, output) \ + FILTER_OUTPUT(site, &(const byte &)(byte)output, 1, 0) + +#define FILTER_OUTPUT2_MODIFIABLE(site, statement, output, length, messageEnd) \ + {\ + /* fall through */ \ + case site: \ + statement; \ + if (OutputModifiable(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MODIFIABLE(site, output, length, messageEnd) \ + FILTER_OUTPUT2_MODIFIABLE(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, statement, output, length, messageEnd, modifiable) \ + {\ + /* fall through */ \ + case site: \ + statement; \ + if (modifiable ? OutputModifiable(site, output, length, messageEnd, blocking) : Output(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MAYBE_MODIFIABLE(site, output, length, messageEnd, modifiable) \ + FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, 0, output, length, messageEnd, modifiable) + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/extension/third_party/cryptopp/gcm.cpp b/extension/third_party/cryptopp/gcm.cpp new file mode 100644 index 00000000..76ef058f --- /dev/null +++ b/extension/third_party/cryptopp/gcm.cpp @@ -0,0 +1,856 @@ +// gcm.cpp - originally written and placed in the public domain by Wei Dai. +// ARM and Aarch64 added by Jeffrey Walton. The ARM carryless +// multiply routines are less efficient because they shadow x86. +// The precomputed key table integration makes it tricky to use the +// more efficient ARMv8 implementation of the multiply and reduce. + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM gcm.cpp" to generate MASM code + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS +#ifndef CRYPTOPP_GENERATE_X64_MASM + +// Visual Studio .Net 2003 compiler crash +#if defined(_MSC_VER) && (_MSC_VER < 1400) +# pragma optimize("", off) +#endif + +#include "gcm.h" +#include "cpu.h" + +#if defined(CRYPTOPP_DISABLE_GCM_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +// Different assemblers accept different mnemonics: 'movd eax, xmm0' vs +// 'movd rax, xmm0' vs 'mov eax, xmm0' vs 'mov rax, xmm0' +#if defined(CRYPTOPP_DISABLE_MIXED_ASM) +// 'movd eax, xmm0' only. REG_WORD() macro not used. Clang path. +# define USE_MOVD_REG32 1 +#elif defined(__GNUC__) || defined(_MSC_VER) +// 'movd eax, xmm0' or 'movd rax, xmm0'. REG_WORD() macro supplies REG32 or REG64. +# define USE_MOVD_REG32_OR_REG64 1 +#else +// 'mov eax, xmm0' or 'mov rax, xmm0'. REG_WORD() macro supplies REG32 or REG64. +# define USE_MOV_REG32_OR_REG64 1 +#endif +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +word16 GCM_Base::s_reductionTable[256]; +volatile bool GCM_Base::s_reductionTableInitialized = false; + +void GCM_Base::GCTR::IncrementCounterBy256() +{ + IncrementCounterByOne(m_counterArray+BlockSize()-4, 3); +} + +static inline void Xor16(byte *a, const byte *b, const byte *c) +{ + CRYPTOPP_ASSERT(IsAlignedOn(a,GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(b,GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(c,GetAlignmentOf())); + ((word64 *)(void *)a)[0] = ((word64 *)(void *)b)[0] ^ ((word64 *)(void *)c)[0]; + ((word64 *)(void *)a)[1] = ((word64 *)(void *)b)[1] ^ ((word64 *)(void *)c)[1]; +} + +#if CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE +// SunCC 5.10-5.11 compiler crash. Move GCM_Xor16_SSE2 out-of-line, and place in +// a source file with a SSE architecture switch. Also see GH #226 and GH #284. +extern void GCM_Xor16_SSE2(byte *a, const byte *b, const byte *c); +#endif // SSE2 + +#if CRYPTOPP_ARM_NEON_AVAILABLE +extern void GCM_Xor16_NEON(byte *a, const byte *b, const byte *c); +#endif + +#if CRYPTOPP_POWER8_AVAILABLE +extern void GCM_Xor16_POWER8(byte *a, const byte *b, const byte *c); +#endif + +#if CRYPTOPP_CLMUL_AVAILABLE +extern void GCM_SetKeyWithoutResync_CLMUL(const byte *hashKey, byte *mulTable, unsigned int tableSize); +extern size_t GCM_AuthenticateBlocks_CLMUL(const byte *data, size_t len, const byte *mtable, byte *hbuffer); +const unsigned int s_cltableSizeInBlocks = 8; +extern void GCM_ReverseHashBufferIfNeeded_CLMUL(byte *hashBuffer); +#endif // CRYPTOPP_CLMUL_AVAILABLE + +#if CRYPTOPP_ARM_PMULL_AVAILABLE +extern void GCM_SetKeyWithoutResync_PMULL(const byte *hashKey, byte *mulTable, unsigned int tableSize); +extern size_t GCM_AuthenticateBlocks_PMULL(const byte *data, size_t len, const byte *mtable, byte *hbuffer); +const unsigned int s_cltableSizeInBlocks = 8; +extern void GCM_ReverseHashBufferIfNeeded_PMULL(byte *hashBuffer); +#endif // CRYPTOPP_ARM_PMULL_AVAILABLE + +#if CRYPTOPP_POWER8_VMULL_AVAILABLE +extern void GCM_SetKeyWithoutResync_VMULL(const byte *hashKey, byte *mulTable, unsigned int tableSize); +extern size_t GCM_AuthenticateBlocks_VMULL(const byte *data, size_t len, const byte *mtable, byte *hbuffer); +const unsigned int s_cltableSizeInBlocks = 8; +extern void GCM_ReverseHashBufferIfNeeded_VMULL(byte *hashBuffer); +#endif // CRYPTOPP_POWER8_VMULL_AVAILABLE + +void GCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) +{ + BlockCipher &blockCipher = AccessBlockCipher(); + blockCipher.SetKey(userKey, keylength, params); + + // GCM is only defined for 16-byte block ciphers at the moment. + // However, variable blocksize support means we have to defer + // blocksize checks to runtime after the key is set. Also see + // https://github.com/weidai11/cryptopp/issues/408. + const unsigned int blockSize = blockCipher.BlockSize(); + CRYPTOPP_ASSERT(blockSize == REQUIRED_BLOCKSIZE); + if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE) + throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16"); + + int tableSize, i, j, k; + +#if CRYPTOPP_CLMUL_AVAILABLE + if (HasCLMUL()) + { + // Avoid "parameter not used" error and suppress Coverity finding + (void)params.GetIntValue(Name::TableSize(), tableSize); + tableSize = s_cltableSizeInBlocks * blockSize; + CRYPTOPP_ASSERT(tableSize > static_cast(blockSize)); + } + else +#elif CRYPTOPP_ARM_PMULL_AVAILABLE + if (HasPMULL()) + { + // Avoid "parameter not used" error and suppress Coverity finding + (void)params.GetIntValue(Name::TableSize(), tableSize); + tableSize = s_cltableSizeInBlocks * blockSize; + CRYPTOPP_ASSERT(tableSize > static_cast(blockSize)); + } + else +#elif CRYPTOPP_POWER8_VMULL_AVAILABLE + if (HasPMULL()) + { + // Avoid "parameter not used" error and suppress Coverity finding + (void)params.GetIntValue(Name::TableSize(), tableSize); + tableSize = s_cltableSizeInBlocks * blockSize; + CRYPTOPP_ASSERT(tableSize > static_cast(blockSize)); + } + else +#endif + { + if (params.GetIntValue(Name::TableSize(), tableSize)) + tableSize = (tableSize >= 64*1024) ? 64*1024 : 2*1024; + else + tableSize = (GetTablesOption() == GCM_64K_Tables) ? 64*1024 : 2*1024; + + //#if defined(_MSC_VER) && (_MSC_VER < 1400) + // VC 2003 workaround: compiler generates bad code for 64K tables + //tableSize = 2*1024; + //#endif + } + + m_buffer.resize(3*blockSize + tableSize); + byte *mulTable = MulTable(); + byte *hashKey = HashKey(); + memset(hashKey, 0, REQUIRED_BLOCKSIZE); + blockCipher.ProcessBlock(hashKey); + +#if CRYPTOPP_CLMUL_AVAILABLE + if (HasCLMUL()) + { + GCM_SetKeyWithoutResync_CLMUL(hashKey, mulTable, tableSize); + return; + } +#elif CRYPTOPP_ARM_PMULL_AVAILABLE + if (HasPMULL()) + { + GCM_SetKeyWithoutResync_PMULL(hashKey, mulTable, tableSize); + return; + } +#elif CRYPTOPP_POWER8_VMULL_AVAILABLE + if (HasPMULL()) + { + GCM_SetKeyWithoutResync_VMULL(hashKey, mulTable, tableSize); + return; + } +#endif + + word64 V0, V1; + typedef BlockGetAndPut Block; + Block::Get(hashKey)(V0)(V1); + + if (tableSize == 64*1024) + { + for (i=0; i<128; i++) + { + k = i%8; + Block::Put(NULLPTR, mulTable+(i/8)*256*16+(size_t(1)<<(11-k)))(V0)(V1); + + int x = (int)V1 & 1; + V1 = (V1>>1) | (V0<<63); + V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0); + } + + for (i=0; i<16; i++) + { + memset(mulTable+i*256*16, 0, 16); +#if CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + for (j=2; j<=0x80; j*=2) + for (k=1; k>1) | (V0<<63); + V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0); + } + + for (i=0; i<4; i++) + { + memset(mulTable+i*256, 0, 16); + memset(mulTable+1024+i*256, 0, 16); +#if CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + for (j=2; j<=8; j*=2) + for (k=1; k= HASH_BLOCKSIZE) + { + len = GCM_Base::AuthenticateBlocks(iv, len); + iv += (origLen - len); + } + + if (len > 0) + { + memcpy(m_buffer, iv, len); + memset(m_buffer+len, 0, HASH_BLOCKSIZE-len); + GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE); + } + + PutBlock(NULLPTR, m_buffer)(0)(origLen*8); + GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE); + + ReverseHashBufferIfNeeded(); + } + + if (m_state >= State_IVSet) + m_ctr.Resynchronize(hashBuffer, REQUIRED_BLOCKSIZE); + else + m_ctr.SetCipherWithIV(cipher, hashBuffer); + + m_ctr.Seek(HASH_BLOCKSIZE); + + memset(hashBuffer, 0, HASH_BLOCKSIZE); +} + +unsigned int GCM_Base::OptimalDataAlignment() const +{ + return +#if CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) + HasSSE2() ? 16 : +#elif CRYPTOPP_ARM_NEON_AVAILABLE + HasNEON() ? 4 : +#elif CRYPTOPP_POWER8_AVAILABLE + HasPower8() ? 16 : +#endif + GetBlockCipher().OptimalDataAlignment(); +} + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code +#endif + +#endif // Not CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void GCM_AuthenticateBlocks_2K_SSE2(const byte *data, size_t blocks, word64 *hashBuffer, const word16 *reductionTable); +void GCM_AuthenticateBlocks_64K_SSE2(const byte *data, size_t blocks, word64 *hashBuffer); +} +#endif + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +size_t GCM_Base::AuthenticateBlocks(const byte *data, size_t len) +{ +#if CRYPTOPP_CLMUL_AVAILABLE + if (HasCLMUL()) + { + return GCM_AuthenticateBlocks_CLMUL(data, len, MulTable(), HashBuffer()); + } +#elif CRYPTOPP_ARM_PMULL_AVAILABLE + if (HasPMULL()) + { + return GCM_AuthenticateBlocks_PMULL(data, len, MulTable(), HashBuffer()); + } +#elif CRYPTOPP_POWER8_VMULL_AVAILABLE + if (HasPMULL()) + { + return GCM_AuthenticateBlocks_VMULL(data, len, MulTable(), HashBuffer()); + } +#endif + + typedef BlockGetAndPut Block; + word64 *hashBuffer = (word64 *)(void *)HashBuffer(); + CRYPTOPP_ASSERT(IsAlignedOn(hashBuffer,GetAlignmentOf())); + + switch (2*(m_buffer.size()>=64*1024) +#if CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) + + HasSSE2() +//#elif CRYPTOPP_ARM_NEON_AVAILABLE +// + HasNEON() +#endif + ) + { + case 0: // non-SSE2 and 2K tables + { + byte *mulTable = MulTable(); + word64 x0 = hashBuffer[0], x1 = hashBuffer[1]; + + do + { + word64 y0, y1, a0, a1, b0, b1, c0, c1, d0, d1; + Block::Get(data)(y0)(y1); + x0 ^= y0; + x1 ^= y1; + + data += HASH_BLOCKSIZE; + len -= HASH_BLOCKSIZE; + + #define READ_TABLE_WORD64_COMMON(a, b, c, d) *(word64 *)(void *)(mulTable+(a*1024)+(b*256)+c+d*8) + + #if (CRYPTOPP_LITTLE_ENDIAN) + #if CRYPTOPP_BOOL_SLOW_WORD64 + word32 z0 = (word32)x0; + word32 z1 = (word32)(x0>>32); + word32 z2 = (word32)x1; + word32 z3 = (word32)(x1>>32); + #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((d%2), c, (d?(z##c>>((d?d-1:0)*4))&0xf0:(z##c&0xf)<<4), e) + #else + #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((d%2), c, ((d+8*b)?(x##a>>(((d+8*b)?(d+8*b)-1:1)*4))&0xf0:(x##a&0xf)<<4), e) + #endif + #define GF_MOST_SIG_8BITS(a) (a##1 >> 7*8) + #define GF_SHIFT_8(a) a##1 = (a##1 << 8) ^ (a##0 >> 7*8); a##0 <<= 8; + #else + #define READ_TABLE_WORD64(a, b, c, d, e) READ_TABLE_WORD64_COMMON((1-d%2), c, ((15-d-8*b)?(x##a>>(((15-d-8*b)?(15-d-8*b)-1:0)*4))&0xf0:(x##a&0xf)<<4), e) + #define GF_MOST_SIG_8BITS(a) (a##1 & 0xff) + #define GF_SHIFT_8(a) a##1 = (a##1 >> 8) ^ (a##0 << 7*8); a##0 >>= 8; + #endif + + #define GF_MUL_32BY128(op, a, b, c) \ + a0 op READ_TABLE_WORD64(a, b, c, 0, 0) ^ READ_TABLE_WORD64(a, b, c, 1, 0); \ + a1 op READ_TABLE_WORD64(a, b, c, 0, 1) ^ READ_TABLE_WORD64(a, b, c, 1, 1); \ + b0 op READ_TABLE_WORD64(a, b, c, 2, 0) ^ READ_TABLE_WORD64(a, b, c, 3, 0); \ + b1 op READ_TABLE_WORD64(a, b, c, 2, 1) ^ READ_TABLE_WORD64(a, b, c, 3, 1); \ + c0 op READ_TABLE_WORD64(a, b, c, 4, 0) ^ READ_TABLE_WORD64(a, b, c, 5, 0); \ + c1 op READ_TABLE_WORD64(a, b, c, 4, 1) ^ READ_TABLE_WORD64(a, b, c, 5, 1); \ + d0 op READ_TABLE_WORD64(a, b, c, 6, 0) ^ READ_TABLE_WORD64(a, b, c, 7, 0); \ + d1 op READ_TABLE_WORD64(a, b, c, 6, 1) ^ READ_TABLE_WORD64(a, b, c, 7, 1); \ + + GF_MUL_32BY128(=, 0, 0, 0) + GF_MUL_32BY128(^=, 0, 1, 1) + GF_MUL_32BY128(^=, 1, 0, 2) + GF_MUL_32BY128(^=, 1, 1, 3) + + word32 r = (word32)s_reductionTable[GF_MOST_SIG_8BITS(d)] << 16; + GF_SHIFT_8(d) + c0 ^= d0; c1 ^= d1; + r ^= (word32)s_reductionTable[GF_MOST_SIG_8BITS(c)] << 8; + GF_SHIFT_8(c) + b0 ^= c0; b1 ^= c1; + r ^= s_reductionTable[GF_MOST_SIG_8BITS(b)]; + GF_SHIFT_8(b) + a0 ^= b0; a1 ^= b1; + a0 ^= ConditionalByteReverse(LITTLE_ENDIAN_ORDER, r); + x0 = a0; x1 = a1; + } + while (len >= HASH_BLOCKSIZE); + + hashBuffer[0] = x0; hashBuffer[1] = x1; + return len; + } + + case 2: // non-SSE2 and 64K tables + { + byte *mulTable = MulTable(); + word64 x0 = hashBuffer[0], x1 = hashBuffer[1]; + + do + { + word64 y0, y1, a0, a1; + Block::Get(data)(y0)(y1); + x0 ^= y0; + x1 ^= y1; + + data += HASH_BLOCKSIZE; + len -= HASH_BLOCKSIZE; + + #undef READ_TABLE_WORD64_COMMON + #undef READ_TABLE_WORD64 + + #define READ_TABLE_WORD64_COMMON(a, c, d) *(word64 *)(void *)(mulTable+(a)*256*16+(c)+(d)*8) + + #if (CRYPTOPP_LITTLE_ENDIAN) + #if CRYPTOPP_BOOL_SLOW_WORD64 + word32 z0 = (word32)x0; + word32 z1 = (word32)(x0>>32); + word32 z2 = (word32)x1; + word32 z3 = (word32)(x1>>32); + #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, (d?(z##c>>((d?d:1)*8-4))&0xff0:(z##c&0xff)<<4), e) + #else + #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, ((d+4*(c%2))?(x##b>>(((d+4*(c%2))?(d+4*(c%2)):1)*8-4))&0xff0:(x##b&0xff)<<4), e) + #endif + #else + #define READ_TABLE_WORD64(b, c, d, e) READ_TABLE_WORD64_COMMON(c*4+d, ((7-d-4*(c%2))?(x##b>>(((7-d-4*(c%2))?(7-d-4*(c%2)):1)*8-4))&0xff0:(x##b&0xff)<<4), e) + #endif + + #define GF_MUL_8BY128(op, b, c, d) \ + a0 op READ_TABLE_WORD64(b, c, d, 0);\ + a1 op READ_TABLE_WORD64(b, c, d, 1);\ + + GF_MUL_8BY128(=, 0, 0, 0) + GF_MUL_8BY128(^=, 0, 0, 1) + GF_MUL_8BY128(^=, 0, 0, 2) + GF_MUL_8BY128(^=, 0, 0, 3) + GF_MUL_8BY128(^=, 0, 1, 0) + GF_MUL_8BY128(^=, 0, 1, 1) + GF_MUL_8BY128(^=, 0, 1, 2) + GF_MUL_8BY128(^=, 0, 1, 3) + GF_MUL_8BY128(^=, 1, 2, 0) + GF_MUL_8BY128(^=, 1, 2, 1) + GF_MUL_8BY128(^=, 1, 2, 2) + GF_MUL_8BY128(^=, 1, 2, 3) + GF_MUL_8BY128(^=, 1, 3, 0) + GF_MUL_8BY128(^=, 1, 3, 1) + GF_MUL_8BY128(^=, 1, 3, 2) + GF_MUL_8BY128(^=, 1, 3, 3) + + x0 = a0; x1 = a1; + } + while (len >= HASH_BLOCKSIZE); + + hashBuffer[0] = x0; hashBuffer[1] = x1; + return len; + } +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE + case 1: // SSE2 and 2K tables + GCM_AuthenticateBlocks_2K_SSE2(data, len/16, hashBuffer, s_reductionTable); + return len % 16; + case 3: // SSE2 and 64K tables + GCM_AuthenticateBlocks_64K_SSE2(data, len/16, hashBuffer); + return len % 16; +#endif + +#if CRYPTOPP_SSE2_ASM_AVAILABLE + case 1: // SSE2 and 2K tables + { + #ifdef __GNUC__ + __asm__ __volatile__ + ( + INTEL_NOPREFIX + #elif defined(CRYPTOPP_GENERATE_X64_MASM) + ALIGN 8 + GCM_AuthenticateBlocks_2K_SSE2 PROC FRAME + rex_push_reg rsi + push_reg rdi + push_reg rbx + .endprolog + mov rsi, r8 + mov r11, r9 + #else + AS2( mov WORD_REG(cx), data ) + AS2( mov WORD_REG(dx), len ) + AS2( mov WORD_REG(si), hashBuffer ) + AS2( shr WORD_REG(dx), 4 ) + #endif + + #if CRYPTOPP_BOOL_X32 + AS1(push rbx) + AS1(push rbp) + #else + AS_PUSH_IF86( bx) + AS_PUSH_IF86( bp) + #endif + + #ifdef __GNUC__ + AS2( mov AS_REG_7, WORD_REG(di)) + #elif CRYPTOPP_BOOL_X86 + AS2( lea AS_REG_7, s_reductionTable) + #endif + + AS2( movdqa xmm0, [WORD_REG(si)] ) + + #define MUL_TABLE_0 WORD_REG(si) + 32 + #define MUL_TABLE_1 WORD_REG(si) + 32 + 1024 + #define RED_TABLE AS_REG_7 + + ASL(0) + AS2( movdqu xmm4, [WORD_REG(cx)] ) + AS2( pxor xmm0, xmm4 ) + + AS2( movd ebx, xmm0 ) + AS2( mov eax, AS_HEX(f0f0f0f0) ) + AS2( and eax, ebx ) + AS2( shl ebx, 4 ) + AS2( and ebx, AS_HEX(f0f0f0f0) ) + AS2( movzx edi, ah ) + AS2( movdqa xmm5, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] ) + AS2( movzx edi, al ) + AS2( movdqa xmm4, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] ) + AS2( shr eax, 16 ) + AS2( movzx edi, ah ) + AS2( movdqa xmm3, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] ) + AS2( movzx edi, al ) + AS2( movdqa xmm2, XMMWORD_PTR [MUL_TABLE_1 + WORD_REG(di)] ) + + #define SSE2_MUL_32BITS(i) \ + AS2( psrldq xmm0, 4 )\ + AS2( movd eax, xmm0 )\ + AS2( and eax, AS_HEX(f0f0f0f0) )\ + AS2( movzx edi, bh )\ + AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\ + AS2( movzx edi, bl )\ + AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\ + AS2( shr ebx, 16 )\ + AS2( movzx edi, bh )\ + AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\ + AS2( movzx edi, bl )\ + AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_0 + (i-1)*256 + WORD_REG(di)] )\ + AS2( movd ebx, xmm0 )\ + AS2( shl ebx, 4 )\ + AS2( and ebx, AS_HEX(f0f0f0f0) )\ + AS2( movzx edi, ah )\ + AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\ + AS2( movzx edi, al )\ + AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\ + AS2( shr eax, 16 )\ + AS2( movzx edi, ah )\ + AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\ + AS2( movzx edi, al )\ + AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_1 + i*256 + WORD_REG(di)] )\ + + SSE2_MUL_32BITS(1) + SSE2_MUL_32BITS(2) + SSE2_MUL_32BITS(3) + + AS2( movzx edi, bh ) + AS2( pxor xmm5, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] ) + AS2( movzx edi, bl ) + AS2( pxor xmm4, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] ) + AS2( shr ebx, 16 ) + AS2( movzx edi, bh ) + AS2( pxor xmm3, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] ) + AS2( movzx edi, bl ) + AS2( pxor xmm2, XMMWORD_PTR [MUL_TABLE_0 + 3*256 + WORD_REG(di)] ) + + AS2( movdqa xmm0, xmm3 ) + AS2( pslldq xmm3, 1 ) + AS2( pxor xmm2, xmm3 ) + AS2( movdqa xmm1, xmm2 ) + AS2( pslldq xmm2, 1 ) + AS2( pxor xmm5, xmm2 ) + + AS2( psrldq xmm0, 15 ) +#if USE_MOVD_REG32 + AS2( movd edi, xmm0 ) +#elif USE_MOV_REG32_OR_REG64 + AS2( mov WORD_REG(di), xmm0 ) +#else // GNU Assembler + AS2( movd WORD_REG(di), xmm0 ) +#endif + AS2( movzx eax, WORD PTR [RED_TABLE + WORD_REG(di)*2] ) + AS2( shl eax, 8 ) + + AS2( movdqa xmm0, xmm5 ) + AS2( pslldq xmm5, 1 ) + AS2( pxor xmm4, xmm5 ) + + AS2( psrldq xmm1, 15 ) +#if USE_MOVD_REG32 + AS2( movd edi, xmm1 ) +#elif USE_MOV_REG32_OR_REG64 + AS2( mov WORD_REG(di), xmm1 ) +#else + AS2( movd WORD_REG(di), xmm1 ) +#endif + AS2( xor ax, WORD PTR [RED_TABLE + WORD_REG(di)*2] ) + AS2( shl eax, 8 ) + + AS2( psrldq xmm0, 15 ) +#if USE_MOVD_REG32 + AS2( movd edi, xmm0 ) +#elif USE_MOV_REG32_OR_REG64 + AS2( mov WORD_REG(di), xmm0 ) +#else + AS2( movd WORD_REG(di), xmm0 ) +#endif + AS2( xor ax, WORD PTR [RED_TABLE + WORD_REG(di)*2] ) + + AS2( movd xmm0, eax ) + AS2( pxor xmm0, xmm4 ) + + AS2( add WORD_REG(cx), 16 ) + AS2( sub WORD_REG(dx), 1 ) + // ATT_NOPREFIX + ASJ( jnz, 0, b ) + INTEL_NOPREFIX + AS2( movdqa [WORD_REG(si)], xmm0 ) + + #if CRYPTOPP_BOOL_X32 + AS1(pop rbp) + AS1(pop rbx) + #else + AS_POP_IF86( bp) + AS_POP_IF86( bx) + #endif + + #ifdef __GNUC__ + ATT_PREFIX + : + : "c" (data), "d" (len/16), "S" (hashBuffer), "D" (s_reductionTable) + : "memory", "cc", "%eax" + #if CRYPTOPP_BOOL_X64 + , "%ebx", "%r11" + #endif + ); + #elif defined(CRYPTOPP_GENERATE_X64_MASM) + pop rbx + pop rdi + pop rsi + ret + GCM_AuthenticateBlocks_2K_SSE2 ENDP + #endif + + return len%16; + } + case 3: // SSE2 and 64K tables + { + #ifdef __GNUC__ + __asm__ __volatile__ + ( + INTEL_NOPREFIX + #elif defined(CRYPTOPP_GENERATE_X64_MASM) + ALIGN 8 + GCM_AuthenticateBlocks_64K_SSE2 PROC FRAME + rex_push_reg rsi + push_reg rdi + .endprolog + mov rsi, r8 + #else + AS2( mov WORD_REG(cx), data ) + AS2( mov WORD_REG(dx), len ) + AS2( mov WORD_REG(si), hashBuffer ) + AS2( shr WORD_REG(dx), 4 ) + #endif + + AS2( movdqa xmm0, [WORD_REG(si)] ) + + #undef MUL_TABLE + #define MUL_TABLE(i,j) WORD_REG(si) + 32 + (i*4+j)*256*16 + + ASL(1) + AS2( movdqu xmm1, [WORD_REG(cx)] ) + AS2( pxor xmm1, xmm0 ) + AS2( pxor xmm0, xmm0 ) + + #undef SSE2_MUL_32BITS + #define SSE2_MUL_32BITS(i) \ + AS2( movd eax, xmm1 )\ + AS2( psrldq xmm1, 4 )\ + AS2( movzx edi, al )\ + AS2( add WORD_REG(di), WORD_REG(di) )\ + AS2( pxor xmm0, [MUL_TABLE(i,0) + WORD_REG(di)*8] )\ + AS2( movzx edi, ah )\ + AS2( add WORD_REG(di), WORD_REG(di) )\ + AS2( pxor xmm0, [MUL_TABLE(i,1) + WORD_REG(di)*8] )\ + AS2( shr eax, 16 )\ + AS2( movzx edi, al )\ + AS2( add WORD_REG(di), WORD_REG(di) )\ + AS2( pxor xmm0, [MUL_TABLE(i,2) + WORD_REG(di)*8] )\ + AS2( movzx edi, ah )\ + AS2( add WORD_REG(di), WORD_REG(di) )\ + AS2( pxor xmm0, [MUL_TABLE(i,3) + WORD_REG(di)*8] )\ + + SSE2_MUL_32BITS(0) + SSE2_MUL_32BITS(1) + SSE2_MUL_32BITS(2) + SSE2_MUL_32BITS(3) + + AS2( add WORD_REG(cx), 16 ) + AS2( sub WORD_REG(dx), 1 ) + // ATT_NOPREFIX + ASJ( jnz, 1, b ) + INTEL_NOPREFIX + AS2( movdqa [WORD_REG(si)], xmm0 ) + + #ifdef __GNUC__ + ATT_PREFIX + : + : "c" (data), "d" (len/16), "S" (hashBuffer) + : "memory", "cc", "%edi", "%eax" + ); + #elif defined(CRYPTOPP_GENERATE_X64_MASM) + pop rdi + pop rsi + ret + GCM_AuthenticateBlocks_64K_SSE2 ENDP + #endif + + return len%16; + } +#endif +#ifndef CRYPTOPP_GENERATE_X64_MASM + } + + return len%16; +} + +void GCM_Base::AuthenticateLastHeaderBlock() +{ + if (m_bufferedDataLength > 0) + { + memset(m_buffer+m_bufferedDataLength, 0, HASH_BLOCKSIZE-m_bufferedDataLength); + m_bufferedDataLength = 0; + GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE); + } +} + +void GCM_Base::AuthenticateLastConfidentialBlock() +{ + GCM_Base::AuthenticateLastHeaderBlock(); + PutBlock(NULLPTR, m_buffer)(m_totalHeaderLength*8)(m_totalMessageLength*8); + GCM_Base::AuthenticateBlocks(m_buffer, HASH_BLOCKSIZE); +} + +void GCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) +{ + m_ctr.Seek(0); + ReverseHashBufferIfNeeded(); + m_ctr.ProcessData(mac, HashBuffer(), macSize); +} + +NAMESPACE_END + +#endif // Not CRYPTOPP_GENERATE_X64_MASM +#endif diff --git a/extension/third_party/cryptopp/gcm.h b/extension/third_party/cryptopp/gcm.h new file mode 100644 index 00000000..a9302eec --- /dev/null +++ b/extension/third_party/cryptopp/gcm.h @@ -0,0 +1,139 @@ +// gcm.h - originally written and placed in the public domain by Wei Dai + +/// \file gcm.h +/// \brief GCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_GCM_H +#define CRYPTOPP_GCM_H + +#include "authenc.h" +#include "modes.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_GCM_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \enum GCM_TablesOption +/// \brief GCM table size options +enum GCM_TablesOption { + /// \brief Use a table with 2K entries + GCM_2K_Tables, + /// \brief Use a table with 64K entries + GCM_64K_Tables}; + +/// \brief GCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/GCM");} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetBlockCipher().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetBlockCipher().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const; + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 12;} + unsigned int MinIVLength() const + {return 1;} + unsigned int MaxIVLength() const + {return UINT_MAX;} // (W64LIT(1)<<61)-1 in the standard + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return (W64LIT(1)<<61)-1;} + lword MaxMessageLength() const + {return ((W64LIT(1)<<39)-256)/8;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return HASH_BLOCKSIZE;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual GCM_TablesOption GetTablesOption() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();} + byte *HashBuffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + byte *HashKey() {return m_buffer+2*REQUIRED_BLOCKSIZE;} + byte *MulTable() {return m_buffer+3*REQUIRED_BLOCKSIZE;} + inline void ReverseHashBufferIfNeeded(); + + class CRYPTOPP_DLL GCTR : public CTR_Mode_ExternalCipher::Encryption + { + protected: + void IncrementCounterBy256(); + }; + + GCTR m_ctr; + static word16 s_reductionTable[256]; + static volatile bool s_reductionTableInitialized; + enum {REQUIRED_BLOCKSIZE = 16, HASH_BLOCKSIZE = 16}; +}; + +/// \brief GCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class GCM_Final : public GCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/GCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + GCM_TablesOption GetTablesOption() const {return T_TablesOption;} + BlockCipher & AccessBlockCipher() {return m_cipher;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief GCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \details \p GCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa GCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct GCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef GCM_Final Encryption; + typedef GCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gcm_simd.cpp b/extension/third_party/cryptopp/gcm_simd.cpp new file mode 100644 index 00000000..59d5d62f --- /dev/null +++ b/extension/third_party/cryptopp/gcm_simd.cpp @@ -0,0 +1,742 @@ +// gcm_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// Original x86 CLMUL by Wei Dai. ARM and POWER8 +// PMULL and VMULL by JW, UB and MR. +// +// This source file uses intrinsics to gain access to SSE4.2 and +// ARMv8a CRC-32 and CRC-32C instructions. A separate source file +// is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "misc.h" + +#if defined(CRYPTOPP_DISABLE_GCM_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +# include +# include +#endif + +#if (CRYPTOPP_CLMUL_AVAILABLE) +# include +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if defined(CRYPTOPP_ARM_PMULL_AVAILABLE) +# include "arm_simd.h" +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char GCM_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ************************* Feature Probes ************************* // + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) +bool CPU_ProbePMULL() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_ARM_PMULL_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + // Linaro is missing a lot of pmull gear. Also see http://github.com/weidai11/cryptopp/issues/233. + const uint64_t wa1[]={0,0x9090909090909090}, wb1[]={0,0xb0b0b0b0b0b0b0b0}; + const uint64x2_t a1=vld1q_u64(wa1), b1=vld1q_u64(wb1); + + const uint8_t wa2[]={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0}, + wb2[]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0}; + const uint8x16_t a2=vld1q_u8(wa2), b2=vld1q_u8(wb2); + + const uint64x2_t r1 = PMULL_00(a1, b1); + const uint64x2_t r2 = PMULL_11(vreinterpretq_u64_u8(a2), + vreinterpretq_u64_u8(b2)); + + result = !!(vgetq_lane_u64(r1,0) == 0x5300530053005300 && + vgetq_lane_u64(r1,1) == 0x5300530053005300 && + vgetq_lane_u64(r2,0) == 0x6c006c006c006c00 && + vgetq_lane_u64(r2,1) == 0x6c006c006c006c00); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + + // longjmp and clobber warnings. Volatile is required. + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // Linaro is missing a lot of pmull gear. Also see http://github.com/weidai11/cryptopp/issues/233. + const uint64_t wa1[]={0,0x9090909090909090}, wb1[]={0,0xb0b0b0b0b0b0b0b0}; + const uint64x2_t a1=vld1q_u64(wa1), b1=vld1q_u64(wb1); + + const uint8_t wa2[]={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0}, + wb2[]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0}; + const uint8x16_t a2=vld1q_u8(wa2), b2=vld1q_u8(wb2); + + const uint64x2_t r1 = PMULL_00(a1, b1); + const uint64x2_t r2 = PMULL_11(vreinterpretq_u64_u8(a2), + vreinterpretq_u64_u8(b2)); + + result = !!(vgetq_lane_u64(r1,0) == 0x5300530053005300 && + vgetq_lane_u64(r1,1) == 0x5300530053005300 && + vgetq_lane_u64(r2,0) == 0x6c006c006c006c00 && + vgetq_lane_u64(r2,1) == 0x6c006c006c006c00); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_PMULL_AVAILABLE +} +#endif // ARM32 or ARM64 + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool CPU_ProbePMULL() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) + // longjmp and clobber warnings. Volatile is required. + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + const uint64_t wa1[]={0,W64LIT(0x9090909090909090)}, + wb1[]={0,W64LIT(0xb0b0b0b0b0b0b0b0)}; + const uint64x2_p a1=VecLoad(wa1), b1=VecLoad(wb1); + + const uint8_t wa2[]={0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0}, + wb2[]={0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0}; + const uint32x4_p a2=VecLoad(wa2), b2=VecLoad(wb2); + + const uint64x2_p r1 = VecIntelMultiply11(a1, b1); + const uint64x2_p r2 = VecIntelMultiply11((uint64x2_p)a2, (uint64x2_p)b2); + + const uint64_t wc1[]={W64LIT(0x5300530053005300), W64LIT(0x5300530053005300)}, + wc2[]={W64LIT(0x6c006c006c006c00), W64LIT(0x6c006c006c006c00)}; + const uint64x2_p c1=VecLoad(wc1), c2=VecLoad(wc2); + + result = !!(VecEqual(r1, c1) && VecEqual(r2, c2)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +#else + return false; +#endif // CRYPTOPP_POWER8_VMULL_AVAILABLE +} +#endif // PPC32 or PPC64 + +// *************************** ARM NEON *************************** // + +#if CRYPTOPP_ARM_NEON_AVAILABLE +void GCM_Xor16_NEON(byte *a, const byte *b, const byte *c) +{ + vst1q_u8(a, veorq_u8(vld1q_u8(b), vld1q_u8(c))); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +#if CRYPTOPP_ARM_PMULL_AVAILABLE + +// Swaps high and low 64-bit words +inline uint64x2_t SwapWords(const uint64x2_t& data) +{ + return (uint64x2_t)vcombine_u64( + vget_high_u64(data), vget_low_u64(data)); +} + +uint64x2_t GCM_Reduce_PMULL(uint64x2_t c0, uint64x2_t c1, uint64x2_t c2, const uint64x2_t &r) +{ + c1 = veorq_u64(c1, VEXT_U8<8>(vdupq_n_u64(0), c0)); + c1 = veorq_u64(c1, PMULL_01(c0, r)); + c0 = VEXT_U8<8>(c0, vdupq_n_u64(0)); + c0 = vshlq_n_u64(veorq_u64(c0, c1), 1); + c0 = PMULL_00(c0, r); + c2 = veorq_u64(c2, c0); + c2 = veorq_u64(c2, VEXT_U8<8>(c1, vdupq_n_u64(0))); + c1 = vshrq_n_u64(vcombine_u64(vget_low_u64(c1), vget_low_u64(c2)), 63); + c2 = vshlq_n_u64(c2, 1); + + return veorq_u64(c2, c1); +} + +uint64x2_t GCM_Multiply_PMULL(const uint64x2_t &x, const uint64x2_t &h, const uint64x2_t &r) +{ + const uint64x2_t c0 = PMULL_00(x, h); + const uint64x2_t c1 = veorq_u64(PMULL_10(x, h), PMULL_01(x, h)); + const uint64x2_t c2 = PMULL_11(x, h); + + return GCM_Reduce_PMULL(c0, c1, c2, r); +} + +void GCM_SetKeyWithoutResync_PMULL(const byte *hashKey, byte *mulTable, unsigned int tableSize) +{ + const uint64x2_t r = {0xe100000000000000ull, 0xc200000000000000ull}; + const uint64x2_t t = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(hashKey))); + const uint64x2_t h0 = vextq_u64(t, t, 1); + + uint64x2_t h = h0; + unsigned int i; + for (i=0; i= 16) + { + size_t i=0, s = UnsignedMin(len/16U, 8U); + uint64x2_t d1, d2 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-1)*16U))); + uint64x2_t c0 = vdupq_n_u64(0); + uint64x2_t c1 = vdupq_n_u64(0); + uint64x2_t c2 = vdupq_n_u64(0); + + while (true) + { + const uint64x2_t h0 = vld1q_u64((const uint64_t*)(mtable+(i+0)*16)); + const uint64x2_t h1 = vld1q_u64((const uint64_t*)(mtable+(i+1)*16)); + const uint64x2_t h2 = veorq_u64(h0, h1); + + if (++i == s) + { + const uint64x2_t t1 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data))); + d1 = veorq_u64(vextq_u64(t1, t1, 1), x); + c0 = veorq_u64(c0, PMULL_00(d1, h0)); + c2 = veorq_u64(c2, PMULL_10(d1, h1)); + d1 = veorq_u64(d1, SwapWords(d1)); + c1 = veorq_u64(c1, PMULL_00(d1, h2)); + + break; + } + + d1 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-i)*16-8))); + c0 = veorq_u64(c0, PMULL_10(d2, h0)); + c2 = veorq_u64(c2, PMULL_10(d1, h1)); + d2 = veorq_u64(d2, d1); + c1 = veorq_u64(c1, PMULL_10(d2, h2)); + + if (++i == s) + { + const uint64x2_t t2 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data))); + d1 = veorq_u64(vextq_u64(t2, t2, 1), x); + c0 = veorq_u64(c0, PMULL_01(d1, h0)); + c2 = veorq_u64(c2, PMULL_11(d1, h1)); + d1 = veorq_u64(d1, SwapWords(d1)); + c1 = veorq_u64(c1, PMULL_01(d1, h2)); + + break; + } + + const uint64x2_t t3 = vreinterpretq_u64_u8(vrev64q_u8(vld1q_u8(data+(s-i)*16-8))); + d2 = vextq_u64(t3, t3, 1); + c0 = veorq_u64(c0, PMULL_01(d1, h0)); + c2 = veorq_u64(c2, PMULL_01(d2, h1)); + d1 = veorq_u64(d1, d2); + c1 = veorq_u64(c1, PMULL_01(d1, h2)); + } + data += s*16; + len -= s*16; + + c1 = veorq_u64(veorq_u64(c1, c0), c2); + x = GCM_Reduce_PMULL(c0, c1, c2, r); + } + + vst1q_u64(reinterpret_cast(hbuffer), x); + return len; +} + +void GCM_ReverseHashBufferIfNeeded_PMULL(byte *hashBuffer) +{ + if (GetNativeByteOrder() != BIG_ENDIAN_ORDER) + { + const uint8x16_t x = vrev64q_u8(vld1q_u8(hashBuffer)); + vst1q_u8(hashBuffer, vextq_u8(x, x, 8)); + } +} +#endif // CRYPTOPP_ARM_PMULL_AVAILABLE + +// ***************************** SSE ***************************** // + +#if CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE +// SunCC 5.10-5.11 compiler crash. Move GCM_Xor16_SSE2 out-of-line, and place in +// a source file with a SSE architecture switch. Also see GH #226 and GH #284. +void GCM_Xor16_SSE2(byte *a, const byte *b, const byte *c) +{ +# if CRYPTOPP_SSE2_ASM_AVAILABLE && defined(__GNUC__) + asm ("movdqa %1, %%xmm0; pxor %2, %%xmm0; movdqa %%xmm0, %0;" + : "=m" (a[0]) : "m"(b[0]), "m"(c[0])); +# else // CRYPTOPP_SSE2_INTRIN_AVAILABLE + _mm_store_si128(M128_CAST(a), _mm_xor_si128( + _mm_load_si128(CONST_M128_CAST(b)), + _mm_load_si128(CONST_M128_CAST(c)))); +# endif +} +#endif // CRYPTOPP_SSE2_ASM_AVAILABLE + +#if CRYPTOPP_CLMUL_AVAILABLE + +#if 0 +// preserved for testing +void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c) +{ + word64 Z0=0, Z1=0, V0, V1; + + typedef BlockGetAndPut Block; + Block::Get(a)(V0)(V1); + + for (int i=0; i<16; i++) + { + for (int j=0x80; j!=0; j>>=1) + { + int x = b[i] & j; + Z0 ^= x ? V0 : 0; + Z1 ^= x ? V1 : 0; + x = (int)V1 & 1; + V1 = (V1>>1) | (V0<<63); + V0 = (V0>>1) ^ (x ? W64LIT(0xe1) << 56 : 0); + } + } + Block::Put(NULLPTR, c)(Z0)(Z1); +} + +__m128i _mm_clmulepi64_si128(const __m128i &a, const __m128i &b, int i) +{ + word64 A[1] = {ByteReverse(((word64*)&a)[i&1])}; + word64 B[1] = {ByteReverse(((word64*)&b)[i>>4])}; + + PolynomialMod2 pa((byte *)A, 8); + PolynomialMod2 pb((byte *)B, 8); + PolynomialMod2 c = pa*pb; + + __m128i output; + for (int i=0; i<16; i++) + ((byte *)&output)[i] = c.GetByte(i); + return output; +} +#endif // Testing + +// Swaps high and low 64-bit words +inline __m128i SwapWords(const __m128i& val) +{ + return _mm_shuffle_epi32(val, _MM_SHUFFLE(1, 0, 3, 2)); +} + +// SunCC 5.11-5.15 compiler crash. Make the function inline +// and parameters non-const. Also see GH #188 and GH #224. +inline __m128i GCM_Reduce_CLMUL(__m128i c0, __m128i c1, __m128i c2, const __m128i& r) +{ + /* + The polynomial to be reduced is c0 * x^128 + c1 * x^64 + c2. c0t below refers to the most + significant half of c0 as a polynomial, which, due to GCM's bit reflection, are in the + rightmost bit positions, and the lowest byte addresses. + + c1 ^= c0t * 0xc200000000000000 + c2t ^= c0t + t = shift (c1t ^ c0b) left 1 bit + c2 ^= t * 0xe100000000000000 + c2t ^= c1b + shift c2 left 1 bit and xor in lowest bit of c1t + */ + c1 = _mm_xor_si128(c1, _mm_slli_si128(c0, 8)); + c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(c0, r, 0x10)); + c0 = _mm_xor_si128(c1, _mm_srli_si128(c0, 8)); + c0 = _mm_slli_epi64(c0, 1); + c0 = _mm_clmulepi64_si128(c0, r, 0); + c2 = _mm_xor_si128(c2, c0); + c2 = _mm_xor_si128(c2, _mm_srli_si128(c1, 8)); + c1 = _mm_unpacklo_epi64(c1, c2); + c1 = _mm_srli_epi64(c1, 63); + c2 = _mm_slli_epi64(c2, 1); + return _mm_xor_si128(c2, c1); +} + +// SunCC 5.13-5.14 compiler crash. Don't make the function inline. +// This is in contrast to GCM_Reduce_CLMUL, which must be inline. +__m128i GCM_Multiply_CLMUL(const __m128i &x, const __m128i &h, const __m128i &r) +{ + const __m128i c0 = _mm_clmulepi64_si128(x,h,0); + const __m128i c1 = _mm_xor_si128(_mm_clmulepi64_si128(x,h,1), _mm_clmulepi64_si128(x,h,0x10)); + const __m128i c2 = _mm_clmulepi64_si128(x,h,0x11); + + return GCM_Reduce_CLMUL(c0, c1, c2, r); +} + +void GCM_SetKeyWithoutResync_CLMUL(const byte *hashKey, byte *mulTable, unsigned int tableSize) +{ + const __m128i r = _mm_set_epi32(0xc2000000, 0x00000000, 0xe1000000, 0x00000000); + const __m128i m = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); + __m128i h0 = _mm_shuffle_epi8(_mm_load_si128(CONST_M128_CAST(hashKey)), m), h = h0; + + unsigned int i; + for (i=0; i= 16) + { + size_t i=0, s = UnsignedMin(len/16, 8U); + __m128i d1 = _mm_loadu_si128(CONST_M128_CAST(data+(s-1)*16)); + __m128i d2 = _mm_shuffle_epi8(d1, m2); + __m128i c0 = _mm_setzero_si128(); + __m128i c1 = _mm_setzero_si128(); + __m128i c2 = _mm_setzero_si128(); + + while (true) + { + const __m128i h0 = _mm_load_si128(CONST_M128_CAST(mtable+(i+0)*16)); + const __m128i h1 = _mm_load_si128(CONST_M128_CAST(mtable+(i+1)*16)); + const __m128i h2 = _mm_xor_si128(h0, h1); + + if (++i == s) + { + d1 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(data)), m1); + d1 = _mm_xor_si128(d1, x); + c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0)); + c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 1)); + d1 = _mm_xor_si128(d1, SwapWords(d1)); + c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0)); + break; + } + + d1 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(data+(s-i)*16-8)), m2); + c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d2, h0, 1)); + c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 1)); + d2 = _mm_xor_si128(d2, d1); + c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d2, h2, 1)); + + if (++i == s) + { + d1 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(data)), m1); + d1 = _mm_xor_si128(d1, x); + c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0x10)); + c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d1, h1, 0x11)); + d1 = _mm_xor_si128(d1, SwapWords(d1)); + c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0x10)); + break; + } + + d2 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(data+(s-i)*16-8)), m1); + c0 = _mm_xor_si128(c0, _mm_clmulepi64_si128(d1, h0, 0x10)); + c2 = _mm_xor_si128(c2, _mm_clmulepi64_si128(d2, h1, 0x10)); + d1 = _mm_xor_si128(d1, d2); + c1 = _mm_xor_si128(c1, _mm_clmulepi64_si128(d1, h2, 0x10)); + } + data += s*16; + len -= s*16; + + c1 = _mm_xor_si128(_mm_xor_si128(c1, c0), c2); + x = GCM_Reduce_CLMUL(c0, c1, c2, r); + } + + _mm_store_si128(M128_CAST(hbuffer), x); + return len; +} + +void GCM_ReverseHashBufferIfNeeded_CLMUL(byte *hashBuffer) +{ + // SSSE3 instruction, but only used with CLMUL + const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); + _mm_storeu_si128(M128_CAST(hashBuffer), _mm_shuffle_epi8( + _mm_loadu_si128(CONST_M128_CAST(hashBuffer)), mask)); +} +#endif // CRYPTOPP_CLMUL_AVAILABLE + +// ***************************** POWER8 ***************************** // + +#if CRYPTOPP_POWER8_AVAILABLE +void GCM_Xor16_POWER8(byte *a, const byte *b, const byte *c) +{ + VecStore(VecXor(VecLoad(b), VecLoad(c)), a); +} +#endif // CRYPTOPP_POWER8_AVAILABLE + +#if CRYPTOPP_POWER8_VMULL_AVAILABLE + +uint64x2_p GCM_Reduce_VMULL(uint64x2_p c0, uint64x2_p c1, uint64x2_p c2, uint64x2_p r) +{ + const uint64x2_p m1 = {1,1}, m63 = {63,63}; + + c1 = VecXor(c1, VecShiftRightOctet<8>(c0)); + c1 = VecXor(c1, VecIntelMultiply10(c0, r)); + c0 = VecXor(c1, VecShiftLeftOctet<8>(c0)); + c0 = VecIntelMultiply00(vec_sl(c0, m1), r); + c2 = VecXor(c2, c0); + c2 = VecXor(c2, VecShiftLeftOctet<8>(c1)); + c1 = vec_sr(vec_mergeh(c1, c2), m63); + c2 = vec_sl(c2, m1); + + return VecXor(c2, c1); +} + +inline uint64x2_p GCM_Multiply_VMULL(uint64x2_p x, uint64x2_p h, uint64x2_p r) +{ + const uint64x2_p c0 = VecIntelMultiply00(x, h); + const uint64x2_p c1 = VecXor(VecIntelMultiply01(x, h), VecIntelMultiply10(x, h)); + const uint64x2_p c2 = VecIntelMultiply11(x, h); + + return GCM_Reduce_VMULL(c0, c1, c2, r); +} + +inline uint64x2_p LoadHashKey(const byte *hashKey) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint64x2_p key = (uint64x2_p)VecLoad(hashKey); + const uint8x16_p mask = {8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7}; + return VecPermute(key, key, mask); +#else + const uint64x2_p key = (uint64x2_p)VecLoad(hashKey); + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return VecPermute(key, key, mask); +#endif +} + +void GCM_SetKeyWithoutResync_VMULL(const byte *hashKey, byte *mulTable, unsigned int tableSize) +{ + const uint64x2_p r = {0xe100000000000000ull, 0xc200000000000000ull}; + uint64x2_p h = LoadHashKey(hashKey), h0 = h; + + unsigned int i; + uint64_t temp[2]; + + for (i=0; i +inline T SwapWords(const T& data) +{ + return (T)VecRotateLeftOctet<8>(data); +} + +inline uint64x2_p LoadBuffer1(const byte *dataBuffer) +{ +#if (CRYPTOPP_BIG_ENDIAN) + return (uint64x2_p)VecLoad(dataBuffer); +#else + const uint64x2_p data = (uint64x2_p)VecLoad(dataBuffer); + const uint8x16_p mask = {7,6,5,4, 3,2,1,0, 15,14,13,12, 11,10,9,8}; + return VecPermute(data, data, mask); +#endif +} + +inline uint64x2_p LoadBuffer2(const byte *dataBuffer) +{ +#if (CRYPTOPP_BIG_ENDIAN) + return (uint64x2_p)SwapWords(VecLoadBE(dataBuffer)); +#else + return (uint64x2_p)VecLoadBE(dataBuffer); +#endif +} + +size_t GCM_AuthenticateBlocks_VMULL(const byte *data, size_t len, const byte *mtable, byte *hbuffer) +{ + const uint64x2_p r = {0xe100000000000000ull, 0xc200000000000000ull}; + uint64x2_p x = (uint64x2_p)VecLoad(hbuffer); + + while (len >= 16) + { + size_t i=0, s = UnsignedMin(len/16, 8U); + uint64x2_p d1, d2 = LoadBuffer1(data+(s-1)*16); + uint64x2_p c0 = {0}, c1 = {0}, c2 = {0}; + + while (true) + { + const uint64x2_p h0 = (uint64x2_p)VecLoad(mtable+(i+0)*16); + const uint64x2_p h1 = (uint64x2_p)VecLoad(mtable+(i+1)*16); + const uint64x2_p h2 = (uint64x2_p)VecXor(h0, h1); + + if (++i == s) + { + d1 = LoadBuffer2(data); + d1 = VecXor(d1, x); + c0 = VecXor(c0, VecIntelMultiply00(d1, h0)); + c2 = VecXor(c2, VecIntelMultiply01(d1, h1)); + d1 = VecXor(d1, SwapWords(d1)); + c1 = VecXor(c1, VecIntelMultiply00(d1, h2)); + break; + } + + d1 = LoadBuffer1(data+(s-i)*16-8); + c0 = VecXor(c0, VecIntelMultiply01(d2, h0)); + c2 = VecXor(c2, VecIntelMultiply01(d1, h1)); + d2 = VecXor(d2, d1); + c1 = VecXor(c1, VecIntelMultiply01(d2, h2)); + + if (++i == s) + { + d1 = LoadBuffer2(data); + d1 = VecXor(d1, x); + c0 = VecXor(c0, VecIntelMultiply10(d1, h0)); + c2 = VecXor(c2, VecIntelMultiply11(d1, h1)); + d1 = VecXor(d1, SwapWords(d1)); + c1 = VecXor(c1, VecIntelMultiply10(d1, h2)); + break; + } + + d2 = LoadBuffer2(data+(s-i)*16-8); + c0 = VecXor(c0, VecIntelMultiply10(d1, h0)); + c2 = VecXor(c2, VecIntelMultiply10(d2, h1)); + d1 = VecXor(d1, d2); + c1 = VecXor(c1, VecIntelMultiply10(d1, h2)); + } + data += s*16; + len -= s*16; + + c1 = VecXor(VecXor(c1, c0), c2); + x = GCM_Reduce_VMULL(c0, c1, c2, r); + } + + VecStore(x, hbuffer); + return len; +} + +void GCM_ReverseHashBufferIfNeeded_VMULL(byte *hashBuffer) +{ + const uint64x2_p mask = {0x08090a0b0c0d0e0full, 0x0001020304050607ull}; + VecStore(VecPermute(VecLoad(hashBuffer), mask), hashBuffer); +} +#endif // CRYPTOPP_POWER8_VMULL_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/gf256.cpp b/extension/third_party/cryptopp/gf256.cpp new file mode 100644 index 00000000..c432344f --- /dev/null +++ b/extension/third_party/cryptopp/gf256.cpp @@ -0,0 +1,34 @@ +// gf256.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gf256.h" + +NAMESPACE_BEGIN(CryptoPP) + +GF256::Element GF256::Multiply(Element a, Element b) const +{ + word result = 0, t = b; + + for (unsigned int i=0; i<8; i++) + { + result <<= 1; + if (result & 0x100) + result ^= m_modulus; + + t <<= 1; + if (t & 0x100) + result ^= a; + } + + return (GF256::Element) result; +} + +GF256::Element GF256::MultiplicativeInverse(Element a) const +{ + Element result = a; + for (int i=1; i<7; i++) + result = Multiply(Square(result), a); + return Square(result); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/gf256.h b/extension/third_party/cryptopp/gf256.h new file mode 100644 index 00000000..9cef8309 --- /dev/null +++ b/extension/third_party/cryptopp/gf256.h @@ -0,0 +1,72 @@ +// gf256.h - originally written and placed in the public domain by Wei Dai + +/// \file gf256.h +/// \brief Classes and functions for schemes over GF(256) + +#ifndef CRYPTOPP_GF256_H +#define CRYPTOPP_GF256_H + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(256) with polynomial basis +class GF256 +{ +public: + typedef byte Element; + typedef int RandomizationParameter; + + GF256(byte modulus) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateByte();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Zero() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element One() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gf2_32.cpp b/extension/third_party/cryptopp/gf2_32.cpp new file mode 100644 index 00000000..51d10a49 --- /dev/null +++ b/extension/third_party/cryptopp/gf2_32.cpp @@ -0,0 +1,99 @@ +// gf2_32.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "misc.h" +#include "gf2_32.h" + +NAMESPACE_BEGIN(CryptoPP) + +GF2_32::Element GF2_32::Multiply(Element a, Element b) const +{ + word32 table[4]; + table[0] = 0; + table[1] = m_modulus; + if (a & 0x80000000) + { + table[2] = m_modulus ^ (a<<1); + table[3] = a<<1; + } + else + { + table[2] = a<<1; + table[3] = m_modulus ^ (a<<1); + } + +#if CRYPTOPP_FAST_ROTATE(32) + b = rotrConstant<30>(b); + word32 result = table[b&2]; + + for (int i=29; i>=0; --i) + { + b = rotlConstant<1>(b); + result = (result<<1) ^ table[(b&2) + (result>>31)]; + } + + return (b&1) ? result ^ a : result; +#else + word32 result = table[(b>>30) & 2]; + + for (int i=29; i>=0; --i) + result = (result<<1) ^ table[((b>>i)&2) + (result>>31)]; + + return (b&1) ? result ^ a : result; +#endif +} + +GF2_32::Element GF2_32::MultiplicativeInverse(Element a) const +{ + if (a <= 1) // 1 is a special case + return a; + + // warning - don't try to adapt this algorithm for another situation + word32 g0=m_modulus, g1=a, g2=a; + word32 v0=0, v1=1, v2=1; + + CRYPTOPP_ASSERT(g1); + + while (!(g2 & 0x80000000)) + { + g2 <<= 1; + v2 <<= 1; + } + + g2 <<= 1; + v2 <<= 1; + + g0 ^= g2; + v0 ^= v2; + + while (g0 != 1) + { + if (g1 < g0 || ((g0^g1) < g0 && (g0^g1) < g1)) + { + CRYPTOPP_ASSERT(BitPrecision(g1) <= BitPrecision(g0)); + g2 = g1; + v2 = v1; + } + else + { + CRYPTOPP_ASSERT(BitPrecision(g1) > BitPrecision(g0)); + g2 = g0; g0 = g1; g1 = g2; + v2 = v0; v0 = v1; v1 = v2; + } + + while ((g0^g2) >= g2) + { + CRYPTOPP_ASSERT(BitPrecision(g0) > BitPrecision(g2)); + g2 <<= 1; + v2 <<= 1; + } + + CRYPTOPP_ASSERT(BitPrecision(g0) == BitPrecision(g2)); + g0 ^= g2; + v0 ^= v2; + } + + return v0; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/gf2_32.h b/extension/third_party/cryptopp/gf2_32.h new file mode 100644 index 00000000..f0d229df --- /dev/null +++ b/extension/third_party/cryptopp/gf2_32.h @@ -0,0 +1,73 @@ +// gf2_32.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2_32.h +/// \brief Classes and functions for schemes over GF(2^32) + +#ifndef CRYPTOPP_GF2_32_H +#define CRYPTOPP_GF2_32_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(2^32) with polynomial basis +class GF2_32 +{ +public: + typedef word32 Element; + typedef int RandomizationParameter; + + GF2_32(word32 modulus=0x0000008D) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateWord32();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Identity() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element MultiplicativeIdentity() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word32 m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gf2n.cpp b/extension/third_party/cryptopp/gf2n.cpp new file mode 100644 index 00000000..452e6982 --- /dev/null +++ b/extension/third_party/cryptopp/gf2n.cpp @@ -0,0 +1,1070 @@ +// gf2n.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "cryptlib.h" +#include "algebra.h" +#include "randpool.h" +#include "filters.h" +#include "smartptr.h" +#include "words.h" +#include "misc.h" +#include "gf2n.h" +#include "oids.h" +#include "asn.h" +#include "cpu.h" + +#include + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::PolynomialMod2; + +#if defined(HAVE_GCC_INIT_PRIORITY) + const PolynomialMod2 g_zero __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 60))) = PolynomialMod2(); + const PolynomialMod2 g_one __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 61))) = PolynomialMod2(1); +#elif defined(HAVE_MSC_INIT_PRIORITY) + #pragma warning(disable: 4075) + #pragma init_seg(".CRT$XCU") + const PolynomialMod2 g_zero; + const PolynomialMod2 g_one(1); + #pragma warning(default: 4075) +#elif defined(HAVE_XLC_INIT_PRIORITY) + #pragma priority(290) + const PolynomialMod2 g_zero; + const PolynomialMod2 g_one(1); +#endif + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_CLMUL_AVAILABLE) +extern CRYPTOPP_DLL void GF2NT_233_Multiply_Reduce_CLMUL(const word* pA, const word* pB, word* pC); +extern CRYPTOPP_DLL void GF2NT_233_Square_Reduce_CLMUL(const word* pA, word* pC); +#endif + +#if (CRYPTOPP_ARM_PMULL_AVAILABLE) +extern void GF2NT_233_Multiply_Reduce_ARMv8(const word* pA, const word* pB, word* pC); +extern void GF2NT_233_Square_Reduce_ARMv8(const word* pA, word* pC); +#endif + +#if (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 +extern void GF2NT_233_Multiply_Reduce_POWER8(const word* pA, const word* pB, word* pC); +extern void GF2NT_233_Square_Reduce_POWER8(const word* pA, word* pC); +#endif + +PolynomialMod2::PolynomialMod2() +{ +} + +PolynomialMod2::PolynomialMod2(word value, size_t bitLength) + : reg(BitsToWords(bitLength)) +{ + CRYPTOPP_ASSERT(value==0 || reg.size()>0); + + if (reg.size() > 0) + { + reg[0] = value; + SetWords(reg+1, 0, reg.size()-1); + } +} + +PolynomialMod2::PolynomialMod2(const PolynomialMod2& t) + : reg(t.reg.size()) +{ + CopyWords(reg, t.reg, reg.size()); +} + +void PolynomialMod2::Randomize(RandomNumberGenerator &rng, size_t nbits) +{ + const size_t nbytes = nbits/8 + 1; + SecByteBlock buf(nbytes); + rng.GenerateBlock(buf, nbytes); + buf[0] = (byte)Crop(buf[0], nbits % 8); + Decode(buf, nbytes); +} + +PolynomialMod2 PolynomialMod2::AllOnes(size_t bitLength) +{ + PolynomialMod2 result((word)0, bitLength); + SetWords(result.reg, ~(word(0)), result.reg.size()); + if (bitLength%WORD_BITS) + result.reg[result.reg.size()-1] = (word)Crop(result.reg[result.reg.size()-1], bitLength%WORD_BITS); + return result; +} + +void PolynomialMod2::SetBit(size_t n, int value) +{ + if (value) + { + reg.CleanGrow(n/WORD_BITS + 1); + reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS)); + } + else + { + if (n/WORD_BITS < reg.size()) + reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS)); + } +} + +byte PolynomialMod2::GetByte(size_t n) const +{ + if (n/WORD_SIZE >= reg.size()) + return 0; + else + return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); +} + +void PolynomialMod2::SetByte(size_t n, byte value) +{ + reg.CleanGrow(BytesToWords(n+1)); + reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); + reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); +} + +PolynomialMod2 PolynomialMod2::Monomial(size_t i) +{ + PolynomialMod2 r((word)0, i+1); + r.SetBit(i); + return r; +} + +PolynomialMod2 PolynomialMod2::Trinomial(size_t t0, size_t t1, size_t t2) +{ + PolynomialMod2 r((word)0, t0+1); + r.SetBit(t0); + r.SetBit(t1); + r.SetBit(t2); + return r; +} + +PolynomialMod2 PolynomialMod2::Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4) +{ + PolynomialMod2 r((word)0, t0+1); + r.SetBit(t0); + r.SetBit(t1); + r.SetBit(t2); + r.SetBit(t3); + r.SetBit(t4); + return r; +} + +template +struct NewPolynomialMod2 +{ + PolynomialMod2 * operator()() const + { + return new PolynomialMod2(i); + } +}; + +const PolynomialMod2 &PolynomialMod2::Zero() +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_zero; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const PolynomialMod2 g_zero; + return g_zero; +#else + return Singleton().Ref(); +#endif +} + +const PolynomialMod2 &PolynomialMod2::One() +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_one; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const PolynomialMod2 g_one(1); + return g_one; +#else + return Singleton >().Ref(); +#endif +} + +void PolynomialMod2::Decode(const byte *input, size_t inputLen) +{ + StringStore store(input, inputLen); + Decode(store, inputLen); +} + +void PolynomialMod2::Encode(byte *output, size_t outputLen) const +{ + ArraySink sink(output, outputLen); + Encode(sink, outputLen); +} + +void PolynomialMod2::Decode(BufferedTransformation &bt, size_t inputLen) +{ + CRYPTOPP_ASSERT(bt.MaxRetrievable() >= inputLen); + if (bt.MaxRetrievable() < inputLen) + throw InvalidArgument("PolynomialMod2: input length is too small"); + + reg.CleanNew(BytesToWords(inputLen)); + + for (size_t i=inputLen; i > 0; i--) + { + byte b; + (void)bt.Get(b); + reg[(i-1)/WORD_SIZE] |= word(b) << ((i-1)%WORD_SIZE)*8; + } +} + +void PolynomialMod2::Encode(BufferedTransformation &bt, size_t outputLen) const +{ + for (size_t i=outputLen; i > 0; i--) + bt.Put(GetByte(i-1)); +} + +void PolynomialMod2::DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const +{ + DERGeneralEncoder enc(bt, OCTET_STRING); + Encode(enc, length); + enc.MessageEnd(); +} + +void PolynomialMod2::BERDecodeAsOctetString(BufferedTransformation &bt, size_t length) +{ + BERGeneralDecoder dec(bt, OCTET_STRING); + if (!dec.IsDefiniteLength() || dec.RemainingLength() != length) + BERDecodeError(); + Decode(dec, length); + dec.MessageEnd(); +} + +unsigned int PolynomialMod2::WordCount() const +{ + return (unsigned int)CountWords(reg, reg.size()); +} + +unsigned int PolynomialMod2::ByteCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int PolynomialMod2::BitCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int PolynomialMod2::Parity() const +{ + unsigned i; + word temp=0; + for (i=0; i= reg.size()) + { + PolynomialMod2 result((word)0, b.reg.size()*WORD_BITS); + XorWords(result.reg, reg, b.reg, reg.size()); + CopyWords(result.reg+reg.size(), b.reg+reg.size(), b.reg.size()-reg.size()); + return result; + } + else + { + PolynomialMod2 result((word)0, reg.size()*WORD_BITS); + XorWords(result.reg, reg, b.reg, b.reg.size()); + CopyWords(result.reg+b.reg.size(), reg+b.reg.size(), reg.size()-b.reg.size()); + return result; + } +} + +PolynomialMod2 PolynomialMod2::And(const PolynomialMod2 &b) const +{ + PolynomialMod2 result((word)0, WORD_BITS*STDMIN(reg.size(), b.reg.size())); + AndWords(result.reg, reg, b.reg, result.reg.size()); + return result; +} + +PolynomialMod2 PolynomialMod2::Times(const PolynomialMod2 &b) const +{ + PolynomialMod2 result((word)0, BitCount() + b.BitCount()); + + for (int i=b.Degree(); i>=0; i--) + { + result <<= 1; + if (b[i]) + XorWords(result.reg, reg, reg.size()); + } + return result; +} + +PolynomialMod2 PolynomialMod2::Squared() const +{ + static const word map[16] = {0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}; + + PolynomialMod2 result((word)0, 2*reg.size()*WORD_BITS); + + for (unsigned i=0; i> (j/2)) % 16] << j; + + for (j=0; j> (j/2 + WORD_BITS/2)) % 16] << j; + } + + return result; +} + +void PolynomialMod2::Divide(PolynomialMod2 &remainder, PolynomialMod2 "ient, + const PolynomialMod2 ÷nd, const PolynomialMod2 &divisor) +{ + if (!divisor) + throw PolynomialMod2::DivideByZero(); + + int degree = divisor.Degree(); + remainder.reg.CleanNew(BitsToWords(degree+1)); + if (dividend.BitCount() >= divisor.BitCount()) + quotient.reg.CleanNew(BitsToWords(dividend.BitCount() - divisor.BitCount() + 1)); + else + quotient.reg.CleanNew(0); + + for (int i=dividend.Degree(); i>=0; i--) + { + remainder <<= 1; + remainder.reg[0] |= dividend[i]; + if (remainder[degree]) + { + remainder -= divisor; + quotient.SetBit(i); + } + } +} + +PolynomialMod2 PolynomialMod2::DividedBy(const PolynomialMod2 &b) const +{ + PolynomialMod2 remainder, quotient; + PolynomialMod2::Divide(remainder, quotient, *this, b); + return quotient; +} + +PolynomialMod2 PolynomialMod2::Modulo(const PolynomialMod2 &b) const +{ + PolynomialMod2 remainder, quotient; + PolynomialMod2::Divide(remainder, quotient, *this, b); + return remainder; +} + +PolynomialMod2& PolynomialMod2::operator<<=(unsigned int n) +{ +#if defined(CRYPTOPP_DEBUG) + int x=0; CRYPTOPP_UNUSED(x); + CRYPTOPP_ASSERT(SafeConvert(n,x)); +#endif + + if (!reg.size()) + return *this; + + int i; + word u; + word carry=0; + word *r=reg; + + if (n==1) // special case code for most frequent case + { + i = (int)reg.size(); + while (i--) + { + u = *r; + *r = (u << 1) | carry; + carry = u >> (WORD_BITS-1); + r++; + } + + if (carry) + { + reg.Grow(reg.size()+1); + reg[reg.size()-1] = carry; + } + + return *this; + } + + const int shiftWords = n / WORD_BITS; + const int shiftBits = n % WORD_BITS; + + if (shiftBits) + { + i = (int)reg.size(); + while (i--) + { + u = *r; + *r = (u << shiftBits) | carry; + carry = u >> (WORD_BITS-shiftBits); + r++; + } + } + + if (carry) + { + // Thanks to Apatryda, http://github.com/weidai11/cryptopp/issues/64 + const size_t carryIndex = reg.size(); + reg.Grow(reg.size()+shiftWords+!!shiftBits); + reg[carryIndex] = carry; + } + else + reg.Grow(reg.size()+shiftWords); + + if (shiftWords) + { + for (i = (int)reg.size()-1; i>=shiftWords; i--) + reg[i] = reg[i-shiftWords]; + for (; i>=0; i--) + reg[i] = 0; + } + + return *this; +} + +PolynomialMod2& PolynomialMod2::operator>>=(unsigned int n) +{ + if (!reg.size()) + return *this; + + int shiftWords = n / WORD_BITS; + int shiftBits = n % WORD_BITS; + + size_t i; + word u; + word carry=0; + word *r=reg+reg.size()-1; + + if (shiftBits) + { + i = reg.size(); + while (i--) + { + u = *r; + *r = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + r--; + } + } + + if (shiftWords) + { + for (i=0; i>(unsigned int n) const +{ + PolynomialMod2 result(*this); + return result>>=n; +} + +bool PolynomialMod2::operator!() const +{ + for (unsigned i=0; i s(a.BitCount()/bits+1); + unsigned i; + + static const char upper[]="0123456789ABCDEF"; + static const char lower[]="0123456789abcdef"; + const char* const vec = (out.flags() & std::ios::uppercase) ? upper : lower; + + for (i=0; i*bits < a.BitCount(); i++) + { + int digit=0; + for (int j=0; j().Gcd(a, b); +} + +PolynomialMod2 PolynomialMod2::InverseMod(const PolynomialMod2 &modulus) const +{ + typedef EuclideanDomainOf Domain; + return QuotientRing(Domain(), modulus).MultiplicativeInverse(*this); +} + +bool PolynomialMod2::IsIrreducible() const +{ + signed int d = Degree(); + if (d <= 0) + return false; + + PolynomialMod2 t(2), u(t); + for (int i=1; i<=d/2; i++) + { + u = u.Squared()%(*this); + if (!Gcd(u+t, *this).IsUnit()) + return false; + } + return true; +} + +// ******************************************************** + +GF2NP::GF2NP(const PolynomialMod2 &modulus) + : QuotientRing >(EuclideanDomainOf(), modulus), m(modulus.Degree()) +{ +} + +GF2NP::Element GF2NP::SquareRoot(const Element &a) const +{ + Element r = a; + for (unsigned int i=1; i c1 && c1 > c2 && c2==0); +} + +const GF2NT::Element& GF2NT::MultiplicativeInverse(const Element &a) const +{ + if (t0-t1 < WORD_BITS) + return GF2NP::MultiplicativeInverse(a); + + SecWordBlock T(m_modulus.reg.size() * 4); + word *b = T; + word *c = T+m_modulus.reg.size(); + word *f = T+2*m_modulus.reg.size(); + word *g = T+3*m_modulus.reg.size(); + size_t bcLen=1, fgLen=m_modulus.reg.size(); + unsigned int k=0; + + SetWords(T, 0, 3*m_modulus.reg.size()); + b[0]=1; + CRYPTOPP_ASSERT(a.reg.size() <= m_modulus.reg.size()); + CopyWords(f, a.reg, a.reg.size()); + CopyWords(g, m_modulus.reg, m_modulus.reg.size()); + + while (1) + { + word t=f[0]; + while (!t) + { + ShiftWordsRightByWords(f, fgLen, 1); + if (c[bcLen-1]) + bcLen++; + CRYPTOPP_ASSERT(bcLen <= m_modulus.reg.size()); + ShiftWordsLeftByWords(c, bcLen, 1); + k+=WORD_BITS; + t=f[0]; + } + + unsigned int i=0; + while (t%2 == 0) + { + t>>=1; + i++; + } + k+=i; + + if (t==1 && CountWords(f, fgLen)==1) + break; + + if (i==1) + { + ShiftWordsRightByBits(f, fgLen, 1); + t=ShiftWordsLeftByBits(c, bcLen, 1); + } + else + { + ShiftWordsRightByBits(f, fgLen, i); + t=ShiftWordsLeftByBits(c, bcLen, i); + } + if (t) + { + c[bcLen] = t; + bcLen++; + CRYPTOPP_ASSERT(bcLen <= m_modulus.reg.size()); + } + + if (f[fgLen-1]==0 && g[fgLen-1]==0) + fgLen--; + + if (f[fgLen-1] < g[fgLen-1]) + { + std::swap(f, g); + std::swap(b, c); + } + + XorWords(f, g, fgLen); + XorWords(b, c, bcLen); + } + + while (k >= WORD_BITS) + { + word temp = b[0]; + // right shift b + for (unsigned i=0; i+1> j) & 1) << (t1 + j); + const unsigned int shift = t1 + j; + CRYPTOPP_ASSERT(shift < WORD_BITS); + temp ^= (shift < WORD_BITS) ? (((temp >> j) & 1) << shift) : 0; + } + else + b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; + + if (t1 % WORD_BITS) + b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); + + if (t0%WORD_BITS) + { + b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; + b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); + } + else + b[t0/WORD_BITS-1] ^= temp; + + k -= WORD_BITS; + } + + if (k) + { + word temp = b[0] << (WORD_BITS - k); + ShiftWordsRightByBits(b, BitsToWords(m), k); + + if (t1 < WORD_BITS) + { + for (unsigned int j=0; j> j) & 1) << (t1 + j); + const unsigned int shift = t1 + j; + CRYPTOPP_ASSERT(shift < WORD_BITS); + temp ^= (shift < WORD_BITS) ? (((temp >> j) & 1) << shift) : 0; + } + } + else + { + b[t1/WORD_BITS-1] ^= temp << t1%WORD_BITS; + } + + if (t1 % WORD_BITS) + b[t1/WORD_BITS] ^= temp >> (WORD_BITS - t1%WORD_BITS); + + if (t0%WORD_BITS) + { + b[t0/WORD_BITS-1] ^= temp << t0%WORD_BITS; + b[t0/WORD_BITS] ^= temp >> (WORD_BITS - t0%WORD_BITS); + } + else + b[t0/WORD_BITS-1] ^= temp; + } + + CopyWords(result.reg.begin(), b, result.reg.size()); + return result; +} + +const GF2NT::Element& GF2NT::Multiply(const Element &a, const Element &b) const +{ + size_t aSize = STDMIN(a.reg.size(), result.reg.size()); + Element r((word)0, m); + + for (int i=m-1; i>=0; i--) + { + if (r[m-1]) + { + ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); + XorWords(r.reg.begin(), m_modulus.reg, r.reg.size()); + } + else + ShiftWordsLeftByBits(r.reg.begin(), r.reg.size(), 1); + + if (b[i]) + XorWords(r.reg.begin(), a.reg, aSize); + } + + if (m%WORD_BITS) + r.reg.begin()[r.reg.size()-1] = (word)Crop(r.reg[r.reg.size()-1], m%WORD_BITS); + + CopyWords(result.reg.begin(), r.reg.begin(), result.reg.size()); + return result; +} + +const GF2NT::Element& GF2NT::Reduced(const Element &a) const +{ + if (t0-t1 < WORD_BITS) + return m_domain.Mod(a, m_modulus); + + SecWordBlock b(a.reg); + + size_t i; + for (i=b.size()-1; i>=BitsToWords(t0); i--) + { + word temp = b[i]; + + if (t0%WORD_BITS) + { + b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; + b[i-t0/WORD_BITS-1] ^= temp << (WORD_BITS - t0%WORD_BITS); + } + else + b[i-t0/WORD_BITS] ^= temp; + + if ((t0-t1)%WORD_BITS) + { + b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; + b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); + } + else + b[i-(t0-t1)/WORD_BITS] ^= temp; + } + + if (i==BitsToWords(t0)-1 && t0%WORD_BITS) + { + word mask = ((word)1<<(t0%WORD_BITS))-1; + word temp = b[i] & ~mask; + b[i] &= mask; + + b[i-t0/WORD_BITS] ^= temp >> t0%WORD_BITS; + + if ((t0-t1)%WORD_BITS) + { + b[i-(t0-t1)/WORD_BITS] ^= temp >> (t0-t1)%WORD_BITS; + if ((t0-t1)%WORD_BITS > t0%WORD_BITS) + b[i-(t0-t1)/WORD_BITS-1] ^= temp << (WORD_BITS - (t0-t1)%WORD_BITS); + else + CRYPTOPP_ASSERT(temp << (WORD_BITS - (t0-t1)%WORD_BITS) == 0); + } + else + b[i-(t0-t1)/WORD_BITS] ^= temp; + } + + SetWords(result.reg.begin(), 0, result.reg.size()); + CopyWords(result.reg.begin(), b, STDMIN(b.size(), result.reg.size())); + return result; +} + +void GF2NP::DEREncodeElement(BufferedTransformation &out, const Element &a) const +{ + a.DEREncodeAsOctetString(out, MaxElementByteLength()); +} + +void GF2NP::BERDecodeElement(BufferedTransformation &in, Element &a) const +{ + a.BERDecodeAsOctetString(in, MaxElementByteLength()); +} + +void GF2NT::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::characteristic_two_field().DEREncode(seq); + DERSequenceEncoder parameters(seq); + DEREncodeUnsigned(parameters, m); + ASN1::tpBasis().DEREncode(parameters); + DEREncodeUnsigned(parameters, t1); + parameters.MessageEnd(); + seq.MessageEnd(); +} + +void GF2NPP::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::characteristic_two_field().DEREncode(seq); + DERSequenceEncoder parameters(seq); + DEREncodeUnsigned(parameters, m); + ASN1::ppBasis().DEREncode(parameters); + DERSequenceEncoder pentanomial(parameters); + DEREncodeUnsigned(pentanomial, t3); + DEREncodeUnsigned(pentanomial, t2); + DEREncodeUnsigned(pentanomial, t1); + pentanomial.MessageEnd(); + parameters.MessageEnd(); + seq.MessageEnd(); +} + +GF2NP * BERDecodeGF2NP(BufferedTransformation &bt) +{ + member_ptr result; + + BERSequenceDecoder seq(bt); + if (OID(seq) != ASN1::characteristic_two_field()) + BERDecodeError(); + BERSequenceDecoder parameters(seq); + unsigned int m; + BERDecodeUnsigned(parameters, m); + OID oid(parameters); + if (oid == ASN1::tpBasis()) + { + unsigned int t1; + BERDecodeUnsigned(parameters, t1); + result.reset(new GF2NT(m, t1, 0)); + } + else if (oid == ASN1::ppBasis()) + { + unsigned int t1, t2, t3; + BERSequenceDecoder pentanomial(parameters); + BERDecodeUnsigned(pentanomial, t3); + BERDecodeUnsigned(pentanomial, t2); + BERDecodeUnsigned(pentanomial, t1); + pentanomial.MessageEnd(); + result.reset(new GF2NPP(m, t3, t2, t1, 0)); + } + else + { + BERDecodeError(); + return NULLPTR; + } + parameters.MessageEnd(); + seq.MessageEnd(); + + return result.release(); +} + +// ******************************************************** + +GF2NT233::GF2NT233(unsigned int c0, unsigned int c1, unsigned int c2) + : GF2NT(c0, c1, c2) +{ + CRYPTOPP_ASSERT(c0 > c1 && c1 > c2 && c2==0); +} + +const GF2NT::Element& GF2NT233::Multiply(const Element &a, const Element &b) const +{ +#if (CRYPTOPP_CLMUL_AVAILABLE) + if (HasCLMUL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + const word* pB = b.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Multiply_Reduce_CLMUL(pA, pB, pR); + return result; + } + else +#elif (CRYPTOPP_ARM_PMULL_AVAILABLE) + if (HasPMULL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + const word* pB = b.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Multiply_Reduce_ARMv8(pA, pB, pR); + return result; + } + else +#elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 + if (HasPMULL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(b.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + const word* pB = b.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Multiply_Reduce_POWER8(pA, pB, pR); + return result; + } + else +#endif + + return GF2NT::Multiply(a, b); +} + +const GF2NT::Element& GF2NT233::Square(const Element &a) const +{ +#if (CRYPTOPP_CLMUL_AVAILABLE) + if (HasCLMUL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Square_Reduce_CLMUL(pA, pR); + return result; + } + else +#elif (CRYPTOPP_ARM_PMULL_AVAILABLE) + if (HasPMULL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Square_Reduce_ARMv8(pA, pR); + return result; + } + else +#elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 + if (HasPMULL()) + { + CRYPTOPP_ASSERT(a.reg.size()*WORD_BITS == 256); + CRYPTOPP_ASSERT(result.reg.size()*WORD_BITS == 256); + + const word* pA = a.reg.begin(); + word* pR = result.reg.begin(); + + GF2NT_233_Square_Reduce_POWER8(pA, pR); + return result; + } + else +#endif + + return GF2NT::Square(a); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gf2n.h b/extension/third_party/cryptopp/gf2n.h new file mode 100644 index 00000000..86cf3b4c --- /dev/null +++ b/extension/third_party/cryptopp/gf2n.h @@ -0,0 +1,404 @@ +// gf2n.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2n.h +/// \brief Classes and functions for schemes over GF(2^n) + +#ifndef CRYPTOPP_GF2N_H +#define CRYPTOPP_GF2N_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" +#include "asn.h" + +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Polynomial with Coefficients in GF(2) +/*! \nosubgrouping */ +class CRYPTOPP_DLL PolynomialMod2 +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Excpetion thrown when divide by zero is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialMod2: division by zero") {} + }; + + typedef unsigned int RandomizationParameter; + //@} + + /// \name CREATORS + //@{ + /// \brief Construct the zero polynomial + PolynomialMod2(); + /// Copy construct a PolynomialMod2 + PolynomialMod2(const PolynomialMod2& t); + + /// \brief Construct a PolynomialMod2 from a word + /// \details value should be encoded with the least significant bit as coefficient to x^0 + /// and most significant bit as coefficient to x^(WORD_BITS-1) + /// bitLength denotes how much memory to allocate initially + PolynomialMod2(word value, size_t bitLength=WORD_BITS); + + /// \brief Construct a PolynomialMod2 from big-endian byte array + PolynomialMod2(const byte *encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Construct a PolynomialMod2 from big-endian form stored in a BufferedTransformation + PolynomialMod2(BufferedTransformation &encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Create a uniformly distributed random polynomial + /// \details Create a random polynomial uniformly distributed over all polynomials with degree less than bitcount + PolynomialMod2(RandomNumberGenerator &rng, size_t bitcount) + {Randomize(rng, bitcount);} + + /// \brief Provides x^i + /// \return x^i + static PolynomialMod2 CRYPTOPP_API Monomial(size_t i); + /// \brief Provides x^t0 + x^t1 + x^t2 + /// \return x^t0 + x^t1 + x^t2 + static PolynomialMod2 CRYPTOPP_API Trinomial(size_t t0, size_t t1, size_t t2); + /// \brief Provides x^t0 + x^t1 + x^t2 + x^t3 + x^t4 + /// \return x^t0 + x^t1 + x^t2 + x^t3 + x^t4 + static PolynomialMod2 CRYPTOPP_API Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4); + /// \brief Provides x^(n-1) + ... + x + 1 + /// \return x^(n-1) + ... + x + 1 + static PolynomialMod2 CRYPTOPP_API AllOnes(size_t n); + + /// \brief The Zero polinomial + /// \return the zero polynomial + static const PolynomialMod2 & CRYPTOPP_API Zero(); + /// \brief The One polinomial + /// \return the one polynomial + static const PolynomialMod2 & CRYPTOPP_API One(); + //@} + + /// \name ENCODE/DECODE + //@{ + /// minimum number of bytes to encode this polynomial + /*! MinEncodedSize of 0 is 1 */ + unsigned int MinEncodedSize() const {return STDMAX(1U, ByteCount());} + + /// encode in big-endian format + /// \details if outputLen < MinEncodedSize, the most significant bytes will be dropped + /// if outputLen > MinEncodedSize, the most significant bytes will be padded + void Encode(byte *output, size_t outputLen) const; + /// + void Encode(BufferedTransformation &bt, size_t outputLen) const; + + /// + void Decode(const byte *input, size_t inputLen); + /// + //* Precondition: bt.MaxRetrievable() >= inputLen + void Decode(BufferedTransformation &bt, size_t inputLen); + + /// encode value as big-endian octet string + void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; + /// decode value as big-endian octet string + void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length); + //@} + + /// \name ACCESSORS + //@{ + /// number of significant bits = Degree() + 1 + unsigned int BitCount() const; + /// number of significant bytes = ceiling(BitCount()/8) + unsigned int ByteCount() const; + /// number of significant words = ceiling(ByteCount()/sizeof(word)) + unsigned int WordCount() const; + + /// return the n-th bit, n=0 being the least significant bit + bool GetBit(size_t n) const {return GetCoefficient(n)!=0;} + /// return the n-th byte + byte GetByte(size_t n) const; + + /// the zero polynomial will return a degree of -1 + signed int Degree() const {return (signed int)(BitCount()-1U);} + /// degree + 1 + unsigned int CoefficientCount() const {return BitCount();} + /// return coefficient for x^i + int GetCoefficient(size_t i) const + {return (i/WORD_BITS < reg.size()) ? int(reg[i/WORD_BITS] >> (i % WORD_BITS)) & 1 : 0;} + /// return coefficient for x^i + int operator[](unsigned int i) const {return GetCoefficient(i);} + + /// + bool IsZero() const {return !*this;} + /// + bool Equals(const PolynomialMod2 &rhs) const; + //@} + + /// \name MANIPULATORS + //@{ + /// + PolynomialMod2& operator=(const PolynomialMod2& t); + /// + PolynomialMod2& operator&=(const PolynomialMod2& t); + /// + PolynomialMod2& operator^=(const PolynomialMod2& t); + /// + PolynomialMod2& operator+=(const PolynomialMod2& t) {return *this ^= t;} + /// + PolynomialMod2& operator-=(const PolynomialMod2& t) {return *this ^= t;} + /// + PolynomialMod2& operator*=(const PolynomialMod2& t); + /// + PolynomialMod2& operator/=(const PolynomialMod2& t); + /// + PolynomialMod2& operator%=(const PolynomialMod2& t); + /// + PolynomialMod2& operator<<=(unsigned int); + /// + PolynomialMod2& operator>>=(unsigned int); + + /// + void Randomize(RandomNumberGenerator &rng, size_t bitcount); + + /// + void SetBit(size_t i, int value = 1); + /// set the n-th byte to value + void SetByte(size_t n, byte value); + + /// + void SetCoefficient(size_t i, int value) {SetBit(i, value);} + + /// + void swap(PolynomialMod2 &a) {reg.swap(a.reg);} + //@} + + /// \name UNARY OPERATORS + //@{ + /// + bool operator!() const; + /// + PolynomialMod2 operator+() const {return *this;} + /// + PolynomialMod2 operator-() const {return *this;} + //@} + + /// \name BINARY OPERATORS + //@{ + /// + PolynomialMod2 And(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Xor(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Plus(const PolynomialMod2 &b) const {return Xor(b);} + /// + PolynomialMod2 Minus(const PolynomialMod2 &b) const {return Xor(b);} + /// + PolynomialMod2 Times(const PolynomialMod2 &b) const; + /// + PolynomialMod2 DividedBy(const PolynomialMod2 &b) const; + /// + PolynomialMod2 Modulo(const PolynomialMod2 &b) const; + + /// + PolynomialMod2 operator>>(unsigned int n) const; + /// + PolynomialMod2 operator<<(unsigned int n) const; + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// sum modulo 2 of all coefficients + unsigned int Parity() const; + + /// check for irreducibility + bool IsIrreducible() const; + + /// is always zero since we're working modulo 2 + PolynomialMod2 Doubled() const {return Zero();} + /// + PolynomialMod2 Squared() const; + + /// only 1 is a unit + bool IsUnit() const {return Equals(One());} + /// return inverse if *this is a unit, otherwise return 0 + PolynomialMod2 MultiplicativeInverse() const {return IsUnit() ? One() : Zero();} + + /// greatest common divisor + static PolynomialMod2 CRYPTOPP_API Gcd(const PolynomialMod2 &a, const PolynomialMod2 &n); + /// calculate multiplicative inverse of *this mod n + PolynomialMod2 InverseMod(const PolynomialMod2 &) const; + + /// calculate r and q such that (a == d*q + r) && (deg(r) < deg(d)) + static void CRYPTOPP_API Divide(PolynomialMod2 &r, PolynomialMod2 &q, const PolynomialMod2 &a, const PolynomialMod2 &d); + //@} + + /// \name INPUT/OUTPUT + //@{ + /// + friend std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a); + //@} + +private: + friend class GF2NT; + friend class GF2NT233; + + SecWordBlock reg; +}; + +/// +inline bool operator==(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Equals(b);} +/// +inline bool operator!=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return !(a==b);} +/// compares degree +inline bool operator> (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() > b.Degree();} +/// compares degree +inline bool operator>=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() >= b.Degree();} +/// compares degree +inline bool operator< (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() < b.Degree();} +/// compares degree +inline bool operator<=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) +{return a.Degree() <= b.Degree();} +/// +inline CryptoPP::PolynomialMod2 operator&(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.And(b);} +/// +inline CryptoPP::PolynomialMod2 operator^(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Xor(b);} +/// +inline CryptoPP::PolynomialMod2 operator+(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Plus(b);} +/// +inline CryptoPP::PolynomialMod2 operator-(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Minus(b);} +/// +inline CryptoPP::PolynomialMod2 operator*(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Times(b);} +/// +inline CryptoPP::PolynomialMod2 operator/(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.DividedBy(b);} +/// +inline CryptoPP::PolynomialMod2 operator%(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Modulo(b);} + +// CodeWarrior 8 workaround: put these template instantiations after overloaded operator declarations, +// but before the use of QuotientRing > for VC .NET 2003 +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain; +CRYPTOPP_DLL_TEMPLATE_CLASS EuclideanDomainOf; +CRYPTOPP_DLL_TEMPLATE_CLASS QuotientRing >; + +/// \brief GF(2^n) with Polynomial Basis +class CRYPTOPP_DLL GF2NP : public QuotientRing > +{ +public: + GF2NP(const PolynomialMod2 &modulus); + + virtual GF2NP * Clone() const {return new GF2NP(*this);} + virtual void DEREncode(BufferedTransformation &bt) const + {CRYPTOPP_UNUSED(bt); CRYPTOPP_ASSERT(false);} // no ASN.1 syntax yet for general polynomial basis + + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + bool Equal(const Element &a, const Element &b) const + {CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree() && b.Degree() < m_modulus.Degree()); return a.Equals(b);} + + bool IsUnit(const Element &a) const + {CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree()); return !!a;} + + unsigned int MaxElementBitLength() const + {return m;} + + unsigned int MaxElementByteLength() const + {return (unsigned int)BitsToBytes(MaxElementBitLength());} + + Element SquareRoot(const Element &a) const; + + Element HalfTrace(const Element &a) const; + + // returns z such that z^2 + z == a + Element SolveQuadraticEquation(const Element &a) const; + +protected: + unsigned int m; +}; + +/// \brief GF(2^n) with Trinomial Basis +class CRYPTOPP_DLL GF2NT : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2 + GF2NT(unsigned int t0, unsigned int t1, unsigned int t2); + + GF2NP * Clone() const {return new GF2NT(*this);} + void DEREncode(BufferedTransformation &bt) const; + + const Element& Multiply(const Element &a, const Element &b) const; + + const Element& Square(const Element &a) const + {return Reduced(a.Squared());} + + const Element& MultiplicativeInverse(const Element &a) const; + +protected: + const Element& Reduced(const Element &a) const; + + unsigned int t0, t1; + mutable PolynomialMod2 result; +}; + +/// \brief GF(2^n) for b233 and k233 +/// \details GF2NT233 is a specialization of GF2NT that provides Multiply() +/// and Square() operations when carryless multiplies is available. +class CRYPTOPP_DLL GF2NT233 : public GF2NT +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2 + GF2NT233(unsigned int t0, unsigned int t1, unsigned int t2); + + GF2NP * Clone() const {return new GF2NT233(*this);} + + const Element& Multiply(const Element &a, const Element &b) const; + + const Element& Square(const Element &a) const; +}; + +/// \brief GF(2^n) with Pentanomial Basis +class CRYPTOPP_DLL GF2NPP : public GF2NP +{ +public: + // polynomial modulus = x^t0 + x^t1 + x^t2 + x^t3 + x^t4, t0 > t1 > t2 > t3 > t4 + GF2NPP(unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4) + : GF2NP(PolynomialMod2::Pentanomial(t0, t1, t2, t3, t4)), t1(t1), t2(t2), t3(t3) {} + + GF2NP * Clone() const {return new GF2NPP(*this);} + void DEREncode(BufferedTransformation &bt) const; + +private: + unsigned int t1, t2, t3; +}; + +// construct new GF2NP from the ASN.1 sequence Characteristic-two +CRYPTOPP_DLL GF2NP * CRYPTOPP_API BERDecodeGF2NP(BufferedTransformation &bt); + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::PolynomialMod2 &a, CryptoPP::PolynomialMod2 &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/gf2n_simd.cpp b/extension/third_party/cryptopp/gf2n_simd.cpp new file mode 100644 index 00000000..aac401ce --- /dev/null +++ b/extension/third_party/cryptopp/gf2n_simd.cpp @@ -0,0 +1,614 @@ +// gf2n_simd.cpp - written and placed in the public domain by Jeffrey Walton +// Also based on PCLMULQDQ code by Jankowski, Laurent and +// O'Mahony from Intel (see reference below). +// +// This source file uses intrinsics and built-ins to gain access to +// CLMUL, ARMv8a, and Power8 instructions. A separate source file is +// needed because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. +// +// Several speedups were taken from Intel Polynomial Multiplication +// Instruction and its Usage for Elliptic Curve Cryptography, by +// Krzysztof Jankowski, Pierre Laurent and Aidan O'Mahony, +// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/polynomial-multiplication-instructions-paper.pdf +// There may be more speedups available, see https://eprint.iacr.org/2011/589.pdf. +// The IACR paper performs some optimizations that the compiler is +// expected to perform, like Common Subexpression Elimination to save +// on variables (among others). Note that the compiler may miss the +// optimization so the IACR paper is useful. However, the code is GPL3 +// and toxic for some users of the library... + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "gf2n.h" + +#if (CRYPTOPP_CLMUL_AVAILABLE) +# include +# include +#endif + +#if (CRYPTOPP_ARM_PMULL_AVAILABLE) +# include "arm_simd.h" +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char GF2N_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +// ************************** ARMv8 ************************** // + +using CryptoPP::word; + +#if (CRYPTOPP_ARM_PMULL_AVAILABLE) + +// c1c0 = a * b +inline void +F2N_Multiply_128x128_ARMv8(uint64x2_t& c1, uint64x2_t& c0, const uint64x2_t& a, const uint64x2_t& b) +{ + uint64x2_t t1, t2, z0={0}; + + c0 = PMULL_00(a, b); + c1 = PMULL_11(a, b); + t1 = vmovq_n_u64(vgetq_lane_u64(a, 1)); + t1 = veorq_u64(a, t1); + t2 = vmovq_n_u64(vgetq_lane_u64(b, 1)); + t2 = veorq_u64(b, t2); + t1 = PMULL_00(t1, t2); + t1 = veorq_u64(c0, t1); + t1 = veorq_u64(c1, t1); + t2 = t1; + t1 = vextq_u64(z0, t1, 1); + t2 = vextq_u64(t2, z0, 1); + c0 = veorq_u64(c0, t1); + c1 = veorq_u64(c1, t2); +} + +// c3c2c1c0 = a1a0 * b1b0 +inline void +F2N_Multiply_256x256_ARMv8(uint64x2_t& c3, uint64x2_t& c2, uint64x2_t& c1, uint64x2_t& c0, + const uint64x2_t& b1, const uint64x2_t& b0, const uint64x2_t& a1, const uint64x2_t& a0) +{ + uint64x2_t c4, c5; + uint64x2_t x0=a0, x1=a1, y0=b0, y1=b1; + + F2N_Multiply_128x128_ARMv8(c1, c0, x0, y0); + F2N_Multiply_128x128_ARMv8(c3, c2, x1, y1); + + x0 = veorq_u64(x0, x1); + y0 = veorq_u64(y0, y1); + + F2N_Multiply_128x128_ARMv8(c5, c4, x0, y0); + + c4 = veorq_u64(c4, c0); + c4 = veorq_u64(c4, c2); + c5 = veorq_u64(c5, c1); + c5 = veorq_u64(c5, c3); + c1 = veorq_u64(c1, c4); + c2 = veorq_u64(c2, c5); +} + +// c3c2c1c0 = a1a0 * a1a0 +inline void +F2N_Square_256_ARMv8(uint64x2_t& c3, uint64x2_t& c2, uint64x2_t& c1, + uint64x2_t& c0, const uint64x2_t& a1, const uint64x2_t& a0) +{ + c0 = PMULL_00(a0, a0); + c1 = PMULL_11(a0, a0); + c2 = PMULL_00(a1, a1); + c3 = PMULL_11(a1, a1); +} + +// x = (x << n), z = 0 +template +inline uint64x2_t ShiftLeft128_ARMv8(uint64x2_t x) +{ + uint64x2_t u=x, v, z={0}; + x = vshlq_n_u64(x, N); + u = vshrq_n_u64(u, (64-N)); + v = vcombine_u64(vget_low_u64(z), vget_low_u64(u)); + x = vorrq_u64(x, v); + return x; +} + +// c1c0 = c3c2c1c0 MOD p. This is a Barrett reduction. Reading at +// Intel paper or https://github.com/antonblanchard/crc32-vpmsum. +inline void +GF2NT_233_Reduce_ARMv8(uint64x2_t& c3, uint64x2_t& c2, uint64x2_t& c1, uint64x2_t& c0) +{ + const unsigned int mask[4] = { + 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff, + }; + + uint64x2_t b3, b2, b1, /*b0,*/ a1, a0, m0, z0={0}; + m0 = vreinterpretq_u64_u32(vld1q_u32(mask)); + b1 = c1; a1 = c1; + a0 = vcombine_u64(vget_low_u64(c1), vget_low_u64(z0)); + a1 = vshlq_n_u64(a1, 23); + a1 = vshrq_n_u64(a1, 23); + c1 = vorrq_u64(a1, a0); + b2 = vshrq_n_u64(c2, (64-23)); + c3 = ShiftLeft128_ARMv8<23>(c3); + a0 = vcombine_u64(vget_high_u64(b2), vget_high_u64(z0)); + c3 = vorrq_u64(c3, a0); + b1 = vshrq_n_u64(b1, (64-23)); + c2 = ShiftLeft128_ARMv8<23>(c2); + a0 = vcombine_u64(vget_high_u64(b1), vget_high_u64(z0)); + c2 = vorrq_u64(c2, a0); + b3 = c3; + b2 = vshrq_n_u64(c2, (64-10)); + b3 = ShiftLeft128_ARMv8<10>(b3); + a0 = vcombine_u64(vget_high_u64(b2), vget_high_u64(z0)); + b3 = vorrq_u64(b3, a0); + a0 = vcombine_u64(vget_high_u64(c3), vget_high_u64(z0)); + b3 = veorq_u64(b3, a0); + b1 = vshrq_n_u64(b3, (64-23)); + b3 = ShiftLeft128_ARMv8<23>(b3); + b3 = vcombine_u64(vget_high_u64(b3), vget_high_u64(z0)); + b3 = vorrq_u64(b3, b1); + c2 = veorq_u64(c2, b3); + b3 = c3; + b2 = vshrq_n_u64(c2, (64-10)); + b3 = ShiftLeft128_ARMv8<10>(b3); + b2 = vcombine_u64(vget_high_u64(b2), vget_high_u64(z0)); + b3 = vorrq_u64(b3, b2); + b2 = c2; + b2 = ShiftLeft128_ARMv8<10>(b2); + a0 = vcombine_u64(vget_low_u64(z0), vget_low_u64(b2)); + c2 = veorq_u64(c2, a0); + a0 = vcombine_u64(vget_low_u64(z0), vget_low_u64(b3)); + a1 = vcombine_u64(vget_high_u64(b2), vget_high_u64(z0)); + a0 = vorrq_u64(a0, a1); + c3 = veorq_u64(c3, a0); + c0 = veorq_u64(c0, c2); + c1 = veorq_u64(c1, c3); + c1 = vandq_u64(c1, m0); +} + +#endif + +// ************************** SSE ************************** // + +#if (CRYPTOPP_CLMUL_AVAILABLE) + +using CryptoPP::word; + +// c1c0 = a * b +inline void +F2N_Multiply_128x128_CLMUL(__m128i& c1, __m128i& c0, const __m128i& a, const __m128i& b) +{ + __m128i t1, t2; + + c0 = _mm_clmulepi64_si128(a, b, 0x00); + c1 = _mm_clmulepi64_si128(a, b, 0x11); + t1 = _mm_shuffle_epi32(a, 0xEE); + t1 = _mm_xor_si128(a, t1); + t2 = _mm_shuffle_epi32(b, 0xEE); + t2 = _mm_xor_si128(b, t2); + t1 = _mm_clmulepi64_si128(t1, t2, 0x00); + t1 = _mm_xor_si128(c0, t1); + t1 = _mm_xor_si128(c1, t1); + t2 = t1; + t1 = _mm_slli_si128(t1, 8); + t2 = _mm_srli_si128(t2, 8); + c0 = _mm_xor_si128(c0, t1); + c1 = _mm_xor_si128(c1, t2); +} + +// c3c2c1c0 = a1a0 * b1b0 +inline void +F2N_Multiply_256x256_CLMUL(__m128i& c3, __m128i& c2, __m128i& c1, __m128i& c0, + const __m128i& b1, const __m128i& b0, const __m128i& a1, const __m128i& a0) +{ + __m128i c4, c5; + __m128i x0=a0, x1=a1, y0=b0, y1=b1; + + F2N_Multiply_128x128_CLMUL(c1, c0, x0, y0); + F2N_Multiply_128x128_CLMUL(c3, c2, x1, y1); + + x0 = _mm_xor_si128(x0, x1); + y0 = _mm_xor_si128(y0, y1); + + F2N_Multiply_128x128_CLMUL(c5, c4, x0, y0); + + c4 = _mm_xor_si128(c4, c0); + c4 = _mm_xor_si128(c4, c2); + c5 = _mm_xor_si128(c5, c1); + c5 = _mm_xor_si128(c5, c3); + c1 = _mm_xor_si128(c1, c4); + c2 = _mm_xor_si128(c2, c5); +} + +// c3c2c1c0 = a1a0 * a1a0 +inline void +F2N_Square_256_CLMUL(__m128i& c3, __m128i& c2, __m128i& c1, + __m128i& c0, const __m128i& a1, const __m128i& a0) +{ + c0 = _mm_clmulepi64_si128(a0, a0, 0x00); + c1 = _mm_clmulepi64_si128(a0, a0, 0x11); + c2 = _mm_clmulepi64_si128(a1, a1, 0x00); + c3 = _mm_clmulepi64_si128(a1, a1, 0x11); +} + +// x = (x << n), z = 0 +template +inline __m128i ShiftLeft128_SSE(__m128i x, const __m128i& z) +{ + __m128i u=x, v; + x = _mm_slli_epi64(x, N); + u = _mm_srli_epi64(u, (64-N)); + v = _mm_unpacklo_epi64(z, u); + x = _mm_or_si128(x, v); + return x; +} + +// c1c0 = c3c2c1c0 MOD p. This is a Barrett reduction. Reading at +// Intel paper or https://github.com/antonblanchard/crc32-vpmsum. +inline void +GF2NT_233_Reduce_CLMUL(__m128i& c3, __m128i& c2, __m128i& c1, __m128i& c0) +{ + const unsigned int m[4] = { + 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff + }; + + __m128i b3, b2, b1, /*b0,*/ a1, a0, m0, z0; + m0 = _mm_set_epi32(m[3], m[2], m[1], m[0]); + z0 = _mm_setzero_si128(); + b1 = c1; a1 = c1; + a0 = _mm_move_epi64(c1); + a1 = _mm_slli_epi64(a1, 23); + a1 = _mm_srli_epi64(a1, 23); + c1 = _mm_or_si128(a1, a0); + b2 = _mm_srli_epi64(c2, (64-23)); + c3 = ShiftLeft128_SSE<23>(c3, z0); + a0 = _mm_unpackhi_epi64(b2, z0); + c3 = _mm_or_si128(c3, a0); + b1 = _mm_srli_epi64(b1, (64-23)); + c2 = ShiftLeft128_SSE<23>(c2, z0); + a0 = _mm_unpackhi_epi64(b1, z0); + c2 = _mm_or_si128(c2, a0); + b3 = c3; + b2 = _mm_srli_epi64(c2, (64-10)); + b3 = ShiftLeft128_SSE<10>(b3, z0); + a0 = _mm_unpackhi_epi64(b2, z0); + b3 = _mm_or_si128(b3, a0); + a0 = _mm_unpackhi_epi64(c3, z0); + b3 = _mm_xor_si128(b3, a0); + b1 = _mm_srli_epi64(b3, (64-23)); + b3 = ShiftLeft128_SSE<23>(b3, z0); + b3 = _mm_unpackhi_epi64(b3, z0); + b3 = _mm_or_si128(b3, b1); + c2 = _mm_xor_si128(c2, b3); + b3 = c3; + b2 = _mm_srli_epi64(c2, (64-10)); + b3 = ShiftLeft128_SSE<10>(b3, z0); + b2 = _mm_unpackhi_epi64(b2, z0); + b3 = _mm_or_si128(b3, b2); + b2 = c2; + b2 = ShiftLeft128_SSE<10>(b2, z0); + a0 = _mm_unpacklo_epi64(z0, b2); + c2 = _mm_xor_si128(c2, a0); + a0 = _mm_unpacklo_epi64(z0, b3); + a1 = _mm_unpackhi_epi64(b2, z0); + a0 = _mm_or_si128(a0, a1); + c3 = _mm_xor_si128(c3, a0); + c0 = _mm_xor_si128(c0, c2); + c1 = _mm_xor_si128(c1, c3); + c1 = _mm_and_si128(c1, m0); +} + +#endif + +// ************************* Power8 ************************* // + +#if (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 + +using CryptoPP::byte; +using CryptoPP::word; +using CryptoPP::uint8x16_p; +using CryptoPP::uint64x2_p; + +using CryptoPP::VecLoad; +using CryptoPP::VecStore; + +using CryptoPP::VecOr; +using CryptoPP::VecXor; +using CryptoPP::VecAnd; + +using CryptoPP::VecPermute; +using CryptoPP::VecMergeLow; +using CryptoPP::VecMergeHigh; +using CryptoPP::VecShiftLeft; +using CryptoPP::VecShiftRight; + +using CryptoPP::VecIntelMultiply00; +using CryptoPP::VecIntelMultiply11; + +// c1c0 = a * b +inline void +F2N_Multiply_128x128_POWER8(uint64x2_p& c1, uint64x2_p& c0, const uint64x2_p& a, const uint64x2_p& b) +{ + uint64x2_p t1, t2; + const uint64x2_p z0={0}; + + c0 = VecIntelMultiply00(a, b); + c1 = VecIntelMultiply11(a, b); + t1 = VecMergeLow(a, a); + t1 = VecXor(a, t1); + t2 = VecMergeLow(b, b); + t2 = VecXor(b, t2); + t1 = VecIntelMultiply00(t1, t2); + t1 = VecXor(c0, t1); + t1 = VecXor(c1, t1); + t2 = t1; + t1 = VecMergeHigh(z0, t1); + t2 = VecMergeLow(t2, z0); + c0 = VecXor(c0, t1); + c1 = VecXor(c1, t2); +} + +// c3c2c1c0 = a1a0 * b1b0 +inline void +F2N_Multiply_256x256_POWER8(uint64x2_p& c3, uint64x2_p& c2, uint64x2_p& c1, uint64x2_p& c0, + const uint64x2_p& b1, const uint64x2_p& b0, const uint64x2_p& a1, const uint64x2_p& a0) +{ + uint64x2_p c4, c5; + uint64x2_p x0=a0, x1=a1, y0=b0, y1=b1; + + F2N_Multiply_128x128_POWER8(c1, c0, x0, y0); + F2N_Multiply_128x128_POWER8(c3, c2, x1, y1); + + x0 = VecXor(x0, x1); + y0 = VecXor(y0, y1); + + F2N_Multiply_128x128_POWER8(c5, c4, x0, y0); + + c4 = VecXor(c4, c0); + c4 = VecXor(c4, c2); + c5 = VecXor(c5, c1); + c5 = VecXor(c5, c3); + c1 = VecXor(c1, c4); + c2 = VecXor(c2, c5); +} + +// c3c2c1c0 = a1a0 * a1a0 +inline void +F2N_Square_256_POWER8(uint64x2_p& c3, uint64x2_p& c2, uint64x2_p& c1, + uint64x2_p& c0, const uint64x2_p& a1, const uint64x2_p& a0) +{ + c0 = VecIntelMultiply00(a0, a0); + c1 = VecIntelMultiply11(a0, a0); + c2 = VecIntelMultiply00(a1, a1); + c3 = VecIntelMultiply11(a1, a1); +} + +// x = (x << n), z = 0 +template +inline uint64x2_p ShiftLeft128_POWER8(uint64x2_p x) +{ + uint64x2_p u=x, v; + const uint64x2_p z={0}; + + x = VecShiftLeft(x); + u = VecShiftRight<64-N>(u); + v = VecMergeHigh(z, u); + x = VecOr(x, v); + return x; +} + +// c1c0 = c3c2c1c0 MOD p. This is a Barrett reduction. Reading at +// Intel paper or https://github.com/antonblanchard/crc32-vpmsum. +inline void +GF2NT_233_Reduce_POWER8(uint64x2_p& c3, uint64x2_p& c2, uint64x2_p& c1, uint64x2_p& c0) +{ + const uint64_t mod[] = {W64LIT(0xffffffffffffffff), W64LIT(0x01ffffffffff)}; + const uint64x2_p m0 = (uint64x2_p)VecLoad(mod); + + uint64x2_p b3, b2, b1, /*b0,*/ a1, a0; + const uint64x2_p z0={0}; + + b1 = c1; a1 = c1; + a0 = VecMergeHigh(c1, z0); + a1 = VecShiftLeft<23>(a1); + a1 = VecShiftRight<23>(a1); + c1 = VecOr(a1, a0); + b2 = VecShiftRight<64-23>(c2); + c3 = ShiftLeft128_POWER8<23>(c3); + a0 = VecMergeLow(b2, z0); + c3 = VecOr(c3, a0); + b1 = VecShiftRight<64-23>(b1); + c2 = ShiftLeft128_POWER8<23>(c2); + a0 = VecMergeLow(b1, z0); + c2 = VecOr(c2, a0); + b3 = c3; + b2 = VecShiftRight<64-10>(c2); + b3 = ShiftLeft128_POWER8<10>(b3); + a0 = VecMergeLow(b2, z0); + b3 = VecOr(b3, a0); + a0 = VecMergeLow(c3, z0); + b3 = VecXor(b3, a0); + b1 = VecShiftRight<64-23>(b3); + b3 = ShiftLeft128_POWER8<23>(b3); + b3 = VecMergeLow(b3, z0); + b3 = VecOr(b3, b1); + c2 = VecXor(c2, b3); + b3 = c3; + b2 = VecShiftRight<64-10>(c2); + b3 = ShiftLeft128_POWER8<10>(b3); + b2 = VecMergeLow(b2, z0); + b3 = VecOr(b3, b2); + b2 = c2; + b2 = ShiftLeft128_POWER8<10>(b2); + a0 = VecMergeHigh(z0, b2); + c2 = VecXor(c2, a0); + a0 = VecMergeHigh(z0, b3); + a1 = VecMergeLow(b2, z0); + a0 = VecOr(a0, a1); + c3 = VecXor(c3, a0); + c0 = VecXor(c0, c2); + c1 = VecXor(c1, c3); + c1 = VecAnd(c1, m0); +} + +#endif + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_CLMUL_AVAILABLE) + +void +GF2NT_233_Multiply_Reduce_CLMUL(const word* pA, const word* pB, word* pC) +{ + enum {S=sizeof(__m128i)/sizeof(word)}; + __m128i a0 = _mm_loadu_si128(reinterpret_cast(pA+0*S)); + __m128i a1 = _mm_loadu_si128(reinterpret_cast(pA+1*S)); + __m128i b0 = _mm_loadu_si128(reinterpret_cast(pB+0*S)); + __m128i b1 = _mm_loadu_si128(reinterpret_cast(pB+1*S)); + + __m128i c0, c1, c2, c3; + F2N_Multiply_256x256_CLMUL(c3, c2, c1, c0, a1, a0, b1, b0); + GF2NT_233_Reduce_CLMUL(c3, c2, c1, c0); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(pC+0*S), c0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(pC+1*S), c1); +} + +void +GF2NT_233_Square_Reduce_CLMUL(const word* pA, word* pC) +{ + enum {S=sizeof(__m128i)/sizeof(word)}; + __m128i a0 = _mm_loadu_si128(reinterpret_cast(pA+0*S)); + __m128i a1 = _mm_loadu_si128(reinterpret_cast(pA+1*S)); + + __m128i c0, c1, c2, c3; + F2N_Square_256_CLMUL(c3, c2, c1, c0, a1, a0); + GF2NT_233_Reduce_CLMUL(c3, c2, c1, c0); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(pC+0*S), c0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(pC+1*S), c1); +} + +#elif (CRYPTOPP_ARM_PMULL_AVAILABLE) + +void +GF2NT_233_Multiply_Reduce_ARMv8(const word* pA, const word* pB, word* pC) +{ + // word is either 32-bit or 64-bit, depending on the platform. + // Load using a 32-bit pointer to avoid possible alignment issues. + const uint32_t* pAA = reinterpret_cast(pA); + const uint32_t* pBB = reinterpret_cast(pB); + + uint64x2_t a0 = vreinterpretq_u64_u32(vld1q_u32(pAA+0)); + uint64x2_t a1 = vreinterpretq_u64_u32(vld1q_u32(pAA+4)); + uint64x2_t b0 = vreinterpretq_u64_u32(vld1q_u32(pBB+0)); + uint64x2_t b1 = vreinterpretq_u64_u32(vld1q_u32(pBB+4)); + + uint64x2_t c0, c1, c2, c3; + F2N_Multiply_256x256_ARMv8(c3, c2, c1, c0, a1, a0, b1, b0); + GF2NT_233_Reduce_ARMv8(c3, c2, c1, c0); + + uint32_t* pCC = reinterpret_cast(pC); + vst1q_u32(pCC+0, vreinterpretq_u32_u64(c0)); + vst1q_u32(pCC+4, vreinterpretq_u32_u64(c1)); +} + +void +GF2NT_233_Square_Reduce_ARMv8(const word* pA, word* pC) +{ + // word is either 32-bit or 64-bit, depending on the platform. + // Load using a 32-bit pointer to avoid possible alignment issues. + const uint32_t* pAA = reinterpret_cast(pA); + uint64x2_t a0 = vreinterpretq_u64_u32(vld1q_u32(pAA+0)); + uint64x2_t a1 = vreinterpretq_u64_u32(vld1q_u32(pAA+4)); + + uint64x2_t c0, c1, c2, c3; + F2N_Square_256_ARMv8(c3, c2, c1, c0, a1, a0); + GF2NT_233_Reduce_ARMv8(c3, c2, c1, c0); + + uint32_t* pCC = reinterpret_cast(pC); + vst1q_u32(pCC+0, vreinterpretq_u32_u64(c0)); + vst1q_u32(pCC+4, vreinterpretq_u32_u64(c1)); +} + +#elif (CRYPTOPP_POWER8_VMULL_AVAILABLE) && 0 + +void +GF2NT_233_Multiply_Reduce_POWER8(const word* pA, const word* pB, word* pC) +{ + // word is either 32-bit or 64-bit, depending on the platform. + // Load using a byte pointer to avoid possible alignment issues. + const byte* pAA = reinterpret_cast(pA); + const byte* pBB = reinterpret_cast(pB); + + uint64x2_p a0 = (uint64x2_p)VecLoad(pAA+0); + uint64x2_p a1 = (uint64x2_p)VecLoad(pAA+16); + uint64x2_p b0 = (uint64x2_p)VecLoad(pBB+0); + uint64x2_p b1 = (uint64x2_p)VecLoad(pBB+16); + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8_t mb[] = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + const uint8x16_p m = (uint8x16_p)VecLoad(mb); + a0 = VecPermute(a0, m); + a1 = VecPermute(a1, m); + b0 = VecPermute(b0, m); + b1 = VecPermute(b1, m); +#endif + + uint64x2_p c0, c1, c2, c3; + F2N_Multiply_256x256_POWER8(c3, c2, c1, c0, a1, a0, b1, b0); + GF2NT_233_Reduce_POWER8(c3, c2, c1, c0); + +#if (CRYPTOPP_BIG_ENDIAN) + c0 = VecPermute(c0, m); + c1 = VecPermute(c1, m); +#endif + + byte* pCC = reinterpret_cast(pC); + VecStore(c0, pCC+0); + VecStore(c1, pCC+16); +} + +void +GF2NT_233_Square_Reduce_POWER8(const word* pA, word* pC) +{ + // word is either 32-bit or 64-bit, depending on the platform. + // Load using a byte pointer to avoid possible alignment issues. + const byte* pAA = reinterpret_cast(pA); + uint64x2_p a0 = (uint64x2_p)VecLoad(pAA+0); + uint64x2_p a1 = (uint64x2_p)VecLoad(pAA+16); + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8_t mb[] = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + const uint8x16_p m = (uint8x16_p)VecLoad(mb); + a0 = VecPermute(a0, m); + a1 = VecPermute(a1, m); +#endif + + uint64x2_p c0, c1, c2, c3; + F2N_Square_256_POWER8(c3, c2, c1, c0, a1, a0); + GF2NT_233_Reduce_POWER8(c3, c2, c1, c0); + +#if (CRYPTOPP_BIG_ENDIAN) + c0 = VecPermute(c0, m); + c1 = VecPermute(c1, m); +#endif + + byte* pCC = reinterpret_cast(pC); + VecStore(c0, pCC+0); + VecStore(c1, pCC+16); +} + +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/gfpcrypt.cpp b/extension/third_party/cryptopp/gfpcrypt.cpp new file mode 100644 index 00000000..4c257cbd --- /dev/null +++ b/extension/third_party/cryptopp/gfpcrypt.cpp @@ -0,0 +1,334 @@ +// dsa.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +// TODO: fix the C4589 warnings +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4189 4589) +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "gfpcrypt.h" +#include "nbtheory.h" +#include "modarith.h" +#include "integer.h" +#include "asn.h" +#include "oids.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void TestInstantiations_gfpcrypt() +{ + GDSA::Signer test; + GDSA::Verifier test1; + DSA::Signer test5(NullRNG(), 100); + DSA::Signer test2(test5); + NR::Signer test3; + NR::Verifier test4; + DLIES<>::Encryptor test6; + DLIES<>::Decryptor test7; +} +#endif + +void DL_GroupParameters_DSA::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + Integer p, q, g; + + if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) + { + q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); + Initialize(p, q, g); + } + else + { + int modulusSize = 2048, defaultSubgroupOrderSize; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + switch (modulusSize) + { + case 1024: + defaultSubgroupOrderSize = 160; + break; + case 2048: + defaultSubgroupOrderSize = 224; + break; + case 3072: + defaultSubgroupOrderSize = 256; + break; + default: + throw InvalidArgument("DSA: not a valid prime length"); + } + + DL_GroupParameters_GFP::GenerateRandom(rng, CombinedNameValuePairs(alg, MakeParameters(Name::SubgroupOrderSize(), defaultSubgroupOrderSize, false))); + } +} + +bool DL_GroupParameters_DSA::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = DL_GroupParameters_GFP::ValidateGroup(rng, level); + CRYPTOPP_ASSERT(pass); + + const int pSize = GetModulus().BitCount(), qSize = GetSubgroupOrder().BitCount(); + pass = pass && ((pSize==1024 && qSize==160) || (pSize==2048 && qSize==224) || (pSize==2048 && qSize==256) || (pSize==3072 && qSize==256)); + CRYPTOPP_ASSERT(pass); + + return pass; +} + +void DL_SignatureMessageEncodingMethod_DSA::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + CRYPTOPP_ASSERT(recoverableMessageLength == 0); + CRYPTOPP_ASSERT(hashIdentifier.second == 0); + + const size_t representativeByteLength = BitsToBytes(representativeBitLength); + const size_t digestSize = hash.DigestSize(); + const size_t paddingLength = SaturatingSubtract(representativeByteLength, digestSize); + + memset(representative, 0, paddingLength); + hash.TruncatedFinal(representative+paddingLength, STDMIN(representativeByteLength, digestSize)); + + if (digestSize*8 > representativeBitLength) + { + Integer h(representative, representativeByteLength); + h >>= representativeByteLength*8 - representativeBitLength; + h.Encode(representative, representativeByteLength); + } +} + +void DL_SignatureMessageEncodingMethod_NR::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + CRYPTOPP_UNUSED(rng);CRYPTOPP_UNUSED(recoverableMessage); CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(hash); CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(messageEmpty); + CRYPTOPP_UNUSED(representative); CRYPTOPP_UNUSED(representativeBitLength); + + CRYPTOPP_ASSERT(recoverableMessageLength == 0); + CRYPTOPP_ASSERT(hashIdentifier.second == 0); + const size_t representativeByteLength = BitsToBytes(representativeBitLength); + const size_t digestSize = hash.DigestSize(); + const size_t paddingLength = SaturatingSubtract(representativeByteLength, digestSize); + + memset(representative, 0, paddingLength); + hash.TruncatedFinal(representative+paddingLength, STDMIN(representativeByteLength, digestSize)); + + if (digestSize*8 >= representativeBitLength) + { + Integer h(representative, representativeByteLength); + h >>= representativeByteLength*8 - representativeBitLength + 1; + h.Encode(representative, representativeByteLength); + } +} + +bool DL_GroupParameters_IntegerBased::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const +{ + const Integer &p = GetModulus(), &q = GetSubgroupOrder(); + bool pass = true; + + CRYPTOPP_ASSERT(p > Integer::One() && p.IsOdd()); + pass = pass && p > Integer::One() && p.IsOdd(); + + CRYPTOPP_ASSERT(q > Integer::One() && q.IsOdd()); + pass = pass && q > Integer::One() && q.IsOdd(); + + if (level >= 1) + { + CRYPTOPP_ASSERT(GetCofactor() > Integer::One()); + CRYPTOPP_ASSERT(GetGroupOrder() % q == Integer::Zero()); + + pass = pass && GetCofactor() > Integer::One() && GetGroupOrder() % q == Integer::Zero(); + } + if (level >= 2) + { + CRYPTOPP_ASSERT(VerifyPrime(rng, q, level-2)); + CRYPTOPP_ASSERT(VerifyPrime(rng, p, level-2)); + + pass = pass && VerifyPrime(rng, q, level-2) && VerifyPrime(rng, p, level-2); + } + + return pass; +} + +bool DL_GroupParameters_IntegerBased::ValidateElement(unsigned int level, const Integer &g, const DL_FixedBasePrecomputation *gpc) const +{ + const Integer &p = GetModulus(), &q = GetSubgroupOrder(); + bool pass = true; + + CRYPTOPP_ASSERT(GetFieldType() == 1 ? g.IsPositive() : g.NotNegative()); + pass = pass && GetFieldType() == 1 ? g.IsPositive() : g.NotNegative(); + + CRYPTOPP_ASSERT(g < p && !IsIdentity(g)); + pass = pass && g < p && !IsIdentity(g); + + if (level >= 1) + { + if (gpc) + { + CRYPTOPP_ASSERT(gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g); + pass = pass && gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g; + } + } + if (level >= 2) + { + if (GetFieldType() == 2) + { + CRYPTOPP_ASSERT(Jacobi(g*g-4, p)==-1); + pass = pass && Jacobi(g*g-4, p)==-1; + } + + // verifying that Lucas((p+1)/2, w, p)==2 is omitted because it's too costly + // and at most 1 bit is leaked if it's false + bool fullValidate = (GetFieldType() == 2 && level >= 3) || !FastSubgroupCheckAvailable(); + + if (fullValidate && pass) + { + Integer gp = gpc ? gpc->Exponentiate(GetGroupPrecomputation(), q) : ExponentiateElement(g, q); + CRYPTOPP_ASSERT(IsIdentity(gp)); + pass = pass && IsIdentity(gp); + } + else if (GetFieldType() == 1) + { + CRYPTOPP_ASSERT(Jacobi(g, p) == 1); + pass = pass && Jacobi(g, p) == 1; + } + } + + return pass; +} + +void DL_GroupParameters_IntegerBased::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + Integer p, q, g; + + if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) + { + q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); + } + else + { + int modulusSize, subgroupOrderSize; + + if (!alg.GetIntValue("ModulusSize", modulusSize)) + modulusSize = alg.GetIntValueWithDefault("KeySize", 2048); + + if (!alg.GetIntValue("SubgroupOrderSize", subgroupOrderSize)) + subgroupOrderSize = GetDefaultSubgroupOrderSize(modulusSize); + + PrimeAndGenerator pg; + pg.Generate(GetFieldType() == 1 ? 1 : -1, rng, modulusSize, subgroupOrderSize); + p = pg.Prime(); + q = pg.SubPrime(); + g = pg.Generator(); + } + + Initialize(p, q, g); +} + +void DL_GroupParameters_IntegerBased::EncodeElement(bool reversible, const Element &element, byte *encoded) const +{ + CRYPTOPP_UNUSED(reversible); + element.Encode(encoded, GetModulus().ByteCount()); +} + +unsigned int DL_GroupParameters_IntegerBased::GetEncodedElementSize(bool reversible) const +{ + CRYPTOPP_UNUSED(reversible); + return GetModulus().ByteCount(); +} + +Integer DL_GroupParameters_IntegerBased::DecodeElement(const byte *encoded, bool checkForGroupMembership) const +{ + CRYPTOPP_UNUSED(checkForGroupMembership); + Integer g(encoded, GetModulus().ByteCount()); + if (!ValidateElement(1, g, NULLPTR)) + throw DL_BadElement(); + return g; +} + +void DL_GroupParameters_IntegerBased::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder parameters(bt); + Integer p(parameters); + Integer q(parameters); + Integer g; + if (parameters.EndReached()) + { + g = q; + q = ComputeGroupOrder(p) / 2; + } + else + g.BERDecode(parameters); + parameters.MessageEnd(); + + SetModulusAndSubgroupGenerator(p, g); + SetSubgroupOrder(q); +} + +void DL_GroupParameters_IntegerBased::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder parameters(bt); + GetModulus().DEREncode(parameters); + m_q.DEREncode(parameters); + GetSubgroupGenerator().DEREncode(parameters); + parameters.MessageEnd(); +} + +bool DL_GroupParameters_IntegerBased::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper >(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus); +} + +void DL_GroupParameters_IntegerBased::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY2(Modulus, SubgroupGenerator) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupOrder) + ; +} + +OID DL_GroupParameters_IntegerBased::GetAlgorithmID() const +{ + return ASN1::id_dsa(); +} + +void DL_GroupParameters_GFP::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + ModularArithmetic ma(GetModulus()); + ma.SimultaneousExponentiate(results, base, exponents, exponentsCount); +} + +DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::MultiplyElements(const Element &a, const Element &b) const +{ + return a_times_b_mod_c(a, b, GetModulus()); +} + +DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const +{ + ModularArithmetic ma(GetModulus()); + return ma.CascadeExponentiate(element1, exponent1, element2, exponent2); +} + +Integer DL_GroupParameters_IntegerBased::GetMaxExponent() const +{ + return STDMIN(GetSubgroupOrder()-1, Integer::Power2(2*DiscreteLogWorkFactor(GetFieldType()*GetModulus().BitCount()))); +} + +unsigned int DL_GroupParameters_IntegerBased::GetDefaultSubgroupOrderSize(unsigned int modulusSize) const +{ + return 2*DiscreteLogWorkFactor(GetFieldType()*modulusSize); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gfpcrypt.h b/extension/third_party/cryptopp/gfpcrypt.h new file mode 100644 index 00000000..ca750fb5 --- /dev/null +++ b/extension/third_party/cryptopp/gfpcrypt.h @@ -0,0 +1,996 @@ +// gfpcrypt.h - originally written and placed in the public domain by Wei Dai +// RFC6979 deterministic signatures added by Douglas Roark +// ECGDSA added by Jeffrey Walton + +/// \file gfpcrypt.h +/// \brief Classes and functions for schemes based on Discrete Logs (DL) over GF(p) + +#ifndef CRYPTOPP_GFPCRYPT_H +#define CRYPTOPP_GFPCRYPT_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4189 4231 4275) +#endif + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "modexppc.h" +#include "algparam.h" +#include "smartptr.h" +#include "sha.h" +#include "asn.h" +#include "hmac.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters; + +/// \brief Integer-based GroupParameters specialization +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBased : public ASN1CryptoMaterial > +{ + typedef DL_GroupParameters_IntegerBased ThisClass; + +public: + virtual ~DL_GroupParameters_IntegerBased() {} + + /// \brief Initialize a group parameters over integers + /// \param params the group parameters + void Initialize(const DL_GroupParameters_IntegerBased ¶ms) + {Initialize(params.GetModulus(), params.GetSubgroupOrder(), params.GetSubgroupGenerator());} + + /// \brief Create a group parameters over integers + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the size of p, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int pbits) + {GenerateRandom(rng, MakeParameters("ModulusSize", (int)pbits));} + + /// \brief Initialize a group parameters over integers + /// \param p the modulus + /// \param g the generator + void Initialize(const Integer &p, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(ComputeGroupOrder(p)/2);} + + /// \brief Initialize a group parameters over integers + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(q);} + + // ASN1Object interface + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Generate a random key + /// \param rng a RandomNumberGenerator to produce keying material + /// \param alg additional initialization parameters + /// \details Recognised NameValuePairs are ModulusSize and + /// SubgroupOrderSize (optional) + /// \throw KeyingErr if a key can't be generated or algorithm parameters + /// are invalid + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + + /// \brief Initialize or reinitialize this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source); + + // DL_GroupParameters + const Integer & GetSubgroupOrder() const {return m_q;} + Integer GetGroupOrder() const {return GetFieldType() == 1 ? GetModulus()-Integer::One() : GetModulus()+Integer::One();} + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Integer &element, const DL_FixedBasePrecomputation *precomp) const; + + /// \brief Determine if subgroup membership check is fast + /// \return true or false + bool FastSubgroupCheckAvailable() const {return GetCofactor() == 2;} + + /// \brief Encodes the element + /// \param reversible flag indicating the encoding format + /// \param element reference to the element to encode + /// \param encoded destination byte array for the encoded element + /// \details EncodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + /// \sa GetEncodedElementSize(), DecodeElement(), Cygwin + /// i386 crash at -O3 + void EncodeElement(bool reversible, const Element &element, byte *encoded) const; + + /// \brief Retrieve the encoded element's size + /// \param reversible flag indicating the encoding format + /// \return encoded element's size, in bytes + /// \details The format of the encoded element varies by the underlying + /// type of the element and the reversible flag. + /// \sa EncodeElement(), DecodeElement() + unsigned int GetEncodedElementSize(bool reversible) const; + + /// \brief Decodes the element + /// \param encoded byte array with the encoded element + /// \param checkForGroupMembership flag indicating if the element should be validated + /// \return Element after decoding + /// \details DecodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + /// \sa GetEncodedElementSize(), EncodeElement() + Integer DecodeElement(const byte *encoded, bool checkForGroupMembership) const; + + /// \brief Converts an element to an Integer + /// \param element the element to convert to an Integer + /// \return Element after converting to an Integer + /// \details ConvertElementToInteger() must be implemented in a derived class. + Integer ConvertElementToInteger(const Element &element) const + {return element;} + + /// \brief Retrieve the maximum exponent for the group + /// \return the maximum exponent for the group + Integer GetMaxExponent() const; + + /// \brief Retrieve the OID of the algorithm + /// \return OID of the algorithm + OID GetAlgorithmID() const; + + /// \brief Retrieve the modulus for the group + /// \return the modulus for the group + virtual const Integer & GetModulus() const =0; + + /// \brief Set group parameters + /// \param p the prime modulus + /// \param g the group generator + virtual void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) =0; + + /// \brief Set subgroup order + /// \param q the subgroup order + void SetSubgroupOrder(const Integer &q) + {m_q = q; ParametersChanged();} + + static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "";} + +protected: + Integer ComputeGroupOrder(const Integer &modulus) const + {return modulus-(GetFieldType() == 1 ? 1 : -1);} + + // GF(p) = 1, GF(p^2) = 2 + virtual int GetFieldType() const =0; + virtual unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const; + +private: + Integer m_q; +}; + +/// \brief Integer-based GroupParameters default implementation +/// \tparam GROUP_PRECOMP group parameters precomputation specialization +/// \tparam BASE_PRECOMP base class precomputation specialization +template > +class CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBasedImpl : public DL_GroupParametersImpl +{ + typedef DL_GroupParameters_IntegerBasedImpl ThisClass; + +public: + typedef typename GROUP_PRECOMP::Element Element; + + virtual ~DL_GroupParameters_IntegerBasedImpl() {} + + // GeneratibleCryptoMaterial interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + {return GetValueHelper(this, name, valueType, pValue).Assignable();} + + void AssignFrom(const NameValuePairs &source) + {AssignFromHelper(this, source);} + + // DL_GroupParameters + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;} + + // IntegerGroupParameters + /// \brief Retrieve the modulus for the group + /// \return the modulus for the group + const Integer & GetModulus() const {return this->m_groupPrecomputation.GetModulus();} + + /// \brief Retrieves a reference to the group generator + /// \return const reference to the group generator + const Integer & GetGenerator() const {return this->m_gpc.GetBase(this->GetGroupPrecomputation());} + + void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) // these have to be set together + {this->m_groupPrecomputation.SetModulus(p); this->m_gpc.SetBase(this->GetGroupPrecomputation(), g); this->ParametersChanged();} + + // non-inherited + bool operator==(const DL_GroupParameters_IntegerBasedImpl &rhs) const + {return GetModulus() == rhs.GetModulus() && GetGenerator() == rhs.GetGenerator() && this->GetSubgroupOrder() == rhs.GetSubgroupOrder();} + bool operator!=(const DL_GroupParameters_IntegerBasedImpl &rhs) const + {return !operator==(rhs);} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_IntegerBasedImpl; + +/// \brief GF(p) group parameters +class CRYPTOPP_DLL DL_GroupParameters_GFP : public DL_GroupParameters_IntegerBasedImpl +{ +public: + virtual ~DL_GroupParameters_GFP() {} + + /// \brief Determines if an element is an identity + /// \param element element to check + /// \return true if the element is an identity, false otherwise + /// \details The identity element or or neutral element is a special element + /// in a group that leaves other elements unchanged when combined with it. + /// \details IsIdentity() must be implemented in a derived class. + bool IsIdentity(const Integer &element) const {return element == Integer::One();} + + /// \brief Exponentiates a base to multiple exponents + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in + /// the exponents array and stores the result at the respective position in + /// the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue).Assignable(); + } + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + +protected: + int GetFieldType() const {return 1;} +}; + +/// \brief GF(p) group parameters that default to safe primes +class CRYPTOPP_DLL DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupParameters_GFP +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + + virtual ~DL_GroupParameters_GFP_DefaultSafePrime() {} + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +/// \brief GDSA algorithm +/// \tparam T FieldElement type or class +template +class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-1363";} + + virtual ~DL_Algorithm_GDSA() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r %= q; + Integer kInv = k.InverseMod(q); + s = (kInv * (x*r + e)) % q; + CRYPTOPP_ASSERT(!!r && !!s); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q || s<1) + return false; + + Integer w = s.InverseMod(q); + Integer u1 = (e * w) % q; + Integer u2 = (r * w) % q; + // verify r == (g^u1 * y^u2 mod p) mod q + return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; + } +}; + +/// \brief DSA signature algorithm based on RFC 6979 +/// \tparam T FieldElement type or class +/// \tparam H HashTransformation derived class +/// \sa RFC 6979, Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +class DL_Algorithm_DSA_RFC6979 : public DL_Algorithm_GDSA, public DeterministicSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-RFC6979";} + + virtual ~DL_Algorithm_DSA_RFC6979() {} + + bool IsProbabilistic() const + {return false;} + bool IsDeterministic() const + {return true;} + + // Deterministic K + Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const + { + static const byte zero = 0, one = 1; + const size_t qlen = q.BitCount(); + const size_t rlen = BitsToBytes(qlen); + + // Step (a) - formatted E(m) + SecByteBlock BH(e.MinEncodedSize()); + e.Encode(BH, BH.size()); + BH = bits2octets(BH, q); + + // Step (a) - private key to byte array + SecByteBlock BX(STDMAX(rlen, x.MinEncodedSize())); + x.Encode(BX, BX.size()); + + // Step (b) + SecByteBlock V(H::DIGESTSIZE); + std::fill(V.begin(), V.begin()+H::DIGESTSIZE, one); + + // Step (c) + SecByteBlock K(H::DIGESTSIZE); + std::fill(K.begin(), K.begin()+H::DIGESTSIZE, zero); + + // Step (d) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (e) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + // Step (f) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&one, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (g) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + Integer k; + SecByteBlock temp(rlen); + for (;;) + { + // We want qlen bits, but we support only hash functions with an output length + // multiple of 8; hence, we will gather rlen bits, i.e., rolen octets. + size_t toff = 0; + while (toff < rlen) + { + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + size_t cc = STDMIN(V.size(), temp.size() - toff); + memcpy_s(temp+toff, temp.size() - toff, V, cc); + toff += cc; + } + + k = bits2int(temp, qlen); + if (k > 0 && k < q) + break; + + // k is not in the proper range; update K and V, and loop. + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.TruncatedFinal(K, K.size()); + + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + } + + return k; + } + +protected: + + Integer bits2int(const SecByteBlock& bits, size_t qlen) const + { + Integer ret(bits, bits.size()); + size_t blen = bits.size()*8; + + if (blen > qlen) + ret >>= blen - qlen; + + return ret; + } + + // RFC 6979 support function. Takes an integer and converts it into bytes that + // are the same length as an elliptic curve's order. + SecByteBlock int2octets(const Integer& val, size_t rlen) const + { + SecByteBlock block(val.MinEncodedSize()); + val.Encode(block, val.MinEncodedSize()); + + if (block.size() == rlen) + return block; + + // The least significant bytes are the ones we need to preserve. + SecByteBlock t(rlen); + if (block.size() > rlen) + { + size_t offset = block.size() - rlen; + std::memcpy(t, block + offset, rlen); + } + else // block.size() < rlen + { + size_t offset = rlen - block.size(); + memset(t, '\x00', offset); + std::memcpy(t + offset, block, rlen - offset); + } + + return t; + } + + // Turn a stream of bits into a set of bytes with the same length as an elliptic + // curve's order. + SecByteBlock bits2octets(const SecByteBlock& in, const Integer& q) const + { + Integer b2 = bits2int(in, q.BitCount()); + Integer b1 = b2 - q; + return int2octets(b1.IsNegative() ? b2 : b1, q.ByteCount()); + } + +private: + mutable H m_hash; + mutable HMAC m_hmac; +}; + +/// \brief German Digital Signature Algorithm +/// \tparam T FieldElement type or class +/// \details The Digital Signature Scheme ECGDSA does not define the algorithm over integers. Rather, the +/// signature algorithm is only defined over elliptic curves. However, The library design is such that the +/// generic algorithm reside in gfpcrypt.h. +/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf +/// The Digital Signature Scheme ECGDSA (October 24, 2006) +template +class DL_Algorithm_GDSA_ISO15946 : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "GDSA-ISO15946";} + + virtual ~DL_Algorithm_GDSA_ISO15946() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + // r = x(k * G) mod q + r = params.ConvertElementToInteger(params.ExponentiateBase(k)) % q; + // s = (k * r - h(m)) * d_A mod q + s = (k * r - e) * x % q; + CRYPTOPP_ASSERT(!!r && !!s); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q || s<1) + return false; + + const Integer& rInv = r.InverseMod(q); + const Integer u1 = (rInv * e) % q; + const Integer u2 = (rInv * s) % q; + // verify x(G^u1 + P_A^u2) mod q + return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; + } +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; + +/// \brief NR algorithm +/// \tparam T FieldElement type or class +template +class DL_Algorithm_NR : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "NR";} + + virtual ~DL_Algorithm_NR() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + r = (r + e) % q; + s = (k - x*r) % q; + CRYPTOPP_ASSERT(!!r); + } + + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const + { + const Integer &q = params.GetSubgroupOrder(); + if (r>=q || r<1 || s>=q) + return false; + + // check r == (m_g^s * m_y^r + m) mod m_q + return r == (params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(s, r)) + e) % q; + } +}; + +/// \brief Discrete Log (DL) public key in GF(p) groups +/// \tparam GP GroupParameters derived class +/// \details DSA public key format is defined in 7.3.3 of RFC 2459. The private key format is defined in 12.9 of PKCS #11 v2.10. +template +class DL_PublicKey_GFP : public DL_PublicKeyImpl +{ +public: + virtual ~DL_PublicKey_GFP() {} + + /// \brief Initialize a public key over GF(p) + /// \param params the group parameters + /// \param y the public element + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &y) + {this->AccessGroupParameters().Initialize(params); this->SetPublicElement(y);} + + /// \brief Initialize a public key over GF(p) + /// \param p the modulus + /// \param g the generator + /// \param y the public element + void Initialize(const Integer &p, const Integer &g, const Integer &y) + {this->AccessGroupParameters().Initialize(p, g); this->SetPublicElement(y);} + + /// \brief Initialize a public key over GF(p) + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \param y the public element + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &y) + {this->AccessGroupParameters().Initialize(p, q, g); this->SetPublicElement(y);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool, size_t) + {this->SetPublicElement(Integer(bt));} + void DEREncodePublicKey(BufferedTransformation &bt) const + {this->GetPublicElement().DEREncode(bt);} +}; + +/// \brief Discrete Log (DL) private key in GF(p) groups +/// \tparam GP GroupParameters derived class +template +class DL_PrivateKey_GFP : public DL_PrivateKeyImpl +{ +public: + virtual ~DL_PrivateKey_GFP(); + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {this->GenerateRandomWithKeySize(rng, modulusBits);} + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param p the modulus + /// \param g the generator + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &g) + {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupGenerator", g));} + + /// \brief Create a private key + /// \param rng a RandomNumberGenerator derived class + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &q, const Integer &g) + {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupOrder", q)("SubgroupGenerator", g));} + + /// \brief Initialize a private key over GF(p) + /// \param params the group parameters + /// \param x the private exponent + void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &x) + {this->AccessGroupParameters().Initialize(params); this->SetPrivateExponent(x);} + + /// \brief Initialize a private key over GF(p) + /// \param p the modulus + /// \param g the generator + /// \param x the private exponent + void Initialize(const Integer &p, const Integer &g, const Integer &x) + {this->AccessGroupParameters().Initialize(p, g); this->SetPrivateExponent(x);} + + /// \brief Initialize a private key over GF(p) + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + /// \param x the private exponent + void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &x) + {this->AccessGroupParameters().Initialize(p, q, g); this->SetPrivateExponent(x);} +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey_GFP::~DL_PrivateKey_GFP() {} + +/// \brief Discrete Log (DL) signing/verification keys in GF(p) groups +struct DL_SignatureKeys_GFP +{ + typedef DL_GroupParameters_GFP GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief Discrete Log (DL) encryption/decryption keys in GF(p) groups +struct DL_CryptoKeys_GFP +{ + typedef DL_GroupParameters_GFP_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief DSA signature scheme +/// \tparam H HashTransformation derived class +/// \sa DSA-1363 +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct GDSA : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_GDSA, + DL_SignatureMessageEncodingMethod_DSA, + H> +{ +}; + +/// \brief NR signature scheme +/// \tparam H HashTransformation derived class +/// \sa NR +template +struct NR : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_NR, + DL_SignatureMessageEncodingMethod_NR, + H> +{ +}; + +/// \brief DSA group parameters +/// \details These are GF(p) group parameters that are allowed by the DSA standard +/// \sa DL_Keys_DSA +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL DL_GroupParameters_DSA : public DL_GroupParameters_GFP +{ +public: + virtual ~DL_GroupParameters_DSA() {} + + /// \brief Check the group for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details ValidateGroup() also checks that the lengths of p and q are allowed + /// by the DSA standard. + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param alg additional initialization parameters + /// \details NameValuePairs can be ModulusSize alone; or Modulus, SubgroupOrder, and + /// SubgroupGenerator. ModulusSize must be between DSA::MIN_PRIME_LENGTH and + /// DSA::MAX_PRIME_LENGTH, and divisible by DSA::PRIME_LENGTH_MULTIPLE. + /// \details An example of changing the modulus size using NameValuePairs is shown below. + ///
+    ///   AlgorithmParameters params = MakeParameters
+    ///     (Name::ModulusSize(), 2048);
+    ///
+    ///   DL_GroupParameters_DSA groupParams;
+    ///   groupParams.GenerateRandom(prng, params);
+    /// 
+ /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid. + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + /// \brief Check the prime length for errors + /// \param pbits number of bits in the prime number + /// \return true if the tests succeed, false otherwise + static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits) + {return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;} + + /// \brief DSA prime length + enum { + /// \brief Minimum prime length + MIN_PRIME_LENGTH = 1024, + /// \brief Maximum prime length + MAX_PRIME_LENGTH = 3072, + /// \brief Prime length multiple + PRIME_LENGTH_MULTIPLE = 1024 + }; +}; + +template +class DSA2; + +/// \brief DSA keys +/// \sa DL_GroupParameters_DSA +/// \since Crypto++ 1.0 +struct DL_Keys_DSA +{ + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 > PrivateKey; +}; + +/// \brief DSA signature scheme +/// \tparam H HashTransformation derived class +/// \details The class is named DSA2 instead of DSA for backwards compatibility because +/// DSA was a non-template class. +/// \details DSA default method GenerateRandom uses a 2048-bit modulus and a 224-bit subgoup by default. +/// The modulus can be changed using the following code: +///
+///   DSA::PrivateKey privateKey;
+///   privateKey.GenerateRandomWithKeySize(prng, 2048);
+/// 
+/// \details The subgroup order can be changed using the following code: +///
+///   AlgorithmParameters params = MakeParameters
+///     (Name::ModulusSize(), 2048)
+///     (Name::SubgroupOrderSize(), 256);
+///
+///   DSA::PrivateKey privateKey;
+///   privateKey.GenerateRandom(prng, params);
+/// 
+/// \sa DSA, as specified in FIPS 186-3, +/// Digital Signature Algorithm on the wiki, and +/// NameValuePairs on the wiki. +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2, Crypto++ 6.1 for 2048-bit modulus. +template +class DSA2 : public DL_SS< + DL_Keys_DSA, + DL_Algorithm_GDSA, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA2 > +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();} +}; + +/// \brief DSA deterministic signature scheme +/// \tparam H HashTransformation derived class +/// \sa DSA-1363 +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct DSA_RFC6979 : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_DSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("DSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// DSA with SHA-1, typedef'd for backwards compatibility +typedef DSA2 DSA; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 >; + +/// \brief P1363 based XOR Encryption Method +/// \tparam MAC MessageAuthenticationCode derived class used for MAC computation +/// \tparam DHAES_MODE flag indicating DHAES mode +/// \tparam LABEL_OCTETS flag indicating the label is octet count +/// \details DL_EncryptionAlgorithm_Xor is based on an early P1363 draft, which itself appears to be based on an +/// early Certicom SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used it in its Integrated +/// Ecryption Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Crypto++ 4.2 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=ture and LABEL_OCTETS=false. +/// \details Bouncy Castle 1.54 and Botan 1.11 compatibility are the default template parameters. +/// \since Crypto++ 4.0 +template +class DL_EncryptionAlgorithm_Xor : public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_EncryptionAlgorithm_Xor() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t GetSymmetricKeyLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DEFAULT_KEYLENGTH);} + size_t GetSymmetricCiphertextLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DIGESTSIZE);} + size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const + {return SaturatingSubtract(ciphertextLength, static_cast(MAC::DIGESTSIZE));} + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(rng); + const byte *cipherKey = NULLPTR, *macKey = NULLPTR; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + if (plaintextLength) // Coverity finding + xorbuf(ciphertext, plaintext, cipherKey, plaintextLength); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + mac.Final(ciphertext + plaintextLength); + } + DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const + { + size_t plaintextLength = GetMaxSymmetricPlaintextLength(ciphertextLength); + const byte *cipherKey, *macKey; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + if (!mac.Verify(ciphertext + plaintextLength)) + return DecodingResult(); + + if (plaintextLength) // Coverity finding + xorbuf(plaintext, ciphertext, cipherKey, plaintextLength); + + return DecodingResult(plaintextLength); + } +}; + +/// _ +template +class DL_KeyDerivationAlgorithm_P1363 : public DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm_P1363() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::KeyDerivationParameters()) == 0;} + void Derive(const DL_GroupParameters ¶ms, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs ¶meters) const + { + SecByteBlock agreedSecret; + if (DHAES_MODE) + { + agreedSecret.New(params.GetEncodedElementSize(true) + params.GetEncodedElementSize(false)); + params.EncodeElement(true, ephemeralPublicKey, agreedSecret); + params.EncodeElement(false, agreedElement, agreedSecret + params.GetEncodedElementSize(true)); + } + else + { + agreedSecret.New(params.GetEncodedElementSize(false)); + params.EncodeElement(false, agreedElement, agreedSecret); + } + + ConstByteArrayParameter derivationParameters; + parameters.GetValue(Name::KeyDerivationParameters(), derivationParameters); + KDF::DeriveKey(derivedKey, derivedLength, agreedSecret, agreedSecret.size(), derivationParameters.begin(), derivationParameters.size()); + } +}; + +/// \brief Discrete Log Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes addition context parameters such as the label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details DLIES is an Integer based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation Method (KEM) +/// with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the DLIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the DLIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the +/// security provided by the MAC. The hash is also used in the key derivation function as a PRF. +/// \details Below is an example of constructing a Crypto++ 4.2 compatible DLIES encryptor and decryptor. +///
+///     AutoSeededRandomPool prng;
+///     DL_PrivateKey_GFP key;
+///     key.Initialize(prng, 2048);
+///
+///     DLIES::Decryptor decryptor(key);
+///     DLIES::Encryptor encryptor(decryptor);
+/// 
+/// \sa ECIES, Discrete Log Integrated Encryption Scheme (DLIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct DLIES + : public DL_ES< + DL_CryptoKeys_GFP, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + DLIES<> > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DLIES";} // TODO: fix this after name is standardized +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/gost.cpp b/extension/third_party/cryptopp/gost.cpp new file mode 100644 index 00000000..dbeff911 --- /dev/null +++ b/extension/third_party/cryptopp/gost.cpp @@ -0,0 +1,123 @@ +#include "pch.h" +#include "gost.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +// these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333 +const byte GOST::Base::sBox[8][16]={ + {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3}, + {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9}, + {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11}, + {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3}, + {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2}, + {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14}, + {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12}, + {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12}}; + +/* // these are the S-boxes given in the GOST source code listing in Applied + // Cryptography 2nd Ed., p. 644. they appear to be from the DES S-boxes + {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, + { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, + {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, + { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, + { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, + {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, + {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, + {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }}; +*/ + +volatile bool GOST::Base::sTableCalculated = false; +word32 GOST::Base::sTable[4][256]; + +void GOST::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + PrecalculateSTable(); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), 8, userKey, KEYLENGTH); +} + +void GOST::Base::PrecalculateSTable() +{ + if (!sTableCalculated) + { + for (unsigned i = 0; i < 4; i++) + for (unsigned j = 0; j < 256; j++) + { + word32 temp = sBox[2*i][j%16] | (sBox[2*i+1][j/16] << 4); + sTable[i][j] = rotlMod(temp, 11+8*i); + } + + sTableCalculated=true; + } +} + +#define f(x) ( t=x, \ + sTable[3][GETBYTE(t, 3)] ^ sTable[2][GETBYTE(t, 2)] \ + ^ sTable[1][GETBYTE(t, 1)] ^ sTable[0][GETBYTE(t, 0)] ) + +typedef BlockGetAndPut Block; + +void GOST::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 n1, n2, t; + + Block::Get(inBlock)(n1)(n2); + + for (unsigned int i=0; i<3; i++) + { + n2 ^= f(n1+m_key[0]); + n1 ^= f(n2+m_key[1]); + n2 ^= f(n1+m_key[2]); + n1 ^= f(n2+m_key[3]); + n2 ^= f(n1+m_key[4]); + n1 ^= f(n2+m_key[5]); + n2 ^= f(n1+m_key[6]); + n1 ^= f(n2+m_key[7]); + } + + n2 ^= f(n1+m_key[7]); + n1 ^= f(n2+m_key[6]); + n2 ^= f(n1+m_key[5]); + n1 ^= f(n2+m_key[4]); + n2 ^= f(n1+m_key[3]); + n1 ^= f(n2+m_key[2]); + n2 ^= f(n1+m_key[1]); + n1 ^= f(n2+m_key[0]); + + Block::Put(xorBlock, outBlock)(n2)(n1); +} + +void GOST::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 n1, n2, t; + + Block::Get(inBlock)(n1)(n2); + + n2 ^= f(n1+m_key[0]); + n1 ^= f(n2+m_key[1]); + n2 ^= f(n1+m_key[2]); + n1 ^= f(n2+m_key[3]); + n2 ^= f(n1+m_key[4]); + n1 ^= f(n2+m_key[5]); + n2 ^= f(n1+m_key[6]); + n1 ^= f(n2+m_key[7]); + + for (unsigned int i=0; i<3; i++) + { + n2 ^= f(n1+m_key[7]); + n1 ^= f(n2+m_key[6]); + n2 ^= f(n1+m_key[5]); + n1 ^= f(n2+m_key[4]); + n2 ^= f(n1+m_key[3]); + n1 ^= f(n2+m_key[2]); + n2 ^= f(n1+m_key[1]); + n1 ^= f(n2+m_key[0]); + } + + Block::Put(xorBlock, outBlock)(n2)(n1); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/gost.h b/extension/third_party/cryptopp/gost.h new file mode 100644 index 00000000..fe6e1576 --- /dev/null +++ b/extension/third_party/cryptopp/gost.h @@ -0,0 +1,66 @@ +// gost.h - originally written and placed in the public domain by Wei Dai + +/// \file gost.h +/// \brief Classes for the GIST block cipher + +#ifndef CRYPTOPP_GOST_H +#define CRYPTOPP_GOST_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GOST block cipher information +/// \since Crypto++ 2.1 +struct GOST_Info : public FixedBlockSize<8>, public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "GOST";} +}; + +/// \brief GOST block cipher +/// \sa GOST +/// \since Crypto++ 2.1 +class GOST : public GOST_Info, public BlockCipherDocumentation +{ + /// \brief GOST block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static void PrecalculateSTable(); + + static const byte sBox[8][16]; + static volatile bool sTableCalculated; + static word32 sTable[4][256]; + + FixedSizeSecBlock m_key; + }; + + /// \brief GOST block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief GOST block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef GOST::Encryption GOSTEncryption; +typedef GOST::Decryption GOSTDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/gzip.cpp b/extension/third_party/cryptopp/gzip.cpp new file mode 100644 index 00000000..ade1d422 --- /dev/null +++ b/extension/third_party/cryptopp/gzip.cpp @@ -0,0 +1,208 @@ +// gzip.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "gzip.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +// Checks whether the character is valid for ISO/IEC 8859-1 as required by RFC 1952 +static inline bool Is8859Character(char c) { + const unsigned char cc = static_cast(c); + return (cc >= 32 && cc <= 126) || (cc >= 160); +} + +void Gzip::IsolatedInitialize(const NameValuePairs ¶meters) +{ + Deflator::IsolatedInitialize(parameters); + + ConstByteArrayParameter v; + if (parameters.GetValue(Name::FileName(), v)) + m_filename.assign(reinterpret_cast(v.begin()), v.size()); + if (parameters.GetValue(Name::Comment(), v)) + m_comment.assign(reinterpret_cast(v.begin()), v.size()); + m_filetime = parameters.GetIntValueWithDefault(Name::FileTime(), 0); +} + +void Gzip::WritePrestreamHeader() +{ + m_totalLen = 0; + m_crc.Restart(); + + int flags = 0; + if(!m_filename.empty()) + flags |= FILENAME; + if(!m_comment.empty()) + flags |= COMMENTS; + + AttachedTransformation()->Put(MAGIC1); + AttachedTransformation()->Put(MAGIC2); + AttachedTransformation()->Put(DEFLATED); + AttachedTransformation()->Put((byte)flags); // general flag + AttachedTransformation()->PutWord32(m_filetime, LITTLE_ENDIAN_ORDER); // time stamp + byte extra = static_cast((GetDeflateLevel() == 1) ? + FAST : ((GetDeflateLevel() == 9) ? SLOW : 0)); + AttachedTransformation()->Put(extra); + AttachedTransformation()->Put(GZIP_OS_CODE); + + // Filename is NULL terminated, hence the +1 + if(!m_filename.empty()) + AttachedTransformation()->Put((const unsigned char*)m_filename.data(), m_filename.size() +1); + + // Comment is NULL terminated, hence the +1 + if(!m_comment.empty()) + AttachedTransformation()->Put((const unsigned char*)m_comment.data(), m_comment.size() +1); +} + +void Gzip::ProcessUncompressedData(const byte *inString, size_t length) +{ + m_crc.Update(inString, length); + m_totalLen += (word32)length; +} + +void Gzip::WritePoststreamTail() +{ + SecByteBlock crc(4); + m_crc.Final(crc); + AttachedTransformation()->Put(crc, 4); + AttachedTransformation()->PutWord32(m_totalLen, LITTLE_ENDIAN_ORDER); + + m_filetime = 0; + m_filename.clear(); + m_comment.clear(); +} + +void Gzip::SetComment(const std::string& comment, bool throwOnEncodingError) +{ + if(throwOnEncodingError) + { + for(size_t i = 0; i < comment.length(); i++) { + const char c = comment[i]; + if(!Is8859Character(c)) + throw InvalidDataFormat("The comment is not ISO/IEC 8859-1 encoded"); + } + } + + m_comment = comment; +} + +void Gzip::SetFilename(const std::string& filename, bool throwOnEncodingError) +{ + if(throwOnEncodingError) + { + for(size_t i = 0; i < filename.length(); i++) { + const char c = filename[i]; + if(!Is8859Character(c)) + throw InvalidDataFormat("The filename is not ISO/IEC 8859-1 encoded"); + } + } + + m_filename = filename; +} + +// ************************************************************* + +Gunzip::Gunzip(BufferedTransformation *attachment, bool repeat, int propagation) + : Inflator(attachment, repeat, propagation), m_length(0), m_filetime(0) +{ +} + +void Gunzip::ProcessPrestreamHeader() +{ + m_length = 0; + m_crc.Restart(); + + m_filetime = 0; + m_filename.clear(); + m_comment.clear(); + + byte buf[6]; + byte b, flags; + + if (m_inQueue.Get(buf, 2)!=2) throw HeaderErr(); + if (buf[0] != MAGIC1 || buf[1] != MAGIC2) throw HeaderErr(); + if (!m_inQueue.Get(b) || (b != DEFLATED)) throw HeaderErr(); // skip CM flag + if (!m_inQueue.Get(flags)) throw HeaderErr(); + if (flags & (ENCRYPTED | CONTINUED)) throw HeaderErr(); + if (m_inQueue.GetWord32(m_filetime, LITTLE_ENDIAN_ORDER) != 4) throw HeaderErr(); + if (m_inQueue.Skip(2)!=2) throw HeaderErr(); // Skip extra flags and OS type + + if (flags & EXTRA_FIELDS) // skip extra fields + { + word16 length; + if (m_inQueue.GetWord16(length, LITTLE_ENDIAN_ORDER) != 2) throw HeaderErr(); + if (m_inQueue.Skip(length)!=length) throw HeaderErr(); + } + + if (flags & FILENAME) // extract filename + { + do + { + if(!m_inQueue.Get(b)) throw HeaderErr(); + if(b) m_filename.append( 1, (char)b ); + } + while (b); + } + + if (flags & COMMENTS) // extract comments + { + do + { + if(!m_inQueue.Get(b)) throw HeaderErr(); + if(b) m_comment.append( 1, (char)b ); + } + while (b); + } +} + +void Gunzip::ProcessDecompressedData(const byte *inString, size_t length) +{ + AttachedTransformation()->Put(inString, length); + m_crc.Update(inString, length); + m_length += (word32)length; +} + +void Gunzip::ProcessPoststreamTail() +{ + SecByteBlock crc(4); + if (m_inQueue.Get(crc, 4) != 4) + throw TailErr(); + if (!m_crc.Verify(crc)) + throw CrcErr(); + + word32 lengthCheck; + if (m_inQueue.GetWord32(lengthCheck, LITTLE_ENDIAN_ORDER) != 4) + throw TailErr(); + if (lengthCheck != m_length) + throw LengthErr(); +} + +const std::string& Gunzip::GetComment(bool throwOnEncodingError) const +{ + if(throwOnEncodingError) + { + for(size_t i = 0; i < m_comment.length(); i++) { + const char c = m_comment[i]; + if(!Is8859Character(c)) + throw InvalidDataFormat("The comment is not ISO/IEC 8859-1 encoded"); + } + } + + return m_comment; +} + +const std::string& Gunzip::GetFilename(bool throwOnEncodingError) const +{ + if(throwOnEncodingError) + { + for(size_t i = 0; i < m_filename.length(); i++) { + const char c = m_filename[i]; + if(!Is8859Character(c)) + throw InvalidDataFormat("The filename is not ISO/IEC 8859-1 encoded"); + } + } + + return m_filename; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/gzip.h b/extension/third_party/cryptopp/gzip.h new file mode 100644 index 00000000..b05feb4c --- /dev/null +++ b/extension/third_party/cryptopp/gzip.h @@ -0,0 +1,144 @@ +// gzip.h - originally written and placed in the public domain by Wei Dai + +/// \file gzip.h +/// \brief GZIP compression and decompression (RFC 1952) + +#ifndef CRYPTOPP_GZIP_H +#define CRYPTOPP_GZIP_H + +#include "cryptlib.h" +#include "zdeflate.h" +#include "zinflate.h" +#include "crc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GZIP Compression (RFC 1952) +class Gzip : public Deflator +{ +public: + /// \brief Construct a Gzip compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Gzip(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible), m_totalLen(0), m_filetime(0) { } + + /// \brief Construct a Gzip compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Gzip(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment), m_totalLen(0), m_filetime(0) + { + IsolatedInitialize(parameters); + } + + /// \param filetime the filetime to set in the header. The application is responsible for setting it. + void SetFiletime(word32 filetime) { m_filetime = filetime; } + + /// \param filename the original filename to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the filename is not checked. + void SetFilename(const std::string& filename, bool throwOnEncodingError = false); + + /// \param comment the comment to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the comment is not checked. + void SetComment(const std::string& comment, bool throwOnEncodingError = false); + + void IsolatedInitialize(const NameValuePairs ¶meters); + +protected: + enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header + DEFLATED=8, FAST=4, SLOW=2}; + + enum FLAG_MASKS { + FILENAME=8, COMMENTS=16}; + + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + word32 m_totalLen; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +/// \brief GZIP Decompression (RFC 1952) +class Gunzip : public Inflator +{ +public: + typedef Inflator::Err Err; + + /// \brief Exception thrown when a header decoding error occurs + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "Gunzip: header decoding error") {}}; + /// \brief Exception thrown when the tail is too short + class TailErr : public Err {public: TailErr() : Err(INVALID_DATA_FORMAT, "Gunzip: tail too short") {}}; + /// \brief Exception thrown when a CRC error occurs + class CrcErr : public Err {public: CrcErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: CRC check error") {}}; + /// \brief Exception thrown when a length error occurs + class LengthErr : public Err {public: LengthErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: length check error") {}}; + + /// \brief Construct a Gunzip decompressor + /// \param attachment an attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Gunzip(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + /// \return the filetime of the stream as set in the header. The application is responsible for setting it on the decompressed file. + word32 GetFiletime() const { return m_filetime; } + + /// \return the filename of the stream as set in the header. The application is responsible for setting it on the decompressed file. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the filename is not checked. + const std::string& GetFilename(bool throwOnEncodingError = false) const; + + /// \return the comment of the stream as set in the header. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the comment is not checked. + const std::string& GetComment(bool throwOnEncodingError = false) const; + +protected: + enum { + /// \brief First header magic value + MAGIC1=0x1f, + /// \brief Second header magic value + MAGIC2=0x8b, + /// \brief Deflated flag + DEFLATED=8 + }; + + enum FLAG_MASKS { + CONTINUED=2, EXTRA_FIELDS=4, FILENAME=8, COMMENTS=16, ENCRYPTED=32}; + + unsigned int MaxPrestreamHeaderSize() const {return 1024;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 8;} + void ProcessPoststreamTail(); + + word32 m_length; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/hashfwd.h b/extension/third_party/cryptopp/hashfwd.h new file mode 100644 index 00000000..49c2b02a --- /dev/null +++ b/extension/third_party/cryptopp/hashfwd.h @@ -0,0 +1,38 @@ +// hashfwd.h - written and placed in the public domain by Jeffrey Walton + +/// \file hashfwd.h +/// \brief Forward declarations for hash functions used in signature encoding methods + +#ifndef CRYPTOPP_HASHFWD_H +#define CRYPTOPP_HASHFWD_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +class SHA1; +class SHA224; +class SHA256; +class SHA384; +class SHA512; + +class SHA3_256; +class SHA3_384; +class SHA3_512; + +class SHAKE128; +class SHAKE256; + +class Tiger; +class RIPEMD128; +class RIPEMD160; +class Whirlpool; + +namespace Weak1 { + class MD2; + class MD5; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HASHFWD_H diff --git a/extension/third_party/cryptopp/hc128.cpp b/extension/third_party/cryptopp/hc128.cpp new file mode 100644 index 00000000..b734d6e5 --- /dev/null +++ b/extension/third_party/cryptopp/hc128.cpp @@ -0,0 +1,279 @@ +// hc128.cpp - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-hc128.html. + +#include "pch.h" +#include "config.h" + +#include "hc128.h" +#include "secblock.h" +#include "misc.h" + +/*h1 function*/ +#define h1(x, y) { \ + byte a,c; \ + a = (byte) (x); \ + c = (byte) ((x) >> 16); \ + y = (m_T[512+a])+(m_T[512+256+c]); \ +} + +/*h2 function*/ +#define h2(x, y) { \ + byte a,c; \ + a = (byte) (x); \ + c = (byte) ((x) >> 16); \ + y = (m_T[a])+(m_T[256+c]); \ +} + +/*one step of HC-128, update P and generate 32 bits keystream*/ +#define step_P(u,v,a,b,c,d,n){ \ + word32 tem0,tem1,tem2,tem3; \ + h1(m_X[(d)],tem3); \ + tem0 = rotrConstant<23>(m_T[(v)]); \ + tem1 = rotrConstant<10>(m_X[(c)]); \ + tem2 = rotrConstant<8>(m_X[(b)]); \ + (m_T[(u)]) += tem2+(tem0 ^ tem1); \ + (m_X[(a)]) = (m_T[(u)]); \ + (n) = tem3 ^ (m_T[(u)]); \ +} + +/*one step of HC-128, update Q and generate 32 bits keystream*/ +#define step_Q(u,v,a,b,c,d,n){ \ + word32 tem0,tem1,tem2,tem3; \ + h2(m_Y[(d)],tem3); \ + tem0 = rotrConstant<(32-23)>(m_T[(v)]); \ + tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \ + tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \ + (m_T[(u)]) += tem2 + (tem0 ^ tem1); \ + (m_Y[(a)]) = (m_T[(u)]); \ + (n) = tem3 ^ (m_T[(u)]) ; \ +} + +/*update table P*/ +#define update_P(u,v,a,b,c,d){ \ + word32 tem0,tem1,tem2,tem3; \ + tem0 = rotrConstant<23>(m_T[(v)]); \ + tem1 = rotrConstant<10>(m_X[(c)]); \ + tem2 = rotrConstant<8>(m_X[(b)]); \ + h1(m_X[(d)],tem3); \ + (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ + (m_X[(a)]) = (m_T[(u)]); \ +} + +/*update table Q*/ +#define update_Q(u,v,a,b,c,d){ \ + word32 tem0,tem1,tem2,tem3; \ + tem0 = rotrConstant<(32-23)>(m_T[(v)]); \ + tem1 = rotrConstant<(32-10)>(m_Y[(c)]); \ + tem2 = rotrConstant<(32-8)>(m_Y[(b)]); \ + h2(m_Y[(d)],tem3); \ + (m_T[(u)]) = ((m_T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ + (m_Y[(a)]) = (m_T[(u)]); \ +} + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::rotrConstant; + +inline word32 f1(word32 x) +{ + return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ ((x) >> 3); +} + +inline word32 f2(word32 x) +{ + return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ ((x) >> 10); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +/*16 steps of HC-128, generate 512 bits keystream*/ +void HC128Policy::GenerateKeystream(word32 keystream[16]) +{ + unsigned int cc = m_ctr & 0x1ff; + unsigned int dd = (cc + 16) & 0x1ff; + + if (m_ctr < 512) + { + m_ctr = (m_ctr + 16) & 0x3ff; + step_P(cc + 0, cc + 1, 0, 6, 13, 4, keystream[0]); + step_P(cc + 1, cc + 2, 1, 7, 14, 5, keystream[1]); + step_P(cc + 2, cc + 3, 2, 8, 15, 6, keystream[2]); + step_P(cc + 3, cc + 4, 3, 9, 0, 7, keystream[3]); + step_P(cc + 4, cc + 5, 4, 10, 1, 8, keystream[4]); + step_P(cc + 5, cc + 6, 5, 11, 2, 9, keystream[5]); + step_P(cc + 6, cc + 7, 6, 12, 3, 10, keystream[6]); + step_P(cc + 7, cc + 8, 7, 13, 4, 11, keystream[7]); + step_P(cc + 8, cc + 9, 8, 14, 5, 12, keystream[8]); + step_P(cc + 9, cc + 10, 9, 15, 6, 13, keystream[9]); + step_P(cc + 10, cc + 11, 10, 0, 7, 14, keystream[10]); + step_P(cc + 11, cc + 12, 11, 1, 8, 15, keystream[11]); + step_P(cc + 12, cc + 13, 12, 2, 9, 0, keystream[12]); + step_P(cc + 13, cc + 14, 13, 3, 10, 1, keystream[13]); + step_P(cc + 14, cc + 15, 14, 4, 11, 2, keystream[14]); + step_P(cc + 15, dd + 0, 15, 5, 12, 3, keystream[15]); + } + else + { + m_ctr = (m_ctr + 16) & 0x3ff; + step_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4, keystream[0]); + step_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5, keystream[1]); + step_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6, keystream[2]); + step_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7, keystream[3]); + step_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8, keystream[4]); + step_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9, keystream[5]); + step_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10, keystream[6]); + step_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11, keystream[7]); + step_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12, keystream[8]); + step_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13, keystream[9]); + step_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14, keystream[10]); + step_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15, keystream[11]); + step_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0, keystream[12]); + step_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1, keystream[13]); + step_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2, keystream[14]); + step_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3, keystream[15]); + } +} + +/*16 steps of HC-128, without generating keystream, */ +/*but use the outputs to update P and Q*/ +void HC128Policy::SetupUpdate() /*each time 16 steps*/ +{ + unsigned int cc = m_ctr & 0x1ff; + unsigned int dd = (cc + 16) & 0x1ff; + + if (m_ctr < 512) + { + m_ctr = (m_ctr + 16) & 0x3ff; + update_P(cc + 0, cc + 1, 0, 6, 13, 4); + update_P(cc + 1, cc + 2, 1, 7, 14, 5); + update_P(cc + 2, cc + 3, 2, 8, 15, 6); + update_P(cc + 3, cc + 4, 3, 9, 0, 7); + update_P(cc + 4, cc + 5, 4, 10, 1, 8); + update_P(cc + 5, cc + 6, 5, 11, 2, 9); + update_P(cc + 6, cc + 7, 6, 12, 3, 10); + update_P(cc + 7, cc + 8, 7, 13, 4, 11); + update_P(cc + 8, cc + 9, 8, 14, 5, 12); + update_P(cc + 9, cc + 10, 9, 15, 6, 13); + update_P(cc + 10, cc + 11, 10, 0, 7, 14); + update_P(cc + 11, cc + 12, 11, 1, 8, 15); + update_P(cc + 12, cc + 13, 12, 2, 9, 0); + update_P(cc + 13, cc + 14, 13, 3, 10, 1); + update_P(cc + 14, cc + 15, 14, 4, 11, 2); + update_P(cc + 15, dd + 0, 15, 5, 12, 3); + } + else + { + m_ctr = (m_ctr + 16) & 0x3ff; + update_Q(512 + cc + 0, 512 + cc + 1, 0, 6, 13, 4); + update_Q(512 + cc + 1, 512 + cc + 2, 1, 7, 14, 5); + update_Q(512 + cc + 2, 512 + cc + 3, 2, 8, 15, 6); + update_Q(512 + cc + 3, 512 + cc + 4, 3, 9, 0, 7); + update_Q(512 + cc + 4, 512 + cc + 5, 4, 10, 1, 8); + update_Q(512 + cc + 5, 512 + cc + 6, 5, 11, 2, 9); + update_Q(512 + cc + 6, 512 + cc + 7, 6, 12, 3, 10); + update_Q(512 + cc + 7, 512 + cc + 8, 7, 13, 4, 11); + update_Q(512 + cc + 8, 512 + cc + 9, 8, 14, 5, 12); + update_Q(512 + cc + 9, 512 + cc + 10, 9, 15, 6, 13); + update_Q(512 + cc + 10, 512 + cc + 11, 10, 0, 7, 14); + update_Q(512 + cc + 11, 512 + cc + 12, 11, 1, 8, 15); + update_Q(512 + cc + 12, 512 + cc + 13, 12, 2, 9, 0); + update_Q(512 + cc + 13, 512 + cc + 14, 13, 3, 10, 1); + update_Q(512 + cc + 14, 512 + cc + 15, 14, 4, 11, 2); + update_Q(512 + cc + 15, 512 + dd + 0, 15, 5, 12, 3); + } +} + +void HC128Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) +{ + CRYPTOPP_UNUSED(params); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), 4, userKey, keylen); + for (unsigned int i = 4; i < 8; i++) + m_key[i] = m_key[i - 4]; +} + +void HC128Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + while (iterationCount--) + { + word32 keystream[16]; + GenerateKeystream(keystream); + + PutWord(false, LITTLE_ENDIAN_ORDER, output + 0, keystream[0]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 4, keystream[1]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 8, keystream[2]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 12, keystream[3]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 16, keystream[4]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 20, keystream[5]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 24, keystream[6]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 28, keystream[7]); + + PutWord(false, LITTLE_ENDIAN_ORDER, output + 32, keystream[8]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 36, keystream[9]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 40, keystream[10]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 44, keystream[11]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 48, keystream[12]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 52, keystream[13]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 56, keystream[14]); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 60, keystream[15]); + + // If AdditiveCipherTemplate does not have an accumulated keystream + // then it will ask OperateKeystream to generate one. Optionally it + // will ask for an XOR of the input with the keystream while + // writing the result to the output buffer. In all cases the + // keystream is written to the output buffer. The optional part is + // adding the input buffer and keystream. + if ((operation & INPUT_NULL) != INPUT_NULL) + { + xorbuf(output, input, BYTES_PER_ITERATION); + input += BYTES_PER_ITERATION; + } + + output += BYTES_PER_ITERATION; + } +} + +void HC128Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_iv.begin(), 4, iv, length); + for (unsigned int i = 4; i < 8; i++) + m_iv[i] = m_iv[i - 4]; + + /* expand the key and IV into the table T */ + /* (expand the key and IV into the table P and Q) */ + + for (unsigned int i = 0; i < 8; i++) + m_T[i] = m_key[i]; + for (unsigned int i = 8; i < 16; i++) + m_T[i] = m_iv[i - 8]; + + for (unsigned int i = 16; i < (256 + 16); i++) + m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + i; + + for (unsigned int i = 0; i < 16; i++) + m_T[i] = m_T[256 + i]; + + for (unsigned int i = 16; i < 1024; i++) + m_T[i] = f2(m_T[i - 2]) + m_T[i - 7] + f1(m_T[i - 15]) + m_T[i - 16] + 256 + i; + + /* initialize counter1024, X and Y */ + m_ctr = 0; + for (unsigned int i = 0; i < 16; i++) + m_X[i] = m_T[512 - 16 + i]; + for (unsigned int i = 0; i < 16; i++) + m_Y[i] = m_T[512 + 512 - 16 + i]; + + /* run the cipher 1024 steps before generating the output */ + for (unsigned int i = 0; i < 64; i++) + SetupUpdate(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/hc128.h b/extension/third_party/cryptopp/hc128.h new file mode 100644 index 00000000..a43eeeb3 --- /dev/null +++ b/extension/third_party/cryptopp/hc128.h @@ -0,0 +1,67 @@ +// hc128.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-hc128.html. + +/// \file hc128.h +/// \brief Classes for HC-128 stream cipher +/// \sa The +/// eSTREAM Project | HC-128 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HC128_H +#define CRYPTOPP_HC128_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HC-128 stream cipher information +/// \since Crypto++ 8.0 +struct HC128Info : public FixedKeyLength<16, SimpleKeyingInterface::UNIQUE_IV, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "HC-128"; } +}; + +/// \brief HC-128 stream cipher implementation +/// \since Crypto++ 8.0 +class HC128Policy : public AdditiveCipherConcretePolicy, public HC128Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + + void GenerateKeystream(word32* keystream); + void SetupUpdate(); + +private: + FixedSizeSecBlock m_X; + FixedSizeSecBlock m_Y; + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_iv; + word32 m_T[1024]; + word32 m_ctr; +}; + +/// \brief HC-128 stream cipher +/// \details HC-128 is a stream cipher developed by Hongjun Wu. HC-128 is one of the +/// final four Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \sa The +/// eSTREAM Project | HC-128 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 +struct HC128 : public HC128Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, HC128Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_HC128_H diff --git a/extension/third_party/cryptopp/hc256.cpp b/extension/third_party/cryptopp/hc256.cpp new file mode 100644 index 00000000..f8ec989f --- /dev/null +++ b/extension/third_party/cryptopp/hc256.cpp @@ -0,0 +1,158 @@ +// hc256.cpp - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/hc256.html. + +#include "pch.h" +#include "config.h" + +#include "hc256.h" +#include "secblock.h" +#include "misc.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::rotrConstant; + +inline word32 f1(word32 x) +{ + return rotrConstant<7>(x) ^ rotrConstant<18>(x) ^ (x >> 3); +} + +inline word32 f2(word32 x) +{ + return rotrConstant<17>(x) ^ rotrConstant<19>(x) ^ (x >> 10); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +inline word32 HC256Policy::H1(word32 u) +{ + word32 tem; + byte a, b, c, d; + a = (byte)(u); + b = (byte)(u >> 8); + c = (byte)(u >> 16); + d = (byte)(u >> 24); + tem = m_Q[a] + m_Q[256 + b] + m_Q[512 + c] + m_Q[768 + d]; + return (tem); +} + +inline word32 HC256Policy::H2(word32 u) +{ + word32 tem; + byte a, b, c, d; + a = (byte)(u); + b = (byte)(u >> 8); + c = (byte)(u >> 16); + d = (byte)(u >> 24); + tem = m_P[a] + m_P[256 + b] + m_P[512 + c] + m_P[768 + d]; + return (tem); +} + +inline word32 HC256Policy::Generate() /*one step of the cipher*/ +{ + word32 i, i3, i10, i12, i1023; + word32 output; + + i = m_ctr & 0x3ff; + i3 = (i - 3) & 0x3ff; + i10 = (i - 10) & 0x3ff; + i12 = (i - 12) & 0x3ff; + i1023 = (i - 1023) & 0x3ff; + + if (m_ctr < 1024) { + m_P[i] = m_P[i] + m_P[i10] + (rotrConstant<10>(m_P[i3]) ^ rotrConstant<23>(m_P[i1023])) + m_Q[(m_P[i3] ^ m_P[i1023]) & 0x3ff]; + output = H1(m_P[i12]) ^ m_P[i]; + } + else { + m_Q[i] = m_Q[i] + m_Q[i10] + (rotrConstant<10>(m_Q[i3]) ^ rotrConstant<23>(m_Q[i1023])) + m_P[(m_Q[i3] ^ m_Q[i1023]) & 0x3ff]; + output = H2(m_Q[i12]) ^ m_Q[i]; + } + m_ctr = (m_ctr + 1) & 0x7ff; + return (output); +} + +void HC256Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) +{ + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(keylen); + CRYPTOPP_ASSERT(keylen == 32); + + for (unsigned int i = 0; i < 8; i++) + m_key[i] = 0; + + for (unsigned int i = 0; i < 32; i++) + { + m_key[i >> 2] = m_key[i >> 2] | userKey[i]; + m_key[i >> 2] = rotlConstant<8>(m_key[i >> 2]); + } +} + +void HC256Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + while (iterationCount--) + { + PutWord(false, LITTLE_ENDIAN_ORDER, output + 0, Generate()); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 4, Generate()); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 8, Generate()); + PutWord(false, LITTLE_ENDIAN_ORDER, output + 12, Generate()); + + // If AdditiveCipherTemplate does not have an accumulated keystream + // then it will ask OperateKeystream to generate one. Optionally it + // will ask for an XOR of the input with the keystream while + // writing the result to the output buffer. In all cases the + // keystream is written to the output buffer. The optional part is + // adding the input buffer and keystream. + if ((operation & INPUT_NULL) != INPUT_NULL) + { + xorbuf(output, input, BYTES_PER_ITERATION); + input += BYTES_PER_ITERATION; + } + + output += BYTES_PER_ITERATION; + } +} + +void HC256Policy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length == 32); + + /* initialize the iv */ + word32 W[2560]; + for (unsigned int i = 0; i < 8; i++) + m_iv[i] = 0; + + for (unsigned int i = 0; i < 32; i++) + { + m_iv[i >> 2] = m_iv[i >> 2] | iv[i]; + m_iv[i >> 2] = rotlConstant<8>(m_iv[i >> 2]); + } + + /* setup the table P and Q */ + + for (unsigned int i = 0; i < 8; i++) + W[i] = m_key[i]; + for (unsigned int i = 8; i < 16; i++) + W[i] = m_iv[i - 8]; + + for (unsigned int i = 16; i < 2560; i++) + W[i] = f2(W[i - 2]) + W[i - 7] + f1(W[i - 15]) + W[i - 16] + i; + + for (unsigned int i = 0; i < 1024; i++) + m_P[i] = W[i + 512]; + for (unsigned int i = 0; i < 1024; i++) + m_Q[i] = W[i + 1536]; + + m_ctr = 0; + + /* run the cipher 4096 steps before generating the output */ + for (unsigned int i = 0; i < 4096; i++) + Generate(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/hc256.h b/extension/third_party/cryptopp/hc256.h new file mode 100644 index 00000000..ccd1ca05 --- /dev/null +++ b/extension/third_party/cryptopp/hc256.h @@ -0,0 +1,67 @@ +// hc256.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/hc256.html. + +/// \file hc256.h +/// \brief Classes for HC-256 stream cipher +/// \sa The +/// eSTREAM Project | HC-256 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HC256_H +#define CRYPTOPP_HC256_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HC-256 stream cipher information +/// \since Crypto++ 8.0 +struct HC256Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "HC-256"; } +}; + +/// \brief HC-256 stream cipher implementation +/// \since Crypto++ 8.0 +class HC256Policy : public AdditiveCipherConcretePolicy, public HC256Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + + word32 H1(word32 u); + word32 H2(word32 u); + word32 Generate(); + +private: + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_iv; + word32 m_P[1024]; + word32 m_Q[1024]; + word32 m_ctr; +}; + +/// \brief HC-256 stream cipher +/// \details HC-256 is a stream cipher developed by Hongjun Wu. HC-256 is the +/// successor to HC-128 from the eSTREAM project. +/// \sa The +/// eSTREAM Project | HC-256 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 +struct HC256 : public HC256Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, HC256Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_HC256_H diff --git a/extension/third_party/cryptopp/hex.cpp b/extension/third_party/cryptopp/hex.cpp new file mode 100644 index 00000000..d347241b --- /dev/null +++ b/extension/third_party/cryptopp/hex.cpp @@ -0,0 +1,58 @@ +// hex.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "hex.h" + +NAMESPACE_BEGIN(CryptoPP) +ANONYMOUS_NAMESPACE_BEGIN + +const byte s_vecUpper[] = "0123456789ABCDEF"; +const byte s_vecLower[] = "0123456789abcdef"; +const int s_array[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +ANONYMOUS_NAMESPACE_END + +void HexEncoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool uppercase = parameters.GetValueWithDefault(Name::Uppercase(), true); + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_vecUpper[0] : &s_vecLower[0], false)(Name::Log2Base(), 4, true))); +} + +void HexDecoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDefaultDecodingLookupArray(), false)(Name::Log2Base(), 4, true))); +} + +// Unrolled initialization, http://github.com/weidai11/cryptopp/issues/376 +const int *HexDecoder::GetDefaultDecodingLookupArray() +{ + return s_array; +} + +NAMESPACE_END + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/hex.h b/extension/third_party/cryptopp/hex.h new file mode 100644 index 00000000..05f10687 --- /dev/null +++ b/extension/third_party/cryptopp/hex.h @@ -0,0 +1,50 @@ +// hex.h - originally written and placed in the public domain by Wei Dai + +/// \file hex.h +/// \brief Classes for HexEncoder and HexDecoder + +#ifndef CRYPTOPP_HEX_H +#define CRYPTOPP_HEX_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Converts given data to base 16 +class CRYPTOPP_DLL HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the output grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator append after processing + HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Decode base 16 data back to bytes +class CRYPTOPP_DLL HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 4, attachment) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/hight.cpp b/extension/third_party/cryptopp/hight.cpp new file mode 100644 index 00000000..8b6f28ed --- /dev/null +++ b/extension/third_party/cryptopp/hight.cpp @@ -0,0 +1,271 @@ +// lea.cpp - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "HIGHT: A 128-Bit Block Cipher for Fast Encryption on Common +// Processors" by Deukjo Hong, Jung-Keun Lee, Dong-Chan Kim, Daesung Kwon, +// Kwon Ho Ryu, and Dong-Geon Lee. +// +// This implementation is based on source files found in a zip file at the +// Korea Internet and Security Agency (https://www.kisa.or.kr/eng/main.jsp). +// The zip files was downloaded from the Korean language area of the site so we +// don't have a url or english zip filename to cite. The source filename from +// the zip is KISA_HIGHT_ECB.c. + +#include "pch.h" +#include "config.h" + +#include "hight.h" +#include "misc.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; + +const byte DELTA[128] = { + 0x5A,0x6D,0x36,0x1B,0x0D,0x06,0x03,0x41, + 0x60,0x30,0x18,0x4C,0x66,0x33,0x59,0x2C, + 0x56,0x2B,0x15,0x4A,0x65,0x72,0x39,0x1C, + 0x4E,0x67,0x73,0x79,0x3C,0x5E,0x6F,0x37, + 0x5B,0x2D,0x16,0x0B,0x05,0x42,0x21,0x50, + 0x28,0x54,0x2A,0x55,0x6A,0x75,0x7A,0x7D, + 0x3E,0x5F,0x2F,0x17,0x4B,0x25,0x52,0x29, + 0x14,0x0A,0x45,0x62,0x31,0x58,0x6C,0x76, + 0x3B,0x1D,0x0E,0x47,0x63,0x71,0x78,0x7C, + 0x7E,0x7F,0x3F,0x1F,0x0F,0x07,0x43,0x61, + 0x70,0x38,0x5C,0x6E,0x77,0x7B,0x3D,0x1E, + 0x4F,0x27,0x53,0x69,0x34,0x1A,0x4D,0x26, + 0x13,0x49,0x24,0x12,0x09,0x04,0x02,0x01, + 0x40,0x20,0x10,0x08,0x44,0x22,0x11,0x48, + 0x64,0x32,0x19,0x0C,0x46,0x23,0x51,0x68, + 0x74,0x3A,0x5D,0x2E,0x57,0x6B,0x35,0x5A +}; + +const byte HIGHT_F0[256] = { + 0x00,0x86,0x0D,0x8B,0x1A,0x9C,0x17,0x91, + 0x34,0xB2,0x39,0xBF,0x2E,0xA8,0x23,0xA5, + 0x68,0xEE,0x65,0xE3,0x72,0xF4,0x7F,0xF9, + 0x5C,0xDA,0x51,0xD7,0x46,0xC0,0x4B,0xCD, + 0xD0,0x56,0xDD,0x5B,0xCA,0x4C,0xC7,0x41, + 0xE4,0x62,0xE9,0x6F,0xFE,0x78,0xF3,0x75, + 0xB8,0x3E,0xB5,0x33,0xA2,0x24,0xAF,0x29, + 0x8C,0x0A,0x81,0x07,0x96,0x10,0x9B,0x1D, + 0xA1,0x27,0xAC,0x2A,0xBB,0x3D,0xB6,0x30, + 0x95,0x13,0x98,0x1E,0x8F,0x09,0x82,0x04, + 0xC9,0x4F,0xC4,0x42,0xD3,0x55,0xDE,0x58, + 0xFD,0x7B,0xF0,0x76,0xE7,0x61,0xEA,0x6C, + 0x71,0xF7,0x7C,0xFA,0x6B,0xED,0x66,0xE0, + 0x45,0xC3,0x48,0xCE,0x5F,0xD9,0x52,0xD4, + 0x19,0x9F,0x14,0x92,0x03,0x85,0x0E,0x88, + 0x2D,0xAB,0x20,0xA6,0x37,0xB1,0x3A,0xBC, + 0x43,0xC5,0x4E,0xC8,0x59,0xDF,0x54,0xD2, + 0x77,0xF1,0x7A,0xFC,0x6D,0xEB,0x60,0xE6, + 0x2B,0xAD,0x26,0xA0,0x31,0xB7,0x3C,0xBA, + 0x1F,0x99,0x12,0x94,0x05,0x83,0x08,0x8E, + 0x93,0x15,0x9E,0x18,0x89,0x0F,0x84,0x02, + 0xA7,0x21,0xAA,0x2C,0xBD,0x3B,0xB0,0x36, + 0xFB,0x7D,0xF6,0x70,0xE1,0x67,0xEC,0x6A, + 0xCF,0x49,0xC2,0x44,0xD5,0x53,0xD8,0x5E, + 0xE2,0x64,0xEF,0x69,0xF8,0x7E,0xF5,0x73, + 0xD6,0x50,0xDB,0x5D,0xCC,0x4A,0xC1,0x47, + 0x8A,0x0C,0x87,0x01,0x90,0x16,0x9D,0x1B, + 0xBE,0x38,0xB3,0x35,0xA4,0x22,0xA9,0x2F, + 0x32,0xB4,0x3F,0xB9,0x28,0xAE,0x25,0xA3, + 0x06,0x80,0x0B,0x8D,0x1C,0x9A,0x11,0x97, + 0x5A,0xDC,0x57,0xD1,0x40,0xC6,0x4D,0xCB, + 0x6E,0xE8,0x63,0xE5,0x74,0xF2,0x79,0xFF +}; + +const byte HIGHT_F1[256] = { + 0x00,0x58,0xB0,0xE8,0x61,0x39,0xD1,0x89, + 0xC2,0x9A,0x72,0x2A,0xA3,0xFB,0x13,0x4B, + 0x85,0xDD,0x35,0x6D,0xE4,0xBC,0x54,0x0C, + 0x47,0x1F,0xF7,0xAF,0x26,0x7E,0x96,0xCE, + 0x0B,0x53,0xBB,0xE3,0x6A,0x32,0xDA,0x82, + 0xC9,0x91,0x79,0x21,0xA8,0xF0,0x18,0x40, + 0x8E,0xD6,0x3E,0x66,0xEF,0xB7,0x5F,0x07, + 0x4C,0x14,0xFC,0xA4,0x2D,0x75,0x9D,0xC5, + 0x16,0x4E,0xA6,0xFE,0x77,0x2F,0xC7,0x9F, + 0xD4,0x8C,0x64,0x3C,0xB5,0xED,0x05,0x5D, + 0x93,0xCB,0x23,0x7B,0xF2,0xAA,0x42,0x1A, + 0x51,0x09,0xE1,0xB9,0x30,0x68,0x80,0xD8, + 0x1D,0x45,0xAD,0xF5,0x7C,0x24,0xCC,0x94, + 0xDF,0x87,0x6F,0x37,0xBE,0xE6,0x0E,0x56, + 0x98,0xC0,0x28,0x70,0xF9,0xA1,0x49,0x11, + 0x5A,0x02,0xEA,0xB2,0x3B,0x63,0x8B,0xD3, + 0x2C,0x74,0x9C,0xC4,0x4D,0x15,0xFD,0xA5, + 0xEE,0xB6,0x5E,0x06,0x8F,0xD7,0x3F,0x67, + 0xA9,0xF1,0x19,0x41,0xC8,0x90,0x78,0x20, + 0x6B,0x33,0xDB,0x83,0x0A,0x52,0xBA,0xE2, + 0x27,0x7F,0x97,0xCF,0x46,0x1E,0xF6,0xAE, + 0xE5,0xBD,0x55,0x0D,0x84,0xDC,0x34,0x6C, + 0xA2,0xFA,0x12,0x4A,0xC3,0x9B,0x73,0x2B, + 0x60,0x38,0xD0,0x88,0x01,0x59,0xB1,0xE9, + 0x3A,0x62,0x8A,0xD2,0x5B,0x03,0xEB,0xB3, + 0xF8,0xA0,0x48,0x10,0x99,0xC1,0x29,0x71, + 0xBF,0xE7,0x0F,0x57,0xDE,0x86,0x6E,0x36, + 0x7D,0x25,0xCD,0x95,0x1C,0x44,0xAC,0xF4, + 0x31,0x69,0x81,0xD9,0x50,0x08,0xE0,0xB8, + 0xF3,0xAB,0x43,0x1B,0x92,0xCA,0x22,0x7A, + 0xB4,0xEC,0x04,0x5C,0xD5,0x8D,0x65,0x3D, + 0x76,0x2E,0xC6,0x9E,0x17,0x4F,0xA7,0xFF +}; + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void HIGHT::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + CRYPTOPP_UNUSED(keyLength); + + for(unsigned int i=0; i<4; i++) { + m_rkey[i ] = userKey[i+12]; + m_rkey[i+4] = userKey[i ]; + } + + for(unsigned int i=0; i<8; i++) { + for(unsigned int j=0; j<8; j++) { + m_rkey[8+16*i+j] = static_cast(userKey[(j-i)&7] + DELTA[16*i+j]); + } + + for(unsigned int j=0; j<8; j++) { + m_rkey[8+16*i+j+8] = static_cast(userKey[((j-i)&7)+8] + DELTA[16*i+j+8]); + } + } +} + +void HIGHT::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // First Round + m_xx[1] = inBlock[1]; + m_xx[3] = inBlock[3]; + m_xx[5] = inBlock[5]; + m_xx[7] = inBlock[7]; + + m_xx[0] = (inBlock[0] + m_rkey[0]) & 0xFF; + m_xx[2] = (inBlock[2] ^ m_rkey[1]); + m_xx[4] = (inBlock[4] + m_rkey[2]) & 0xFF; + m_xx[6] = (inBlock[6] ^ m_rkey[3]); + + // Encryption Round + #define HIGHT_ENC(k, i0,i1,i2,i3,i4,i5,i6,i7) { \ + m_xx[i0] = (m_xx[i0] ^ (HIGHT_F0[m_xx[i1]] + m_rkey[4*k+3])) & 0xFF; \ + m_xx[i2] = (m_xx[i2] + (HIGHT_F1[m_xx[i3]] ^ m_rkey[4*k+2])) & 0xFF; \ + m_xx[i4] = (m_xx[i4] ^ (HIGHT_F0[m_xx[i5]] + m_rkey[4*k+1])) & 0xFF; \ + m_xx[i6] = (m_xx[i6] + (HIGHT_F1[m_xx[i7]] ^ m_rkey[4*k+0])) & 0xFF; \ + } + + HIGHT_ENC( 2, 7,6,5,4,3,2,1,0); + HIGHT_ENC( 3, 6,5,4,3,2,1,0,7); + HIGHT_ENC( 4, 5,4,3,2,1,0,7,6); + HIGHT_ENC( 5, 4,3,2,1,0,7,6,5); + HIGHT_ENC( 6, 3,2,1,0,7,6,5,4); + HIGHT_ENC( 7, 2,1,0,7,6,5,4,3); + HIGHT_ENC( 8, 1,0,7,6,5,4,3,2); + HIGHT_ENC( 9, 0,7,6,5,4,3,2,1); + HIGHT_ENC(10, 7,6,5,4,3,2,1,0); + HIGHT_ENC(11, 6,5,4,3,2,1,0,7); + HIGHT_ENC(12, 5,4,3,2,1,0,7,6); + HIGHT_ENC(13, 4,3,2,1,0,7,6,5); + HIGHT_ENC(14, 3,2,1,0,7,6,5,4); + HIGHT_ENC(15, 2,1,0,7,6,5,4,3); + HIGHT_ENC(16, 1,0,7,6,5,4,3,2); + HIGHT_ENC(17, 0,7,6,5,4,3,2,1); + HIGHT_ENC(18, 7,6,5,4,3,2,1,0); + HIGHT_ENC(19, 6,5,4,3,2,1,0,7); + HIGHT_ENC(20, 5,4,3,2,1,0,7,6); + HIGHT_ENC(21, 4,3,2,1,0,7,6,5); + HIGHT_ENC(22, 3,2,1,0,7,6,5,4); + HIGHT_ENC(23, 2,1,0,7,6,5,4,3); + HIGHT_ENC(24, 1,0,7,6,5,4,3,2); + HIGHT_ENC(25, 0,7,6,5,4,3,2,1); + HIGHT_ENC(26, 7,6,5,4,3,2,1,0); + HIGHT_ENC(27, 6,5,4,3,2,1,0,7); + HIGHT_ENC(28, 5,4,3,2,1,0,7,6); + HIGHT_ENC(29, 4,3,2,1,0,7,6,5); + HIGHT_ENC(30, 3,2,1,0,7,6,5,4); + HIGHT_ENC(31, 2,1,0,7,6,5,4,3); + HIGHT_ENC(32, 1,0,7,6,5,4,3,2); + HIGHT_ENC(33, 0,7,6,5,4,3,2,1); + + // Final Round + outBlock[1] = static_cast(m_xx[2]); + outBlock[3] = static_cast(m_xx[4]); + outBlock[5] = static_cast(m_xx[6]); + outBlock[7] = static_cast(m_xx[0]); + + outBlock[0] = static_cast(m_xx[1] + m_rkey[4]); + outBlock[2] = static_cast(m_xx[3] ^ m_rkey[5]); + outBlock[4] = static_cast(m_xx[5] + m_rkey[6]); + outBlock[6] = static_cast(m_xx[7] ^ m_rkey[7]); + + if (xorBlock) + xorbuf(outBlock, xorBlock, 8); +} + +void HIGHT::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + m_xx[2] = static_cast(inBlock[1]); + m_xx[4] = static_cast(inBlock[3]); + m_xx[6] = static_cast(inBlock[5]); + m_xx[0] = static_cast(inBlock[7]); + + m_xx[1] = static_cast(inBlock[0] - m_rkey[4]); + m_xx[3] = static_cast(inBlock[2] ^ m_rkey[5]); + m_xx[5] = static_cast(inBlock[4] - m_rkey[6]); + m_xx[7] = static_cast(inBlock[6] ^ m_rkey[7]); + + #define HIGHT_DEC(k, i0,i1,i2,i3,i4,i5,i6,i7) { \ + m_xx[i1] = (m_xx[i1] - (HIGHT_F1[m_xx[i2]] ^ m_rkey[4*k+2])) & 0xFF; \ + m_xx[i3] = (m_xx[i3] ^ (HIGHT_F0[m_xx[i4]] + m_rkey[4*k+1])) & 0xFF; \ + m_xx[i5] = (m_xx[i5] - (HIGHT_F1[m_xx[i6]] ^ m_rkey[4*k+0])) & 0xFF; \ + m_xx[i7] = (m_xx[i7] ^ (HIGHT_F0[m_xx[i0]] + m_rkey[4*k+3])) & 0xFF; \ + } + + HIGHT_DEC(33, 7,6,5,4,3,2,1,0); + HIGHT_DEC(32, 0,7,6,5,4,3,2,1); + HIGHT_DEC(31, 1,0,7,6,5,4,3,2); + HIGHT_DEC(30, 2,1,0,7,6,5,4,3); + HIGHT_DEC(29, 3,2,1,0,7,6,5,4); + HIGHT_DEC(28, 4,3,2,1,0,7,6,5); + HIGHT_DEC(27, 5,4,3,2,1,0,7,6); + HIGHT_DEC(26, 6,5,4,3,2,1,0,7); + HIGHT_DEC(25, 7,6,5,4,3,2,1,0); + HIGHT_DEC(24, 0,7,6,5,4,3,2,1); + HIGHT_DEC(23, 1,0,7,6,5,4,3,2); + HIGHT_DEC(22, 2,1,0,7,6,5,4,3); + HIGHT_DEC(21, 3,2,1,0,7,6,5,4); + HIGHT_DEC(20, 4,3,2,1,0,7,6,5); + HIGHT_DEC(19, 5,4,3,2,1,0,7,6); + HIGHT_DEC(18, 6,5,4,3,2,1,0,7); + HIGHT_DEC(17, 7,6,5,4,3,2,1,0); + HIGHT_DEC(16, 0,7,6,5,4,3,2,1); + HIGHT_DEC(15, 1,0,7,6,5,4,3,2); + HIGHT_DEC(14, 2,1,0,7,6,5,4,3); + HIGHT_DEC(13, 3,2,1,0,7,6,5,4); + HIGHT_DEC(12, 4,3,2,1,0,7,6,5); + HIGHT_DEC(11, 5,4,3,2,1,0,7,6); + HIGHT_DEC(10, 6,5,4,3,2,1,0,7); + HIGHT_DEC( 9, 7,6,5,4,3,2,1,0); + HIGHT_DEC( 8, 0,7,6,5,4,3,2,1); + HIGHT_DEC( 7, 1,0,7,6,5,4,3,2); + HIGHT_DEC( 6, 2,1,0,7,6,5,4,3); + HIGHT_DEC( 5, 3,2,1,0,7,6,5,4); + HIGHT_DEC( 4, 4,3,2,1,0,7,6,5); + HIGHT_DEC( 3, 5,4,3,2,1,0,7,6); + HIGHT_DEC( 2, 6,5,4,3,2,1,0,7); + + outBlock[1] = static_cast(m_xx[1]); + outBlock[3] = static_cast(m_xx[3]); + outBlock[5] = static_cast(m_xx[5]); + outBlock[7] = static_cast(m_xx[7]); + + outBlock[0] = static_cast(m_xx[0] - m_rkey[0]); + outBlock[2] = static_cast(m_xx[2] ^ m_rkey[1]); + outBlock[4] = static_cast(m_xx[4] - m_rkey[2]); + outBlock[6] = static_cast(m_xx[6] ^ m_rkey[3]); + + if (xorBlock) + xorbuf(outBlock, xorBlock, 8); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/hight.h b/extension/third_party/cryptopp/hight.h new file mode 100644 index 00000000..0262382b --- /dev/null +++ b/extension/third_party/cryptopp/hight.h @@ -0,0 +1,81 @@ +// hight.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "HIGHT: A New Block Cipher Suitable for Low-Resource Device" +// by Deukjo Hong, Jaechul Sung, Seokhie Hong, Jongin Lim, Sangjin Lee, +// Bon-Seok Koo, Changhoon Lee, Donghoon Chang, Jesang Lee, Kitae Jeong, +// Hyun Kim, Jongsung Kim, and Seongtaek Chee + +/// \file hight.h +/// \brief Classes for the HIGHT block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HIGHT_H +#define CRYPTOPP_HIGHT_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HIGHT block cipher information +/// \since Crypto++ 8.0 +struct HIGHT_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "HIGHT"; + } +}; + +/// \brief HIGHT 64-bit block cipher +/// \details HIGHT provides 64-bit block size. The valid key size is 128-bits. +/// \note Crypto++ provides a byte oriented implementation +/// \sa HIGHT, +/// Korea Internet & Security +/// Agency website +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE HIGHT : public HIGHT_Info, public BlockCipherDocumentation +{ +public: + /// \brief HIGHT block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + FixedSizeSecBlock m_rkey; + mutable FixedSizeSecBlock m_xx; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef HIGHT::Encryption HIGHTEncryption; +typedef HIGHT::Decryption HIGHTDecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_HIGHT_H diff --git a/extension/third_party/cryptopp/hkdf.h b/extension/third_party/cryptopp/hkdf.h new file mode 100644 index 00000000..c6256020 --- /dev/null +++ b/extension/third_party/cryptopp/hkdf.h @@ -0,0 +1,179 @@ +// hkdf.h - written and placed in public domain by Jeffrey Walton. + +/// \file hkdf.h +/// \brief Classes for HKDF from RFC 5869 +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_HKDF_H +#define CRYPTOPP_HKDF_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algparam.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Extract-and-Expand Key Derivation Function (HKDF) +/// \tparam T HashTransformation class +/// \sa Cryptographic Extraction and Key +/// Derivation: The HKDF Scheme and +/// HMAC-based Extract-and-Expand Key +/// Derivation Function (HKDF) +/// \since Crypto++ 5.6.3 +template +class HKDF : public KeyDerivationFunction +{ +public: + virtual ~HKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("HKDF(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(T::DIGESTSIZE) * 255; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param info the additional input buffer + /// \param infoLen the size of the info buffer, in bytes + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details salt and info can be nullptr with 0 length. + /// HKDF is unusual in that a non-NULL salt with length 0 is different than a + /// NULL salt. A NULL salt causes HKDF to use a string of 0's + /// of length T::DIGESTSIZE for the salt. + /// \details HKDF always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + // If salt is absent (NULL), then use the NULL vector. Missing is different than + // EMPTY (Non-NULL, 0 length). The length of s_NullVector used depends on the Hash + // function. SHA-256 will use 32 bytes of s_NullVector. + typedef byte NullVectorType[T::DIGESTSIZE]; + static const NullVectorType& GetNullVector() { + static const NullVectorType s_NullVector = {0}; + return s_NullVector; + } +}; + +template +size_t HKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + ConstByteArrayParameter p; + SecByteBlock salt, info; + + if (params.GetValue("Salt", p)) + salt.Assign(p.begin(), p.size()); + else + salt.Assign(GetNullVector(), T::DIGESTSIZE); + + if (params.GetValue("Info", p)) + info.Assign(p.begin(), p.size()); + else + info.Assign(GetNullVector(), 0); + + return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), info.begin(), info.size()); +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // HKDF business logic. NULL is different than empty. + if (salt == NULLPTR) + { + salt = GetNullVector(); + saltLen = T::DIGESTSIZE; + } + + // key is PRK from the RFC, salt is IKM from the RFC + HMAC hmac; + SecByteBlock key(T::DIGESTSIZE), buffer(T::DIGESTSIZE); + + // Extract + hmac.SetKey(salt, saltLen); + hmac.CalculateDigest(key, secret, secretLen); + + // Key + hmac.SetKey(key.begin(), key.size()); + byte block = 0; + + // Expand + while (derivedLen > 0) + { + if (block++) {hmac.Update(buffer, buffer.size());} + if (infoLen) {hmac.Update(info, infoLen);} + hmac.CalculateDigest(buffer, &block, 1); + +#if CRYPTOPP_MSC_VERSION + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + std::memcpy(derived, buffer, segmentLen); +#endif + + derived += segmentLen; + derivedLen -= segmentLen; + } + + return 1; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HKDF_H diff --git a/extension/third_party/cryptopp/hmac.cpp b/extension/third_party/cryptopp/hmac.cpp new file mode 100644 index 00000000..7648ea9e --- /dev/null +++ b/extension/third_party/cryptopp/hmac.cpp @@ -0,0 +1,90 @@ +// hmac.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +void HMAC_Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + Restart(); + + HashTransformation &hash = AccessHash(); + unsigned int blockSize = hash.BlockSize(); + + if (!blockSize) + throw InvalidArgument("HMAC: can only be used with a block-based hash function"); + + m_buf.resize(2*AccessHash().BlockSize() + AccessHash().DigestSize()); + + if (keylength <= blockSize) + { + // hmac.cpp:26:9: runtime error: null pointer passed as argument 2 + if (AccessIpad() && userKey && keylength) + memcpy(AccessIpad(), userKey, keylength); + } + else + { + AccessHash().CalculateDigest(AccessIpad(), userKey, keylength); + keylength = hash.DigestSize(); + } + + CRYPTOPP_ASSERT(keylength <= blockSize); + memset(AccessIpad()+keylength, 0, blockSize-keylength); + + for (unsigned int i=0; i, public MessageAuthenticationCode +{ +public: + virtual ~HMAC_Base() {} + + /// \brief Construct a HMAC_Base + HMAC_Base() : m_innerHashKeyed(false) {} + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + + void Restart(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int OptimalBlockSize() const {return const_cast(this)->AccessHash().OptimalBlockSize();} + unsigned int DigestSize() const {return const_cast(this)->AccessHash().DigestSize();} + +protected: + virtual HashTransformation & AccessHash() =0; + byte * AccessIpad() {return m_buf;} + byte * AccessOpad() {return m_buf + AccessHash().BlockSize();} + byte * AccessInnerHash() {return m_buf + 2*AccessHash().BlockSize();} + +private: + void KeyInnerHash(); + + SecByteBlock m_buf; + bool m_innerHashKeyed; +}; + +/// \brief HMAC +/// \tparam T HashTransformation derived class +/// \details HMAC derives from MessageAuthenticationCodeImpl. It calculates the HMAC using +/// HMAC(K, text) = H(K XOR opad, H(K XOR ipad, text)). +/// \sa HMAC +/// \since Crypto++ 2.1 +template +class HMAC : public MessageAuthenticationCodeImpl > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE); + + virtual ~HMAC() {} + + /// \brief Construct a HMAC + HMAC() {} + /// \brief Construct a HMAC + /// \param key the HMAC key + /// \param length the size of the HMAC key + HMAC(const byte *key, size_t length=HMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("HMAC(") + T::StaticAlgorithmName() + ")";} + std::string AlgorithmName() const {return std::string("HMAC(") + m_hash.AlgorithmName() + ")";} + std::string AlgorithmProvider() const {return m_hash.AlgorithmProvider();} + +private: + HashTransformation & AccessHash() {return m_hash;} + + T m_hash; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/hmqv.h b/extension/third_party/cryptopp/hmqv.h new file mode 100644 index 00000000..fb11b310 --- /dev/null +++ b/extension/third_party/cryptopp/hmqv.h @@ -0,0 +1,417 @@ +// hmqv.h - written and placed in the public domain by Uri Blumenthal +// Shamelessly based upon Wei Dai's MQV source files + +#ifndef CRYPTOPP_HMQV_H +#define CRYPTOPP_HMQV_H + +/// \file hmqv.h +/// \brief Classes for Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class HMQV_Domain: public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef HMQV_Domain Domain; + + virtual ~HMQV_Domain() {} + + /// \brief Construct a HMQV domain + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) {} + + /// \brief Construct a HMQV domain + /// \param params group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + /// \brief Construct a HMQV domain + /// \param bt BufferedTransformation with group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 is passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const + {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + this->GetMaterial().DoQuickSanityCheck(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = ephemeralOtherPublicKey; + xxs = EphemeralPublicKeyLength(); + YY = ephemeralPrivateKey + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = staticOtherPublicKey; + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = ephemeralPrivateKey + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = ephemeralOtherPublicKey; + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = staticOtherPublicKey; + bbs = StaticPublicKeyLength(); + } + + Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true); + + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + SecByteBlock dd(len), ee(len); + + // Compute $d = \hat{H}(X, \hat{B})$ + Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + Integer d(dd.BytePtr(), dd.SizeInBytes()); + + // Compute $e = \hat{H}(Y, \hat{A})$ + Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes()); + Integer e(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + // $\sigma_B}=(X \cdot A^{d})^{s_B} + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t3 = params.ExponentiateElement(B, e); + Element t4 = m_groupParameters.MultiplyElements(Y, t3); + + // $\sigma_A}=(Y \cdot B^{e})^{s_A} + sigma = params.ExponentiateElement(t4, s_A); + } + Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + CRYPTOPP_ASSERT(0); + return false; + } + return true; + } + +protected: + // Hash invocation by client and server differ only in what keys + // each provides. + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, // Ephemeral key and key length + const byte* s1, size_t s1len, // Static key and key length + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + if (e1len != 0 || s1len != 0) { + CRYPTOPP_ASSERT(0); + } + //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + //SecByteBlock sbb(x.MinEncodedSize()); + //x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false)); + GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } else { + if (e1len == 0 || s1len == 0) { + CRYPTOPP_ASSERT(0); + } + hash.Update(e1, e1len); + hash.Update(s1, s1len); + } + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole { RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() + {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const + {return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa HMQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef HMQV_Domain HMQV; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/hrtimer.cpp b/extension/third_party/cryptopp/hrtimer.cpp new file mode 100644 index 00000000..f9b8a7cd --- /dev/null +++ b/extension/third_party/cryptopp/hrtimer.cpp @@ -0,0 +1,174 @@ +// hrtimer.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "hrtimer.h" +#include "misc.h" + +#include // for NULL +#include + +#if defined(CRYPTOPP_WIN32_AVAILABLE) +#define WIN32_LEAN_AND_MEAN +#include +# if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)) +# include +# if defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_FAMILY_PHONE_APP)) +# include +# endif +# endif +#endif +#endif + +#if defined(CRYPTOPP_UNIX_AVAILABLE) +#include +#include +#include +#endif + +#include "trap.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_WIN32_AVAILABLE) +static TimerWord InitializePerformanceCounterFrequency() +{ + LARGE_INTEGER freq = {0,0}; + if (!QueryPerformanceFrequency(&freq)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError())); + return freq.QuadPart; +} + +inline TimerWord PerformanceCounterFrequency() +{ + static const word64 freq = InitializePerformanceCounterFrequency(); + return freq; +} +#endif + +#ifndef CRYPTOPP_IMPORTS + +double TimerBase::ConvertTo(TimerWord t, Unit unit) +{ + static unsigned long unitsPerSecondTable[] = {1, 1000, 1000*1000, 1000*1000*1000}; + + // When 'unit' is an enum 'Unit', a Clang warning is generated. + CRYPTOPP_ASSERT(static_cast(unit) < COUNTOF(unitsPerSecondTable)); + return static_cast(t) * unitsPerSecondTable[unit] / TicksPerSecond(); +} + +void TimerBase::StartTimer() +{ + m_last = m_start = GetCurrentTimerValue(); + m_started = true; +} + +double TimerBase::ElapsedTimeAsDouble() +{ + if (m_stuckAtZero) + return 0; + + if (m_started) + { + TimerWord now = GetCurrentTimerValue(); + if (m_last < now) // protect against OS bugs where time goes backwards + m_last = now; + return ConvertTo(m_last - m_start, m_timerUnit); + } + + StartTimer(); + return 0; +} + +unsigned long TimerBase::ElapsedTime() +{ + double elapsed = ElapsedTimeAsDouble(); + CRYPTOPP_ASSERT(elapsed <= (double)ULONG_MAX); + return (unsigned long)elapsed; +} + +TimerWord Timer::GetCurrentTimerValue() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) + // Use the first union member to avoid an uninitialized warning + LARGE_INTEGER now = {0,0}; + if (!QueryPerformanceCounter(&now)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError())); + return now.QuadPart; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + timeval now; + gettimeofday(&now, NULLPTR); + return (TimerWord)now.tv_sec * 1000000 + now.tv_usec; +#else + // clock_t now; + return clock(); +#endif +} + +TimerWord Timer::TicksPerSecond() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) + return PerformanceCounterFrequency(); +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + return 1000000; +#else + return CLOCKS_PER_SEC; +#endif +} + +#endif // #ifndef CRYPTOPP_IMPORTS + +TimerWord ThreadUserTimer::GetCurrentTimerValue() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE) + static bool getCurrentThreadImplemented = true; + if (getCurrentThreadImplemented) + { + FILETIME now, ignored; + if (!GetThreadTimes(GetCurrentThread(), &ignored, &ignored, &ignored, &now)) + { + const DWORD lastError = GetLastError(); + if (lastError == ERROR_CALL_NOT_IMPLEMENTED) + { + getCurrentThreadImplemented = false; + goto GetCurrentThreadNotImplemented; + } + throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: GetThreadTimes failed with error " + IntToString(lastError)); + } + return now.dwLowDateTime + ((TimerWord)now.dwHighDateTime << 32); + } +GetCurrentThreadNotImplemented: + return (TimerWord)clock() * (10*1000*1000 / CLOCKS_PER_SEC); +#elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE) + LARGE_INTEGER now; + if (!QueryPerformanceCounter(&now)) + { + const DWORD lastError = GetLastError(); + throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: QueryPerformanceCounter failed with error " + IntToString(lastError)); + } + return now.QuadPart; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + tms now; + times(&now); + return now.tms_utime; +#else + return clock(); +#endif +} + +TimerWord ThreadUserTimer::TicksPerSecond() +{ +#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE) + return 10*1000*1000; +#elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE) + static const TimerWord ticksPerSecond = PerformanceCounterFrequency(); + return ticksPerSecond; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) + static const long ticksPerSecond = sysconf(_SC_CLK_TCK); + return ticksPerSecond; +#else + return CLOCKS_PER_SEC; +#endif +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/hrtimer.h b/extension/third_party/cryptopp/hrtimer.h new file mode 100644 index 00000000..a7e7d977 --- /dev/null +++ b/extension/third_party/cryptopp/hrtimer.h @@ -0,0 +1,134 @@ +// hrtimer.h - originally written and placed in the public domain by Wei Dai + +/// \file hrtimer.h +/// \brief Classes for timers + +#ifndef CRYPTOPP_HRTIMER_H +#define CRYPTOPP_HRTIMER_H + +#include "config.h" + +#if !defined(HIGHRES_TIMER_AVAILABLE) || (defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)) +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef HIGHRES_TIMER_AVAILABLE + /// \brief TimerWord is a 64-bit word + typedef word64 TimerWord; +#else + /// \brief TimerWord is a clock_t + typedef clock_t TimerWord; +#endif + +/// \brief Base class for timers +/// \sa ThreadUserTimer, Timer +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TimerBase +{ +public: + /// \brief Unit of measure + /// \details Unit selects the unit of measure as returned by functions + /// ElapsedTimeAsDouble() and ElapsedTime(). + /// \sa ElapsedTimeAsDouble, ElapsedTime + enum Unit { + /// \brief Timer unit is seconds + /// \details All timers support seconds + SECONDS = 0, + /// \brief Timer unit is milliseconds + /// \details All timers support milliseconds + MILLISECONDS, + /// \brief Timer unit is microseconds + /// \details The timer requires hardware support microseconds + MICROSECONDS, + /// \brief Timer unit is nanoseconds + /// \details The timer requires hardware support nanoseconds + NANOSECONDS + }; + + /// \brief Construct a TimerBase + /// \param unit the unit of measure + /// \param stuckAtZero flag + TimerBase(Unit unit, bool stuckAtZero) + : m_timerUnit(unit), m_stuckAtZero(stuckAtZero), m_started(false) + , m_start(0), m_last(0) {} + + /// \brief Retrieve the current timer value + /// \return the current timer value + virtual TimerWord GetCurrentTimerValue() =0; + + /// \brief Retrieve ticks per second + /// \return ticks per second + /// \details TicksPerSecond() is not the timer resolution. It is a + /// conversion factor into seconds. + virtual TimerWord TicksPerSecond() =0; + + /// \brief Start the timer + void StartTimer(); + + /// \brief Retrieve the elapsed time + /// \return the elapsed time as a double + /// \details The return value of ElapsedTimeAsDouble() depends upon + /// the Unit selected during construction of the timer. For example, + /// if Unit = SECONDS and ElapsedTimeAsDouble() returns 3, + /// then the timer has run for 3 seconds. If + /// Unit = MILLISECONDS and ElapsedTimeAsDouble() returns + /// 3000, then the timer has run for 3 seconds. + /// \sa Unit, ElapsedTime + double ElapsedTimeAsDouble(); + + /// \brief Retrieve the elapsed time + /// \return the elapsed time as an unsigned long + /// \details The return value of ElapsedTime() depends upon the + /// Unit selected during construction of the timer. For example, if + /// Unit = SECONDS and ElapsedTime() returns 3, then + /// the timer has run for 3 seconds. If Unit = MILLISECONDS + /// and ElapsedTime() returns 3000, then the timer has run for 3 + /// seconds. + /// \sa Unit, ElapsedTimeAsDouble + unsigned long ElapsedTime(); + +private: + double ConvertTo(TimerWord t, Unit unit); + + Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX + bool m_stuckAtZero, m_started; + TimerWord m_start, m_last; +}; + +/// \brief Measure CPU time spent executing instructions of this thread +/// \details ThreadUserTimer requires support of the OS. On Unix-based it +/// reports process time. On Windows NT or later desktops and servers it +/// reports thread times with performance counter precision.. On Windows +/// Phone and Windows Store it reports wall clock time with performance +/// counter precision. On all others it reports wall clock time. +/// \note ThreadUserTimer only works correctly on Windows NT or later +/// desktops and servers. +/// \sa Timer +class ThreadUserTimer : public TimerBase +{ +public: + /// \brief Construct a ThreadUserTimer + /// \param unit the unit of measure + /// \param stuckAtZero flag + ThreadUserTimer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +/// \brief High resolution timer +/// \sa ThreadUserTimer +class CRYPTOPP_DLL Timer : public TimerBase +{ +public: + /// \brief Construct a Timer + /// \param unit the unit of measure + /// \param stuckAtZero flag + Timer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ida.cpp b/extension/third_party/cryptopp/ida.cpp new file mode 100644 index 00000000..1c8b3ab2 --- /dev/null +++ b/extension/third_party/cryptopp/ida.cpp @@ -0,0 +1,418 @@ +// ida.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#include "ida.h" +#include "stdcpp.h" +#include "algebra.h" +#include "polynomi.h" +#include "polynomi.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +#if (defined(_MSC_VER) && (_MSC_VER < 1400)) && !defined(__MWERKS__) + // VC60 and VC7 workaround: built-in reverse_iterator has two template parameters, Dinkumware only has one + typedef std::reverse_bidirectional_iterator RevIt; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator RevIt; +#else + typedef std::reverse_iterator RevIt; +#endif + +void RawIDA::IsolatedInitialize(const NameValuePairs ¶meters) +{ + if (!parameters.GetIntValue("RecoveryThreshold", m_threshold)) + throw InvalidArgument("RawIDA: missing RecoveryThreshold argument"); + + CRYPTOPP_ASSERT(m_threshold > 0); + if (m_threshold <= 0) + throw InvalidArgument("RawIDA: RecoveryThreshold must be greater than 0"); + + m_lastMapPosition = m_inputChannelMap.end(); + m_channelsReady = 0; + m_channelsFinished = 0; + m_w.New(m_threshold); + m_y.New(m_threshold); + m_inputQueues.reserve(m_threshold); + + m_outputChannelIds.clear(); + m_outputChannelIdStrings.clear(); + m_outputQueues.clear(); + + word32 outputChannelID; + if (parameters.GetValue("OutputChannelID", outputChannelID)) + AddOutputChannel(outputChannelID); + else + { + int nShares = parameters.GetIntValueWithDefault("NumberOfShares", m_threshold); + CRYPTOPP_ASSERT(nShares > 0); + if (nShares <= 0) {nShares = m_threshold;} + for (unsigned int i=0; i< (unsigned int)(nShares); i++) + AddOutputChannel(i); + } +} + +unsigned int RawIDA::InsertInputChannel(word32 channelId) +{ + if (m_lastMapPosition != m_inputChannelMap.end()) + { + if (m_lastMapPosition->first == channelId) + goto skipFind; + ++m_lastMapPosition; + if (m_lastMapPosition != m_inputChannelMap.end() && m_lastMapPosition->first == channelId) + goto skipFind; + } + m_lastMapPosition = m_inputChannelMap.find(channelId); + +skipFind: + if (m_lastMapPosition == m_inputChannelMap.end()) + { + if (m_inputChannelIds.size() == size_t(m_threshold)) + return m_threshold; + + m_lastMapPosition = m_inputChannelMap.insert(InputChannelMap::value_type(channelId, (unsigned int)m_inputChannelIds.size())).first; + m_inputQueues.push_back(MessageQueue()); + m_inputChannelIds.push_back(channelId); + + if (m_inputChannelIds.size() == size_t(m_threshold)) + PrepareInterpolation(); + } + return m_lastMapPosition->second; +} + +unsigned int RawIDA::LookupInputChannel(word32 channelId) const +{ + std::map::const_iterator it = m_inputChannelMap.find(channelId); + if (it == m_inputChannelMap.end()) + return m_threshold; + else + return it->second; +} + +void RawIDA::ChannelData(word32 channelId, const byte *inString, size_t length, bool messageEnd) +{ + int i = InsertInputChannel(channelId); + if (i < m_threshold) + { + lword size = m_inputQueues[i].MaxRetrievable(); + m_inputQueues[i].Put(inString, length); + if (size < 4 && size + length >= 4) + { + m_channelsReady++; + if (m_channelsReady == size_t(m_threshold)) + ProcessInputQueues(); + } + + if (messageEnd) + { + m_inputQueues[i].MessageEnd(); + if (m_inputQueues[i].NumberOfMessages() == 1) + { + m_channelsFinished++; + if (m_channelsFinished == size_t(m_threshold)) + { + m_channelsReady = 0; + for (i=0; i= m_v.size()) + { + m_v.resize(i+1); + m_outputToInput.resize(i+1); + } + + m_outputToInput[i] = LookupInputChannel(m_outputChannelIds[i]); + if (m_outputToInput[i] == size_t(m_threshold) && i * size_t(m_threshold) <= 1000*1000) + { + m_v[i].resize(m_threshold); + PrepareBulkPolynomialInterpolationAt(m_gf32, m_v[i].begin(), m_outputChannelIds[i], &(m_inputChannelIds[0]), m_w.begin(), m_threshold); + } +} + +void RawIDA::AddOutputChannel(word32 channelId) +{ + m_outputChannelIds.push_back(channelId); + m_outputChannelIdStrings.push_back(WordToString(channelId)); + m_outputQueues.push_back(ByteQueue()); + if (m_inputChannelIds.size() == size_t(m_threshold)) + ComputeV((unsigned int)m_outputChannelIds.size() - 1); +} + +void RawIDA::PrepareInterpolation() +{ + CRYPTOPP_ASSERT(m_inputChannelIds.size() == size_t(m_threshold)); + PrepareBulkPolynomialInterpolation(m_gf32, m_w.begin(), &(m_inputChannelIds[0]), (unsigned int)(m_threshold)); + for (unsigned int i=0; i 0 : m_channelsReady == size_t(m_threshold)) + { + m_channelsReady = 0; + for (i=0; i 0 || queue.MaxRetrievable() >= 4; + } + + for (i=0; (unsigned int)i 0 && m_outputQueues[0].AnyRetrievable()) + FlushOutputQueues(); + + if (finished) + { + OutputMessageEnds(); + + m_channelsReady = 0; + m_channelsFinished = 0; + m_v.clear(); + + std::vector inputQueues; + std::vector inputChannelIds; + + inputQueues.swap(m_inputQueues); + inputChannelIds.swap(m_inputChannelIds); + m_inputChannelMap.clear(); + m_lastMapPosition = m_inputChannelMap.end(); + + for (i=0; iChannelMessageEnd(m_outputChannelIdStrings[i], GetAutoSignalPropagation()-1); + } +} + +// **************************************************************** + +void SecretSharing::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_pad = parameters.GetValueWithDefault("AddPadding", true); + m_ida.IsolatedInitialize(parameters); +} + +size_t SecretSharing::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("SecretSharing"); + + SecByteBlock buf(UnsignedMin(256, length)); + unsigned int threshold = m_ida.GetThreshold(); + while (length > 0) + { + size_t len = STDMIN(length, buf.size()); + m_ida.ChannelData(0xffffffff, begin, len, false); + for (unsigned int i=0; i 0) + SecretSharing::Put(0); + } + m_ida.ChannelData(0xffffffff, NULLPTR, 0, true); + for (unsigned int i=0; iMessageEnd(GetAutoSignalPropagation()-1); +} + +// **************************************************************** + +void InformationDispersal::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_nextChannel = 0; + m_pad = parameters.GetValueWithDefault("AddPadding", true); + m_ida.IsolatedInitialize(parameters); +} + +size_t InformationDispersal::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("InformationDispersal"); + + while (length--) + { + m_ida.ChannelData(m_nextChannel, begin, 1, false); + begin++; + m_nextChannel++; + if (m_nextChannel == m_ida.GetThreshold()) + m_nextChannel = 0; + } + + if (messageEnd) + { + m_ida.SetAutoSignalPropagation(messageEnd-1); + if (m_pad) + InformationDispersal::Put(1); + for (word32 i=0; iMessageEnd(GetAutoSignalPropagation()-1); +} + +size_t PaddingRemover::Put2(const byte *begin, size_t length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("PaddingRemover"); + + const byte *const end = begin + length; + + if (m_possiblePadding) + { + size_t len = FindIfNot(begin, end, byte(0)) - begin; + m_zeroCount += len; + begin += len; + if (begin == end) + return 0; + + AttachedTransformation()->Put(1); + while (m_zeroCount--) + AttachedTransformation()->Put(0); + AttachedTransformation()->Put(*begin++); + m_possiblePadding = false; + } + + const byte *x = FindIfNot(RevIt(end), RevIt(begin), byte(0)).base(); + if (x != begin && *(x-1) == 1) + { + AttachedTransformation()->Put(begin, x-begin-1); + m_possiblePadding = true; + m_zeroCount = end - x; + } + else + AttachedTransformation()->Put(begin, end-begin); + + if (messageEnd) + { + m_possiblePadding = false; + Output(0, begin, length, messageEnd, blocking); + } + return 0; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ida.h b/extension/third_party/cryptopp/ida.h new file mode 100644 index 00000000..82b48df1 --- /dev/null +++ b/extension/third_party/cryptopp/ida.h @@ -0,0 +1,182 @@ +// ida.h - originally written and placed in the public domain by Wei Dai + +/// \file ida.h +/// \brief Classes for Rabin's Information Dispersal and Shamir's Secret Sharing algorithms + +#ifndef CRYPTOPP_IDA_H +#define CRYPTOPP_IDA_H + +#include "cryptlib.h" +#include "mqueue.h" +#include "filters.h" +#include "channels.h" +#include "secblock.h" +#include "gf2_32.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Secret sharing and information dispersal base class +/// \since Crypto++ 1.0 +class RawIDA : public AutoSignaling > > +{ +public: + RawIDA(BufferedTransformation *attachment=NULLPTR) + : m_channelsReady(0), m_channelsFinished(0), m_threshold (0) + {Detach(attachment);} + + unsigned int GetThreshold() const {return m_threshold;} + void AddOutputChannel(word32 channelId); + void ChannelData(word32 channelId, const byte *inString, size_t length, bool messageEnd); + lword InputBuffered(word32 channelId) const; + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("RawIDA"); + ChannelData(StringToWord(channel), begin, length, messageEnd != 0); + return 0; + } + +protected: + virtual void FlushOutputQueues(); + virtual void OutputMessageEnds(); + + unsigned int InsertInputChannel(word32 channelId); + unsigned int LookupInputChannel(word32 channelId) const; + void ComputeV(unsigned int); + void PrepareInterpolation(); + void ProcessInputQueues(); + + typedef std::map InputChannelMap; + InputChannelMap m_inputChannelMap; + InputChannelMap::iterator m_lastMapPosition; + std::vector m_inputQueues; + std::vector m_inputChannelIds, m_outputChannelIds, m_outputToInput; + std::vector m_outputChannelIdStrings; + std::vector m_outputQueues; + std::vector > m_v; + SecBlock m_u, m_w, m_y; + const GF2_32 m_gf32; + unsigned int m_channelsReady, m_channelsFinished; + int m_threshold; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretSharing : public CustomFlushPropagation +{ +public: + /// \brief Construct a SecretSharing + SecretSharing(RandomNumberGenerator &rng, int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_rng(rng), m_ida(new OutputProxy(*this, true)) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RandomNumberGenerator &m_rng; + RawIDA m_ida; + bool m_pad; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretRecovery : public RawIDA +{ +public: + /// \brief Construct a SecretRecovery + SecretRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; +}; + +/// a variant of Rabin's Information Dispersal Algorithm + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationDispersal : public CustomFlushPropagation +{ +public: + /// \brief Construct a InformationDispersal + InformationDispersal(int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_ida(new OutputProxy(*this, true)), m_pad(false), m_nextChannel(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RawIDA m_ida; + bool m_pad; + unsigned int m_nextChannel; +}; + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationRecovery : public RawIDA +{ +public: + /// \brief Construct a InformationRecovery + InformationRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment), m_pad(false) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; + ByteQueue m_queue; +}; + +class PaddingRemover : public Unflushable +{ +public: + PaddingRemover(BufferedTransformation *attachment=NULLPTR) + : m_possiblePadding(false), m_zeroCount(0) {Detach(attachment);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_possiblePadding = false;} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + // GetPossiblePadding() == false at the end of a message indicates incorrect padding + bool GetPossiblePadding() const {return m_possiblePadding;} + +private: + bool m_possiblePadding; + lword m_zeroCount; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/idea.cpp b/extension/third_party/cryptopp/idea.cpp new file mode 100644 index 00000000..dde2fdb4 --- /dev/null +++ b/extension/third_party/cryptopp/idea.cpp @@ -0,0 +1,191 @@ +// idea.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "idea.h" +#include "misc.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const int IDEA_KEYLEN=(6*IDEA::ROUNDS+4); // key schedule length in # of word16s + +#define low16(x) ((x)&0xffff) // compiler should be able to optimize this away if word is 16 bits +#define high16(x) ((x)>>16) + +CRYPTOPP_COMPILE_ASSERT(sizeof(IDEA::Word) >= 2); + +// should use an inline function but macros are still faster in MSVC 4.0 +#define DirectMUL(a,b) \ +{ \ + word32 p=(word32)low16(a)*b; \ + \ + if (p) \ + { \ + p = low16(p) - high16(p); \ + a = (IDEA::Word)p - (IDEA::Word)high16(p); \ + } \ + else \ + a = 1-a-b; \ +} + +#ifdef IDEA_LARGECACHE +volatile bool IDEA::Base::tablesBuilt = false; +word16 IDEA::Base::log[0x10000]; +word16 IDEA::Base::antilog[0x10000]; + +void IDEA::Base::BuildLogTables() +{ + if (tablesBuilt) + return; + else + { + tablesBuilt = true; + + IDEA::Word x=1; + word32 i; + + for (i=0; i<0x10000; i++) + { + antilog[i] = (word16)x; + DirectMUL(x, 3); + } + + for (i=0; i<0x10000; i++) + log[antilog[i]] = (word16)i; + } +} + +void IDEA::Base::LookupKeyLogs() +{ + IDEA::Word* Z=key; + int r=ROUNDS; + do + { + Z[0] = log[Z[0]]; + Z[3] = log[Z[3]]; + Z[4] = log[Z[4]]; + Z[5] = log[Z[5]]; + Z+=6; + } while (--r); + Z[0] = log[Z[0]]; + Z[3] = log[Z[3]]; +} + +inline void IDEA::Base::LookupMUL(IDEA::Word &a, IDEA::Word b) +{ + a = antilog[low16(log[low16(a)]+b)]; +} +#endif // IDEA_LARGECACHE + +void IDEA::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + +#ifdef IDEA_LARGECACHE + BuildLogTables(); +#endif + + EnKey(userKey); + + if (!IsForwardTransformation()) + DeKey(); + +#ifdef IDEA_LARGECACHE + LookupKeyLogs(); +#endif +} + +void IDEA::Base::EnKey (const byte *userKey) +{ + unsigned int i; + + for (i=0; i<8; i++) + m_key[i] = ((IDEA::Word)userKey[2*i]<<8) | userKey[2*i+1]; + + for (; i> 7)); + } +} + +static IDEA::Word MulInv(IDEA::Word x) +{ + IDEA::Word y=x; + for (unsigned i=0; i<15; i++) + { + DirectMUL(y,low16(y)); + DirectMUL(y,x); + } + return low16(y); +} + +static inline IDEA::Word AddInv(IDEA::Word x) +{ + return low16(0-x); +} + +void IDEA::Base::DeKey() +{ + FixedSizeSecBlock tempkey; + size_t i; + + for (i=0; i0)]); + tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2-(i>0)]); + tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); + tempkey[i*6+4] = m_key[(ROUNDS-1-i)*6+4]; + tempkey[i*6+5] = m_key[(ROUNDS-1-i)*6+5]; + } + + tempkey[i*6+0] = MulInv(m_key[(ROUNDS-i)*6+0]); + tempkey[i*6+1] = AddInv(m_key[(ROUNDS-i)*6+1]); + tempkey[i*6+2] = AddInv(m_key[(ROUNDS-i)*6+2]); + tempkey[i*6+3] = MulInv(m_key[(ROUNDS-i)*6+3]); + + m_key = tempkey; +} + +#ifdef IDEA_LARGECACHE +#define MUL(a,b) LookupMUL(a,b) +#else +#define MUL(a,b) DirectMUL(a,b) +#endif + +void IDEA::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut Block; + + const IDEA::Word *key = m_key; + IDEA::Word x0,x1,x2,x3,t0,t1; + Block::Get(inBlock)(x0)(x1)(x2)(x3); + + for (unsigned int i=0; i, public FixedKeyLength<16>, public FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "IDEA";} +}; + +/// \brief IDEA block cipher +/// \sa IDEA +/// \since Crypto++ 1.0 +class IDEA : public IDEA_Info, public BlockCipherDocumentation +{ +public: // made public for internal purposes +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + typedef word Word; +#else + typedef hword Word; +#endif + +private: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + unsigned int OptimalDataAlignment() const {return 2;} + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + private: + void EnKey(const byte *); + void DeKey(); + FixedSizeSecBlock m_key; + + #ifdef IDEA_LARGECACHE + static inline void LookupMUL(word &a, word b); + void LookupKeyLogs(); + static void BuildLogTables(); + static volatile bool tablesBuilt; + static word16 log[0x10000], antilog[0x10000]; + #endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef IDEA::Encryption IDEAEncryption; +typedef IDEA::Decryption IDEADecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/integer.cpp b/extension/third_party/cryptopp/integer.cpp new file mode 100644 index 00000000..9ab70e17 --- /dev/null +++ b/extension/third_party/cryptopp/integer.cpp @@ -0,0 +1,4894 @@ +// integer.cpp - originally written and placed in the public domain by Wei Dai +// contains public domain code contributed by Alister Lee and Leonard Janke + +// Notes by JW: The Integer class needs to do two things. First, it needs +// to set function pointers on some platforms, like X86 and X64. The +// function pointers select a fast multiply and addition based on the cpu. +// Second, it wants to create Integer::Zero(), Integer::One() and +// Integer::Two(). +// The function pointers are initialized in the InitializeInteger class by +// calling SetFunctionPointers(). The call to SetFunctionPointers() is +// guarded to run once using a double-checked pattern. We don't use C++ +// std::call_once due to bad interactions between libstdc++, glibc and +// pthreads. The bad interactions were causing crashes for us on platforms +// like Sparc and PowerPC. Since we are only setting function pointers we +// don't have to worry about leaking memory. The worst case seems to be the +// pointers gets written twice until the init flag is set and visible to +// all threads. +// For Integer::Zero(), Integer::One() and Integer::Two(), we use one of three +// strategies. First, if initialization priorities are available then we use +// them. Initialization priorities are init_priority() on Linux and init_seg() +// on Windows. OS X and several other platforms lack them. Initialization +// priorities are platform specific but they are also the most trouble free +// with determisitic destruction. +// Second, if C++11 dynamic initialization is available, then we use it. After +// the std::call_once fiasco we moved to dynamic initialization to avoid +// unknown troubles platforms that are tested less frequently. In addition +// Microsoft platforms mostly do not provide dynamic initialization. +// The MSDN docs claim they do but they don't in practice because we need +// Visual Studio 2017 and Windows 10 or above. +// Third, we fall back to Wei's original code of a Singleton. Wei's original +// code was much simpler. It simply used the Singleton pattern, but it always +// produced memory findings on some platforms. The Singleton generates memory +// findings because it uses a Create On First Use pattern (a dumb Nifty +// Counter) and the compiler had to be smart enough to fold them to return +// the same object. Unix and Linux compilers do a good job of folding objects, +// but Microsoft compilers do a rather poor job for some versions of the +// compiler. +// Another problem with the Singleton is resource destruction requires running +// resource acquisition in reverse. For resources provided through the +// Singletons, there is no way to express the dependency order to safely +// destroy resources. (That's one of the problems C++11 dynamic +// intitialization with concurrent execution is supposed to solve). +// The final problem with Singletons is resource/memory exhaustion in languages +// like Java and .Net. Java and .Net load and unload a native DLL hundreds or +// thousands of times during the life of a program. Each load produces a +// memory leak and they can add up quickly. If they library is being used in +// Java or .Net then Singleton must be avoided at all costs. +// +// The code below has a path cut-in for BMI2 using mulx and adcx instructions. +// There was a modest speedup of approximately 0.03 ms in public key Integer +// operations. We had to disable BMI2 for the moment because some OS X machines +// were advertising BMI/BMI2 support but caused SIGILL's at runtime. Also see +// https://github.com/weidai11/cryptopp/issues/850. + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "integer.h" +#include "secblock.h" +#include "modarith.h" +#include "nbtheory.h" +#include "smartptr.h" +#include "algparam.h" +#include "filters.h" +#include "stdcpp.h" +#include "asn.h" +#include "oids.h" +#include "words.h" +#include "pubkey.h" // for P1363_KDF2 +#include "sha.h" +#include "cpu.h" +#include "misc.h" + +#include + +#if (_MSC_VER >= 1400) && !defined(_M_ARM) + #include +#endif + +#ifdef __DECCXX + #include +#endif + +// "Error: The operand ___LKDB cannot be assigned to", +// http://github.com/weidai11/cryptopp/issues/188 +#if (__SUNPRO_CC >= 0x5130) +# define MAYBE_CONST +# define MAYBE_UNCONST_CAST(x) const_cast(x) +#else +# define MAYBE_CONST const +# define MAYBE_UNCONST_CAST(x) x +#endif + +// "Inline assembly operands don't work with .intel_syntax", +// http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +# undef CRYPTOPP_SSSE3_ASM_AVAILABLE +#else +# define CRYPTOPP_INTEGER_SSE2 (CRYPTOPP_SSE2_ASM_AVAILABLE && (CRYPTOPP_BOOL_X86)) +#endif + +// ***************** C++ Static Initialization ******************** + +NAMESPACE_BEGIN(CryptoPP) + +// Function body near the middle of the file +static void SetFunctionPointers(); + +// Use a double-checked pattern. We are not leaking anything so it +// does not matter if a pointer is written twice during a race. +// Avoid std::call_once due to too many problems on platforms like +// Solaris and Sparc. Also see +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=66146 and +// http://github.com/weidai11/cryptopp/issues/707. +InitializeInteger::InitializeInteger() +{ + static bool s_flag; + MEMORY_BARRIER(); + if (s_flag == false) + { + SetFunctionPointers(); + s_flag = true; + MEMORY_BARRIER(); + } +} + +template +struct NewInteger +{ + Integer * operator()() const + { + return new Integer(i); + } +}; + +// ***************** Library code ******************** + +inline static int Compare(const word *A, const word *B, size_t N) +{ + while (N--) + if (A[N] > B[N]) + return 1; + else if (A[N] < B[N]) + return -1; + + return 0; +} + +inline static int Increment(word *A, size_t N, word B=1) +{ + CRYPTOPP_ASSERT(N); + word t = A[0]; + A[0] = t+B; + if (A[0] >= t) + return 0; + for (unsigned i=1; i>(WORD_BITS-1)); d##0 = 2*d##0 + (c>>(WORD_BITS-1)); c *= 2; + #endif + #ifndef Acc2WordsBy2 + #define Acc2WordsBy2(a, b) a##0 += b##0; a##1 += a##0 < b##0; a##1 += b##1; + #endif + #define AddWithCarry(u, a, b) {word t = a+b; u##0 = t + u##1; u##1 = (ta) + (u##0>t);} + #define GetCarry(u) u##1 + #define GetBorrow(u) u##1 +#else + #define Declare2Words(x) dword x; + #if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64)) + #define MultiplyWords(p, a, b) p = __emulu(a, b); + #else + #define MultiplyWords(p, a, b) p = (dword)a*b; + #endif + #define AssignWord(a, b) a = b; + #define Add2WordsBy1(a, b, c) a = b + c; + #define Acc2WordsBy2(a, b) a += b; + #define LowWord(a) word(a) + #define HighWord(a) word(a>>WORD_BITS) + #define Double3Words(c, d) d = 2*d + (c>>(WORD_BITS-1)); c *= 2; + #define AddWithCarry(u, a, b) u = dword(a) + b + GetCarry(u); + #define SubtractWithBorrow(u, a, b) u = dword(a) - b - GetBorrow(u); + #define GetCarry(u) HighWord(u) + #define GetBorrow(u) word(u>>(WORD_BITS*2-1)) +#endif +#ifndef MulAcc + #define MulAcc(c, d, a, b) MultiplyWords(p, a, b); Acc2WordsBy1(p, c); c = LowWord(p); Acc2WordsBy1(d, HighWord(p)); +#endif +#ifndef Acc2WordsBy1 + #define Acc2WordsBy1(a, b) Add2WordsBy1(a, a, b) +#endif +#ifndef Acc3WordsBy2 + #define Acc3WordsBy2(c, d, e) Acc2WordsBy1(e, c); c = LowWord(e); Add2WordsBy1(e, d, HighWord(e)); +#endif + +class DWord +{ +public: +#if defined(CRYPTOPP_NATIVE_DWORD_AVAILABLE) + DWord() {std::memset(&m_whole, 0x00, sizeof(m_whole));} +#else + DWord() {std::memset(&m_halfs, 0x00, sizeof(m_halfs));} +#endif + +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + explicit DWord(word low) : m_whole(low) { } +#else + explicit DWord(word low) + { + m_halfs.high = 0; + m_halfs.low = low; + } +#endif + +#if defined(CRYPTOPP_NATIVE_DWORD_AVAILABLE) + DWord(word low, word high) : m_whole() +#else + DWord(word low, word high) : m_halfs() +#endif + { +#if defined(CRYPTOPP_NATIVE_DWORD_AVAILABLE) +# if (CRYPTOPP_LITTLE_ENDIAN) + const word t[2] = {low,high}; + memcpy(&m_whole, t, sizeof(m_whole)); +# else + const word t[2] = {high,low}; + memcpy(&m_whole, t, sizeof(m_whole)); +# endif +#else + m_halfs.low = low; + m_halfs.high = high; +#endif + } + + static DWord Multiply(word a, word b) + { + DWord r; + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + r.m_whole = (dword)a * b; + #elif defined(MultiplyWordsLoHi) + MultiplyWordsLoHi(r.m_halfs.low, r.m_halfs.high, a, b); + #else + CRYPTOPP_ASSERT(0); + #endif + return r; + } + + static DWord MultiplyAndAdd(word a, word b, word c) + { + DWord r = Multiply(a, b); + return r += c; + } + + DWord & operator+=(word a) + { + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + m_whole = m_whole + a; + #else + m_halfs.low += a; + m_halfs.high += (m_halfs.low < a); + #endif + return *this; + } + + DWord operator+(word a) + { + DWord r; + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + r.m_whole = m_whole + a; + #else + r.m_halfs.low = m_halfs.low + a; + r.m_halfs.high = m_halfs.high + (r.m_halfs.low < a); + #endif + return r; + } + + DWord operator-(DWord a) + { + DWord r; + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + r.m_whole = m_whole - a.m_whole; + #else + r.m_halfs.low = m_halfs.low - a.m_halfs.low; + r.m_halfs.high = m_halfs.high - a.m_halfs.high - (r.m_halfs.low > m_halfs.low); + #endif + return r; + } + + DWord operator-(word a) + { + DWord r; + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + r.m_whole = m_whole - a; + #else + r.m_halfs.low = m_halfs.low - a; + r.m_halfs.high = m_halfs.high - (r.m_halfs.low > m_halfs.low); + #endif + return r; + } + + // returns quotient, which must fit in a word + word operator/(word divisor); + + word operator%(word a); + + bool operator!() const + { + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + return !m_whole; + #else + return !m_halfs.high && !m_halfs.low; + #endif + } + + // TODO: When NATIVE_DWORD is in effect, we access high and low, which are inactive + // union members, and that's UB. Also see http://stackoverflow.com/q/11373203. + word GetLowHalf() const {return m_halfs.low;} + word GetHighHalf() const {return m_halfs.high;} + word GetHighHalfAsBorrow() const {return 0-m_halfs.high;} + +private: + // Issue 274, "Types cannot be declared in anonymous union", + // http://github.com/weidai11/cryptopp/issues/274 + // Thanks to Martin Bonner at http://stackoverflow.com/a/39507183 + struct half_words + { + #if (CRYPTOPP_LITTLE_ENDIAN) + word low; + word high; + #else + word high; + word low; + #endif + }; + union + { + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + dword m_whole; + #endif + half_words m_halfs; + }; +}; + +class Word +{ +public: + Word() : m_whole(0) {} + Word(word value) : m_whole(value) {} + Word(hword low, hword high) : m_whole(low | (word(high) << (WORD_BITS/2))) {} + + static Word Multiply(hword a, hword b) + { + Word r; + r.m_whole = (word)a * b; + return r; + } + + Word operator-(Word a) + { + Word r; + r.m_whole = m_whole - a.m_whole; + return r; + } + + Word operator-(hword a) + { + Word r; + r.m_whole = m_whole - a; + return r; + } + + // returns quotient, which must fit in a word + hword operator/(hword divisor) + { + return hword(m_whole / divisor); + } + + bool operator!() const + { + return !m_whole; + } + + word GetWhole() const {return m_whole;} + hword GetLowHalf() const {return hword(m_whole);} + hword GetHighHalf() const {return hword(m_whole>>(WORD_BITS/2));} + hword GetHighHalfAsBorrow() const {return 0-hword(m_whole>>(WORD_BITS/2));} + +private: + word m_whole; +}; + +// do a 3 word by 2 word divide, returns quotient and leaves remainder in A +template +S DivideThreeWordsByTwo(S *A, S B0, S B1, D *dummy=NULLPTR) +{ + CRYPTOPP_UNUSED(dummy); + + // Assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a S + CRYPTOPP_ASSERT(A[2] < B1 || (A[2]==B1 && A[1] < B0)); + + // Profiling guided the flow below. + + // estimate the quotient: do a 2 S by 1 S divide. + S Q; bool pre = (S(B1+1) == 0); + if (B1 > 0 && !pre) + Q = D(A[1], A[2]) / S(B1+1); + else if (pre) + Q = A[2]; + else + Q = D(A[0], A[1]) / B0; + + // now subtract Q*B from A + D p = D::Multiply(B0, Q); + D u = (D) A[0] - p.GetLowHalf(); + A[0] = u.GetLowHalf(); + u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - D::Multiply(B1, Q); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + + // Q <= actual quotient, so fix it + while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) + { + u = (D) A[0] - B0; + A[0] = u.GetLowHalf(); + u = (D) A[1] - B1 - u.GetHighHalfAsBorrow(); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + Q++; + CRYPTOPP_ASSERT(Q); // shouldn't overflow + } + + return Q; +} + +// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1 +template +inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B) +{ + // Profiling guided the flow below. + + if (!!B) + { + S Q[2]; + T[0] = Al.GetLowHalf(); + T[1] = Al.GetHighHalf(); + T[2] = Ah.GetLowHalf(); + T[3] = Ah.GetHighHalf(); + Q[1] = DivideThreeWordsByTwo(T+1, B.GetLowHalf(), B.GetHighHalf()); + Q[0] = DivideThreeWordsByTwo(T, B.GetLowHalf(), B.GetHighHalf()); + return D(Q[0], Q[1]); + } + else // if divisor is 0, we assume divisor==2**(2*WORD_BITS) + { + return D(Ah.GetLowHalf(), Ah.GetHighHalf()); + } +} + +// returns quotient, which must fit in a word +inline word DWord::operator/(word a) +{ + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + return word(m_whole / a); + #else + hword r[4]; + return DivideFourWordsByTwo(r, m_halfs.low, m_halfs.high, a).GetWhole(); + #endif +} + +inline word DWord::operator%(word a) +{ + #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + return word(m_whole % a); + #else + if (a < (word(1) << (WORD_BITS/2))) + { + hword h = hword(a); + word r = m_halfs.high % h; + r = ((m_halfs.low >> (WORD_BITS/2)) + (r << (WORD_BITS/2))) % h; + return hword((hword(m_halfs.low) + (r << (WORD_BITS/2))) % h); + } + else + { + hword r[4]; + DivideFourWordsByTwo(r, m_halfs.low, m_halfs.high, a); + return Word(r[0], r[1]).GetWhole(); + } + #endif +} + +// ******************************************************** + +// Use some tricks to share assembly code between MSVC, GCC, Clang and Sun CC. +#if defined(__GNUC__) + #define AddPrologue \ + int result; \ + __asm__ __volatile__ \ + ( \ + INTEL_NOPREFIX + #define AddEpilogue \ + ATT_PREFIX \ + : "=a" (result)\ + : "d" (C), "a" (A), "D" (B), "c" (N) \ + : "%esi", "memory", "cc" \ + );\ + return result; + #define MulPrologue \ + __asm__ __volatile__ \ + ( \ + INTEL_NOPREFIX \ + AS1( push ebx) \ + AS2( mov ebx, edx) + #define MulEpilogue \ + AS1( pop ebx) \ + ATT_PREFIX \ + : \ + : "d" (s_maskLow16), "c" (C), "a" (A), "D" (B) \ + : "%esi", "memory", "cc" \ + ); + #define SquPrologue MulPrologue + #define SquEpilogue \ + AS1( pop ebx) \ + ATT_PREFIX \ + : \ + : "d" (s_maskLow16), "c" (C), "a" (A) \ + : "%esi", "%edi", "memory", "cc" \ + ); + #define TopPrologue MulPrologue + #define TopEpilogue \ + AS1( pop ebx) \ + ATT_PREFIX \ + : \ + : "d" (s_maskLow16), "c" (C), "a" (A), "D" (B), "S" (L) \ + : "memory", "cc" \ + ); +#else + #define AddPrologue \ + __asm push edi \ + __asm push esi \ + __asm mov eax, [esp+12] \ + __asm mov edi, [esp+16] + #define AddEpilogue \ + __asm pop esi \ + __asm pop edi \ + __asm ret 8 + #define SaveEBX + #define RestoreEBX + #define SquPrologue \ + AS2( mov eax, A) \ + AS2( mov ecx, C) \ + SaveEBX \ + AS2( lea ebx, s_maskLow16) + #define MulPrologue \ + AS2( mov eax, A) \ + AS2( mov edi, B) \ + AS2( mov ecx, C) \ + SaveEBX \ + AS2( lea ebx, s_maskLow16) + #define TopPrologue \ + AS2( mov eax, A) \ + AS2( mov edi, B) \ + AS2( mov ecx, C) \ + AS2( mov esi, L) \ + SaveEBX \ + AS2( lea ebx, s_maskLow16) + #define SquEpilogue RestoreEBX + #define MulEpilogue RestoreEBX + #define TopEpilogue RestoreEBX +#endif + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +int Baseline_Add(size_t N, word *C, const word *A, const word *B); +int Baseline_Sub(size_t N, word *C, const word *A, const word *B); +} +#elif defined(CRYPTOPP_X64_ASM_AVAILABLE) && defined(__GNUC__) && defined(CRYPTOPP_WORD128_AVAILABLE) +int Baseline_Add(size_t N, word *C, const word *A, const word *B) +{ + word result; + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS1( neg %1) + ASJ( jz, 1, f) + AS2( mov %0,[%3+8*%1]) + AS2( add %0,[%4+8*%1]) + AS2( mov [%2+8*%1],%0) + ASL(0) + AS2( mov %0,[%3+8*%1+8]) + AS2( adc %0,[%4+8*%1+8]) + AS2( mov [%2+8*%1+8],%0) + AS2( lea %1,[%1+2]) + ASJ( jrcxz, 1, f) + AS2( mov %0,[%3+8*%1]) + AS2( adc %0,[%4+8*%1]) + AS2( mov [%2+8*%1],%0) + ASJ( jmp, 0, b) + ASL(1) + AS2( mov %0, 0) + AS2( adc %0, %0) + ATT_NOPREFIX + : "=&r" (result), "+c" (N) + : "r" (C+N), "r" (A+N), "r" (B+N) + : "memory", "cc" + ); + return (int)result; +} + +int Baseline_Sub(size_t N, word *C, const word *A, const word *B) +{ + word result; + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS1( neg %1) + ASJ( jz, 1, f) + AS2( mov %0,[%3+8*%1]) + AS2( sub %0,[%4+8*%1]) + AS2( mov [%2+8*%1],%0) + ASL(0) + AS2( mov %0,[%3+8*%1+8]) + AS2( sbb %0,[%4+8*%1+8]) + AS2( mov [%2+8*%1+8],%0) + AS2( lea %1,[%1+2]) + ASJ( jrcxz, 1, f) + AS2( mov %0,[%3+8*%1]) + AS2( sbb %0,[%4+8*%1]) + AS2( mov [%2+8*%1],%0) + ASJ( jmp, 0, b) + ASL(1) + AS2( mov %0, 0) + AS2( adc %0, %0) + ATT_NOPREFIX + : "=&r" (result), "+c" (N) + : "r" (C+N), "r" (A+N), "r" (B+N) + : "memory", "cc" + ); + return (int)result; +} +#elif defined(CRYPTOPP_X86_ASM_AVAILABLE) && CRYPTOPP_BOOL_X86 +CRYPTOPP_NAKED int CRYPTOPP_FASTCALL Baseline_Add(size_t N, word *C, const word *A, const word *B) +{ + AddPrologue + + // now: eax = A, edi = B, edx = C, ecx = N + AS2( lea eax, [eax+4*ecx]) + AS2( lea edi, [edi+4*ecx]) + AS2( lea edx, [edx+4*ecx]) + + AS1( neg ecx) // ecx is negative index + AS2( test ecx, 2) // this clears carry flag + ASJ( jz, 0, f) + AS2( sub ecx, 2) + ASJ( jmp, 1, f) + + ASL(0) + ASJ( jecxz, 2, f) // loop until ecx overflows and becomes zero + AS2( mov esi,[eax+4*ecx]) + AS2( adc esi,[edi+4*ecx]) + AS2( mov [edx+4*ecx],esi) + AS2( mov esi,[eax+4*ecx+4]) + AS2( adc esi,[edi+4*ecx+4]) + AS2( mov [edx+4*ecx+4],esi) + ASL(1) + AS2( mov esi,[eax+4*ecx+8]) + AS2( adc esi,[edi+4*ecx+8]) + AS2( mov [edx+4*ecx+8],esi) + AS2( mov esi,[eax+4*ecx+12]) + AS2( adc esi,[edi+4*ecx+12]) + AS2( mov [edx+4*ecx+12],esi) + + AS2( lea ecx,[ecx+4]) // advance index, avoid inc which causes slowdown on Intel Core 2 + ASJ( jmp, 0, b) + + ASL(2) + AS2( mov eax, 0) + AS1( setc al) // store carry into eax (return result register) + + AddEpilogue + + // http://github.com/weidai11/cryptopp/issues/340 + CRYPTOPP_UNUSED(A); CRYPTOPP_UNUSED(B); + CRYPTOPP_UNUSED(C); CRYPTOPP_UNUSED(N); +} + +CRYPTOPP_NAKED int CRYPTOPP_FASTCALL Baseline_Sub(size_t N, word *C, const word *A, const word *B) +{ + AddPrologue + + // now: eax = A, edi = B, edx = C, ecx = N + AS2( lea eax, [eax+4*ecx]) + AS2( lea edi, [edi+4*ecx]) + AS2( lea edx, [edx+4*ecx]) + + AS1( neg ecx) // ecx is negative index + AS2( test ecx, 2) // this clears carry flag + ASJ( jz, 0, f) + AS2( sub ecx, 2) + ASJ( jmp, 1, f) + + ASL(0) + ASJ( jecxz, 2, f) // loop until ecx overflows and becomes zero + AS2( mov esi,[eax+4*ecx]) + AS2( sbb esi,[edi+4*ecx]) + AS2( mov [edx+4*ecx],esi) + AS2( mov esi,[eax+4*ecx+4]) + AS2( sbb esi,[edi+4*ecx+4]) + AS2( mov [edx+4*ecx+4],esi) + ASL(1) + AS2( mov esi,[eax+4*ecx+8]) + AS2( sbb esi,[edi+4*ecx+8]) + AS2( mov [edx+4*ecx+8],esi) + AS2( mov esi,[eax+4*ecx+12]) + AS2( sbb esi,[edi+4*ecx+12]) + AS2( mov [edx+4*ecx+12],esi) + + AS2( lea ecx,[ecx+4]) // advance index, avoid inc which causes slowdown on Intel Core 2 + ASJ( jmp, 0, b) + + ASL(2) + AS2( mov eax, 0) + AS1( setc al) // store carry into eax (return result register) + + AddEpilogue + + // http://github.com/weidai11/cryptopp/issues/340 + CRYPTOPP_UNUSED(A); CRYPTOPP_UNUSED(B); + CRYPTOPP_UNUSED(C); CRYPTOPP_UNUSED(N); +} + +#if CRYPTOPP_INTEGER_SSE2 +CRYPTOPP_NAKED int CRYPTOPP_FASTCALL SSE2_Add(size_t N, word *C, const word *A, const word *B) +{ + AddPrologue + + // now: eax = A, edi = B, edx = C, ecx = N + AS2( lea eax, [eax+4*ecx]) + AS2( lea edi, [edi+4*ecx]) + AS2( lea edx, [edx+4*ecx]) + + AS1( neg ecx) // ecx is negative index + AS2( pxor mm2, mm2) + ASJ( jz, 2, f) + AS2( test ecx, 2) // this clears carry flag + ASJ( jz, 0, f) + AS2( sub ecx, 2) + ASJ( jmp, 1, f) + + ASL(0) + AS2( movd mm0, DWORD PTR [eax+4*ecx]) + AS2( movd mm1, DWORD PTR [edi+4*ecx]) + AS2( paddq mm0, mm1) + AS2( paddq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx], mm2) + AS2( psrlq mm2, 32) + + AS2( movd mm0, DWORD PTR [eax+4*ecx+4]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+4]) + AS2( paddq mm0, mm1) + AS2( paddq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx+4], mm2) + AS2( psrlq mm2, 32) + + ASL(1) + AS2( movd mm0, DWORD PTR [eax+4*ecx+8]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+8]) + AS2( paddq mm0, mm1) + AS2( paddq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx+8], mm2) + AS2( psrlq mm2, 32) + + AS2( movd mm0, DWORD PTR [eax+4*ecx+12]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+12]) + AS2( paddq mm0, mm1) + AS2( paddq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx+12], mm2) + AS2( psrlq mm2, 32) + + AS2( add ecx, 4) + ASJ( jnz, 0, b) + + ASL(2) + AS2( movd eax, mm2) + AS1( emms) + + AddEpilogue + + // http://github.com/weidai11/cryptopp/issues/340 + CRYPTOPP_UNUSED(A); CRYPTOPP_UNUSED(B); + CRYPTOPP_UNUSED(C); CRYPTOPP_UNUSED(N); +} +CRYPTOPP_NAKED int CRYPTOPP_FASTCALL SSE2_Sub(size_t N, word *C, const word *A, const word *B) +{ + AddPrologue + + // now: eax = A, edi = B, edx = C, ecx = N + AS2( lea eax, [eax+4*ecx]) + AS2( lea edi, [edi+4*ecx]) + AS2( lea edx, [edx+4*ecx]) + + AS1( neg ecx) // ecx is negative index + AS2( pxor mm2, mm2) + ASJ( jz, 2, f) + AS2( test ecx, 2) // this clears carry flag + ASJ( jz, 0, f) + AS2( sub ecx, 2) + ASJ( jmp, 1, f) + + ASL(0) + AS2( movd mm0, DWORD PTR [eax+4*ecx]) + AS2( movd mm1, DWORD PTR [edi+4*ecx]) + AS2( psubq mm0, mm1) + AS2( psubq mm0, mm2) + AS2( movd DWORD PTR [edx+4*ecx], mm0) + AS2( psrlq mm0, 63) + + AS2( movd mm2, DWORD PTR [eax+4*ecx+4]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+4]) + AS2( psubq mm2, mm1) + AS2( psubq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx+4], mm2) + AS2( psrlq mm2, 63) + + ASL(1) + AS2( movd mm0, DWORD PTR [eax+4*ecx+8]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+8]) + AS2( psubq mm0, mm1) + AS2( psubq mm0, mm2) + AS2( movd DWORD PTR [edx+4*ecx+8], mm0) + AS2( psrlq mm0, 63) + + AS2( movd mm2, DWORD PTR [eax+4*ecx+12]) + AS2( movd mm1, DWORD PTR [edi+4*ecx+12]) + AS2( psubq mm2, mm1) + AS2( psubq mm2, mm0) + AS2( movd DWORD PTR [edx+4*ecx+12], mm2) + AS2( psrlq mm2, 63) + + AS2( add ecx, 4) + ASJ( jnz, 0, b) + + ASL(2) + AS2( movd eax, mm2) + AS1( emms) + + AddEpilogue + + // http://github.com/weidai11/cryptopp/issues/340 + CRYPTOPP_UNUSED(A); CRYPTOPP_UNUSED(B); + CRYPTOPP_UNUSED(C); CRYPTOPP_UNUSED(N); +} +#endif // CRYPTOPP_INTEGER_SSE2 +#else // CRYPTOPP_SSE2_ASM_AVAILABLE +int CRYPTOPP_FASTCALL Baseline_Add(size_t N, word *C, const word *A, const word *B) +{ + CRYPTOPP_ASSERT (N%2 == 0); + + Declare2Words(u); + AssignWord(u, 0); + for (size_t i=0; i=2 && N%2==0); + + if (N <= s_recursionLimit) + s_pMul[N/4](R, A, B); + else + { + const size_t N2 = N/2; + + size_t AN2 = Compare(A0, A1, N2) > 0 ? 0 : N2; + Subtract(R0, A + AN2, A + (N2 ^ AN2), N2); + + size_t BN2 = Compare(B0, B1, N2) > 0 ? 0 : N2; + Subtract(R1, B + BN2, B + (N2 ^ BN2), N2); + + RecursiveMultiply(R2, T2, A1, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + RecursiveMultiply(R0, T2, A0, B0, N2); + + // now T[01] holds (A1-A0)*(B0-B1), R[01] holds A0*B0, R[23] holds A1*B1 + + int c2 = Add(R2, R2, R1, N2); + int c3 = c2; + c2 += Add(R1, R2, R0, N2); + c3 += Add(R2, R2, R3, N2); + + if (AN2 == BN2) + c3 -= Subtract(R1, R1, T0, N); + else + c3 += Add(R1, R1, T0, N); + + c3 += Increment(R2, N2, c2); + CRYPTOPP_ASSERT (c3 >= 0 && c3 <= 2); + Increment(R3, N2, c3); + } +} + +// R[2*N] - result = A*A +// T[2*N] - temporary work space +// A[N] --- number to be squared + +void RecursiveSquare(word *R, word *T, const word *A, size_t N) +{ + CRYPTOPP_ASSERT(N && N%2==0); + + if (N <= s_recursionLimit) + s_pSqu[N/4](R, A); + else + { + const size_t N2 = N/2; + + RecursiveSquare(R0, T2, A0, N2); + RecursiveSquare(R2, T2, A1, N2); + RecursiveMultiply(T0, T2, A0, A1, N2); + + int carry = Add(R1, R1, T0, N); + carry += Add(R1, R1, T0, N); + Increment(R3, N2, carry); + } +} + +// R[N] - bottom half of A*B +// T[3*N/2] - temporary work space +// A[N] - multiplier +// B[N] - multiplicant + +void RecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, size_t N) +{ + CRYPTOPP_ASSERT(N>=2 && N%2==0); + + if (N <= s_recursionLimit) + s_pBot[N/4](R, A, B); + else + { + const size_t N2 = N/2; + + RecursiveMultiply(R, T, A0, B0, N2); + RecursiveMultiplyBottom(T0, T1, A1, B0, N2); + Add(R1, R1, T0, N2); + RecursiveMultiplyBottom(T0, T1, A0, B1, N2); + Add(R1, R1, T0, N2); + } +} + +// R[N] --- upper half of A*B +// T[2*N] - temporary work space +// L[N] --- lower half of A*B +// A[N] --- multiplier +// B[N] --- multiplicant + +void MultiplyTop(word *R, word *T, const word *L, const word *A, const word *B, size_t N) +{ + CRYPTOPP_ASSERT(N>=2 && N%2==0); + + if (N <= s_recursionLimit) + s_pTop[N/4](R, A, B, L[N-1]); + else + { + const size_t N2 = N/2; + + size_t AN2 = Compare(A0, A1, N2) > 0 ? 0 : N2; + Subtract(R0, A + AN2, A + (N2 ^ AN2), N2); + + size_t BN2 = Compare(B0, B1, N2) > 0 ? 0 : N2; + Subtract(R1, B + BN2, B + (N2 ^ BN2), N2); + + RecursiveMultiply(T0, T2, R0, R1, N2); + RecursiveMultiply(R0, T2, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1) = A1*B0+A0*B1-A1*B1-A0*B0, R[01] holds A1*B1 + + int t, c3; + int c2 = Subtract(T2, L+N2, L, N2); + + if (AN2 == BN2) + { + c2 -= Add(T2, T2, T0, N2); + t = (Compare(T2, R0, N2) == -1); + c3 = t - Subtract(T2, T2, T1, N2); + } + else + { + c2 += Subtract(T2, T2, T0, N2); + t = (Compare(T2, R0, N2) == -1); + c3 = t + Add(T2, T2, T1, N2); + } + + c2 += t; + if (c2 >= 0) + c3 += Increment(T2, N2, c2); + else + c3 -= Decrement(T2, N2, -c2); + c3 += Add(R0, T2, R1, N2); + + CRYPTOPP_ASSERT (c3 >= 0 && c3 <= 2); + Increment(R1, N2, c3); + } +} + +inline void Multiply(word *R, word *T, const word *A, const word *B, size_t N) +{ + RecursiveMultiply(R, T, A, B, N); +} + +inline void Square(word *R, word *T, const word *A, size_t N) +{ + RecursiveSquare(R, T, A, N); +} + +inline void MultiplyBottom(word *R, word *T, const word *A, const word *B, size_t N) +{ + RecursiveMultiplyBottom(R, T, A, B, N); +} + +// R[NA+NB] - result = A*B +// T[NA+NB] - temporary work space +// A[NA] ---- multiplier +// B[NB] ---- multiplicant + +void AsymmetricMultiply(word *R, word *T, const word *A, size_t NA, const word *B, size_t NB) +{ + if (NA == NB) + { + // Profiling guided the flow below. + if (A != B) + Multiply(R, T, A, B, NA); + else + Square(R, T, A, NA); + + return; + } + + if (NA > NB) + { + std::swap(A, B); + std::swap(NA, NB); + } + + CRYPTOPP_ASSERT(NB % NA == 0); + + if (NA==2 && !A[1]) + { + // Profiling guided the flow below. + switch (A[0]) + { + default: + R[NB] = LinearMultiply(R, B, A[0], NB); + R[NB+1] = 0; + return; + case 0: + SetWords(R, 0, NB+2); + return; + case 1: + CopyWords(R, B, NB); + R[NB] = R[NB+1] = 0; + return; + } + } + + size_t i; + if ((NB/NA)%2 == 0) + { + Multiply(R, T, A, B, NA); + CopyWords(T+2*NA, R+NA, NA); + + for (i=2*NA; i=4); + +#define M0 M +#define M1 (M+N2) +#define V0 V +#define V1 (V+N2) + +#define X0 X +#define X1 (X+N2) +#define X2 (X+N) +#define X3 (X+N+N2) + + const size_t N2 = N/2; + Multiply(T0, T2, V0, X3, N2); + int c2 = Add(T0, T0, X0, N); + MultiplyBottom(T3, T2, T0, U, N2); + MultiplyTop(T2, R, T0, T3, M0, N2); + c2 -= Subtract(T2, T1, T2, N2); + Multiply(T0, R, T3, M1, N2); + c2 -= Subtract(T0, T2, T0, N2); + int c3 = -(int)Subtract(T1, X2, T1, N2); + Multiply(R0, T2, V1, X3, N2); + c3 += Add(R, R, T, N); + + if (c2>0) + c3 += Increment(R1, N2); + else if (c2<0) + c3 -= Decrement(R1, N2, -c2); + + CRYPTOPP_ASSERT(c3>=-1 && c3<=1); + if (c3>0) + Subtract(R, R, M, N); + else if (c3<0) + Add(R, R, M, N); + +#undef M0 +#undef M1 +#undef V0 +#undef V1 + +#undef X0 +#undef X1 +#undef X2 +#undef X3 +} + +#undef A0 +#undef A1 +#undef B0 +#undef B1 + +#undef T0 +#undef T1 +#undef T2 +#undef T3 + +#undef R0 +#undef R1 +#undef R2 +#undef R3 + +/* +// do a 3 word by 2 word divide, returns quotient and leaves remainder in A +static word SubatomicDivide(word *A, word B0, word B1) +{ + // Assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a word + CRYPTOPP_ASSERT(A[2] < B1 || (A[2]==B1 && A[1] < B0)); + + // estimate the quotient: do a 2 word by 1 word divide + word Q; + if (B1+1 == 0) + Q = A[2]; + else + Q = DWord(A[1], A[2]).DividedBy(B1+1); + + // now subtract Q*B from A + DWord p = DWord::Multiply(B0, Q); + DWord u = (DWord) A[0] - p.GetLowHalf(); + A[0] = u.GetLowHalf(); + u = (DWord) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - DWord::Multiply(B1, Q); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + + // Q <= actual quotient, so fix it + while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) + { + u = (DWord) A[0] - B0; + A[0] = u.GetLowHalf(); + u = (DWord) A[1] - B1 - u.GetHighHalfAsBorrow(); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + Q++; + CRYPTOPP_ASSERT(Q); // shouldn't overflow + } + + return Q; +} + +// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1 +static inline void AtomicDivide(word *Q, const word *A, const word *B) +{ + if (!B[0] && !B[1]) // if divisor is 0, we assume divisor==2**(2*WORD_BITS) + { + Q[0] = A[2]; + Q[1] = A[3]; + } + else + { + word T[4]; + T[0] = A[0]; T[1] = A[1]; T[2] = A[2]; T[3] = A[3]; + Q[1] = SubatomicDivide(T+1, B[0], B[1]); + Q[0] = SubatomicDivide(T, B[0], B[1]); + +#if defined(CRYPTOPP_DEBUG) + // multiply quotient and divisor and add remainder, make sure it equals dividend + CRYPTOPP_ASSERT(!T[2] && !T[3] && (T[1] < B[1] || (T[1]==B[1] && T[0](T, DWord(A[0], A[1]), DWord(A[2], A[3]), DWord(B[0], B[1])); + Q[0] = q.GetLowHalf(); + Q[1] = q.GetHighHalf(); + +#if defined(CRYPTOPP_DEBUG) + if (B[0] || B[1]) + { + // multiply quotient and divisor and add remainder, make sure it equals dividend + CRYPTOPP_ASSERT(!T[2] && !T[3] && (T[1] < B[1] || (T[1]==B[1] && T[0]= 0) + { + R[N] -= Subtract(R, R, B, N); + Q[1] += (++Q[0]==0); + CRYPTOPP_ASSERT(Q[0] || Q[1]); // no overflow + } +} + +// R[NB] -------- remainder = A%B +// Q[NA-NB+2] --- quotient = A/B +// T[NA+3*(NB+2)] - temp work space +// A[NA] -------- dividend +// B[NB] -------- divisor + +void Divide(word *R, word *Q, word *T, const word *A, size_t NA, const word *B, size_t NB) +{ + CRYPTOPP_ASSERT(NA && NB && NA%2==0 && NB%2==0); + CRYPTOPP_ASSERT(B[NB-1] || B[NB-2]); + CRYPTOPP_ASSERT(NB <= NA); + + // set up temporary work space + word *const TA=T; + word *const TB=T+NA+2; + word *const TP=T+NA+2+NB; + + // copy B into TB and normalize it so that TB has highest bit set to 1 + unsigned shiftWords = (B[NB-1]==0); + TB[0] = TB[NB-1] = 0; + CopyWords(TB+shiftWords, B, NB-shiftWords); + unsigned shiftBits = WORD_BITS - BitPrecision(TB[NB-1]); + CRYPTOPP_ASSERT(shiftBits < WORD_BITS); + ShiftWordsLeftByBits(TB, NB, shiftBits); + + // copy A into TA and normalize it + TA[0] = TA[NA] = TA[NA+1] = 0; + CopyWords(TA+shiftWords, A, NA); + ShiftWordsLeftByBits(TA, NA+2, shiftBits); + + if (TA[NA+1]==0 && TA[NA] <= 1) + { + Q[NA-NB+1] = Q[NA-NB] = 0; + while (TA[NA] || Compare(TA+NA-NB, TB, NB) >= 0) + { + TA[NA] -= Subtract(TA+NA-NB, TA+NA-NB, TB, NB); + ++Q[NA-NB]; + } + } + else + { + NA+=2; + CRYPTOPP_ASSERT(Compare(TA+NA-NB, TB, NB) < 0); + } + + word BT[2]; + BT[0] = TB[NB-2] + 1; + BT[1] = TB[NB-1] + (BT[0]==0); + + // start reducing TA mod TB, 2 words at a time + for (size_t i=NA-2; i>=NB; i-=2) + { + AtomicDivide(Q+i-NB, TA+i-2, BT); + CorrectQuotientEstimate(TA+i-NB, TP, Q+i-NB, TB, NB); + } + + // copy TA into R, and denormalize it + CopyWords(R, TA+shiftWords, NB); + ShiftWordsRightByBits(R, NB, shiftBits); +} + +static inline size_t EvenWordCount(const word *X, size_t N) +{ + while (N && X[N-2]==0 && X[N-1]==0) + N-=2; + return N; +} + +// return k +// R[N] --- result = A^(-1) * 2^k mod M +// T[4*N] - temporary work space +// A[NA] -- number to take inverse of +// M[N] --- modulus + +unsigned int AlmostInverse(word *R, word *T, const word *A, size_t NA, const word *M, size_t N) +{ + CRYPTOPP_ASSERT(NA<=N && N && N%2==0); + + word *b = T; + word *c = T+N; + word *f = T+2*N; + word *g = T+3*N; + size_t bcLen=2, fgLen=EvenWordCount(M, N); + unsigned int k=0; + bool s=false; + + SetWords(T, 0, 3*N); + b[0]=1; + CopyWords(f, A, NA); + CopyWords(g, M, N); + + while (1) + { + word t=f[0]; + while (!t) + { + if (EvenWordCount(f, fgLen)==0) + { + SetWords(R, 0, N); + return 0; + } + + ShiftWordsRightByWords(f, fgLen, 1); + bcLen += 2 * (c[bcLen-1] != 0); + CRYPTOPP_ASSERT(bcLen <= N); + ShiftWordsLeftByWords(c, bcLen, 1); + k+=WORD_BITS; + t=f[0]; + } + + // t must be non-0; otherwise undefined. + unsigned int i = TrailingZeros(t); + t >>= i; + k += i; + + if (t==1 && f[1]==0 && EvenWordCount(f+2, fgLen-2)==0) + { + if (s) + Subtract(R, M, b, N); + else + CopyWords(R, b, N); + return k; + } + + ShiftWordsRightByBits(f, fgLen, i); + t = ShiftWordsLeftByBits(c, bcLen, i); + c[bcLen] += t; + bcLen += 2 * (t!=0); + CRYPTOPP_ASSERT(bcLen <= N); + + bool swap = Compare(f, g, fgLen)==-1; + ConditionalSwapPointers(swap, f, g); + ConditionalSwapPointers(swap, b, c); + s ^= swap; + + fgLen -= 2 * !(f[fgLen-2] | f[fgLen-1]); + + Subtract(f, f, g, fgLen); + t = Add(b, b, c, bcLen); + b[bcLen] += t; + bcLen += 2*t; + CRYPTOPP_ASSERT(bcLen <= N); + } +} + +// R[N] - result = A/(2^k) mod M +// A[N] - input +// M[N] - modulus + +void DivideByPower2Mod(word *R, const word *A, size_t k, const word *M, size_t N) +{ + CopyWords(R, A, N); + + while (k--) + { + if (R[0]%2==0) + ShiftWordsRightByBits(R, N, 1); + else + { + word carry = Add(R, R, M, N); + ShiftWordsRightByBits(R, N, 1); + R[N-1] += carry<<(WORD_BITS-1); + } + } +} + +// R[N] - result = A*(2^k) mod M +// A[N] - input +// M[N] - modulus + +void MultiplyByPower2Mod(word *R, const word *A, size_t k, const word *M, size_t N) +{ + CopyWords(R, A, N); + + while (k--) + if (ShiftWordsLeftByBits(R, N, 1) || Compare(R, M, N)>=0) + Subtract(R, R, M, N); +} + +// ****************************************************************** + +static const unsigned int RoundupSizeTable[] = {2, 2, 2, 4, 4, 8, 8, 8, 8}; + +static inline size_t RoundupSize(size_t n) +{ + if (n<=8) + return RoundupSizeTable[n]; + else if (n<=16) + return 16; + else if (n<=32) + return 32; + else if (n<=64) + return 64; + else + return size_t(1) << BitPrecision(n-1); +} + +Integer::Integer() + : reg(2), sign(POSITIVE) +{ + reg[0] = reg[1] = 0; +} + +Integer::Integer(const Integer& t) + : reg(RoundupSize(t.WordCount())), sign(t.sign) +{ + CopyWords(reg, t.reg, reg.size()); +} + +Integer::Integer(Sign s, lword value) + : reg(2), sign(s) +{ + reg[0] = word(value); + reg[1] = word(SafeRightShift(value)); +} + +Integer::Integer(signed long value) + : reg(2) +{ + if (value >= 0) + sign = POSITIVE; + else + { + sign = NEGATIVE; + value = -value; + } + reg[0] = word(value); + reg[1] = word(SafeRightShift((unsigned long)value)); +} + +Integer::Integer(Sign s, word high, word low) + : reg(2), sign(s) +{ + reg[0] = low; + reg[1] = high; +} + +bool Integer::IsConvertableToLong() const +{ + if (ByteCount() > sizeof(long)) + return false; + + unsigned long value = (unsigned long)reg[0]; + value += SafeLeftShift((unsigned long)reg[1]); + + if (sign==POSITIVE) + return (signed long)value >= 0; + else + return -(signed long)value < 0; +} + +signed long Integer::ConvertToLong() const +{ + CRYPTOPP_ASSERT(IsConvertableToLong()); + + unsigned long value = (unsigned long)reg[0]; + value += SafeLeftShift((unsigned long)reg[1]); + return sign==POSITIVE ? value : -(signed long)value; +} + +Integer::Integer(BufferedTransformation &encodedInteger, size_t byteCount, Signedness s, ByteOrder o) +{ + CRYPTOPP_ASSERT(o == BIG_ENDIAN_ORDER || o == LITTLE_ENDIAN_ORDER); + + if (o != LITTLE_ENDIAN_ORDER) + { + Decode(encodedInteger, byteCount, s); + } + else + { + SecByteBlock block(byteCount); + encodedInteger.Get(block, block.size()); + std::reverse(block.begin(), block.begin()+block.size()); + + Decode(block.begin(), block.size(), s); + } +} + +Integer::Integer(const byte *encodedInteger, size_t byteCount, Signedness s, ByteOrder o) +{ + CRYPTOPP_ASSERT(encodedInteger && byteCount); // NULL buffer + CRYPTOPP_ASSERT(o == BIG_ENDIAN_ORDER || o == LITTLE_ENDIAN_ORDER); + + if (o != LITTLE_ENDIAN_ORDER) + { + Decode(encodedInteger, byteCount, s); + } + else + { + SecByteBlock block(byteCount); +#if (_MSC_VER >= 1500) + std::reverse_copy(encodedInteger, encodedInteger+byteCount, + stdext::make_checked_array_iterator(block.begin(), block.size())); +#else + std::reverse_copy(encodedInteger, encodedInteger+byteCount, block.begin()); +#endif + Decode(block.begin(), block.size(), s); + return; + } +} + +Integer::Integer(BufferedTransformation &bt) +{ + // Make explicit call to avoid virtual-dispatch findings in ctor + Integer::BERDecode(bt); +} + +Integer::Integer(RandomNumberGenerator &rng, size_t bitcount) +{ + Randomize(rng, bitcount); +} + +Integer::Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod) +{ + if (!Randomize(rng, min, max, rnType, equiv, mod)) + throw Integer::RandomNumberNotFound(); +} + +Integer Integer::Power2(size_t e) +{ + Integer r((word)0, BitsToWords(e+1)); + r.SetBit(e); + return r; +} + +bool Integer::operator!() const +{ + return IsNegative() ? false : (reg[0]==0 && WordCount()==0); +} + +Integer& Integer::operator=(const Integer& t) +{ + if (this != &t) + { + if (reg.size() != t.reg.size() || t.reg[t.reg.size()/2] == 0) + reg.New(RoundupSize(t.WordCount())); + CopyWords(reg, t.reg, reg.size()); + sign = t.sign; + } + return *this; +} + +bool Integer::GetBit(size_t n) const +{ + // Profiling guided the flow below. + if (n/WORD_BITS < reg.size()) + return bool((reg[n/WORD_BITS] >> (n % WORD_BITS)) & 1); + else + return 0; +} + +void Integer::SetBit(size_t n, bool value) +{ + if (value) + { + reg.CleanGrow(RoundupSize(BitsToWords(n+1))); + reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS)); + } + else + { + if (n/WORD_BITS < reg.size()) + reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS)); + } +} + +byte Integer::GetByte(size_t n) const +{ + // Profiling guided the flow below. + if (n/WORD_SIZE < reg.size()) + return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); + else + return 0; +} + +void Integer::SetByte(size_t n, byte value) +{ + reg.CleanGrow(RoundupSize(BytesToWords(n+1))); + reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); + reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); +} + +lword Integer::GetBits(size_t i, size_t n) const +{ + lword v = 0; + CRYPTOPP_ASSERT(n <= sizeof(v)*8); + for (unsigned int j=0; j +static Integer StringToInteger(const T *str, ByteOrder order) +{ + CRYPTOPP_ASSERT( order == BIG_ENDIAN_ORDER || order == LITTLE_ENDIAN_ORDER ); + + int radix, sign = 1; + // GCC workaround + // std::char_traits::length() not defined in GCC 3.2 and STLport 4.5.3 + unsigned int length; + for (length = 0; str[length] != 0; length++) {} + + Integer v; + + if (length == 0) + return Integer::Zero(); + + switch (str[length-1]) + { + case 'h': + case 'H': + radix=16; + break; + case 'o': + case 'O': + radix=8; + break; + case 'b': + case 'B': + radix=2; + break; + default: + radix=10; + } + + // 'str' is of length 1 or more + if (str[0] == '-') + { + sign = -1; + str += 1, length -= 1; + } + + if (length > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + { + radix = 16; + str += 2, length -= 2; + } + + if (order == BIG_ENDIAN_ORDER) + { + for (unsigned int i=0; i(str[i]); + + // Profiling guided the flow below. + if (ch >= '0' && ch <= '9') + digit = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + digit = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + digit = ch - 'A' + 10; + else + digit = radix; + + if (digit < radix) + { + v *= radix; + v += digit; + } + } + } + else if (radix == 16 && order == LITTLE_ENDIAN_ORDER) + { + // Nibble high, low and count + unsigned int nh = 0, nl = 0, nc = 0; + Integer position(Integer::One()); + + for (unsigned int i=0; i(str[i]); + + if (ch >= '0' && ch <= '9') + digit = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + digit = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + digit = ch - 'A' + 10; + else + digit = radix; + + if (digit < radix) + { + if (nc++ == 0) + nh = digit; + else + nl = digit; + + if (nc == 2) + { + v += position * (nh << 4 | nl); + nc = 0, position <<= 8; + } + } + } + + if (nc == 1) + v += nh * position; + } + else // LITTLE_ENDIAN_ORDER && radix != 16 + { + for (int i=static_cast(length)-1; i>=0; i--) + { + int digit, ch = static_cast(str[i]); + + if (ch >= '0' && ch <= '9') + digit = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + digit = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + digit = ch - 'A' + 10; + else + digit = radix; + + if (digit < radix) + { + v *= radix; + v += digit; + } + } + } + + if (sign == -1) + v.Negate(); + + return v; +} + +Integer::Integer(const char *str, ByteOrder order) + : reg(2), sign(POSITIVE) +{ + *this = StringToInteger(str,order); +} + +Integer::Integer(const wchar_t *str, ByteOrder order) + : reg(2), sign(POSITIVE) +{ + *this = StringToInteger(str,order); +} + +unsigned int Integer::WordCount() const +{ + return (unsigned int)CountWords(reg, reg.size()); +} + +unsigned int Integer::ByteCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]); + else + return 0; +} + +unsigned int Integer::BitCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]); + else + return 0; +} + +void Integer::Decode(const byte *input, size_t inputLen, Signedness s) +{ + CRYPTOPP_ASSERT(input && inputLen); // NULL buffer + StringStore store(input, inputLen); + Decode(store, inputLen, s); +} + +void Integer::Decode(BufferedTransformation &bt, size_t inputLen, Signedness s) +{ + CRYPTOPP_ASSERT(bt.MaxRetrievable() >= inputLen); + if (bt.MaxRetrievable() < inputLen) + throw InvalidArgument("Integer: input length is too small"); + + byte b; + bt.Peek(b); + sign = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; + + while (inputLen>0 && (sign==POSITIVE ? b==0 : b==0xff)) + { + bt.Skip(1); + inputLen--; + bt.Peek(b); + } + + reg.CleanNew(RoundupSize(BytesToWords(inputLen))); + for (size_t i=inputLen; i > 0; i--) + { + (void)bt.Get(b); + reg[(i-1)/WORD_SIZE] |= word(b) << ((i-1)%WORD_SIZE)*8; + } + + if (sign == NEGATIVE) + { + for (size_t i=inputLen; i 0; i--) + bt.Put(GetByte(i-1)); + } + else + { + // take two's complement of *this + Integer temp = Integer::Power2(8*STDMAX((size_t)ByteCount(), outputLen)) + *this; + temp.Encode(bt, outputLen, UNSIGNED); + } +} + +void Integer::DEREncode(BufferedTransformation &bt) const +{ + DERGeneralEncoder enc(bt, INTEGER); + Encode(enc, MinEncodedSize(SIGNED), SIGNED); + enc.MessageEnd(); +} + +void Integer::BERDecode(const byte *input, size_t len) +{ + CRYPTOPP_ASSERT(input && len); // NULL buffer + StringStore store(input, len); + BERDecode(store); +} + +void Integer::BERDecode(BufferedTransformation &bt) +{ + BERGeneralDecoder dec(bt, INTEGER); + if (!dec.IsDefiniteLength() || dec.MaxRetrievable() < dec.RemainingLength()) + BERDecodeError(); + Decode(dec, (size_t)dec.RemainingLength(), SIGNED); + dec.MessageEnd(); +} + +void Integer::DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const +{ + DERGeneralEncoder enc(bt, OCTET_STRING); + Encode(enc, length); + enc.MessageEnd(); +} + +void Integer::BERDecodeAsOctetString(BufferedTransformation &bt, size_t length) +{ + BERGeneralDecoder dec(bt, OCTET_STRING); + if (!dec.IsDefiniteLength() || dec.RemainingLength() != length) + BERDecodeError(); + Decode(dec, length); + dec.MessageEnd(); +} + +size_t Integer::OpenPGPEncode(byte *output, size_t bufferSize) const +{ + CRYPTOPP_ASSERT(output && bufferSize); // NULL buffer + CRYPTOPP_ASSERT(bufferSize >= 2+ByteCount()); // Undersized buffer + ArraySink sink(output, bufferSize); + return OpenPGPEncode(sink); +} + +size_t Integer::OpenPGPEncode(BufferedTransformation &bt) const +{ + word16 bitCount = word16(BitCount()); + bt.PutWord16(bitCount); + size_t byteCount = BitsToBytes(bitCount); + Encode(bt, byteCount); + return 2 + byteCount; +} + +void Integer::OpenPGPDecode(const byte *input, size_t len) +{ + CRYPTOPP_ASSERT(input && len); // NULL buffer + StringStore store(input, len); + OpenPGPDecode(store); +} + +void Integer::OpenPGPDecode(BufferedTransformation &bt) +{ + word16 bitCount; + if (bt.GetWord16(bitCount) != 2 || bt.MaxRetrievable() < BitsToBytes(bitCount)) + throw OpenPGPDecodeErr(); + Decode(bt, BitsToBytes(bitCount)); +} + +void Integer::Randomize(RandomNumberGenerator &rng, size_t nbits) +{ + const size_t nbytes = nbits/8 + 1; + SecByteBlock buf(nbytes); + rng.GenerateBlock(buf, nbytes); + if (nbytes) + buf[0] = (byte)Crop(buf[0], nbits % 8); + Decode(buf, nbytes, UNSIGNED); +} + +void Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max) +{ + if (min > max) + throw InvalidArgument("Integer: Min must be no greater than Max"); + + Integer range = max - min; + const unsigned int nbits = range.BitCount(); + + do + { + Randomize(rng, nbits); + } + while (*this > range); + + *this += min; +} + +bool Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod) +{ + return GenerateRandomNoThrow(rng, MakeParameters("Min", min)("Max", max) + ("RandomNumberType", rnType)("EquivalentTo", equiv)("Mod", mod)); +} + +class KDF2_RNG : public RandomNumberGenerator +{ +public: + KDF2_RNG(const byte *seed, size_t seedSize) + : m_counter(0), m_counterAndSeed(ClampSize(seedSize) + 4) + { + memcpy(m_counterAndSeed + 4, seed, ClampSize(seedSize)); + } + + void GenerateBlock(byte *output, size_t size) + { + CRYPTOPP_ASSERT(output && size); // NULL buffer + PutWord(false, BIG_ENDIAN_ORDER, m_counterAndSeed, m_counter); + ++m_counter; + P1363_KDF2::DeriveKey(output, size, m_counterAndSeed, m_counterAndSeed.size(), NULLPTR, 0); + } + + // UBsan finding, -Wstringop-overflow + inline size_t ClampSize(size_t req) const + { + // Clamp at 16 MB + if (req > 16U*1024*1024) + return 16U*1024*1024; + return req; + } + +private: + word32 m_counter; + SecByteBlock m_counterAndSeed; +}; + +bool Integer::GenerateRandomNoThrow(RandomNumberGenerator &i_rng, const NameValuePairs ¶ms) +{ + Integer min = params.GetValueWithDefault("Min", Integer::Zero()); + Integer max; + if (!params.GetValue("Max", max)) + { + int bitLength; + if (params.GetIntValue("BitLength", bitLength)) + max = Integer::Power2(bitLength); + else + throw InvalidArgument("Integer: missing Max argument"); + } + if (min > max) + throw InvalidArgument("Integer: Min must be no greater than Max"); + + Integer equiv = params.GetValueWithDefault("EquivalentTo", Integer::Zero()); + Integer mod = params.GetValueWithDefault("Mod", Integer::One()); + + if (equiv.IsNegative() || equiv >= mod) + throw InvalidArgument("Integer: invalid EquivalentTo and/or Mod argument"); + + Integer::RandomNumberType rnType = params.GetValueWithDefault("RandomNumberType", Integer::ANY); + + member_ptr kdf2Rng; + ConstByteArrayParameter seed; + if (params.GetValue(Name::Seed(), seed)) + { + ByteQueue bq; + DERSequenceEncoder seq(bq); + min.DEREncode(seq); + max.DEREncode(seq); + equiv.DEREncode(seq); + mod.DEREncode(seq); + DEREncodeUnsigned(seq, rnType); + DEREncodeOctetString(seq, seed.begin(), seed.size()); + seq.MessageEnd(); + + SecByteBlock finalSeed((size_t)bq.MaxRetrievable()); + bq.Get(finalSeed, finalSeed.size()); + kdf2Rng.reset(new KDF2_RNG(finalSeed.begin(), finalSeed.size())); + } + RandomNumberGenerator &rng = kdf2Rng.get() ? (RandomNumberGenerator &)*kdf2Rng : i_rng; + + switch (rnType) + { + case ANY: + if (mod == One()) + Randomize(rng, min, max); + else + { + Integer min1 = min + (equiv-min)%mod; + if (max < min1) + return false; + Randomize(rng, Zero(), (max - min1) / mod); + *this *= mod; + *this += min1; + } + return true; + + case PRIME: + { + const PrimeSelector *pSelector = params.GetValueWithDefault(Name::PointerToPrimeSelector(), (const PrimeSelector *)NULLPTR); + + int i; + i = 0; + while (1) + { + if (++i==16) + { + // check if there are any suitable primes in [min, max] + Integer first = min; + if (FirstPrime(first, max, equiv, mod, pSelector)) + { + // if there is only one suitable prime, we're done + *this = first; + if (!FirstPrime(first, max, equiv, mod, pSelector)) + return true; + } + else + return false; + } + + Randomize(rng, min, max); + if (FirstPrime(*this, STDMIN(*this+mod*PrimeSearchInterval(max), max), equiv, mod, pSelector)) + return true; + } + } + + default: + throw InvalidArgument("Integer: invalid RandomNumberType argument"); + } +} + +std::istream& operator>>(std::istream& in, Integer &a) +{ + char c; + unsigned int length = 0; + SecBlock str(length + 16); + + std::ws(in); + + do + { + in.read(&c, 1); + str[length++] = c; + if (length >= str.size()) + str.Grow(length + 16); + } + while (in && (c=='-' || c=='x' || (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F') || c=='h' || c=='H' || c=='o' || c=='O' || c==',' || c=='.')); + + if (in.gcount()) + in.putback(c); + str[length-1] = '\0'; + a = Integer(str); + + return in; +} + +// Ensure base 10 is default +inline int FlagToBase(long f) { + return f == std::ios::hex ? 16 : (f == std::ios::oct ? 8 : 10); +} + +inline char FlagToSuffix(long f) { + return f == std::ios::hex ? 'h' : (f == std::ios::oct ? 'o' : '.'); +} + +// Ensure base 10 is default +std::ostream& operator<<(std::ostream& out, const Integer &a) +{ + // Get relevant conversion specifications from ostream. + const long f = out.flags() & std::ios::basefield; + const int base = FlagToBase(f); + const char suffix = FlagToSuffix(f); + + Integer temp1=a, temp2; + if (a.IsNegative()) + { + out << '-'; + temp1.Negate(); + } + + if (!a) + out << '0'; + + static const char upper[]="0123456789ABCDEF"; + static const char lower[]="0123456789abcdef"; + + const char* vec = (out.flags() & std::ios::uppercase) ? upper : lower; + unsigned int i=0; + SecBlock s(a.BitCount() / (SaturatingSubtract1(BitPrecision(base),1U)) + 1); + + while (!!temp1) + { + word digit; + Integer::Divide(digit, temp2, temp1, base); + s[i++]=vec[digit]; + temp1.swap(temp2); + } + + while (i--) + { + out << s[i]; + } + +#ifdef CRYPTOPP_USE_STD_SHOWBASE + if (out.flags() & std::ios_base::showbase) + out << suffix; + + return out; +#else + return out << suffix; +#endif +} + +Integer& Integer::operator++() +{ + if (NotNegative()) + { + if (Increment(reg, reg.size())) + { + reg.CleanGrow(2*reg.size()); + reg[reg.size()/2]=1; + } + } + else + { + word borrow = Decrement(reg, reg.size()); + CRYPTOPP_ASSERT(!borrow); CRYPTOPP_UNUSED(borrow); + + if (WordCount()==0) + *this = Zero(); + } + return *this; +} + +Integer& Integer::operator--() +{ + if (IsNegative()) + { + if (Increment(reg, reg.size())) + { + reg.CleanGrow(2*reg.size()); + reg[reg.size()/2]=1; + } + } + else + { + if (Decrement(reg, reg.size())) + *this = -One(); + } + return *this; +} + +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::And(const Integer& t) const +{ + if (this == &t) + { + return AbsoluteValue(); + } + else if (reg.size() >= t.reg.size()) + { + Integer result(t); + AndWords(result.reg, reg, t.reg.size()); + + result.sign = POSITIVE; + return result; + } + else // reg.size() < t.reg.size() + { + Integer result(*this); + AndWords(result.reg, t.reg, reg.size()); + + result.sign = POSITIVE; + return result; + } +} + +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::Or(const Integer& t) const +{ + if (this == &t) + { + return AbsoluteValue(); + } + else if (reg.size() >= t.reg.size()) + { + Integer result(*this); + OrWords(result.reg, t.reg, t.reg.size()); + + result.sign = POSITIVE; + return result; + } + else // reg.size() < t.reg.size() + { + Integer result(t); + OrWords(result.reg, reg, reg.size()); + + result.sign = POSITIVE; + return result; + } +} + +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::Xor(const Integer& t) const +{ + if (this == &t) + { + return Integer::Zero(); + } + else if (reg.size() >= t.reg.size()) + { + Integer result(*this); + XorWords(result.reg, t.reg, t.reg.size()); + + result.sign = POSITIVE; + return result; + } + else // reg.size() < t.reg.size() + { + Integer result(t); + XorWords(result.reg, reg, reg.size()); + + result.sign = POSITIVE; + return result; + } +} + +void PositiveAdd(Integer &sum, const Integer &a, const Integer& b) +{ + // Profiling guided the flow below. + int carry; const bool pre = (a.reg.size() == b.reg.size()); + if (!pre && a.reg.size() > b.reg.size()) + { + carry = Add(sum.reg, a.reg, b.reg, b.reg.size()); + CopyWords(sum.reg+b.reg.size(), a.reg+b.reg.size(), a.reg.size()-b.reg.size()); + carry = Increment(sum.reg+b.reg.size(), a.reg.size()-b.reg.size(), carry); + } + else if (pre) + { + carry = Add(sum.reg, a.reg, b.reg, a.reg.size()); + } + else + { + carry = Add(sum.reg, a.reg, b.reg, a.reg.size()); + CopyWords(sum.reg+a.reg.size(), b.reg+a.reg.size(), b.reg.size()-a.reg.size()); + carry = Increment(sum.reg+a.reg.size(), b.reg.size()-a.reg.size(), carry); + } + + if (carry) + { + sum.reg.CleanGrow(2*sum.reg.size()); + sum.reg[sum.reg.size()/2] = 1; + } + sum.sign = Integer::POSITIVE; +} + +void PositiveSubtract(Integer &diff, const Integer &a, const Integer& b) +{ + unsigned aSize = a.WordCount(); + aSize += aSize%2; + unsigned bSize = b.WordCount(); + bSize += bSize%2; + + // Profiling guided the flow below. + if (aSize > bSize) + { + word borrow = Subtract(diff.reg, a.reg, b.reg, bSize); + CopyWords(diff.reg+bSize, a.reg+bSize, aSize-bSize); + borrow = Decrement(diff.reg+bSize, aSize-bSize, borrow); + CRYPTOPP_ASSERT(!borrow); CRYPTOPP_UNUSED(borrow); + diff.sign = Integer::POSITIVE; + } + else if (aSize == bSize) + { + if (Compare(a.reg, b.reg, aSize) >= 0) + { + Subtract(diff.reg, a.reg, b.reg, aSize); + diff.sign = Integer::POSITIVE; + } + else + { + Subtract(diff.reg, b.reg, a.reg, aSize); + diff.sign = Integer::NEGATIVE; + } + } + else + { + word borrow = Subtract(diff.reg, b.reg, a.reg, aSize); + CopyWords(diff.reg+aSize, b.reg+aSize, bSize-aSize); + borrow = Decrement(diff.reg+aSize, bSize-aSize, borrow); + CRYPTOPP_ASSERT(!borrow); CRYPTOPP_UNUSED(borrow); + diff.sign = Integer::NEGATIVE; + } +} + +// MSVC .NET 2003 workaround +template inline const T& STDMAX2(const T& a, const T& b) +{ + return a < b ? b : a; +} + +Integer Integer::Plus(const Integer& b) const +{ + Integer sum((word)0, STDMAX2(reg.size(), b.reg.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveAdd(sum, *this, b); + else + PositiveSubtract(sum, *this, b); + } + else + { + if (b.NotNegative()) + PositiveSubtract(sum, b, *this); + else + { + PositiveAdd(sum, *this, b); + sum.sign = Integer::NEGATIVE; + } + } + return sum; +} + +Integer& Integer::operator+=(const Integer& t) +{ + reg.CleanGrow(t.reg.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveAdd(*this, *this, t); + else + PositiveSubtract(*this, *this, t); + } + else + { + if (t.NotNegative()) + PositiveSubtract(*this, t, *this); + else + { + PositiveAdd(*this, *this, t); + sign = Integer::NEGATIVE; + } + } + return *this; +} + +Integer Integer::Minus(const Integer& b) const +{ + Integer diff((word)0, STDMAX2(reg.size(), b.reg.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveSubtract(diff, *this, b); + else + PositiveAdd(diff, *this, b); + } + else + { + if (b.NotNegative()) + { + PositiveAdd(diff, *this, b); + diff.sign = Integer::NEGATIVE; + } + else + PositiveSubtract(diff, b, *this); + } + return diff; +} + +Integer& Integer::operator-=(const Integer& t) +{ + reg.CleanGrow(t.reg.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveSubtract(*this, *this, t); + else + PositiveAdd(*this, *this, t); + } + else + { + if (t.NotNegative()) + { + PositiveAdd(*this, *this, t); + sign = Integer::NEGATIVE; + } + else + PositiveSubtract(*this, t, *this); + } + return *this; +} + +Integer& Integer::operator<<=(size_t n) +{ + const size_t wordCount = WordCount(); + const size_t shiftWords = n / WORD_BITS; + const unsigned int shiftBits = (unsigned int)(n % WORD_BITS); + + reg.CleanGrow(RoundupSize(wordCount+BitsToWords(n))); + ShiftWordsLeftByWords(reg, wordCount + shiftWords, shiftWords); + ShiftWordsLeftByBits(reg+shiftWords, wordCount+BitsToWords(shiftBits), shiftBits); + return *this; +} + +Integer& Integer::operator>>=(size_t n) +{ + const size_t wordCount = WordCount(); + const size_t shiftWords = n / WORD_BITS; + const unsigned int shiftBits = (unsigned int)(n % WORD_BITS); + + ShiftWordsRightByWords(reg, wordCount, shiftWords); + if (wordCount > shiftWords) + ShiftWordsRightByBits(reg, wordCount-shiftWords, shiftBits); + if (IsNegative() && WordCount()==0) // avoid -0 + *this = Zero(); + return *this; +} + +Integer& Integer::operator&=(const Integer& t) +{ + if (this != &t) + { + const size_t size = STDMIN(reg.size(), t.reg.size()); + reg.resize(size); + AndWords(reg, t.reg, size); + } + sign = POSITIVE; + return *this; +} + +Integer& Integer::operator|=(const Integer& t) +{ + if (this != &t) + { + if (reg.size() >= t.reg.size()) + { + OrWords(reg, t.reg, t.reg.size()); + } + else // reg.size() < t.reg.size() + { + const size_t head = reg.size(); + const size_t tail = t.reg.size() - reg.size(); + reg.resize(head+tail); + OrWords(reg, t.reg, head); + CopyWords(reg+head,t.reg+head,tail); + } + } + sign = POSITIVE; + return *this; +} + +Integer& Integer::operator^=(const Integer& t) +{ + if (this == &t) + { + *this = Zero(); + } + else + { + if (reg.size() >= t.reg.size()) + { + XorWords(reg, t.reg, t.reg.size()); + } + else // reg.size() < t.reg.size() + { + const size_t head = reg.size(); + const size_t tail = t.reg.size() - reg.size(); + reg.resize(head+tail); + XorWords(reg, t.reg, head); + CopyWords(reg+head,t.reg+head,tail); + } + } + sign = POSITIVE; + return *this; +} + +void PositiveMultiply(Integer &product, const Integer &a, const Integer &b) +{ + size_t aSize = RoundupSize(a.WordCount()); + size_t bSize = RoundupSize(b.WordCount()); + + product.reg.CleanNew(RoundupSize(aSize+bSize)); + product.sign = Integer::POSITIVE; + + IntegerSecBlock workspace(aSize + bSize); + AsymmetricMultiply(product.reg, workspace, a.reg, aSize, b.reg, bSize); +} + +void Multiply(Integer &product, const Integer &a, const Integer &b) +{ + PositiveMultiply(product, a, b); + + if (a.NotNegative() != b.NotNegative()) + product.Negate(); +} + +Integer Integer::Times(const Integer &b) const +{ + Integer product; + Multiply(product, *this, b); + return product; +} + +/* +void PositiveDivide(Integer &remainder, Integer "ient, + const Integer ÷nd, const Integer &divisor) +{ + remainder.reg.CleanNew(divisor.reg.size()); + remainder.sign = Integer::POSITIVE; + quotient.reg.New(0); + quotient.sign = Integer::POSITIVE; + unsigned i=dividend.BitCount(); + while (i--) + { + word overflow = ShiftWordsLeftByBits(remainder.reg, remainder.reg.size(), 1); + remainder.reg[0] |= dividend[i]; + if (overflow || remainder >= divisor) + { + Subtract(remainder.reg, remainder.reg, divisor.reg, remainder.reg.size()); + quotient.SetBit(i); + } + } +} +*/ + +void PositiveDivide(Integer &remainder, Integer "ient, + const Integer &a, const Integer &b) +{ + unsigned aSize = a.WordCount(); + unsigned bSize = b.WordCount(); + + if (!bSize) + throw Integer::DivideByZero(); + + if (aSize < bSize) + { + remainder = a; + remainder.sign = Integer::POSITIVE; + quotient = Integer::Zero(); + return; + } + + aSize += aSize%2; // round up to next even number + bSize += bSize%2; + + remainder.reg.CleanNew(RoundupSize(bSize)); + remainder.sign = Integer::POSITIVE; + quotient.reg.CleanNew(RoundupSize(aSize-bSize+2)); + quotient.sign = Integer::POSITIVE; + + IntegerSecBlock T(aSize+3*(bSize+2)); + Divide(remainder.reg, quotient.reg, T, a.reg, aSize, b.reg, bSize); +} + +void Integer::Divide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor) +{ + PositiveDivide(remainder, quotient, dividend, divisor); + + if (dividend.IsNegative()) + { + quotient.Negate(); + if (remainder.NotZero()) + { + --quotient; + remainder = divisor.AbsoluteValue() - remainder; + } + } + + if (divisor.IsNegative()) + quotient.Negate(); +} + +void Integer::DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n) +{ + q = a; + q >>= n; + + const size_t wordCount = BitsToWords(n); + if (wordCount <= a.WordCount()) + { + r.reg.resize(RoundupSize(wordCount)); + CopyWords(r.reg, a.reg, wordCount); + SetWords(r.reg+wordCount, 0, r.reg.size()-wordCount); + if (n % WORD_BITS != 0) + r.reg[wordCount-1] %= (word(1) << (n % WORD_BITS)); + } + else + { + r.reg.resize(RoundupSize(a.WordCount())); + CopyWords(r.reg, a.reg, r.reg.size()); + } + r.sign = POSITIVE; + + if (a.IsNegative() && r.NotZero()) + { + --q; + r = Power2(n) - r; + } +} + +Integer Integer::DividedBy(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +Integer Integer::Modulo(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return remainder; +} + +void Integer::Divide(word &remainder, Integer "ient, const Integer ÷nd, word divisor) +{ + if (!divisor) + throw Integer::DivideByZero(); + + // IsPowerOf2 uses BMI on x86 if available. There is a small + // but measurable improvement during decryption and signing. + if (IsPowerOf2(divisor)) + { + quotient = dividend >> (BitPrecision(divisor)-1); + remainder = dividend.reg[0] & (divisor-1); + return; + } + + unsigned int i = dividend.WordCount(); + quotient.reg.CleanNew(RoundupSize(i)); + remainder = 0; + while (i--) + { + quotient.reg[i] = DWord(dividend.reg[i], remainder) / divisor; + remainder = DWord(dividend.reg[i], remainder) % divisor; + } + + if (dividend.NotNegative()) + quotient.sign = POSITIVE; + else + { + quotient.sign = NEGATIVE; + if (remainder) + { + --quotient; + remainder = divisor - remainder; + } + } +} + +Integer Integer::DividedBy(word b) const +{ + word remainder; + Integer quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +word Integer::Modulo(word divisor) const +{ + if (!divisor) + throw Integer::DivideByZero(); + + word remainder; + + // Profiling guided the flow below. + if ((divisor & (divisor-1)) != 0) // divisor is not a power of 2 + { + // Profiling guided the flow below. + unsigned int i = WordCount(); + if (divisor > 5) + { + remainder = 0; + while (i--) + remainder = DWord(reg[i], remainder) % divisor; + } + else + { + DWord sum(0, 0); + while (i--) + sum += reg[i]; + remainder = sum % divisor; + } + } + else // divisor is a power of 2 + { + remainder = reg[0] & (divisor-1); + } + + if (IsNegative() && remainder) + remainder = divisor - remainder; + + return remainder; +} + +void Integer::Negate() +{ + if (!!(*this)) // don't flip sign if *this==0 + sign = Sign(1-sign); +} + +int Integer::PositiveCompare(const Integer& t) const +{ + // Profiling guided the flow below. + const unsigned size = WordCount(), tSize = t.WordCount(); + if (size != tSize) + return size > tSize ? 1 : -1; + else + return CryptoPP::Compare(reg, t.reg, size); +} + +int Integer::Compare(const Integer& t) const +{ + if (NotNegative()) + { + if (t.NotNegative()) + return PositiveCompare(t); + else + return 1; + } + else + { + if (t.NotNegative()) + return -1; + else + return -PositiveCompare(t); + } +} + +Integer Integer::SquareRoot() const +{ + if (!IsPositive()) + return Zero(); + + // overestimate square root + Integer x, y = Power2((BitCount()+1)/2); + CRYPTOPP_ASSERT(y*y >= *this); + + do + { + x = y; + y = (x + *this/x) >> 1; + } while (y().Gcd(a, b); +} + +Integer Integer::InverseMod(const Integer &m) const +{ + CRYPTOPP_ASSERT(m.NotNegative()); + CRYPTOPP_ASSERT(m.NotZero()); + + if (IsNegative()) + return Modulo(m).InverseModNext(m); + + // http://github.com/weidai11/cryptopp/issues/602 + if (*this >= m) + return Modulo(m).InverseModNext(m); + + return InverseModNext(m); +} + +Integer Integer::InverseModNext(const Integer &m) const +{ + CRYPTOPP_ASSERT(m.NotNegative()); + CRYPTOPP_ASSERT(m.NotZero()); + + if (m.IsEven()) + { + if (!m || IsEven()) + return Zero(); // no inverse + if (*this == One()) + return One(); + + Integer u = m.Modulo(*this).InverseModNext(*this); + return !u ? Zero() : (m*(*this-u)+1)/(*this); + } + + // AlmostInverse requires a 4x workspace + IntegerSecBlock T(m.reg.size() * 4); + Integer r((word)0, m.reg.size()); + unsigned k = AlmostInverse(r.reg, T, reg, reg.size(), m.reg, m.reg.size()); + DivideByPower2Mod(r.reg, r.reg, k, m.reg, m.reg.size()); + return r; +} + +word Integer::InverseMod(word mod) const +{ + CRYPTOPP_ASSERT(mod != 0); + + word g0 = mod, g1 = *this % mod; + word v0 = 0, v1 = 1; + word y; + + while (g1) + { + if (g1 == 1) + return v1; + y = g0 / g1; + g0 = g0 % g1; + v0 += y * v1; + + if (!g0) + break; + if (g0 == 1) + return mod-v0; + y = g1 / g0; + g1 = g1 % g0; + v1 += y * v0; + } + return 0; +} + +// ******************************************************** + +ModularArithmetic::ModularArithmetic(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + OID oid(seq); + if (oid != ASN1::prime_field()) + BERDecodeError(); + m_modulus.BERDecode(seq); + seq.MessageEnd(); + m_result.reg.resize(m_modulus.reg.size()); +} + +void ModularArithmetic::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + ASN1::prime_field().DEREncode(seq); + m_modulus.DEREncode(seq); + seq.MessageEnd(); +} + +void ModularArithmetic::DEREncodeElement(BufferedTransformation &out, const Element &a) const +{ + a.DEREncodeAsOctetString(out, MaxElementByteLength()); +} + +void ModularArithmetic::BERDecodeElement(BufferedTransformation &in, Element &a) const +{ + a.BERDecodeAsOctetString(in, MaxElementByteLength()); +} + +const Integer& ModularArithmetic::Half(const Integer &a) const +{ + if (a.reg.size()==m_modulus.reg.size()) + { + CryptoPP::DivideByPower2Mod(m_result.reg.begin(), a.reg, 1, m_modulus.reg, a.reg.size()); + return m_result; + } + else + return m_result1 = (a.IsEven() ? (a >> 1) : ((a+m_modulus) >> 1)); +} + +const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const +{ + if (a.reg.size()==m_modulus.reg.size() && b.reg.size()==m_modulus.reg.size()) + { + if (CryptoPP::Add(m_result.reg.begin(), a.reg, b.reg, a.reg.size()) + || Compare(m_result.reg, m_modulus.reg, a.reg.size()) >= 0) + { + CryptoPP::Subtract(m_result.reg.begin(), m_result.reg, m_modulus.reg, a.reg.size()); + } + return m_result; + } + else + { + m_result1 = a+b; + if (m_result1 >= m_modulus) + m_result1 -= m_modulus; + return m_result1; + } +} + +Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const +{ + if (a.reg.size()==m_modulus.reg.size() && b.reg.size()==m_modulus.reg.size()) + { + if (CryptoPP::Add(a.reg, a.reg, b.reg, a.reg.size()) + || Compare(a.reg, m_modulus.reg, a.reg.size()) >= 0) + { + CryptoPP::Subtract(a.reg, a.reg, m_modulus.reg, a.reg.size()); + } + } + else + { + a+=b; + if (a>=m_modulus) + a-=m_modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Subtract(const Integer &a, const Integer &b) const +{ + if (a.reg.size()==m_modulus.reg.size() && b.reg.size()==m_modulus.reg.size()) + { + if (CryptoPP::Subtract(m_result.reg.begin(), a.reg, b.reg, a.reg.size())) + CryptoPP::Add(m_result.reg.begin(), m_result.reg, m_modulus.reg, a.reg.size()); + return m_result; + } + else + { + m_result1 = a-b; + if (m_result1.IsNegative()) + m_result1 += m_modulus; + return m_result1; + } +} + +Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const +{ + if (a.reg.size()==m_modulus.reg.size() && b.reg.size()==m_modulus.reg.size()) + { + if (CryptoPP::Subtract(a.reg, a.reg, b.reg, a.reg.size())) + CryptoPP::Add(a.reg, a.reg, m_modulus.reg, a.reg.size()); + } + else + { + a-=b; + if (a.IsNegative()) + a+=m_modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Inverse(const Integer &a) const +{ + if (!a) + return a; + + CopyWords(m_result.reg.begin(), m_modulus.reg, m_modulus.reg.size()); + if (CryptoPP::Subtract(m_result.reg.begin(), m_result.reg, a.reg, a.reg.size())) + Decrement(m_result.reg.begin()+a.reg.size(), m_modulus.reg.size()-a.reg.size()); + + return m_result; +} + +Integer ModularArithmetic::CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const +{ + if (m_modulus.IsOdd()) + { + MontgomeryRepresentation dr(m_modulus); + return dr.ConvertOut(dr.CascadeExponentiate(dr.ConvertIn(x), e1, dr.ConvertIn(y), e2)); + } + else + return AbstractRing::CascadeExponentiate(x, e1, y, e2); +} + +void ModularArithmetic::SimultaneousExponentiate(Integer *results, const Integer &base, const Integer *exponents, unsigned int exponentsCount) const +{ + if (m_modulus.IsOdd()) + { + MontgomeryRepresentation dr(m_modulus); + dr.SimultaneousExponentiate(results, dr.ConvertIn(base), exponents, exponentsCount); + for (unsigned int i=0; i::SimultaneousExponentiate(results, base, exponents, exponentsCount); +} + +MontgomeryRepresentation::MontgomeryRepresentation(const Integer &m) // modulus must be odd + : ModularArithmetic(m), + m_u((word)0, m_modulus.reg.size()), + m_workspace(5*m_modulus.reg.size()) +{ + if (!m_modulus.IsOdd()) + throw InvalidArgument("MontgomeryRepresentation: Montgomery representation requires an odd modulus"); + + RecursiveInverseModPower2(m_u.reg, m_workspace, m_modulus.reg, m_modulus.reg.size()); +} + +const Integer& MontgomeryRepresentation::Multiply(const Integer &a, const Integer &b) const +{ + word *const T = m_workspace.begin(); + word *const R = m_result.reg.begin(); + const size_t N = m_modulus.reg.size(); + CRYPTOPP_ASSERT(a.reg.size()<=N && b.reg.size()<=N); + + AsymmetricMultiply(T, T+2*N, a.reg, a.reg.size(), b.reg, b.reg.size()); + SetWords(T+a.reg.size()+b.reg.size(), 0, 2*N-a.reg.size()-b.reg.size()); + MontgomeryReduce(R, T+2*N, T, m_modulus.reg, m_u.reg, N); + return m_result; +} + +const Integer& MontgomeryRepresentation::Square(const Integer &a) const +{ + word *const T = m_workspace.begin(); + word *const R = m_result.reg.begin(); + const size_t N = m_modulus.reg.size(); + CRYPTOPP_ASSERT(a.reg.size()<=N); + + CryptoPP::Square(T, T+2*N, a.reg, a.reg.size()); + SetWords(T+2*a.reg.size(), 0, 2*N-2*a.reg.size()); + MontgomeryReduce(R, T+2*N, T, m_modulus.reg, m_u.reg, N); + return m_result; +} + +Integer MontgomeryRepresentation::ConvertOut(const Integer &a) const +{ + word *const T = m_workspace.begin(); + word *const R = m_result.reg.begin(); + const size_t N = m_modulus.reg.size(); + CRYPTOPP_ASSERT(a.reg.size()<=N); + + CopyWords(T, a.reg, a.reg.size()); + SetWords(T+a.reg.size(), 0, 2*N-a.reg.size()); + MontgomeryReduce(R, T+2*N, T, m_modulus.reg, m_u.reg, N); + return m_result; +} + +const Integer& MontgomeryRepresentation::MultiplicativeInverse(const Integer &a) const +{ +// return (EuclideanMultiplicativeInverse(a, modulus)<<(2*WORD_BITS*modulus.reg.size()))%modulus; + word *const T = m_workspace.begin(); + word *const R = m_result.reg.begin(); + const size_t N = m_modulus.reg.size(); + CRYPTOPP_ASSERT(a.reg.size()<=N); + + CopyWords(T, a.reg, a.reg.size()); + SetWords(T+a.reg.size(), 0, 2*N-a.reg.size()); + MontgomeryReduce(R, T+2*N, T, m_modulus.reg, m_u.reg, N); + unsigned k = AlmostInverse(R, T, R, N, m_modulus.reg, N); + +// cout << "k=" << k << " N*32=" << 32*N << endl; + + if (k>N*WORD_BITS) + DivideByPower2Mod(R, R, k-N*WORD_BITS, m_modulus.reg, N); + else + MultiplyByPower2Mod(R, R, N*WORD_BITS-k, m_modulus.reg, N); + + return m_result; +} + +// Specialization declared in misc.h to allow us to print integers +// with additional control options, like arbirary bases and uppercase. +template <> CRYPTOPP_DLL +std::string IntToString(Integer value, unsigned int base) +{ + // Hack... set the high bit for uppercase. Set the next bit fo a suffix. + static const unsigned int BIT_32 = (1U << 31); + const bool UPPER = !!(base & BIT_32); + static const unsigned int BIT_31 = (1U << 30); + const bool BASE = !!(base & BIT_31); + + const char CH = UPPER ? 'A' : 'a'; + base &= ~(BIT_32|BIT_31); + CRYPTOPP_ASSERT(base >= 2 && base <= 32); + + if (value == 0) + return "0"; + + bool negative = false, zero = false; + if (value.IsNegative()) + { + negative = true; + value.Negate(); + } + + if (!value) + zero = true; + + SecBlock s(value.BitCount() / (SaturatingSubtract1(BitPrecision(base),1U)) + 1); + Integer temp; + + unsigned int i=0; + while (!!value) + { + word digit; + Integer::Divide(digit, temp, value, word(base)); + s[i++]=char((digit < 10 ? '0' : (CH - 10)) + digit); + value.swap(temp); + } + + std::string result; + result.reserve(i+2); + + if (negative) + result += '-'; + + if (zero) + result += '0'; + + while (i--) + result += s[i]; + + if (BASE) + { + if (base == 10) + result += '.'; + else if (base == 16) + result += 'h'; + else if (base == 8) + result += 'o'; + else if (base == 2) + result += 'b'; + } + + return result; +} + +// Specialization declared in misc.h to avoid Coverity findings. +template <> CRYPTOPP_DLL +std::string IntToString(word64 value, unsigned int base) +{ + // Hack... set the high bit for uppercase. + static const unsigned int HIGH_BIT = (1U << 31); + const char CH = !!(base & HIGH_BIT) ? 'A' : 'a'; + base &= ~HIGH_BIT; + + CRYPTOPP_ASSERT(base >= 2); + if (value == 0) + return "0"; + + std::string result; + while (value > 0) + { + word64 digit = value % base; + result = char((digit < 10 ? '0' : (CH - 10)) + digit) + result; + value /= base; + } + return result; +} + +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER +// Allow the linker to discard Integer code if not needed. +// Also see http://github.com/weidai11/cryptopp/issues/389. +bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt) +{ + if (valueType != typeid(Integer)) + return false; + *reinterpret_cast(pInteger) = *reinterpret_cast(pInt); + return true; +} +#endif // CRYPTOPP_NO_ASSIGN_TO_INTEGER + +// *************************** C++ Static Initialization *************************** + +class InitInteger +{ +public: + InitInteger() + { + SetFunctionPointers(); + } +}; + +// This is not really needed because each Integer can dynamically initialize +// itself, but we take a peephole optimization and initialize the class once +// if init priorities are available. Dynamic initialization will be used if +// init priorities are not available. + +#if defined(HAVE_GCC_INIT_PRIORITY) + const InitInteger s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 10))) = InitInteger(); + const Integer g_zero __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 11))) = Integer(0L); + const Integer g_one __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 12))) = Integer(1L); + const Integer g_two __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 13))) = Integer(2L); +#elif defined(HAVE_MSC_INIT_PRIORITY) + #pragma warning(disable: 4075) + #pragma init_seg(".CRT$XCU") + const InitInteger s_init; + const Integer g_zero(0L); + const Integer g_one(1L); + const Integer g_two(2L); + #pragma warning(default: 4075) +#elif HAVE_XLC_INIT_PRIORITY + // XLC needs constant, not a define + #pragma priority(280) + const InitInteger s_init; + const Integer g_zero(0L); + const Integer g_one(1L); + const Integer g_two(2L); +#else + const InitInteger s_init; +#endif + +// ***************** Library code ******************** + +const Integer &Integer::Zero() +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_zero; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const Integer s_zero(0L); + return s_zero; +#else // Potential memory leak. Avoid if possible. + return Singleton >().Ref(); +#endif +} + +const Integer &Integer::One() +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_one; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const Integer s_one(1L); + return s_one; +#else // Potential memory leak. Avoid if possible. + return Singleton >().Ref(); +#endif +} + +const Integer &Integer::Two() +{ +#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY) + return g_two; +#elif defined(CRYPTOPP_CXX11_STATIC_INIT) + static const Integer s_two(2L); + return s_two; +#else // Potential memory leak. Avoid if possible. + return Singleton >().Ref(); +#endif +} + +NAMESPACE_END + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/integer.h b/extension/third_party/cryptopp/integer.h new file mode 100644 index 00000000..d727bdf7 --- /dev/null +++ b/extension/third_party/cryptopp/integer.h @@ -0,0 +1,837 @@ +// integer.h - originally written and placed in the public domain by Wei Dai + +/// \file integer.h +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_INTEGER_H +#define CRYPTOPP_INTEGER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "stdcpp.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \struct InitializeInteger +/// \brief Performs static initialization of the Integer class +struct InitializeInteger +{ + InitializeInteger(); +}; + +// Always align, http://github.com/weidai11/cryptopp/issues/256 +typedef SecBlock > IntegerSecBlock; + +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 +/// \nosubgrouping +class CRYPTOPP_DLL Integer : private InitializeInteger, public ASN1Object +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Exception thrown when division by 0 is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {} + }; + + /// \brief Exception thrown when a random number cannot be found that + /// satisfies the condition + class RandomNumberNotFound : public Exception + { + public: + RandomNumberNotFound() : Exception(OTHER_ERROR, "Integer: no integer satisfies the given parameters") {} + }; + + /// \enum Sign + /// \brief Used internally to represent the integer + /// \details Sign is used internally to represent the integer. It is also used in a few API functions. + /// \sa SetPositive(), SetNegative(), Signedness + enum Sign { + /// \brief the value is positive or 0 + POSITIVE=0, + /// \brief the value is negative + NEGATIVE=1}; + + /// \enum Signedness + /// \brief Used when importing and exporting integers + /// \details Signedness is usually used in API functions. + /// \sa Sign + enum Signedness { + /// \brief an unsigned value + UNSIGNED, + /// \brief a signed value + SIGNED}; + + /// \enum RandomNumberType + /// \brief Properties of a random integer + enum RandomNumberType { + /// \brief a number with no special properties + ANY, + /// \brief a number which is probabilistically prime + PRIME}; + //@} + + /// \name CREATORS + //@{ + /// \brief Creates the zero integer + Integer(); + + /// copy constructor + Integer(const Integer& t); + + /// \brief Convert from signed long + Integer(signed long value); + + /// \brief Convert from lword + /// \param sign enumeration indicating Sign + /// \param value the long word + Integer(Sign sign, lword value); + + /// \brief Convert from two words + /// \param sign enumeration indicating Sign + /// \param highWord the high word + /// \param lowWord the low word + Integer(Sign sign, word highWord, word lowWord); + + /// \brief Convert from a C-string + /// \param str C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case + /// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const char *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a wide C-string + /// \param str wide C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case + /// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const wchar_t *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian byte array + /// \param encodedInteger big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the array to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(const byte *encodedInteger, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian array + /// \param bt BufferedTransformation object with big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the data to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(BufferedTransformation &bt, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a BER encoded byte array + /// \param bt BufferedTransformation object with BER encoded byte array + explicit Integer(BufferedTransformation &bt); + + /// \brief Create a random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + Integer(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Integer representing 0 + /// \return an Integer representing 0 + /// \details Zero() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Zero(); + /// \brief Integer representing 1 + /// \return an Integer representing 1 + /// \details One() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API One(); + /// \brief Integer representing 2 + /// \return an Integer representing 2 + /// \details Two() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Two(); + + /// \brief Create a random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType=ANY, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Exponentiates to a power of 2 + /// \return the Integer 2e + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + static Integer CRYPTOPP_API Power2(size_t e); + //@} + + /// \name ENCODE/DECODE + //@{ + /// \brief Minimum number of bytes to encode this integer + /// \param sign enumeration indicating Signedness + /// \note The MinEncodedSize() of 0 is 1. + size_t MinEncodedSize(Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param output big-endian byte array + /// \param outputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param bt BufferedTransformation object + /// \param outputLen length of the encoding + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(BufferedTransformation &bt, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in DER format + /// \param bt BufferedTransformation object + /// \details Encodes the Integer using Distinguished Encoding Rules + /// The result is placed into a BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encode absolute value as big-endian octet string + /// \param bt BufferedTransformation object + /// \param length the number of mytes to decode + void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param output big-endian byte array + /// \param bufferSize length of the byte array + /// \return length of the output + /// \details OpenPGPEncode places result into the buffer and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(byte *output, size_t bufferSize) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param bt BufferedTransformation object + /// \return length of the output + /// \details OpenPGPEncode places result into a BufferedTransformation object and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(BufferedTransformation &bt) const; + + /// \brief Decode from big-endian byte array + /// \param input big-endian byte array + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode nonnegative value from big-endian byte array + /// \param bt BufferedTransformation object + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \note bt.MaxRetrievable() \>= inputLen. + void Decode(BufferedTransformation &bt, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode from BER format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void BERDecode(const byte *input, size_t inputLen); + + /// \brief Decode from BER format + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief Decode nonnegative value from big-endian octet string + /// \param bt BufferedTransformation object + /// \param length length of the byte array + void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length); + + /// \brief Exception thrown when an error is encountered decoding an OpenPGP integer + class OpenPGPDecodeErr : public Exception + { + public: + OpenPGPDecodeErr() : Exception(INVALID_DATA_FORMAT, "OpenPGP decode error") {} + }; + + /// \brief Decode from OpenPGP format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void OpenPGPDecode(const byte *input, size_t inputLen); + /// \brief Decode from OpenPGP format + /// \param bt BufferedTransformation object + void OpenPGPDecode(BufferedTransformation &bt); + //@} + + /// \name ACCESSORS + //@{ + /// \brief Determines if the Integer is convertable to Long + /// \return true if *this can be represented as a signed long + /// \sa ConvertToLong() + bool IsConvertableToLong() const; + /// \brief Convert the Integer to Long + /// \return equivalent signed long if possible, otherwise undefined + /// \sa IsConvertableToLong() + signed long ConvertToLong() const; + + /// \brief Determines the number of bits required to represent the Integer + /// \return number of significant bits + /// \details BitCount is calculated as floor(log2(abs(*this))) + 1. + unsigned int BitCount() const; + /// \brief Determines the number of bytes required to represent the Integer + /// \return number of significant bytes + /// \details ByteCount is calculated as ceiling(BitCount()/8). + unsigned int ByteCount() const; + /// \brief Determines the number of words required to represent the Integer + /// \return number of significant words + /// \details WordCount is calculated as ceiling(ByteCount()/sizeof(word)). + unsigned int WordCount() const; + + /// \brief Provides the i-th bit of the Integer + /// \return the i-th bit, i=0 being the least significant bit + bool GetBit(size_t i) const; + /// \brief Provides the i-th byte of the Integer + /// \return the i-th byte + byte GetByte(size_t i) const; + /// \brief Provides the low order bits of the Integer + /// \return n lowest bits of *this >> i + lword GetBits(size_t i, size_t n) const; + + /// \brief Determines if the Integer is 0 + /// \return true if the Integer is 0, false otherwise + bool IsZero() const {return !*this;} + /// \brief Determines if the Integer is non-0 + /// \return true if the Integer is non-0, false otherwise + bool NotZero() const {return !IsZero();} + /// \brief Determines if the Integer is negative + /// \return true if the Integer is negative, false otherwise + bool IsNegative() const {return sign == NEGATIVE;} + /// \brief Determines if the Integer is non-negative + /// \return true if the Integer is non-negative, false otherwise + bool NotNegative() const {return !IsNegative();} + /// \brief Determines if the Integer is positive + /// \return true if the Integer is positive, false otherwise + bool IsPositive() const {return NotNegative() && NotZero();} + /// \brief Determines if the Integer is non-positive + /// \return true if the Integer is non-positive, false otherwise + bool NotPositive() const {return !IsPositive();} + /// \brief Determines if the Integer is even parity + /// \return true if the Integer is even, false otherwise + bool IsEven() const {return GetBit(0) == 0;} + /// \brief Determines if the Integer is odd parity + /// \return true if the Integer is odd, false otherwise + bool IsOdd() const {return GetBit(0) == 1;} + //@} + + /// \name MANIPULATORS + //@{ + /// \brief Assignment + /// \param t the other Integer + /// \return the result of assignment + Integer& operator=(const Integer& t); + /// \brief Addition Assignment + /// \param t the other Integer + /// \return the result of *this + t + Integer& operator+=(const Integer& t); + /// \brief Subtraction Assignment + /// \param t the other Integer + /// \return the result of *this - t + Integer& operator-=(const Integer& t); + /// \brief Multiplication Assignment + /// \param t the other Integer + /// \return the result of *this * t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator*=(const Integer& t) {return *this = Times(t);} + /// \brief Division Assignment + /// \param t the other Integer + /// \return the result of *this / t + Integer& operator/=(const Integer& t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \param t the other Integer + /// \return the result of *this % t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(const Integer& t) {return *this = Modulo(t);} + /// \brief Division Assignment + /// \param t the other word + /// \return the result of *this / t + Integer& operator/=(word t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \param t the other word + /// \return the result of *this % t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));} + + /// \brief Left-shift Assignment + /// \param n number of bits to shift + /// \return reference to this Integer + Integer& operator<<=(size_t n); + /// \brief Right-shift Assignment + /// \param n number of bits to shift + /// \return reference to this Integer + Integer& operator>>=(size_t n); + + /// \brief Bitwise AND Assignment + /// \param t the other Integer + /// \return the result of *this & t + /// \details operator&=() performs a bitwise AND on *this. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator&=(const Integer& t); + /// \brief Bitwise OR Assignment + /// \param t the second Integer + /// \return the result of *this | t + /// \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator|=(const Integer& t); + /// \brief Bitwise XOR Assignment + /// \param t the other Integer + /// \return the result of *this ^ t + /// \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted + /// in at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator^=(const Integer& t); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + void Randomize(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \details The random integer created is uniformly distributed over [min, max]. + void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); + + /// \brief Set this Integer to random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + bool Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \return true if a random number was generated, false otherwise + /// \details GenerateRandomNoThrow attempts to generate a random number according to the + /// parameters specified in params. The function does not throw RandomNumberNotFound. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///     AutoSeededRandomPool prng;
+		///     AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                                ("RandomNumberType", Integer::PRIME);
+		///     Integer x;
+		///     if (x.GenerateRandomNoThrow(prng, params) == false)
+		///         throw std::runtime_error("Failed to generate prime number");
+		/// 
+ bool GenerateRandomNoThrow(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \throw RandomNumberNotFound if a random number is not found + /// \details GenerateRandom attempts to generate a random number according to the + /// parameters specified in params. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///     AutoSeededRandomPool prng;
+		///     AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                                ("RandomNumberType", Integer::PRIME);
+		///     Integer x;
+		///     try { x.GenerateRandom(prng, params); }
+		///     catch (RandomNumberNotFound&) { x = -1; }
+		/// 
+ void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) + { + if (!GenerateRandomNoThrow(rng, params)) + throw RandomNumberNotFound(); + } + + /// \brief Set the n-th bit to value + /// \details 0-based numbering. + void SetBit(size_t n, bool value=1); + + /// \brief Set the n-th byte to value + /// \details 0-based numbering. + void SetByte(size_t n, byte value); + + /// \brief Reverse the Sign of the Integer + void Negate(); + + /// \brief Sets the Integer to positive + void SetPositive() {sign = POSITIVE;} + + /// \brief Sets the Integer to negative + void SetNegative() {if (!!(*this)) sign = NEGATIVE;} + + /// \brief Swaps this Integer with another Integer + void swap(Integer &a); + //@} + + /// \name UNARY OPERATORS + //@{ + /// \brief Negation + bool operator!() const; + /// \brief Addition + Integer operator+() const {return *this;} + /// \brief Subtraction + Integer operator-() const; + /// \brief Pre-increment + Integer& operator++(); + /// \brief Pre-decrement + Integer& operator--(); + /// \brief Post-increment + Integer operator++(int) {Integer temp = *this; ++*this; return temp;} + /// \brief Post-decrement + Integer operator--(int) {Integer temp = *this; --*this; return temp;} + //@} + + /// \name BINARY OPERATORS + //@{ + /// \brief Perform signed comparison + /// \param a the Integer to comapre + /// \retval -1 if *this < a + /// \retval 0 if *this = a + /// \retval 1 if *this > a + int Compare(const Integer& a) const; + + /// \brief Addition + Integer Plus(const Integer &b) const; + /// \brief Subtraction + Integer Minus(const Integer &b) const; + /// \brief Multiplication + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Times(const Integer &b) const; + /// \brief Division + Integer DividedBy(const Integer &b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Modulo(const Integer &b) const; + /// \brief Division + Integer DividedBy(word b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word Modulo(word b) const; + + /// \brief Bitwise AND + /// \param t the other Integer + /// \return the result of *this & t + /// \details And() performs a bitwise AND on the operands. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer And(const Integer& t) const; + + /// \brief Bitwise OR + /// \param t the other Integer + /// \return the result of *this | t + /// \details Or() performs a bitwise OR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Or(const Integer& t) const; + + /// \brief Bitwise XOR + /// \param t the other Integer + /// \return the result of *this ^ t + /// \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Xor(const Integer& t) const; + + /// \brief Right-shift + Integer operator>>(size_t n) const {return Integer(*this)>>=n;} + /// \brief Left-shift + Integer operator<<(size_t n) const {return Integer(*this)<<=n;} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// \brief Retrieve the absolute value of this integer + Integer AbsoluteValue() const; + /// \brief Add this integer to itself + Integer Doubled() const {return Plus(*this);} + /// \brief Multiply this integer by itself + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Squared() const {return Times(*this);} + /// \brief Extract square root + /// \details if negative return 0, else return floor of square root + Integer SquareRoot() const; + /// \brief Determine whether this integer is a perfect square + bool IsSquare() const; + + /// \brief Determine if 1 or -1 + /// \return true if this integer is 1 or -1, false otherwise + bool IsUnit() const; + /// \brief Calculate multiplicative inverse + /// \return MultiplicativeInverse inverse if 1 or -1, otherwise return 0. + Integer MultiplicativeInverse() const; + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param d a reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param d a reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// This overload uses a faster division algorithm because the divisor is short. + static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a a reference to the dividend + /// \param n a reference to the divisor + /// \details DivideByPowerOf2 calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// It returns same result as Divide(r, q, a, Power2(n)), but faster. + /// This overload uses a faster division algorithm because the divisor is a power of 2. + static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n); + + /// \brief Calculate greatest common divisor + /// \param a a reference to the first number + /// \param n a reference to the secind number + /// \return the greatest common divisor a and n. + static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n); + + /// \brief Calculate multiplicative inverse + /// \param n a reference to the modulus + /// \return an Integer *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the Integer n. If no Integer exists then Integer 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer InverseMod(const Integer &n) const; + + /// \brief Calculate multiplicative inverse + /// \param n the modulus + /// \return a word *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the word n. If no Integer exists then word 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word InverseMod(word n) const; + //@} + + /// \name INPUT/OUTPUT + //@{ + /// \brief Extraction operator + /// \param in a reference to a std::istream + /// \param a a reference to an Integer + /// \return a reference to a std::istream reference + friend CRYPTOPP_DLL std::istream& CRYPTOPP_API operator>>(std::istream& in, Integer &a); + + /// \brief Insertion operator + /// \param out a reference to a std::ostream + /// \param a a constant reference to an Integer + /// \return a reference to a std::ostream reference + /// \details The output integer responds to std::hex, std::oct, std::hex, std::upper and + /// std::lower. The output includes the suffix \a h (for hex), \a . (\a dot, for dec) + /// and \a o (for octal). There is currently no way to suppress the suffix. + /// \details If you want to print an Integer without the suffix or using an arbitrary base, then + /// use IntToString(). + /// \sa IntToString + friend CRYPTOPP_DLL std::ostream& CRYPTOPP_API operator<<(std::ostream& out, const Integer &a); + //@} + + /// \brief Modular multiplication + /// \param x a reference to the first term + /// \param y a reference to the second term + /// \param m a reference to the modulus + /// \return an Integer (a * b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m); + /// \brief Modular exponentiation + /// \param x a reference to the base + /// \param e a reference to the exponent + /// \param m a reference to the modulus + /// \return an Integer (a ^ b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m); + +protected: + + // http://github.com/weidai11/cryptopp/issues/602 + Integer InverseModNext(const Integer &n) const; + +private: + + Integer(word value, size_t length); + int PositiveCompare(const Integer &t) const; + + IntegerSecBlock reg; + Sign sign; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + friend class ModularArithmetic; + friend class MontgomeryRepresentation; + friend class HalfMontgomeryRepresentation; + + friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b); + friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b); + friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b); + friend void PositiveDivide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor); +#endif +}; + +/// \brief Comparison +inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;} +/// \brief Comparison +inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;} +/// \brief Comparison +inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;} +/// \brief Comparison +inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;} +/// \brief Comparison +inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;} +/// \brief Comparison +inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;} +/// \brief Addition +inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);} +/// \brief Subtraction +inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);} +/// \brief Multiplication +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);} + +/// \brief Bitwise AND +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a & b +/// \details operator&() performs a bitwise AND on the operands. Missing bits are truncated +/// at the most significant bit positions, so the result is as small as the +/// smaller of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);} + +/// \brief Bitwise OR +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a | b +/// \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in +/// at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);} + +/// \brief Bitwise XOR +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a ^ b +/// \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted +/// in at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);} + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/extension/third_party/cryptopp/iterhash.cpp b/extension/third_party/cryptopp/iterhash.cpp new file mode 100644 index 00000000..938a0fac --- /dev/null +++ b/extension/third_party/cryptopp/iterhash.cpp @@ -0,0 +1,200 @@ +// iterhash.cpp - originally written and placed in the public domain by Wei Dai + +#ifndef __GNUC__ +#define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#endif + +#include "iterhash.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +template void IteratedHashBase::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0)); + if (length == 0) { return; } + + HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi; + if ((m_countLo = oldCountLo + HashWordType(length)) < oldCountLo) + m_countHi++; // carry from low to high + m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(length); + if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(length) != 0) + throw HashInputTooLong(this->AlgorithmName()); + + const unsigned int blockSize = this->BlockSize(); + unsigned int num = ModPowerOf2(oldCountLo, blockSize); + + T* dataBuf = this->DataBuf(); + byte* data = (byte *)dataBuf; + + if (num != 0) // process left over data + { + if (num+length >= blockSize) + { + if (input) + {std::memcpy(data+num, input, blockSize-num);} + + HashBlock(dataBuf); + input += (blockSize-num); + length -= (blockSize-num); + num = 0; + // drop through and do the rest + } + else + { + if (input && length) + {std::memcpy(data+num, input, length);} + return; + } + } + + // now process the input data in blocks of blockSize bytes and save the leftovers to m_data + if (length >= blockSize) + { + if (input == data) + { + CRYPTOPP_ASSERT(length == blockSize); + HashBlock(dataBuf); + return; + } + else if (IsAligned(input)) + { + size_t leftOver = HashMultipleBlocks((T *)(void*)input, length); + input += (length - leftOver); + length = leftOver; + } + else + { + do + { // copy input first if it's not aligned correctly + if (input) + { std::memcpy(data, input, blockSize); } + + HashBlock(dataBuf); + input+=blockSize; + length-=blockSize; + } while (length >= blockSize); + } + } + + if (input && data != input) + std::memcpy(data, input, length); +} + +template byte * IteratedHashBase::CreateUpdateSpace(size_t &size) +{ + unsigned int blockSize = this->BlockSize(); + unsigned int num = ModPowerOf2(m_countLo, blockSize); + size = blockSize - num; + return (byte *)DataBuf() + num; +} + +template size_t IteratedHashBase::HashMultipleBlocks(const T *input, size_t length) +{ + const unsigned int blockSize = this->BlockSize(); + bool noReverse = NativeByteOrderIs(this->GetByteOrder()); + T* dataBuf = this->DataBuf(); + + // Alignment checks due to http://github.com/weidai11/cryptopp/issues/690. + // Sparc requires 8-byte aligned buffer when HashWordType is word64. + // We also had to provide a GetAlignmentOf specialization for word64 on Sparc. + + do + { + if (noReverse) + { + if (IsAligned(input)) + { + // Sparc bus error with non-aligned input. + this->HashEndianCorrectedBlock(input); + } + else + { + std::memcpy(dataBuf, input, blockSize); + this->HashEndianCorrectedBlock(dataBuf); + } + } + else + { + if (IsAligned(input)) + { + // Sparc bus error with non-aligned input. + ByteReverse(dataBuf, input, blockSize); + this->HashEndianCorrectedBlock(dataBuf); + } + else + { + std::memcpy(dataBuf, input, blockSize); + ByteReverse(dataBuf, dataBuf, blockSize); + this->HashEndianCorrectedBlock(dataBuf); + } + } + + input += blockSize/sizeof(T); + length -= blockSize; + } + while (length >= blockSize); + return length; +} + +template void IteratedHashBase::PadLastBlock(unsigned int lastBlockSize, byte padFirst) +{ + unsigned int blockSize = this->BlockSize(); + unsigned int num = ModPowerOf2(m_countLo, blockSize); + T* dataBuf = this->DataBuf(); + byte* data = (byte *)dataBuf; + + data[num++] = padFirst; + if (num <= lastBlockSize) + memset(data+num, 0, lastBlockSize-num); + else + { + memset(data+num, 0, blockSize-num); + HashBlock(dataBuf); + memset(data, 0, lastBlockSize); + } +} + +template void IteratedHashBase::Restart() +{ + m_countLo = m_countHi = 0; + Init(); +} + +template void IteratedHashBase::TruncatedFinal(byte *digest, size_t size) +{ + CRYPTOPP_ASSERT(digest != NULLPTR); + this->ThrowIfInvalidTruncatedSize(size); + + T* dataBuf = this->DataBuf(); + T* stateBuf = this->StateBuf(); + unsigned int blockSize = this->BlockSize(); + ByteOrder order = this->GetByteOrder(); + + PadLastBlock(blockSize - 2*sizeof(HashWordType)); + dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo()); + dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi()); + + HashBlock(dataBuf); + + if (IsAligned(digest) && size%sizeof(HashWordType)==0) + ConditionalByteReverse(order, (HashWordType *)(void*)digest, stateBuf, size); + else + { + ConditionalByteReverse(order, stateBuf, stateBuf, this->DigestSize()); + std::memcpy(digest, stateBuf, size); + } + + this->Restart(); // reinit for next use +} + +#if defined(__GNUC__) || defined(__clang__) + template class IteratedHashBase; + template class IteratedHashBase; + + template class IteratedHashBase; + template class IteratedHashBase; +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/iterhash.h b/extension/third_party/cryptopp/iterhash.h new file mode 100644 index 00000000..5a65b5ba --- /dev/null +++ b/extension/third_party/cryptopp/iterhash.h @@ -0,0 +1,217 @@ +// iterhash.h - originally written and placed in the public domain by Wei Dai + +/// \file iterhash.h +/// \brief Base classes for iterated hashes + +#ifndef CRYPTOPP_ITERHASH_H +#define CRYPTOPP_ITERHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "simple.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when trying to hash more data than is allowed by a hash function +class CRYPTOPP_DLL HashInputTooLong : public InvalidDataFormat +{ +public: + explicit HashInputTooLong(const std::string &alg) + : InvalidDataFormat("IteratedHashBase: input data exceeds maximum allowed by hash function " + alg) {} +}; + +/// \brief Iterated hash base class +/// \tparam T Hash word type +/// \tparam BASE HashTransformation derived class +/// \details IteratedHashBase provides an interface for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashBase : public BASE +{ +public: + typedef T HashWordType; + + virtual ~IteratedHashBase() {} + + /// \brief Construct an IteratedHashBase + IteratedHashBase() : m_countLo(0), m_countHi(0) {} + + /// \brief Provides the input block size most efficient for this cipher. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + unsigned int OptimalBlockSize() const {return this->BlockSize();} + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \details OptimalDataAlignment returns the natural alignment of the hash word. + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + void Update(const byte *input, size_t length); + + /// \brief Requests space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + byte * CreateUpdateSpace(size_t &size); + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + void Restart(); + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + void TruncatedFinal(byte *digest, size_t digestSize); + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } + +protected: + inline T GetBitCountHi() const + {return (m_countLo >> (8*sizeof(T)-3)) + (m_countHi << 3);} + inline T GetBitCountLo() const + {return m_countLo << 3;} + + void PadLastBlock(unsigned int lastBlockSize, byte padFirst=0x80); + virtual void Init() =0; + + virtual ByteOrder GetByteOrder() const =0; + virtual void HashEndianCorrectedBlock(const HashWordType *data) =0; + virtual size_t HashMultipleBlocks(const T *input, size_t length); + void HashBlock(const HashWordType *input) + {HashMultipleBlocks(input, this->BlockSize());} + + virtual T* DataBuf() =0; + virtual T* StateBuf() =0; + +private: + T m_countLo, m_countHi; +}; + +/// \brief Iterated hash base class +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_Base HashTransformation derived class +/// \details IteratedHash provides a default implementation for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHash : public IteratedHashBase +{ +public: + typedef T_Endianness ByteOrderClass; + typedef T_HashWordType HashWordType; + + CRYPTOPP_CONSTANT(BLOCKSIZE = T_BlockSize); + // BCB2006 workaround: can't use BLOCKSIZE here + CRYPTOPP_COMPILE_ASSERT((T_BlockSize & (T_BlockSize - 1)) == 0); // blockSize is a power of 2 + + virtual ~IteratedHash() {} + + /// \brief Provides the block size of the hash + /// \return the block size of the hash, in bytes + /// \details BlockSize() returns T_BlockSize. + unsigned int BlockSize() const {return T_BlockSize;} + + /// \brief Provides the byte order of the hash + /// \return the byte order of the hash as an enumeration + /// \details GetByteOrder() returns T_Endianness::ToEnum(). + /// \sa ByteOrder() + ByteOrder GetByteOrder() const {return T_Endianness::ToEnum();} + + /// \brief Adjusts the byte ordering of the hash + /// \param out the output buffer + /// \param in the input buffer + /// \param byteCount the size of the buffers, in bytes + /// \details CorrectEndianess() calls ConditionalByteReverse() using T_Endianness. + inline void CorrectEndianess(HashWordType *out, const HashWordType *in, size_t byteCount) + { + CRYPTOPP_ASSERT(in != NULLPTR); + CRYPTOPP_ASSERT(out != NULLPTR); + CRYPTOPP_ASSERT(IsAligned(in)); + CRYPTOPP_ASSERT(IsAligned(out)); + + ConditionalByteReverse(T_Endianness::ToEnum(), out, in, byteCount); + } + +protected: + enum { Blocks = T_BlockSize/sizeof(T_HashWordType) }; + T_HashWordType* DataBuf() {return this->m_data;} + FixedSizeSecBlock m_data; +}; + +/// \brief Iterated hash with a static transformation function +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_StateSize Internal state size of the hash +/// \tparam T_Transform HashTransformation derived class +/// \tparam T_DigestSize Digest size of the hash +/// \tparam T_StateAligned Flag indicating if state is 16-byte aligned +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashWithStaticTransform + : public ClonableImpl, T_Transform> > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize ? T_DigestSize : T_StateSize); + + virtual ~IteratedHashWithStaticTransform() {} + + /// \brief Provides the digest size of the hash + /// \return the digest size of the hash, in bytes + /// \details DigestSize() returns DIGESTSIZE. + unsigned int DigestSize() const {return DIGESTSIZE;} + +protected: + IteratedHashWithStaticTransform() {this->Init();} + void HashEndianCorrectedBlock(const T_HashWordType *data) {T_Transform::Transform(this->m_state, data);} + void Init() {T_Transform::InitState(this->m_state);} + + enum { Blocks = T_BlockSize/sizeof(T_HashWordType) }; + T_HashWordType* StateBuf() {return this->m_state;} + FixedSizeAlignedSecBlock m_state; +}; + +#if !defined(__GNUC__) && !defined(__clang__) + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; + + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/kalyna.cpp b/extension/third_party/cryptopp/kalyna.cpp new file mode 100644 index 00000000..14d411e1 --- /dev/null +++ b/extension/third_party/cryptopp/kalyna.cpp @@ -0,0 +1,1362 @@ +// kalyna.cpp - written and placed in the public domain by Jeffrey Walton +// This code relied upon three sources. First was Oliynykov, Gorbenko, Kazymyrov, Ruzhentsev, +// Kuznetsov, Gorbenko, Dyrda, Dolgov, Pushkaryov, Mordvinov and Kaidalov's "A New Encryption +// Standard of Ukraine: The Kalyna Block Cipher" (http://eprint.iacr.org/2015/650.pdf). Second +// was Roman Oliynykov and Oleksandr Kazymyrov's GitHub with the reference implementation +// (http://github.com/Roman-Oliynykov/Kalyna-reference). The third and most utilized resource +// was Keru Kuro's public domain implementation of Kalyna in CppCrypto +// (http://sourceforge.net/projects/cppcrypto/). Kuro has an outstanding implementation that +// performed better than the reference implementation and our initial attempts. The only downside +// was the missing big endian port. + +#include "pch.h" +#include "config.h" + +#include "kalyna.h" +#include "argnames.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(KalynaTab) + +// T can be shared between Kupyna and Kalyna; IT, S and IS are Kalyna specific +extern const word64 T[8][256]; // Columns +extern const word64 IT[8][256]; // Inverse +extern const byte S[4][256]; // Substitution +extern const byte IS[4][256]; // Inverse + +NAMESPACE_END +NAMESPACE_END + +ANONYMOUS_NAMESPACE_BEGIN + +// The typedef here is to sidestep problems with byte in the global namespace +typedef unsigned char byte; + +using CryptoPP::word64; +using CryptoPP::KalynaTab::T; +using CryptoPP::KalynaTab::S; +using CryptoPP::KalynaTab::IT; +using CryptoPP::KalynaTab::IS; + +template +inline void MakeOddKey(const word64 evenkey[NB], word64 oddkey[NB]) +{ +#if (CRYPTOPP_BIG_ENDIAN) + if (NB == 2) + { + oddkey[0] = (evenkey[1] << 8) | (evenkey[0] >> 56); + oddkey[1] = (evenkey[0] << 8) | (evenkey[1] >> 56); + } + else if (NB == 4) + { + oddkey[0] = (evenkey[2] << 40) | (evenkey[1] >> 24); + oddkey[1] = (evenkey[3] << 40) | (evenkey[2] >> 24); + oddkey[2] = (evenkey[0] << 40) | (evenkey[3] >> 24); + oddkey[3] = (evenkey[1] << 40) | (evenkey[0] >> 24); + } + else if (NB == 8) + { + oddkey[0] = (evenkey[3] << 40) | (evenkey[2] >> 24); + oddkey[1] = (evenkey[4] << 40) | (evenkey[3] >> 24); + oddkey[2] = (evenkey[5] << 40) | (evenkey[4] >> 24); + oddkey[3] = (evenkey[6] << 40) | (evenkey[5] >> 24); + + oddkey[4] = (evenkey[7] << 40) | (evenkey[6] >> 24); + oddkey[5] = (evenkey[0] << 40) | (evenkey[7] >> 24); + oddkey[6] = (evenkey[1] << 40) | (evenkey[0] >> 24); + oddkey[7] = (evenkey[2] << 40) | (evenkey[1] >> 24); + } + else + { + CRYPTOPP_ASSERT(0); + } +#else + static const unsigned int U = (NB == 2) ? 16 : (NB == 4) ? 32 : (NB == 8) ? 64 : -1; + static const unsigned int V = (NB == 2) ? 7 : (NB == 4) ? 11 : (NB == 8) ? 19 : -1; + + const byte* even = reinterpret_cast(evenkey); + byte* odd = reinterpret_cast(oddkey); + + memcpy(odd, even + V, U - V); + memcpy(odd + U - V, even, V); +#endif +} + +template +inline void SwapBlocks(word64 k[NB]) +{ + const word64 t = k[0]; + k[0] = k[1]; + + if (NB > 2) + { + k[1] = k[2]; + k[2] = k[3]; + } + + if (NB > 4) + { + k[3] = k[4]; + k[4] = k[5]; + k[5] = k[6]; + k[6] = k[7]; + } + + k[NB - 1] = t; +} + +template +inline void AddKey(const word64 x[NB], word64 y[NB], const word64 k[NB]) +{ + y[0] = x[0] + k[0]; + y[1] = x[1] + k[1]; + + if (NB > 2) + { + y[2] = x[2] + k[2]; + y[3] = x[3] + k[3]; + } + + if (NB > 4) + { + y[4] = x[4] + k[4]; + y[5] = x[5] + k[5]; + y[6] = x[6] + k[6]; + y[7] = x[7] + k[7]; + } +} + +template +inline void SubKey(const word64 x[NB], word64 y[NB], const word64 k[NB]) +{ + y[0] = x[0] - k[0]; + y[1] = x[1] - k[1]; + + if (NB > 2) + { + y[2] = x[2] - k[2]; + y[3] = x[3] - k[3]; + } + + if (NB > 4) + { + y[4] = x[4] - k[4]; + y[5] = x[5] - k[5]; + y[6] = x[6] - k[6]; + y[7] = x[7] - k[7]; + } +} + +template +static inline void AddConstant(word64 src[NB], word64 dst[NB], word64 constant) +{ + dst[0] = src[0] + constant; + dst[1] = src[1] + constant; + + if (NB > 2) + { + dst[2] = src[2] + constant; + dst[3] = src[3] + constant; + } + + if (NB > 4) + { + dst[4] = src[4] + constant; + dst[5] = src[5] + constant; + dst[6] = src[6] + constant; + dst[7] = src[7] + constant; + } +} + +inline void G0128(const word64 x[2], word64 y[2]) +{ + y[0] = T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +inline void G0256(const word64 x[4], word64 y[4]) +{ + y[0] = T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[2] >> 56)]; + y[2] = T[0][(byte)x[2]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[3] >> 56)]; + y[3] = T[0][(byte)x[3]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +inline void G0512(const word64 x[8], word64 y[8]) +{ + y[0] = T[0][(byte)x[0]] ^ T[1][(byte)(x[7] >> 8)] ^ T[2][(byte)(x[6] >> 16)] ^ T[3][(byte)(x[5] >> 24)] ^ + T[4][(byte)(x[4] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = T[0][(byte)x[1]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[7] >> 16)] ^ T[3][(byte)(x[6] >> 24)] ^ + T[4][(byte)(x[5] >> 32)] ^ T[5][(byte)(x[4] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[2] >> 56)]; + y[2] = T[0][(byte)x[2]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[7] >> 24)] ^ + T[4][(byte)(x[6] >> 32)] ^ T[5][(byte)(x[5] >> 40)] ^ T[6][(byte)(x[4] >> 48)] ^ T[7][(byte)(x[3] >> 56)]; + y[3] = T[0][(byte)x[3]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[7] >> 32)] ^ T[5][(byte)(x[6] >> 40)] ^ T[6][(byte)(x[5] >> 48)] ^ T[7][(byte)(x[4] >> 56)]; + y[4] = T[0][(byte)x[4]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[7] >> 40)] ^ T[6][(byte)(x[6] >> 48)] ^ T[7][(byte)(x[5] >> 56)]; + y[5] = T[0][(byte)x[5]] ^ T[1][(byte)(x[4] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[7] >> 48)] ^ T[7][(byte)(x[6] >> 56)]; + y[6] = T[0][(byte)x[6]] ^ T[1][(byte)(x[5] >> 8)] ^ T[2][(byte)(x[4] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[7] >> 56)]; + y[7] = T[0][(byte)x[7]] ^ T[1][(byte)(x[6] >> 8)] ^ T[2][(byte)(x[5] >> 16)] ^ T[3][(byte)(x[4] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +inline void GL128(const word64 x[2], word64 y[2], const word64 k[2]) +{ + y[0] = k[0] + (T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]); + y[1] = k[1] + (T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]); +} + +inline void GL256(const word64 x[4], word64 y[4], const word64 k[4]) +{ + y[0] = k[0] + (T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]); + y[1] = k[1] + (T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[2] >> 56)]); + y[2] = k[2] + (T[0][(byte)x[2]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[3] >> 56)]); + y[3] = k[3] + (T[0][(byte)x[3]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]); +} + +inline void GL512(const word64 x[8], word64 y[8], const word64 k[8]) +{ + y[0] = k[0] + (T[0][(byte)x[0]] ^ T[1][(byte)(x[7] >> 8)] ^ T[2][(byte)(x[6] >> 16)] ^ T[3][(byte)(x[5] >> 24)] ^ + T[4][(byte)(x[4] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[1] >> 56)]); + y[1] = k[1] + (T[0][(byte)x[1]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[7] >> 16)] ^ T[3][(byte)(x[6] >> 24)] ^ + T[4][(byte)(x[5] >> 32)] ^ T[5][(byte)(x[4] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[2] >> 56)]); + y[2] = k[2] + (T[0][(byte)x[2]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[7] >> 24)] ^ + T[4][(byte)(x[6] >> 32)] ^ T[5][(byte)(x[5] >> 40)] ^ T[6][(byte)(x[4] >> 48)] ^ T[7][(byte)(x[3] >> 56)]); + y[3] = k[3] + (T[0][(byte)x[3]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[7] >> 32)] ^ T[5][(byte)(x[6] >> 40)] ^ T[6][(byte)(x[5] >> 48)] ^ T[7][(byte)(x[4] >> 56)]); + y[4] = k[4] + (T[0][(byte)x[4]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[7] >> 40)] ^ T[6][(byte)(x[6] >> 48)] ^ T[7][(byte)(x[5] >> 56)]); + y[5] = k[5] + (T[0][(byte)x[5]] ^ T[1][(byte)(x[4] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[7] >> 48)] ^ T[7][(byte)(x[6] >> 56)]); + y[6] = k[6] + (T[0][(byte)x[6]] ^ T[1][(byte)(x[5] >> 8)] ^ T[2][(byte)(x[4] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[7] >> 56)]); + y[7] = k[7] + (T[0][(byte)x[7]] ^ T[1][(byte)(x[6] >> 8)] ^ T[2][(byte)(x[5] >> 16)] ^ T[3][(byte)(x[4] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[0] >> 56)]); +} + +inline void IMC128(word64 x[2]) +{ + x[0] = IT[0][S[0][(byte)x[0]]] ^ IT[1][S[1][(byte)(x[0] >> 8)]] ^ IT[2][S[2][(byte)(x[0] >> 16)]] ^ IT[3][S[3][(byte)(x[0] >> 24)]] ^ + IT[4][S[0][(byte)(x[0] >> 32)]] ^ IT[5][S[1][(byte)(x[0] >> 40)]] ^ IT[6][S[2][(byte)(x[0] >> 48)]] ^ IT[7][S[3][(byte)(x[0] >> 56)]]; + x[1] = IT[0][S[0][(byte)x[1]]] ^ IT[1][S[1][(byte)(x[1] >> 8)]] ^ IT[2][S[2][(byte)(x[1] >> 16)]] ^ IT[3][S[3][(byte)(x[1] >> 24)]] ^ + IT[4][S[0][(byte)(x[1] >> 32)]] ^ IT[5][S[1][(byte)(x[1] >> 40)]] ^ IT[6][S[2][(byte)(x[1] >> 48)]] ^ IT[7][S[3][(byte)(x[1] >> 56)]]; +} + +inline void IMC256(word64 x[4]) +{ + x[0] = IT[0][S[0][(byte)x[0]]] ^ IT[1][S[1][(byte)(x[0] >> 8)]] ^ IT[2][S[2][(byte)(x[0] >> 16)]] ^ IT[3][S[3][(byte)(x[0] >> 24)]] ^ + IT[4][S[0][(byte)(x[0] >> 32)]] ^ IT[5][S[1][(byte)(x[0] >> 40)]] ^ IT[6][S[2][(byte)(x[0] >> 48)]] ^ IT[7][S[3][(byte)(x[0] >> 56)]]; + x[1] = IT[0][S[0][(byte)x[1]]] ^ IT[1][S[1][(byte)(x[1] >> 8)]] ^ IT[2][S[2][(byte)(x[1] >> 16)]] ^ IT[3][S[3][(byte)(x[1] >> 24)]] ^ + IT[4][S[0][(byte)(x[1] >> 32)]] ^ IT[5][S[1][(byte)(x[1] >> 40)]] ^ IT[6][S[2][(byte)(x[1] >> 48)]] ^ IT[7][S[3][(byte)(x[1] >> 56)]]; + x[2] = IT[0][S[0][(byte)x[2]]] ^ IT[1][S[1][(byte)(x[2] >> 8)]] ^ IT[2][S[2][(byte)(x[2] >> 16)]] ^ IT[3][S[3][(byte)(x[2] >> 24)]] ^ + IT[4][S[0][(byte)(x[2] >> 32)]] ^ IT[5][S[1][(byte)(x[2] >> 40)]] ^ IT[6][S[2][(byte)(x[2] >> 48)]] ^ IT[7][S[3][(byte)(x[2] >> 56)]]; + x[3] = IT[0][S[0][(byte)x[3]]] ^ IT[1][S[1][(byte)(x[3] >> 8)]] ^ IT[2][S[2][(byte)(x[3] >> 16)]] ^ IT[3][S[3][(byte)(x[3] >> 24)]] ^ + IT[4][S[0][(byte)(x[3] >> 32)]] ^ IT[5][S[1][(byte)(x[3] >> 40)]] ^ IT[6][S[2][(byte)(x[3] >> 48)]] ^ IT[7][S[3][(byte)(x[3] >> 56)]]; +} + +inline void IMC512(word64 x[8]) +{ + x[0] = IT[0][S[0][(byte)x[0]]] ^ IT[1][S[1][(byte)(x[0] >> 8)]] ^ IT[2][S[2][(byte)(x[0] >> 16)]] ^ IT[3][S[3][(byte)(x[0] >> 24)]] ^ + IT[4][S[0][(byte)(x[0] >> 32)]] ^ IT[5][S[1][(byte)(x[0] >> 40)]] ^ IT[6][S[2][(byte)(x[0] >> 48)]] ^ IT[7][S[3][(byte)(x[0] >> 56)]]; + x[1] = IT[0][S[0][(byte)x[1]]] ^ IT[1][S[1][(byte)(x[1] >> 8)]] ^ IT[2][S[2][(byte)(x[1] >> 16)]] ^ IT[3][S[3][(byte)(x[1] >> 24)]] ^ + IT[4][S[0][(byte)(x[1] >> 32)]] ^ IT[5][S[1][(byte)(x[1] >> 40)]] ^ IT[6][S[2][(byte)(x[1] >> 48)]] ^ IT[7][S[3][(byte)(x[1] >> 56)]]; + x[2] = IT[0][S[0][(byte)x[2]]] ^ IT[1][S[1][(byte)(x[2] >> 8)]] ^ IT[2][S[2][(byte)(x[2] >> 16)]] ^ IT[3][S[3][(byte)(x[2] >> 24)]] ^ + IT[4][S[0][(byte)(x[2] >> 32)]] ^ IT[5][S[1][(byte)(x[2] >> 40)]] ^ IT[6][S[2][(byte)(x[2] >> 48)]] ^ IT[7][S[3][(byte)(x[2] >> 56)]]; + x[3] = IT[0][S[0][(byte)x[3]]] ^ IT[1][S[1][(byte)(x[3] >> 8)]] ^ IT[2][S[2][(byte)(x[3] >> 16)]] ^ IT[3][S[3][(byte)(x[3] >> 24)]] ^ + IT[4][S[0][(byte)(x[3] >> 32)]] ^ IT[5][S[1][(byte)(x[3] >> 40)]] ^ IT[6][S[2][(byte)(x[3] >> 48)]] ^ IT[7][S[3][(byte)(x[3] >> 56)]]; + x[4] = IT[0][S[0][(byte)x[4]]] ^ IT[1][S[1][(byte)(x[4] >> 8)]] ^ IT[2][S[2][(byte)(x[4] >> 16)]] ^ IT[3][S[3][(byte)(x[4] >> 24)]] ^ + IT[4][S[0][(byte)(x[4] >> 32)]] ^ IT[5][S[1][(byte)(x[4] >> 40)]] ^ IT[6][S[2][(byte)(x[4] >> 48)]] ^ IT[7][S[3][(byte)(x[4] >> 56)]]; + x[5] = IT[0][S[0][(byte)x[5]]] ^ IT[1][S[1][(byte)(x[5] >> 8)]] ^ IT[2][S[2][(byte)(x[5] >> 16)]] ^ IT[3][S[3][(byte)(x[5] >> 24)]] ^ + IT[4][S[0][(byte)(x[5] >> 32)]] ^ IT[5][S[1][(byte)(x[5] >> 40)]] ^ IT[6][S[2][(byte)(x[5] >> 48)]] ^ IT[7][S[3][(byte)(x[5] >> 56)]]; + x[6] = IT[0][S[0][(byte)x[6]]] ^ IT[1][S[1][(byte)(x[6] >> 8)]] ^ IT[2][S[2][(byte)(x[6] >> 16)]] ^ IT[3][S[3][(byte)(x[6] >> 24)]] ^ + IT[4][S[0][(byte)(x[6] >> 32)]] ^ IT[5][S[1][(byte)(x[6] >> 40)]] ^ IT[6][S[2][(byte)(x[6] >> 48)]] ^ IT[7][S[3][(byte)(x[6] >> 56)]]; + x[7] = IT[0][S[0][(byte)x[7]]] ^ IT[1][S[1][(byte)(x[7] >> 8)]] ^ IT[2][S[2][(byte)(x[7] >> 16)]] ^ IT[3][S[3][(byte)(x[7] >> 24)]] ^ + IT[4][S[0][(byte)(x[7] >> 32)]] ^ IT[5][S[1][(byte)(x[7] >> 40)]] ^ IT[6][S[2][(byte)(x[7] >> 48)]] ^ IT[7][S[3][(byte)(x[7] >> 56)]]; +} + +inline void IG128(const word64 x[2], word64 y[2], const word64 k[2]) +{ + y[0] = k[0] ^ IT[0][(byte)x[0]] ^ IT[1][(byte)(x[0] >> 8)] ^ IT[2][(byte)(x[0] >> 16)] ^ IT[3][(byte)(x[0] >> 24)] ^ + IT[4][(byte)(x[1] >> 32)] ^ IT[5][(byte)(x[1] >> 40)] ^ IT[6][(byte)(x[1] >> 48)] ^ IT[7][(byte)(x[1] >> 56)]; + y[1] = k[1] ^ IT[0][(byte)x[1]] ^ IT[1][(byte)(x[1] >> 8)] ^ IT[2][(byte)(x[1] >> 16)] ^ IT[3][(byte)(x[1] >> 24)] ^ + IT[4][(byte)(x[0] >> 32)] ^ IT[5][(byte)(x[0] >> 40)] ^ IT[6][(byte)(x[0] >> 48)] ^ IT[7][(byte)(x[0] >> 56)]; +} + +inline void IG256(const word64 x[4], word64 y[4], const word64 k[4]) +{ + y[0] = k[0] ^ IT[0][(byte)x[0]] ^ IT[1][(byte)(x[0] >> 8)] ^ IT[2][(byte)(x[1] >> 16)] ^ IT[3][(byte)(x[1] >> 24)] ^ + IT[4][(byte)(x[2] >> 32)] ^ IT[5][(byte)(x[2] >> 40)] ^ IT[6][(byte)(x[3] >> 48)] ^ IT[7][(byte)(x[3] >> 56)]; + y[1] = k[1] ^ IT[0][(byte)x[1]] ^ IT[1][(byte)(x[1] >> 8)] ^ IT[2][(byte)(x[2] >> 16)] ^ IT[3][(byte)(x[2] >> 24)] ^ + IT[4][(byte)(x[3] >> 32)] ^ IT[5][(byte)(x[3] >> 40)] ^ IT[6][(byte)(x[0] >> 48)] ^ IT[7][(byte)(x[0] >> 56)]; + y[2] = k[2] ^ IT[0][(byte)x[2]] ^ IT[1][(byte)(x[2] >> 8)] ^ IT[2][(byte)(x[3] >> 16)] ^ IT[3][(byte)(x[3] >> 24)] ^ + IT[4][(byte)(x[0] >> 32)] ^ IT[5][(byte)(x[0] >> 40)] ^ IT[6][(byte)(x[1] >> 48)] ^ IT[7][(byte)(x[1] >> 56)]; + y[3] = k[3] ^ IT[0][(byte)x[3]] ^ IT[1][(byte)(x[3] >> 8)] ^ IT[2][(byte)(x[0] >> 16)] ^ IT[3][(byte)(x[0] >> 24)] ^ + IT[4][(byte)(x[1] >> 32)] ^ IT[5][(byte)(x[1] >> 40)] ^ IT[6][(byte)(x[2] >> 48)] ^ IT[7][(byte)(x[2] >> 56)]; +} + +inline void IG512(const word64 x[8], word64 y[8], const word64 k[8]) +{ + y[0] = k[0] ^ IT[0][(byte)x[0]] ^ IT[1][(byte)(x[1] >> 8)] ^ IT[2][(byte)(x[2] >> 16)] ^ IT[3][(byte)(x[3] >> 24)] ^ + IT[4][(byte)(x[4] >> 32)] ^ IT[5][(byte)(x[5] >> 40)] ^ IT[6][(byte)(x[6] >> 48)] ^ IT[7][(byte)(x[7] >> 56)]; + y[1] = k[1] ^ IT[0][(byte)x[1]] ^ IT[1][(byte)(x[2] >> 8)] ^ IT[2][(byte)(x[3] >> 16)] ^ IT[3][(byte)(x[4] >> 24)] ^ + IT[4][(byte)(x[5] >> 32)] ^ IT[5][(byte)(x[6] >> 40)] ^ IT[6][(byte)(x[7] >> 48)] ^ IT[7][(byte)(x[0] >> 56)]; + y[2] = k[2] ^ IT[0][(byte)x[2]] ^ IT[1][(byte)(x[3] >> 8)] ^ IT[2][(byte)(x[4] >> 16)] ^ IT[3][(byte)(x[5] >> 24)] ^ + IT[4][(byte)(x[6] >> 32)] ^ IT[5][(byte)(x[7] >> 40)] ^ IT[6][(byte)(x[0] >> 48)] ^ IT[7][(byte)(x[1] >> 56)]; + y[3] = k[3] ^ IT[0][(byte)x[3]] ^ IT[1][(byte)(x[4] >> 8)] ^ IT[2][(byte)(x[5] >> 16)] ^ IT[3][(byte)(x[6] >> 24)] ^ + IT[4][(byte)(x[7] >> 32)] ^ IT[5][(byte)(x[0] >> 40)] ^ IT[6][(byte)(x[1] >> 48)] ^ IT[7][(byte)(x[2] >> 56)]; + y[4] = k[4] ^ IT[0][(byte)x[4]] ^ IT[1][(byte)(x[5] >> 8)] ^ IT[2][(byte)(x[6] >> 16)] ^ IT[3][(byte)(x[7] >> 24)] ^ + IT[4][(byte)(x[0] >> 32)] ^ IT[5][(byte)(x[1] >> 40)] ^ IT[6][(byte)(x[2] >> 48)] ^ IT[7][(byte)(x[3] >> 56)]; + y[5] = k[5] ^ IT[0][(byte)x[5]] ^ IT[1][(byte)(x[6] >> 8)] ^ IT[2][(byte)(x[7] >> 16)] ^ IT[3][(byte)(x[0] >> 24)] ^ + IT[4][(byte)(x[1] >> 32)] ^ IT[5][(byte)(x[2] >> 40)] ^ IT[6][(byte)(x[3] >> 48)] ^ IT[7][(byte)(x[4] >> 56)]; + y[6] = k[6] ^ IT[0][(byte)x[6]] ^ IT[1][(byte)(x[7] >> 8)] ^ IT[2][(byte)(x[0] >> 16)] ^ IT[3][(byte)(x[1] >> 24)] ^ + IT[4][(byte)(x[2] >> 32)] ^ IT[5][(byte)(x[3] >> 40)] ^ IT[6][(byte)(x[4] >> 48)] ^ IT[7][(byte)(x[5] >> 56)]; + y[7] = k[7] ^ IT[0][(byte)x[7]] ^ IT[1][(byte)(x[0] >> 8)] ^ IT[2][(byte)(x[1] >> 16)] ^ IT[3][(byte)(x[2] >> 24)] ^ + IT[4][(byte)(x[3] >> 32)] ^ IT[5][(byte)(x[4] >> 40)] ^ IT[6][(byte)(x[5] >> 48)] ^ IT[7][(byte)(x[6] >> 56)]; +} + +inline void IGL128(const word64 x[2], word64 y[2], const word64 k[2]) +{ + y[0] = (word64(IS[0][(byte)x[0]]) ^ word64(IS[1][(byte)(x[0] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[0] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[0] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[1] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[1] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[1] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[1] >> 56)]) << 56) - k[0]; + y[1] = (word64(IS[0][(byte)x[1]]) ^ word64(IS[1][(byte)(x[1] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[1] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[1] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[0] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[0] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[0] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[0] >> 56)]) << 56) - k[1]; +} + +inline void IGL256(const word64 x[4], word64 y[4], const word64 k[4]) +{ + y[0] = (word64(IS[0][(byte)x[0]]) ^ word64(IS[1][(byte)(x[0] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[1] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[1] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[2] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[2] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[3] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[3] >> 56)]) << 56) - k[0]; + y[1] = (word64(IS[0][(byte)x[1]]) ^ word64(IS[1][(byte)(x[1] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[2] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[2] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[3] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[3] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[0] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[0] >> 56)]) << 56) - k[1]; + y[2] = (word64(IS[0][(byte)x[2]]) ^ word64(IS[1][(byte)(x[2] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[3] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[3] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[0] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[0] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[1] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[1] >> 56)]) << 56) - k[2]; + y[3] = (word64(IS[0][(byte)x[3]]) ^ word64(IS[1][(byte)(x[3] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[0] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[0] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[1] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[1] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[2] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[2] >> 56)]) << 56) - k[3]; +} + +inline void IGL512(const word64 x[8], word64 y[8], const word64 k[8]) +{ + y[0] = (word64(IS[0][(byte)x[0]]) ^ word64(IS[1][(byte)(x[1] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[2] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[3] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[4] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[5] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[6] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[7] >> 56)]) << 56) - k[0]; + y[1] = (word64(IS[0][(byte)x[1]]) ^ word64(IS[1][(byte)(x[2] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[3] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[4] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[5] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[6] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[7] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[0] >> 56)]) << 56) - k[1]; + y[2] = (word64(IS[0][(byte)x[2]]) ^ word64(IS[1][(byte)(x[3] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[4] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[5] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[6] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[7] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[0] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[1] >> 56)]) << 56) - k[2]; + y[3] = (word64(IS[0][(byte)x[3]]) ^ word64(IS[1][(byte)(x[4] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[5] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[6] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[7] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[0] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[1] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[2] >> 56)]) << 56) - k[3]; + y[4] = (word64(IS[0][(byte)x[4]]) ^ word64(IS[1][(byte)(x[5] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[6] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[7] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[0] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[1] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[2] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[3] >> 56)]) << 56) - k[4]; + y[5] = (word64(IS[0][(byte)x[5]]) ^ word64(IS[1][(byte)(x[6] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[7] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[0] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[1] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[2] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[3] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[4] >> 56)]) << 56) - k[5]; + y[6] = (word64(IS[0][(byte)x[6]]) ^ word64(IS[1][(byte)(x[7] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[0] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[1] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[2] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[3] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[4] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[5] >> 56)]) << 56) - k[6]; + y[7] = (word64(IS[0][(byte)x[7]]) ^ word64(IS[1][(byte)(x[0] >> 8)]) << 8 ^ word64(IS[2][(byte)(x[1] >> 16)]) << 16 ^ word64(IS[3][(byte)(x[2] >> 24)]) << 24 ^ + word64(IS[0][(byte)(x[3] >> 32)]) << 32 ^ word64(IS[1][(byte)(x[4] >> 40)]) << 40 ^ word64(IS[2][(byte)(x[5] >> 48)]) << 48 ^ word64(IS[3][(byte)(x[6] >> 56)]) << 56) - k[7]; +} + +inline void G128(const word64 x[2], word64 y[2], const word64 k[2]) +{ + y[0] = k[0] ^ T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = k[1] ^ T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +inline void G256(const word64 x[4], word64 y[4], const word64 k[4]) +{ + y[0] = k[0] ^ T[0][(byte)x[0]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = k[1] ^ T[0][(byte)x[1]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[2] >> 56)]; + y[2] = k[2] ^ T[0][(byte)x[2]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[3] >> 56)]; + y[3] = k[3] ^ T[0][(byte)x[3]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +inline void G512(const word64 x[8], word64 y[8], const word64 k[8]) +{ + y[0] = k[0] ^ T[0][(byte)x[0]] ^ T[1][(byte)(x[7] >> 8)] ^ T[2][(byte)(x[6] >> 16)] ^ T[3][(byte)(x[5] >> 24)] ^ + T[4][(byte)(x[4] >> 32)] ^ T[5][(byte)(x[3] >> 40)] ^ T[6][(byte)(x[2] >> 48)] ^ T[7][(byte)(x[1] >> 56)]; + y[1] = k[1] ^ T[0][(byte)x[1]] ^ T[1][(byte)(x[0] >> 8)] ^ T[2][(byte)(x[7] >> 16)] ^ T[3][(byte)(x[6] >> 24)] ^ + T[4][(byte)(x[5] >> 32)] ^ T[5][(byte)(x[4] >> 40)] ^ T[6][(byte)(x[3] >> 48)] ^ T[7][(byte)(x[2] >> 56)]; + y[2] = k[2] ^ T[0][(byte)x[2]] ^ T[1][(byte)(x[1] >> 8)] ^ T[2][(byte)(x[0] >> 16)] ^ T[3][(byte)(x[7] >> 24)] ^ + T[4][(byte)(x[6] >> 32)] ^ T[5][(byte)(x[5] >> 40)] ^ T[6][(byte)(x[4] >> 48)] ^ T[7][(byte)(x[3] >> 56)]; + y[3] = k[3] ^ T[0][(byte)x[3]] ^ T[1][(byte)(x[2] >> 8)] ^ T[2][(byte)(x[1] >> 16)] ^ T[3][(byte)(x[0] >> 24)] ^ + T[4][(byte)(x[7] >> 32)] ^ T[5][(byte)(x[6] >> 40)] ^ T[6][(byte)(x[5] >> 48)] ^ T[7][(byte)(x[4] >> 56)]; + y[4] = k[4] ^ T[0][(byte)x[4]] ^ T[1][(byte)(x[3] >> 8)] ^ T[2][(byte)(x[2] >> 16)] ^ T[3][(byte)(x[1] >> 24)] ^ + T[4][(byte)(x[0] >> 32)] ^ T[5][(byte)(x[7] >> 40)] ^ T[6][(byte)(x[6] >> 48)] ^ T[7][(byte)(x[5] >> 56)]; + y[5] = k[5] ^ T[0][(byte)x[5]] ^ T[1][(byte)(x[4] >> 8)] ^ T[2][(byte)(x[3] >> 16)] ^ T[3][(byte)(x[2] >> 24)] ^ + T[4][(byte)(x[1] >> 32)] ^ T[5][(byte)(x[0] >> 40)] ^ T[6][(byte)(x[7] >> 48)] ^ T[7][(byte)(x[6] >> 56)]; + y[6] = k[6] ^ T[0][(byte)x[6]] ^ T[1][(byte)(x[5] >> 8)] ^ T[2][(byte)(x[4] >> 16)] ^ T[3][(byte)(x[3] >> 24)] ^ + T[4][(byte)(x[2] >> 32)] ^ T[5][(byte)(x[1] >> 40)] ^ T[6][(byte)(x[0] >> 48)] ^ T[7][(byte)(x[7] >> 56)]; + y[7] = k[7] ^ T[0][(byte)x[7]] ^ T[1][(byte)(x[6] >> 8)] ^ T[2][(byte)(x[5] >> 16)] ^ T[3][(byte)(x[4] >> 24)] ^ + T[4][(byte)(x[3] >> 32)] ^ T[5][(byte)(x[2] >> 40)] ^ T[6][(byte)(x[1] >> 48)] ^ T[7][(byte)(x[0] >> 56)]; +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +// *********************** UncheckedSetKey specializations *********************** // + +void Kalyna128::Base::SetKey_22(const word64 key[2]) +{ + word64 *ks = m_wspace+0, *ksc = m_wspace+2, *t1 = m_wspace+4; + word64 *t2 = m_wspace+6, *k = m_wspace+8, *kswapped = m_wspace+10; + + memset(t1, 0, 2*8); + t1[0] = (128 + 128 + 64) / 64; + + AddKey<2>(t1, t2, key); + G128(t2, t1, key); + GL128(t1, t2, key); + G0128(t2, ks); + + word64 constant = W64LIT(0x0001000100010001); + + // round 0 + memcpy(k, key, 16); + kswapped[1] = k[0]; + kswapped[0] = k[1]; + + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[0], ksc); + MakeOddKey<2>(&m_rkeys[0], &m_rkeys[2]); + + // round 2 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(kswapped, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[4], ksc); + MakeOddKey<2>(&m_rkeys[4], &m_rkeys[6]); + + // round 4 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[8], ksc); + MakeOddKey<2>(&m_rkeys[8], &m_rkeys[10]); + + // round 6 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(kswapped, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[12], ksc); + MakeOddKey<2>(&m_rkeys[12], &m_rkeys[14]); + + // round 8 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[16], ksc); + MakeOddKey<2>(&m_rkeys[16], &m_rkeys[18]); + + // round 10 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(kswapped, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[20], ksc); + + if (!IsForwardTransformation()) + { + IMC128(&m_rkeys[18]); IMC128(&m_rkeys[16]); + IMC128(&m_rkeys[14]); IMC128(&m_rkeys[12]); + IMC128(&m_rkeys[10]); IMC128(&m_rkeys[ 8]); + IMC128(&m_rkeys[ 6]); IMC128(&m_rkeys[ 4]); + IMC128(&m_rkeys[ 2]); + } +} + +void Kalyna128::Base::SetKey_24(const word64 key[4]) +{ + word64 *ks = m_wspace+0, *ksc = m_wspace+2, *t1 = m_wspace+4, *t2 = m_wspace+6; + word64 *k = m_wspace+8, *ka = m_wspace+12, *ko = m_wspace+14; + + memset(t1, 0, 2*8); + t1[0] = (128 + 256 + 64) / 64; + memcpy(ka, key, 16); + memcpy(ko, key + 2, 16); + + AddKey<2>(t1, t2, ka); + G128(t2, t1, ko); + GL128(t1, t2, ka); + G0128(t2, ks); + + word64 constant = W64LIT(0x0001000100010001); + + // round 0 + memcpy(k, key, 256 / 8); + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[0], ksc); + MakeOddKey<2>(&m_rkeys[0], &m_rkeys[2]); + + // round 2 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k + 2, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[4], ksc); + MakeOddKey<2>(&m_rkeys[4], &m_rkeys[6]); + + // round 4 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[8], ksc); + MakeOddKey<2>(&m_rkeys[8], &m_rkeys[10]); + + // round 6 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k + 2, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[12], ksc); + MakeOddKey<2>(&m_rkeys[12], &m_rkeys[14]); + + // round 8 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[16], ksc); + MakeOddKey<2>(&m_rkeys[16], &m_rkeys[18]); + + // round 10 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k + 2, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[20], ksc); + MakeOddKey<2>(&m_rkeys[20], &m_rkeys[22]); + + // round 12 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[24], ksc); + MakeOddKey<2>(&m_rkeys[24], &m_rkeys[26]); + + // round 14 + constant <<= 1; + AddConstant<2>(ks, ksc, constant); + AddKey<2>(k + 2, t2, ksc); + G128(t2, t1, ksc); + GL128(t1, &m_rkeys[28], ksc); + + if (!IsForwardTransformation()) + { + IMC128(&m_rkeys[26]); + IMC128(&m_rkeys[24]); + IMC128(&m_rkeys[22]); + IMC128(&m_rkeys[20]); + IMC128(&m_rkeys[18]); + IMC128(&m_rkeys[16]); + IMC128(&m_rkeys[14]); + IMC128(&m_rkeys[12]); + IMC128(&m_rkeys[10]); + IMC128(&m_rkeys[8]); + IMC128(&m_rkeys[6]); + IMC128(&m_rkeys[4]); + IMC128(&m_rkeys[2]); + } +} + +void Kalyna256::Base::SetKey_44(const word64 key[4]) +{ + word64 *ks = m_wspace+0, *ksc = m_wspace+4, *t1 = m_wspace+8; + word64 *t2 = m_wspace+12, *k = m_wspace+16; + + memset(t1, 0, 32); + t1[0] = (256 + 256 + 64) / 64; + + AddKey<4>(t1, t2, key); + G256(t2, t1, key); + GL256(t1, t2, key); + G0256(t2, ks); + + word64 constant = W64LIT(0x0001000100010001); + + // round 0 + memcpy(k, key, 32); + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[0], ksc); + MakeOddKey<4>(&m_rkeys[0], &m_rkeys[4]); + + // round 2 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[8], ksc); + MakeOddKey<4>(&m_rkeys[8], &m_rkeys[12]); + + // round 4 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[16], ksc); + MakeOddKey<4>(&m_rkeys[16], &m_rkeys[20]); + + // round 6 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[24], ksc); + MakeOddKey<4>(&m_rkeys[24], &m_rkeys[28]); + + // round 8 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[32], ksc); + MakeOddKey<4>(&m_rkeys[32], &m_rkeys[36]); + + // round 10 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[40], ksc); + MakeOddKey<4>(&m_rkeys[40], &m_rkeys[44]); + + // round 12 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[48], ksc); + MakeOddKey<4>(&m_rkeys[48], &m_rkeys[52]); + + // round 14 + SwapBlocks<4>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[56], ksc); + + if (!IsForwardTransformation()) + { + IMC256(&m_rkeys[52]); + IMC256(&m_rkeys[48]); + IMC256(&m_rkeys[44]); + IMC256(&m_rkeys[40]); + IMC256(&m_rkeys[36]); + IMC256(&m_rkeys[32]); + IMC256(&m_rkeys[28]); + IMC256(&m_rkeys[24]); + IMC256(&m_rkeys[20]); + IMC256(&m_rkeys[16]); + IMC256(&m_rkeys[12]); + IMC256(&m_rkeys[8]); + IMC256(&m_rkeys[4]); + } +} + +void Kalyna256::Base::SetKey_48(const word64 key[8]) +{ + word64 *ks = m_wspace+0, *ksc = m_wspace+4, *t1 = m_wspace+8, *t2 = m_wspace+12; + word64 *k = m_wspace+16, *ka = m_wspace+24, *ko = m_wspace+28; + + memset(t1, 0, 4*8); + t1[0] = (512 + 256 + 64) / 64; + memcpy(ka, key, 32); + memcpy(ko, key+4, 32); + + AddKey<4>(t1, t2, ka); + G256(t2, t1, ko); + GL256(t1, t2, ka); + G0256(t2, ks); + + word64 constant = W64LIT(0x0001000100010001); + + // round 0 + memcpy(k, key, 512 / 8); + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[0], ksc); + MakeOddKey<4>(&m_rkeys[0], &m_rkeys[4]); + + // round 2 + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k+4, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[8], ksc); + MakeOddKey<4>(&m_rkeys[8], &m_rkeys[12]); + + // round 4 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[16], ksc); + MakeOddKey<4>(&m_rkeys[16], &m_rkeys[20]); + + // round 6 + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k+4, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[24], ksc); + MakeOddKey<4>(&m_rkeys[24], &m_rkeys[28]); + + // round 8 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[32], ksc); + MakeOddKey<4>(&m_rkeys[32], &m_rkeys[36]); + + // round 10 + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k+4, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[40], ksc); + MakeOddKey<4>(&m_rkeys[40], &m_rkeys[44]); + + // round 12 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[48], ksc); + MakeOddKey<4>(&m_rkeys[48], &m_rkeys[52]); + + // round 14 + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k+4, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[56], ksc); + MakeOddKey<4>(&m_rkeys[56], &m_rkeys[60]); + + // round 16 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[64], ksc); + MakeOddKey<4>(&m_rkeys[64], &m_rkeys[68]); + + // round 18 + constant <<= 1; + AddConstant<4>(ks, ksc, constant); + AddKey<4>(k+4, t2, ksc); + G256(t2, t1, ksc); + GL256(t1, &m_rkeys[72], ksc); + + if (!IsForwardTransformation()) + { + IMC256(&m_rkeys[68]); + IMC256(&m_rkeys[64]); + IMC256(&m_rkeys[60]); + IMC256(&m_rkeys[56]); + IMC256(&m_rkeys[52]); + IMC256(&m_rkeys[48]); + IMC256(&m_rkeys[44]); + IMC256(&m_rkeys[40]); + IMC256(&m_rkeys[36]); + IMC256(&m_rkeys[32]); + IMC256(&m_rkeys[28]); + IMC256(&m_rkeys[24]); + IMC256(&m_rkeys[20]); + IMC256(&m_rkeys[16]); + IMC256(&m_rkeys[12]); + IMC256(&m_rkeys[8]); + IMC256(&m_rkeys[4]); + } +} + +void Kalyna512::Base::SetKey_88(const word64 key[8]) +{ + word64 *ks = m_wspace+0, *ksc = m_wspace+8, *t1 = m_wspace+16; + word64 *t2 = m_wspace+24, *k = m_wspace+32; + + memset(t1, 0, 8*8); + t1[0] = (512 + 512 + 64) / 64; + + AddKey<8>(t1, t2, key); + G512(t2, t1, key); + GL512(t1, t2, key); + G0512(t2, ks); + + word64 constant = W64LIT(0x0001000100010001); + + // round 0 + memcpy(k, key, 512 / 8); + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[0], ksc); + MakeOddKey<8>(&m_rkeys[0], &m_rkeys[8]); + + // round 2 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[16], ksc); + MakeOddKey<8>(&m_rkeys[16], &m_rkeys[24]); + + // round 4 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[32], ksc); + MakeOddKey<8>(&m_rkeys[32], &m_rkeys[40]); + + // round 6 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[48], ksc); + MakeOddKey<8>(&m_rkeys[48], &m_rkeys[56]); + + // round 8 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[64], ksc); + MakeOddKey<8>(&m_rkeys[64], &m_rkeys[72]); + + // round 10 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[80], ksc); + MakeOddKey<8>(&m_rkeys[80], &m_rkeys[88]); + + // round 12 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[96], ksc); + MakeOddKey<8>(&m_rkeys[96], &m_rkeys[104]); + + // round 14 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[112], ksc); + MakeOddKey<8>(&m_rkeys[112], &m_rkeys[120]); + + // round 16 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[128], ksc); + MakeOddKey<8>(&m_rkeys[128], &m_rkeys[136]); + + // round 18 + SwapBlocks<8>(k); + constant <<= 1; + AddConstant<8>(ks, ksc, constant); + AddKey<8>(k, t2, ksc); + G512(t2, t1, ksc); + GL512(t1, &m_rkeys[144], ksc); + + if (!IsForwardTransformation()) + { + IMC512(&m_rkeys[136]); IMC512(&m_rkeys[128]); IMC512(&m_rkeys[120]); IMC512(&m_rkeys[112]); + IMC512(&m_rkeys[104]); IMC512(&m_rkeys[ 96]); IMC512(&m_rkeys[ 88]); IMC512(&m_rkeys[ 80]); + IMC512(&m_rkeys[ 72]); IMC512(&m_rkeys[ 64]); IMC512(&m_rkeys[ 56]); IMC512(&m_rkeys[ 48]); + IMC512(&m_rkeys[ 40]); IMC512(&m_rkeys[ 32]); IMC512(&m_rkeys[ 24]); IMC512(&m_rkeys[ 16]); + IMC512(&m_rkeys[ 8]); + } +} + +// *********************** ProcessAndXorBlock specializations *********************** // + +void Kalyna128::Base::ProcessBlock_22(const byte* inBlock, const byte* xorBlock, byte* outBlock) const +{ + word64 *t1 = m_wspace+0, *t2 = m_wspace+2, *msg = m_wspace+4; + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(msg[0])(msg[1]); + + if (IsForwardTransformation()) + { + AddKey<2>(msg, t1, m_rkeys); + G128(t1, t2, &m_rkeys[2]); // 1 + G128(t2, t1, &m_rkeys[4]); // 2 + G128(t1, t2, &m_rkeys[6]); // 3 + G128(t2, t1, &m_rkeys[8]); // 4 + G128(t1, t2, &m_rkeys[10]); // 5 + G128(t2, t1, &m_rkeys[12]); // 6 + G128(t1, t2, &m_rkeys[14]); // 7 + G128(t2, t1, &m_rkeys[16]); // 8 + G128(t1, t2, &m_rkeys[18]); // 9 + GL128(t2, t1, &m_rkeys[20]); // 10 + } + else + { + SubKey<2>(msg, t1, &m_rkeys[20]); + IMC128(t1); + IG128(t1, t2, &m_rkeys[18]); + IG128(t2, t1, &m_rkeys[16]); + IG128(t1, t2, &m_rkeys[14]); + IG128(t2, t1, &m_rkeys[12]); + IG128(t1, t2, &m_rkeys[10]); + IG128(t2, t1, &m_rkeys[8]); + IG128(t1, t2, &m_rkeys[6]); + IG128(t2, t1, &m_rkeys[4]); + IG128(t1, t2, &m_rkeys[2]); + IGL128(t2, t1, &m_rkeys[0]); + } + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(t1[0])(t1[1]); +} + +void Kalyna128::Base::ProcessBlock_24(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 *t1 = m_wspace+0, *t2 = m_wspace+2, *msg = m_wspace+4; + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(msg[0])(msg[1]); + + if (IsForwardTransformation()) + { + AddKey<2>(msg, t1, m_rkeys); + G128(t1, t2, &m_rkeys[ 2]); // 1 + G128(t2, t1, &m_rkeys[ 4]); // 2 + G128(t1, t2, &m_rkeys[ 6]); // 3 + G128(t2, t1, &m_rkeys[ 8]); // 4 + G128(t1, t2, &m_rkeys[10]); // 5 + G128(t2, t1, &m_rkeys[12]); // 6 + G128(t1, t2, &m_rkeys[14]); // 7 + G128(t2, t1, &m_rkeys[16]); // 8 + G128(t1, t2, &m_rkeys[18]); // 9 + G128(t2, t1, &m_rkeys[20]); // 10 + G128(t1, t2, &m_rkeys[22]); // 11 + G128(t2, t1, &m_rkeys[24]); // 12 + G128(t1, t2, &m_rkeys[26]); // 13 + GL128(t2, t1, &m_rkeys[28]); // 14 + } + else + { + SubKey<2>(msg, t1, &m_rkeys[28]); + IMC128(t1); + IG128(t1, t2, &m_rkeys[26]); + IG128(t2, t1, &m_rkeys[24]); + IG128(t1, t2, &m_rkeys[22]); + IG128(t2, t1, &m_rkeys[20]); + IG128(t1, t2, &m_rkeys[18]); + IG128(t2, t1, &m_rkeys[16]); + IG128(t1, t2, &m_rkeys[14]); + IG128(t2, t1, &m_rkeys[12]); + IG128(t1, t2, &m_rkeys[10]); + IG128(t2, t1, &m_rkeys[8]); + IG128(t1, t2, &m_rkeys[6]); + IG128(t2, t1, &m_rkeys[4]); + IG128(t1, t2, &m_rkeys[2]); + IGL128(t2, t1, &m_rkeys[0]); + } + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(t1[0])(t1[1]); +} + +void Kalyna256::Base::ProcessBlock_44(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 *t1 = m_wspace+0, *t2 = m_wspace+4, *msg = m_wspace+8; + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(msg[0])(msg[1])(msg[2])(msg[3]); + + if (IsForwardTransformation()) + { + AddKey<4>(msg, t1, m_rkeys); + G256(t1, t2, &m_rkeys[4]); // 1 + G256(t2, t1, &m_rkeys[8]); // 2 + G256(t1, t2, &m_rkeys[12]); // 3 + G256(t2, t1, &m_rkeys[16]); // 4 + G256(t1, t2, &m_rkeys[20]); // 5 + G256(t2, t1, &m_rkeys[24]); // 6 + G256(t1, t2, &m_rkeys[28]); // 7 + G256(t2, t1, &m_rkeys[32]); // 8 + G256(t1, t2, &m_rkeys[36]); // 9 + G256(t2, t1, &m_rkeys[40]); // 10 + G256(t1, t2, &m_rkeys[44]); // 11 + G256(t2, t1, &m_rkeys[48]); // 12 + G256(t1, t2, &m_rkeys[52]); // 13 + GL256(t2, t1, &m_rkeys[56]); // 14 + } + else + { + SubKey<4>(msg, t1, &m_rkeys[56]); + IMC256(t1); + IG256(t1, t2, &m_rkeys[52]); + IG256(t2, t1, &m_rkeys[48]); + IG256(t1, t2, &m_rkeys[44]); + IG256(t2, t1, &m_rkeys[40]); + IG256(t1, t2, &m_rkeys[36]); + IG256(t2, t1, &m_rkeys[32]); + IG256(t1, t2, &m_rkeys[28]); + IG256(t2, t1, &m_rkeys[24]); + IG256(t1, t2, &m_rkeys[20]); + IG256(t2, t1, &m_rkeys[16]); + IG256(t1, t2, &m_rkeys[12]); + IG256(t2, t1, &m_rkeys[8]); + IG256(t1, t2, &m_rkeys[4]); + IGL256(t2, t1, &m_rkeys[0]); + } + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(t1[0])(t1[1])(t1[2])(t1[3]); +} + +void Kalyna256::Base::ProcessBlock_48(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 *t1 = m_wspace+0, *t2 = m_wspace+4, *msg = m_wspace+8; + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(msg[0])(msg[1])(msg[2])(msg[3]); + + if (IsForwardTransformation()) + { + AddKey<4>(msg, t1, m_rkeys); + G256(t1, t2, &m_rkeys[4]); // 1 + G256(t2, t1, &m_rkeys[8]); // 2 + G256(t1, t2, &m_rkeys[12]); // 3 + G256(t2, t1, &m_rkeys[16]); // 4 + G256(t1, t2, &m_rkeys[20]); // 5 + G256(t2, t1, &m_rkeys[24]); // 6 + G256(t1, t2, &m_rkeys[28]); // 7 + G256(t2, t1, &m_rkeys[32]); // 8 + G256(t1, t2, &m_rkeys[36]); // 9 + G256(t2, t1, &m_rkeys[40]); // 10 + G256(t1, t2, &m_rkeys[44]); // 11 + G256(t2, t1, &m_rkeys[48]); // 12 + G256(t1, t2, &m_rkeys[52]); // 13 + G256(t2, t1, &m_rkeys[56]); // 14 + G256(t1, t2, &m_rkeys[60]); // 15 + G256(t2, t1, &m_rkeys[64]); // 16 + G256(t1, t2, &m_rkeys[68]); // 17 + GL256(t2, t1, &m_rkeys[72]); // 18 + } + else + { + SubKey<4>(msg, t1, &m_rkeys[72]); + IMC256(t1); + IG256(t1, t2, &m_rkeys[68]); + IG256(t2, t1, &m_rkeys[64]); + IG256(t1, t2, &m_rkeys[60]); + IG256(t2, t1, &m_rkeys[56]); + IG256(t1, t2, &m_rkeys[52]); + IG256(t2, t1, &m_rkeys[48]); + IG256(t1, t2, &m_rkeys[44]); + IG256(t2, t1, &m_rkeys[40]); + IG256(t1, t2, &m_rkeys[36]); + IG256(t2, t1, &m_rkeys[32]); + IG256(t1, t2, &m_rkeys[28]); + IG256(t2, t1, &m_rkeys[24]); + IG256(t1, t2, &m_rkeys[20]); + IG256(t2, t1, &m_rkeys[16]); + IG256(t1, t2, &m_rkeys[12]); + IG256(t2, t1, &m_rkeys[8]); + IG256(t1, t2, &m_rkeys[4]); + IGL256(t2, t1, &m_rkeys[0]); + } + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(t1[0])(t1[1])(t1[2])(t1[3]); +} + +void Kalyna512::Base::ProcessBlock_88(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 *t1 = m_wspace+0, *t2 = m_wspace+8, *msg = m_wspace+16; + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(msg[0])(msg[1])(msg[2])(msg[3])(msg[4])(msg[5])(msg[6])(msg[7]); + + if (IsForwardTransformation()) + { + AddKey<8>(msg, t1, m_rkeys); + G512(t1, t2, &m_rkeys[8]); // 1 + G512(t2, t1, &m_rkeys[16]); // 2 + G512(t1, t2, &m_rkeys[24]); // 3 + G512(t2, t1, &m_rkeys[32]); // 4 + G512(t1, t2, &m_rkeys[40]); // 5 + G512(t2, t1, &m_rkeys[48]); // 6 + G512(t1, t2, &m_rkeys[56]); // 7 + G512(t2, t1, &m_rkeys[64]); // 8 + G512(t1, t2, &m_rkeys[72]); // 9 + G512(t2, t1, &m_rkeys[80]); // 10 + G512(t1, t2, &m_rkeys[88]); // 11 + G512(t2, t1, &m_rkeys[96]); // 12 + G512(t1, t2, &m_rkeys[104]); // 13 + G512(t2, t1, &m_rkeys[112]); // 14 + G512(t1, t2, &m_rkeys[120]); // 15 + G512(t2, t1, &m_rkeys[128]); // 16 + G512(t1, t2, &m_rkeys[136]); // 17 + GL512(t2, t1, &m_rkeys[144]); // 18 + } + else + { + SubKey<8>(msg, t1, &m_rkeys[144]); + IMC512(t1); + IG512(t1, t2, &m_rkeys[136]); + IG512(t2, t1, &m_rkeys[128]); + IG512(t1, t2, &m_rkeys[120]); + IG512(t2, t1, &m_rkeys[112]); + IG512(t1, t2, &m_rkeys[104]); + IG512(t2, t1, &m_rkeys[96]); + IG512(t1, t2, &m_rkeys[88]); + IG512(t2, t1, &m_rkeys[80]); + IG512(t1, t2, &m_rkeys[72]); + IG512(t2, t1, &m_rkeys[64]); + IG512(t1, t2, &m_rkeys[56]); + IG512(t2, t1, &m_rkeys[48]); + IG512(t1, t2, &m_rkeys[40]); + IG512(t2, t1, &m_rkeys[32]); + IG512(t1, t2, &m_rkeys[24]); + IG512(t2, t1, &m_rkeys[16]); + IG512(t1, t2, &m_rkeys[8]); + IGL512(t2, t1, &m_rkeys[0]); + } + + // Reverse bytes on BigEndian; Align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(t1[0])(t1[1])(t1[2])(t1[3])(t1[4])(t1[5])(t1[6])(t1[7]); +} + +// *********************** Library routines *********************** // + +void Kalyna128::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + m_nb = static_cast(16U / sizeof(word64)); + m_nk = static_cast(keylen / sizeof(word64)); + + switch (keylen) + { + case 16: // 128 + m_kl = 16; + m_mkey.New(2); + m_rkeys.New(11*2); + m_wspace.New(2*6); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_mkey.begin(), 2, key, 16); + SetKey_22(m_mkey.begin()); + break; + case 32: // 256 + m_kl = 32; + m_mkey.New(4); + m_rkeys.New(15*2); + m_wspace.New(6*2+4); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_mkey.begin(), 4, key, 32); + SetKey_24(m_mkey.begin()); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void Kalyna128::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Timing attack countermeasure. see comments in Rijndael for more details + const int cacheLineSize = GetCacheLineSize(); + volatile word64 _u = 0; + word64 u = _u; + + const byte* p = reinterpret_cast(KalynaTab::S); + for (unsigned int i=0; i<256; i+=cacheLineSize) + u ^= *reinterpret_cast(p+i); + m_wspace[0] = u; + + switch ((m_nb << 8) | m_nk) + { + case (2 << 8) | 2: + ProcessBlock_22(inBlock, xorBlock, outBlock); + break; + case (2 << 8) | 4: + ProcessBlock_24(inBlock, xorBlock, outBlock); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void Kalyna256::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + m_nb = static_cast(32U / sizeof(word64)); + m_nk = static_cast(keylen / sizeof(word64)); + + switch (keylen) + { + case 32: // 256 + m_kl = 32; + m_mkey.New(4); + m_rkeys.New(15*4); + m_wspace.New(5*4); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_mkey.begin(), 4, key, 32); + SetKey_44(m_mkey.begin()); + break; + case 64: // 512 + m_kl = 64; + m_mkey.New(8); + m_rkeys.New(19*4); + m_wspace.New(6*4+8); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_mkey.begin(), 8, key, 64); + SetKey_48(m_mkey.begin()); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void Kalyna256::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Timing attack countermeasure. see comments in Rijndael for more details + const int cacheLineSize = GetCacheLineSize(); + volatile word64 _u = 0; + word64 u = _u; + + const byte* p = reinterpret_cast(KalynaTab::S); + for (unsigned int i=0; i<256; i+=cacheLineSize) + u ^= *reinterpret_cast(p+i); + m_wspace[0] = u; + + switch ((m_nb << 8) | m_nk) + { + case (4 << 8) | 4: + ProcessBlock_44(inBlock, xorBlock, outBlock); + break; + case (4 << 8) | 8: + ProcessBlock_48(inBlock, xorBlock, outBlock); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void Kalyna512::Base::UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + m_nb = static_cast(64U / sizeof(word64)); + m_nk = static_cast(keylen / sizeof(word64)); + + switch (keylen) + { + case 64: // 512 + m_kl = 64; + m_nb = static_cast(64U / sizeof(word64)); + m_nk = static_cast(keylen / sizeof(word64)); + + m_mkey.New(8); + m_rkeys.New(19*8); + m_wspace.New(5*8); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_mkey.begin(), 8, key, 64); + SetKey_88(m_mkey.begin()); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void Kalyna512::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Timing attack countermeasure. see comments in Rijndael for more details + const int cacheLineSize = GetCacheLineSize(); + volatile word64 _u = 0; + word64 u = _u; + + const byte* p = reinterpret_cast(KalynaTab::S); + for (unsigned int i=0; i<256; i+=cacheLineSize) + u ^= *reinterpret_cast(p+i); + m_wspace[0] = u; + + ProcessBlock_88(inBlock, xorBlock, outBlock); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/kalyna.h b/extension/third_party/cryptopp/kalyna.h new file mode 100644 index 00000000..277fccb5 --- /dev/null +++ b/extension/third_party/cryptopp/kalyna.h @@ -0,0 +1,218 @@ +// kalyna.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. + +/// \file kalyna.h +/// \brief Classes for the Kalyna block cipher +/// \details The Crypto++ implementation relied upon three sources. First was Oliynykov, Gorbenko, Kazymyrov, +/// Ruzhentsev, Kuznetsov, Gorbenko, Dyrda, Dolgov, Pushkaryov, Mordvinov and Kaidalov's "A New Encryption +/// Standard of Ukraine: The Kalyna Block Cipher" (http://eprint.iacr.org/2015/650.pdf). Second was Roman +/// Oliynykov and Oleksandr Kazymyrov's GitHub with the reference implementation +/// (http://github.com/Roman-Oliynykov/Kalyna-reference). The third resource was Keru Kuro's implementation +/// of Kalyna in CppCrypto (http://sourceforge.net/projects/cppcrypto/). Kuro has an outstanding +/// implementation that performed better than the reference implementation and our initial attempts. + +#ifndef CRYPTOPP_KALYNA_H +#define CRYPTOPP_KALYNA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Kalyna-128 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna128_Info : public FixedBlockSize<16>, VariableKeyLength<16, 16, 32> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-128"; + } +}; + +/// \brief Kalyna-256 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna256_Info : public FixedBlockSize<32>, VariableKeyLength<32, 32, 64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-256"; + } +}; + +/// \brief Kalyna-512 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna512_Info : public FixedBlockSize<64>, FixedKeyLength<64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-512"; + } +}; + +/// \brief Kalyna block cipher base class +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Kalyna_Base +{ +public: + virtual ~Kalyna_Base() {} + +protected: + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // work space + AlignedSecBlock64 m_mkey; // master key + AlignedSecBlock64 m_rkeys; // round keys + unsigned int m_kl, m_nb, m_nk; // number 64-bit blocks and keys +}; + +/// \brief Kalyna 128-bit block cipher +/// \details Kalyna128 provides 128-bit block size. The valid key sizes are 128-bit and 256-bit. +/// \since Crypto++ 6.0 +class Kalyna128 : public Kalyna128_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-128") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_22(const word64 key[2]); + void SetKey_24(const word64 key[4]); + void ProcessBlock_22(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void ProcessBlock_24(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 256-bit block cipher +/// \details Kalyna256 provides 256-bit block size. The valid key sizes are 256-bit and 512-bit. +/// \since Crypto++ 6.0 +class Kalyna256 : public Kalyna256_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-256") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_44(const word64 key[4]); + void SetKey_48(const word64 key[8]); + void ProcessBlock_44(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void ProcessBlock_48(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 512-bit block cipher +/// \details Kalyna512 provides 512-bit block size. The valid key size is 512-bit. +/// \since Crypto++ 6.0 +class Kalyna512 : public Kalyna512_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-512") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_88(const word64 key[8]); + void ProcessBlock_88(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Kalyna128::Encryption Kalyna128Encryption; +typedef Kalyna128::Decryption Kalyna128Decryption; + +typedef Kalyna256::Encryption Kalyna256Encryption; +typedef Kalyna256::Decryption Kalyna256Decryption; + +typedef Kalyna512::Encryption Kalyna512Encryption; +typedef Kalyna512::Decryption Kalyna512Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_KALYNA_H diff --git a/extension/third_party/cryptopp/kalynatab.cpp b/extension/third_party/cryptopp/kalynatab.cpp new file mode 100644 index 00000000..d4ad171c --- /dev/null +++ b/extension/third_party/cryptopp/kalynatab.cpp @@ -0,0 +1,1232 @@ +// kalynatab.cpp - written and placed in the public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" +#include "kalyna.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(KalynaTab) + +extern const word64 T[8][256]; // Columns +extern const word64 IT[8][256]; // Inverse +extern const byte S[4][256]; // Substitution +extern const byte IS[4][256]; // Inverse + +const word64 T[8][256] = +{ + { + W64LIT(0xa832a829d77f9aa8), W64LIT(0x4352432297d41143), W64LIT(0x5f3e5fc2df80615f), W64LIT(0x061e063014121806), + W64LIT(0x6bda6b7f670cb16b), W64LIT(0x75bc758f2356c975), W64LIT(0x6cc16c477519ad6c), W64LIT(0x592059f2cb927959), + W64LIT(0x71a871af3b4ad971), W64LIT(0xdf84dfb6f8275bdf), W64LIT(0x87a1874c35b22687), W64LIT(0x95fb95dc59cc6e95), + W64LIT(0x174b17b872655c17), W64LIT(0xf017f0d31aeae7f0), W64LIT(0xd89fd88eea3247d8), W64LIT(0x092d0948363f2409), + W64LIT(0x6dc46d4f731ea96d), W64LIT(0xf318f3cb10e3ebf3), W64LIT(0x1d691de84e53741d), W64LIT(0xcbc0cb16804b0bcb), + W64LIT(0xc9cac9068c4503c9), W64LIT(0x4d644d52b3fe294d), W64LIT(0x2c9c2c7de8c4b02c), W64LIT(0xaf29af11c56a86af), + W64LIT(0x798079ef0b72f979), W64LIT(0xe047e0537a9aa7e0), W64LIT(0x97f197cc55c26697), W64LIT(0xfd2efdbb34c9d3fd), + W64LIT(0x6fce6f5f7f10a16f), W64LIT(0x4b7a4b62a7ec314b), W64LIT(0x454c451283c60945), W64LIT(0x39dd39d596afe439), + W64LIT(0x3ec63eed84baf83e), W64LIT(0xdd8edda6f42953dd), W64LIT(0xa315a371ed4eb6a3), W64LIT(0x4f6e4f42bff0214f), + W64LIT(0xb45eb4c99f2beab4), W64LIT(0xb654b6d99325e2b6), W64LIT(0x9ac89aa47be1529a), W64LIT(0x0e360e70242a380e), + W64LIT(0x1f631ff8425d7c1f), W64LIT(0xbf79bf91a51ac6bf), W64LIT(0x154115a87e6b5415), W64LIT(0xe142e15b7c9da3e1), + W64LIT(0x49704972abe23949), W64LIT(0xd2bdd2ded6046fd2), W64LIT(0x93e593ec4dde7693), W64LIT(0xc6f9c67eae683fc6), + W64LIT(0x92e092e44bd97292), W64LIT(0x72a772b73143d572), W64LIT(0x9edc9e8463fd429e), W64LIT(0x61f8612f5b3a9961), + W64LIT(0xd1b2d1c6dc0d63d1), W64LIT(0x63f2633f57349163), W64LIT(0xfa35fa8326dccffa), W64LIT(0xee71ee235eb09fee), + W64LIT(0xf403f4f302f6f7f4), W64LIT(0x197d19c8564f6419), W64LIT(0xd5a6d5e6c41173d5), W64LIT(0xad23ad01c9648ead), + W64LIT(0x582558facd957d58), W64LIT(0xa40ea449ff5baaa4), W64LIT(0xbb6dbbb1bd06d6bb), W64LIT(0xa11fa161e140bea1), + W64LIT(0xdc8bdcaef22e57dc), W64LIT(0xf21df2c316e4eff2), W64LIT(0x83b5836c2dae3683), W64LIT(0x37eb37a5b285dc37), + W64LIT(0x4257422a91d31542), W64LIT(0xe453e4736286b7e4), W64LIT(0x7a8f7af7017bf57a), W64LIT(0x32fa328dac9ec832), + W64LIT(0x9cd69c946ff34a9c), W64LIT(0xccdbcc2e925e17cc), W64LIT(0xab3dab31dd7696ab), W64LIT(0x4a7f4a6aa1eb354a), + W64LIT(0x8f898f0c058a068f), W64LIT(0x6ecb6e577917a56e), W64LIT(0x04140420181c1004), W64LIT(0x27bb2725d2f59c27), + W64LIT(0x2e962e6de4cab82e), W64LIT(0xe75ce76b688fbbe7), W64LIT(0xe24de2437694afe2), W64LIT(0x5a2f5aeac19b755a), + W64LIT(0x96f496c453c56296), W64LIT(0x164e16b074625816), W64LIT(0x23af2305cae98c23), W64LIT(0x2b872b45fad1ac2b), + W64LIT(0xc2edc25eb6742fc2), W64LIT(0x65ec650f43268965), W64LIT(0x66e36617492f8566), W64LIT(0x0f330f78222d3c0f), + W64LIT(0xbc76bc89af13cabc), W64LIT(0xa937a921d1789ea9), W64LIT(0x474647028fc80147), W64LIT(0x415841329bda1941), + W64LIT(0x34e434bdb88cd034), W64LIT(0x4875487aade53d48), W64LIT(0xfc2bfcb332ced7fc), W64LIT(0xb751b7d19522e6b7), + W64LIT(0x6adf6a77610bb56a), W64LIT(0x88928834179f1a88), W64LIT(0xa50ba541f95caea5), W64LIT(0x530253a2f7a45153), + W64LIT(0x86a4864433b52286), W64LIT(0xf93af99b2cd5c3f9), W64LIT(0x5b2a5be2c79c715b), W64LIT(0xdb90db96e03b4bdb), + W64LIT(0x38d838dd90a8e038), W64LIT(0x7b8a7bff077cf17b), W64LIT(0xc3e8c356b0732bc3), W64LIT(0x1e661ef0445a781e), + W64LIT(0x22aa220dccee8822), W64LIT(0x33ff3385aa99cc33), W64LIT(0x24b4243dd8fc9024), W64LIT(0x2888285df0d8a028), + W64LIT(0x36ee36adb482d836), W64LIT(0xc7fcc776a86f3bc7), W64LIT(0xb240b2f98b39f2b2), W64LIT(0x3bd73bc59aa1ec3b), + W64LIT(0x8e8c8e04038d028e), W64LIT(0x77b6779f2f58c177), W64LIT(0xba68bab9bb01d2ba), W64LIT(0xf506f5fb04f1f3f5), + W64LIT(0x144414a0786c5014), W64LIT(0x9fd99f8c65fa469f), W64LIT(0x0828084030382008), W64LIT(0x551c5592e3b64955), + W64LIT(0x9bcd9bac7de6569b), W64LIT(0x4c614c5ab5f92d4c), W64LIT(0xfe21fea33ec0dffe), W64LIT(0x60fd60275d3d9d60), + W64LIT(0x5c315cdad5896d5c), W64LIT(0xda95da9ee63c4fda), W64LIT(0x187818c050486018), W64LIT(0x4643460a89cf0546), + W64LIT(0xcddecd26945913cd), W64LIT(0x7d947dcf136ee97d), W64LIT(0x21a52115c6e78421), W64LIT(0xb04ab0e98737fab0), + W64LIT(0x3fc33fe582bdfc3f), W64LIT(0x1b771bd85a416c1b), W64LIT(0x8997893c11981e89), W64LIT(0xff24ffab38c7dbff), + W64LIT(0xeb60eb0b40ab8beb), W64LIT(0x84ae84543fbb2a84), W64LIT(0x69d0696f6b02b969), W64LIT(0x3ad23acd9ca6e83a), + W64LIT(0x9dd39d9c69f44e9d), W64LIT(0xd7acd7f6c81f7bd7), W64LIT(0xd3b8d3d6d0036bd3), W64LIT(0x70ad70a73d4ddd70), + W64LIT(0x67e6671f4f288167), W64LIT(0x405d403a9ddd1d40), W64LIT(0xb55bb5c1992ceeb5), W64LIT(0xde81debefe205fde), + W64LIT(0x5d345dd2d38e695d), W64LIT(0x30f0309da090c030), W64LIT(0x91ef91fc41d07e91), W64LIT(0xb14fb1e18130feb1), + W64LIT(0x788578e70d75fd78), W64LIT(0x1155118866774411), W64LIT(0x0105010806070401), W64LIT(0xe556e57b6481b3e5), + W64LIT(0x0000000000000000), W64LIT(0x68d568676d05bd68), W64LIT(0x98c298b477ef5a98), W64LIT(0xa01aa069e747baa0), + W64LIT(0xc5f6c566a46133c5), W64LIT(0x020a02100c0e0802), W64LIT(0xa604a659f355a2a6), W64LIT(0x74b974872551cd74), + W64LIT(0x2d992d75eec3b42d), W64LIT(0x0b270b583a312c0b), W64LIT(0xa210a279eb49b2a2), W64LIT(0x76b37697295fc576), + W64LIT(0xb345b3f18d3ef6b3), W64LIT(0xbe7cbe99a31dc2be), W64LIT(0xced1ce3e9e501fce), W64LIT(0xbd73bd81a914cebd), + W64LIT(0xae2cae19c36d82ae), W64LIT(0xe96ae91b4ca583e9), W64LIT(0x8a988a241b91128a), W64LIT(0x31f53195a697c431), + W64LIT(0x1c6c1ce04854701c), W64LIT(0xec7bec3352be97ec), W64LIT(0xf112f1db1cede3f1), W64LIT(0x99c799bc71e85e99), + W64LIT(0x94fe94d45fcb6a94), W64LIT(0xaa38aa39db7192aa), W64LIT(0xf609f6e30ef8fff6), W64LIT(0x26be262dd4f29826), + W64LIT(0x2f932f65e2cdbc2f), W64LIT(0xef74ef2b58b79bef), W64LIT(0xe86fe8134aa287e8), W64LIT(0x8c868c140f830a8c), + W64LIT(0x35e135b5be8bd435), W64LIT(0x030f03180a090c03), W64LIT(0xd4a3d4eec21677d4), W64LIT(0x7f9e7fdf1f60e17f), + W64LIT(0xfb30fb8b20dbcbfb), W64LIT(0x051105281e1b1405), W64LIT(0xc1e2c146bc7d23c1), W64LIT(0x5e3b5ecad987655e), + W64LIT(0x90ea90f447d77a90), W64LIT(0x20a0201dc0e08020), W64LIT(0x3dc93df58eb3f43d), W64LIT(0x82b082642ba93282), + W64LIT(0xf70cf7eb08fffbf7), W64LIT(0xea65ea0346ac8fea), W64LIT(0x0a220a503c36280a), W64LIT(0x0d390d682e23340d), + W64LIT(0x7e9b7ed71967e57e), W64LIT(0xf83ff8932ad2c7f8), W64LIT(0x500d50bafdad5d50), W64LIT(0x1a721ad05c46681a), + W64LIT(0xc4f3c46ea26637c4), W64LIT(0x071b073812151c07), W64LIT(0x57165782efb84157), W64LIT(0xb862b8a9b70fdab8), + W64LIT(0x3ccc3cfd88b4f03c), W64LIT(0x62f7623751339562), W64LIT(0xe348e34b7093abe3), W64LIT(0xc8cfc80e8a4207c8), + W64LIT(0xac26ac09cf638aac), W64LIT(0x520752aaf1a35552), W64LIT(0x64e9640745218d64), W64LIT(0x1050108060704010), + W64LIT(0xd0b7d0ceda0a67d0), W64LIT(0xd99ad986ec3543d9), W64LIT(0x135f13986a794c13), W64LIT(0x0c3c0c602824300c), + W64LIT(0x125a12906c7e4812), W64LIT(0x298d2955f6dfa429), W64LIT(0x510851b2fbaa5951), W64LIT(0xb967b9a1b108deb9), + W64LIT(0xcfd4cf3698571bcf), W64LIT(0xd6a9d6fece187fd6), W64LIT(0x73a273bf3744d173), W64LIT(0x8d838d1c09840e8d), + W64LIT(0x81bf817c21a03e81), W64LIT(0x5419549ae5b14d54), W64LIT(0xc0e7c04eba7a27c0), W64LIT(0xed7eed3b54b993ed), + W64LIT(0x4e6b4e4ab9f7254e), W64LIT(0x4449441a85c10d44), W64LIT(0xa701a751f552a6a7), W64LIT(0x2a822a4dfcd6a82a), + W64LIT(0x85ab855c39bc2e85), W64LIT(0x25b12535defb9425), W64LIT(0xe659e6636e88bfe6), W64LIT(0xcac5ca1e864c0fca), + W64LIT(0x7c917cc71569ed7c), W64LIT(0x8b9d8b2c1d96168b), W64LIT(0x5613568ae9bf4556), W64LIT(0x80ba807427a73a80) + }, + { + W64LIT(0xd1ce3e9e501fcece), W64LIT(0x6dbbb1bd06d6bbbb), W64LIT(0x60eb0b40ab8bebeb), W64LIT(0xe092e44bd9729292), + W64LIT(0x65ea0346ac8feaea), W64LIT(0xc0cb16804b0bcbcb), W64LIT(0x5f13986a794c1313), W64LIT(0xe2c146bc7d23c1c1), + W64LIT(0x6ae91b4ca583e9e9), W64LIT(0xd23acd9ca6e83a3a), W64LIT(0xa9d6fece187fd6d6), W64LIT(0x40b2f98b39f2b2b2), + W64LIT(0xbdd2ded6046fd2d2), W64LIT(0xea90f447d77a9090), W64LIT(0x4b17b872655c1717), W64LIT(0x3ff8932ad2c7f8f8), + W64LIT(0x57422a91d3154242), W64LIT(0x4115a87e6b541515), W64LIT(0x13568ae9bf455656), W64LIT(0x5eb4c99f2beab4b4), + W64LIT(0xec650f4326896565), W64LIT(0x6c1ce04854701c1c), W64LIT(0x928834179f1a8888), W64LIT(0x52432297d4114343), + W64LIT(0xf6c566a46133c5c5), W64LIT(0x315cdad5896d5c5c), W64LIT(0xee36adb482d83636), W64LIT(0x68bab9bb01d2baba), + W64LIT(0x06f5fb04f1f3f5f5), W64LIT(0x165782efb8415757), W64LIT(0xe6671f4f28816767), W64LIT(0x838d1c09840e8d8d), + W64LIT(0xf53195a697c43131), W64LIT(0x09f6e30ef8fff6f6), W64LIT(0xe9640745218d6464), W64LIT(0x2558facd957d5858), + W64LIT(0xdc9e8463fd429e9e), W64LIT(0x03f4f302f6f7f4f4), W64LIT(0xaa220dccee882222), W64LIT(0x38aa39db7192aaaa), + W64LIT(0xbc758f2356c97575), W64LIT(0x330f78222d3c0f0f), W64LIT(0x0a02100c0e080202), W64LIT(0x4fb1e18130feb1b1), + W64LIT(0x84dfb6f8275bdfdf), W64LIT(0xc46d4f731ea96d6d), W64LIT(0xa273bf3744d17373), W64LIT(0x644d52b3fe294d4d), + W64LIT(0x917cc71569ed7c7c), W64LIT(0xbe262dd4f2982626), W64LIT(0x962e6de4cab82e2e), W64LIT(0x0cf7eb08fffbf7f7), + W64LIT(0x2808403038200808), W64LIT(0x345dd2d38e695d5d), W64LIT(0x49441a85c10d4444), W64LIT(0xc63eed84baf83e3e), + W64LIT(0xd99f8c65fa469f9f), W64LIT(0x4414a0786c501414), W64LIT(0xcfc80e8a4207c8c8), W64LIT(0x2cae19c36d82aeae), + W64LIT(0x19549ae5b14d5454), W64LIT(0x5010806070401010), W64LIT(0x9fd88eea3247d8d8), W64LIT(0x76bc89af13cabcbc), + W64LIT(0x721ad05c46681a1a), W64LIT(0xda6b7f670cb16b6b), W64LIT(0xd0696f6b02b96969), W64LIT(0x18f3cb10e3ebf3f3), + W64LIT(0x73bd81a914cebdbd), W64LIT(0xff3385aa99cc3333), W64LIT(0x3dab31dd7696abab), W64LIT(0x35fa8326dccffafa), + W64LIT(0xb2d1c6dc0d63d1d1), W64LIT(0xcd9bac7de6569b9b), W64LIT(0xd568676d05bd6868), W64LIT(0x6b4e4ab9f7254e4e), + W64LIT(0x4e16b07462581616), W64LIT(0xfb95dc59cc6e9595), W64LIT(0xef91fc41d07e9191), W64LIT(0x71ee235eb09feeee), + W64LIT(0x614c5ab5f92d4c4c), W64LIT(0xf2633f5734916363), W64LIT(0x8c8e04038d028e8e), W64LIT(0x2a5be2c79c715b5b), + W64LIT(0xdbcc2e925e17cccc), W64LIT(0xcc3cfd88b4f03c3c), W64LIT(0x7d19c8564f641919), W64LIT(0x1fa161e140bea1a1), + W64LIT(0xbf817c21a03e8181), W64LIT(0x704972abe2394949), W64LIT(0x8a7bff077cf17b7b), W64LIT(0x9ad986ec3543d9d9), + W64LIT(0xce6f5f7f10a16f6f), W64LIT(0xeb37a5b285dc3737), W64LIT(0xfd60275d3d9d6060), W64LIT(0xc5ca1e864c0fcaca), + W64LIT(0x5ce76b688fbbe7e7), W64LIT(0x872b45fad1ac2b2b), W64LIT(0x75487aade53d4848), W64LIT(0x2efdbb34c9d3fdfd), + W64LIT(0xf496c453c5629696), W64LIT(0x4c451283c6094545), W64LIT(0x2bfcb332ced7fcfc), W64LIT(0x5841329bda194141), + W64LIT(0x5a12906c7e481212), W64LIT(0x390d682e23340d0d), W64LIT(0x8079ef0b72f97979), W64LIT(0x56e57b6481b3e5e5), + W64LIT(0x97893c11981e8989), W64LIT(0x868c140f830a8c8c), W64LIT(0x48e34b7093abe3e3), W64LIT(0xa0201dc0e0802020), + W64LIT(0xf0309da090c03030), W64LIT(0x8bdcaef22e57dcdc), W64LIT(0x51b7d19522e6b7b7), W64LIT(0xc16c477519ad6c6c), + W64LIT(0x7f4a6aa1eb354a4a), W64LIT(0x5bb5c1992ceeb5b5), W64LIT(0xc33fe582bdfc3f3f), W64LIT(0xf197cc55c2669797), + W64LIT(0xa3d4eec21677d4d4), W64LIT(0xf762375133956262), W64LIT(0x992d75eec3b42d2d), W64LIT(0x1e06301412180606), + W64LIT(0x0ea449ff5baaa4a4), W64LIT(0x0ba541f95caea5a5), W64LIT(0xb5836c2dae368383), W64LIT(0x3e5fc2df80615f5f), + W64LIT(0x822a4dfcd6a82a2a), W64LIT(0x95da9ee63c4fdada), W64LIT(0xcac9068c4503c9c9), W64LIT(0x0000000000000000), + W64LIT(0x9b7ed71967e57e7e), W64LIT(0x10a279eb49b2a2a2), W64LIT(0x1c5592e3b6495555), W64LIT(0x79bf91a51ac6bfbf), + W64LIT(0x5511886677441111), W64LIT(0xa6d5e6c41173d5d5), W64LIT(0xd69c946ff34a9c9c), W64LIT(0xd4cf3698571bcfcf), + W64LIT(0x360e70242a380e0e), W64LIT(0x220a503c36280a0a), W64LIT(0xc93df58eb3f43d3d), W64LIT(0x0851b2fbaa595151), + W64LIT(0x947dcf136ee97d7d), W64LIT(0xe593ec4dde769393), W64LIT(0x771bd85a416c1b1b), W64LIT(0x21fea33ec0dffefe), + W64LIT(0xf3c46ea26637c4c4), W64LIT(0x4647028fc8014747), W64LIT(0x2d0948363f240909), W64LIT(0xa4864433b5228686), + W64LIT(0x270b583a312c0b0b), W64LIT(0x898f0c058a068f8f), W64LIT(0xd39d9c69f44e9d9d), W64LIT(0xdf6a77610bb56a6a), + W64LIT(0x1b073812151c0707), W64LIT(0x67b9a1b108deb9b9), W64LIT(0x4ab0e98737fab0b0), W64LIT(0xc298b477ef5a9898), + W64LIT(0x7818c05048601818), W64LIT(0xfa328dac9ec83232), W64LIT(0xa871af3b4ad97171), W64LIT(0x7a4b62a7ec314b4b), + W64LIT(0x74ef2b58b79befef), W64LIT(0xd73bc59aa1ec3b3b), W64LIT(0xad70a73d4ddd7070), W64LIT(0x1aa069e747baa0a0), + W64LIT(0x53e4736286b7e4e4), W64LIT(0x5d403a9ddd1d4040), W64LIT(0x24ffab38c7dbffff), W64LIT(0xe8c356b0732bc3c3), + W64LIT(0x37a921d1789ea9a9), W64LIT(0x59e6636e88bfe6e6), W64LIT(0x8578e70d75fd7878), W64LIT(0x3af99b2cd5c3f9f9), + W64LIT(0x9d8b2c1d96168b8b), W64LIT(0x43460a89cf054646), W64LIT(0xba807427a73a8080), W64LIT(0x661ef0445a781e1e), + W64LIT(0xd838dd90a8e03838), W64LIT(0x42e15b7c9da3e1e1), W64LIT(0x62b8a9b70fdab8b8), W64LIT(0x32a829d77f9aa8a8), + W64LIT(0x47e0537a9aa7e0e0), W64LIT(0x3c0c602824300c0c), W64LIT(0xaf2305cae98c2323), W64LIT(0xb37697295fc57676), + W64LIT(0x691de84e53741d1d), W64LIT(0xb12535defb942525), W64LIT(0xb4243dd8fc902424), W64LIT(0x1105281e1b140505), + W64LIT(0x12f1db1cede3f1f1), W64LIT(0xcb6e577917a56e6e), W64LIT(0xfe94d45fcb6a9494), W64LIT(0x88285df0d8a02828), + W64LIT(0xc89aa47be1529a9a), W64LIT(0xae84543fbb2a8484), W64LIT(0x6fe8134aa287e8e8), W64LIT(0x15a371ed4eb6a3a3), + W64LIT(0x6e4f42bff0214f4f), W64LIT(0xb6779f2f58c17777), W64LIT(0xb8d3d6d0036bd3d3), W64LIT(0xab855c39bc2e8585), + W64LIT(0x4de2437694afe2e2), W64LIT(0x0752aaf1a3555252), W64LIT(0x1df2c316e4eff2f2), W64LIT(0xb082642ba9328282), + W64LIT(0x0d50bafdad5d5050), W64LIT(0x8f7af7017bf57a7a), W64LIT(0x932f65e2cdbc2f2f), W64LIT(0xb974872551cd7474), + W64LIT(0x0253a2f7a4515353), W64LIT(0x45b3f18d3ef6b3b3), W64LIT(0xf8612f5b3a996161), W64LIT(0x29af11c56a86afaf), + W64LIT(0xdd39d596afe43939), W64LIT(0xe135b5be8bd43535), W64LIT(0x81debefe205fdede), W64LIT(0xdecd26945913cdcd), + W64LIT(0x631ff8425d7c1f1f), W64LIT(0xc799bc71e85e9999), W64LIT(0x26ac09cf638aacac), W64LIT(0x23ad01c9648eadad), + W64LIT(0xa772b73143d57272), W64LIT(0x9c2c7de8c4b02c2c), W64LIT(0x8edda6f42953dddd), W64LIT(0xb7d0ceda0a67d0d0), + W64LIT(0xa1874c35b2268787), W64LIT(0x7cbe99a31dc2bebe), W64LIT(0x3b5ecad987655e5e), W64LIT(0x04a659f355a2a6a6), + W64LIT(0x7bec3352be97ecec), W64LIT(0x140420181c100404), W64LIT(0xf9c67eae683fc6c6), W64LIT(0x0f03180a090c0303), + W64LIT(0xe434bdb88cd03434), W64LIT(0x30fb8b20dbcbfbfb), W64LIT(0x90db96e03b4bdbdb), W64LIT(0x2059f2cb92795959), + W64LIT(0x54b6d99325e2b6b6), W64LIT(0xedc25eb6742fc2c2), W64LIT(0x0501080607040101), W64LIT(0x17f0d31aeae7f0f0), + W64LIT(0x2f5aeac19b755a5a), W64LIT(0x7eed3b54b993eded), W64LIT(0x01a751f552a6a7a7), W64LIT(0xe36617492f856666), + W64LIT(0xa52115c6e7842121), W64LIT(0x9e7fdf1f60e17f7f), W64LIT(0x988a241b91128a8a), W64LIT(0xbb2725d2f59c2727), + W64LIT(0xfcc776a86f3bc7c7), W64LIT(0xe7c04eba7a27c0c0), W64LIT(0x8d2955f6dfa42929), W64LIT(0xacd7f6c81f7bd7d7) + }, + { + W64LIT(0x93ec4dde769393e5), W64LIT(0xd986ec3543d9d99a), W64LIT(0x9aa47be1529a9ac8), W64LIT(0xb5c1992ceeb5b55b), + W64LIT(0x98b477ef5a9898c2), W64LIT(0x220dccee882222aa), W64LIT(0x451283c60945454c), W64LIT(0xfcb332ced7fcfc2b), + W64LIT(0xbab9bb01d2baba68), W64LIT(0x6a77610bb56a6adf), W64LIT(0xdfb6f8275bdfdf84), W64LIT(0x02100c0e0802020a), + W64LIT(0x9f8c65fa469f9fd9), W64LIT(0xdcaef22e57dcdc8b), W64LIT(0x51b2fbaa59515108), W64LIT(0x59f2cb9279595920), + W64LIT(0x4a6aa1eb354a4a7f), W64LIT(0x17b872655c17174b), W64LIT(0x2b45fad1ac2b2b87), W64LIT(0xc25eb6742fc2c2ed), + W64LIT(0x94d45fcb6a9494fe), W64LIT(0xf4f302f6f7f4f403), W64LIT(0xbbb1bd06d6bbbb6d), W64LIT(0xa371ed4eb6a3a315), + W64LIT(0x62375133956262f7), W64LIT(0xe4736286b7e4e453), W64LIT(0x71af3b4ad97171a8), W64LIT(0xd4eec21677d4d4a3), + W64LIT(0xcd26945913cdcdde), W64LIT(0x70a73d4ddd7070ad), W64LIT(0x16b074625816164e), W64LIT(0xe15b7c9da3e1e142), + W64LIT(0x4972abe239494970), W64LIT(0x3cfd88b4f03c3ccc), W64LIT(0xc04eba7a27c0c0e7), W64LIT(0xd88eea3247d8d89f), + W64LIT(0x5cdad5896d5c5c31), W64LIT(0x9bac7de6569b9bcd), W64LIT(0xad01c9648eadad23), W64LIT(0x855c39bc2e8585ab), + W64LIT(0x53a2f7a451535302), W64LIT(0xa161e140bea1a11f), W64LIT(0x7af7017bf57a7a8f), W64LIT(0xc80e8a4207c8c8cf), + W64LIT(0x2d75eec3b42d2d99), W64LIT(0xe0537a9aa7e0e047), W64LIT(0xd1c6dc0d63d1d1b2), W64LIT(0x72b73143d57272a7), + W64LIT(0xa659f355a2a6a604), W64LIT(0x2c7de8c4b02c2c9c), W64LIT(0xc46ea26637c4c4f3), W64LIT(0xe34b7093abe3e348), + W64LIT(0x7697295fc57676b3), W64LIT(0x78e70d75fd787885), W64LIT(0xb7d19522e6b7b751), W64LIT(0xb4c99f2beab4b45e), + W64LIT(0x0948363f2409092d), W64LIT(0x3bc59aa1ec3b3bd7), W64LIT(0x0e70242a380e0e36), W64LIT(0x41329bda19414158), + W64LIT(0x4c5ab5f92d4c4c61), W64LIT(0xdebefe205fdede81), W64LIT(0xb2f98b39f2b2b240), W64LIT(0x90f447d77a9090ea), + W64LIT(0x2535defb942525b1), W64LIT(0xa541f95caea5a50b), W64LIT(0xd7f6c81f7bd7d7ac), W64LIT(0x03180a090c03030f), + W64LIT(0x1188667744111155), W64LIT(0x0000000000000000), W64LIT(0xc356b0732bc3c3e8), W64LIT(0x2e6de4cab82e2e96), + W64LIT(0x92e44bd9729292e0), W64LIT(0xef2b58b79befef74), W64LIT(0x4e4ab9f7254e4e6b), W64LIT(0x12906c7e4812125a), + W64LIT(0x9d9c69f44e9d9dd3), W64LIT(0x7dcf136ee97d7d94), W64LIT(0xcb16804b0bcbcbc0), W64LIT(0x35b5be8bd43535e1), + W64LIT(0x1080607040101050), W64LIT(0xd5e6c41173d5d5a6), W64LIT(0x4f42bff0214f4f6e), W64LIT(0x9e8463fd429e9edc), + W64LIT(0x4d52b3fe294d4d64), W64LIT(0xa921d1789ea9a937), W64LIT(0x5592e3b64955551c), W64LIT(0xc67eae683fc6c6f9), + W64LIT(0xd0ceda0a67d0d0b7), W64LIT(0x7bff077cf17b7b8a), W64LIT(0x18c0504860181878), W64LIT(0x97cc55c2669797f1), + W64LIT(0xd3d6d0036bd3d3b8), W64LIT(0x36adb482d83636ee), W64LIT(0xe6636e88bfe6e659), W64LIT(0x487aade53d484875), + W64LIT(0x568ae9bf45565613), W64LIT(0x817c21a03e8181bf), W64LIT(0x8f0c058a068f8f89), W64LIT(0x779f2f58c17777b6), + W64LIT(0xcc2e925e17ccccdb), W64LIT(0x9c946ff34a9c9cd6), W64LIT(0xb9a1b108deb9b967), W64LIT(0xe2437694afe2e24d), + W64LIT(0xac09cf638aacac26), W64LIT(0xb8a9b70fdab8b862), W64LIT(0x2f65e2cdbc2f2f93), W64LIT(0x15a87e6b54151541), + W64LIT(0xa449ff5baaa4a40e), W64LIT(0x7cc71569ed7c7c91), W64LIT(0xda9ee63c4fdada95), W64LIT(0x38dd90a8e03838d8), + W64LIT(0x1ef0445a781e1e66), W64LIT(0x0b583a312c0b0b27), W64LIT(0x05281e1b14050511), W64LIT(0xd6fece187fd6d6a9), + W64LIT(0x14a0786c50141444), W64LIT(0x6e577917a56e6ecb), W64LIT(0x6c477519ad6c6cc1), W64LIT(0x7ed71967e57e7e9b), + W64LIT(0x6617492f856666e3), W64LIT(0xfdbb34c9d3fdfd2e), W64LIT(0xb1e18130feb1b14f), W64LIT(0xe57b6481b3e5e556), + W64LIT(0x60275d3d9d6060fd), W64LIT(0xaf11c56a86afaf29), W64LIT(0x5ecad987655e5e3b), W64LIT(0x3385aa99cc3333ff), + W64LIT(0x874c35b2268787a1), W64LIT(0xc9068c4503c9c9ca), W64LIT(0xf0d31aeae7f0f017), W64LIT(0x5dd2d38e695d5d34), + W64LIT(0x6d4f731ea96d6dc4), W64LIT(0x3fe582bdfc3f3fc3), W64LIT(0x8834179f1a888892), W64LIT(0x8d1c09840e8d8d83), + W64LIT(0xc776a86f3bc7c7fc), W64LIT(0xf7eb08fffbf7f70c), W64LIT(0x1de84e53741d1d69), W64LIT(0xe91b4ca583e9e96a), + W64LIT(0xec3352be97ecec7b), W64LIT(0xed3b54b993eded7e), W64LIT(0x807427a73a8080ba), W64LIT(0x2955f6dfa429298d), + W64LIT(0x2725d2f59c2727bb), W64LIT(0xcf3698571bcfcfd4), W64LIT(0x99bc71e85e9999c7), W64LIT(0xa829d77f9aa8a832), + W64LIT(0x50bafdad5d50500d), W64LIT(0x0f78222d3c0f0f33), W64LIT(0x37a5b285dc3737eb), W64LIT(0x243dd8fc902424b4), + W64LIT(0x285df0d8a0282888), W64LIT(0x309da090c03030f0), W64LIT(0x95dc59cc6e9595fb), W64LIT(0xd2ded6046fd2d2bd), + W64LIT(0x3eed84baf83e3ec6), W64LIT(0x5be2c79c715b5b2a), W64LIT(0x403a9ddd1d40405d), W64LIT(0x836c2dae368383b5), + W64LIT(0xb3f18d3ef6b3b345), W64LIT(0x696f6b02b96969d0), W64LIT(0x5782efb841575716), W64LIT(0x1ff8425d7c1f1f63), + W64LIT(0x073812151c07071b), W64LIT(0x1ce04854701c1c6c), W64LIT(0x8a241b91128a8a98), W64LIT(0xbc89af13cabcbc76), + W64LIT(0x201dc0e0802020a0), W64LIT(0xeb0b40ab8bebeb60), W64LIT(0xce3e9e501fceced1), W64LIT(0x8e04038d028e8e8c), + W64LIT(0xab31dd7696abab3d), W64LIT(0xee235eb09feeee71), W64LIT(0x3195a697c43131f5), W64LIT(0xa279eb49b2a2a210), + W64LIT(0x73bf3744d17373a2), W64LIT(0xf99b2cd5c3f9f93a), W64LIT(0xca1e864c0fcacac5), W64LIT(0x3acd9ca6e83a3ad2), + W64LIT(0x1ad05c46681a1a72), W64LIT(0xfb8b20dbcbfbfb30), W64LIT(0x0d682e23340d0d39), W64LIT(0xc146bc7d23c1c1e2), + W64LIT(0xfea33ec0dffefe21), W64LIT(0xfa8326dccffafa35), W64LIT(0xf2c316e4eff2f21d), W64LIT(0x6f5f7f10a16f6fce), + W64LIT(0xbd81a914cebdbd73), W64LIT(0x96c453c5629696f4), W64LIT(0xdda6f42953dddd8e), W64LIT(0x432297d411434352), + W64LIT(0x52aaf1a355525207), W64LIT(0xb6d99325e2b6b654), W64LIT(0x0840303820080828), W64LIT(0xf3cb10e3ebf3f318), + W64LIT(0xae19c36d82aeae2c), W64LIT(0xbe99a31dc2bebe7c), W64LIT(0x19c8564f6419197d), W64LIT(0x893c11981e898997), + W64LIT(0x328dac9ec83232fa), W64LIT(0x262dd4f2982626be), W64LIT(0xb0e98737fab0b04a), W64LIT(0xea0346ac8feaea65), + W64LIT(0x4b62a7ec314b4b7a), W64LIT(0x640745218d6464e9), W64LIT(0x84543fbb2a8484ae), W64LIT(0x82642ba9328282b0), + W64LIT(0x6b7f670cb16b6bda), W64LIT(0xf5fb04f1f3f5f506), W64LIT(0x79ef0b72f9797980), W64LIT(0xbf91a51ac6bfbf79), + W64LIT(0x0108060704010105), W64LIT(0x5fc2df80615f5f3e), W64LIT(0x758f2356c97575bc), W64LIT(0x633f5734916363f2), + W64LIT(0x1bd85a416c1b1b77), W64LIT(0x2305cae98c2323af), W64LIT(0x3df58eb3f43d3dc9), W64LIT(0x68676d05bd6868d5), + W64LIT(0x2a4dfcd6a82a2a82), W64LIT(0x650f4326896565ec), W64LIT(0xe8134aa287e8e86f), W64LIT(0x91fc41d07e9191ef), + W64LIT(0xf6e30ef8fff6f609), W64LIT(0xffab38c7dbffff24), W64LIT(0x13986a794c13135f), W64LIT(0x58facd957d585825), + W64LIT(0xf1db1cede3f1f112), W64LIT(0x47028fc801474746), W64LIT(0x0a503c36280a0a22), W64LIT(0x7fdf1f60e17f7f9e), + W64LIT(0xc566a46133c5c5f6), W64LIT(0xa751f552a6a7a701), W64LIT(0xe76b688fbbe7e75c), W64LIT(0x612f5b3a996161f8), + W64LIT(0x5aeac19b755a5a2f), W64LIT(0x063014121806061e), W64LIT(0x460a89cf05464643), W64LIT(0x441a85c10d444449), + W64LIT(0x422a91d315424257), W64LIT(0x0420181c10040414), W64LIT(0xa069e747baa0a01a), W64LIT(0xdb96e03b4bdbdb90), + W64LIT(0x39d596afe43939dd), W64LIT(0x864433b5228686a4), W64LIT(0x549ae5b14d545419), W64LIT(0xaa39db7192aaaa38), + W64LIT(0x8c140f830a8c8c86), W64LIT(0x34bdb88cd03434e4), W64LIT(0x2115c6e7842121a5), W64LIT(0x8b2c1d96168b8b9d), + W64LIT(0xf8932ad2c7f8f83f), W64LIT(0x0c602824300c0c3c), W64LIT(0x74872551cd7474b9), W64LIT(0x671f4f28816767e6) + }, + { + W64LIT(0x676d05bd6868d568), W64LIT(0x1c09840e8d8d838d), W64LIT(0x1e864c0fcacac5ca), W64LIT(0x52b3fe294d4d644d), + W64LIT(0xbf3744d17373a273), W64LIT(0x62a7ec314b4b7a4b), W64LIT(0x4ab9f7254e4e6b4e), W64LIT(0x4dfcd6a82a2a822a), + W64LIT(0xeec21677d4d4a3d4), W64LIT(0xaaf1a35552520752), W64LIT(0x2dd4f2982626be26), W64LIT(0xf18d3ef6b3b345b3), + W64LIT(0x9ae5b14d54541954), W64LIT(0xf0445a781e1e661e), W64LIT(0xc8564f6419197d19), W64LIT(0xf8425d7c1f1f631f), + W64LIT(0x0dccee882222aa22), W64LIT(0x180a090c03030f03), W64LIT(0x0a89cf0546464346), W64LIT(0xf58eb3f43d3dc93d), + W64LIT(0x75eec3b42d2d992d), W64LIT(0x6aa1eb354a4a7f4a), W64LIT(0xa2f7a45153530253), W64LIT(0x6c2dae368383b583), + W64LIT(0x986a794c13135f13), W64LIT(0x241b91128a8a988a), W64LIT(0xd19522e6b7b751b7), W64LIT(0xe6c41173d5d5a6d5), + W64LIT(0x35defb942525b125), W64LIT(0xef0b72f979798079), W64LIT(0xfb04f1f3f5f506f5), W64LIT(0x81a914cebdbd73bd), + W64LIT(0xfacd957d58582558), W64LIT(0x65e2cdbc2f2f932f), W64LIT(0x682e23340d0d390d), W64LIT(0x100c0e0802020a02), + W64LIT(0x3b54b993eded7eed), W64LIT(0xb2fbaa5951510851), W64LIT(0x8463fd429e9edc9e), W64LIT(0x8866774411115511), + W64LIT(0xc316e4eff2f21df2), W64LIT(0xed84baf83e3ec63e), W64LIT(0x92e3b64955551c55), W64LIT(0xcad987655e5e3b5e), + W64LIT(0xc6dc0d63d1d1b2d1), W64LIT(0xb074625816164e16), W64LIT(0xfd88b4f03c3ccc3c), W64LIT(0x17492f856666e366), + W64LIT(0xa73d4ddd7070ad70), W64LIT(0xd2d38e695d5d345d), W64LIT(0xcb10e3ebf3f318f3), W64LIT(0x1283c60945454c45), + W64LIT(0x3a9ddd1d40405d40), W64LIT(0x2e925e17ccccdbcc), W64LIT(0x134aa287e8e86fe8), W64LIT(0xd45fcb6a9494fe94), + W64LIT(0x8ae9bf4556561356), W64LIT(0x4030382008082808), W64LIT(0x3e9e501fceced1ce), W64LIT(0xd05c46681a1a721a), + W64LIT(0xcd9ca6e83a3ad23a), W64LIT(0xded6046fd2d2bdd2), W64LIT(0x5b7c9da3e1e142e1), W64LIT(0xb6f8275bdfdf84df), + W64LIT(0xc1992ceeb5b55bb5), W64LIT(0xdd90a8e03838d838), W64LIT(0x577917a56e6ecb6e), W64LIT(0x70242a380e0e360e), + W64LIT(0x7b6481b3e5e556e5), W64LIT(0xf302f6f7f4f403f4), W64LIT(0x9b2cd5c3f9f93af9), W64LIT(0x4433b5228686a486), + W64LIT(0x1b4ca583e9e96ae9), W64LIT(0x42bff0214f4f6e4f), W64LIT(0xfece187fd6d6a9d6), W64LIT(0x5c39bc2e8585ab85), + W64LIT(0x05cae98c2323af23), W64LIT(0x3698571bcfcfd4cf), W64LIT(0x8dac9ec83232fa32), W64LIT(0xbc71e85e9999c799), + W64LIT(0x95a697c43131f531), W64LIT(0xa0786c5014144414), W64LIT(0x19c36d82aeae2cae), W64LIT(0x235eb09feeee71ee), + W64LIT(0x0e8a4207c8c8cfc8), W64LIT(0x7aade53d48487548), W64LIT(0xd6d0036bd3d3b8d3), W64LIT(0x9da090c03030f030), + W64LIT(0x61e140bea1a11fa1), W64LIT(0xe44bd9729292e092), W64LIT(0x329bda1941415841), W64LIT(0xe18130feb1b14fb1), + W64LIT(0xc050486018187818), W64LIT(0x6ea26637c4c4f3c4), W64LIT(0x7de8c4b02c2c9c2c), W64LIT(0xaf3b4ad97171a871), + W64LIT(0xb73143d57272a772), W64LIT(0x1a85c10d44444944), W64LIT(0xa87e6b5415154115), W64LIT(0xbb34c9d3fdfd2efd), + W64LIT(0xa5b285dc3737eb37), W64LIT(0x99a31dc2bebe7cbe), W64LIT(0xc2df80615f5f3e5f), W64LIT(0x39db7192aaaa38aa), + W64LIT(0xac7de6569b9bcd9b), W64LIT(0x34179f1a88889288), W64LIT(0x8eea3247d8d89fd8), W64LIT(0x31dd7696abab3dab), + W64LIT(0x3c11981e89899789), W64LIT(0x946ff34a9c9cd69c), W64LIT(0x8326dccffafa35fa), W64LIT(0x275d3d9d6060fd60), + W64LIT(0x0346ac8feaea65ea), W64LIT(0x89af13cabcbc76bc), W64LIT(0x375133956262f762), W64LIT(0x602824300c0c3c0c), + W64LIT(0x3dd8fc902424b424), W64LIT(0x59f355a2a6a604a6), W64LIT(0x29d77f9aa8a832a8), W64LIT(0x3352be97ecec7bec), + W64LIT(0x1f4f28816767e667), W64LIT(0x1dc0e0802020a020), W64LIT(0x96e03b4bdbdb90db), W64LIT(0xc71569ed7c7c917c), + W64LIT(0x5df0d8a028288828), W64LIT(0xa6f42953dddd8edd), W64LIT(0x09cf638aacac26ac), W64LIT(0xe2c79c715b5b2a5b), + W64LIT(0xbdb88cd03434e434), W64LIT(0xd71967e57e7e9b7e), W64LIT(0x8060704010105010), W64LIT(0xdb1cede3f1f112f1), + W64LIT(0xff077cf17b7b8a7b), W64LIT(0x0c058a068f8f898f), W64LIT(0x3f5734916363f263), W64LIT(0x69e747baa0a01aa0), + W64LIT(0x281e1b1405051105), W64LIT(0xa47be1529a9ac89a), W64LIT(0x2297d41143435243), W64LIT(0x9f2f58c17777b677), + W64LIT(0x15c6e7842121a521), W64LIT(0x91a51ac6bfbf79bf), W64LIT(0x25d2f59c2727bb27), W64LIT(0x48363f2409092d09), + W64LIT(0x56b0732bc3c3e8c3), W64LIT(0x8c65fa469f9fd99f), W64LIT(0xd99325e2b6b654b6), W64LIT(0xf6c81f7bd7d7acd7), + W64LIT(0x55f6dfa429298d29), W64LIT(0x5eb6742fc2c2edc2), W64LIT(0x0b40ab8bebeb60eb), W64LIT(0x4eba7a27c0c0e7c0), + W64LIT(0x49ff5baaa4a40ea4), W64LIT(0x2c1d96168b8b9d8b), W64LIT(0x140f830a8c8c868c), W64LIT(0xe84e53741d1d691d), + W64LIT(0x8b20dbcbfbfb30fb), W64LIT(0xab38c7dbffff24ff), W64LIT(0x46bc7d23c1c1e2c1), W64LIT(0xf98b39f2b2b240b2), + W64LIT(0xcc55c2669797f197), W64LIT(0x6de4cab82e2e962e), W64LIT(0x932ad2c7f8f83ff8), W64LIT(0x0f4326896565ec65), + W64LIT(0xe30ef8fff6f609f6), W64LIT(0x8f2356c97575bc75), W64LIT(0x3812151c07071b07), W64LIT(0x20181c1004041404), + W64LIT(0x72abe23949497049), W64LIT(0x85aa99cc3333ff33), W64LIT(0x736286b7e4e453e4), W64LIT(0x86ec3543d9d99ad9), + W64LIT(0xa1b108deb9b967b9), W64LIT(0xceda0a67d0d0b7d0), W64LIT(0x2a91d31542425742), W64LIT(0x76a86f3bc7c7fcc7), + W64LIT(0x477519ad6c6cc16c), W64LIT(0xf447d77a9090ea90), W64LIT(0x0000000000000000), W64LIT(0x04038d028e8e8c8e), + W64LIT(0x5f7f10a16f6fce6f), W64LIT(0xbafdad5d50500d50), W64LIT(0x0806070401010501), W64LIT(0x66a46133c5c5f6c5), + W64LIT(0x9ee63c4fdada95da), W64LIT(0x028fc80147474647), W64LIT(0xe582bdfc3f3fc33f), W64LIT(0x26945913cdcddecd), + W64LIT(0x6f6b02b96969d069), W64LIT(0x79eb49b2a2a210a2), W64LIT(0x437694afe2e24de2), W64LIT(0xf7017bf57a7a8f7a), + W64LIT(0x51f552a6a7a701a7), W64LIT(0x7eae683fc6c6f9c6), W64LIT(0xec4dde769393e593), W64LIT(0x78222d3c0f0f330f), + W64LIT(0x503c36280a0a220a), W64LIT(0x3014121806061e06), W64LIT(0x636e88bfe6e659e6), W64LIT(0x45fad1ac2b2b872b), + W64LIT(0xc453c5629696f496), W64LIT(0x71ed4eb6a3a315a3), W64LIT(0xe04854701c1c6c1c), W64LIT(0x11c56a86afaf29af), + W64LIT(0x77610bb56a6adf6a), W64LIT(0x906c7e4812125a12), W64LIT(0x543fbb2a8484ae84), W64LIT(0xd596afe43939dd39), + W64LIT(0x6b688fbbe7e75ce7), W64LIT(0xe98737fab0b04ab0), W64LIT(0x642ba9328282b082), W64LIT(0xeb08fffbf7f70cf7), + W64LIT(0xa33ec0dffefe21fe), W64LIT(0x9c69f44e9d9dd39d), W64LIT(0x4c35b2268787a187), W64LIT(0xdad5896d5c5c315c), + W64LIT(0x7c21a03e8181bf81), W64LIT(0xb5be8bd43535e135), W64LIT(0xbefe205fdede81de), W64LIT(0xc99f2beab4b45eb4), + W64LIT(0x41f95caea5a50ba5), W64LIT(0xb332ced7fcfc2bfc), W64LIT(0x7427a73a8080ba80), W64LIT(0x2b58b79befef74ef), + W64LIT(0x16804b0bcbcbc0cb), W64LIT(0xb1bd06d6bbbb6dbb), W64LIT(0x7f670cb16b6bda6b), W64LIT(0x97295fc57676b376), + W64LIT(0xb9bb01d2baba68ba), W64LIT(0xeac19b755a5a2f5a), W64LIT(0xcf136ee97d7d947d), W64LIT(0xe70d75fd78788578), + W64LIT(0x583a312c0b0b270b), W64LIT(0xdc59cc6e9595fb95), W64LIT(0x4b7093abe3e348e3), W64LIT(0x01c9648eadad23ad), + W64LIT(0x872551cd7474b974), W64LIT(0xb477ef5a9898c298), W64LIT(0xc59aa1ec3b3bd73b), W64LIT(0xadb482d83636ee36), + W64LIT(0x0745218d6464e964), W64LIT(0x4f731ea96d6dc46d), W64LIT(0xaef22e57dcdc8bdc), W64LIT(0xd31aeae7f0f017f0), + W64LIT(0xf2cb927959592059), W64LIT(0x21d1789ea9a937a9), W64LIT(0x5ab5f92d4c4c614c), W64LIT(0xb872655c17174b17), + W64LIT(0xdf1f60e17f7f9e7f), W64LIT(0xfc41d07e9191ef91), W64LIT(0xa9b70fdab8b862b8), W64LIT(0x068c4503c9c9cac9), + W64LIT(0x82efb84157571657), W64LIT(0xd85a416c1b1b771b), W64LIT(0x537a9aa7e0e047e0), W64LIT(0x2f5b3a996161f861) + }, + { + W64LIT(0xd77f9aa8a832a829), W64LIT(0x97d4114343524322), W64LIT(0xdf80615f5f3e5fc2), W64LIT(0x14121806061e0630), + W64LIT(0x670cb16b6bda6b7f), W64LIT(0x2356c97575bc758f), W64LIT(0x7519ad6c6cc16c47), W64LIT(0xcb927959592059f2), + W64LIT(0x3b4ad97171a871af), W64LIT(0xf8275bdfdf84dfb6), W64LIT(0x35b2268787a1874c), W64LIT(0x59cc6e9595fb95dc), + W64LIT(0x72655c17174b17b8), W64LIT(0x1aeae7f0f017f0d3), W64LIT(0xea3247d8d89fd88e), W64LIT(0x363f2409092d0948), + W64LIT(0x731ea96d6dc46d4f), W64LIT(0x10e3ebf3f318f3cb), W64LIT(0x4e53741d1d691de8), W64LIT(0x804b0bcbcbc0cb16), + W64LIT(0x8c4503c9c9cac906), W64LIT(0xb3fe294d4d644d52), W64LIT(0xe8c4b02c2c9c2c7d), W64LIT(0xc56a86afaf29af11), + W64LIT(0x0b72f979798079ef), W64LIT(0x7a9aa7e0e047e053), W64LIT(0x55c2669797f197cc), W64LIT(0x34c9d3fdfd2efdbb), + W64LIT(0x7f10a16f6fce6f5f), W64LIT(0xa7ec314b4b7a4b62), W64LIT(0x83c60945454c4512), W64LIT(0x96afe43939dd39d5), + W64LIT(0x84baf83e3ec63eed), W64LIT(0xf42953dddd8edda6), W64LIT(0xed4eb6a3a315a371), W64LIT(0xbff0214f4f6e4f42), + W64LIT(0x9f2beab4b45eb4c9), W64LIT(0x9325e2b6b654b6d9), W64LIT(0x7be1529a9ac89aa4), W64LIT(0x242a380e0e360e70), + W64LIT(0x425d7c1f1f631ff8), W64LIT(0xa51ac6bfbf79bf91), W64LIT(0x7e6b5415154115a8), W64LIT(0x7c9da3e1e142e15b), + W64LIT(0xabe2394949704972), W64LIT(0xd6046fd2d2bdd2de), W64LIT(0x4dde769393e593ec), W64LIT(0xae683fc6c6f9c67e), + W64LIT(0x4bd9729292e092e4), W64LIT(0x3143d57272a772b7), W64LIT(0x63fd429e9edc9e84), W64LIT(0x5b3a996161f8612f), + W64LIT(0xdc0d63d1d1b2d1c6), W64LIT(0x5734916363f2633f), W64LIT(0x26dccffafa35fa83), W64LIT(0x5eb09feeee71ee23), + W64LIT(0x02f6f7f4f403f4f3), W64LIT(0x564f6419197d19c8), W64LIT(0xc41173d5d5a6d5e6), W64LIT(0xc9648eadad23ad01), + W64LIT(0xcd957d58582558fa), W64LIT(0xff5baaa4a40ea449), W64LIT(0xbd06d6bbbb6dbbb1), W64LIT(0xe140bea1a11fa161), + W64LIT(0xf22e57dcdc8bdcae), W64LIT(0x16e4eff2f21df2c3), W64LIT(0x2dae368383b5836c), W64LIT(0xb285dc3737eb37a5), + W64LIT(0x91d315424257422a), W64LIT(0x6286b7e4e453e473), W64LIT(0x017bf57a7a8f7af7), W64LIT(0xac9ec83232fa328d), + W64LIT(0x6ff34a9c9cd69c94), W64LIT(0x925e17ccccdbcc2e), W64LIT(0xdd7696abab3dab31), W64LIT(0xa1eb354a4a7f4a6a), + W64LIT(0x058a068f8f898f0c), W64LIT(0x7917a56e6ecb6e57), W64LIT(0x181c100404140420), W64LIT(0xd2f59c2727bb2725), + W64LIT(0xe4cab82e2e962e6d), W64LIT(0x688fbbe7e75ce76b), W64LIT(0x7694afe2e24de243), W64LIT(0xc19b755a5a2f5aea), + W64LIT(0x53c5629696f496c4), W64LIT(0x74625816164e16b0), W64LIT(0xcae98c2323af2305), W64LIT(0xfad1ac2b2b872b45), + W64LIT(0xb6742fc2c2edc25e), W64LIT(0x4326896565ec650f), W64LIT(0x492f856666e36617), W64LIT(0x222d3c0f0f330f78), + W64LIT(0xaf13cabcbc76bc89), W64LIT(0xd1789ea9a937a921), W64LIT(0x8fc8014747464702), W64LIT(0x9bda194141584132), + W64LIT(0xb88cd03434e434bd), W64LIT(0xade53d484875487a), W64LIT(0x32ced7fcfc2bfcb3), W64LIT(0x9522e6b7b751b7d1), + W64LIT(0x610bb56a6adf6a77), W64LIT(0x179f1a8888928834), W64LIT(0xf95caea5a50ba541), W64LIT(0xf7a45153530253a2), + W64LIT(0x33b5228686a48644), W64LIT(0x2cd5c3f9f93af99b), W64LIT(0xc79c715b5b2a5be2), W64LIT(0xe03b4bdbdb90db96), + W64LIT(0x90a8e03838d838dd), W64LIT(0x077cf17b7b8a7bff), W64LIT(0xb0732bc3c3e8c356), W64LIT(0x445a781e1e661ef0), + W64LIT(0xccee882222aa220d), W64LIT(0xaa99cc3333ff3385), W64LIT(0xd8fc902424b4243d), W64LIT(0xf0d8a0282888285d), + W64LIT(0xb482d83636ee36ad), W64LIT(0xa86f3bc7c7fcc776), W64LIT(0x8b39f2b2b240b2f9), W64LIT(0x9aa1ec3b3bd73bc5), + W64LIT(0x038d028e8e8c8e04), W64LIT(0x2f58c17777b6779f), W64LIT(0xbb01d2baba68bab9), W64LIT(0x04f1f3f5f506f5fb), + W64LIT(0x786c5014144414a0), W64LIT(0x65fa469f9fd99f8c), W64LIT(0x3038200808280840), W64LIT(0xe3b64955551c5592), + W64LIT(0x7de6569b9bcd9bac), W64LIT(0xb5f92d4c4c614c5a), W64LIT(0x3ec0dffefe21fea3), W64LIT(0x5d3d9d6060fd6027), + W64LIT(0xd5896d5c5c315cda), W64LIT(0xe63c4fdada95da9e), W64LIT(0x50486018187818c0), W64LIT(0x89cf05464643460a), + W64LIT(0x945913cdcddecd26), W64LIT(0x136ee97d7d947dcf), W64LIT(0xc6e7842121a52115), W64LIT(0x8737fab0b04ab0e9), + W64LIT(0x82bdfc3f3fc33fe5), W64LIT(0x5a416c1b1b771bd8), W64LIT(0x11981e898997893c), W64LIT(0x38c7dbffff24ffab), + W64LIT(0x40ab8bebeb60eb0b), W64LIT(0x3fbb2a8484ae8454), W64LIT(0x6b02b96969d0696f), W64LIT(0x9ca6e83a3ad23acd), + W64LIT(0x69f44e9d9dd39d9c), W64LIT(0xc81f7bd7d7acd7f6), W64LIT(0xd0036bd3d3b8d3d6), W64LIT(0x3d4ddd7070ad70a7), + W64LIT(0x4f28816767e6671f), W64LIT(0x9ddd1d40405d403a), W64LIT(0x992ceeb5b55bb5c1), W64LIT(0xfe205fdede81debe), + W64LIT(0xd38e695d5d345dd2), W64LIT(0xa090c03030f0309d), W64LIT(0x41d07e9191ef91fc), W64LIT(0x8130feb1b14fb1e1), + W64LIT(0x0d75fd78788578e7), W64LIT(0x6677441111551188), W64LIT(0x0607040101050108), W64LIT(0x6481b3e5e556e57b), + W64LIT(0x0000000000000000), W64LIT(0x6d05bd6868d56867), W64LIT(0x77ef5a9898c298b4), W64LIT(0xe747baa0a01aa069), + W64LIT(0xa46133c5c5f6c566), W64LIT(0x0c0e0802020a0210), W64LIT(0xf355a2a6a604a659), W64LIT(0x2551cd7474b97487), + W64LIT(0xeec3b42d2d992d75), W64LIT(0x3a312c0b0b270b58), W64LIT(0xeb49b2a2a210a279), W64LIT(0x295fc57676b37697), + W64LIT(0x8d3ef6b3b345b3f1), W64LIT(0xa31dc2bebe7cbe99), W64LIT(0x9e501fceced1ce3e), W64LIT(0xa914cebdbd73bd81), + W64LIT(0xc36d82aeae2cae19), W64LIT(0x4ca583e9e96ae91b), W64LIT(0x1b91128a8a988a24), W64LIT(0xa697c43131f53195), + W64LIT(0x4854701c1c6c1ce0), W64LIT(0x52be97ecec7bec33), W64LIT(0x1cede3f1f112f1db), W64LIT(0x71e85e9999c799bc), + W64LIT(0x5fcb6a9494fe94d4), W64LIT(0xdb7192aaaa38aa39), W64LIT(0x0ef8fff6f609f6e3), W64LIT(0xd4f2982626be262d), + W64LIT(0xe2cdbc2f2f932f65), W64LIT(0x58b79befef74ef2b), W64LIT(0x4aa287e8e86fe813), W64LIT(0x0f830a8c8c868c14), + W64LIT(0xbe8bd43535e135b5), W64LIT(0x0a090c03030f0318), W64LIT(0xc21677d4d4a3d4ee), W64LIT(0x1f60e17f7f9e7fdf), + W64LIT(0x20dbcbfbfb30fb8b), W64LIT(0x1e1b140505110528), W64LIT(0xbc7d23c1c1e2c146), W64LIT(0xd987655e5e3b5eca), + W64LIT(0x47d77a9090ea90f4), W64LIT(0xc0e0802020a0201d), W64LIT(0x8eb3f43d3dc93df5), W64LIT(0x2ba9328282b08264), + W64LIT(0x08fffbf7f70cf7eb), W64LIT(0x46ac8feaea65ea03), W64LIT(0x3c36280a0a220a50), W64LIT(0x2e23340d0d390d68), + W64LIT(0x1967e57e7e9b7ed7), W64LIT(0x2ad2c7f8f83ff893), W64LIT(0xfdad5d50500d50ba), W64LIT(0x5c46681a1a721ad0), + W64LIT(0xa26637c4c4f3c46e), W64LIT(0x12151c07071b0738), W64LIT(0xefb8415757165782), W64LIT(0xb70fdab8b862b8a9), + W64LIT(0x88b4f03c3ccc3cfd), W64LIT(0x5133956262f76237), W64LIT(0x7093abe3e348e34b), W64LIT(0x8a4207c8c8cfc80e), + W64LIT(0xcf638aacac26ac09), W64LIT(0xf1a35552520752aa), W64LIT(0x45218d6464e96407), W64LIT(0x6070401010501080), + W64LIT(0xda0a67d0d0b7d0ce), W64LIT(0xec3543d9d99ad986), W64LIT(0x6a794c13135f1398), W64LIT(0x2824300c0c3c0c60), + W64LIT(0x6c7e4812125a1290), W64LIT(0xf6dfa429298d2955), W64LIT(0xfbaa5951510851b2), W64LIT(0xb108deb9b967b9a1), + W64LIT(0x98571bcfcfd4cf36), W64LIT(0xce187fd6d6a9d6fe), W64LIT(0x3744d17373a273bf), W64LIT(0x09840e8d8d838d1c), + W64LIT(0x21a03e8181bf817c), W64LIT(0xe5b14d545419549a), W64LIT(0xba7a27c0c0e7c04e), W64LIT(0x54b993eded7eed3b), + W64LIT(0xb9f7254e4e6b4e4a), W64LIT(0x85c10d444449441a), W64LIT(0xf552a6a7a701a751), W64LIT(0xfcd6a82a2a822a4d), + W64LIT(0x39bc2e8585ab855c), W64LIT(0xdefb942525b12535), W64LIT(0x6e88bfe6e659e663), W64LIT(0x864c0fcacac5ca1e), + W64LIT(0x1569ed7c7c917cc7), W64LIT(0x1d96168b8b9d8b2c), W64LIT(0xe9bf45565613568a), W64LIT(0x27a73a8080ba8074) + }, + { + W64LIT(0x501fceced1ce3e9e), W64LIT(0x06d6bbbb6dbbb1bd), W64LIT(0xab8bebeb60eb0b40), W64LIT(0xd9729292e092e44b), + W64LIT(0xac8feaea65ea0346), W64LIT(0x4b0bcbcbc0cb1680), W64LIT(0x794c13135f13986a), W64LIT(0x7d23c1c1e2c146bc), + W64LIT(0xa583e9e96ae91b4c), W64LIT(0xa6e83a3ad23acd9c), W64LIT(0x187fd6d6a9d6fece), W64LIT(0x39f2b2b240b2f98b), + W64LIT(0x046fd2d2bdd2ded6), W64LIT(0xd77a9090ea90f447), W64LIT(0x655c17174b17b872), W64LIT(0xd2c7f8f83ff8932a), + W64LIT(0xd315424257422a91), W64LIT(0x6b5415154115a87e), W64LIT(0xbf45565613568ae9), W64LIT(0x2beab4b45eb4c99f), + W64LIT(0x26896565ec650f43), W64LIT(0x54701c1c6c1ce048), W64LIT(0x9f1a888892883417), W64LIT(0xd411434352432297), + W64LIT(0x6133c5c5f6c566a4), W64LIT(0x896d5c5c315cdad5), W64LIT(0x82d83636ee36adb4), W64LIT(0x01d2baba68bab9bb), + W64LIT(0xf1f3f5f506f5fb04), W64LIT(0xb8415757165782ef), W64LIT(0x28816767e6671f4f), W64LIT(0x840e8d8d838d1c09), + W64LIT(0x97c43131f53195a6), W64LIT(0xf8fff6f609f6e30e), W64LIT(0x218d6464e9640745), W64LIT(0x957d58582558facd), + W64LIT(0xfd429e9edc9e8463), W64LIT(0xf6f7f4f403f4f302), W64LIT(0xee882222aa220dcc), W64LIT(0x7192aaaa38aa39db), + W64LIT(0x56c97575bc758f23), W64LIT(0x2d3c0f0f330f7822), W64LIT(0x0e0802020a02100c), W64LIT(0x30feb1b14fb1e181), + W64LIT(0x275bdfdf84dfb6f8), W64LIT(0x1ea96d6dc46d4f73), W64LIT(0x44d17373a273bf37), W64LIT(0xfe294d4d644d52b3), + W64LIT(0x69ed7c7c917cc715), W64LIT(0xf2982626be262dd4), W64LIT(0xcab82e2e962e6de4), W64LIT(0xfffbf7f70cf7eb08), + W64LIT(0x3820080828084030), W64LIT(0x8e695d5d345dd2d3), W64LIT(0xc10d444449441a85), W64LIT(0xbaf83e3ec63eed84), + W64LIT(0xfa469f9fd99f8c65), W64LIT(0x6c5014144414a078), W64LIT(0x4207c8c8cfc80e8a), W64LIT(0x6d82aeae2cae19c3), + W64LIT(0xb14d545419549ae5), W64LIT(0x7040101050108060), W64LIT(0x3247d8d89fd88eea), W64LIT(0x13cabcbc76bc89af), + W64LIT(0x46681a1a721ad05c), W64LIT(0x0cb16b6bda6b7f67), W64LIT(0x02b96969d0696f6b), W64LIT(0xe3ebf3f318f3cb10), + W64LIT(0x14cebdbd73bd81a9), W64LIT(0x99cc3333ff3385aa), W64LIT(0x7696abab3dab31dd), W64LIT(0xdccffafa35fa8326), + W64LIT(0x0d63d1d1b2d1c6dc), W64LIT(0xe6569b9bcd9bac7d), W64LIT(0x05bd6868d568676d), W64LIT(0xf7254e4e6b4e4ab9), + W64LIT(0x625816164e16b074), W64LIT(0xcc6e9595fb95dc59), W64LIT(0xd07e9191ef91fc41), W64LIT(0xb09feeee71ee235e), + W64LIT(0xf92d4c4c614c5ab5), W64LIT(0x34916363f2633f57), W64LIT(0x8d028e8e8c8e0403), W64LIT(0x9c715b5b2a5be2c7), + W64LIT(0x5e17ccccdbcc2e92), W64LIT(0xb4f03c3ccc3cfd88), W64LIT(0x4f6419197d19c856), W64LIT(0x40bea1a11fa161e1), + W64LIT(0xa03e8181bf817c21), W64LIT(0xe2394949704972ab), W64LIT(0x7cf17b7b8a7bff07), W64LIT(0x3543d9d99ad986ec), + W64LIT(0x10a16f6fce6f5f7f), W64LIT(0x85dc3737eb37a5b2), W64LIT(0x3d9d6060fd60275d), W64LIT(0x4c0fcacac5ca1e86), + W64LIT(0x8fbbe7e75ce76b68), W64LIT(0xd1ac2b2b872b45fa), W64LIT(0xe53d484875487aad), W64LIT(0xc9d3fdfd2efdbb34), + W64LIT(0xc5629696f496c453), W64LIT(0xc60945454c451283), W64LIT(0xced7fcfc2bfcb332), W64LIT(0xda1941415841329b), + W64LIT(0x7e4812125a12906c), W64LIT(0x23340d0d390d682e), W64LIT(0x72f979798079ef0b), W64LIT(0x81b3e5e556e57b64), + W64LIT(0x981e898997893c11), W64LIT(0x830a8c8c868c140f), W64LIT(0x93abe3e348e34b70), W64LIT(0xe0802020a0201dc0), + W64LIT(0x90c03030f0309da0), W64LIT(0x2e57dcdc8bdcaef2), W64LIT(0x22e6b7b751b7d195), W64LIT(0x19ad6c6cc16c4775), + W64LIT(0xeb354a4a7f4a6aa1), W64LIT(0x2ceeb5b55bb5c199), W64LIT(0xbdfc3f3fc33fe582), W64LIT(0xc2669797f197cc55), + W64LIT(0x1677d4d4a3d4eec2), W64LIT(0x33956262f7623751), W64LIT(0xc3b42d2d992d75ee), W64LIT(0x121806061e063014), + W64LIT(0x5baaa4a40ea449ff), W64LIT(0x5caea5a50ba541f9), W64LIT(0xae368383b5836c2d), W64LIT(0x80615f5f3e5fc2df), + W64LIT(0xd6a82a2a822a4dfc), W64LIT(0x3c4fdada95da9ee6), W64LIT(0x4503c9c9cac9068c), W64LIT(0x0000000000000000), + W64LIT(0x67e57e7e9b7ed719), W64LIT(0x49b2a2a210a279eb), W64LIT(0xb64955551c5592e3), W64LIT(0x1ac6bfbf79bf91a5), + W64LIT(0x7744111155118866), W64LIT(0x1173d5d5a6d5e6c4), W64LIT(0xf34a9c9cd69c946f), W64LIT(0x571bcfcfd4cf3698), + W64LIT(0x2a380e0e360e7024), W64LIT(0x36280a0a220a503c), W64LIT(0xb3f43d3dc93df58e), W64LIT(0xaa5951510851b2fb), + W64LIT(0x6ee97d7d947dcf13), W64LIT(0xde769393e593ec4d), W64LIT(0x416c1b1b771bd85a), W64LIT(0xc0dffefe21fea33e), + W64LIT(0x6637c4c4f3c46ea2), W64LIT(0xc80147474647028f), W64LIT(0x3f2409092d094836), W64LIT(0xb5228686a4864433), + W64LIT(0x312c0b0b270b583a), W64LIT(0x8a068f8f898f0c05), W64LIT(0xf44e9d9dd39d9c69), W64LIT(0x0bb56a6adf6a7761), + W64LIT(0x151c07071b073812), W64LIT(0x08deb9b967b9a1b1), W64LIT(0x37fab0b04ab0e987), W64LIT(0xef5a9898c298b477), + W64LIT(0x486018187818c050), W64LIT(0x9ec83232fa328dac), W64LIT(0x4ad97171a871af3b), W64LIT(0xec314b4b7a4b62a7), + W64LIT(0xb79befef74ef2b58), W64LIT(0xa1ec3b3bd73bc59a), W64LIT(0x4ddd7070ad70a73d), W64LIT(0x47baa0a01aa069e7), + W64LIT(0x86b7e4e453e47362), W64LIT(0xdd1d40405d403a9d), W64LIT(0xc7dbffff24ffab38), W64LIT(0x732bc3c3e8c356b0), + W64LIT(0x789ea9a937a921d1), W64LIT(0x88bfe6e659e6636e), W64LIT(0x75fd78788578e70d), W64LIT(0xd5c3f9f93af99b2c), + W64LIT(0x96168b8b9d8b2c1d), W64LIT(0xcf05464643460a89), W64LIT(0xa73a8080ba807427), W64LIT(0x5a781e1e661ef044), + W64LIT(0xa8e03838d838dd90), W64LIT(0x9da3e1e142e15b7c), W64LIT(0x0fdab8b862b8a9b7), W64LIT(0x7f9aa8a832a829d7), + W64LIT(0x9aa7e0e047e0537a), W64LIT(0x24300c0c3c0c6028), W64LIT(0xe98c2323af2305ca), W64LIT(0x5fc57676b3769729), + W64LIT(0x53741d1d691de84e), W64LIT(0xfb942525b12535de), W64LIT(0xfc902424b4243dd8), W64LIT(0x1b1405051105281e), + W64LIT(0xede3f1f112f1db1c), W64LIT(0x17a56e6ecb6e5779), W64LIT(0xcb6a9494fe94d45f), W64LIT(0xd8a0282888285df0), + W64LIT(0xe1529a9ac89aa47b), W64LIT(0xbb2a8484ae84543f), W64LIT(0xa287e8e86fe8134a), W64LIT(0x4eb6a3a315a371ed), + W64LIT(0xf0214f4f6e4f42bf), W64LIT(0x58c17777b6779f2f), W64LIT(0x036bd3d3b8d3d6d0), W64LIT(0xbc2e8585ab855c39), + W64LIT(0x94afe2e24de24376), W64LIT(0xa35552520752aaf1), W64LIT(0xe4eff2f21df2c316), W64LIT(0xa9328282b082642b), + W64LIT(0xad5d50500d50bafd), W64LIT(0x7bf57a7a8f7af701), W64LIT(0xcdbc2f2f932f65e2), W64LIT(0x51cd7474b9748725), + W64LIT(0xa45153530253a2f7), W64LIT(0x3ef6b3b345b3f18d), W64LIT(0x3a996161f8612f5b), W64LIT(0x6a86afaf29af11c5), + W64LIT(0xafe43939dd39d596), W64LIT(0x8bd43535e135b5be), W64LIT(0x205fdede81debefe), W64LIT(0x5913cdcddecd2694), + W64LIT(0x5d7c1f1f631ff842), W64LIT(0xe85e9999c799bc71), W64LIT(0x638aacac26ac09cf), W64LIT(0x648eadad23ad01c9), + W64LIT(0x43d57272a772b731), W64LIT(0xc4b02c2c9c2c7de8), W64LIT(0x2953dddd8edda6f4), W64LIT(0x0a67d0d0b7d0ceda), + W64LIT(0xb2268787a1874c35), W64LIT(0x1dc2bebe7cbe99a3), W64LIT(0x87655e5e3b5ecad9), W64LIT(0x55a2a6a604a659f3), + W64LIT(0xbe97ecec7bec3352), W64LIT(0x1c10040414042018), W64LIT(0x683fc6c6f9c67eae), W64LIT(0x090c03030f03180a), + W64LIT(0x8cd03434e434bdb8), W64LIT(0xdbcbfbfb30fb8b20), W64LIT(0x3b4bdbdb90db96e0), W64LIT(0x927959592059f2cb), + W64LIT(0x25e2b6b654b6d993), W64LIT(0x742fc2c2edc25eb6), W64LIT(0x0704010105010806), W64LIT(0xeae7f0f017f0d31a), + W64LIT(0x9b755a5a2f5aeac1), W64LIT(0xb993eded7eed3b54), W64LIT(0x52a6a7a701a751f5), W64LIT(0x2f856666e3661749), + W64LIT(0xe7842121a52115c6), W64LIT(0x60e17f7f9e7fdf1f), W64LIT(0x91128a8a988a241b), W64LIT(0xf59c2727bb2725d2), + W64LIT(0x6f3bc7c7fcc776a8), W64LIT(0x7a27c0c0e7c04eba), W64LIT(0xdfa429298d2955f6), W64LIT(0x1f7bd7d7acd7f6c8) + }, + { + W64LIT(0x769393e593ec4dde), W64LIT(0x43d9d99ad986ec35), W64LIT(0x529a9ac89aa47be1), W64LIT(0xeeb5b55bb5c1992c), + W64LIT(0x5a9898c298b477ef), W64LIT(0x882222aa220dccee), W64LIT(0x0945454c451283c6), W64LIT(0xd7fcfc2bfcb332ce), + W64LIT(0xd2baba68bab9bb01), W64LIT(0xb56a6adf6a77610b), W64LIT(0x5bdfdf84dfb6f827), W64LIT(0x0802020a02100c0e), + W64LIT(0x469f9fd99f8c65fa), W64LIT(0x57dcdc8bdcaef22e), W64LIT(0x5951510851b2fbaa), W64LIT(0x7959592059f2cb92), + W64LIT(0x354a4a7f4a6aa1eb), W64LIT(0x5c17174b17b87265), W64LIT(0xac2b2b872b45fad1), W64LIT(0x2fc2c2edc25eb674), + W64LIT(0x6a9494fe94d45fcb), W64LIT(0xf7f4f403f4f302f6), W64LIT(0xd6bbbb6dbbb1bd06), W64LIT(0xb6a3a315a371ed4e), + W64LIT(0x956262f762375133), W64LIT(0xb7e4e453e4736286), W64LIT(0xd97171a871af3b4a), W64LIT(0x77d4d4a3d4eec216), + W64LIT(0x13cdcddecd269459), W64LIT(0xdd7070ad70a73d4d), W64LIT(0x5816164e16b07462), W64LIT(0xa3e1e142e15b7c9d), + W64LIT(0x394949704972abe2), W64LIT(0xf03c3ccc3cfd88b4), W64LIT(0x27c0c0e7c04eba7a), W64LIT(0x47d8d89fd88eea32), + W64LIT(0x6d5c5c315cdad589), W64LIT(0x569b9bcd9bac7de6), W64LIT(0x8eadad23ad01c964), W64LIT(0x2e8585ab855c39bc), + W64LIT(0x5153530253a2f7a4), W64LIT(0xbea1a11fa161e140), W64LIT(0xf57a7a8f7af7017b), W64LIT(0x07c8c8cfc80e8a42), + W64LIT(0xb42d2d992d75eec3), W64LIT(0xa7e0e047e0537a9a), W64LIT(0x63d1d1b2d1c6dc0d), W64LIT(0xd57272a772b73143), + W64LIT(0xa2a6a604a659f355), W64LIT(0xb02c2c9c2c7de8c4), W64LIT(0x37c4c4f3c46ea266), W64LIT(0xabe3e348e34b7093), + W64LIT(0xc57676b37697295f), W64LIT(0xfd78788578e70d75), W64LIT(0xe6b7b751b7d19522), W64LIT(0xeab4b45eb4c99f2b), + W64LIT(0x2409092d0948363f), W64LIT(0xec3b3bd73bc59aa1), W64LIT(0x380e0e360e70242a), W64LIT(0x1941415841329bda), + W64LIT(0x2d4c4c614c5ab5f9), W64LIT(0x5fdede81debefe20), W64LIT(0xf2b2b240b2f98b39), W64LIT(0x7a9090ea90f447d7), + W64LIT(0x942525b12535defb), W64LIT(0xaea5a50ba541f95c), W64LIT(0x7bd7d7acd7f6c81f), W64LIT(0x0c03030f03180a09), + W64LIT(0x4411115511886677), W64LIT(0x0000000000000000), W64LIT(0x2bc3c3e8c356b073), W64LIT(0xb82e2e962e6de4ca), + W64LIT(0x729292e092e44bd9), W64LIT(0x9befef74ef2b58b7), W64LIT(0x254e4e6b4e4ab9f7), W64LIT(0x4812125a12906c7e), + W64LIT(0x4e9d9dd39d9c69f4), W64LIT(0xe97d7d947dcf136e), W64LIT(0x0bcbcbc0cb16804b), W64LIT(0xd43535e135b5be8b), + W64LIT(0x4010105010806070), W64LIT(0x73d5d5a6d5e6c411), W64LIT(0x214f4f6e4f42bff0), W64LIT(0x429e9edc9e8463fd), + W64LIT(0x294d4d644d52b3fe), W64LIT(0x9ea9a937a921d178), W64LIT(0x4955551c5592e3b6), W64LIT(0x3fc6c6f9c67eae68), + W64LIT(0x67d0d0b7d0ceda0a), W64LIT(0xf17b7b8a7bff077c), W64LIT(0x6018187818c05048), W64LIT(0x669797f197cc55c2), + W64LIT(0x6bd3d3b8d3d6d003), W64LIT(0xd83636ee36adb482), W64LIT(0xbfe6e659e6636e88), W64LIT(0x3d484875487aade5), + W64LIT(0x45565613568ae9bf), W64LIT(0x3e8181bf817c21a0), W64LIT(0x068f8f898f0c058a), W64LIT(0xc17777b6779f2f58), + W64LIT(0x17ccccdbcc2e925e), W64LIT(0x4a9c9cd69c946ff3), W64LIT(0xdeb9b967b9a1b108), W64LIT(0xafe2e24de2437694), + W64LIT(0x8aacac26ac09cf63), W64LIT(0xdab8b862b8a9b70f), W64LIT(0xbc2f2f932f65e2cd), W64LIT(0x5415154115a87e6b), + W64LIT(0xaaa4a40ea449ff5b), W64LIT(0xed7c7c917cc71569), W64LIT(0x4fdada95da9ee63c), W64LIT(0xe03838d838dd90a8), + W64LIT(0x781e1e661ef0445a), W64LIT(0x2c0b0b270b583a31), W64LIT(0x1405051105281e1b), W64LIT(0x7fd6d6a9d6fece18), + W64LIT(0x5014144414a0786c), W64LIT(0xa56e6ecb6e577917), W64LIT(0xad6c6cc16c477519), W64LIT(0xe57e7e9b7ed71967), + W64LIT(0x856666e36617492f), W64LIT(0xd3fdfd2efdbb34c9), W64LIT(0xfeb1b14fb1e18130), W64LIT(0xb3e5e556e57b6481), + W64LIT(0x9d6060fd60275d3d), W64LIT(0x86afaf29af11c56a), W64LIT(0x655e5e3b5ecad987), W64LIT(0xcc3333ff3385aa99), + W64LIT(0x268787a1874c35b2), W64LIT(0x03c9c9cac9068c45), W64LIT(0xe7f0f017f0d31aea), W64LIT(0x695d5d345dd2d38e), + W64LIT(0xa96d6dc46d4f731e), W64LIT(0xfc3f3fc33fe582bd), W64LIT(0x1a8888928834179f), W64LIT(0x0e8d8d838d1c0984), + W64LIT(0x3bc7c7fcc776a86f), W64LIT(0xfbf7f70cf7eb08ff), W64LIT(0x741d1d691de84e53), W64LIT(0x83e9e96ae91b4ca5), + W64LIT(0x97ecec7bec3352be), W64LIT(0x93eded7eed3b54b9), W64LIT(0x3a8080ba807427a7), W64LIT(0xa429298d2955f6df), + W64LIT(0x9c2727bb2725d2f5), W64LIT(0x1bcfcfd4cf369857), W64LIT(0x5e9999c799bc71e8), W64LIT(0x9aa8a832a829d77f), + W64LIT(0x5d50500d50bafdad), W64LIT(0x3c0f0f330f78222d), W64LIT(0xdc3737eb37a5b285), W64LIT(0x902424b4243dd8fc), + W64LIT(0xa0282888285df0d8), W64LIT(0xc03030f0309da090), W64LIT(0x6e9595fb95dc59cc), W64LIT(0x6fd2d2bdd2ded604), + W64LIT(0xf83e3ec63eed84ba), W64LIT(0x715b5b2a5be2c79c), W64LIT(0x1d40405d403a9ddd), W64LIT(0x368383b5836c2dae), + W64LIT(0xf6b3b345b3f18d3e), W64LIT(0xb96969d0696f6b02), W64LIT(0x415757165782efb8), W64LIT(0x7c1f1f631ff8425d), + W64LIT(0x1c07071b07381215), W64LIT(0x701c1c6c1ce04854), W64LIT(0x128a8a988a241b91), W64LIT(0xcabcbc76bc89af13), + W64LIT(0x802020a0201dc0e0), W64LIT(0x8bebeb60eb0b40ab), W64LIT(0x1fceced1ce3e9e50), W64LIT(0x028e8e8c8e04038d), + W64LIT(0x96abab3dab31dd76), W64LIT(0x9feeee71ee235eb0), W64LIT(0xc43131f53195a697), W64LIT(0xb2a2a210a279eb49), + W64LIT(0xd17373a273bf3744), W64LIT(0xc3f9f93af99b2cd5), W64LIT(0x0fcacac5ca1e864c), W64LIT(0xe83a3ad23acd9ca6), + W64LIT(0x681a1a721ad05c46), W64LIT(0xcbfbfb30fb8b20db), W64LIT(0x340d0d390d682e23), W64LIT(0x23c1c1e2c146bc7d), + W64LIT(0xdffefe21fea33ec0), W64LIT(0xcffafa35fa8326dc), W64LIT(0xeff2f21df2c316e4), W64LIT(0xa16f6fce6f5f7f10), + W64LIT(0xcebdbd73bd81a914), W64LIT(0x629696f496c453c5), W64LIT(0x53dddd8edda6f429), W64LIT(0x11434352432297d4), + W64LIT(0x5552520752aaf1a3), W64LIT(0xe2b6b654b6d99325), W64LIT(0x2008082808403038), W64LIT(0xebf3f318f3cb10e3), + W64LIT(0x82aeae2cae19c36d), W64LIT(0xc2bebe7cbe99a31d), W64LIT(0x6419197d19c8564f), W64LIT(0x1e898997893c1198), + W64LIT(0xc83232fa328dac9e), W64LIT(0x982626be262dd4f2), W64LIT(0xfab0b04ab0e98737), W64LIT(0x8feaea65ea0346ac), + W64LIT(0x314b4b7a4b62a7ec), W64LIT(0x8d6464e964074521), W64LIT(0x2a8484ae84543fbb), W64LIT(0x328282b082642ba9), + W64LIT(0xb16b6bda6b7f670c), W64LIT(0xf3f5f506f5fb04f1), W64LIT(0xf979798079ef0b72), W64LIT(0xc6bfbf79bf91a51a), + W64LIT(0x0401010501080607), W64LIT(0x615f5f3e5fc2df80), W64LIT(0xc97575bc758f2356), W64LIT(0x916363f2633f5734), + W64LIT(0x6c1b1b771bd85a41), W64LIT(0x8c2323af2305cae9), W64LIT(0xf43d3dc93df58eb3), W64LIT(0xbd6868d568676d05), + W64LIT(0xa82a2a822a4dfcd6), W64LIT(0x896565ec650f4326), W64LIT(0x87e8e86fe8134aa2), W64LIT(0x7e9191ef91fc41d0), + W64LIT(0xfff6f609f6e30ef8), W64LIT(0xdbffff24ffab38c7), W64LIT(0x4c13135f13986a79), W64LIT(0x7d58582558facd95), + W64LIT(0xe3f1f112f1db1ced), W64LIT(0x0147474647028fc8), W64LIT(0x280a0a220a503c36), W64LIT(0xe17f7f9e7fdf1f60), + W64LIT(0x33c5c5f6c566a461), W64LIT(0xa6a7a701a751f552), W64LIT(0xbbe7e75ce76b688f), W64LIT(0x996161f8612f5b3a), + W64LIT(0x755a5a2f5aeac19b), W64LIT(0x1806061e06301412), W64LIT(0x05464643460a89cf), W64LIT(0x0d444449441a85c1), + W64LIT(0x15424257422a91d3), W64LIT(0x100404140420181c), W64LIT(0xbaa0a01aa069e747), W64LIT(0x4bdbdb90db96e03b), + W64LIT(0xe43939dd39d596af), W64LIT(0x228686a4864433b5), W64LIT(0x4d545419549ae5b1), W64LIT(0x92aaaa38aa39db71), + W64LIT(0x0a8c8c868c140f83), W64LIT(0xd03434e434bdb88c), W64LIT(0x842121a52115c6e7), W64LIT(0x168b8b9d8b2c1d96), + W64LIT(0xc7f8f83ff8932ad2), W64LIT(0x300c0c3c0c602824), W64LIT(0xcd7474b974872551), W64LIT(0x816767e6671f4f28) + }, + { + W64LIT(0x6868d568676d05bd), W64LIT(0x8d8d838d1c09840e), W64LIT(0xcacac5ca1e864c0f), W64LIT(0x4d4d644d52b3fe29), + W64LIT(0x7373a273bf3744d1), W64LIT(0x4b4b7a4b62a7ec31), W64LIT(0x4e4e6b4e4ab9f725), W64LIT(0x2a2a822a4dfcd6a8), + W64LIT(0xd4d4a3d4eec21677), W64LIT(0x52520752aaf1a355), W64LIT(0x2626be262dd4f298), W64LIT(0xb3b345b3f18d3ef6), + W64LIT(0x545419549ae5b14d), W64LIT(0x1e1e661ef0445a78), W64LIT(0x19197d19c8564f64), W64LIT(0x1f1f631ff8425d7c), + W64LIT(0x2222aa220dccee88), W64LIT(0x03030f03180a090c), W64LIT(0x464643460a89cf05), W64LIT(0x3d3dc93df58eb3f4), + W64LIT(0x2d2d992d75eec3b4), W64LIT(0x4a4a7f4a6aa1eb35), W64LIT(0x53530253a2f7a451), W64LIT(0x8383b5836c2dae36), + W64LIT(0x13135f13986a794c), W64LIT(0x8a8a988a241b9112), W64LIT(0xb7b751b7d19522e6), W64LIT(0xd5d5a6d5e6c41173), + W64LIT(0x2525b12535defb94), W64LIT(0x79798079ef0b72f9), W64LIT(0xf5f506f5fb04f1f3), W64LIT(0xbdbd73bd81a914ce), + W64LIT(0x58582558facd957d), W64LIT(0x2f2f932f65e2cdbc), W64LIT(0x0d0d390d682e2334), W64LIT(0x02020a02100c0e08), + W64LIT(0xeded7eed3b54b993), W64LIT(0x51510851b2fbaa59), W64LIT(0x9e9edc9e8463fd42), W64LIT(0x1111551188667744), + W64LIT(0xf2f21df2c316e4ef), W64LIT(0x3e3ec63eed84baf8), W64LIT(0x55551c5592e3b649), W64LIT(0x5e5e3b5ecad98765), + W64LIT(0xd1d1b2d1c6dc0d63), W64LIT(0x16164e16b0746258), W64LIT(0x3c3ccc3cfd88b4f0), W64LIT(0x6666e36617492f85), + W64LIT(0x7070ad70a73d4ddd), W64LIT(0x5d5d345dd2d38e69), W64LIT(0xf3f318f3cb10e3eb), W64LIT(0x45454c451283c609), + W64LIT(0x40405d403a9ddd1d), W64LIT(0xccccdbcc2e925e17), W64LIT(0xe8e86fe8134aa287), W64LIT(0x9494fe94d45fcb6a), + W64LIT(0x565613568ae9bf45), W64LIT(0x0808280840303820), W64LIT(0xceced1ce3e9e501f), W64LIT(0x1a1a721ad05c4668), + W64LIT(0x3a3ad23acd9ca6e8), W64LIT(0xd2d2bdd2ded6046f), W64LIT(0xe1e142e15b7c9da3), W64LIT(0xdfdf84dfb6f8275b), + W64LIT(0xb5b55bb5c1992cee), W64LIT(0x3838d838dd90a8e0), W64LIT(0x6e6ecb6e577917a5), W64LIT(0x0e0e360e70242a38), + W64LIT(0xe5e556e57b6481b3), W64LIT(0xf4f403f4f302f6f7), W64LIT(0xf9f93af99b2cd5c3), W64LIT(0x8686a4864433b522), + W64LIT(0xe9e96ae91b4ca583), W64LIT(0x4f4f6e4f42bff021), W64LIT(0xd6d6a9d6fece187f), W64LIT(0x8585ab855c39bc2e), + W64LIT(0x2323af2305cae98c), W64LIT(0xcfcfd4cf3698571b), W64LIT(0x3232fa328dac9ec8), W64LIT(0x9999c799bc71e85e), + W64LIT(0x3131f53195a697c4), W64LIT(0x14144414a0786c50), W64LIT(0xaeae2cae19c36d82), W64LIT(0xeeee71ee235eb09f), + W64LIT(0xc8c8cfc80e8a4207), W64LIT(0x484875487aade53d), W64LIT(0xd3d3b8d3d6d0036b), W64LIT(0x3030f0309da090c0), + W64LIT(0xa1a11fa161e140be), W64LIT(0x9292e092e44bd972), W64LIT(0x41415841329bda19), W64LIT(0xb1b14fb1e18130fe), + W64LIT(0x18187818c0504860), W64LIT(0xc4c4f3c46ea26637), W64LIT(0x2c2c9c2c7de8c4b0), W64LIT(0x7171a871af3b4ad9), + W64LIT(0x7272a772b73143d5), W64LIT(0x444449441a85c10d), W64LIT(0x15154115a87e6b54), W64LIT(0xfdfd2efdbb34c9d3), + W64LIT(0x3737eb37a5b285dc), W64LIT(0xbebe7cbe99a31dc2), W64LIT(0x5f5f3e5fc2df8061), W64LIT(0xaaaa38aa39db7192), + W64LIT(0x9b9bcd9bac7de656), W64LIT(0x8888928834179f1a), W64LIT(0xd8d89fd88eea3247), W64LIT(0xabab3dab31dd7696), + W64LIT(0x898997893c11981e), W64LIT(0x9c9cd69c946ff34a), W64LIT(0xfafa35fa8326dccf), W64LIT(0x6060fd60275d3d9d), + W64LIT(0xeaea65ea0346ac8f), W64LIT(0xbcbc76bc89af13ca), W64LIT(0x6262f76237513395), W64LIT(0x0c0c3c0c60282430), + W64LIT(0x2424b4243dd8fc90), W64LIT(0xa6a604a659f355a2), W64LIT(0xa8a832a829d77f9a), W64LIT(0xecec7bec3352be97), + W64LIT(0x6767e6671f4f2881), W64LIT(0x2020a0201dc0e080), W64LIT(0xdbdb90db96e03b4b), W64LIT(0x7c7c917cc71569ed), + W64LIT(0x282888285df0d8a0), W64LIT(0xdddd8edda6f42953), W64LIT(0xacac26ac09cf638a), W64LIT(0x5b5b2a5be2c79c71), + W64LIT(0x3434e434bdb88cd0), W64LIT(0x7e7e9b7ed71967e5), W64LIT(0x1010501080607040), W64LIT(0xf1f112f1db1cede3), + W64LIT(0x7b7b8a7bff077cf1), W64LIT(0x8f8f898f0c058a06), W64LIT(0x6363f2633f573491), W64LIT(0xa0a01aa069e747ba), + W64LIT(0x05051105281e1b14), W64LIT(0x9a9ac89aa47be152), W64LIT(0x434352432297d411), W64LIT(0x7777b6779f2f58c1), + W64LIT(0x2121a52115c6e784), W64LIT(0xbfbf79bf91a51ac6), W64LIT(0x2727bb2725d2f59c), W64LIT(0x09092d0948363f24), + W64LIT(0xc3c3e8c356b0732b), W64LIT(0x9f9fd99f8c65fa46), W64LIT(0xb6b654b6d99325e2), W64LIT(0xd7d7acd7f6c81f7b), + W64LIT(0x29298d2955f6dfa4), W64LIT(0xc2c2edc25eb6742f), W64LIT(0xebeb60eb0b40ab8b), W64LIT(0xc0c0e7c04eba7a27), + W64LIT(0xa4a40ea449ff5baa), W64LIT(0x8b8b9d8b2c1d9616), W64LIT(0x8c8c868c140f830a), W64LIT(0x1d1d691de84e5374), + W64LIT(0xfbfb30fb8b20dbcb), W64LIT(0xffff24ffab38c7db), W64LIT(0xc1c1e2c146bc7d23), W64LIT(0xb2b240b2f98b39f2), + W64LIT(0x9797f197cc55c266), W64LIT(0x2e2e962e6de4cab8), W64LIT(0xf8f83ff8932ad2c7), W64LIT(0x6565ec650f432689), + W64LIT(0xf6f609f6e30ef8ff), W64LIT(0x7575bc758f2356c9), W64LIT(0x07071b073812151c), W64LIT(0x0404140420181c10), + W64LIT(0x4949704972abe239), W64LIT(0x3333ff3385aa99cc), W64LIT(0xe4e453e4736286b7), W64LIT(0xd9d99ad986ec3543), + W64LIT(0xb9b967b9a1b108de), W64LIT(0xd0d0b7d0ceda0a67), W64LIT(0x424257422a91d315), W64LIT(0xc7c7fcc776a86f3b), + W64LIT(0x6c6cc16c477519ad), W64LIT(0x9090ea90f447d77a), W64LIT(0x0000000000000000), W64LIT(0x8e8e8c8e04038d02), + W64LIT(0x6f6fce6f5f7f10a1), W64LIT(0x50500d50bafdad5d), W64LIT(0x0101050108060704), W64LIT(0xc5c5f6c566a46133), + W64LIT(0xdada95da9ee63c4f), W64LIT(0x47474647028fc801), W64LIT(0x3f3fc33fe582bdfc), W64LIT(0xcdcddecd26945913), + W64LIT(0x6969d0696f6b02b9), W64LIT(0xa2a210a279eb49b2), W64LIT(0xe2e24de2437694af), W64LIT(0x7a7a8f7af7017bf5), + W64LIT(0xa7a701a751f552a6), W64LIT(0xc6c6f9c67eae683f), W64LIT(0x9393e593ec4dde76), W64LIT(0x0f0f330f78222d3c), + W64LIT(0x0a0a220a503c3628), W64LIT(0x06061e0630141218), W64LIT(0xe6e659e6636e88bf), W64LIT(0x2b2b872b45fad1ac), + W64LIT(0x9696f496c453c562), W64LIT(0xa3a315a371ed4eb6), W64LIT(0x1c1c6c1ce0485470), W64LIT(0xafaf29af11c56a86), + W64LIT(0x6a6adf6a77610bb5), W64LIT(0x12125a12906c7e48), W64LIT(0x8484ae84543fbb2a), W64LIT(0x3939dd39d596afe4), + W64LIT(0xe7e75ce76b688fbb), W64LIT(0xb0b04ab0e98737fa), W64LIT(0x8282b082642ba932), W64LIT(0xf7f70cf7eb08fffb), + W64LIT(0xfefe21fea33ec0df), W64LIT(0x9d9dd39d9c69f44e), W64LIT(0x8787a1874c35b226), W64LIT(0x5c5c315cdad5896d), + W64LIT(0x8181bf817c21a03e), W64LIT(0x3535e135b5be8bd4), W64LIT(0xdede81debefe205f), W64LIT(0xb4b45eb4c99f2bea), + W64LIT(0xa5a50ba541f95cae), W64LIT(0xfcfc2bfcb332ced7), W64LIT(0x8080ba807427a73a), W64LIT(0xefef74ef2b58b79b), + W64LIT(0xcbcbc0cb16804b0b), W64LIT(0xbbbb6dbbb1bd06d6), W64LIT(0x6b6bda6b7f670cb1), W64LIT(0x7676b37697295fc5), + W64LIT(0xbaba68bab9bb01d2), W64LIT(0x5a5a2f5aeac19b75), W64LIT(0x7d7d947dcf136ee9), W64LIT(0x78788578e70d75fd), + W64LIT(0x0b0b270b583a312c), W64LIT(0x9595fb95dc59cc6e), W64LIT(0xe3e348e34b7093ab), W64LIT(0xadad23ad01c9648e), + W64LIT(0x7474b974872551cd), W64LIT(0x9898c298b477ef5a), W64LIT(0x3b3bd73bc59aa1ec), W64LIT(0x3636ee36adb482d8), + W64LIT(0x6464e9640745218d), W64LIT(0x6d6dc46d4f731ea9), W64LIT(0xdcdc8bdcaef22e57), W64LIT(0xf0f017f0d31aeae7), + W64LIT(0x59592059f2cb9279), W64LIT(0xa9a937a921d1789e), W64LIT(0x4c4c614c5ab5f92d), W64LIT(0x17174b17b872655c), + W64LIT(0x7f7f9e7fdf1f60e1), W64LIT(0x9191ef91fc41d07e), W64LIT(0xb8b862b8a9b70fda), W64LIT(0xc9c9cac9068c4503), + W64LIT(0x5757165782efb841), W64LIT(0x1b1b771bd85a416c), W64LIT(0xe0e047e0537a9aa7), W64LIT(0x6161f8612f5b3a99) + } +}; + +const word64 IT[8][256] = +{ + { + W64LIT(0x7826942b9f5f8a9a), W64LIT(0x210f43c934970c53), W64LIT(0x5f028fdd9d0551b8), W64LIT(0x14facd82b494c83b), + W64LIT(0x2b72ab886edd68c0), W64LIT(0xa6a87e5bff19d9b4), W64LIT(0xa29ae571db6443ea), W64LIT(0x039b2c911be8e5b6), + W64LIT(0xd9275dcb5fd32cc6), W64LIT(0x10c856a890e95265), W64LIT(0x7d96e085b27ab85d), W64LIT(0x31c71561a47e5e36), + W64LIT(0x74702455f3d83978), W64LIT(0xe8e048aafbad72f0), W64LIT(0x9b39db4437e03460), W64LIT(0x75f2cbd1fa8091e1), + W64LIT(0x1ab5bee9caa336f6), W64LIT(0x8395a6b8eff34fb9), W64LIT(0x64b872fd63316b1d), W64LIT(0xe1068c7aba0ff3d5), + W64LIT(0xeecb1095cd60a581), W64LIT(0xbc1dc0b235baef42), W64LIT(0xf04c355623be0929), W64LIT(0xb252b3d94b8d118f), + W64LIT(0x18ac7dfcd8137bd9), W64LIT(0xbbb477090a2f90aa), W64LIT(0x8625d216c2d67d7e), W64LIT(0x66a1b1e871812632), + W64LIT(0x6f4775383023a717), W64LIT(0x92df1f947642b545), W64LIT(0xe962a72ef2f5da69), W64LIT(0x8bf18deca7096605), + W64LIT(0xc86de4e7c662d63a), W64LIT(0xaafece25939e6a56), W64LIT(0x5c99a34c86edb40e), W64LIT(0x52d6d027f8da4ac3), + W64LIT(0x6b75ee12145e3d49), W64LIT(0x54fd8818ce179db2), W64LIT(0xa3180af5d23ceb73), W64LIT(0xbe0403a7270aa26d), + W64LIT(0xfe03463d5d89f7e4), W64LIT(0xf1cedad22ae6a1b0), W64LIT(0xd143769f1729057a), W64LIT(0xc7a07808b10d806e), + W64LIT(0xfc1a85284f39bacb), W64LIT(0xa4b1bd4eeda9949b), W64LIT(0x0bff07c55312cc0a), W64LIT(0xef49ff11c4380d18), + W64LIT(0xc392e32295701a30), W64LIT(0x7f8f2390a0caf572), W64LIT(0x62932ac255fcbc6c), W64LIT(0xc9ef0b63cf3a7ea3), + W64LIT(0xf9aaf186621c880c), W64LIT(0x818c65adfd430296), W64LIT(0x325c39f0bf96bb80), W64LIT(0x0c56b07e6c87b3e2), + W64LIT(0x4bf8425f29919983), W64LIT(0xb5fb046274186e67), W64LIT(0x462c1da54c4e82f8), W64LIT(0x90c6dc8164f2f86a), + W64LIT(0xf8281e026b442095), W64LIT(0x6af701961d0695d0), W64LIT(0x5766a489d5ff7804), W64LIT(0xf3d719c73856ec9f), + W64LIT(0xad57799eac0b15be), W64LIT(0x1b37516dc3fb9e6f), W64LIT(0xc009cfb38e98ff86), W64LIT(0x9576a82f49d7caad), + W64LIT(0xe6af3bc1859a8c3d), W64LIT(0x208dac4d3dcfa4ca), W64LIT(0x8ddad5d391c4b174), W64LIT(0x8e41f9428a2c54c2), + W64LIT(0x6cdc59a92bcb42a1), W64LIT(0xe53417509e72698b), W64LIT(0xd0c1991b1e71ade3), W64LIT(0x8217493ce6abe720), + W64LIT(0xd4f302313a0c37bd), W64LIT(0x5e806059945df921), W64LIT(0x73d993eecc4d4690), W64LIT(0xf5fc41f80e9b3bee), + W64LIT(0x13537a398b01b7d3), W64LIT(0x53543fa3f182e25a), W64LIT(0x2d59f3b75810bfb1), W64LIT(0x35f58e4b8003c468), + W64LIT(0x886aa17dbce183b3), W64LIT(0x4c51f5e41604e66b), W64LIT(0x98a2f7d52c08d1d6), W64LIT(0xa101c9e0c08ca65c), + W64LIT(0x4007459a7a835589), W64LIT(0xcc5f7fcde21f4c64), W64LIT(0xa965e2b488768fe0), W64LIT(0x12d195bd82591f4a), + W64LIT(0x2f4030a24aa0f29e), W64LIT(0x56e44b0ddca7d09d), W64LIT(0x914433056daa50f3), W64LIT(0x37ec4d5e92b38947), + W64LIT(0xe31f4f6fa8bfbefa), W64LIT(0x50cf1332ea6a07ec), W64LIT(0x6d5eb62d2293ea38), W64LIT(0x09e6c4d041a28125), + W64LIT(0x8fc316c68374fc5b), W64LIT(0x421e868f683318a6), W64LIT(0xe08463feb3575b4c), W64LIT(0x3821d1b1e5dcdf13), + W64LIT(0xed503c04d6884037), W64LIT(0xd35ab58a05994855), W64LIT(0x976f6b3a5b678782), W64LIT(0x6ec59abc397b0f8e), + W64LIT(0x5929d7e2abc886c9), W64LIT(0xa53352cae4f13c02), W64LIT(0x89e84ef9b5b92b2a), W64LIT(0x1761e113af7c2d8d), + W64LIT(0x28e9871975358d76), W64LIT(0xdc97296572f61e01), W64LIT(0x67235e6c78d98eab), W64LIT(0x3d91a51fc8f9edd4), + W64LIT(0x68eec2830fb6d8ff), W64LIT(0xfbb3329370acc523), W64LIT(0x062b583f36cdd771), W64LIT(0x15782206bdcc60a2), + W64LIT(0x16e30e97a6248514), W64LIT(0x79a47baf96072203), W64LIT(0xf7e582ed1c2b76c1), W64LIT(0xde8eea706046532e), + W64LIT(0xaf4eba8bbebb5891), W64LIT(0x08642b5448fa29bc), W64LIT(0x24bf376719b23e94), W64LIT(0x231680dc2627417c), + W64LIT(0x0dd45ffa65df1b7b), W64LIT(0x1d1c0952f536491e), W64LIT(0xff81a9b954d15f7d), W64LIT(0x992018512550794f), + W64LIT(0x71c050fbdefd0bbf), W64LIT(0xc18b203787c0571f), W64LIT(0x253dd8e310ea960d), W64LIT(0xeb7b643be0459746), + W64LIT(0x0219c31512b04d2f), W64LIT(0xc43b5499aae565d8), W64LIT(0xeaf98bbfe91d3fdf), W64LIT(0x3a3812a4f76c923c), + W64LIT(0x4dd31a601f5c4ef2), W64LIT(0xa8e70d30812e2779), W64LIT(0x800e8a29f41baa0f), W64LIT(0x1c9ee6d6fc6ee187), + W64LIT(0x5d1b4cc88fb51c97), W64LIT(0x610806534e1459da), W64LIT(0xf255f643310e4406), W64LIT(0xd2d85a0e0cc1e0cc), + W64LIT(0x0182ef840958a899), W64LIT(0x7e0dcc14a9925deb), W64LIT(0x653a9d796a69c384), W64LIT(0x4e4836f104b4ab44), + W64LIT(0x4fcad9750dec03dd), W64LIT(0xcddd9049eb47e4fd), W64LIT(0x0e4f736b7e37fecd), W64LIT(0x4185aa1e73dbfd10), + W64LIT(0x725b7c6ac515ee09), W64LIT(0x8a736268ae51ce9c), W64LIT(0xc5b9bb1da3bdcd41), W64LIT(0x7bbdb8ba84b76f2c), + W64LIT(0xdabc715a443bc970), W64LIT(0xe29da0eba1e71663), W64LIT(0x935df0107f1a1ddc), W64LIT(0x608ae9d7474cf143), + W64LIT(0xd571edb533549f24), W64LIT(0xa0832664c9d40ec5), W64LIT(0xfd986aac46611252), W64LIT(0x4435deb05efecfd7), + W64LIT(0x0000000000000000), W64LIT(0x2cdb1c3351481728), W64LIT(0x94f447ab408f6234), W64LIT(0x45b7313457a6674e), + W64LIT(0xb82f5b9811c7751c), W64LIT(0x8c583a57989c19ed), W64LIT(0xdd15c6e17baeb698), W64LIT(0x696c2d0706ee7066), + W64LIT(0x3f88660ada49a0fb), W64LIT(0xf47eae7c07c39377), W64LIT(0x05b074ae2d2532c7), W64LIT(0xb3d05c5d42d5b916), + W64LIT(0x39a33e35ec84778a), W64LIT(0x0fcd9cef776f5654), W64LIT(0xacd5961aa553bd27), W64LIT(0x5b3014f7b978cbe6), + W64LIT(0x347761cf895b6cf1), W64LIT(0xc622978cb85528f7), W64LIT(0xb7e2c77766a82348), W64LIT(0x77eb08c4e830dcce), + W64LIT(0xb9adb41c189fdd85), W64LIT(0x114ab92c99b1fafc), W64LIT(0x26a6f4720b0273bb), W64LIT(0x1e8725c3eedeaca8), + W64LIT(0x2af0440c6785c059), W64LIT(0x04329b2a247d9a5e), W64LIT(0xd7682ea021e4d20b), W64LIT(0x7c140f01bb2210c4), + W64LIT(0x96ed84be523f2f1b), W64LIT(0xca7427f2d4d29b15), W64LIT(0x47aef22145162a61), W64LIT(0xa72a91dff641712d), + W64LIT(0x5ab2fb73b020637f), W64LIT(0xcbf6c876dd8a338c), W64LIT(0x6311c5465ca414f5), W64LIT(0x07a9b7bb3f957fe8), + W64LIT(0xe72dd4458cc224a4), W64LIT(0x9d12837b012de311), W64LIT(0x843c1103d0663051), W64LIT(0x0a7de8415a4a6493), + W64LIT(0xd6eac12428bc7a92), W64LIT(0x9c906cff08754b88), W64LIT(0x7042bf7fd7a5a326), W64LIT(0xbd9f2f363ce247db), + W64LIT(0xb66028f36ff08bd1), W64LIT(0x192e9278d14bd340), W64LIT(0x9f0b406e139dae3e), W64LIT(0x1f05ca47e7860431), + W64LIT(0x85befe87d93e98c8), W64LIT(0x439c690b616bb03f), W64LIT(0xba36988d03773833), W64LIT(0x87a73d92cb8ed5e7), + W64LIT(0xaecc550fb7e3f008), W64LIT(0xc2100ca69c28b2a9), W64LIT(0x9abb34c03eb89cf9), W64LIT(0x49e1814a3b21d4ac), + W64LIT(0xecd2d380dfd0e8ae), W64LIT(0x296b689d7c6d25ef), W64LIT(0x3c134a9bc1a1454d), W64LIT(0xcfc4535cf9f7a9d2), + W64LIT(0x557f679cc74f352b), W64LIT(0xb479ebe67d40c6fe), W64LIT(0xf6676d691573de58), W64LIT(0x9e89afea1ac506a7), + W64LIT(0xd8a5b24f568b845f), W64LIT(0x48636ece32797c35), W64LIT(0xdf0c05f4691efbb7), W64LIT(0xe4b6f8d4972ac112), + W64LIT(0xfa31dd1779f46dba), W64LIT(0xbf86ec232e520af4), W64LIT(0x3e0a898ed3110862), W64LIT(0x7a3f573e8defc7b5), + W64LIT(0x27241bf6025adb22), W64LIT(0x58ab3866a2902e50), W64LIT(0x3bbafd20fe343aa5), W64LIT(0x3045fae5ad26f6af), + W64LIT(0x2ec2df2643f85a07), W64LIT(0x22946f582f7fe9e5), W64LIT(0x366ea2da9beb21de), W64LIT(0x4a7aaddb20c9311a), + W64LIT(0xb1c99f485065f439), W64LIT(0xb04b70cc593d5ca0), W64LIT(0xab7c21a19ac6c2cf), W64LIT(0x33ded674b6ce1319), + W64LIT(0xce46bcd8f0af014b), W64LIT(0xdb3e9ede4d6361e9), W64LIT(0x7669e740e1687457), W64LIT(0x514dfcb6e332af75) + }, + { + W64LIT(0x1f4f6fa8bfbefae3), W64LIT(0xf0440c6785c0592a), W64LIT(0x1dc0b235baef42bc), W64LIT(0x22978cb85528f7c6), + W64LIT(0xcedad22ae6a1b0f1), W64LIT(0x180af5d23ceb73a3), W64LIT(0x946f582f7fe9e522), W64LIT(0xe44b0ddca7d09d56), + W64LIT(0x906cff08754b889c), W64LIT(0x9f2f363ce247dbbd), W64LIT(0xa1b1e87181263266), W64LIT(0x21d1b1e5dcdf1338), + W64LIT(0x31dd1779f46dbafa), W64LIT(0x4b70cc593d5ca0b0), W64LIT(0xd719c73856ec9ff3), W64LIT(0x8725c3eedeaca81e), + W64LIT(0x71edb533549f24d5), W64LIT(0x12837b012de3119d), W64LIT(0x3dd8e310ea960d25), W64LIT(0x29d7e2abc886c959), + W64LIT(0xb477090a2f90aabb), W64LIT(0x45fae5ad26f6af30), W64LIT(0x9ee6d6fc6ee1871c), W64LIT(0xbefe87d93e98c885), + W64LIT(0xe30e97a624851416), W64LIT(0xd6d027f8da4ac352), W64LIT(0xcc550fb7e3f008ae), W64LIT(0x5ab58a05994855d3), + W64LIT(0x806059945df9215e), W64LIT(0x82ef840958a89901), W64LIT(0x4ab92c99b1fafc11), W64LIT(0x281e026b442095f8), + W64LIT(0x62a72ef2f5da69e9), W64LIT(0x8b203787c0571fc1), W64LIT(0x4f736b7e37fecd0e), W64LIT(0xab3866a2902e5058), + W64LIT(0x6ea2da9beb21de36), W64LIT(0xf447ab408f623494), W64LIT(0x235e6c78d98eab67), W64LIT(0x11c5465ca414f563), + W64LIT(0xd31a601f5c4ef24d), W64LIT(0xa2f7d52c08d1d698), W64LIT(0x85aa1e73dbfd1041), W64LIT(0xdc59a92bcb42a16c), + W64LIT(0x59f3b75810bfb12d), W64LIT(0xe2c77766a82348b7), W64LIT(0xb9bb1da3bdcd41c5), W64LIT(0x96e085b27ab85d7d), + W64LIT(0x99a34c86edb40e5c), W64LIT(0x66a489d5ff780457), W64LIT(0x95a6b8eff34fb983), W64LIT(0x7f679cc74f352b55), + W64LIT(0x7de8415a4a64930a), W64LIT(0x9b2c911be8e5b603), W64LIT(0x4836f104b4ab444e), W64LIT(0xdb1c33514817282c), + W64LIT(0x15c6e17baeb698dd), W64LIT(0xed84be523f2f1b96), W64LIT(0xe1814a3b21d4ac49), W64LIT(0x503c04d6884037ed), + W64LIT(0x4c355623be0929f0), W64LIT(0x3b5499aae565d8c4), W64LIT(0x0a898ed31108623e), W64LIT(0xb074ae2d2532c705), + W64LIT(0x028fdd9d0551b85f), W64LIT(0xf58e4b8003c46835), W64LIT(0x3352cae4f13c02a5), W64LIT(0x6c2d0706ee706669), + W64LIT(0x7c21a19ac6c2cfab), W64LIT(0x19c31512b04d2f02), W64LIT(0xa6f4720b0273bb26), W64LIT(0x05ca47e78604311f), + W64LIT(0x46bcd8f0af014bce), W64LIT(0x1e868f683318a642), W64LIT(0x5c39f0bf96bb8032), W64LIT(0x79ebe67d40c6feb4), + W64LIT(0xff07c55312cc0a0b), W64LIT(0xaef22145162a6147), W64LIT(0xc1991b1e71ade3d0), W64LIT(0xded674b6ce131933), + W64LIT(0x7aaddb20c9311a4a), W64LIT(0x4dfcb6e332af7551), W64LIT(0x6de4e7c662d63ac8), W64LIT(0xbf376719b23e9424), + W64LIT(0x07459a7a83558940), W64LIT(0xac7dfcd8137bd918), W64LIT(0xdf1f947642b54592), W64LIT(0x17493ce6abe72082), + W64LIT(0xfc41f80e9b3beef5), W64LIT(0xe70d30812e2779a8), W64LIT(0xd993eecc4d469073), W64LIT(0x65e2b488768fe0a9), + W64LIT(0xd2d380dfd0e8aeec), W64LIT(0xe6c4d041a2812509), W64LIT(0x068c7aba0ff3d5e1), W64LIT(0x51f5e41604e66b4c), + W64LIT(0x41f9428a2c54c28e), W64LIT(0x537a398b01b7d313), W64LIT(0x782206bdcc60a215), W64LIT(0x89afea1ac506a79e), + W64LIT(0x8ae9d7474cf14360), W64LIT(0xf6c876dd8a338ccb), W64LIT(0x43769f1729057ad1), W64LIT(0x8dac4d3dcfa4ca20), + W64LIT(0xb7313457a6674e45), W64LIT(0x2018512550794f99), W64LIT(0xbb34c03eb89cf99a), W64LIT(0xbafd20fe343aa53b), + W64LIT(0x03463d5d89f7e4fe), W64LIT(0x42bf7fd7a5a32670), W64LIT(0x3f573e8defc7b57a), W64LIT(0xadb41c189fdd85b9), + W64LIT(0xcad9750dec03dd4f), W64LIT(0x0f43c934970c5321), W64LIT(0x2f5b9811c7751cb8), W64LIT(0xd85a0e0cc1e0ccd2), + W64LIT(0xe048aafbad72f0e8), W64LIT(0xf18deca70966058b), W64LIT(0xdd9049eb47e4fdcd), W64LIT(0xa87e5bff19d9b4a6), + W64LIT(0x5df0107f1a1ddc93), W64LIT(0xd195bd82591f4a12), W64LIT(0x0c05f4691efbb7df), W64LIT(0x8463feb3575b4ce0), + W64LIT(0x55f643310e4406f2), W64LIT(0xb6f8d4972ac112e4), W64LIT(0x4030a24aa0f29e2f), W64LIT(0xfd8818ce179db254), + W64LIT(0x3c1103d066305184), W64LIT(0x682ea021e4d20bd7), W64LIT(0x81a9b954d15f7dff), W64LIT(0x275dcb5fd32cc6d9), + W64LIT(0xfacd82b494c83b14), W64LIT(0x4433056daa50f391), W64LIT(0xe9871975358d7628), W64LIT(0xeac12428bc7a92d6), + W64LIT(0x1a85284f39bacbfc), W64LIT(0xf8425f299199834b), W64LIT(0x676d691573de58f6), W64LIT(0xd05c5d42d5b916b3), + W64LIT(0x8eea706046532ede), W64LIT(0xfb046274186e67b5), W64LIT(0x134a9bc1a1454d3c), W64LIT(0x57799eac0b15bead), + W64LIT(0x241bf6025adb2227), W64LIT(0x72ab886edd68c02b), W64LIT(0x9ae571db6443eaa2), W64LIT(0xc050fbdefd0bbf71), + W64LIT(0xa5b24f568b845fd8), W64LIT(0xe84ef9b5b92b2a89), W64LIT(0x6f6b3a5b67878297), W64LIT(0xc6dc8164f2f86a90), + W64LIT(0x7eae7c07c39377f4), W64LIT(0x5eb62d2293ea386d), W64LIT(0x8c65adfd43029681), W64LIT(0x2dd4458cc224a4e7), + W64LIT(0xfece25939e6a56aa), W64LIT(0xcd9cef776f56540f), W64LIT(0xa33e35ec84778a39), W64LIT(0xc2df2643f85a072e), + W64LIT(0xbc715a443bc970da), W64LIT(0xa07808b10d806ec7), W64LIT(0x36988d03773833ba), W64LIT(0x1680dc2627417c23), + W64LIT(0xcb1095cd60a581ee), W64LIT(0xbdb8ba84b76f2c7b), W64LIT(0x702455f3d8397874), W64LIT(0x35deb05efecfd744), + W64LIT(0x8f2390a0caf5727f), W64LIT(0xb1bd4eeda9949ba4), W64LIT(0x39db4437e034609b), W64LIT(0xe582ed1c2b76c1f7), + W64LIT(0xc4535cf9f7a9d2cf), W64LIT(0xb2fb73b020637f5a), W64LIT(0x583a57989c19ed8c), W64LIT(0x25d216c2d67d7e86), + W64LIT(0x0806534e1459da61), W64LIT(0x6b689d7c6d25ef29), W64LIT(0x0dcc14a9925deb7e), W64LIT(0xc99f485065f439b1), + W64LIT(0xa9b7bb3f957fe807), W64LIT(0x2a91dff641712da7), W64LIT(0x1c0952f536491e1d), W64LIT(0x75ee12145e3d496b), + W64LIT(0xf98bbfe91d3fdfea), W64LIT(0x92e32295701a30c3), W64LIT(0x3e9ede4d6361e9db), W64LIT(0x76a82f49d7caad95), + W64LIT(0x9da0eba1e71663e2), W64LIT(0x09cfb38e98ff86c0), W64LIT(0x9c690b616bb03f43), W64LIT(0xdad5d391c4b1748d), + W64LIT(0x3812a4f76c923c3a), W64LIT(0x5f7fcde21f4c64cc), W64LIT(0x6aa17dbce183b388), W64LIT(0xeec2830fb6d8ff68), + W64LIT(0x736268ae51ce9c8a), W64LIT(0xa47baf9607220379), W64LIT(0x543fa3f182e25a53), W64LIT(0x4eba8bbebb5891af), + W64LIT(0x2e9278d14bd34019), W64LIT(0x69e740e168745776), W64LIT(0x37516dc3fb9e6f1b), W64LIT(0xb3329370acc523fb), + W64LIT(0x3a9d796a69c38465), W64LIT(0x7761cf895b6cf134), W64LIT(0x0000000000000000), W64LIT(0x88660ada49a0fb3f), + W64LIT(0xb5bee9caa336f61a), W64LIT(0x5b7c6ac515ee0972), W64LIT(0x52b3d94b8d118fb2), W64LIT(0x329b2a247d9a5e04), + W64LIT(0x0e8a29f41baa0f80), W64LIT(0x642b5448fa29bc08), W64LIT(0x7b643be0459746eb), W64LIT(0xd45ffa65df1b7b0d), + W64LIT(0xeb08c4e830dcce77), W64LIT(0xf2cbd1fa8091e175), W64LIT(0xf302313a0c37bdd4), W64LIT(0x91a51fc8f9edd43d), + W64LIT(0xef0b63cf3a7ea3c9), W64LIT(0xc316c68374fc5b8f), W64LIT(0x01c9e0c08ca65ca1), W64LIT(0x3417509e72698be5), + W64LIT(0x4775383023a7176f), W64LIT(0x636ece32797c3548), W64LIT(0x1b4cc88fb51c975d), W64LIT(0x140f01bb2210c47c), + W64LIT(0x7427f2d4d29b15ca), W64LIT(0xa73d92cb8ed5e787), W64LIT(0xc71561a47e5e3631), W64LIT(0xaaf186621c880cf9), + W64LIT(0x6028f36ff08bd1b6), W64LIT(0x97296572f61e01dc), W64LIT(0xc59abc397b0f8e6e), W64LIT(0xec4d5e92b3894737), + W64LIT(0xb872fd63316b1d64), W64LIT(0xaf3bc1859a8c3de6), W64LIT(0x0403a7270aa26dbe), W64LIT(0x26942b9f5f8a9a78), + W64LIT(0x86ec232e520af4bf), W64LIT(0x49ff11c4380d18ef), W64LIT(0xf701961d0695d06a), W64LIT(0x56b07e6c87b3e20c), + W64LIT(0xd5961aa553bd27ac), W64LIT(0x61e113af7c2d8d17), W64LIT(0x100ca69c28b2a9c2), W64LIT(0xcf1332ea6a07ec50), + W64LIT(0xc856a890e9526510), W64LIT(0x2b583f36cdd77106), W64LIT(0x932ac255fcbc6c62), W64LIT(0x0b406e139dae3e9f), + W64LIT(0x832664c9d40ec5a0), W64LIT(0x3014f7b978cbe65b), W64LIT(0x2c1da54c4e82f846), W64LIT(0x986aac46611252fd) + }, + { + W64LIT(0x679cc74f352b557f), W64LIT(0x376719b23e9424bf), W64LIT(0xcc14a9925deb7e0d), W64LIT(0xb07e6c87b3e20c56), + W64LIT(0xa17dbce183b3886a), W64LIT(0xee12145e3d496b75), W64LIT(0x406e139dae3e9f0b), W64LIT(0x942b9f5f8a9a7826), + W64LIT(0xb24f568b845fd8a5), W64LIT(0xdf2643f85a072ec2), W64LIT(0x8c7aba0ff3d5e106), W64LIT(0x0b63cf3a7ea3c9ef), + W64LIT(0x12a4f76c923c3a38), W64LIT(0x8bbfe91d3fdfeaf9), W64LIT(0x9278d14bd340192e), W64LIT(0xca47e78604311f05), + W64LIT(0x07c55312cc0a0bff), W64LIT(0xcfb38e98ff86c009), W64LIT(0x991b1e71ade3d0c1), W64LIT(0x16c68374fc5b8fc3), + W64LIT(0x39f0bf96bb80325c), W64LIT(0x3d92cb8ed5e787a7), W64LIT(0xac4d3dcfa4ca208d), W64LIT(0xfae5ad26f6af3045), + W64LIT(0x63feb3575b4ce084), W64LIT(0x28f36ff08bd1b660), W64LIT(0xc6e17baeb698dd15), W64LIT(0x84be523f2f1b96ed), + W64LIT(0x3c04d6884037ed50), W64LIT(0xce25939e6a56aafe), W64LIT(0xa34c86edb40e5c99), W64LIT(0xebe67d40c6feb479), + W64LIT(0x27f2d4d29b15ca74), W64LIT(0x6d691573de58f667), W64LIT(0x329370acc523fbb3), W64LIT(0x2c911be8e5b6039b), + W64LIT(0x871975358d7628e9), W64LIT(0x550fb7e3f008aecc), W64LIT(0x7e5bff19d9b4a6a8), W64LIT(0xf8d4972ac112e4b6), + W64LIT(0xd1b1e5dcdf133821), W64LIT(0xfcb6e332af75514d), W64LIT(0x1e026b442095f828), W64LIT(0x1f947642b54592df), + W64LIT(0x5e6c78d98eab6723), W64LIT(0x17509e72698be534), W64LIT(0x2ac255fcbc6c6293), W64LIT(0x95bd82591f4a12d1), + W64LIT(0x799eac0b15bead57), W64LIT(0xf0107f1a1ddc935d), W64LIT(0xd674b6ce131933de), W64LIT(0xf5e41604e66b4c51), + W64LIT(0x8818ce179db254fd), W64LIT(0x03a7270aa26dbe04), W64LIT(0x1c33514817282cdb), W64LIT(0x2f363ce247dbbd9f), + W64LIT(0xa72ef2f5da69e962), W64LIT(0x93eecc4d469073d9), W64LIT(0xb92c99b1fafc114a), W64LIT(0x77090a2f90aabbb4), + W64LIT(0x0ca69c28b2a9c210), W64LIT(0xc9e0c08ca65ca101), W64LIT(0x4b0ddca7d09d56e4), W64LIT(0x988d03773833ba36), + W64LIT(0x06534e1459da6108), W64LIT(0x3a57989c19ed8c58), W64LIT(0x0952f536491e1d1c), W64LIT(0x0af5d23ceb73a318), + W64LIT(0x0d30812e2779a8e7), W64LIT(0xd7e2abc886c95929), W64LIT(0xa51fc8f9edd43d91), W64LIT(0x690b616bb03f439c), + W64LIT(0x516dc3fb9e6f1b37), W64LIT(0xa489d5ff78045766), W64LIT(0x52cae4f13c02a533), W64LIT(0x4cc88fb51c975d1b), + W64LIT(0x459a7a8355894007), W64LIT(0x9d796a69c384653a), W64LIT(0x313457a6674e45b7), W64LIT(0x4a9bc1a1454d3c13), + W64LIT(0x6268ae51ce9c8a73), W64LIT(0xfe87d93e98c885be), W64LIT(0xff11c4380d18ef49), W64LIT(0x8deca70966058bf1), + W64LIT(0xdeb05efecfd74435), W64LIT(0xd027f8da4ac352d6), W64LIT(0xf186621c880cf9aa), W64LIT(0x43c934970c53210f), + W64LIT(0xbee9caa336f61ab5), W64LIT(0x56a890e9526510c8), W64LIT(0xe8415a4a64930a7d), W64LIT(0xe32295701a30c392), + W64LIT(0x3e35ec84778a39a3), W64LIT(0x4f6fa8bfbefae31f), W64LIT(0x5dcb5fd32cc6d927), W64LIT(0x9f485065f439b1c9), + W64LIT(0x1095cd60a581eecb), W64LIT(0x978cb85528f7c622), W64LIT(0x7baf9607220379a4), W64LIT(0xd216c2d67d7e8625), + W64LIT(0xe4e7c662d63ac86d), W64LIT(0xb62d2293ea386d5e), W64LIT(0x8a29f41baa0f800e), W64LIT(0x5ffa65df1b7b0dd4), + W64LIT(0x61cf895b6cf13477), W64LIT(0xa6b8eff34fb98395), W64LIT(0x814a3b21d4ac49e1), W64LIT(0xaddb20c9311a4a7a), + W64LIT(0x74ae2d2532c705b0), W64LIT(0x30a24aa0f29e2f40), W64LIT(0x91dff641712da72a), W64LIT(0x9049eb47e4fdcddd), + W64LIT(0x493ce6abe7208217), W64LIT(0x36f104b4ab444e48), W64LIT(0xf22145162a6147ae), W64LIT(0x5c5d42d5b916b3d0), + W64LIT(0xf7d52c08d1d698a2), W64LIT(0x7a398b01b7d31353), W64LIT(0x6cff08754b889c90), W64LIT(0x14f7b978cbe65b30), + W64LIT(0xc4d041a2812509e6), W64LIT(0xe085b27ab85d7d96), W64LIT(0xc0b235baef42bc1d), W64LIT(0x868f683318a6421e), + W64LIT(0xea706046532ede8e), W64LIT(0x4ef9b5b92b2a89e8), W64LIT(0xdc8164f2f86a90c6), W64LIT(0x2455f3d839787470), + W64LIT(0x5499aae565d8c43b), W64LIT(0x59a92bcb42a16cdc), W64LIT(0xa9b954d15f7dff81), W64LIT(0xae7c07c39377f47e), + W64LIT(0x01961d0695d06af7), W64LIT(0xdb4437e034609b39), W64LIT(0x3bc1859a8c3de6af), W64LIT(0xaa1e73dbfd104185), + W64LIT(0x7dfcd8137bd918ac), W64LIT(0x80dc2627417c2316), W64LIT(0xd9750dec03dd4fca), W64LIT(0xc5465ca414f56311), + W64LIT(0x203787c0571fc18b), W64LIT(0xd5d391c4b1748dda), W64LIT(0xc2830fb6d8ff68ee), W64LIT(0xbcd8f0af014bce46), + W64LIT(0xa0eba1e71663e29d), W64LIT(0xfb73b020637f5ab2), W64LIT(0x7c6ac515ee09725b), W64LIT(0x0000000000000000), + W64LIT(0xc876dd8a338ccbf6), W64LIT(0x9cef776f56540fcd), W64LIT(0x47ab408f623494f4), W64LIT(0xcbd1fa8091e175f2), + W64LIT(0x9abc397b0f8e6ec5), W64LIT(0xb58a05994855d35a), W64LIT(0x4d5e92b3894737ec), W64LIT(0x961aa553bd27acd5), + W64LIT(0xc31512b04d2f0219), W64LIT(0xe6d6fc6ee1871c9e), W64LIT(0xe2b488768fe0a965), W64LIT(0xb3d94b8d118fb252), + W64LIT(0x440c6785c0592af0), W64LIT(0x25c3eedeaca81e87), W64LIT(0x583f36cdd771062b), W64LIT(0x2d0706ee7066696c), + W64LIT(0x425f299199834bf8), W64LIT(0xfd20fe343aa53bba), W64LIT(0xf643310e4406f255), W64LIT(0xdad22ae6a1b0f1ce), + W64LIT(0x1da54c4e82f8462c), W64LIT(0x355623be0929f04c), W64LIT(0x769f1729057ad143), W64LIT(0xbd4eeda9949ba4b1), + W64LIT(0xd8e310ea960d253d), W64LIT(0x736b7e37fecd0e4f), W64LIT(0x65adfd430296818c), W64LIT(0xb8ba84b76f2c7bbd), + W64LIT(0x9b2a247d9a5e0432), W64LIT(0xc77766a82348b7e2), W64LIT(0x08c4e830dcce77eb), W64LIT(0x0e97a624851416e3), + W64LIT(0x898ed31108623e0a), W64LIT(0xe571db6443eaa29a), W64LIT(0x573e8defc7b57a3f), W64LIT(0x21a19ac6c2cfab7c), + W64LIT(0x70cc593d5ca0b04b), W64LIT(0x2664c9d40ec5a083), W64LIT(0x296572f61e01dc97), W64LIT(0x85284f39bacbfc1a), + W64LIT(0x715a443bc970dabc), W64LIT(0xef840958a8990182), W64LIT(0xcd82b494c83b14fa), W64LIT(0x48aafbad72f0e8e0), + W64LIT(0xe9d7474cf143608a), W64LIT(0x2390a0caf5727f8f), W64LIT(0xb7bb3f957fe807a9), W64LIT(0x82ed1c2b76c1f7e5), + W64LIT(0xbb1da3bdcd41c5b9), W64LIT(0x72fd63316b1d64b8), W64LIT(0x7808b10d806ec7a0), W64LIT(0x837b012de3119d12), + W64LIT(0x689d7c6d25ef296b), W64LIT(0x02313a0c37bdd4f3), W64LIT(0x1103d0663051843c), W64LIT(0xab886edd68c02b72), + W64LIT(0x6b3a5b678782976f), W64LIT(0xe113af7c2d8d1761), W64LIT(0x6aac46611252fd98), W64LIT(0x50fbdefd0bbf71c0), + W64LIT(0x2ea021e4d20bd768), W64LIT(0x5a0e0cc1e0ccd2d8), W64LIT(0x34c03eb89cf99abb), W64LIT(0xb41c189fdd85b9ad), + W64LIT(0x9ede4d6361e9db3e), W64LIT(0xafea1ac506a79e89), W64LIT(0x463d5d89f7e4fe03), W64LIT(0x18512550794f9920), + W64LIT(0x41f80e9b3beef5fc), W64LIT(0xa82f49d7caad9576), W64LIT(0x0f01bb2210c47c14), W64LIT(0xec232e520af4bf86), + W64LIT(0x1bf6025adb222724), W64LIT(0xa2da9beb21de366e), W64LIT(0xedb533549f24d571), W64LIT(0x643be0459746eb7b), + W64LIT(0xbf7fd7a5a3267042), W64LIT(0x046274186e67b5fb), W64LIT(0x8e4b8003c46835f5), W64LIT(0x1332ea6a07ec50cf), + W64LIT(0xd380dfd0e8aeecd2), W64LIT(0x6f582f7fe9e52294), W64LIT(0xf9428a2c54c28e41), W64LIT(0x3fa3f182e25a5354), + W64LIT(0x535cf9f7a9d2cfc4), W64LIT(0x660ada49a0fb3f88), W64LIT(0x33056daa50f39144), W64LIT(0x8fdd9d0551b85f02), + W64LIT(0x19c73856ec9ff3d7), W64LIT(0xb1e87181263266a1), W64LIT(0x1561a47e5e3631c7), W64LIT(0xd4458cc224a4e72d), + W64LIT(0xe740e16874577669), W64LIT(0xc12428bc7a92d6ea), W64LIT(0x3866a2902e5058ab), W64LIT(0x1a601f5c4ef24dd3), + W64LIT(0x6059945df9215e80), W64LIT(0x05f4691efbb7df0c), W64LIT(0x5b9811c7751cb82f), W64LIT(0x2b5448fa29bc0864), + W64LIT(0xba8bbebb5891af4e), W64LIT(0xf4720b0273bb26a6), W64LIT(0xdd1779f46dbafa31), W64LIT(0x6ece32797c354863), + W64LIT(0x7fcde21f4c64cc5f), W64LIT(0x2206bdcc60a21578), W64LIT(0x75383023a7176f47), W64LIT(0xf3b75810bfb12d59) + }, + { + W64LIT(0x03d0663051843c11), W64LIT(0xbfe91d3fdfeaf98b), W64LIT(0xf80e9b3beef5fc41), W64LIT(0xe5ad26f6af3045fa), + W64LIT(0x5a443bc970dabc71), W64LIT(0x7b012de3119d1283), W64LIT(0x82b494c83b14facd), W64LIT(0x750dec03dd4fcad9), + W64LIT(0x090a2f90aabbb477), W64LIT(0xb6e332af75514dfc), W64LIT(0xadfd430296818c65), W64LIT(0xfd63316b1d64b872), + W64LIT(0x3d5d89f7e4fe0346), W64LIT(0xd7474cf143608ae9), W64LIT(0x7e6c87b3e20c56b0), W64LIT(0x601f5c4ef24dd31a), + W64LIT(0x40e16874577669e7), W64LIT(0x4437e034609b39db), W64LIT(0xe7c662d63ac86de4), W64LIT(0xaf9607220379a47b), + W64LIT(0xea1ac506a79e89af), W64LIT(0xd8f0af014bce46bc), W64LIT(0x7fd7a5a3267042bf), W64LIT(0x9f1729057ad14376), + W64LIT(0x1c189fdd85b9adb4), W64LIT(0x87d93e98c885befe), W64LIT(0x57989c19ed8c583a), W64LIT(0xa4f76c923c3a3812), + W64LIT(0x2a247d9a5e04329b), W64LIT(0xc03eb89cf99abb34), W64LIT(0xf6025adb2227241b), W64LIT(0xa890e9526510c856), + W64LIT(0x06bdcc60a2157822), W64LIT(0xc73856ec9ff3d719), W64LIT(0xcae4f13c02a53352), W64LIT(0xd6fc6ee1871c9ee6), + W64LIT(0xf0bf96bb80325c39), W64LIT(0x13af7c2d8d1761e1), W64LIT(0x3be0459746eb7b64), W64LIT(0x99aae565d8c43b54), + W64LIT(0x95cd60a581eecb10), W64LIT(0x68ae51ce9c8a7362), W64LIT(0xcde21f4c64cc5f7f), W64LIT(0xdc2627417c231680), + W64LIT(0x428a2c54c28e41f9), W64LIT(0x76dd8a338ccbf6c8), W64LIT(0xb8eff34fb98395a6), W64LIT(0xa69c28b2a9c2100c), + W64LIT(0x08b10d806ec7a078), W64LIT(0xc55312cc0a0bff07), W64LIT(0x886edd68c02b72ab), W64LIT(0xdd9d0551b85f028f), + W64LIT(0x1e73dbfd104185aa), W64LIT(0x911be8e5b6039b2c), W64LIT(0x30812e2779a8e70d), W64LIT(0x3a5b678782976f6b), + W64LIT(0x20fe343aa53bbafd), W64LIT(0xb954d15f7dff81a9), W64LIT(0x9a7a835589400745), W64LIT(0x1fc8f9edd43d91a5), + W64LIT(0x0e0cc1e0ccd2d85a), W64LIT(0xbb3f957fe807a9b7), W64LIT(0xc3eedeaca81e8725), W64LIT(0x66a2902e5058ab38), + W64LIT(0xff08754b889c906c), W64LIT(0xfeb3575b4ce08463), W64LIT(0x107f1a1ddc935df0), W64LIT(0x25939e6a56aafece), + W64LIT(0xa92bcb42a16cdc59), W64LIT(0x32ea6a07ec50cf13), W64LIT(0x947642b54592df1f), W64LIT(0x1779f46dbafa31dd), + W64LIT(0x5623be0929f04c35), W64LIT(0xf2d4d29b15ca7427), W64LIT(0x59945df9215e8060), W64LIT(0x9370acc523fbb332), + W64LIT(0xb05efecfd74435de), W64LIT(0x71db6443eaa29ae5), W64LIT(0xe2abc886c95929d7), W64LIT(0x458cc224a4e72dd4), + W64LIT(0xce32797c3548636e), W64LIT(0x1aa553bd27acd596), W64LIT(0x4a3b21d4ac49e181), W64LIT(0x284f39bacbfc1a85), + W64LIT(0xd94b8d118fb252b3), W64LIT(0xb235baef42bc1dc0), W64LIT(0x2643f85a072ec2df), W64LIT(0x8bbebb5891af4eba), + W64LIT(0x89d5ff78045766a4), W64LIT(0xeecc4d469073d993), W64LIT(0x0b616bb03f439c69), W64LIT(0xe41604e66b4c51f5), + W64LIT(0x16c2d67d7e8625d2), W64LIT(0x6c78d98eab67235e), W64LIT(0x9d7c6d25ef296b68), W64LIT(0x64c9d40ec5a08326), + W64LIT(0x2ef2f5da69e962a7), W64LIT(0xfa65df1b7b0dd45f), W64LIT(0x12145e3d496b75ee), W64LIT(0xfcd8137bd918ac7d), + W64LIT(0x52f536491e1d1c09), W64LIT(0xe67d40c6feb479eb), W64LIT(0x2145162a6147aef2), W64LIT(0x29f41baa0f800e8a), + W64LIT(0x0000000000000000), W64LIT(0x840958a8990182ef), W64LIT(0xc88fb51c975d1b4c), W64LIT(0xc68374fc5b8fc316), + W64LIT(0x5d42d5b916b3d05c), W64LIT(0x7dbce183b3886aa1), W64LIT(0x512550794f992018), W64LIT(0xe17baeb698dd15c6), + W64LIT(0x43310e4406f255f6), W64LIT(0x6dc3fb9e6f1b3751), W64LIT(0x86621c880cf9aaf1), W64LIT(0xbc397b0f8e6ec59a), + W64LIT(0x415a4a64930a7de8), W64LIT(0x04d6884037ed503c), W64LIT(0xe9caa336f61ab5be), W64LIT(0x0ada49a0fb3f8866), + W64LIT(0x55f3d83978747024), W64LIT(0x3ce6abe720821749), W64LIT(0xf5d23ceb73a3180a), W64LIT(0xa24aa0f29e2f4030), + W64LIT(0x582f7fe9e522946f), W64LIT(0x7aba0ff3d5e1068c), W64LIT(0x313a0c37bdd4f302), W64LIT(0x3787c0571fc18b20), + W64LIT(0x5cf9f7a9d2cfc453), W64LIT(0xbe523f2f1b96ed84), W64LIT(0x85b27ab85d7d96e0), W64LIT(0x0706ee7066696c2d), + W64LIT(0x961d0695d06af701), W64LIT(0x1b1e71ade3d0c199), W64LIT(0xc255fcbc6c62932a), W64LIT(0x398b01b7d313537a), + W64LIT(0xcc593d5ca0b04b70), W64LIT(0x5f299199834bf842), W64LIT(0x80dfd0e8aeecd2d3), W64LIT(0x9eac0b15bead5779), + W64LIT(0xef776f56540fcd9c), W64LIT(0x2f49d7caad9576a8), W64LIT(0x2c99b1fafc114ab9), W64LIT(0x8d03773833ba3698), + W64LIT(0x720b0273bb26a6f4), W64LIT(0x18ce179db254fd88), W64LIT(0x8f683318a6421e86), W64LIT(0x4f568b845fd8a5b2), + W64LIT(0x8ed31108623e0a89), W64LIT(0xd22ae6a1b0f1ceda), W64LIT(0x74b6ce131933ded6), W64LIT(0x97a624851416e30e), + W64LIT(0x6e139dae3e9f0b40), W64LIT(0xa7270aa26dbe0403), W64LIT(0x5448fa29bc08642b), W64LIT(0xe310ea960d253dd8), + W64LIT(0x706046532ede8eea), W64LIT(0x485065f439b1c99f), W64LIT(0x6b7e37fecd0e4f73), W64LIT(0xfbdefd0bbf71c050), + W64LIT(0xd391c4b1748ddad5), W64LIT(0xa021e4d20bd7682e), W64LIT(0xab408f623494f447), W64LIT(0x5bff19d9b4a6a87e), + W64LIT(0xb1e5dcdf133821d1), W64LIT(0x026b442095f8281e), W64LIT(0xdff641712da72a91), W64LIT(0x11c4380d18ef49ff), + W64LIT(0xae2d2532c705b074), W64LIT(0xc1859a8c3de6af3b), W64LIT(0x4b8003c46835f58e), W64LIT(0x92cb8ed5e787a73d), + W64LIT(0xcb5fd32cc6d9275d), W64LIT(0x8cb85528f7c62297), W64LIT(0x9bc1a1454d3c134a), W64LIT(0x056daa50f3914433), + W64LIT(0xf4691efbb7df0c05), W64LIT(0xd1fa8091e175f2cb), W64LIT(0x7c07c39377f47eae), W64LIT(0x14a9925deb7e0dcc), + W64LIT(0xcf895b6cf1347761), W64LIT(0x0fb7e3f008aecc55), W64LIT(0x8a05994855d35ab5), W64LIT(0xf104b4ab444e4836), + W64LIT(0x691573de58f6676d), W64LIT(0x4eeda9949ba4b1bd), W64LIT(0x2428bc7a92d6eac1), W64LIT(0xb75810bfb12d59f3), + W64LIT(0x63cf3a7ea3c9ef0b), W64LIT(0x6274186e67b5fb04), W64LIT(0x1512b04d2f0219c3), W64LIT(0xe87181263266a1b1), + W64LIT(0x1975358d7628e987), W64LIT(0x534e1459da610806), W64LIT(0x47e78604311f05ca), W64LIT(0xd4972ac112e4b6f8), + W64LIT(0x33514817282cdb1c), W64LIT(0x90a0caf5727f8f23), W64LIT(0x3e8defc7b57a3f57), W64LIT(0x3f36cdd771062b58), + W64LIT(0x796a69c384653a9d), W64LIT(0x465ca414f56311c5), W64LIT(0x5e92b3894737ec4d), W64LIT(0x9811c7751cb82f5b), + W64LIT(0xd041a2812509e6c4), W64LIT(0x49eb47e4fdcddd90), W64LIT(0x78d14bd340192e92), W64LIT(0xf9b5b92b2a89e84e), + W64LIT(0x61a47e5e3631c715), W64LIT(0x509e72698be53417), W64LIT(0xb533549f24d571ed), W64LIT(0x27f8da4ac352d6d0), + W64LIT(0x6572f61e01dc9729), W64LIT(0xde4d6361e9db3e9e), W64LIT(0x3457a6674e45b731), W64LIT(0xa54c4e82f8462c1d), + W64LIT(0xbd82591f4a12d195), W64LIT(0x830fb6d8ff68eec2), W64LIT(0x383023a7176f4775), W64LIT(0x7766a82348b7e2c7), + W64LIT(0x0c6785c0592af044), W64LIT(0xba84b76f2c7bbdb8), W64LIT(0xe0c08ca65ca101c9), W64LIT(0xeba1e71663e29da0), + W64LIT(0xd52c08d1d698a2f7), W64LIT(0xc4e830dcce77eb08), W64LIT(0xda9beb21de366ea2), W64LIT(0xa3f182e25a53543f), + W64LIT(0xac46611252fd986a), W64LIT(0xb38e98ff86c009cf), W64LIT(0xf36ff08bd1b66028), W64LIT(0xdb20c9311a4a7aad), + W64LIT(0xa19ac6c2cfab7c21), W64LIT(0x6ac515ee09725b7c), W64LIT(0x4c86edb40e5c99a3), W64LIT(0x363ce247dbbd9f2f), + W64LIT(0x8164f2f86a90c6dc), W64LIT(0x35ec84778a39a33e), W64LIT(0xb488768fe0a965e2), W64LIT(0x73b020637f5ab2fb), + W64LIT(0x232e520af4bf86ec), W64LIT(0x6fa8bfbefae31f4f), W64LIT(0xeca70966058bf18d), W64LIT(0x1da3bdcd41c5b9bb), + W64LIT(0x9cc74f352b557f67), W64LIT(0x4d3dcfa4ca208dac), W64LIT(0x2b9f5f8a9a782694), W64LIT(0xaafbad72f0e8e048), + W64LIT(0xc934970c53210f43), W64LIT(0xed1c2b76c1f7e582), W64LIT(0x01bb2210c47c140f), W64LIT(0x0ddca7d09d56e44b), + W64LIT(0x2d2293ea386d5eb6), W64LIT(0xf7b978cbe65b3014), W64LIT(0x6719b23e9424bf37), W64LIT(0x2295701a30c392e3) + }, + { + W64LIT(0x9f5f8a9a7826942b), W64LIT(0x34970c53210f43c9), W64LIT(0x9d0551b85f028fdd), W64LIT(0xb494c83b14facd82), + W64LIT(0x6edd68c02b72ab88), W64LIT(0xff19d9b4a6a87e5b), W64LIT(0xdb6443eaa29ae571), W64LIT(0x1be8e5b6039b2c91), + W64LIT(0x5fd32cc6d9275dcb), W64LIT(0x90e9526510c856a8), W64LIT(0xb27ab85d7d96e085), W64LIT(0xa47e5e3631c71561), + W64LIT(0xf3d8397874702455), W64LIT(0xfbad72f0e8e048aa), W64LIT(0x37e034609b39db44), W64LIT(0xfa8091e175f2cbd1), + W64LIT(0xcaa336f61ab5bee9), W64LIT(0xeff34fb98395a6b8), W64LIT(0x63316b1d64b872fd), W64LIT(0xba0ff3d5e1068c7a), + W64LIT(0xcd60a581eecb1095), W64LIT(0x35baef42bc1dc0b2), W64LIT(0x23be0929f04c3556), W64LIT(0x4b8d118fb252b3d9), + W64LIT(0xd8137bd918ac7dfc), W64LIT(0x0a2f90aabbb47709), W64LIT(0xc2d67d7e8625d216), W64LIT(0x7181263266a1b1e8), + W64LIT(0x3023a7176f477538), W64LIT(0x7642b54592df1f94), W64LIT(0xf2f5da69e962a72e), W64LIT(0xa70966058bf18dec), + W64LIT(0xc662d63ac86de4e7), W64LIT(0x939e6a56aafece25), W64LIT(0x86edb40e5c99a34c), W64LIT(0xf8da4ac352d6d027), + W64LIT(0x145e3d496b75ee12), W64LIT(0xce179db254fd8818), W64LIT(0xd23ceb73a3180af5), W64LIT(0x270aa26dbe0403a7), + W64LIT(0x5d89f7e4fe03463d), W64LIT(0x2ae6a1b0f1cedad2), W64LIT(0x1729057ad143769f), W64LIT(0xb10d806ec7a07808), + W64LIT(0x4f39bacbfc1a8528), W64LIT(0xeda9949ba4b1bd4e), W64LIT(0x5312cc0a0bff07c5), W64LIT(0xc4380d18ef49ff11), + W64LIT(0x95701a30c392e322), W64LIT(0xa0caf5727f8f2390), W64LIT(0x55fcbc6c62932ac2), W64LIT(0xcf3a7ea3c9ef0b63), + W64LIT(0x621c880cf9aaf186), W64LIT(0xfd430296818c65ad), W64LIT(0xbf96bb80325c39f0), W64LIT(0x6c87b3e20c56b07e), + W64LIT(0x299199834bf8425f), W64LIT(0x74186e67b5fb0462), W64LIT(0x4c4e82f8462c1da5), W64LIT(0x64f2f86a90c6dc81), + W64LIT(0x6b442095f8281e02), W64LIT(0x1d0695d06af70196), W64LIT(0xd5ff78045766a489), W64LIT(0x3856ec9ff3d719c7), + W64LIT(0xac0b15bead57799e), W64LIT(0xc3fb9e6f1b37516d), W64LIT(0x8e98ff86c009cfb3), W64LIT(0x49d7caad9576a82f), + W64LIT(0x859a8c3de6af3bc1), W64LIT(0x3dcfa4ca208dac4d), W64LIT(0x91c4b1748ddad5d3), W64LIT(0x8a2c54c28e41f942), + W64LIT(0x2bcb42a16cdc59a9), W64LIT(0x9e72698be5341750), W64LIT(0x1e71ade3d0c1991b), W64LIT(0xe6abe7208217493c), + W64LIT(0x3a0c37bdd4f30231), W64LIT(0x945df9215e806059), W64LIT(0xcc4d469073d993ee), W64LIT(0x0e9b3beef5fc41f8), + W64LIT(0x8b01b7d313537a39), W64LIT(0xf182e25a53543fa3), W64LIT(0x5810bfb12d59f3b7), W64LIT(0x8003c46835f58e4b), + W64LIT(0xbce183b3886aa17d), W64LIT(0x1604e66b4c51f5e4), W64LIT(0x2c08d1d698a2f7d5), W64LIT(0xc08ca65ca101c9e0), + W64LIT(0x7a8355894007459a), W64LIT(0xe21f4c64cc5f7fcd), W64LIT(0x88768fe0a965e2b4), W64LIT(0x82591f4a12d195bd), + W64LIT(0x4aa0f29e2f4030a2), W64LIT(0xdca7d09d56e44b0d), W64LIT(0x6daa50f391443305), W64LIT(0x92b3894737ec4d5e), + W64LIT(0xa8bfbefae31f4f6f), W64LIT(0xea6a07ec50cf1332), W64LIT(0x2293ea386d5eb62d), W64LIT(0x41a2812509e6c4d0), + W64LIT(0x8374fc5b8fc316c6), W64LIT(0x683318a6421e868f), W64LIT(0xb3575b4ce08463fe), W64LIT(0xe5dcdf133821d1b1), + W64LIT(0xd6884037ed503c04), W64LIT(0x05994855d35ab58a), W64LIT(0x5b678782976f6b3a), W64LIT(0x397b0f8e6ec59abc), + W64LIT(0xabc886c95929d7e2), W64LIT(0xe4f13c02a53352ca), W64LIT(0xb5b92b2a89e84ef9), W64LIT(0xaf7c2d8d1761e113), + W64LIT(0x75358d7628e98719), W64LIT(0x72f61e01dc972965), W64LIT(0x78d98eab67235e6c), W64LIT(0xc8f9edd43d91a51f), + W64LIT(0x0fb6d8ff68eec283), W64LIT(0x70acc523fbb33293), W64LIT(0x36cdd771062b583f), W64LIT(0xbdcc60a215782206), + W64LIT(0xa624851416e30e97), W64LIT(0x9607220379a47baf), W64LIT(0x1c2b76c1f7e582ed), W64LIT(0x6046532ede8eea70), + W64LIT(0xbebb5891af4eba8b), W64LIT(0x48fa29bc08642b54), W64LIT(0x19b23e9424bf3767), W64LIT(0x2627417c231680dc), + W64LIT(0x65df1b7b0dd45ffa), W64LIT(0xf536491e1d1c0952), W64LIT(0x54d15f7dff81a9b9), W64LIT(0x2550794f99201851), + W64LIT(0xdefd0bbf71c050fb), W64LIT(0x87c0571fc18b2037), W64LIT(0x10ea960d253dd8e3), W64LIT(0xe0459746eb7b643b), + W64LIT(0x12b04d2f0219c315), W64LIT(0xaae565d8c43b5499), W64LIT(0xe91d3fdfeaf98bbf), W64LIT(0xf76c923c3a3812a4), + W64LIT(0x1f5c4ef24dd31a60), W64LIT(0x812e2779a8e70d30), W64LIT(0xf41baa0f800e8a29), W64LIT(0xfc6ee1871c9ee6d6), + W64LIT(0x8fb51c975d1b4cc8), W64LIT(0x4e1459da61080653), W64LIT(0x310e4406f255f643), W64LIT(0x0cc1e0ccd2d85a0e), + W64LIT(0x0958a8990182ef84), W64LIT(0xa9925deb7e0dcc14), W64LIT(0x6a69c384653a9d79), W64LIT(0x04b4ab444e4836f1), + W64LIT(0x0dec03dd4fcad975), W64LIT(0xeb47e4fdcddd9049), W64LIT(0x7e37fecd0e4f736b), W64LIT(0x73dbfd104185aa1e), + W64LIT(0xc515ee09725b7c6a), W64LIT(0xae51ce9c8a736268), W64LIT(0xa3bdcd41c5b9bb1d), W64LIT(0x84b76f2c7bbdb8ba), + W64LIT(0x443bc970dabc715a), W64LIT(0xa1e71663e29da0eb), W64LIT(0x7f1a1ddc935df010), W64LIT(0x474cf143608ae9d7), + W64LIT(0x33549f24d571edb5), W64LIT(0xc9d40ec5a0832664), W64LIT(0x46611252fd986aac), W64LIT(0x5efecfd74435deb0), + W64LIT(0x0000000000000000), W64LIT(0x514817282cdb1c33), W64LIT(0x408f623494f447ab), W64LIT(0x57a6674e45b73134), + W64LIT(0x11c7751cb82f5b98), W64LIT(0x989c19ed8c583a57), W64LIT(0x7baeb698dd15c6e1), W64LIT(0x06ee7066696c2d07), + W64LIT(0xda49a0fb3f88660a), W64LIT(0x07c39377f47eae7c), W64LIT(0x2d2532c705b074ae), W64LIT(0x42d5b916b3d05c5d), + W64LIT(0xec84778a39a33e35), W64LIT(0x776f56540fcd9cef), W64LIT(0xa553bd27acd5961a), W64LIT(0xb978cbe65b3014f7), + W64LIT(0x895b6cf1347761cf), W64LIT(0xb85528f7c622978c), W64LIT(0x66a82348b7e2c777), W64LIT(0xe830dcce77eb08c4), + W64LIT(0x189fdd85b9adb41c), W64LIT(0x99b1fafc114ab92c), W64LIT(0x0b0273bb26a6f472), W64LIT(0xeedeaca81e8725c3), + W64LIT(0x6785c0592af0440c), W64LIT(0x247d9a5e04329b2a), W64LIT(0x21e4d20bd7682ea0), W64LIT(0xbb2210c47c140f01), + W64LIT(0x523f2f1b96ed84be), W64LIT(0xd4d29b15ca7427f2), W64LIT(0x45162a6147aef221), W64LIT(0xf641712da72a91df), + W64LIT(0xb020637f5ab2fb73), W64LIT(0xdd8a338ccbf6c876), W64LIT(0x5ca414f56311c546), W64LIT(0x3f957fe807a9b7bb), + W64LIT(0x8cc224a4e72dd445), W64LIT(0x012de3119d12837b), W64LIT(0xd0663051843c1103), W64LIT(0x5a4a64930a7de841), + W64LIT(0x28bc7a92d6eac124), W64LIT(0x08754b889c906cff), W64LIT(0xd7a5a3267042bf7f), W64LIT(0x3ce247dbbd9f2f36), + W64LIT(0x6ff08bd1b66028f3), W64LIT(0xd14bd340192e9278), W64LIT(0x139dae3e9f0b406e), W64LIT(0xe78604311f05ca47), + W64LIT(0xd93e98c885befe87), W64LIT(0x616bb03f439c690b), W64LIT(0x03773833ba36988d), W64LIT(0xcb8ed5e787a73d92), + W64LIT(0xb7e3f008aecc550f), W64LIT(0x9c28b2a9c2100ca6), W64LIT(0x3eb89cf99abb34c0), W64LIT(0x3b21d4ac49e1814a), + W64LIT(0xdfd0e8aeecd2d380), W64LIT(0x7c6d25ef296b689d), W64LIT(0xc1a1454d3c134a9b), W64LIT(0xf9f7a9d2cfc4535c), + W64LIT(0xc74f352b557f679c), W64LIT(0x7d40c6feb479ebe6), W64LIT(0x1573de58f6676d69), W64LIT(0x1ac506a79e89afea), + W64LIT(0x568b845fd8a5b24f), W64LIT(0x32797c3548636ece), W64LIT(0x691efbb7df0c05f4), W64LIT(0x972ac112e4b6f8d4), + W64LIT(0x79f46dbafa31dd17), W64LIT(0x2e520af4bf86ec23), W64LIT(0xd31108623e0a898e), W64LIT(0x8defc7b57a3f573e), + W64LIT(0x025adb2227241bf6), W64LIT(0xa2902e5058ab3866), W64LIT(0xfe343aa53bbafd20), W64LIT(0xad26f6af3045fae5), + W64LIT(0x43f85a072ec2df26), W64LIT(0x2f7fe9e522946f58), W64LIT(0x9beb21de366ea2da), W64LIT(0x20c9311a4a7aaddb), + W64LIT(0x5065f439b1c99f48), W64LIT(0x593d5ca0b04b70cc), W64LIT(0x9ac6c2cfab7c21a1), W64LIT(0xb6ce131933ded674), + W64LIT(0xf0af014bce46bcd8), W64LIT(0x4d6361e9db3e9ede), W64LIT(0xe16874577669e740), W64LIT(0xe332af75514dfcb6) + }, + { + W64LIT(0xbfbefae31f4f6fa8), W64LIT(0x85c0592af0440c67), W64LIT(0xbaef42bc1dc0b235), W64LIT(0x5528f7c622978cb8), + W64LIT(0xe6a1b0f1cedad22a), W64LIT(0x3ceb73a3180af5d2), W64LIT(0x7fe9e522946f582f), W64LIT(0xa7d09d56e44b0ddc), + W64LIT(0x754b889c906cff08), W64LIT(0xe247dbbd9f2f363c), W64LIT(0x81263266a1b1e871), W64LIT(0xdcdf133821d1b1e5), + W64LIT(0xf46dbafa31dd1779), W64LIT(0x3d5ca0b04b70cc59), W64LIT(0x56ec9ff3d719c738), W64LIT(0xdeaca81e8725c3ee), + W64LIT(0x549f24d571edb533), W64LIT(0x2de3119d12837b01), W64LIT(0xea960d253dd8e310), W64LIT(0xc886c95929d7e2ab), + W64LIT(0x2f90aabbb477090a), W64LIT(0x26f6af3045fae5ad), W64LIT(0x6ee1871c9ee6d6fc), W64LIT(0x3e98c885befe87d9), + W64LIT(0x24851416e30e97a6), W64LIT(0xda4ac352d6d027f8), W64LIT(0xe3f008aecc550fb7), W64LIT(0x994855d35ab58a05), + W64LIT(0x5df9215e80605994), W64LIT(0x58a8990182ef8409), W64LIT(0xb1fafc114ab92c99), W64LIT(0x442095f8281e026b), + W64LIT(0xf5da69e962a72ef2), W64LIT(0xc0571fc18b203787), W64LIT(0x37fecd0e4f736b7e), W64LIT(0x902e5058ab3866a2), + W64LIT(0xeb21de366ea2da9b), W64LIT(0x8f623494f447ab40), W64LIT(0xd98eab67235e6c78), W64LIT(0xa414f56311c5465c), + W64LIT(0x5c4ef24dd31a601f), W64LIT(0x08d1d698a2f7d52c), W64LIT(0xdbfd104185aa1e73), W64LIT(0xcb42a16cdc59a92b), + W64LIT(0x10bfb12d59f3b758), W64LIT(0xa82348b7e2c77766), W64LIT(0xbdcd41c5b9bb1da3), W64LIT(0x7ab85d7d96e085b2), + W64LIT(0xedb40e5c99a34c86), W64LIT(0xff78045766a489d5), W64LIT(0xf34fb98395a6b8ef), W64LIT(0x4f352b557f679cc7), + W64LIT(0x4a64930a7de8415a), W64LIT(0xe8e5b6039b2c911b), W64LIT(0xb4ab444e4836f104), W64LIT(0x4817282cdb1c3351), + W64LIT(0xaeb698dd15c6e17b), W64LIT(0x3f2f1b96ed84be52), W64LIT(0x21d4ac49e1814a3b), W64LIT(0x884037ed503c04d6), + W64LIT(0xbe0929f04c355623), W64LIT(0xe565d8c43b5499aa), W64LIT(0x1108623e0a898ed3), W64LIT(0x2532c705b074ae2d), + W64LIT(0x0551b85f028fdd9d), W64LIT(0x03c46835f58e4b80), W64LIT(0xf13c02a53352cae4), W64LIT(0xee7066696c2d0706), + W64LIT(0xc6c2cfab7c21a19a), W64LIT(0xb04d2f0219c31512), W64LIT(0x0273bb26a6f4720b), W64LIT(0x8604311f05ca47e7), + W64LIT(0xaf014bce46bcd8f0), W64LIT(0x3318a6421e868f68), W64LIT(0x96bb80325c39f0bf), W64LIT(0x40c6feb479ebe67d), + W64LIT(0x12cc0a0bff07c553), W64LIT(0x162a6147aef22145), W64LIT(0x71ade3d0c1991b1e), W64LIT(0xce131933ded674b6), + W64LIT(0xc9311a4a7aaddb20), W64LIT(0x32af75514dfcb6e3), W64LIT(0x62d63ac86de4e7c6), W64LIT(0xb23e9424bf376719), + W64LIT(0x8355894007459a7a), W64LIT(0x137bd918ac7dfcd8), W64LIT(0x42b54592df1f9476), W64LIT(0xabe7208217493ce6), + W64LIT(0x9b3beef5fc41f80e), W64LIT(0x2e2779a8e70d3081), W64LIT(0x4d469073d993eecc), W64LIT(0x768fe0a965e2b488), + W64LIT(0xd0e8aeecd2d380df), W64LIT(0xa2812509e6c4d041), W64LIT(0x0ff3d5e1068c7aba), W64LIT(0x04e66b4c51f5e416), + W64LIT(0x2c54c28e41f9428a), W64LIT(0x01b7d313537a398b), W64LIT(0xcc60a215782206bd), W64LIT(0xc506a79e89afea1a), + W64LIT(0x4cf143608ae9d747), W64LIT(0x8a338ccbf6c876dd), W64LIT(0x29057ad143769f17), W64LIT(0xcfa4ca208dac4d3d), + W64LIT(0xa6674e45b7313457), W64LIT(0x50794f9920185125), W64LIT(0xb89cf99abb34c03e), W64LIT(0x343aa53bbafd20fe), + W64LIT(0x89f7e4fe03463d5d), W64LIT(0xa5a3267042bf7fd7), W64LIT(0xefc7b57a3f573e8d), W64LIT(0x9fdd85b9adb41c18), + W64LIT(0xec03dd4fcad9750d), W64LIT(0x970c53210f43c934), W64LIT(0xc7751cb82f5b9811), W64LIT(0xc1e0ccd2d85a0e0c), + W64LIT(0xad72f0e8e048aafb), W64LIT(0x0966058bf18deca7), W64LIT(0x47e4fdcddd9049eb), W64LIT(0x19d9b4a6a87e5bff), + W64LIT(0x1a1ddc935df0107f), W64LIT(0x591f4a12d195bd82), W64LIT(0x1efbb7df0c05f469), W64LIT(0x575b4ce08463feb3), + W64LIT(0x0e4406f255f64331), W64LIT(0x2ac112e4b6f8d497), W64LIT(0xa0f29e2f4030a24a), W64LIT(0x179db254fd8818ce), + W64LIT(0x663051843c1103d0), W64LIT(0xe4d20bd7682ea021), W64LIT(0xd15f7dff81a9b954), W64LIT(0xd32cc6d9275dcb5f), + W64LIT(0x94c83b14facd82b4), W64LIT(0xaa50f3914433056d), W64LIT(0x358d7628e9871975), W64LIT(0xbc7a92d6eac12428), + W64LIT(0x39bacbfc1a85284f), W64LIT(0x9199834bf8425f29), W64LIT(0x73de58f6676d6915), W64LIT(0xd5b916b3d05c5d42), + W64LIT(0x46532ede8eea7060), W64LIT(0x186e67b5fb046274), W64LIT(0xa1454d3c134a9bc1), W64LIT(0x0b15bead57799eac), + W64LIT(0x5adb2227241bf602), W64LIT(0xdd68c02b72ab886e), W64LIT(0x6443eaa29ae571db), W64LIT(0xfd0bbf71c050fbde), + W64LIT(0x8b845fd8a5b24f56), W64LIT(0xb92b2a89e84ef9b5), W64LIT(0x678782976f6b3a5b), W64LIT(0xf2f86a90c6dc8164), + W64LIT(0xc39377f47eae7c07), W64LIT(0x93ea386d5eb62d22), W64LIT(0x430296818c65adfd), W64LIT(0xc224a4e72dd4458c), + W64LIT(0x9e6a56aafece2593), W64LIT(0x6f56540fcd9cef77), W64LIT(0x84778a39a33e35ec), W64LIT(0xf85a072ec2df2643), + W64LIT(0x3bc970dabc715a44), W64LIT(0x0d806ec7a07808b1), W64LIT(0x773833ba36988d03), W64LIT(0x27417c231680dc26), + W64LIT(0x60a581eecb1095cd), W64LIT(0xb76f2c7bbdb8ba84), W64LIT(0xd8397874702455f3), W64LIT(0xfecfd74435deb05e), + W64LIT(0xcaf5727f8f2390a0), W64LIT(0xa9949ba4b1bd4eed), W64LIT(0xe034609b39db4437), W64LIT(0x2b76c1f7e582ed1c), + W64LIT(0xf7a9d2cfc4535cf9), W64LIT(0x20637f5ab2fb73b0), W64LIT(0x9c19ed8c583a5798), W64LIT(0xd67d7e8625d216c2), + W64LIT(0x1459da610806534e), W64LIT(0x6d25ef296b689d7c), W64LIT(0x925deb7e0dcc14a9), W64LIT(0x65f439b1c99f4850), + W64LIT(0x957fe807a9b7bb3f), W64LIT(0x41712da72a91dff6), W64LIT(0x36491e1d1c0952f5), W64LIT(0x5e3d496b75ee1214), + W64LIT(0x1d3fdfeaf98bbfe9), W64LIT(0x701a30c392e32295), W64LIT(0x6361e9db3e9ede4d), W64LIT(0xd7caad9576a82f49), + W64LIT(0xe71663e29da0eba1), W64LIT(0x98ff86c009cfb38e), W64LIT(0x6bb03f439c690b61), W64LIT(0xc4b1748ddad5d391), + W64LIT(0x6c923c3a3812a4f7), W64LIT(0x1f4c64cc5f7fcde2), W64LIT(0xe183b3886aa17dbc), W64LIT(0xb6d8ff68eec2830f), + W64LIT(0x51ce9c8a736268ae), W64LIT(0x07220379a47baf96), W64LIT(0x82e25a53543fa3f1), W64LIT(0xbb5891af4eba8bbe), + W64LIT(0x4bd340192e9278d1), W64LIT(0x6874577669e740e1), W64LIT(0xfb9e6f1b37516dc3), W64LIT(0xacc523fbb3329370), + W64LIT(0x69c384653a9d796a), W64LIT(0x5b6cf1347761cf89), W64LIT(0x0000000000000000), W64LIT(0x49a0fb3f88660ada), + W64LIT(0xa336f61ab5bee9ca), W64LIT(0x15ee09725b7c6ac5), W64LIT(0x8d118fb252b3d94b), W64LIT(0x7d9a5e04329b2a24), + W64LIT(0x1baa0f800e8a29f4), W64LIT(0xfa29bc08642b5448), W64LIT(0x459746eb7b643be0), W64LIT(0xdf1b7b0dd45ffa65), + W64LIT(0x30dcce77eb08c4e8), W64LIT(0x8091e175f2cbd1fa), W64LIT(0x0c37bdd4f302313a), W64LIT(0xf9edd43d91a51fc8), + W64LIT(0x3a7ea3c9ef0b63cf), W64LIT(0x74fc5b8fc316c683), W64LIT(0x8ca65ca101c9e0c0), W64LIT(0x72698be53417509e), + W64LIT(0x23a7176f47753830), W64LIT(0x797c3548636ece32), W64LIT(0xb51c975d1b4cc88f), W64LIT(0x2210c47c140f01bb), + W64LIT(0xd29b15ca7427f2d4), W64LIT(0x8ed5e787a73d92cb), W64LIT(0x7e5e3631c71561a4), W64LIT(0x1c880cf9aaf18662), + W64LIT(0xf08bd1b66028f36f), W64LIT(0xf61e01dc97296572), W64LIT(0x7b0f8e6ec59abc39), W64LIT(0xb3894737ec4d5e92), + W64LIT(0x316b1d64b872fd63), W64LIT(0x9a8c3de6af3bc185), W64LIT(0x0aa26dbe0403a727), W64LIT(0x5f8a9a7826942b9f), + W64LIT(0x520af4bf86ec232e), W64LIT(0x380d18ef49ff11c4), W64LIT(0x0695d06af701961d), W64LIT(0x87b3e20c56b07e6c), + W64LIT(0x53bd27acd5961aa5), W64LIT(0x7c2d8d1761e113af), W64LIT(0x28b2a9c2100ca69c), W64LIT(0x6a07ec50cf1332ea), + W64LIT(0xe9526510c856a890), W64LIT(0xcdd771062b583f36), W64LIT(0xfcbc6c62932ac255), W64LIT(0x9dae3e9f0b406e13), + W64LIT(0xd40ec5a0832664c9), W64LIT(0x78cbe65b3014f7b9), W64LIT(0x4e82f8462c1da54c), W64LIT(0x611252fd986aac46) + }, + { + W64LIT(0x352b557f679cc74f), W64LIT(0x3e9424bf376719b2), W64LIT(0x5deb7e0dcc14a992), W64LIT(0xb3e20c56b07e6c87), + W64LIT(0x83b3886aa17dbce1), W64LIT(0x3d496b75ee12145e), W64LIT(0xae3e9f0b406e139d), W64LIT(0x8a9a7826942b9f5f), + W64LIT(0x845fd8a5b24f568b), W64LIT(0x5a072ec2df2643f8), W64LIT(0xf3d5e1068c7aba0f), W64LIT(0x7ea3c9ef0b63cf3a), + W64LIT(0x923c3a3812a4f76c), W64LIT(0x3fdfeaf98bbfe91d), W64LIT(0xd340192e9278d14b), W64LIT(0x04311f05ca47e786), + W64LIT(0xcc0a0bff07c55312), W64LIT(0xff86c009cfb38e98), W64LIT(0xade3d0c1991b1e71), W64LIT(0xfc5b8fc316c68374), + W64LIT(0xbb80325c39f0bf96), W64LIT(0xd5e787a73d92cb8e), W64LIT(0xa4ca208dac4d3dcf), W64LIT(0xf6af3045fae5ad26), + W64LIT(0x5b4ce08463feb357), W64LIT(0x8bd1b66028f36ff0), W64LIT(0xb698dd15c6e17bae), W64LIT(0x2f1b96ed84be523f), + W64LIT(0x4037ed503c04d688), W64LIT(0x6a56aafece25939e), W64LIT(0xb40e5c99a34c86ed), W64LIT(0xc6feb479ebe67d40), + W64LIT(0x9b15ca7427f2d4d2), W64LIT(0xde58f6676d691573), W64LIT(0xc523fbb3329370ac), W64LIT(0xe5b6039b2c911be8), + W64LIT(0x8d7628e987197535), W64LIT(0xf008aecc550fb7e3), W64LIT(0xd9b4a6a87e5bff19), W64LIT(0xc112e4b6f8d4972a), + W64LIT(0xdf133821d1b1e5dc), W64LIT(0xaf75514dfcb6e332), W64LIT(0x2095f8281e026b44), W64LIT(0xb54592df1f947642), + W64LIT(0x8eab67235e6c78d9), W64LIT(0x698be53417509e72), W64LIT(0xbc6c62932ac255fc), W64LIT(0x1f4a12d195bd8259), + W64LIT(0x15bead57799eac0b), W64LIT(0x1ddc935df0107f1a), W64LIT(0x131933ded674b6ce), W64LIT(0xe66b4c51f5e41604), + W64LIT(0x9db254fd8818ce17), W64LIT(0xa26dbe0403a7270a), W64LIT(0x17282cdb1c335148), W64LIT(0x47dbbd9f2f363ce2), + W64LIT(0xda69e962a72ef2f5), W64LIT(0x469073d993eecc4d), W64LIT(0xfafc114ab92c99b1), W64LIT(0x90aabbb477090a2f), + W64LIT(0xb2a9c2100ca69c28), W64LIT(0xa65ca101c9e0c08c), W64LIT(0xd09d56e44b0ddca7), W64LIT(0x3833ba36988d0377), + W64LIT(0x59da610806534e14), W64LIT(0x19ed8c583a57989c), W64LIT(0x491e1d1c0952f536), W64LIT(0xeb73a3180af5d23c), + W64LIT(0x2779a8e70d30812e), W64LIT(0x86c95929d7e2abc8), W64LIT(0xedd43d91a51fc8f9), W64LIT(0xb03f439c690b616b), + W64LIT(0x9e6f1b37516dc3fb), W64LIT(0x78045766a489d5ff), W64LIT(0x3c02a53352cae4f1), W64LIT(0x1c975d1b4cc88fb5), + W64LIT(0x55894007459a7a83), W64LIT(0xc384653a9d796a69), W64LIT(0x674e45b7313457a6), W64LIT(0x454d3c134a9bc1a1), + W64LIT(0xce9c8a736268ae51), W64LIT(0x98c885befe87d93e), W64LIT(0x0d18ef49ff11c438), W64LIT(0x66058bf18deca709), + W64LIT(0xcfd74435deb05efe), W64LIT(0x4ac352d6d027f8da), W64LIT(0x880cf9aaf186621c), W64LIT(0x0c53210f43c93497), + W64LIT(0x36f61ab5bee9caa3), W64LIT(0x526510c856a890e9), W64LIT(0x64930a7de8415a4a), W64LIT(0x1a30c392e3229570), + W64LIT(0x778a39a33e35ec84), W64LIT(0xbefae31f4f6fa8bf), W64LIT(0x2cc6d9275dcb5fd3), W64LIT(0xf439b1c99f485065), + W64LIT(0xa581eecb1095cd60), W64LIT(0x28f7c622978cb855), W64LIT(0x220379a47baf9607), W64LIT(0x7d7e8625d216c2d6), + W64LIT(0xd63ac86de4e7c662), W64LIT(0xea386d5eb62d2293), W64LIT(0xaa0f800e8a29f41b), W64LIT(0x1b7b0dd45ffa65df), + W64LIT(0x6cf1347761cf895b), W64LIT(0x4fb98395a6b8eff3), W64LIT(0xd4ac49e1814a3b21), W64LIT(0x311a4a7aaddb20c9), + W64LIT(0x32c705b074ae2d25), W64LIT(0xf29e2f4030a24aa0), W64LIT(0x712da72a91dff641), W64LIT(0xe4fdcddd9049eb47), + W64LIT(0xe7208217493ce6ab), W64LIT(0xab444e4836f104b4), W64LIT(0x2a6147aef2214516), W64LIT(0xb916b3d05c5d42d5), + W64LIT(0xd1d698a2f7d52c08), W64LIT(0xb7d313537a398b01), W64LIT(0x4b889c906cff0875), W64LIT(0xcbe65b3014f7b978), + W64LIT(0x812509e6c4d041a2), W64LIT(0xb85d7d96e085b27a), W64LIT(0xef42bc1dc0b235ba), W64LIT(0x18a6421e868f6833), + W64LIT(0x532ede8eea706046), W64LIT(0x2b2a89e84ef9b5b9), W64LIT(0xf86a90c6dc8164f2), W64LIT(0x397874702455f3d8), + W64LIT(0x65d8c43b5499aae5), W64LIT(0x42a16cdc59a92bcb), W64LIT(0x5f7dff81a9b954d1), W64LIT(0x9377f47eae7c07c3), + W64LIT(0x95d06af701961d06), W64LIT(0x34609b39db4437e0), W64LIT(0x8c3de6af3bc1859a), W64LIT(0xfd104185aa1e73db), + W64LIT(0x7bd918ac7dfcd813), W64LIT(0x417c231680dc2627), W64LIT(0x03dd4fcad9750dec), W64LIT(0x14f56311c5465ca4), + W64LIT(0x571fc18b203787c0), W64LIT(0xb1748ddad5d391c4), W64LIT(0xd8ff68eec2830fb6), W64LIT(0x014bce46bcd8f0af), + W64LIT(0x1663e29da0eba1e7), W64LIT(0x637f5ab2fb73b020), W64LIT(0xee09725b7c6ac515), W64LIT(0x0000000000000000), + W64LIT(0x338ccbf6c876dd8a), W64LIT(0x56540fcd9cef776f), W64LIT(0x623494f447ab408f), W64LIT(0x91e175f2cbd1fa80), + W64LIT(0x0f8e6ec59abc397b), W64LIT(0x4855d35ab58a0599), W64LIT(0x894737ec4d5e92b3), W64LIT(0xbd27acd5961aa553), + W64LIT(0x4d2f0219c31512b0), W64LIT(0xe1871c9ee6d6fc6e), W64LIT(0x8fe0a965e2b48876), W64LIT(0x118fb252b3d94b8d), + W64LIT(0xc0592af0440c6785), W64LIT(0xaca81e8725c3eede), W64LIT(0xd771062b583f36cd), W64LIT(0x7066696c2d0706ee), + W64LIT(0x99834bf8425f2991), W64LIT(0x3aa53bbafd20fe34), W64LIT(0x4406f255f643310e), W64LIT(0xa1b0f1cedad22ae6), + W64LIT(0x82f8462c1da54c4e), W64LIT(0x0929f04c355623be), W64LIT(0x057ad143769f1729), W64LIT(0x949ba4b1bd4eeda9), + W64LIT(0x960d253dd8e310ea), W64LIT(0xfecd0e4f736b7e37), W64LIT(0x0296818c65adfd43), W64LIT(0x6f2c7bbdb8ba84b7), + W64LIT(0x9a5e04329b2a247d), W64LIT(0x2348b7e2c77766a8), W64LIT(0xdcce77eb08c4e830), W64LIT(0x851416e30e97a624), + W64LIT(0x08623e0a898ed311), W64LIT(0x43eaa29ae571db64), W64LIT(0xc7b57a3f573e8def), W64LIT(0xc2cfab7c21a19ac6), + W64LIT(0x5ca0b04b70cc593d), W64LIT(0x0ec5a0832664c9d4), W64LIT(0x1e01dc97296572f6), W64LIT(0xbacbfc1a85284f39), + W64LIT(0xc970dabc715a443b), W64LIT(0xa8990182ef840958), W64LIT(0xc83b14facd82b494), W64LIT(0x72f0e8e048aafbad), + W64LIT(0xf143608ae9d7474c), W64LIT(0xf5727f8f2390a0ca), W64LIT(0x7fe807a9b7bb3f95), W64LIT(0x76c1f7e582ed1c2b), + W64LIT(0xcd41c5b9bb1da3bd), W64LIT(0x6b1d64b872fd6331), W64LIT(0x806ec7a07808b10d), W64LIT(0xe3119d12837b012d), + W64LIT(0x25ef296b689d7c6d), W64LIT(0x37bdd4f302313a0c), W64LIT(0x3051843c1103d066), W64LIT(0x68c02b72ab886edd), + W64LIT(0x8782976f6b3a5b67), W64LIT(0x2d8d1761e113af7c), W64LIT(0x1252fd986aac4661), W64LIT(0x0bbf71c050fbdefd), + W64LIT(0xd20bd7682ea021e4), W64LIT(0xe0ccd2d85a0e0cc1), W64LIT(0x9cf99abb34c03eb8), W64LIT(0xdd85b9adb41c189f), + W64LIT(0x61e9db3e9ede4d63), W64LIT(0x06a79e89afea1ac5), W64LIT(0xf7e4fe03463d5d89), W64LIT(0x794f992018512550), + W64LIT(0x3beef5fc41f80e9b), W64LIT(0xcaad9576a82f49d7), W64LIT(0x10c47c140f01bb22), W64LIT(0x0af4bf86ec232e52), + W64LIT(0xdb2227241bf6025a), W64LIT(0x21de366ea2da9beb), W64LIT(0x9f24d571edb53354), W64LIT(0x9746eb7b643be045), + W64LIT(0xa3267042bf7fd7a5), W64LIT(0x6e67b5fb04627418), W64LIT(0xc46835f58e4b8003), W64LIT(0x07ec50cf1332ea6a), + W64LIT(0xe8aeecd2d380dfd0), W64LIT(0xe9e522946f582f7f), W64LIT(0x54c28e41f9428a2c), W64LIT(0xe25a53543fa3f182), + W64LIT(0xa9d2cfc4535cf9f7), W64LIT(0xa0fb3f88660ada49), W64LIT(0x50f3914433056daa), W64LIT(0x51b85f028fdd9d05), + W64LIT(0xec9ff3d719c73856), W64LIT(0x263266a1b1e87181), W64LIT(0x5e3631c71561a47e), W64LIT(0x24a4e72dd4458cc2), + W64LIT(0x74577669e740e168), W64LIT(0x7a92d6eac12428bc), W64LIT(0x2e5058ab3866a290), W64LIT(0x4ef24dd31a601f5c), + W64LIT(0xf9215e806059945d), W64LIT(0xfbb7df0c05f4691e), W64LIT(0x751cb82f5b9811c7), W64LIT(0x29bc08642b5448fa), + W64LIT(0x5891af4eba8bbebb), W64LIT(0x73bb26a6f4720b02), W64LIT(0x6dbafa31dd1779f4), W64LIT(0x7c3548636ece3279), + W64LIT(0x4c64cc5f7fcde21f), W64LIT(0x60a215782206bdcc), W64LIT(0xa7176f4775383023), W64LIT(0xbfb12d59f3b75810) + }, + { + W64LIT(0x51843c1103d06630), W64LIT(0xdfeaf98bbfe91d3f), W64LIT(0xeef5fc41f80e9b3b), W64LIT(0xaf3045fae5ad26f6), + W64LIT(0x70dabc715a443bc9), W64LIT(0x119d12837b012de3), W64LIT(0x3b14facd82b494c8), W64LIT(0xdd4fcad9750dec03), + W64LIT(0xaabbb477090a2f90), W64LIT(0x75514dfcb6e332af), W64LIT(0x96818c65adfd4302), W64LIT(0x1d64b872fd63316b), + W64LIT(0xe4fe03463d5d89f7), W64LIT(0x43608ae9d7474cf1), W64LIT(0xe20c56b07e6c87b3), W64LIT(0xf24dd31a601f5c4e), + W64LIT(0x577669e740e16874), W64LIT(0x609b39db4437e034), W64LIT(0x3ac86de4e7c662d6), W64LIT(0x0379a47baf960722), + W64LIT(0xa79e89afea1ac506), W64LIT(0x4bce46bcd8f0af01), W64LIT(0x267042bf7fd7a5a3), W64LIT(0x7ad143769f172905), + W64LIT(0x85b9adb41c189fdd), W64LIT(0xc885befe87d93e98), W64LIT(0xed8c583a57989c19), W64LIT(0x3c3a3812a4f76c92), + W64LIT(0x5e04329b2a247d9a), W64LIT(0xf99abb34c03eb89c), W64LIT(0x2227241bf6025adb), W64LIT(0x6510c856a890e952), + W64LIT(0xa215782206bdcc60), W64LIT(0x9ff3d719c73856ec), W64LIT(0x02a53352cae4f13c), W64LIT(0x871c9ee6d6fc6ee1), + W64LIT(0x80325c39f0bf96bb), W64LIT(0x8d1761e113af7c2d), W64LIT(0x46eb7b643be04597), W64LIT(0xd8c43b5499aae565), + W64LIT(0x81eecb1095cd60a5), W64LIT(0x9c8a736268ae51ce), W64LIT(0x64cc5f7fcde21f4c), W64LIT(0x7c231680dc262741), + W64LIT(0xc28e41f9428a2c54), W64LIT(0x8ccbf6c876dd8a33), W64LIT(0xb98395a6b8eff34f), W64LIT(0xa9c2100ca69c28b2), + W64LIT(0x6ec7a07808b10d80), W64LIT(0x0a0bff07c55312cc), W64LIT(0xc02b72ab886edd68), W64LIT(0xb85f028fdd9d0551), + W64LIT(0x104185aa1e73dbfd), W64LIT(0xb6039b2c911be8e5), W64LIT(0x79a8e70d30812e27), W64LIT(0x82976f6b3a5b6787), + W64LIT(0xa53bbafd20fe343a), W64LIT(0x7dff81a9b954d15f), W64LIT(0x894007459a7a8355), W64LIT(0xd43d91a51fc8f9ed), + W64LIT(0xccd2d85a0e0cc1e0), W64LIT(0xe807a9b7bb3f957f), W64LIT(0xa81e8725c3eedeac), W64LIT(0x5058ab3866a2902e), + W64LIT(0x889c906cff08754b), W64LIT(0x4ce08463feb3575b), W64LIT(0xdc935df0107f1a1d), W64LIT(0x56aafece25939e6a), + W64LIT(0xa16cdc59a92bcb42), W64LIT(0xec50cf1332ea6a07), W64LIT(0x4592df1f947642b5), W64LIT(0xbafa31dd1779f46d), + W64LIT(0x29f04c355623be09), W64LIT(0x15ca7427f2d4d29b), W64LIT(0x215e806059945df9), W64LIT(0x23fbb3329370acc5), + W64LIT(0xd74435deb05efecf), W64LIT(0xeaa29ae571db6443), W64LIT(0xc95929d7e2abc886), W64LIT(0xa4e72dd4458cc224), + W64LIT(0x3548636ece32797c), W64LIT(0x27acd5961aa553bd), W64LIT(0xac49e1814a3b21d4), W64LIT(0xcbfc1a85284f39ba), + W64LIT(0x8fb252b3d94b8d11), W64LIT(0x42bc1dc0b235baef), W64LIT(0x072ec2df2643f85a), W64LIT(0x91af4eba8bbebb58), + W64LIT(0x045766a489d5ff78), W64LIT(0x9073d993eecc4d46), W64LIT(0x3f439c690b616bb0), W64LIT(0x6b4c51f5e41604e6), + W64LIT(0x7e8625d216c2d67d), W64LIT(0xab67235e6c78d98e), W64LIT(0xef296b689d7c6d25), W64LIT(0xc5a0832664c9d40e), + W64LIT(0x69e962a72ef2f5da), W64LIT(0x7b0dd45ffa65df1b), W64LIT(0x496b75ee12145e3d), W64LIT(0xd918ac7dfcd8137b), + W64LIT(0x1e1d1c0952f53649), W64LIT(0xfeb479ebe67d40c6), W64LIT(0x6147aef22145162a), W64LIT(0x0f800e8a29f41baa), + W64LIT(0x0000000000000000), W64LIT(0x990182ef840958a8), W64LIT(0x975d1b4cc88fb51c), W64LIT(0x5b8fc316c68374fc), + W64LIT(0x16b3d05c5d42d5b9), W64LIT(0xb3886aa17dbce183), W64LIT(0x4f99201851255079), W64LIT(0x98dd15c6e17baeb6), + W64LIT(0x06f255f643310e44), W64LIT(0x6f1b37516dc3fb9e), W64LIT(0x0cf9aaf186621c88), W64LIT(0x8e6ec59abc397b0f), + W64LIT(0x930a7de8415a4a64), W64LIT(0x37ed503c04d68840), W64LIT(0xf61ab5bee9caa336), W64LIT(0xfb3f88660ada49a0), + W64LIT(0x7874702455f3d839), W64LIT(0x208217493ce6abe7), W64LIT(0x73a3180af5d23ceb), W64LIT(0x9e2f4030a24aa0f2), + W64LIT(0xe522946f582f7fe9), W64LIT(0xd5e1068c7aba0ff3), W64LIT(0xbdd4f302313a0c37), W64LIT(0x1fc18b203787c057), + W64LIT(0xd2cfc4535cf9f7a9), W64LIT(0x1b96ed84be523f2f), W64LIT(0x5d7d96e085b27ab8), W64LIT(0x66696c2d0706ee70), + W64LIT(0xd06af701961d0695), W64LIT(0xe3d0c1991b1e71ad), W64LIT(0x6c62932ac255fcbc), W64LIT(0xd313537a398b01b7), + W64LIT(0xa0b04b70cc593d5c), W64LIT(0x834bf8425f299199), W64LIT(0xaeecd2d380dfd0e8), W64LIT(0xbead57799eac0b15), + W64LIT(0x540fcd9cef776f56), W64LIT(0xad9576a82f49d7ca), W64LIT(0xfc114ab92c99b1fa), W64LIT(0x33ba36988d037738), + W64LIT(0xbb26a6f4720b0273), W64LIT(0xb254fd8818ce179d), W64LIT(0xa6421e868f683318), W64LIT(0x5fd8a5b24f568b84), + W64LIT(0x623e0a898ed31108), W64LIT(0xb0f1cedad22ae6a1), W64LIT(0x1933ded674b6ce13), W64LIT(0x1416e30e97a62485), + W64LIT(0x3e9f0b406e139dae), W64LIT(0x6dbe0403a7270aa2), W64LIT(0xbc08642b5448fa29), W64LIT(0x0d253dd8e310ea96), + W64LIT(0x2ede8eea70604653), W64LIT(0x39b1c99f485065f4), W64LIT(0xcd0e4f736b7e37fe), W64LIT(0xbf71c050fbdefd0b), + W64LIT(0x748ddad5d391c4b1), W64LIT(0x0bd7682ea021e4d2), W64LIT(0x3494f447ab408f62), W64LIT(0xb4a6a87e5bff19d9), + W64LIT(0x133821d1b1e5dcdf), W64LIT(0x95f8281e026b4420), W64LIT(0x2da72a91dff64171), W64LIT(0x18ef49ff11c4380d), + W64LIT(0xc705b074ae2d2532), W64LIT(0x3de6af3bc1859a8c), W64LIT(0x6835f58e4b8003c4), W64LIT(0xe787a73d92cb8ed5), + W64LIT(0xc6d9275dcb5fd32c), W64LIT(0xf7c622978cb85528), W64LIT(0x4d3c134a9bc1a145), W64LIT(0xf3914433056daa50), + W64LIT(0xb7df0c05f4691efb), W64LIT(0xe175f2cbd1fa8091), W64LIT(0x77f47eae7c07c393), W64LIT(0xeb7e0dcc14a9925d), + W64LIT(0xf1347761cf895b6c), W64LIT(0x08aecc550fb7e3f0), W64LIT(0x55d35ab58a059948), W64LIT(0x444e4836f104b4ab), + W64LIT(0x58f6676d691573de), W64LIT(0x9ba4b1bd4eeda994), W64LIT(0x92d6eac12428bc7a), W64LIT(0xb12d59f3b75810bf), + W64LIT(0xa3c9ef0b63cf3a7e), W64LIT(0x67b5fb046274186e), W64LIT(0x2f0219c31512b04d), W64LIT(0x3266a1b1e8718126), + W64LIT(0x7628e9871975358d), W64LIT(0xda610806534e1459), W64LIT(0x311f05ca47e78604), W64LIT(0x12e4b6f8d4972ac1), + W64LIT(0x282cdb1c33514817), W64LIT(0x727f8f2390a0caf5), W64LIT(0xb57a3f573e8defc7), W64LIT(0x71062b583f36cdd7), + W64LIT(0x84653a9d796a69c3), W64LIT(0xf56311c5465ca414), W64LIT(0x4737ec4d5e92b389), W64LIT(0x1cb82f5b9811c775), + W64LIT(0x2509e6c4d041a281), W64LIT(0xfdcddd9049eb47e4), W64LIT(0x40192e9278d14bd3), W64LIT(0x2a89e84ef9b5b92b), + W64LIT(0x3631c71561a47e5e), W64LIT(0x8be53417509e7269), W64LIT(0x24d571edb533549f), W64LIT(0xc352d6d027f8da4a), + W64LIT(0x01dc97296572f61e), W64LIT(0xe9db3e9ede4d6361), W64LIT(0x4e45b7313457a667), W64LIT(0xf8462c1da54c4e82), + W64LIT(0x4a12d195bd82591f), W64LIT(0xff68eec2830fb6d8), W64LIT(0x176f4775383023a7), W64LIT(0x48b7e2c77766a823), + W64LIT(0x592af0440c6785c0), W64LIT(0x2c7bbdb8ba84b76f), W64LIT(0x5ca101c9e0c08ca6), W64LIT(0x63e29da0eba1e716), + W64LIT(0xd698a2f7d52c08d1), W64LIT(0xce77eb08c4e830dc), W64LIT(0xde366ea2da9beb21), W64LIT(0x5a53543fa3f182e2), + W64LIT(0x52fd986aac466112), W64LIT(0x86c009cfb38e98ff), W64LIT(0xd1b66028f36ff08b), W64LIT(0x1a4a7aaddb20c931), + W64LIT(0xcfab7c21a19ac6c2), W64LIT(0x09725b7c6ac515ee), W64LIT(0x0e5c99a34c86edb4), W64LIT(0xdbbd9f2f363ce247), + W64LIT(0x6a90c6dc8164f2f8), W64LIT(0x8a39a33e35ec8477), W64LIT(0xe0a965e2b488768f), W64LIT(0x7f5ab2fb73b02063), + W64LIT(0xf4bf86ec232e520a), W64LIT(0xfae31f4f6fa8bfbe), W64LIT(0x058bf18deca70966), W64LIT(0x41c5b9bb1da3bdcd), + W64LIT(0x2b557f679cc74f35), W64LIT(0xca208dac4d3dcfa4), W64LIT(0x9a7826942b9f5f8a), W64LIT(0xf0e8e048aafbad72), + W64LIT(0x53210f43c934970c), W64LIT(0xc1f7e582ed1c2b76), W64LIT(0xc47c140f01bb2210), W64LIT(0x9d56e44b0ddca7d0), + W64LIT(0x386d5eb62d2293ea), W64LIT(0xe65b3014f7b978cb), W64LIT(0x9424bf376719b23e), W64LIT(0x30c392e32295701a) + } +}; + +const byte S[4][256] = +{ + { + 0xA8, 0x43, 0x5F, 0x06, 0x6B, 0x75, 0x6C, 0x59, 0x71, 0xDF, 0x87, 0x95, 0x17, 0xF0, 0xD8, 0x09, + 0x6D, 0xF3, 0x1D, 0xCB, 0xC9, 0x4D, 0x2C, 0xAF, 0x79, 0xE0, 0x97, 0xFD, 0x6F, 0x4B, 0x45, 0x39, + 0x3E, 0xDD, 0xA3, 0x4F, 0xB4, 0xB6, 0x9A, 0x0E, 0x1F, 0xBF, 0x15, 0xE1, 0x49, 0xD2, 0x93, 0xC6, + 0x92, 0x72, 0x9E, 0x61, 0xD1, 0x63, 0xFA, 0xEE, 0xF4, 0x19, 0xD5, 0xAD, 0x58, 0xA4, 0xBB, 0xA1, + 0xDC, 0xF2, 0x83, 0x37, 0x42, 0xE4, 0x7A, 0x32, 0x9C, 0xCC, 0xAB, 0x4A, 0x8F, 0x6E, 0x04, 0x27, + 0x2E, 0xE7, 0xE2, 0x5A, 0x96, 0x16, 0x23, 0x2B, 0xC2, 0x65, 0x66, 0x0F, 0xBC, 0xA9, 0x47, 0x41, + 0x34, 0x48, 0xFC, 0xB7, 0x6A, 0x88, 0xA5, 0x53, 0x86, 0xF9, 0x5B, 0xDB, 0x38, 0x7B, 0xC3, 0x1E, + 0x22, 0x33, 0x24, 0x28, 0x36, 0xC7, 0xB2, 0x3B, 0x8E, 0x77, 0xBA, 0xF5, 0x14, 0x9F, 0x08, 0x55, + 0x9B, 0x4C, 0xFE, 0x60, 0x5C, 0xDA, 0x18, 0x46, 0xCD, 0x7D, 0x21, 0xB0, 0x3F, 0x1B, 0x89, 0xFF, + 0xEB, 0x84, 0x69, 0x3A, 0x9D, 0xD7, 0xD3, 0x70, 0x67, 0x40, 0xB5, 0xDE, 0x5D, 0x30, 0x91, 0xB1, + 0x78, 0x11, 0x01, 0xE5, 0x00, 0x68, 0x98, 0xA0, 0xC5, 0x02, 0xA6, 0x74, 0x2D, 0x0B, 0xA2, 0x76, + 0xB3, 0xBE, 0xCE, 0xBD, 0xAE, 0xE9, 0x8A, 0x31, 0x1C, 0xEC, 0xF1, 0x99, 0x94, 0xAA, 0xF6, 0x26, + 0x2F, 0xEF, 0xE8, 0x8C, 0x35, 0x03, 0xD4, 0x7F, 0xFB, 0x05, 0xC1, 0x5E, 0x90, 0x20, 0x3D, 0x82, + 0xF7, 0xEA, 0x0A, 0x0D, 0x7E, 0xF8, 0x50, 0x1A, 0xC4, 0x07, 0x57, 0xB8, 0x3C, 0x62, 0xE3, 0xC8, + 0xAC, 0x52, 0x64, 0x10, 0xD0, 0xD9, 0x13, 0x0C, 0x12, 0x29, 0x51, 0xB9, 0xCF, 0xD6, 0x73, 0x8D, + 0x81, 0x54, 0xC0, 0xED, 0x4E, 0x44, 0xA7, 0x2A, 0x85, 0x25, 0xE6, 0xCA, 0x7C, 0x8B, 0x56, 0x80 + }, + { + 0xCE, 0xBB, 0xEB, 0x92, 0xEA, 0xCB, 0x13, 0xC1, 0xE9, 0x3A, 0xD6, 0xB2, 0xD2, 0x90, 0x17, 0xF8, + 0x42, 0x15, 0x56, 0xB4, 0x65, 0x1C, 0x88, 0x43, 0xC5, 0x5C, 0x36, 0xBA, 0xF5, 0x57, 0x67, 0x8D, + 0x31, 0xF6, 0x64, 0x58, 0x9E, 0xF4, 0x22, 0xAA, 0x75, 0x0F, 0x02, 0xB1, 0xDF, 0x6D, 0x73, 0x4D, + 0x7C, 0x26, 0x2E, 0xF7, 0x08, 0x5D, 0x44, 0x3E, 0x9F, 0x14, 0xC8, 0xAE, 0x54, 0x10, 0xD8, 0xBC, + 0x1A, 0x6B, 0x69, 0xF3, 0xBD, 0x33, 0xAB, 0xFA, 0xD1, 0x9B, 0x68, 0x4E, 0x16, 0x95, 0x91, 0xEE, + 0x4C, 0x63, 0x8E, 0x5B, 0xCC, 0x3C, 0x19, 0xA1, 0x81, 0x49, 0x7B, 0xD9, 0x6F, 0x37, 0x60, 0xCA, + 0xE7, 0x2B, 0x48, 0xFD, 0x96, 0x45, 0xFC, 0x41, 0x12, 0x0D, 0x79, 0xE5, 0x89, 0x8C, 0xE3, 0x20, + 0x30, 0xDC, 0xB7, 0x6C, 0x4A, 0xB5, 0x3F, 0x97, 0xD4, 0x62, 0x2D, 0x06, 0xA4, 0xA5, 0x83, 0x5F, + 0x2A, 0xDA, 0xC9, 0x00, 0x7E, 0xA2, 0x55, 0xBF, 0x11, 0xD5, 0x9C, 0xCF, 0x0E, 0x0A, 0x3D, 0x51, + 0x7D, 0x93, 0x1B, 0xFE, 0xC4, 0x47, 0x09, 0x86, 0x0B, 0x8F, 0x9D, 0x6A, 0x07, 0xB9, 0xB0, 0x98, + 0x18, 0x32, 0x71, 0x4B, 0xEF, 0x3B, 0x70, 0xA0, 0xE4, 0x40, 0xFF, 0xC3, 0xA9, 0xE6, 0x78, 0xF9, + 0x8B, 0x46, 0x80, 0x1E, 0x38, 0xE1, 0xB8, 0xA8, 0xE0, 0x0C, 0x23, 0x76, 0x1D, 0x25, 0x24, 0x05, + 0xF1, 0x6E, 0x94, 0x28, 0x9A, 0x84, 0xE8, 0xA3, 0x4F, 0x77, 0xD3, 0x85, 0xE2, 0x52, 0xF2, 0x82, + 0x50, 0x7A, 0x2F, 0x74, 0x53, 0xB3, 0x61, 0xAF, 0x39, 0x35, 0xDE, 0xCD, 0x1F, 0x99, 0xAC, 0xAD, + 0x72, 0x2C, 0xDD, 0xD0, 0x87, 0xBE, 0x5E, 0xA6, 0xEC, 0x04, 0xC6, 0x03, 0x34, 0xFB, 0xDB, 0x59, + 0xB6, 0xC2, 0x01, 0xF0, 0x5A, 0xED, 0xA7, 0x66, 0x21, 0x7F, 0x8A, 0x27, 0xC7, 0xC0, 0x29, 0xD7 + }, + { + 0x93, 0xD9, 0x9A, 0xB5, 0x98, 0x22, 0x45, 0xFC, 0xBA, 0x6A, 0xDF, 0x02, 0x9F, 0xDC, 0x51, 0x59, + 0x4A, 0x17, 0x2B, 0xC2, 0x94, 0xF4, 0xBB, 0xA3, 0x62, 0xE4, 0x71, 0xD4, 0xCD, 0x70, 0x16, 0xE1, + 0x49, 0x3C, 0xC0, 0xD8, 0x5C, 0x9B, 0xAD, 0x85, 0x53, 0xA1, 0x7A, 0xC8, 0x2D, 0xE0, 0xD1, 0x72, + 0xA6, 0x2C, 0xC4, 0xE3, 0x76, 0x78, 0xB7, 0xB4, 0x09, 0x3B, 0x0E, 0x41, 0x4C, 0xDE, 0xB2, 0x90, + 0x25, 0xA5, 0xD7, 0x03, 0x11, 0x00, 0xC3, 0x2E, 0x92, 0xEF, 0x4E, 0x12, 0x9D, 0x7D, 0xCB, 0x35, + 0x10, 0xD5, 0x4F, 0x9E, 0x4D, 0xA9, 0x55, 0xC6, 0xD0, 0x7B, 0x18, 0x97, 0xD3, 0x36, 0xE6, 0x48, + 0x56, 0x81, 0x8F, 0x77, 0xCC, 0x9C, 0xB9, 0xE2, 0xAC, 0xB8, 0x2F, 0x15, 0xA4, 0x7C, 0xDA, 0x38, + 0x1E, 0x0B, 0x05, 0xD6, 0x14, 0x6E, 0x6C, 0x7E, 0x66, 0xFD, 0xB1, 0xE5, 0x60, 0xAF, 0x5E, 0x33, + 0x87, 0xC9, 0xF0, 0x5D, 0x6D, 0x3F, 0x88, 0x8D, 0xC7, 0xF7, 0x1D, 0xE9, 0xEC, 0xED, 0x80, 0x29, + 0x27, 0xCF, 0x99, 0xA8, 0x50, 0x0F, 0x37, 0x24, 0x28, 0x30, 0x95, 0xD2, 0x3E, 0x5B, 0x40, 0x83, + 0xB3, 0x69, 0x57, 0x1F, 0x07, 0x1C, 0x8A, 0xBC, 0x20, 0xEB, 0xCE, 0x8E, 0xAB, 0xEE, 0x31, 0xA2, + 0x73, 0xF9, 0xCA, 0x3A, 0x1A, 0xFB, 0x0D, 0xC1, 0xFE, 0xFA, 0xF2, 0x6F, 0xBD, 0x96, 0xDD, 0x43, + 0x52, 0xB6, 0x08, 0xF3, 0xAE, 0xBE, 0x19, 0x89, 0x32, 0x26, 0xB0, 0xEA, 0x4B, 0x64, 0x84, 0x82, + 0x6B, 0xF5, 0x79, 0xBF, 0x01, 0x5F, 0x75, 0x63, 0x1B, 0x23, 0x3D, 0x68, 0x2A, 0x65, 0xE8, 0x91, + 0xF6, 0xFF, 0x13, 0x58, 0xF1, 0x47, 0x0A, 0x7F, 0xC5, 0xA7, 0xE7, 0x61, 0x5A, 0x06, 0x46, 0x44, + 0x42, 0x04, 0xA0, 0xDB, 0x39, 0x86, 0x54, 0xAA, 0x8C, 0x34, 0x21, 0x8B, 0xF8, 0x0C, 0x74, 0x67 + }, + { + 0x68, 0x8D, 0xCA, 0x4D, 0x73, 0x4B, 0x4E, 0x2A, 0xD4, 0x52, 0x26, 0xB3, 0x54, 0x1E, 0x19, 0x1F, + 0x22, 0x03, 0x46, 0x3D, 0x2D, 0x4A, 0x53, 0x83, 0x13, 0x8A, 0xB7, 0xD5, 0x25, 0x79, 0xF5, 0xBD, + 0x58, 0x2F, 0x0D, 0x02, 0xED, 0x51, 0x9E, 0x11, 0xF2, 0x3E, 0x55, 0x5E, 0xD1, 0x16, 0x3C, 0x66, + 0x70, 0x5D, 0xF3, 0x45, 0x40, 0xCC, 0xE8, 0x94, 0x56, 0x08, 0xCE, 0x1A, 0x3A, 0xD2, 0xE1, 0xDF, + 0xB5, 0x38, 0x6E, 0x0E, 0xE5, 0xF4, 0xF9, 0x86, 0xE9, 0x4F, 0xD6, 0x85, 0x23, 0xCF, 0x32, 0x99, + 0x31, 0x14, 0xAE, 0xEE, 0xC8, 0x48, 0xD3, 0x30, 0xA1, 0x92, 0x41, 0xB1, 0x18, 0xC4, 0x2C, 0x71, + 0x72, 0x44, 0x15, 0xFD, 0x37, 0xBE, 0x5F, 0xAA, 0x9B, 0x88, 0xD8, 0xAB, 0x89, 0x9C, 0xFA, 0x60, + 0xEA, 0xBC, 0x62, 0x0C, 0x24, 0xA6, 0xA8, 0xEC, 0x67, 0x20, 0xDB, 0x7C, 0x28, 0xDD, 0xAC, 0x5B, + 0x34, 0x7E, 0x10, 0xF1, 0x7B, 0x8F, 0x63, 0xA0, 0x05, 0x9A, 0x43, 0x77, 0x21, 0xBF, 0x27, 0x09, + 0xC3, 0x9F, 0xB6, 0xD7, 0x29, 0xC2, 0xEB, 0xC0, 0xA4, 0x8B, 0x8C, 0x1D, 0xFB, 0xFF, 0xC1, 0xB2, + 0x97, 0x2E, 0xF8, 0x65, 0xF6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xE4, 0xD9, 0xB9, 0xD0, 0x42, 0xC7, + 0x6C, 0x90, 0x00, 0x8E, 0x6F, 0x50, 0x01, 0xC5, 0xDA, 0x47, 0x3F, 0xCD, 0x69, 0xA2, 0xE2, 0x7A, + 0xA7, 0xC6, 0x93, 0x0F, 0x0A, 0x06, 0xE6, 0x2B, 0x96, 0xA3, 0x1C, 0xAF, 0x6A, 0x12, 0x84, 0x39, + 0xE7, 0xB0, 0x82, 0xF7, 0xFE, 0x9D, 0x87, 0x5C, 0x81, 0x35, 0xDE, 0xB4, 0xA5, 0xFC, 0x80, 0xEF, + 0xCB, 0xBB, 0x6B, 0x76, 0xBA, 0x5A, 0x7D, 0x78, 0x0B, 0x95, 0xE3, 0xAD, 0x74, 0x98, 0x3B, 0x36, + 0x64, 0x6D, 0xDC, 0xF0, 0x59, 0xA9, 0x4C, 0x17, 0x7F, 0x91, 0xB8, 0xC9, 0x57, 0x1B, 0xE0, 0x61 + } +}; + +const byte IS[4][256] = +{ + { + 0xA4, 0xA2, 0xA9, 0xC5, 0x4E, 0xC9, 0x03, 0xD9, 0x7E, 0x0F, 0xD2, 0xAD, 0xE7, 0xD3, 0x27, 0x5B, + 0xE3, 0xA1, 0xE8, 0xE6, 0x7C, 0x2A, 0x55, 0x0C, 0x86, 0x39, 0xD7, 0x8D, 0xB8, 0x12, 0x6F, 0x28, + 0xCD, 0x8A, 0x70, 0x56, 0x72, 0xF9, 0xBF, 0x4F, 0x73, 0xE9, 0xF7, 0x57, 0x16, 0xAC, 0x50, 0xC0, + 0x9D, 0xB7, 0x47, 0x71, 0x60, 0xC4, 0x74, 0x43, 0x6C, 0x1F, 0x93, 0x77, 0xDC, 0xCE, 0x20, 0x8C, + 0x99, 0x5F, 0x44, 0x01, 0xF5, 0x1E, 0x87, 0x5E, 0x61, 0x2C, 0x4B, 0x1D, 0x81, 0x15, 0xF4, 0x23, + 0xD6, 0xEA, 0xE1, 0x67, 0xF1, 0x7F, 0xFE, 0xDA, 0x3C, 0x07, 0x53, 0x6A, 0x84, 0x9C, 0xCB, 0x02, + 0x83, 0x33, 0xDD, 0x35, 0xE2, 0x59, 0x5A, 0x98, 0xA5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4D, 0x1C, + 0x97, 0x08, 0x31, 0xEE, 0xAB, 0x05, 0xAF, 0x79, 0xA0, 0x18, 0x46, 0x6D, 0xFC, 0x89, 0xD4, 0xC7, + 0xFF, 0xF0, 0xCF, 0x42, 0x91, 0xF8, 0x68, 0x0A, 0x65, 0x8E, 0xB6, 0xFD, 0xC3, 0xEF, 0x78, 0x4C, + 0xCC, 0x9E, 0x30, 0x2E, 0xBC, 0x0B, 0x54, 0x1A, 0xA6, 0xBB, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7D, + 0xA7, 0x3F, 0xAE, 0x22, 0x3D, 0x66, 0xAA, 0xF6, 0x00, 0x5D, 0xBD, 0x4A, 0xE0, 0x3B, 0xB4, 0x17, + 0x8B, 0x9F, 0x76, 0xB0, 0x24, 0x9A, 0x25, 0x63, 0xDB, 0xEB, 0x7A, 0x3E, 0x5C, 0xB3, 0xB1, 0x29, + 0xF2, 0xCA, 0x58, 0x6E, 0xD8, 0xA8, 0x2F, 0x75, 0xDF, 0x14, 0xFB, 0x13, 0x49, 0x88, 0xB2, 0xEC, + 0xE4, 0x34, 0x2D, 0x96, 0xC6, 0x3A, 0xED, 0x95, 0x0E, 0xE5, 0x85, 0x6B, 0x40, 0x21, 0x9B, 0x09, + 0x19, 0x2B, 0x52, 0xDE, 0x45, 0xA3, 0xFA, 0x51, 0xC2, 0xB5, 0xD1, 0x90, 0xB9, 0xF3, 0x37, 0xC1, + 0x0D, 0xBA, 0x41, 0x11, 0x38, 0x7B, 0xBE, 0xD0, 0xD5, 0x69, 0x36, 0xC8, 0x62, 0x1B, 0x82, 0x8F + }, + { + 0x83, 0xF2, 0x2A, 0xEB, 0xE9, 0xBF, 0x7B, 0x9C, 0x34, 0x96, 0x8D, 0x98, 0xB9, 0x69, 0x8C, 0x29, + 0x3D, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4C, 0x0E, 0xA0, 0x56, 0x40, 0x92, 0x15, 0xBC, 0xB3, 0xDC, + 0x6F, 0xF8, 0x26, 0xBA, 0xBE, 0xBD, 0x31, 0xFB, 0xC3, 0xFE, 0x80, 0x61, 0xE1, 0x7A, 0x32, 0xD2, + 0x70, 0x20, 0xA1, 0x45, 0xEC, 0xD9, 0x1A, 0x5D, 0xB4, 0xD8, 0x09, 0xA5, 0x55, 0x8E, 0x37, 0x76, + 0xA9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xB1, 0x95, 0x62, 0x59, 0x74, 0xA3, 0x50, 0x2F, 0x4B, 0xC8, + 0xD0, 0x8F, 0xCD, 0xD4, 0x3C, 0x86, 0x12, 0x1D, 0x23, 0xEF, 0xF4, 0x53, 0x19, 0x35, 0xE6, 0x7F, + 0x5E, 0xD6, 0x79, 0x51, 0x22, 0x14, 0xF7, 0x1E, 0x4A, 0x42, 0x9B, 0x41, 0x73, 0x2D, 0xC1, 0x5C, + 0xA6, 0xA2, 0xE0, 0x2E, 0xD3, 0x28, 0xBB, 0xC9, 0xAE, 0x6A, 0xD1, 0x5A, 0x30, 0x90, 0x84, 0xF9, + 0xB2, 0x58, 0xCF, 0x7E, 0xC5, 0xCB, 0x97, 0xE4, 0x16, 0x6C, 0xFA, 0xB0, 0x6D, 0x1F, 0x52, 0x99, + 0x0D, 0x4E, 0x03, 0x91, 0xC2, 0x4D, 0x64, 0x77, 0x9F, 0xDD, 0xC4, 0x49, 0x8A, 0x9A, 0x24, 0x38, + 0xA7, 0x57, 0x85, 0xC7, 0x7C, 0x7D, 0xE7, 0xF6, 0xB7, 0xAC, 0x27, 0x46, 0xDE, 0xDF, 0x3B, 0xD7, + 0x9E, 0x2B, 0x0B, 0xD5, 0x13, 0x75, 0xF0, 0x72, 0xB6, 0x9D, 0x1B, 0x01, 0x3F, 0x44, 0xE5, 0x87, + 0xFD, 0x07, 0xF1, 0xAB, 0x94, 0x18, 0xEA, 0xFC, 0x3A, 0x82, 0x5F, 0x05, 0x54, 0xDB, 0x00, 0x8B, + 0xE3, 0x48, 0x0C, 0xCA, 0x78, 0x89, 0x0A, 0xFF, 0x3E, 0x5B, 0x81, 0xEE, 0x71, 0xE2, 0xDA, 0x2C, + 0xB8, 0xB5, 0xCC, 0x6E, 0xA8, 0x6B, 0xAD, 0x60, 0xC6, 0x08, 0x04, 0x02, 0xE8, 0xF5, 0x4F, 0xA4, + 0xF3, 0xC0, 0xCE, 0x43, 0x25, 0x1C, 0x21, 0x33, 0x0F, 0xAF, 0x47, 0xED, 0x66, 0x63, 0x93, 0xAA + }, + { + 0x45, 0xD4, 0x0B, 0x43, 0xF1, 0x72, 0xED, 0xA4, 0xC2, 0x38, 0xE6, 0x71, 0xFD, 0xB6, 0x3A, 0x95, + 0x50, 0x44, 0x4B, 0xE2, 0x74, 0x6B, 0x1E, 0x11, 0x5A, 0xC6, 0xB4, 0xD8, 0xA5, 0x8A, 0x70, 0xA3, + 0xA8, 0xFA, 0x05, 0xD9, 0x97, 0x40, 0xC9, 0x90, 0x98, 0x8F, 0xDC, 0x12, 0x31, 0x2C, 0x47, 0x6A, + 0x99, 0xAE, 0xC8, 0x7F, 0xF9, 0x4F, 0x5D, 0x96, 0x6F, 0xF4, 0xB3, 0x39, 0x21, 0xDA, 0x9C, 0x85, + 0x9E, 0x3B, 0xF0, 0xBF, 0xEF, 0x06, 0xEE, 0xE5, 0x5F, 0x20, 0x10, 0xCC, 0x3C, 0x54, 0x4A, 0x52, + 0x94, 0x0E, 0xC0, 0x28, 0xF6, 0x56, 0x60, 0xA2, 0xE3, 0x0F, 0xEC, 0x9D, 0x24, 0x83, 0x7E, 0xD5, + 0x7C, 0xEB, 0x18, 0xD7, 0xCD, 0xDD, 0x78, 0xFF, 0xDB, 0xA1, 0x09, 0xD0, 0x76, 0x84, 0x75, 0xBB, + 0x1D, 0x1A, 0x2F, 0xB0, 0xFE, 0xD6, 0x34, 0x63, 0x35, 0xD2, 0x2A, 0x59, 0x6D, 0x4D, 0x77, 0xE7, + 0x8E, 0x61, 0xCF, 0x9F, 0xCE, 0x27, 0xF5, 0x80, 0x86, 0xC7, 0xA6, 0xFB, 0xF8, 0x87, 0xAB, 0x62, + 0x3F, 0xDF, 0x48, 0x00, 0x14, 0x9A, 0xBD, 0x5B, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4C, 0x53, 0x0C, + 0xF2, 0x29, 0xAF, 0x17, 0x6C, 0x41, 0x30, 0xE9, 0x93, 0x55, 0xF7, 0xAC, 0x68, 0x26, 0xC4, 0x7D, + 0xCA, 0x7A, 0x3E, 0xA0, 0x37, 0x03, 0xC1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xA7, 0xBC, 0xC5, 0xD3, + 0x22, 0xB7, 0x13, 0x46, 0x32, 0xE8, 0x57, 0x88, 0x2B, 0x81, 0xB2, 0x4E, 0x64, 0x1C, 0xAA, 0x91, + 0x58, 0x2E, 0x9B, 0x5C, 0x1B, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6E, 0xF3, 0x0D, 0xBE, 0x3D, 0x0A, + 0x2D, 0x1F, 0x67, 0x33, 0x19, 0x7B, 0x5E, 0xEA, 0xDE, 0x8B, 0xCB, 0xA9, 0x8C, 0x8D, 0xAD, 0x49, + 0x82, 0xE4, 0xBA, 0xC3, 0x15, 0xD1, 0xE0, 0x89, 0xFC, 0xB1, 0xB9, 0xB5, 0x07, 0x79, 0xB8, 0xE1 + }, + { + 0xB2, 0xB6, 0x23, 0x11, 0xA7, 0x88, 0xC5, 0xA6, 0x39, 0x8F, 0xC4, 0xE8, 0x73, 0x22, 0x43, 0xC3, + 0x82, 0x27, 0xCD, 0x18, 0x51, 0x62, 0x2D, 0xF7, 0x5C, 0x0E, 0x3B, 0xFD, 0xCA, 0x9B, 0x0D, 0x0F, + 0x79, 0x8C, 0x10, 0x4C, 0x74, 0x1C, 0x0A, 0x8E, 0x7C, 0x94, 0x07, 0xC7, 0x5E, 0x14, 0xA1, 0x21, + 0x57, 0x50, 0x4E, 0xA9, 0x80, 0xD9, 0xEF, 0x64, 0x41, 0xCF, 0x3C, 0xEE, 0x2E, 0x13, 0x29, 0xBA, + 0x34, 0x5A, 0xAE, 0x8A, 0x61, 0x33, 0x12, 0xB9, 0x55, 0xA8, 0x15, 0x05, 0xF6, 0x03, 0x06, 0x49, + 0xB5, 0x25, 0x09, 0x16, 0x0C, 0x2A, 0x38, 0xFC, 0x20, 0xF4, 0xE5, 0x7F, 0xD7, 0x31, 0x2B, 0x66, + 0x6F, 0xFF, 0x72, 0x86, 0xF0, 0xA3, 0x2F, 0x78, 0x00, 0xBC, 0xCC, 0xE2, 0xB0, 0xF1, 0x42, 0xB4, + 0x30, 0x5F, 0x60, 0x04, 0xEC, 0xA5, 0xE3, 0x8B, 0xE7, 0x1D, 0xBF, 0x84, 0x7B, 0xE6, 0x81, 0xF8, + 0xDE, 0xD8, 0xD2, 0x17, 0xCE, 0x4B, 0x47, 0xD6, 0x69, 0x6C, 0x19, 0x99, 0x9A, 0x01, 0xB3, 0x85, + 0xB1, 0xF9, 0x59, 0xC2, 0x37, 0xE9, 0xC8, 0xA0, 0xED, 0x4F, 0x89, 0x68, 0x6D, 0xD5, 0x26, 0x91, + 0x87, 0x58, 0xBD, 0xC9, 0x98, 0xDC, 0x75, 0xC0, 0x76, 0xF5, 0x67, 0x6B, 0x7E, 0xEB, 0x52, 0xCB, + 0xD1, 0x5B, 0x9F, 0x0B, 0xDB, 0x40, 0x92, 0x1A, 0xFA, 0xAC, 0xE4, 0xE1, 0x71, 0x1F, 0x65, 0x8D, + 0x97, 0x9E, 0x95, 0x90, 0x5D, 0xB7, 0xC1, 0xAF, 0x54, 0xFB, 0x02, 0xE0, 0x35, 0xBB, 0x3A, 0x4D, + 0xAD, 0x2C, 0x3D, 0x56, 0x08, 0x1B, 0x4A, 0x93, 0x6A, 0xAB, 0xB8, 0x7A, 0xF2, 0x7D, 0xDA, 0x3F, + 0xFE, 0x3E, 0xBE, 0xEA, 0xAA, 0x44, 0xC6, 0xD0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xDF, + 0xF3, 0x83, 0x28, 0x32, 0x45, 0x1E, 0xA4, 0xD3, 0xA2, 0x46, 0x6E, 0x9C, 0xDD, 0x63, 0xD4, 0x9D + } +}; + +NAMESPACE_END +NAMESPACE_END diff --git a/extension/third_party/cryptopp/keccak.cpp b/extension/third_party/cryptopp/keccak.cpp new file mode 100644 index 00000000..ed69590e --- /dev/null +++ b/extension/third_party/cryptopp/keccak.cpp @@ -0,0 +1,67 @@ +// keccak.cpp - modified by Wei Dai from Ronny Van Keer's public domain +// sha3-simple.c. All modifications here are placed in the +// public domain by Wei Dai. +// Keccack core function moved to keccakc.cpp in AUG 2018 +// by Jeffrey Walton. Separating the core file allows both +// SHA3 and Keccack to share the core implementation. + +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michael Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "pch.h" +#include "keccak.h" + +NAMESPACE_BEGIN(CryptoPP) + +// The Keccak core function +extern void KeccakF1600(word64 *state); + +void Keccak::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0)); + if (length == 0) { return; } + + size_t spaceLeft; + while (length >= (spaceLeft = r() - m_counter)) + { + if (spaceLeft) + xorbuf(m_state.BytePtr() + m_counter, input, spaceLeft); + KeccakF1600(m_state); + input += spaceLeft; + length -= spaceLeft; + m_counter = 0; + } + + if (length) + xorbuf(m_state.BytePtr() + m_counter, input, length); + m_counter += (unsigned int)length; +} + +void Keccak::Restart() +{ + memset(m_state, 0, m_state.SizeInBytes()); + m_counter = 0; +} + +void Keccak::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + ThrowIfInvalidTruncatedSize(size); + + m_state.BytePtr()[m_counter] ^= 0x01; + m_state.BytePtr()[r()-1] ^= 0x80; + KeccakF1600(m_state); + std::memcpy(hash, m_state, size); + Restart(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/keccak.h b/extension/third_party/cryptopp/keccak.h new file mode 100644 index 00000000..f40cec5e --- /dev/null +++ b/extension/third_party/cryptopp/keccak.h @@ -0,0 +1,118 @@ +// keccak.h - originally written and placed in the public domain by Wei Dai + +/// \file keccak.h +/// \brief Classes for Keccak message digests +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \sa Keccak +/// \since Crypto++ 5.6.4 + +#ifndef CRYPTOPP_KECCAK_H +#define CRYPTOPP_KECCAK_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Keccak message digest base class +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// Library users should instantiate a derived class, and only use Keccak +/// as a base class reference or pointer. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \details Perform the following to specify a different digest size. The class will use F1600, +/// XOF d=0x01, and a new vaue for r() (which will be 200-2*24 = 152). +///
  Keccack_192 : public Keccack
+///   {
+///     public:
+///       CRYPTOPP_CONSTANT(DIGESTSIZE = 24);
+///       Keccack_192() : Keccack(DIGESTSIZE) {}
+///   };
+///   
+/// +/// \sa SHA3, Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// \since Crypto++ 5.6.4 +class Keccak : public HashTransformation +{ +protected: + /// \brief Construct a Keccak + /// \param digestSize the digest size, in bytes + /// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. + /// Library users should instantiate a derived class, and only use Keccak + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 5.6.4 + Keccak(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief Keccak message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 6.0 +template +class Keccak_Final : public Keccak +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize); + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE); + static std::string StaticAlgorithmName() + { return "Keccak-" + IntToString(DIGESTSIZE * 8); } + + /// \brief Construct a Keccak-X message digest + Keccak_Final() : Keccak(DIGESTSIZE) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief Keccak-224 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<28>, Keccak_224); + +/// \brief Keccak-256 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<32>, Keccak_256); + +/// \brief Keccak-384 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<48>, Keccak_384); + +/// \brief Keccak-512 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<64>, Keccak_512); + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/keccak_core.cpp b/extension/third_party/cryptopp/keccak_core.cpp new file mode 100644 index 00000000..6a8a91bf --- /dev/null +++ b/extension/third_party/cryptopp/keccak_core.cpp @@ -0,0 +1,261 @@ +// keccakc.cpp - Keccak core functions shared between SHA3 and Keccak. +// written and placed in the public domain by JW. + +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michael Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "pch.h" +#include "keccak.h" + +NAMESPACE_BEGIN(CryptoPP) + +// The Keccak core function +extern void KeccakF1600(word64 *state); +// The F1600 round constants +extern const word64 KeccakF1600Constants[24]; + +NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_ALIGN_DATA(8) +const word64 KeccakF1600Constants[24] = +{ + W64LIT(0x0000000000000001), W64LIT(0x0000000000008082), + W64LIT(0x800000000000808a), W64LIT(0x8000000080008000), + W64LIT(0x000000000000808b), W64LIT(0x0000000080000001), + W64LIT(0x8000000080008081), W64LIT(0x8000000000008009), + W64LIT(0x000000000000008a), W64LIT(0x0000000000000088), + W64LIT(0x0000000080008009), W64LIT(0x000000008000000a), + W64LIT(0x000000008000808b), W64LIT(0x800000000000008b), + W64LIT(0x8000000000008089), W64LIT(0x8000000000008003), + W64LIT(0x8000000000008002), W64LIT(0x8000000000000080), + W64LIT(0x000000000000800a), W64LIT(0x800000008000000a), + W64LIT(0x8000000080008081), W64LIT(0x8000000000008080), + W64LIT(0x0000000080000001), W64LIT(0x8000000080008008) +}; + +void KeccakF1600(word64 *state) +{ + word64 Aba, Abe, Abi, Abo, Abu; + word64 Aga, Age, Agi, Ago, Agu; + word64 Aka, Ake, Aki, Ako, Aku; + word64 Ama, Ame, Ami, Amo, Amu; + word64 Asa, Ase, Asi, Aso, Asu; + word64 BCa, BCe, BCi, BCo, BCu; + word64 Da, De, Di, Do, Du; + word64 Eba, Ebe, Ebi, Ebo, Ebu; + word64 Ega, Ege, Egi, Ego, Egu; + word64 Eka, Eke, Eki, Eko, Eku; + word64 Ema, Eme, Emi, Emo, Emu; + word64 Esa, Ese, Esi, Eso, Esu; + + typedef BlockGetAndPut Block; + Block::Get(state)(Aba)(Abe)(Abi)(Abo)(Abu)(Aga)(Age)(Agi)(Ago)(Agu)(Aka)(Ake)(Aki)(Ako)(Aku)(Ama)(Ame)(Ami)(Amo)(Amu)(Asa)(Ase)(Asi)(Aso)(Asu); + + for( unsigned int round = 0; round < 24; round += 2 ) + { + // prepareTheta + BCa = Aba^Aga^Aka^Ama^Asa; + BCe = Abe^Age^Ake^Ame^Ase; + BCi = Abi^Agi^Aki^Ami^Asi; + BCo = Abo^Ago^Ako^Amo^Aso; + BCu = Abu^Agu^Aku^Amu^Asu; + + //thetaRhoPiChiIotaPrepareTheta(round , A, E) + Da = BCu^rotlConstant<1>(BCe); + De = BCa^rotlConstant<1>(BCi); + Di = BCe^rotlConstant<1>(BCo); + Do = BCi^rotlConstant<1>(BCu); + Du = BCo^rotlConstant<1>(BCa); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = rotlConstant<44>(Age); + Aki ^= Di; + BCi = rotlConstant<43>(Aki); + Amo ^= Do; + BCo = rotlConstant<21>(Amo); + Asu ^= Du; + BCu = rotlConstant<14>(Asu); + Eba = BCa ^((~BCe)& BCi ); + Eba ^= KeccakF1600Constants[round]; + Ebe = BCe ^((~BCi)& BCo ); + Ebi = BCi ^((~BCo)& BCu ); + Ebo = BCo ^((~BCu)& BCa ); + Ebu = BCu ^((~BCa)& BCe ); + + Abo ^= Do; + BCa = rotlConstant<28>(Abo); + Agu ^= Du; + BCe = rotlConstant<20>(Agu); + Aka ^= Da; + BCi = rotlConstant<3>(Aka); + Ame ^= De; + BCo = rotlConstant<45>(Ame); + Asi ^= Di; + BCu = rotlConstant<61>(Asi); + Ega = BCa ^((~BCe)& BCi ); + Ege = BCe ^((~BCi)& BCo ); + Egi = BCi ^((~BCo)& BCu ); + Ego = BCo ^((~BCu)& BCa ); + Egu = BCu ^((~BCa)& BCe ); + + Abe ^= De; + BCa = rotlConstant<1>(Abe); + Agi ^= Di; + BCe = rotlConstant<6>(Agi); + Ako ^= Do; + BCi = rotlConstant<25>(Ako); + Amu ^= Du; + BCo = rotlConstant<8>(Amu); + Asa ^= Da; + BCu = rotlConstant<18>(Asa); + Eka = BCa ^((~BCe)& BCi ); + Eke = BCe ^((~BCi)& BCo ); + Eki = BCi ^((~BCo)& BCu ); + Eko = BCo ^((~BCu)& BCa ); + Eku = BCu ^((~BCa)& BCe ); + + Abu ^= Du; + BCa = rotlConstant<27>(Abu); + Aga ^= Da; + BCe = rotlConstant<36>(Aga); + Ake ^= De; + BCi = rotlConstant<10>(Ake); + Ami ^= Di; + BCo = rotlConstant<15>(Ami); + Aso ^= Do; + BCu = rotlConstant<56>(Aso); + Ema = BCa ^((~BCe)& BCi ); + Eme = BCe ^((~BCi)& BCo ); + Emi = BCi ^((~BCo)& BCu ); + Emo = BCo ^((~BCu)& BCa ); + Emu = BCu ^((~BCa)& BCe ); + + Abi ^= Di; + BCa = rotlConstant<62>(Abi); + Ago ^= Do; + BCe = rotlConstant<55>(Ago); + Aku ^= Du; + BCi = rotlConstant<39>(Aku); + Ama ^= Da; + BCo = rotlConstant<41>(Ama); + Ase ^= De; + BCu = rotlConstant<2>(Ase); + Esa = BCa ^((~BCe)& BCi ); + Ese = BCe ^((~BCi)& BCo ); + Esi = BCi ^((~BCo)& BCu ); + Eso = BCo ^((~BCu)& BCa ); + Esu = BCu ^((~BCa)& BCe ); + + // prepareTheta + BCa = Eba^Ega^Eka^Ema^Esa; + BCe = Ebe^Ege^Eke^Eme^Ese; + BCi = Ebi^Egi^Eki^Emi^Esi; + BCo = Ebo^Ego^Eko^Emo^Eso; + BCu = Ebu^Egu^Eku^Emu^Esu; + + //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) + Da = BCu^rotlConstant<1>(BCe); + De = BCa^rotlConstant<1>(BCi); + Di = BCe^rotlConstant<1>(BCo); + Do = BCi^rotlConstant<1>(BCu); + Du = BCo^rotlConstant<1>(BCa); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = rotlConstant<44>(Ege); + Eki ^= Di; + BCi = rotlConstant<43>(Eki); + Emo ^= Do; + BCo = rotlConstant<21>(Emo); + Esu ^= Du; + BCu = rotlConstant<14>(Esu); + Aba = BCa ^((~BCe)& BCi ); + Aba ^= KeccakF1600Constants[round+1]; + Abe = BCe ^((~BCi)& BCo ); + Abi = BCi ^((~BCo)& BCu ); + Abo = BCo ^((~BCu)& BCa ); + Abu = BCu ^((~BCa)& BCe ); + + Ebo ^= Do; + BCa = rotlConstant<28>(Ebo); + Egu ^= Du; + BCe = rotlConstant<20>(Egu); + Eka ^= Da; + BCi = rotlConstant<3>(Eka); + Eme ^= De; + BCo = rotlConstant<45>(Eme); + Esi ^= Di; + BCu = rotlConstant<61>(Esi); + Aga = BCa ^((~BCe)& BCi ); + Age = BCe ^((~BCi)& BCo ); + Agi = BCi ^((~BCo)& BCu ); + Ago = BCo ^((~BCu)& BCa ); + Agu = BCu ^((~BCa)& BCe ); + + Ebe ^= De; + BCa = rotlConstant<1>(Ebe); + Egi ^= Di; + BCe = rotlConstant<6>(Egi); + Eko ^= Do; + BCi = rotlConstant<25>(Eko); + Emu ^= Du; + BCo = rotlConstant<8>(Emu); + Esa ^= Da; + BCu = rotlConstant<18>(Esa); + Aka = BCa ^((~BCe)& BCi ); + Ake = BCe ^((~BCi)& BCo ); + Aki = BCi ^((~BCo)& BCu ); + Ako = BCo ^((~BCu)& BCa ); + Aku = BCu ^((~BCa)& BCe ); + + Ebu ^= Du; + BCa = rotlConstant<27>(Ebu); + Ega ^= Da; + BCe = rotlConstant<36>(Ega); + Eke ^= De; + BCi = rotlConstant<10>(Eke); + Emi ^= Di; + BCo = rotlConstant<15>(Emi); + Eso ^= Do; + BCu = rotlConstant<56>(Eso); + Ama = BCa ^((~BCe)& BCi ); + Ame = BCe ^((~BCi)& BCo ); + Ami = BCi ^((~BCo)& BCu ); + Amo = BCo ^((~BCu)& BCa ); + Amu = BCu ^((~BCa)& BCe ); + + Ebi ^= Di; + BCa = rotlConstant<62>(Ebi); + Ego ^= Do; + BCe = rotlConstant<55>(Ego); + Eku ^= Du; + BCi = rotlConstant<39>(Eku); + Ema ^= Da; + BCo = rotlConstant<41>(Ema); + Ese ^= De; + BCu = rotlConstant<2>(Ese); + Asa = BCa ^((~BCe)& BCi ); + Ase = BCe ^((~BCi)& BCo ); + Asi = BCi ^((~BCo)& BCu ); + Aso = BCo ^((~BCu)& BCa ); + Asu = BCu ^((~BCa)& BCe ); + } + + Block::Put(NULLPTR, state)(Aba)(Abe)(Abi)(Abo)(Abu)(Aga)(Age)(Agi)(Ago)(Agu)(Aka)(Ake)(Aki)(Ako)(Aku)(Ama)(Ame)(Ami)(Amo)(Amu)(Asa)(Ase)(Asi)(Aso)(Asu); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/keccak_simd.cpp b/extension/third_party/cryptopp/keccak_simd.cpp new file mode 100644 index 00000000..f2bb8b71 --- /dev/null +++ b/extension/third_party/cryptopp/keccak_simd.cpp @@ -0,0 +1,2685 @@ +// keccak_simd.cpp - written and placed in the public domain by Jeffrey Walton. +// +// This source file uses intrinsics to gain access to SSE and +// NEON instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate +// instructions sets in some build configurations. + +// The XKCP package is provided by Guido Bertoni, Joan Daemen, Seth Hoffert, +// Michael Peeters, Gilles Van Assche, and Ronny Van Keer. The code was +// placed public domain by the authors. + +// KeccakF1600x2_SSE is ParallelHash128. The SSE2 ParallelHash128 +// implementation was extracted from XKCP using the following command. +// +// gcc -I lib/common -I lib/low/KeccakP-1600/Optimized +// -I lib/low/KeccakP-1600-times2/SIMD128/SSE2ufull +// lib/low/KeccakP-1600-times2/SIMD128/KeccakP-1600-times2-SIMD128.c -E + +#include "pch.h" +#include "config.h" +#include "keccak.h" +#include "misc.h" + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char KECCAK_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +// The Keccak ParallelHash128 core function +extern void KeccakF1600x2_SSE(word64 *state); + +// The F1600 round constants +extern const word64 KeccakF1600Constants[24]; + +CRYPTOPP_ALIGN_DATA(16) +const word64 +rho8[2] = {W64LIT(0x0605040302010007), W64LIT(0x0E0D0C0B0A09080F)}; + +CRYPTOPP_ALIGN_DATA(16) +const word64 +rho56[2] = {W64LIT(0x0007060504030201), W64LIT(0x080F0E0D0C0B0A09)}; + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +#if defined(__XOP__) +# define ROL64in128(a, o) _mm_roti_epi64((a), (o)) +# define ROL64in128_8(a) ROL64in128((a), 8) +# define ROL64in128_56(a) ROL64in128((a), 56) +#else +# define ROL64in128(a, o) _mm_or_si128(_mm_slli_epi64((a), (o)), _mm_srli_epi64(a, 64-(o))) +# define ROL64in128_8(a) _mm_shuffle_epi8((a), _mm_load_si128(CONST_M128_CAST(rho8))) +# define ROL64in128_56(a) _mm_shuffle_epi8((a), _mm_load_si128(CONST_M128_CAST(rho56))) +#endif + +// Damn Visual Studio is missing too many intrinsics... +inline __m128i SPLAT64(const word64 a) +{ +#if defined(_MSC_VER) + double x; std::memcpy(&x, &a, 8); + return _mm_castpd_si128(_mm_loaddup_pd(&x)); +#else + return _mm_set1_epi64x(a); +#endif +} + +// The Keccak ParallelHash128 core function +void KeccakF1600x2_SSE(word64 *state) +{ + __m128i Aba, Abe, Abi, Abo, Abu; + __m128i Aga, Age, Agi, Ago, Agu; + __m128i Aka, Ake, Aki, Ako, Aku; + __m128i Ama, Ame, Ami, Amo, Amu; + __m128i Asa, Ase, Asi, Aso, Asu; + __m128i Bba, Bbe, Bbi, Bbo, Bbu; + __m128i Bga, Bge, Bgi, Bgo, Bgu; + __m128i Bka, Bke, Bki, Bko, Bku; + __m128i Bma, Bme, Bmi, Bmo, Bmu; + __m128i Bsa, Bse, Bsi, Bso, Bsu; + __m128i Ca, Ce, Ci, Co, Cu; + __m128i Da, De, Di, Do, Du; + __m128i Eba, Ebe, Ebi, Ebo, Ebu; + __m128i Ega, Ege, Egi, Ego, Egu; + __m128i Eka, Eke, Eki, Eko, Eku; + __m128i Ema, Eme, Emi, Emo, Emu; + __m128i Esa, Ese, Esi, Eso, Esu; + + __m128i* lanes = reinterpret_cast<__m128i*>(state); + Aba = _mm_loadu_si128(CONST_M128_CAST(lanes+ 0)); + Abe = _mm_loadu_si128(CONST_M128_CAST(lanes+ 1)); + Abi = _mm_loadu_si128(CONST_M128_CAST(lanes+ 2)); + Abo = _mm_loadu_si128(CONST_M128_CAST(lanes+ 3)); + Abu = _mm_loadu_si128(CONST_M128_CAST(lanes+ 4)); + Aga = _mm_loadu_si128(CONST_M128_CAST(lanes+ 5)); + Age = _mm_loadu_si128(CONST_M128_CAST(lanes+ 6)); + Agi = _mm_loadu_si128(CONST_M128_CAST(lanes+ 7)); + Ago = _mm_loadu_si128(CONST_M128_CAST(lanes+ 8)); + Agu = _mm_loadu_si128(CONST_M128_CAST(lanes+ 9)); + Aka = _mm_loadu_si128(CONST_M128_CAST(lanes+10)); + Ake = _mm_loadu_si128(CONST_M128_CAST(lanes+11)); + Aki = _mm_loadu_si128(CONST_M128_CAST(lanes+12)); + Ako = _mm_loadu_si128(CONST_M128_CAST(lanes+13)); + Aku = _mm_loadu_si128(CONST_M128_CAST(lanes+14)); + Ama = _mm_loadu_si128(CONST_M128_CAST(lanes+15)); + Ame = _mm_loadu_si128(CONST_M128_CAST(lanes+16)); + Ami = _mm_loadu_si128(CONST_M128_CAST(lanes+17)); + Amo = _mm_loadu_si128(CONST_M128_CAST(lanes+18)); + Amu = _mm_loadu_si128(CONST_M128_CAST(lanes+19)); + Asa = _mm_loadu_si128(CONST_M128_CAST(lanes+20)); + Ase = _mm_loadu_si128(CONST_M128_CAST(lanes+21)); + Asi = _mm_loadu_si128(CONST_M128_CAST(lanes+22)); + Aso = _mm_loadu_si128(CONST_M128_CAST(lanes+23)); + Asu = _mm_loadu_si128(CONST_M128_CAST(lanes+24)); + + Ca = _mm_xor_si128(Aba, _mm_xor_si128(Aga, _mm_xor_si128(Aka, _mm_xor_si128(Ama, Asa)))); + Ce = _mm_xor_si128(Abe, _mm_xor_si128(Age, _mm_xor_si128(Ake, _mm_xor_si128(Ame, Ase)))); + Ci = _mm_xor_si128(Abi, _mm_xor_si128(Agi, _mm_xor_si128(Aki, _mm_xor_si128(Ami, Asi)))); + Co = _mm_xor_si128(Abo, _mm_xor_si128(Ago, _mm_xor_si128(Ako, _mm_xor_si128(Amo, Aso)))); + Cu = _mm_xor_si128(Abu, _mm_xor_si128(Agu, _mm_xor_si128(Aku, _mm_xor_si128(Amu, Asu)))); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[0])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[1])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[2])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[3])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[4])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[5])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[6])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[7])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[8])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[9])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[10])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[11])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[12])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[13])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[14])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[15])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[16])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[17])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[18])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[19])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[20])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[21])); + Ca = Aba; + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Abe; + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Abi; + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Abo; + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Abu; + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Aga); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Age); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Agi); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ago); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Agu); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Aka); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Ake); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Aki); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Ako); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Aku); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ama); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Ame); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Ami); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Amo); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Amu); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Asa); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ase); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Asi); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Aso); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Asu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Aba = _mm_xor_si128(Aba, Da); + Bba = Aba; + Age = _mm_xor_si128(Age, De); + Bbe = ROL64in128(Age, 44); + Aki = _mm_xor_si128(Aki, Di); + Bbi = ROL64in128(Aki, 43); + Eba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Eba = _mm_xor_si128(Eba, SPLAT64(KeccakF1600Constants[22])); + Ca = Eba; + Amo = _mm_xor_si128(Amo, Do); + Bbo = ROL64in128(Amo, 21); + Ebe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Ce = Ebe; + Asu = _mm_xor_si128(Asu, Du); + Bbu = ROL64in128(Asu, 14); + Ebi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Ci = Ebi; + Ebo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Co = Ebo; + Ebu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Cu = Ebu; + Abo = _mm_xor_si128(Abo, Do); + Bga = ROL64in128(Abo, 28); + Agu = _mm_xor_si128(Agu, Du); + Bge = ROL64in128(Agu, 20); + Aka = _mm_xor_si128(Aka, Da); + Bgi = ROL64in128(Aka, 3); + Ega = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Ca = _mm_xor_si128(Ca, Ega); + Ame = _mm_xor_si128(Ame, De); + Bgo = ROL64in128(Ame, 45); + Ege = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Ce = _mm_xor_si128(Ce, Ege); + Asi = _mm_xor_si128(Asi, Di); + Bgu = ROL64in128(Asi, 61); + Egi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ci = _mm_xor_si128(Ci, Egi); + Ego = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Co = _mm_xor_si128(Co, Ego); + Egu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Cu = _mm_xor_si128(Cu, Egu); + Abe = _mm_xor_si128(Abe, De); + Bka = ROL64in128(Abe, 1); + Agi = _mm_xor_si128(Agi, Di); + Bke = ROL64in128(Agi, 6); + Ako = _mm_xor_si128(Ako, Do); + Bki = ROL64in128(Ako, 25); + Eka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Ca = _mm_xor_si128(Ca, Eka); + Amu = _mm_xor_si128(Amu, Du); + Bko = ROL64in128_8(Amu); + Eke = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Ce = _mm_xor_si128(Ce, Eke); + Asa = _mm_xor_si128(Asa, Da); + Bku = ROL64in128(Asa, 18); + Eki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ci = _mm_xor_si128(Ci, Eki); + Eko = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Co = _mm_xor_si128(Co, Eko); + Eku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Cu = _mm_xor_si128(Cu, Eku); + Abu = _mm_xor_si128(Abu, Du); + Bma = ROL64in128(Abu, 27); + Aga = _mm_xor_si128(Aga, Da); + Bme = ROL64in128(Aga, 36); + Ake = _mm_xor_si128(Ake, De); + Bmi = ROL64in128(Ake, 10); + Ema = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Ca = _mm_xor_si128(Ca, Ema); + Ami = _mm_xor_si128(Ami, Di); + Bmo = ROL64in128(Ami, 15); + Eme = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Ce = _mm_xor_si128(Ce, Eme); + Aso = _mm_xor_si128(Aso, Do); + Bmu = ROL64in128_56(Aso); + Emi = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Ci = _mm_xor_si128(Ci, Emi); + Emo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Co = _mm_xor_si128(Co, Emo); + Emu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Cu = _mm_xor_si128(Cu, Emu); + Abi = _mm_xor_si128(Abi, Di); + Bsa = ROL64in128(Abi, 62); + Ago = _mm_xor_si128(Ago, Do); + Bse = ROL64in128(Ago, 55); + Aku = _mm_xor_si128(Aku, Du); + Bsi = ROL64in128(Aku, 39); + Esa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ca = _mm_xor_si128(Ca, Esa); + Ama = _mm_xor_si128(Ama, Da); + Bso = ROL64in128(Ama, 41); + Ese = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ce = _mm_xor_si128(Ce, Ese); + Ase = _mm_xor_si128(Ase, De); + Bsu = ROL64in128(Ase, 2); + Esi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Ci = _mm_xor_si128(Ci, Esi); + Eso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Co = _mm_xor_si128(Co, Eso); + Esu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + Cu = _mm_xor_si128(Cu, Esu); + Da = _mm_xor_si128(Cu, ROL64in128(Ce, 1)); + De = _mm_xor_si128(Ca, ROL64in128(Ci, 1)); + Di = _mm_xor_si128(Ce, ROL64in128(Co, 1)); + Do = _mm_xor_si128(Ci, ROL64in128(Cu, 1)); + Du = _mm_xor_si128(Co, ROL64in128(Ca, 1)); + Eba = _mm_xor_si128(Eba, Da); + Bba = Eba; + Ege = _mm_xor_si128(Ege, De); + Bbe = ROL64in128(Ege, 44); + Eki = _mm_xor_si128(Eki, Di); + Bbi = ROL64in128(Eki, 43); + Aba = _mm_xor_si128(Bba, _mm_andnot_si128(Bbe, Bbi)); + Aba = _mm_xor_si128(Aba, SPLAT64(KeccakF1600Constants[23])); + Emo = _mm_xor_si128(Emo, Do); + Bbo = ROL64in128(Emo, 21); + Abe = _mm_xor_si128(Bbe, _mm_andnot_si128(Bbi, Bbo)); + Esu = _mm_xor_si128(Esu, Du); + Bbu = ROL64in128(Esu, 14); + Abi = _mm_xor_si128(Bbi, _mm_andnot_si128(Bbo, Bbu)); + Abo = _mm_xor_si128(Bbo, _mm_andnot_si128(Bbu, Bba)); + Abu = _mm_xor_si128(Bbu, _mm_andnot_si128(Bba, Bbe)); + Ebo = _mm_xor_si128(Ebo, Do); + Bga = ROL64in128(Ebo, 28); + Egu = _mm_xor_si128(Egu, Du); + Bge = ROL64in128(Egu, 20); + Eka = _mm_xor_si128(Eka, Da); + Bgi = ROL64in128(Eka, 3); + Aga = _mm_xor_si128(Bga, _mm_andnot_si128(Bge, Bgi)); + Eme = _mm_xor_si128(Eme, De); + Bgo = ROL64in128(Eme, 45); + Age = _mm_xor_si128(Bge, _mm_andnot_si128(Bgi, Bgo)); + Esi = _mm_xor_si128(Esi, Di); + Bgu = ROL64in128(Esi, 61); + Agi = _mm_xor_si128(Bgi, _mm_andnot_si128(Bgo, Bgu)); + Ago = _mm_xor_si128(Bgo, _mm_andnot_si128(Bgu, Bga)); + Agu = _mm_xor_si128(Bgu, _mm_andnot_si128(Bga, Bge)); + Ebe = _mm_xor_si128(Ebe, De); + Bka = ROL64in128(Ebe, 1); + Egi = _mm_xor_si128(Egi, Di); + Bke = ROL64in128(Egi, 6); + Eko = _mm_xor_si128(Eko, Do); + Bki = ROL64in128(Eko, 25); + Aka = _mm_xor_si128(Bka, _mm_andnot_si128(Bke, Bki)); + Emu = _mm_xor_si128(Emu, Du); + Bko = ROL64in128_8(Emu); + Ake = _mm_xor_si128(Bke, _mm_andnot_si128(Bki, Bko)); + Esa = _mm_xor_si128(Esa, Da); + Bku = ROL64in128(Esa, 18); + Aki = _mm_xor_si128(Bki, _mm_andnot_si128(Bko, Bku)); + Ako = _mm_xor_si128(Bko, _mm_andnot_si128(Bku, Bka)); + Aku = _mm_xor_si128(Bku, _mm_andnot_si128(Bka, Bke)); + Ebu = _mm_xor_si128(Ebu, Du); + Bma = ROL64in128(Ebu, 27); + Ega = _mm_xor_si128(Ega, Da); + Bme = ROL64in128(Ega, 36); + Eke = _mm_xor_si128(Eke, De); + Bmi = ROL64in128(Eke, 10); + Ama = _mm_xor_si128(Bma, _mm_andnot_si128(Bme, Bmi)); + Emi = _mm_xor_si128(Emi, Di); + Bmo = ROL64in128(Emi, 15); + Ame = _mm_xor_si128(Bme, _mm_andnot_si128(Bmi, Bmo)); + Eso = _mm_xor_si128(Eso, Do); + Bmu = ROL64in128_56(Eso); + Ami = _mm_xor_si128(Bmi, _mm_andnot_si128(Bmo, Bmu)); + Amo = _mm_xor_si128(Bmo, _mm_andnot_si128(Bmu, Bma)); + Amu = _mm_xor_si128(Bmu, _mm_andnot_si128(Bma, Bme)); + Ebi = _mm_xor_si128(Ebi, Di); + Bsa = ROL64in128(Ebi, 62); + Ego = _mm_xor_si128(Ego, Do); + Bse = ROL64in128(Ego, 55); + Eku = _mm_xor_si128(Eku, Du); + Bsi = ROL64in128(Eku, 39); + Asa = _mm_xor_si128(Bsa, _mm_andnot_si128(Bse, Bsi)); + Ema = _mm_xor_si128(Ema, Da); + Bso = ROL64in128(Ema, 41); + Ase = _mm_xor_si128(Bse, _mm_andnot_si128(Bsi, Bso)); + Ese = _mm_xor_si128(Ese, De); + Bsu = ROL64in128(Ese, 2); + Asi = _mm_xor_si128(Bsi, _mm_andnot_si128(Bso, Bsu)); + Aso = _mm_xor_si128(Bso, _mm_andnot_si128(Bsu, Bsa)); + Asu = _mm_xor_si128(Bsu, _mm_andnot_si128(Bsa, Bse)); + + _mm_storeu_si128(M128_CAST(lanes+ 0), Aba); + _mm_storeu_si128(M128_CAST(lanes+ 1), Abe); + _mm_storeu_si128(M128_CAST(lanes+ 2), Abi); + _mm_storeu_si128(M128_CAST(lanes+ 3), Abo); + _mm_storeu_si128(M128_CAST(lanes+ 4), Abu); + _mm_storeu_si128(M128_CAST(lanes+ 5), Aga); + _mm_storeu_si128(M128_CAST(lanes+ 6), Age); + _mm_storeu_si128(M128_CAST(lanes+ 7), Agi); + _mm_storeu_si128(M128_CAST(lanes+ 8), Ago); + _mm_storeu_si128(M128_CAST(lanes+ 9), Agu); + _mm_storeu_si128(M128_CAST(lanes+10), Aka); + _mm_storeu_si128(M128_CAST(lanes+11), Ake); + _mm_storeu_si128(M128_CAST(lanes+12), Aki); + _mm_storeu_si128(M128_CAST(lanes+13), Ako); + _mm_storeu_si128(M128_CAST(lanes+14), Aku); + _mm_storeu_si128(M128_CAST(lanes+15), Ama); + _mm_storeu_si128(M128_CAST(lanes+16), Ame); + _mm_storeu_si128(M128_CAST(lanes+17), Ami); + _mm_storeu_si128(M128_CAST(lanes+18), Amo); + _mm_storeu_si128(M128_CAST(lanes+19), Amu); + _mm_storeu_si128(M128_CAST(lanes+20), Asa); + _mm_storeu_si128(M128_CAST(lanes+21), Ase); + _mm_storeu_si128(M128_CAST(lanes+22), Asi); + _mm_storeu_si128(M128_CAST(lanes+23), Aso); + _mm_storeu_si128(M128_CAST(lanes+24), Asu); +} + +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/lea.cpp b/extension/third_party/cryptopp/lea.cpp new file mode 100644 index 00000000..4361d513 --- /dev/null +++ b/extension/third_party/cryptopp/lea.cpp @@ -0,0 +1,899 @@ +// lea.cpp - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "LEA: A 128-Bit Block Cipher for Fast Encryption on Common +// Processors" by Deukjo Hong, Jung-Keun Lee, Dong-Chan Kim, Daesung Kwon, +// Kwon Ho Ryu, and Dong-Geon Lee. +// +// This implementation is based on source files found in a zip file at the +// Korea Internet and Security Agency (https://www.kisa.or.kr/eng/main.jsp). +// The zip files was downloaded from the Korean language area of the site so we +// don't have a url or english zip filename to cite. The source filename from +// the zip is lea_core.c. +// +// The LEA team appears to have applied optimizations to functions in lea_core.c. +// The implementation does not exactly follow the aglorithmic description from +// the LEA paper. + +#include "pch.h" +#include "config.h" + +#include "lea.h" +#include "misc.h" +#include "cpu.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::rotlConstant; + +ANONYMOUS_NAMESPACE_END + +const word32 delta[8][36] = { + {0xc3efe9db, 0x87dfd3b7, 0x0fbfa76f, 0x1f7f4ede, 0x3efe9dbc, 0x7dfd3b78, 0xfbfa76f0, 0xf7f4ede1, + 0xefe9dbc3, 0xdfd3b787, 0xbfa76f0f, 0x7f4ede1f, 0xfe9dbc3e, 0xfd3b787d, 0xfa76f0fb, 0xf4ede1f7, + 0xe9dbc3ef, 0xd3b787df, 0xa76f0fbf, 0x4ede1f7f, 0x9dbc3efe, 0x3b787dfd, 0x76f0fbfa, 0xede1f7f4, + 0xdbc3efe9, 0xb787dfd3, 0x6f0fbfa7, 0xde1f7f4e, 0xbc3efe9d, 0x787dfd3b, 0xf0fbfa76, 0xe1f7f4eD, + 0xc3efe9db, 0x87dfd3b7, 0x0fbfa76f, 0x1f7f4ede}, + {0x44626b02, 0x88c4d604, 0x1189ac09, 0x23135812, 0x4626b024, 0x8c4d6048, 0x189ac091, 0x31358122, + 0x626b0244, 0xc4d60488, 0x89ac0911, 0x13581223, 0x26b02446, 0x4d60488c, 0x9ac09118, 0x35812231, + 0x6b024462, 0xd60488c4, 0xac091189, 0x58122313, 0xb0244626, 0x60488c4d, 0xc091189a, 0x81223135, + 0x0244626b, 0x0488c4d6, 0x091189ac, 0x12231358, 0x244626b0, 0x488c4d60, 0x91189ac0, 0x22313581, + 0x44626b02, 0x88c4d604, 0x1189ac09, 0x23135812}, + {0x79e27c8a, 0xf3c4f914, 0xe789f229, 0xcf13e453, 0x9e27c8a7, 0x3c4f914f, 0x789f229e, 0xf13e453c, + 0xe27c8a79, 0xc4f914f3, 0x89f229e7, 0x13e453cf, 0x27c8a79e, 0x4f914f3c, 0x9f229e78, 0x3e453cf1, + 0x7c8a79e2, 0xf914f3c4, 0xf229e789, 0xe453cf13, 0xc8a79e27, 0x914f3c4f, 0x229e789f, 0x453cf13e, + 0x8a79e27c, 0x14f3c4f9, 0x29e789f2, 0x53cf13e4, 0xa79e27c8, 0x4f3c4f91, 0x9e789f22, 0x3cf13e45, + 0x79e27c8a, 0xf3c4f914, 0xe789f229, 0xcf13e453}, + {0x78df30ec, 0xf1be61d8, 0xe37cc3b1, 0xc6f98763, 0x8df30ec7, 0x1be61d8f, 0x37cc3b1e, 0x6f98763c, + 0xdf30ec78, 0xbe61d8f1, 0x7cc3b1e3, 0xf98763c6, 0xf30ec78d, 0xe61d8f1b, 0xcc3b1e37, 0x98763c6f, + 0x30ec78df, 0x61d8f1be, 0xc3b1e37c, 0x8763c6f9, 0x0ec78df3, 0x1d8f1be6, 0x3b1e37cc, 0x763c6f98, + 0xec78df30, 0xd8f1be61, 0xb1e37cc3, 0x63c6f987, 0xc78df30e, 0x8f1be61d, 0x1e37cc3b, 0x3c6f9876, + 0x78df30ec, 0xf1be61d8, 0xe37cc3b1, 0xc6f98763}, + {0x715ea49e, 0xe2bd493c, 0xc57a9279, 0x8af524f3, 0x15ea49e7, 0x2bd493ce, 0x57a9279c, 0xaf524f38, + 0x5ea49e71, 0xbd493ce2, 0x7a9279c5, 0xf524f38a, 0xea49e715, 0xd493ce2b, 0xa9279c57, 0x524f38af, + 0xa49e715e, 0x493ce2bd, 0x9279c57a, 0x24f38af5, 0x49e715ea, 0x93ce2bd4, 0x279c57a9, 0x4f38af52, + 0x9e715ea4, 0x3ce2bd49, 0x79c57a92, 0xf38af524, 0xe715ea49, 0xce2bd493, 0x9c57a927, 0x38af524f, + 0x715ea49e, 0xe2bd493c, 0xc57a9279, 0x8af524f3}, + {0xc785da0a, 0x8f0bb415, 0x1e17682b, 0x3c2ed056, 0x785da0ac, 0xf0bb4158, 0xe17682b1, 0xc2ed0563, + 0x85da0ac7, 0x0bb4158f, 0x17682b1e, 0x2ed0563c, 0x5da0ac78, 0xbb4158f0, 0x7682b1e1, 0xed0563c2, + 0xda0ac785, 0xb4158f0b, 0x682b1e17, 0xd0563c2e, 0xa0ac785d, 0x4158f0bb, 0x82b1e176, 0x0563c2ed, + 0x0ac785da, 0x158f0bb4, 0x2b1e1768, 0x563c2ed0, 0xac785da0, 0x58f0bb41, 0xb1e17682, 0x63c2ed05, + 0xc785da0a, 0x8f0bb415, 0x1e17682b, 0x3c2ed056}, + {0xe04ef22a, 0xc09de455, 0x813bc8ab, 0x02779157, 0x04ef22ae, 0x09de455c, 0x13bc8ab8, 0x27791570, + 0x4ef22ae0, 0x9de455c0, 0x3bc8ab81, 0x77915702, 0xef22ae04, 0xde455c09, 0xbc8ab813, 0x79157027, + 0xf22ae04e, 0xe455c09d, 0xc8ab813b, 0x91570277, 0x22ae04ef, 0x455c09de, 0x8ab813bc, 0x15702779, + 0x2ae04ef2, 0x55c09de4, 0xab813bc8, 0x57027791, 0xae04ef22, 0x5c09de45, 0xb813bc8a, 0x70277915, + 0xe04ef22a, 0xc09de455, 0x813bc8ab, 0x02779157}, + {0xe5c40957, 0xcb8812af, 0x9710255f, 0x2e204abf, 0x5c40957e, 0xb8812afc, 0x710255f9, 0xe204abf2, + 0xc40957e5, 0x8812afcb, 0x10255f97, 0x204abf2e, 0x40957e5c, 0x812afcb8, 0x0255f971, 0x04abf2e2, + 0x0957e5c4, 0x12afcb88, 0x255f9710, 0x4abf2e20, 0x957e5c40, 0x2afcb881, 0x55f97102, 0xabf2e204, + 0x57e5c409, 0xafcb8812, 0x5f971025, 0xbf2e204a, 0x7e5c4095, 0xfcb8812a, 0xf9710255, 0xf2e204ab, + 0xe5c40957, 0xcb8812af, 0x9710255f, 0x2e204abf} +}; + +inline void SetKey128(word32 rkey[144], const word32 key[4]) +{ + rkey[ 0] = rotlConstant<1>( key[ 0] + delta[0][ 0]); + rkey[ 6] = rotlConstant<1>(rkey[ 0] + delta[1][ 1]); + rkey[ 12] = rotlConstant<1>(rkey[ 6] + delta[2][ 2]); + rkey[ 18] = rotlConstant<1>(rkey[ 12] + delta[3][ 3]); + rkey[ 24] = rotlConstant<1>(rkey[ 18] + delta[0][ 4]); + rkey[ 30] = rotlConstant<1>(rkey[ 24] + delta[1][ 5]); + rkey[ 36] = rotlConstant<1>(rkey[ 30] + delta[2][ 6]); + rkey[ 42] = rotlConstant<1>(rkey[ 36] + delta[3][ 7]); + rkey[ 48] = rotlConstant<1>(rkey[ 42] + delta[0][ 8]); + rkey[ 54] = rotlConstant<1>(rkey[ 48] + delta[1][ 9]); + rkey[ 60] = rotlConstant<1>(rkey[ 54] + delta[2][10]); + rkey[ 66] = rotlConstant<1>(rkey[ 60] + delta[3][11]); + rkey[ 72] = rotlConstant<1>(rkey[ 66] + delta[0][12]); + rkey[ 78] = rotlConstant<1>(rkey[ 72] + delta[1][13]); + rkey[ 84] = rotlConstant<1>(rkey[ 78] + delta[2][14]); + rkey[ 90] = rotlConstant<1>(rkey[ 84] + delta[3][15]); + rkey[ 96] = rotlConstant<1>(rkey[ 90] + delta[0][16]); + rkey[102] = rotlConstant<1>(rkey[ 96] + delta[1][17]); + rkey[108] = rotlConstant<1>(rkey[102] + delta[2][18]); + rkey[114] = rotlConstant<1>(rkey[108] + delta[3][19]); + rkey[120] = rotlConstant<1>(rkey[114] + delta[0][20]); + rkey[126] = rotlConstant<1>(rkey[120] + delta[1][21]); + rkey[132] = rotlConstant<1>(rkey[126] + delta[2][22]); + rkey[138] = rotlConstant<1>(rkey[132] + delta[3][23]); + + rkey[ 1] = rkey[ 3] = rkey[ 5] = rotlConstant<3>( key[ 1] + delta[0][ 1]); + rkey[ 7] = rkey[ 9] = rkey[ 11] = rotlConstant<3>(rkey[ 1] + delta[1][ 2]); + rkey[ 13] = rkey[ 15] = rkey[ 17] = rotlConstant<3>(rkey[ 7] + delta[2][ 3]); + rkey[ 19] = rkey[ 21] = rkey[ 23] = rotlConstant<3>(rkey[ 13] + delta[3][ 4]); + rkey[ 25] = rkey[ 27] = rkey[ 29] = rotlConstant<3>(rkey[ 19] + delta[0][ 5]); + rkey[ 31] = rkey[ 33] = rkey[ 35] = rotlConstant<3>(rkey[ 25] + delta[1][ 6]); + rkey[ 37] = rkey[ 39] = rkey[ 41] = rotlConstant<3>(rkey[ 31] + delta[2][ 7]); + rkey[ 43] = rkey[ 45] = rkey[ 47] = rotlConstant<3>(rkey[ 37] + delta[3][ 8]); + rkey[ 49] = rkey[ 51] = rkey[ 53] = rotlConstant<3>(rkey[ 43] + delta[0][ 9]); + rkey[ 55] = rkey[ 57] = rkey[ 59] = rotlConstant<3>(rkey[ 49] + delta[1][10]); + rkey[ 61] = rkey[ 63] = rkey[ 65] = rotlConstant<3>(rkey[ 55] + delta[2][11]); + rkey[ 67] = rkey[ 69] = rkey[ 71] = rotlConstant<3>(rkey[ 61] + delta[3][12]); + rkey[ 73] = rkey[ 75] = rkey[ 77] = rotlConstant<3>(rkey[ 67] + delta[0][13]); + rkey[ 79] = rkey[ 81] = rkey[ 83] = rotlConstant<3>(rkey[ 73] + delta[1][14]); + rkey[ 85] = rkey[ 87] = rkey[ 89] = rotlConstant<3>(rkey[ 79] + delta[2][15]); + rkey[ 91] = rkey[ 93] = rkey[ 95] = rotlConstant<3>(rkey[ 85] + delta[3][16]); + rkey[ 97] = rkey[ 99] = rkey[101] = rotlConstant<3>(rkey[ 91] + delta[0][17]); + rkey[103] = rkey[105] = rkey[107] = rotlConstant<3>(rkey[ 97] + delta[1][18]); + rkey[109] = rkey[111] = rkey[113] = rotlConstant<3>(rkey[103] + delta[2][19]); + rkey[115] = rkey[117] = rkey[119] = rotlConstant<3>(rkey[109] + delta[3][20]); + rkey[121] = rkey[123] = rkey[125] = rotlConstant<3>(rkey[115] + delta[0][21]); + rkey[127] = rkey[129] = rkey[131] = rotlConstant<3>(rkey[121] + delta[1][22]); + rkey[133] = rkey[135] = rkey[137] = rotlConstant<3>(rkey[127] + delta[2][23]); + rkey[139] = rkey[141] = rkey[143] = rotlConstant<3>(rkey[133] + delta[3][24]); + + rkey[ 2] = rotlConstant<6>( key[ 2] + delta[0][ 2]); + rkey[ 8] = rotlConstant<6>(rkey[ 2] + delta[1][ 3]); + rkey[ 14] = rotlConstant<6>(rkey[ 8] + delta[2][ 4]); + rkey[ 20] = rotlConstant<6>(rkey[ 14] + delta[3][ 5]); + rkey[ 26] = rotlConstant<6>(rkey[ 20] + delta[0][ 6]); + rkey[ 32] = rotlConstant<6>(rkey[ 26] + delta[1][ 7]); + rkey[ 38] = rotlConstant<6>(rkey[ 32] + delta[2][ 8]); + rkey[ 44] = rotlConstant<6>(rkey[ 38] + delta[3][ 9]); + rkey[ 50] = rotlConstant<6>(rkey[ 44] + delta[0][10]); + rkey[ 56] = rotlConstant<6>(rkey[ 50] + delta[1][11]); + rkey[ 62] = rotlConstant<6>(rkey[ 56] + delta[2][12]); + rkey[ 68] = rotlConstant<6>(rkey[ 62] + delta[3][13]); + rkey[ 74] = rotlConstant<6>(rkey[ 68] + delta[0][14]); + rkey[ 80] = rotlConstant<6>(rkey[ 74] + delta[1][15]); + rkey[ 86] = rotlConstant<6>(rkey[ 80] + delta[2][16]); + rkey[ 92] = rotlConstant<6>(rkey[ 86] + delta[3][17]); + rkey[ 98] = rotlConstant<6>(rkey[ 92] + delta[0][18]); + rkey[104] = rotlConstant<6>(rkey[ 98] + delta[1][19]); + rkey[110] = rotlConstant<6>(rkey[104] + delta[2][20]); + rkey[116] = rotlConstant<6>(rkey[110] + delta[3][21]); + rkey[122] = rotlConstant<6>(rkey[116] + delta[0][22]); + rkey[128] = rotlConstant<6>(rkey[122] + delta[1][23]); + rkey[134] = rotlConstant<6>(rkey[128] + delta[2][24]); + rkey[140] = rotlConstant<6>(rkey[134] + delta[3][25]); + + rkey[ 4] = rotlConstant<11>( key[ 3] + delta[0][ 3]); + rkey[ 10] = rotlConstant<11>(rkey[ 4] + delta[1][ 4]); + rkey[ 16] = rotlConstant<11>(rkey[ 10] + delta[2][ 5]); + rkey[ 22] = rotlConstant<11>(rkey[ 16] + delta[3][ 6]); + rkey[ 28] = rotlConstant<11>(rkey[ 22] + delta[0][ 7]); + rkey[ 34] = rotlConstant<11>(rkey[ 28] + delta[1][ 8]); + rkey[ 40] = rotlConstant<11>(rkey[ 34] + delta[2][ 9]); + rkey[ 46] = rotlConstant<11>(rkey[ 40] + delta[3][10]); + rkey[ 52] = rotlConstant<11>(rkey[ 46] + delta[0][11]); + rkey[ 58] = rotlConstant<11>(rkey[ 52] + delta[1][12]); + rkey[ 64] = rotlConstant<11>(rkey[ 58] + delta[2][13]); + rkey[ 70] = rotlConstant<11>(rkey[ 64] + delta[3][14]); + rkey[ 76] = rotlConstant<11>(rkey[ 70] + delta[0][15]); + rkey[ 82] = rotlConstant<11>(rkey[ 76] + delta[1][16]); + rkey[ 88] = rotlConstant<11>(rkey[ 82] + delta[2][17]); + rkey[ 94] = rotlConstant<11>(rkey[ 88] + delta[3][18]); + rkey[100] = rotlConstant<11>(rkey[ 94] + delta[0][19]); + rkey[106] = rotlConstant<11>(rkey[100] + delta[1][20]); + rkey[112] = rotlConstant<11>(rkey[106] + delta[2][21]); + rkey[118] = rotlConstant<11>(rkey[112] + delta[3][22]); + rkey[124] = rotlConstant<11>(rkey[118] + delta[0][23]); + rkey[130] = rotlConstant<11>(rkey[124] + delta[1][24]); + rkey[136] = rotlConstant<11>(rkey[130] + delta[2][25]); + rkey[142] = rotlConstant<11>(rkey[136] + delta[3][26]); +} + +inline void SetKey192(word32 rkey[168], const word32 key[6]) +{ + rkey[ 0] = rotlConstant<1>( key[ 0] + delta[0][ 0]); + rkey[ 6] = rotlConstant<1>(rkey[ 0] + delta[1][ 1]); + rkey[ 12] = rotlConstant<1>(rkey[ 6] + delta[2][ 2]); + rkey[ 18] = rotlConstant<1>(rkey[ 12] + delta[3][ 3]); + rkey[ 24] = rotlConstant<1>(rkey[ 18] + delta[4][ 4]); + rkey[ 30] = rotlConstant<1>(rkey[ 24] + delta[5][ 5]); + rkey[ 36] = rotlConstant<1>(rkey[ 30] + delta[0][ 6]); + rkey[ 42] = rotlConstant<1>(rkey[ 36] + delta[1][ 7]); + rkey[ 48] = rotlConstant<1>(rkey[ 42] + delta[2][ 8]); + rkey[ 54] = rotlConstant<1>(rkey[ 48] + delta[3][ 9]); + rkey[ 60] = rotlConstant<1>(rkey[ 54] + delta[4][10]); + rkey[ 66] = rotlConstant<1>(rkey[ 60] + delta[5][11]); + rkey[ 72] = rotlConstant<1>(rkey[ 66] + delta[0][12]); + rkey[ 78] = rotlConstant<1>(rkey[ 72] + delta[1][13]); + rkey[ 84] = rotlConstant<1>(rkey[ 78] + delta[2][14]); + rkey[ 90] = rotlConstant<1>(rkey[ 84] + delta[3][15]); + rkey[ 96] = rotlConstant<1>(rkey[ 90] + delta[4][16]); + rkey[102] = rotlConstant<1>(rkey[ 96] + delta[5][17]); + rkey[108] = rotlConstant<1>(rkey[102] + delta[0][18]); + rkey[114] = rotlConstant<1>(rkey[108] + delta[1][19]); + rkey[120] = rotlConstant<1>(rkey[114] + delta[2][20]); + rkey[126] = rotlConstant<1>(rkey[120] + delta[3][21]); + rkey[132] = rotlConstant<1>(rkey[126] + delta[4][22]); + rkey[138] = rotlConstant<1>(rkey[132] + delta[5][23]); + rkey[144] = rotlConstant<1>(rkey[138] + delta[0][24]); + rkey[150] = rotlConstant<1>(rkey[144] + delta[1][25]); + rkey[156] = rotlConstant<1>(rkey[150] + delta[2][26]); + rkey[162] = rotlConstant<1>(rkey[156] + delta[3][27]); + + rkey[ 1] = rotlConstant<3>( key[ 1] + delta[0][ 1]); + rkey[ 7] = rotlConstant<3>(rkey[ 1] + delta[1][ 2]); + rkey[ 13] = rotlConstant<3>(rkey[ 7] + delta[2][ 3]); + rkey[ 19] = rotlConstant<3>(rkey[ 13] + delta[3][ 4]); + rkey[ 25] = rotlConstant<3>(rkey[ 19] + delta[4][ 5]); + rkey[ 31] = rotlConstant<3>(rkey[ 25] + delta[5][ 6]); + rkey[ 37] = rotlConstant<3>(rkey[ 31] + delta[0][ 7]); + rkey[ 43] = rotlConstant<3>(rkey[ 37] + delta[1][ 8]); + rkey[ 49] = rotlConstant<3>(rkey[ 43] + delta[2][ 9]); + rkey[ 55] = rotlConstant<3>(rkey[ 49] + delta[3][10]); + rkey[ 61] = rotlConstant<3>(rkey[ 55] + delta[4][11]); + rkey[ 67] = rotlConstant<3>(rkey[ 61] + delta[5][12]); + rkey[ 73] = rotlConstant<3>(rkey[ 67] + delta[0][13]); + rkey[ 79] = rotlConstant<3>(rkey[ 73] + delta[1][14]); + rkey[ 85] = rotlConstant<3>(rkey[ 79] + delta[2][15]); + rkey[ 91] = rotlConstant<3>(rkey[ 85] + delta[3][16]); + rkey[ 97] = rotlConstant<3>(rkey[ 91] + delta[4][17]); + rkey[103] = rotlConstant<3>(rkey[ 97] + delta[5][18]); + rkey[109] = rotlConstant<3>(rkey[103] + delta[0][19]); + rkey[115] = rotlConstant<3>(rkey[109] + delta[1][20]); + rkey[121] = rotlConstant<3>(rkey[115] + delta[2][21]); + rkey[127] = rotlConstant<3>(rkey[121] + delta[3][22]); + rkey[133] = rotlConstant<3>(rkey[127] + delta[4][23]); + rkey[139] = rotlConstant<3>(rkey[133] + delta[5][24]); + rkey[145] = rotlConstant<3>(rkey[139] + delta[0][25]); + rkey[151] = rotlConstant<3>(rkey[145] + delta[1][26]); + rkey[157] = rotlConstant<3>(rkey[151] + delta[2][27]); + rkey[163] = rotlConstant<3>(rkey[157] + delta[3][28]); + + rkey[ 2] = rotlConstant<6>( key[ 2] + delta[0][ 2]); + rkey[ 8] = rotlConstant<6>(rkey[ 2] + delta[1][ 3]); + rkey[ 14] = rotlConstant<6>(rkey[ 8] + delta[2][ 4]); + rkey[ 20] = rotlConstant<6>(rkey[ 14] + delta[3][ 5]); + rkey[ 26] = rotlConstant<6>(rkey[ 20] + delta[4][ 6]); + rkey[ 32] = rotlConstant<6>(rkey[ 26] + delta[5][ 7]); + rkey[ 38] = rotlConstant<6>(rkey[ 32] + delta[0][ 8]); + rkey[ 44] = rotlConstant<6>(rkey[ 38] + delta[1][ 9]); + rkey[ 50] = rotlConstant<6>(rkey[ 44] + delta[2][10]); + rkey[ 56] = rotlConstant<6>(rkey[ 50] + delta[3][11]); + rkey[ 62] = rotlConstant<6>(rkey[ 56] + delta[4][12]); + rkey[ 68] = rotlConstant<6>(rkey[ 62] + delta[5][13]); + rkey[ 74] = rotlConstant<6>(rkey[ 68] + delta[0][14]); + rkey[ 80] = rotlConstant<6>(rkey[ 74] + delta[1][15]); + rkey[ 86] = rotlConstant<6>(rkey[ 80] + delta[2][16]); + rkey[ 92] = rotlConstant<6>(rkey[ 86] + delta[3][17]); + rkey[ 98] = rotlConstant<6>(rkey[ 92] + delta[4][18]); + rkey[104] = rotlConstant<6>(rkey[ 98] + delta[5][19]); + rkey[110] = rotlConstant<6>(rkey[104] + delta[0][20]); + rkey[116] = rotlConstant<6>(rkey[110] + delta[1][21]); + rkey[122] = rotlConstant<6>(rkey[116] + delta[2][22]); + rkey[128] = rotlConstant<6>(rkey[122] + delta[3][23]); + rkey[134] = rotlConstant<6>(rkey[128] + delta[4][24]); + rkey[140] = rotlConstant<6>(rkey[134] + delta[5][25]); + rkey[146] = rotlConstant<6>(rkey[140] + delta[0][26]); + rkey[152] = rotlConstant<6>(rkey[146] + delta[1][27]); + rkey[158] = rotlConstant<6>(rkey[152] + delta[2][28]); + rkey[164] = rotlConstant<6>(rkey[158] + delta[3][29]); + + rkey[ 3] = rotlConstant<11>( key[ 3] + delta[0][ 3]); + rkey[ 9] = rotlConstant<11>(rkey[ 3] + delta[1][ 4]); + rkey[ 15] = rotlConstant<11>(rkey[ 9] + delta[2][ 5]); + rkey[ 21] = rotlConstant<11>(rkey[ 15] + delta[3][ 6]); + rkey[ 27] = rotlConstant<11>(rkey[ 21] + delta[4][ 7]); + rkey[ 33] = rotlConstant<11>(rkey[ 27] + delta[5][ 8]); + rkey[ 39] = rotlConstant<11>(rkey[ 33] + delta[0][ 9]); + rkey[ 45] = rotlConstant<11>(rkey[ 39] + delta[1][10]); + rkey[ 51] = rotlConstant<11>(rkey[ 45] + delta[2][11]); + rkey[ 57] = rotlConstant<11>(rkey[ 51] + delta[3][12]); + rkey[ 63] = rotlConstant<11>(rkey[ 57] + delta[4][13]); + rkey[ 69] = rotlConstant<11>(rkey[ 63] + delta[5][14]); + rkey[ 75] = rotlConstant<11>(rkey[ 69] + delta[0][15]); + rkey[ 81] = rotlConstant<11>(rkey[ 75] + delta[1][16]); + rkey[ 87] = rotlConstant<11>(rkey[ 81] + delta[2][17]); + rkey[ 93] = rotlConstant<11>(rkey[ 87] + delta[3][18]); + rkey[ 99] = rotlConstant<11>(rkey[ 93] + delta[4][19]); + rkey[105] = rotlConstant<11>(rkey[ 99] + delta[5][20]); + rkey[111] = rotlConstant<11>(rkey[105] + delta[0][21]); + rkey[117] = rotlConstant<11>(rkey[111] + delta[1][22]); + rkey[123] = rotlConstant<11>(rkey[117] + delta[2][23]); + rkey[129] = rotlConstant<11>(rkey[123] + delta[3][24]); + rkey[135] = rotlConstant<11>(rkey[129] + delta[4][25]); + rkey[141] = rotlConstant<11>(rkey[135] + delta[5][26]); + rkey[147] = rotlConstant<11>(rkey[141] + delta[0][27]); + rkey[153] = rotlConstant<11>(rkey[147] + delta[1][28]); + rkey[159] = rotlConstant<11>(rkey[153] + delta[2][29]); + rkey[165] = rotlConstant<11>(rkey[159] + delta[3][30]); + + rkey[ 4] = rotlConstant<13>( key[ 4] + delta[0][ 4]); + rkey[ 10] = rotlConstant<13>(rkey[ 4] + delta[1][ 5]); + rkey[ 16] = rotlConstant<13>(rkey[ 10] + delta[2][ 6]); + rkey[ 22] = rotlConstant<13>(rkey[ 16] + delta[3][ 7]); + rkey[ 28] = rotlConstant<13>(rkey[ 22] + delta[4][ 8]); + rkey[ 34] = rotlConstant<13>(rkey[ 28] + delta[5][ 9]); + rkey[ 40] = rotlConstant<13>(rkey[ 34] + delta[0][10]); + rkey[ 46] = rotlConstant<13>(rkey[ 40] + delta[1][11]); + rkey[ 52] = rotlConstant<13>(rkey[ 46] + delta[2][12]); + rkey[ 58] = rotlConstant<13>(rkey[ 52] + delta[3][13]); + rkey[ 64] = rotlConstant<13>(rkey[ 58] + delta[4][14]); + rkey[ 70] = rotlConstant<13>(rkey[ 64] + delta[5][15]); + rkey[ 76] = rotlConstant<13>(rkey[ 70] + delta[0][16]); + rkey[ 82] = rotlConstant<13>(rkey[ 76] + delta[1][17]); + rkey[ 88] = rotlConstant<13>(rkey[ 82] + delta[2][18]); + rkey[ 94] = rotlConstant<13>(rkey[ 88] + delta[3][19]); + rkey[100] = rotlConstant<13>(rkey[ 94] + delta[4][20]); + rkey[106] = rotlConstant<13>(rkey[100] + delta[5][21]); + rkey[112] = rotlConstant<13>(rkey[106] + delta[0][22]); + rkey[118] = rotlConstant<13>(rkey[112] + delta[1][23]); + rkey[124] = rotlConstant<13>(rkey[118] + delta[2][24]); + rkey[130] = rotlConstant<13>(rkey[124] + delta[3][25]); + rkey[136] = rotlConstant<13>(rkey[130] + delta[4][26]); + rkey[142] = rotlConstant<13>(rkey[136] + delta[5][27]); + rkey[148] = rotlConstant<13>(rkey[142] + delta[0][28]); + rkey[154] = rotlConstant<13>(rkey[148] + delta[1][29]); + rkey[160] = rotlConstant<13>(rkey[154] + delta[2][30]); + rkey[166] = rotlConstant<13>(rkey[160] + delta[3][31]); + + rkey[ 5] = rotlConstant<17>( key[ 5] + delta[0][ 5]); + rkey[ 11] = rotlConstant<17>(rkey[ 5] + delta[1][ 6]); + rkey[ 17] = rotlConstant<17>(rkey[ 11] + delta[2][ 7]); + rkey[ 23] = rotlConstant<17>(rkey[ 17] + delta[3][ 8]); + rkey[ 29] = rotlConstant<17>(rkey[ 23] + delta[4][ 9]); + rkey[ 35] = rotlConstant<17>(rkey[ 29] + delta[5][10]); + rkey[ 41] = rotlConstant<17>(rkey[ 35] + delta[0][11]); + rkey[ 47] = rotlConstant<17>(rkey[ 41] + delta[1][12]); + rkey[ 53] = rotlConstant<17>(rkey[ 47] + delta[2][13]); + rkey[ 59] = rotlConstant<17>(rkey[ 53] + delta[3][14]); + rkey[ 65] = rotlConstant<17>(rkey[ 59] + delta[4][15]); + rkey[ 71] = rotlConstant<17>(rkey[ 65] + delta[5][16]); + rkey[ 77] = rotlConstant<17>(rkey[ 71] + delta[0][17]); + rkey[ 83] = rotlConstant<17>(rkey[ 77] + delta[1][18]); + rkey[ 89] = rotlConstant<17>(rkey[ 83] + delta[2][19]); + rkey[ 95] = rotlConstant<17>(rkey[ 89] + delta[3][20]); + rkey[101] = rotlConstant<17>(rkey[ 95] + delta[4][21]); + rkey[107] = rotlConstant<17>(rkey[101] + delta[5][22]); + rkey[113] = rotlConstant<17>(rkey[107] + delta[0][23]); + rkey[119] = rotlConstant<17>(rkey[113] + delta[1][24]); + rkey[125] = rotlConstant<17>(rkey[119] + delta[2][25]); + rkey[131] = rotlConstant<17>(rkey[125] + delta[3][26]); + rkey[137] = rotlConstant<17>(rkey[131] + delta[4][27]); + rkey[143] = rotlConstant<17>(rkey[137] + delta[5][28]); + rkey[149] = rotlConstant<17>(rkey[143] + delta[0][29]); + rkey[155] = rotlConstant<17>(rkey[149] + delta[1][30]); + rkey[161] = rotlConstant<17>(rkey[155] + delta[2][31]); + rkey[167] = rotlConstant<17>(rkey[161] + delta[3][ 0]); +} + +inline void SetKey256(word32 rkey[192], const word32 key[8]) +{ + rkey[ 0] = rotlConstant< 1>( key[ 0] + delta[0][ 0]); + rkey[ 8] = rotlConstant< 6>(rkey[ 0] + delta[1][ 3]); + rkey[ 16] = rotlConstant<13>(rkey[ 8] + delta[2][ 6]); + rkey[ 24] = rotlConstant< 1>(rkey[ 16] + delta[4][ 4]); + rkey[ 32] = rotlConstant< 6>(rkey[ 24] + delta[5][ 7]); + rkey[ 40] = rotlConstant<13>(rkey[ 32] + delta[6][10]); + rkey[ 48] = rotlConstant< 1>(rkey[ 40] + delta[0][ 8]); + rkey[ 56] = rotlConstant< 6>(rkey[ 48] + delta[1][11]); + rkey[ 64] = rotlConstant<13>(rkey[ 56] + delta[2][14]); + rkey[ 72] = rotlConstant< 1>(rkey[ 64] + delta[4][12]); + rkey[ 80] = rotlConstant< 6>(rkey[ 72] + delta[5][15]); + rkey[ 88] = rotlConstant<13>(rkey[ 80] + delta[6][18]); + rkey[ 96] = rotlConstant< 1>(rkey[ 88] + delta[0][16]); + rkey[104] = rotlConstant< 6>(rkey[ 96] + delta[1][19]); + rkey[112] = rotlConstant<13>(rkey[104] + delta[2][22]); + rkey[120] = rotlConstant< 1>(rkey[112] + delta[4][20]); + rkey[128] = rotlConstant< 6>(rkey[120] + delta[5][23]); + rkey[136] = rotlConstant<13>(rkey[128] + delta[6][26]); + rkey[144] = rotlConstant< 1>(rkey[136] + delta[0][24]); + rkey[152] = rotlConstant< 6>(rkey[144] + delta[1][27]); + rkey[160] = rotlConstant<13>(rkey[152] + delta[2][30]); + rkey[168] = rotlConstant< 1>(rkey[160] + delta[4][28]); + rkey[176] = rotlConstant< 6>(rkey[168] + delta[5][31]); + rkey[184] = rotlConstant<13>(rkey[176] + delta[6][ 2]); + + rkey[ 1] = rotlConstant< 3>( key[ 1] + delta[0][ 1]); + rkey[ 9] = rotlConstant<11>(rkey[ 1] + delta[1][ 4]); + rkey[ 17] = rotlConstant<17>(rkey[ 9] + delta[2][ 7]); + rkey[ 25] = rotlConstant< 3>(rkey[ 17] + delta[4][ 5]); + rkey[ 33] = rotlConstant<11>(rkey[ 25] + delta[5][ 8]); + rkey[ 41] = rotlConstant<17>(rkey[ 33] + delta[6][11]); + rkey[ 49] = rotlConstant< 3>(rkey[ 41] + delta[0][ 9]); + rkey[ 57] = rotlConstant<11>(rkey[ 49] + delta[1][12]); + rkey[ 65] = rotlConstant<17>(rkey[ 57] + delta[2][15]); + rkey[ 73] = rotlConstant< 3>(rkey[ 65] + delta[4][13]); + rkey[ 81] = rotlConstant<11>(rkey[ 73] + delta[5][16]); + rkey[ 89] = rotlConstant<17>(rkey[ 81] + delta[6][19]); + rkey[ 97] = rotlConstant< 3>(rkey[ 89] + delta[0][17]); + rkey[105] = rotlConstant<11>(rkey[ 97] + delta[1][20]); + rkey[113] = rotlConstant<17>(rkey[105] + delta[2][23]); + rkey[121] = rotlConstant< 3>(rkey[113] + delta[4][21]); + rkey[129] = rotlConstant<11>(rkey[121] + delta[5][24]); + rkey[137] = rotlConstant<17>(rkey[129] + delta[6][27]); + rkey[145] = rotlConstant< 3>(rkey[137] + delta[0][25]); + rkey[153] = rotlConstant<11>(rkey[145] + delta[1][28]); + rkey[161] = rotlConstant<17>(rkey[153] + delta[2][31]); + rkey[169] = rotlConstant< 3>(rkey[161] + delta[4][29]); + rkey[177] = rotlConstant<11>(rkey[169] + delta[5][ 0]); + rkey[185] = rotlConstant<17>(rkey[177] + delta[6][ 3]); + + rkey[ 2] = rotlConstant< 6>( key[ 2] + delta[0][ 2]); + rkey[ 10] = rotlConstant<13>(rkey[ 2] + delta[1][ 5]); + rkey[ 18] = rotlConstant< 1>(rkey[ 10] + delta[3][ 3]); + rkey[ 26] = rotlConstant< 6>(rkey[ 18] + delta[4][ 6]); + rkey[ 34] = rotlConstant<13>(rkey[ 26] + delta[5][ 9]); + rkey[ 42] = rotlConstant< 1>(rkey[ 34] + delta[7][ 7]); + rkey[ 50] = rotlConstant< 6>(rkey[ 42] + delta[0][10]); + rkey[ 58] = rotlConstant<13>(rkey[ 50] + delta[1][13]); + rkey[ 66] = rotlConstant< 1>(rkey[ 58] + delta[3][11]); + rkey[ 74] = rotlConstant< 6>(rkey[ 66] + delta[4][14]); + rkey[ 82] = rotlConstant<13>(rkey[ 74] + delta[5][17]); + rkey[ 90] = rotlConstant< 1>(rkey[ 82] + delta[7][15]); + rkey[ 98] = rotlConstant< 6>(rkey[ 90] + delta[0][18]); + rkey[106] = rotlConstant<13>(rkey[ 98] + delta[1][21]); + rkey[114] = rotlConstant< 1>(rkey[106] + delta[3][19]); + rkey[122] = rotlConstant< 6>(rkey[114] + delta[4][22]); + rkey[130] = rotlConstant<13>(rkey[122] + delta[5][25]); + rkey[138] = rotlConstant< 1>(rkey[130] + delta[7][23]); + rkey[146] = rotlConstant< 6>(rkey[138] + delta[0][26]); + rkey[154] = rotlConstant<13>(rkey[146] + delta[1][29]); + rkey[162] = rotlConstant< 1>(rkey[154] + delta[3][27]); + rkey[170] = rotlConstant< 6>(rkey[162] + delta[4][30]); + rkey[178] = rotlConstant<13>(rkey[170] + delta[5][ 1]); + rkey[186] = rotlConstant< 1>(rkey[178] + delta[7][31]); + + rkey[ 3] = rotlConstant<11>( key[ 3] + delta[0][ 3]); + rkey[ 11] = rotlConstant<17>(rkey[ 3] + delta[1][ 6]); + rkey[ 19] = rotlConstant< 3>(rkey[ 11] + delta[3][ 4]); + rkey[ 27] = rotlConstant<11>(rkey[ 19] + delta[4][ 7]); + rkey[ 35] = rotlConstant<17>(rkey[ 27] + delta[5][10]); + rkey[ 43] = rotlConstant< 3>(rkey[ 35] + delta[7][ 8]); + rkey[ 51] = rotlConstant<11>(rkey[ 43] + delta[0][11]); + rkey[ 59] = rotlConstant<17>(rkey[ 51] + delta[1][14]); + rkey[ 67] = rotlConstant< 3>(rkey[ 59] + delta[3][12]); + rkey[ 75] = rotlConstant<11>(rkey[ 67] + delta[4][15]); + rkey[ 83] = rotlConstant<17>(rkey[ 75] + delta[5][18]); + rkey[ 91] = rotlConstant< 3>(rkey[ 83] + delta[7][16]); + rkey[ 99] = rotlConstant<11>(rkey[ 91] + delta[0][19]); + rkey[107] = rotlConstant<17>(rkey[ 99] + delta[1][22]); + rkey[115] = rotlConstant< 3>(rkey[107] + delta[3][20]); + rkey[123] = rotlConstant<11>(rkey[115] + delta[4][23]); + rkey[131] = rotlConstant<17>(rkey[123] + delta[5][26]); + rkey[139] = rotlConstant< 3>(rkey[131] + delta[7][24]); + rkey[147] = rotlConstant<11>(rkey[139] + delta[0][27]); + rkey[155] = rotlConstant<17>(rkey[147] + delta[1][30]); + rkey[163] = rotlConstant< 3>(rkey[155] + delta[3][28]); + rkey[171] = rotlConstant<11>(rkey[163] + delta[4][31]); + rkey[179] = rotlConstant<17>(rkey[171] + delta[5][ 2]); + rkey[187] = rotlConstant< 3>(rkey[179] + delta[7][ 0]); + + rkey[ 4] = rotlConstant<13>( key[ 4] + delta[0][ 4]); + rkey[ 12] = rotlConstant< 1>(rkey[ 4] + delta[2][ 2]); + rkey[ 20] = rotlConstant< 6>(rkey[ 12] + delta[3][ 5]); + rkey[ 28] = rotlConstant<13>(rkey[ 20] + delta[4][ 8]); + rkey[ 36] = rotlConstant< 1>(rkey[ 28] + delta[6][ 6]); + rkey[ 44] = rotlConstant< 6>(rkey[ 36] + delta[7][ 9]); + rkey[ 52] = rotlConstant<13>(rkey[ 44] + delta[0][12]); + rkey[ 60] = rotlConstant< 1>(rkey[ 52] + delta[2][10]); + rkey[ 68] = rotlConstant< 6>(rkey[ 60] + delta[3][13]); + rkey[ 76] = rotlConstant<13>(rkey[ 68] + delta[4][16]); + rkey[ 84] = rotlConstant< 1>(rkey[ 76] + delta[6][14]); + rkey[ 92] = rotlConstant< 6>(rkey[ 84] + delta[7][17]); + rkey[100] = rotlConstant<13>(rkey[ 92] + delta[0][20]); + rkey[108] = rotlConstant< 1>(rkey[100] + delta[2][18]); + rkey[116] = rotlConstant< 6>(rkey[108] + delta[3][21]); + rkey[124] = rotlConstant<13>(rkey[116] + delta[4][24]); + rkey[132] = rotlConstant< 1>(rkey[124] + delta[6][22]); + rkey[140] = rotlConstant< 6>(rkey[132] + delta[7][25]); + rkey[148] = rotlConstant<13>(rkey[140] + delta[0][28]); + rkey[156] = rotlConstant< 1>(rkey[148] + delta[2][26]); + rkey[164] = rotlConstant< 6>(rkey[156] + delta[3][29]); + rkey[172] = rotlConstant<13>(rkey[164] + delta[4][ 0]); + rkey[180] = rotlConstant< 1>(rkey[172] + delta[6][30]); + rkey[188] = rotlConstant< 6>(rkey[180] + delta[7][ 1]); + + rkey[ 5] = rotlConstant<17>( key[ 5] + delta[0][ 5]); + rkey[ 13] = rotlConstant< 3>(rkey[ 5] + delta[2][ 3]); + rkey[ 21] = rotlConstant<11>(rkey[ 13] + delta[3][ 6]); + rkey[ 29] = rotlConstant<17>(rkey[ 21] + delta[4][ 9]); + rkey[ 37] = rotlConstant< 3>(rkey[ 29] + delta[6][ 7]); + rkey[ 45] = rotlConstant<11>(rkey[ 37] + delta[7][10]); + rkey[ 53] = rotlConstant<17>(rkey[ 45] + delta[0][13]); + rkey[ 61] = rotlConstant< 3>(rkey[ 53] + delta[2][11]); + rkey[ 69] = rotlConstant<11>(rkey[ 61] + delta[3][14]); + rkey[ 77] = rotlConstant<17>(rkey[ 69] + delta[4][17]); + rkey[ 85] = rotlConstant< 3>(rkey[ 77] + delta[6][15]); + rkey[ 93] = rotlConstant<11>(rkey[ 85] + delta[7][18]); + rkey[101] = rotlConstant<17>(rkey[ 93] + delta[0][21]); + rkey[109] = rotlConstant< 3>(rkey[101] + delta[2][19]); + rkey[117] = rotlConstant<11>(rkey[109] + delta[3][22]); + rkey[125] = rotlConstant<17>(rkey[117] + delta[4][25]); + rkey[133] = rotlConstant< 3>(rkey[125] + delta[6][23]); + rkey[141] = rotlConstant<11>(rkey[133] + delta[7][26]); + rkey[149] = rotlConstant<17>(rkey[141] + delta[0][29]); + rkey[157] = rotlConstant< 3>(rkey[149] + delta[2][27]); + rkey[165] = rotlConstant<11>(rkey[157] + delta[3][30]); + rkey[173] = rotlConstant<17>(rkey[165] + delta[4][ 1]); + rkey[181] = rotlConstant< 3>(rkey[173] + delta[6][31]); + rkey[189] = rotlConstant<11>(rkey[181] + delta[7][ 2]); + + rkey[ 6] = rotlConstant< 1>( key[ 6] + delta[1][ 1]); + rkey[ 14] = rotlConstant< 6>(rkey[ 6] + delta[2][ 4]); + rkey[ 22] = rotlConstant<13>(rkey[ 14] + delta[3][ 7]); + rkey[ 30] = rotlConstant< 1>(rkey[ 22] + delta[5][ 5]); + rkey[ 38] = rotlConstant< 6>(rkey[ 30] + delta[6][ 8]); + rkey[ 46] = rotlConstant<13>(rkey[ 38] + delta[7][11]); + rkey[ 54] = rotlConstant< 1>(rkey[ 46] + delta[1][ 9]); + rkey[ 62] = rotlConstant< 6>(rkey[ 54] + delta[2][12]); + rkey[ 70] = rotlConstant<13>(rkey[ 62] + delta[3][15]); + rkey[ 78] = rotlConstant< 1>(rkey[ 70] + delta[5][13]); + rkey[ 86] = rotlConstant< 6>(rkey[ 78] + delta[6][16]); + rkey[ 94] = rotlConstant<13>(rkey[ 86] + delta[7][19]); + rkey[102] = rotlConstant< 1>(rkey[ 94] + delta[1][17]); + rkey[110] = rotlConstant< 6>(rkey[102] + delta[2][20]); + rkey[118] = rotlConstant<13>(rkey[110] + delta[3][23]); + rkey[126] = rotlConstant< 1>(rkey[118] + delta[5][21]); + rkey[134] = rotlConstant< 6>(rkey[126] + delta[6][24]); + rkey[142] = rotlConstant<13>(rkey[134] + delta[7][27]); + rkey[150] = rotlConstant< 1>(rkey[142] + delta[1][25]); + rkey[158] = rotlConstant< 6>(rkey[150] + delta[2][28]); + rkey[166] = rotlConstant<13>(rkey[158] + delta[3][31]); + rkey[174] = rotlConstant< 1>(rkey[166] + delta[5][29]); + rkey[182] = rotlConstant< 6>(rkey[174] + delta[6][ 0]); + rkey[190] = rotlConstant<13>(rkey[182] + delta[7][ 3]); + + rkey[ 7] = rotlConstant< 3>( key[ 7] + delta[1][ 2]); + rkey[ 15] = rotlConstant<11>(rkey[ 7] + delta[2][ 5]); + rkey[ 23] = rotlConstant<17>(rkey[ 15] + delta[3][ 8]); + rkey[ 31] = rotlConstant< 3>(rkey[ 23] + delta[5][ 6]); + rkey[ 39] = rotlConstant<11>(rkey[ 31] + delta[6][ 9]); + rkey[ 47] = rotlConstant<17>(rkey[ 39] + delta[7][12]); + rkey[ 55] = rotlConstant< 3>(rkey[ 47] + delta[1][10]); + rkey[ 63] = rotlConstant<11>(rkey[ 55] + delta[2][13]); + rkey[ 71] = rotlConstant<17>(rkey[ 63] + delta[3][16]); + rkey[ 79] = rotlConstant< 3>(rkey[ 71] + delta[5][14]); + rkey[ 87] = rotlConstant<11>(rkey[ 79] + delta[6][17]); + rkey[ 95] = rotlConstant<17>(rkey[ 87] + delta[7][20]); + rkey[103] = rotlConstant< 3>(rkey[ 95] + delta[1][18]); + rkey[111] = rotlConstant<11>(rkey[103] + delta[2][21]); + rkey[119] = rotlConstant<17>(rkey[111] + delta[3][24]); + rkey[127] = rotlConstant< 3>(rkey[119] + delta[5][22]); + rkey[135] = rotlConstant<11>(rkey[127] + delta[6][25]); + rkey[143] = rotlConstant<17>(rkey[135] + delta[7][28]); + rkey[151] = rotlConstant< 3>(rkey[143] + delta[1][26]); + rkey[159] = rotlConstant<11>(rkey[151] + delta[2][29]); + rkey[167] = rotlConstant<17>(rkey[159] + delta[3][ 0]); + rkey[175] = rotlConstant< 3>(rkey[167] + delta[5][30]); + rkey[183] = rotlConstant<11>(rkey[175] + delta[6][ 1]); + rkey[191] = rotlConstant<17>(rkey[183] + delta[7][ 4]); +} + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS +# if defined(CRYPTOPP_SSSE3_AVAILABLE) +extern size_t LEA_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t LEA_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +# endif + +# if (CRYPTOPP_ARM_NEON_AVAILABLE) +extern size_t LEA_Enc_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t LEA_Dec_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +# endif +#endif + +std::string LEA::Base::AlgorithmProvider() const +{ +#if (CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS) +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return "SSSE3"; +# endif +# if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; +# endif +#endif + return "C++"; +} + +void LEA::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + + switch(keyLength) + { + case 16: // 128-bit key + { + m_rkey.New(144); m_temp.New(4); m_rounds = 24; + GetUserKey(LITTLE_ENDIAN_ORDER, m_temp.begin(), 4, userKey, 16); + SetKey128(m_rkey, m_temp); + break; + } + case 24: // 192-bit key + { + m_rkey.New(168); m_temp.New(6); m_rounds = 28; + GetUserKey(LITTLE_ENDIAN_ORDER, m_temp.begin(), 6, userKey, 24); + SetKey192(m_rkey, m_temp); + break; + } + case 32: // 256-bit key + { + m_rkey.New(192); m_temp.New(8); m_rounds = 32; + GetUserKey(LITTLE_ENDIAN_ORDER, m_temp.begin(), 8, userKey, 32); + SetKey256(m_rkey, m_temp); + break; + } + default: + CRYPTOPP_ASSERT(0); + } +} + +void LEA::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_temp[0])(m_temp[1])(m_temp[2])(m_temp[3]); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[ 4]) + (m_temp[3] ^ m_rkey[ 5])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[ 2]) + (m_temp[2] ^ m_rkey[ 3])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[ 0]) + (m_temp[1] ^ m_rkey[ 1])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[ 10]) + (m_temp[0] ^ m_rkey[ 11])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[ 8]) + (m_temp[3] ^ m_rkey[ 9])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[ 6]) + (m_temp[2] ^ m_rkey[ 7])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[ 16]) + (m_temp[1] ^ m_rkey[ 17])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[ 14]) + (m_temp[0] ^ m_rkey[ 15])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[ 12]) + (m_temp[3] ^ m_rkey[ 13])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[ 22]) + (m_temp[2] ^ m_rkey[ 23])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[ 20]) + (m_temp[1] ^ m_rkey[ 21])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[ 18]) + (m_temp[0] ^ m_rkey[ 19])); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[ 28]) + (m_temp[3] ^ m_rkey[ 29])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[ 26]) + (m_temp[2] ^ m_rkey[ 27])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[ 24]) + (m_temp[1] ^ m_rkey[ 25])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[ 34]) + (m_temp[0] ^ m_rkey[ 35])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[ 32]) + (m_temp[3] ^ m_rkey[ 33])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[ 30]) + (m_temp[2] ^ m_rkey[ 31])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[ 40]) + (m_temp[1] ^ m_rkey[ 41])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[ 38]) + (m_temp[0] ^ m_rkey[ 39])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[ 36]) + (m_temp[3] ^ m_rkey[ 37])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[ 46]) + (m_temp[2] ^ m_rkey[ 47])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[ 44]) + (m_temp[1] ^ m_rkey[ 45])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[ 42]) + (m_temp[0] ^ m_rkey[ 43])); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[ 52]) + (m_temp[3] ^ m_rkey[ 53])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[ 50]) + (m_temp[2] ^ m_rkey[ 51])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[ 48]) + (m_temp[1] ^ m_rkey[ 49])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[ 58]) + (m_temp[0] ^ m_rkey[ 59])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[ 56]) + (m_temp[3] ^ m_rkey[ 57])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[ 54]) + (m_temp[2] ^ m_rkey[ 55])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[ 64]) + (m_temp[1] ^ m_rkey[ 65])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[ 62]) + (m_temp[0] ^ m_rkey[ 63])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[ 60]) + (m_temp[3] ^ m_rkey[ 61])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[ 70]) + (m_temp[2] ^ m_rkey[ 71])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[ 68]) + (m_temp[1] ^ m_rkey[ 69])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[ 66]) + (m_temp[0] ^ m_rkey[ 67])); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[ 76]) + (m_temp[3] ^ m_rkey[ 77])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[ 74]) + (m_temp[2] ^ m_rkey[ 75])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[ 72]) + (m_temp[1] ^ m_rkey[ 73])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[ 82]) + (m_temp[0] ^ m_rkey[ 83])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[ 80]) + (m_temp[3] ^ m_rkey[ 81])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[ 78]) + (m_temp[2] ^ m_rkey[ 79])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[ 88]) + (m_temp[1] ^ m_rkey[ 89])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[ 86]) + (m_temp[0] ^ m_rkey[ 87])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[ 84]) + (m_temp[3] ^ m_rkey[ 85])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[ 94]) + (m_temp[2] ^ m_rkey[ 95])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[ 92]) + (m_temp[1] ^ m_rkey[ 93])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[ 90]) + (m_temp[0] ^ m_rkey[ 91])); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[100]) + (m_temp[3] ^ m_rkey[101])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[ 98]) + (m_temp[2] ^ m_rkey[ 99])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[ 96]) + (m_temp[1] ^ m_rkey[ 97])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[106]) + (m_temp[0] ^ m_rkey[107])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[104]) + (m_temp[3] ^ m_rkey[105])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[102]) + (m_temp[2] ^ m_rkey[103])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[112]) + (m_temp[1] ^ m_rkey[113])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[110]) + (m_temp[0] ^ m_rkey[111])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[108]) + (m_temp[3] ^ m_rkey[109])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[118]) + (m_temp[2] ^ m_rkey[119])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[116]) + (m_temp[1] ^ m_rkey[117])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[114]) + (m_temp[0] ^ m_rkey[115])); + + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[124]) + (m_temp[3] ^ m_rkey[125])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[122]) + (m_temp[2] ^ m_rkey[123])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[120]) + (m_temp[1] ^ m_rkey[121])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[130]) + (m_temp[0] ^ m_rkey[131])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[128]) + (m_temp[3] ^ m_rkey[129])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[126]) + (m_temp[2] ^ m_rkey[127])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[136]) + (m_temp[1] ^ m_rkey[137])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[134]) + (m_temp[0] ^ m_rkey[135])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[132]) + (m_temp[3] ^ m_rkey[133])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[142]) + (m_temp[2] ^ m_rkey[143])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[140]) + (m_temp[1] ^ m_rkey[141])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[138]) + (m_temp[0] ^ m_rkey[139])); + + if(m_rounds > 24) + { + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[148]) + (m_temp[3] ^ m_rkey[149])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[146]) + (m_temp[2] ^ m_rkey[147])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[144]) + (m_temp[1] ^ m_rkey[145])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[154]) + (m_temp[0] ^ m_rkey[155])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[152]) + (m_temp[3] ^ m_rkey[153])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[150]) + (m_temp[2] ^ m_rkey[151])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[160]) + (m_temp[1] ^ m_rkey[161])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[158]) + (m_temp[0] ^ m_rkey[159])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[156]) + (m_temp[3] ^ m_rkey[157])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[166]) + (m_temp[2] ^ m_rkey[167])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[164]) + (m_temp[1] ^ m_rkey[165])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[162]) + (m_temp[0] ^ m_rkey[163])); + } + + if(m_rounds > 28) + { + m_temp[3] = rotrConstant<3>((m_temp[2] ^ m_rkey[172]) + (m_temp[3] ^ m_rkey[173])); + m_temp[2] = rotrConstant<5>((m_temp[1] ^ m_rkey[170]) + (m_temp[2] ^ m_rkey[171])); + m_temp[1] = rotlConstant<9>((m_temp[0] ^ m_rkey[168]) + (m_temp[1] ^ m_rkey[169])); + m_temp[0] = rotrConstant<3>((m_temp[3] ^ m_rkey[178]) + (m_temp[0] ^ m_rkey[179])); + m_temp[3] = rotrConstant<5>((m_temp[2] ^ m_rkey[176]) + (m_temp[3] ^ m_rkey[177])); + m_temp[2] = rotlConstant<9>((m_temp[1] ^ m_rkey[174]) + (m_temp[2] ^ m_rkey[175])); + m_temp[1] = rotrConstant<3>((m_temp[0] ^ m_rkey[184]) + (m_temp[1] ^ m_rkey[185])); + m_temp[0] = rotrConstant<5>((m_temp[3] ^ m_rkey[182]) + (m_temp[0] ^ m_rkey[183])); + m_temp[3] = rotlConstant<9>((m_temp[2] ^ m_rkey[180]) + (m_temp[3] ^ m_rkey[181])); + m_temp[2] = rotrConstant<3>((m_temp[1] ^ m_rkey[190]) + (m_temp[2] ^ m_rkey[191])); + m_temp[1] = rotrConstant<5>((m_temp[0] ^ m_rkey[188]) + (m_temp[1] ^ m_rkey[189])); + m_temp[0] = rotlConstant<9>((m_temp[3] ^ m_rkey[186]) + (m_temp[0] ^ m_rkey[187])); + } + + PutBlock oblock(xorBlock, outBlock); + oblock(m_temp[0])(m_temp[1])(m_temp[2])(m_temp[3]); +} + +void LEA::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_temp[0])(m_temp[1])(m_temp[2])(m_temp[3]); + + if(m_rounds > 28) + { + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[186])) ^ m_rkey[187]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[188])) ^ m_rkey[189]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[190])) ^ m_rkey[191]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[180])) ^ m_rkey[181]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[182])) ^ m_rkey[183]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[184])) ^ m_rkey[185]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[174])) ^ m_rkey[175]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[176])) ^ m_rkey[177]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[178])) ^ m_rkey[179]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[168])) ^ m_rkey[169]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[170])) ^ m_rkey[171]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[172])) ^ m_rkey[173]; + } + + if(m_rounds > 24) + { + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[162])) ^ m_rkey[163]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[164])) ^ m_rkey[165]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[166])) ^ m_rkey[167]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[156])) ^ m_rkey[157]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[158])) ^ m_rkey[159]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[160])) ^ m_rkey[161]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[150])) ^ m_rkey[151]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[152])) ^ m_rkey[153]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[154])) ^ m_rkey[155]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[144])) ^ m_rkey[145]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[146])) ^ m_rkey[147]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[148])) ^ m_rkey[149]; + } + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[138])) ^ m_rkey[139]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[140])) ^ m_rkey[141]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[142])) ^ m_rkey[143]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[132])) ^ m_rkey[133]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[134])) ^ m_rkey[135]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[136])) ^ m_rkey[137]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[126])) ^ m_rkey[127]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[128])) ^ m_rkey[129]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[130])) ^ m_rkey[131]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[120])) ^ m_rkey[121]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[122])) ^ m_rkey[123]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[124])) ^ m_rkey[125]; + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[114])) ^ m_rkey[115]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[116])) ^ m_rkey[117]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[118])) ^ m_rkey[119]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[108])) ^ m_rkey[109]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[110])) ^ m_rkey[111]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[112])) ^ m_rkey[113]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[102])) ^ m_rkey[103]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[104])) ^ m_rkey[105]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[106])) ^ m_rkey[107]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 96])) ^ m_rkey[ 97]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 98])) ^ m_rkey[ 99]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[100])) ^ m_rkey[101]; + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 90])) ^ m_rkey[ 91]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 92])) ^ m_rkey[ 93]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 94])) ^ m_rkey[ 95]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 84])) ^ m_rkey[ 85]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 86])) ^ m_rkey[ 87]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 88])) ^ m_rkey[ 89]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 78])) ^ m_rkey[ 79]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 80])) ^ m_rkey[ 81]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 82])) ^ m_rkey[ 83]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 72])) ^ m_rkey[ 73]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 74])) ^ m_rkey[ 75]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 76])) ^ m_rkey[ 77]; + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 66])) ^ m_rkey[ 67]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 68])) ^ m_rkey[ 69]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 70])) ^ m_rkey[ 71]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 60])) ^ m_rkey[ 61]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 62])) ^ m_rkey[ 63]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 64])) ^ m_rkey[ 65]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 54])) ^ m_rkey[ 55]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 56])) ^ m_rkey[ 57]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 58])) ^ m_rkey[ 59]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 48])) ^ m_rkey[ 49]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 50])) ^ m_rkey[ 51]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 52])) ^ m_rkey[ 53]; + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 42])) ^ m_rkey[ 43]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 44])) ^ m_rkey[ 45]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 46])) ^ m_rkey[ 47]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 36])) ^ m_rkey[ 37]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 38])) ^ m_rkey[ 39]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 40])) ^ m_rkey[ 41]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 30])) ^ m_rkey[ 31]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 32])) ^ m_rkey[ 33]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 34])) ^ m_rkey[ 35]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 24])) ^ m_rkey[ 25]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 26])) ^ m_rkey[ 27]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 28])) ^ m_rkey[ 29]; + + m_temp[0] = (rotrConstant<9>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 18])) ^ m_rkey[ 19]; + m_temp[1] = (rotlConstant<5>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 20])) ^ m_rkey[ 21]; + m_temp[2] = (rotlConstant<3>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 22])) ^ m_rkey[ 23]; + m_temp[3] = (rotrConstant<9>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 12])) ^ m_rkey[ 13]; + m_temp[0] = (rotlConstant<5>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 14])) ^ m_rkey[ 15]; + m_temp[1] = (rotlConstant<3>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 16])) ^ m_rkey[ 17]; + m_temp[2] = (rotrConstant<9>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 6])) ^ m_rkey[ 7]; + m_temp[3] = (rotlConstant<5>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 8])) ^ m_rkey[ 9]; + m_temp[0] = (rotlConstant<3>(m_temp[0]) - (m_temp[3] ^ m_rkey[ 10])) ^ m_rkey[ 11]; + m_temp[1] = (rotrConstant<9>(m_temp[1]) - (m_temp[0] ^ m_rkey[ 0])) ^ m_rkey[ 1]; + m_temp[2] = (rotlConstant<5>(m_temp[2]) - (m_temp[1] ^ m_rkey[ 2])) ^ m_rkey[ 3]; + m_temp[3] = (rotlConstant<3>(m_temp[3]) - (m_temp[2] ^ m_rkey[ 4])) ^ m_rkey[ 5]; + + PutBlock oblock(xorBlock, outBlock); + oblock(m_temp[0])(m_temp[1])(m_temp[2])(m_temp[3]); +} + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS +size_t LEA::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if defined(CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + return LEA_Enc_AdvancedProcessBlocks_SSSE3(m_rkey, m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); + } +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return LEA_Enc_AdvancedProcessBlocks_NEON(m_rkey, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t LEA::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if defined(CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) { + return LEA_Dec_AdvancedProcessBlocks_SSSE3(m_rkey, m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); + } +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return LEA_Dec_AdvancedProcessBlocks_NEON(m_rkey, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/lea.h b/extension/third_party/cryptopp/lea.h new file mode 100644 index 00000000..26650d39 --- /dev/null +++ b/extension/third_party/cryptopp/lea.h @@ -0,0 +1,108 @@ +// lea.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "LEA: A 128-Bit Block Cipher for Fast Encryption on Common +// Processors" by Deukjo Hong, Jung-Keun Lee, Dong-Chan Kim, Daesung Kwon, +// Kwon Ho Ryu, and Dong-Geon Lee. + +/// \file lea.h +/// \brief Classes for the LEA block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_LEA_H +#define CRYPTOPP_LEA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) +# ifndef CRYPTOPP_DISABLE_LEA_SIMD +# define CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief LEA block cipher information +/// \since Crypto++ 8.0 +struct LEA_Info : public FixedBlockSize<16>, public VariableKeyLength<16,16,32,8> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "LEA-128"; + } +}; + +/// \brief LEA 128-bit block cipher +/// \details LEA provides 128-bit block size. The valid key size is 128-bits, 192-bits and 256-bits. +/// \note Crypto++ provides a byte oriented implementation +/// \sa LEA, +/// +/// LEA: A 128-Bit Block Cipher for Fast Encryption on Common Processors +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE LEA : public LEA_Info, public BlockCipherDocumentation +{ +public: + /// \brief LEA block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + SecBlock m_rkey; + mutable SecBlock m_temp; + unsigned int m_rounds; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef LEA::Encryption LEAEncryption; +typedef LEA::Decryption LEADecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_LEA_H diff --git a/extension/third_party/cryptopp/lea_simd.cpp b/extension/third_party/cryptopp/lea_simd.cpp new file mode 100644 index 00000000..b0ffc767 --- /dev/null +++ b/extension/third_party/cryptopp/lea_simd.cpp @@ -0,0 +1,1072 @@ +// lea_simd.cpp - written and placed in the public domain by Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSSE3, ARM NEON and ARMv8a, and Power8 Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#include "lea.h" +#include "misc.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both simon.cpp and simon_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include "adv_simd.h" +# include +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if defined(__AVX512F__) +# define CRYPTOPP_AVX512_ROTATE 1 +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include "adv_simd.h" +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if defined(_M_ARM64) +# include "adv_simd.h" +#endif + +// Do not port this to POWER architecture. Naively we hoped +// for a 2x to 3x speedup. The result was a 5x slow down. +// The table below shows MiB/s and cpb. +// +// C++: +// LEA-128(128)/CTR (128-bit key)C++20715.64 +// LEA-128(192)/CTR (192-bit key)C++18617.48 +// LEA-128(256)/CTR (256-bit key)C++12426.2 +// +// Power8: +// LEA-128(128)/CTR (128-bit key)Power83788.7 +// LEA-128(192)/CTR (192-bit key)Power84082.1 +// LEA-128(256)/CTR (256-bit key)Power828116.0 + +#undef CRYPTOPP_POWER8_AVAILABLE +#if defined(CRYPTOPP_POWER8_AVAILABLE) +# include "adv_simd.h" +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char LEA_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; + +// *************************** ARM NEON ***************************// + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +inline uint32x4_t Xor(const uint32x4_t& a, const uint32x4_t& b) +{ + return veorq_u32(a, b); +} + +inline uint32x4_t Add(const uint32x4_t& a, const uint32x4_t& b) +{ + return vaddq_u32(a, b); +} + +inline uint32x4_t Sub(const uint32x4_t& a, const uint32x4_t& b) +{ + return vsubq_u32(a, b); +} + +template +inline uint32x4_t RotateLeft(const uint32x4_t& val) +{ + const uint32x4_t a(vshlq_n_u32(val, R)); + const uint32x4_t b(vshrq_n_u32(val, 32 - R)); + return vorrq_u32(a, b); +} + +template +inline uint32x4_t RotateRight(const uint32x4_t& val) +{ + const uint32x4_t a(vshlq_n_u32(val, 32 - R)); + const uint32x4_t b(vshrq_n_u32(val, R)); + return vorrq_u32(a, b); +} + +#if defined(__aarch32__) || defined(__aarch64__) +template <> +inline uint32x4_t RotateLeft<8>(const uint32x4_t& val) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8_t maskb[16] = { 14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3 }; + const uint8x16_t mask = vld1q_u8(maskb); +#else + const uint8_t maskb[16] = { 3,0,1,2, 7,4,5,6, 11,8,9,10, 15,12,13,14 }; + const uint8x16_t mask = vld1q_u8(maskb); +#endif + + return vreinterpretq_u32_u8( + vqtbl1q_u8(vreinterpretq_u8_u32(val), mask)); +} + +template <> +inline uint32x4_t RotateRight<8>(const uint32x4_t& val) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8_t maskb[16] = { 12,15,14,13, 8,11,10,9, 4,7,6,5, 0,3,2,1 }; + const uint8x16_t mask = vld1q_u8(maskb); +#else + const uint8_t maskb[16] = { 1,2,3,0, 5,6,7,4, 9,10,11,8, 13,14,14,12 }; + const uint8x16_t mask = vld1q_u8(maskb); +#endif + + return vreinterpretq_u32_u8( + vqtbl1q_u8(vreinterpretq_u8_u32(val), mask)); +} +#endif + +uint32x4_t UnpackLow32(uint32x4_t a, uint32x4_t b) +{ + uint32x2_t a1 = vget_low_u32(a); + uint32x2_t b1 = vget_low_u32(b); + uint32x2x2_t result = vzip_u32(a1, b1); + return vcombine_u32(result.val[0], result.val[1]); +} + +uint32x4_t UnpackHigh32(uint32x4_t a, uint32x4_t b) +{ + uint32x2_t a1 = vget_high_u32(a); + uint32x2_t b1 = vget_high_u32(b); + uint32x2x2_t result = vzip_u32(a1, b1); + return vcombine_u32(result.val[0], result.val[1]); +} + +uint32x4_t UnpackLow64(uint32x4_t a, uint32x4_t b) +{ + uint64x1_t a1 = vget_low_u64((uint64x2_t)a); + uint64x1_t b1 = vget_low_u64((uint64x2_t)b); + return (uint32x4_t)vcombine_u64(a1, b1); +} + +uint32x4_t UnpackHigh64(uint32x4_t a, uint32x4_t b) +{ + uint64x1_t a1 = vget_high_u64((uint64x2_t)a); + uint64x1_t b1 = vget_high_u64((uint64x2_t)b); + return (uint32x4_t)vcombine_u64(a1, b1); +} + +template +inline uint32x4_t LoadKey(const word32 rkey[]) +{ + return vdupq_n_u32(rkey[IDX]); +} + +template +inline uint32x4_t UnpackNEON(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + // Should not be instantiated + CRYPTOPP_ASSERT(0); + return vmovq_n_u32(0); +} + +template <> +inline uint32x4_t UnpackNEON<0>(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + const uint32x4_t r1 = UnpackLow32(a, b); + const uint32x4_t r2 = UnpackLow32(c, d); + return UnpackLow64(r1, r2); +} + +template <> +inline uint32x4_t UnpackNEON<1>(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + const uint32x4_t r1 = UnpackLow32(a, b); + const uint32x4_t r2 = UnpackLow32(c, d); + return UnpackHigh64(r1, r2); +} + +template <> +inline uint32x4_t UnpackNEON<2>(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + const uint32x4_t r1 = UnpackHigh32(a, b); + const uint32x4_t r2 = UnpackHigh32(c, d); + return UnpackLow64(r1, r2); +} + +template <> +inline uint32x4_t UnpackNEON<3>(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + const uint32x4_t r1 = UnpackHigh32(a, b); + const uint32x4_t r2 = UnpackHigh32(c, d); + return UnpackHigh64(r1, r2); +} + +template +inline uint32x4_t UnpackNEON(const uint32x4_t& v) +{ + // Should not be instantiated + CRYPTOPP_ASSERT(0); + return vmovq_n_u32(0); +} + +template <> +inline uint32x4_t UnpackNEON<0>(const uint32x4_t& v) +{ + // Splat to all lanes + return vdupq_n_u32(vgetq_lane_u32(v, 0)); +} + +template <> +inline uint32x4_t UnpackNEON<1>(const uint32x4_t& v) +{ + // Splat to all lanes + return vdupq_n_u32(vgetq_lane_u32(v, 1)); +} + +template <> +inline uint32x4_t UnpackNEON<2>(const uint32x4_t& v) +{ + // Splat to all lanes + return vdupq_n_u32(vgetq_lane_u32(v, 2)); +} + +template <> +inline uint32x4_t UnpackNEON<3>(const uint32x4_t& v) +{ + // Splat to all lanes + return vdupq_n_u32(vgetq_lane_u32(v, 3)); +} + +template +inline uint32x4_t RepackNEON(const uint32x4_t& a, const uint32x4_t& b, const uint32x4_t& c, const uint32x4_t& d) +{ + return UnpackNEON(a, b, c, d); +} + +template +inline uint32x4_t RepackNEON(const uint32x4_t& v) +{ + return UnpackNEON(v); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// *************************** IA-32 ***************************// + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +inline __m128i Xor(const __m128i& a, const __m128i& b) +{ + return _mm_xor_si128(a, b); +} + +inline __m128i Add(const __m128i& a, const __m128i& b) +{ + return _mm_add_epi32(a, b); +} + +inline __m128i Sub(const __m128i& a, const __m128i& b) +{ + return _mm_sub_epi32(a, b); +} + +template +inline __m128i RotateLeft(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, R), _mm_srli_epi32(val, 32-R)); +#endif +} + +template +inline __m128i RotateRight(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 32-R); +#else + return _mm_or_si128( + _mm_slli_epi32(val, 32-R), _mm_srli_epi32(val, R)); +#endif +} + +// Faster than two Shifts and an Or. +template <> +inline __m128i RotateLeft<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 8); +#else + const __m128i mask = _mm_set_epi8(14,13,12,15, 10,9,8,11, 6,5,4,7, 2,1,0,3); + return _mm_shuffle_epi8(val, mask); +#endif +} + +// Faster than two Shifts and an Or. +template <> +inline __m128i RotateRight<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi32(val, 32-8); +#else + const __m128i mask = _mm_set_epi8(12,15,14,13, 8,11,10,9, 4,7,6,5, 0,3,2,1); + return _mm_shuffle_epi8(val, mask); +#endif +} + +template +inline __m128i LoadKey(const word32 rkey[]) +{ + float rk; std::memcpy(&rk, rkey+IDX, sizeof(rk)); + return _mm_castps_si128(_mm_load_ps1(&rk)); +} + +template +inline __m128i UnpackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + CRYPTOPP_UNUSED(c); CRYPTOPP_UNUSED(d); + CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // LEA is little-endian oriented, so there is no need for a separate shuffle. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_unpacklo_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // LEA is little-endian oriented, so there is no need for a separate shuffle. + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_unpackhi_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // LEA is little-endian oriented, so there is no need for a separate shuffle. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_unpacklo_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // LEA is little-endian oriented, so there is no need for a separate shuffle. + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_unpackhi_epi64(r1, r2); +} + +template +inline __m128i UnpackXMM(const __m128i& v) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(v); CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(11,10,9,8, 11,10,9,8, 11,10,9,8, 11,10,9,8)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(15,14,13,12, 15,14,13,12, 15,14,13,12, 15,14,13,12)); +} + +template +inline __m128i RepackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + return UnpackXMM(a, b, c, d); +} + +template +inline __m128i RepackXMM(const __m128i& v) +{ + return UnpackXMM(v); +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// *************************** Power8 ***************************// + +#if (CRYPTOPP_POWER8_AVAILABLE) + +using CryptoPP::uint8x16_p; +using CryptoPP::uint32x4_p; +using CryptoPP::uint64x2_p; + +inline uint32x4_p Xor(const uint32x4_p& a, const uint32x4_p& b) +{ + return VecXor(a, b); +} + +inline uint32x4_p Add(const uint32x4_p& a, const uint32x4_p& b) +{ + return VecAdd(a, b); +} + +inline uint32x4_p Sub(const uint32x4_p& a, const uint32x4_p& b) +{ + return VecSub(a, b); +} + +template +inline uint32x4_p RotateLeft(const uint32x4_p& val) +{ + const uint32x4_p m = {R, R, R, R}; + return vec_rl(val, m); +} + +template +inline uint32x4_p RotateRight(const uint32x4_p& val) +{ + const uint32x4_p m = {32-R, 32-R, 32-R, 32-R}; + return vec_rl(val, m); +} + +template +inline uint32x4_p LoadKey(const word32 rkey[]) +{ + return vec_splats(rkey[IDX]); +} + +template +inline uint32x4_p UnpackSIMD(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + CRYPTOPP_UNUSED(c); CRYPTOPP_UNUSED(d); + CRYPTOPP_ASSERT(0); + return VecXor(a, a); +} + +template <> +inline uint32x4_p UnpackSIMD<0>(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + const uint64x2_p r1 = (uint64x2_p)vec_mergel(a, b); + const uint64x2_p r2 = (uint64x2_p)vec_mergel(c, d); + return (uint32x4_p)vec_mergel(r1, r2); +} + +template <> +inline uint32x4_p UnpackSIMD<1>(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + const uint64x2_p r1 = (uint64x2_p)vec_mergel(a, b); + const uint64x2_p r2 = (uint64x2_p)vec_mergel(c, d); + return (uint32x4_p)vec_mergeh(r1, r2); +} + +template <> +inline uint32x4_p UnpackSIMD<2>(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + const uint64x2_p r1 = (uint64x2_p)vec_mergeh(a, b); + const uint64x2_p r2 = (uint64x2_p)vec_mergeh(c, d); + return (uint32x4_p)vec_mergel(r1, r2); +} + +template <> +inline uint32x4_p UnpackSIMD<3>(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + const uint64x2_p r1 = (uint64x2_p)vec_mergeh(a, b); + const uint64x2_p r2 = (uint64x2_p)vec_mergeh(c, d); + return (uint32x4_p)vec_mergeh(r1, r2); +} + +template +inline uint32x4_p UnpackSIMD(const uint32x4_p& v) +{ + // Should not be instantiated + CRYPTOPP_ASSERT(0); + return VecXor(v, v); +} + +template <> +inline uint32x4_p UnpackSIMD<0>(const uint32x4_p& v) +{ + // Splat to all lanes + const uint8x16_p m = {3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0}; + return (uint32x4_p)VecPermute(v, v, m); +} + +template <> +inline uint32x4_p UnpackSIMD<1>(const uint32x4_p& v) +{ + // Splat to all lanes + const uint8x16_p m = {7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4}; + return (uint32x4_p)VecPermute(v, v, m); +} + +template <> +inline uint32x4_p UnpackSIMD<2>(const uint32x4_p& v) +{ + // Splat to all lanes + const uint8x16_p m = {11,10,9,8, 11,10,9,8, 11,10,9,8, 11,10,9,8}; + return (uint32x4_p)VecPermute(v, v, m); +} + +template <> +inline uint32x4_p UnpackSIMD<3>(const uint32x4_p& v) +{ + // Splat to all lanes + const uint8x16_p m = {15,14,13,12, 15,14,13,12, 15,14,13,12, 15,14,13,12}; + return (uint32x4_p)VecPermute(v, v, m); +} + +template +inline uint32x4_p RepackSIMD(const uint32x4_p& a, const uint32x4_p& b, const uint32x4_p& c, const uint32x4_p& d) +{ + return UnpackSIMD(a, b, c, d); +} + +template +inline uint32x4_p RepackSIMD(const uint32x4_p& v) +{ + return UnpackSIMD(v); +} + +#endif // CRYPTOPP_POWER8_AVAILABLE + +// *************************** LEA Encryption ***************************// + +#if (CRYPTOPP_ARM_NEON_AVAILABLE || CRYPTOPP_SSSE3_AVAILABLE) + +template +inline void LEA_Encryption(W temp[4], const word32 *subkeys, unsigned int rounds) +{ + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<4>(subkeys)), Xor(temp[3], LoadKey<5>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<2>(subkeys)), Xor(temp[2], LoadKey<3>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<0>(subkeys)), Xor(temp[1], LoadKey<1>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<10>(subkeys)), Xor(temp[0], LoadKey<11>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<8>(subkeys)), Xor(temp[3], LoadKey<9>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<6>(subkeys)), Xor(temp[2], LoadKey<7>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<16>(subkeys)), Xor(temp[1], LoadKey<17>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<14>(subkeys)), Xor(temp[0], LoadKey<15>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<12>(subkeys)), Xor(temp[3], LoadKey<13>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<22>(subkeys)), Xor(temp[2], LoadKey<23>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<20>(subkeys)), Xor(temp[1], LoadKey<21>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<18>(subkeys)), Xor(temp[0], LoadKey<19>(subkeys)))); + + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<28>(subkeys)), Xor(temp[3], LoadKey<29>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<26>(subkeys)), Xor(temp[2], LoadKey<27>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<24>(subkeys)), Xor(temp[1], LoadKey<25>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<34>(subkeys)), Xor(temp[0], LoadKey<35>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<32>(subkeys)), Xor(temp[3], LoadKey<33>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<30>(subkeys)), Xor(temp[2], LoadKey<31>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<40>(subkeys)), Xor(temp[1], LoadKey<41>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<38>(subkeys)), Xor(temp[0], LoadKey<39>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<36>(subkeys)), Xor(temp[3], LoadKey<37>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<46>(subkeys)), Xor(temp[2], LoadKey<47>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<44>(subkeys)), Xor(temp[1], LoadKey<45>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<42>(subkeys)), Xor(temp[0], LoadKey<43>(subkeys)))); + + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<52>(subkeys)), Xor(temp[3], LoadKey<53>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<50>(subkeys)), Xor(temp[2], LoadKey<51>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<48>(subkeys)), Xor(temp[1], LoadKey<49>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<58>(subkeys)), Xor(temp[0], LoadKey<59>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<56>(subkeys)), Xor(temp[3], LoadKey<57>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<54>(subkeys)), Xor(temp[2], LoadKey<55>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<64>(subkeys)), Xor(temp[1], LoadKey<65>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<62>(subkeys)), Xor(temp[0], LoadKey<63>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<60>(subkeys)), Xor(temp[3], LoadKey<61>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<70>(subkeys)), Xor(temp[2], LoadKey<71>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<68>(subkeys)), Xor(temp[1], LoadKey<69>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<66>(subkeys)), Xor(temp[0], LoadKey<67>(subkeys)))); + + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<76>(subkeys)), Xor(temp[3], LoadKey<77>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<74>(subkeys)), Xor(temp[2], LoadKey<75>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<72>(subkeys)), Xor(temp[1], LoadKey<73>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<82>(subkeys)), Xor(temp[0], LoadKey<83>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<80>(subkeys)), Xor(temp[3], LoadKey<81>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<78>(subkeys)), Xor(temp[2], LoadKey<79>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<88>(subkeys)), Xor(temp[1], LoadKey<89>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<86>(subkeys)), Xor(temp[0], LoadKey<87>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<84>(subkeys)), Xor(temp[3], LoadKey<85>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<94>(subkeys)), Xor(temp[2], LoadKey<95>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<92>(subkeys)), Xor(temp[1], LoadKey<93>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<90>(subkeys)), Xor(temp[0], LoadKey<91>(subkeys)))); + + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<100>(subkeys)), Xor(temp[3], LoadKey<101>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<98>(subkeys)), Xor(temp[2], LoadKey<99>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<96>(subkeys)), Xor(temp[1], LoadKey<97>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<106>(subkeys)), Xor(temp[0], LoadKey<107>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<104>(subkeys)), Xor(temp[3], LoadKey<105>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<102>(subkeys)), Xor(temp[2], LoadKey<103>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<112>(subkeys)), Xor(temp[1], LoadKey<113>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<110>(subkeys)), Xor(temp[0], LoadKey<111>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<108>(subkeys)), Xor(temp[3], LoadKey<109>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<118>(subkeys)), Xor(temp[2], LoadKey<119>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<116>(subkeys)), Xor(temp[1], LoadKey<117>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<114>(subkeys)), Xor(temp[0], LoadKey<115>(subkeys)))); + + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<124>(subkeys)), Xor(temp[3], LoadKey<125>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<122>(subkeys)), Xor(temp[2], LoadKey<123>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<120>(subkeys)), Xor(temp[1], LoadKey<121>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<130>(subkeys)), Xor(temp[0], LoadKey<131>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<128>(subkeys)), Xor(temp[3], LoadKey<129>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<126>(subkeys)), Xor(temp[2], LoadKey<127>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<136>(subkeys)), Xor(temp[1], LoadKey<137>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<134>(subkeys)), Xor(temp[0], LoadKey<135>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<132>(subkeys)), Xor(temp[3], LoadKey<133>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<142>(subkeys)), Xor(temp[2], LoadKey<143>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<140>(subkeys)), Xor(temp[1], LoadKey<141>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<138>(subkeys)), Xor(temp[0], LoadKey<139>(subkeys)))); + + if(rounds > 24) + { + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<148>(subkeys)), Xor(temp[3], LoadKey<149>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<146>(subkeys)), Xor(temp[2], LoadKey<147>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<144>(subkeys)), Xor(temp[1], LoadKey<145>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<154>(subkeys)), Xor(temp[0], LoadKey<155>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<152>(subkeys)), Xor(temp[3], LoadKey<153>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<150>(subkeys)), Xor(temp[2], LoadKey<151>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<160>(subkeys)), Xor(temp[1], LoadKey<161>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<158>(subkeys)), Xor(temp[0], LoadKey<159>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<156>(subkeys)), Xor(temp[3], LoadKey<157>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<166>(subkeys)), Xor(temp[2], LoadKey<167>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<164>(subkeys)), Xor(temp[1], LoadKey<165>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<162>(subkeys)), Xor(temp[0], LoadKey<163>(subkeys)))); + } + + if(rounds > 28) + { + temp[3] = RotateRight<3>(Add(Xor(temp[2], LoadKey<172>(subkeys)), Xor(temp[3], LoadKey<173>(subkeys)))); + temp[2] = RotateRight<5>(Add(Xor(temp[1], LoadKey<170>(subkeys)), Xor(temp[2], LoadKey<171>(subkeys)))); + temp[1] = RotateLeft<9>(Add(Xor(temp[0], LoadKey<168>(subkeys)), Xor(temp[1], LoadKey<169>(subkeys)))); + temp[0] = RotateRight<3>(Add(Xor(temp[3], LoadKey<178>(subkeys)), Xor(temp[0], LoadKey<179>(subkeys)))); + temp[3] = RotateRight<5>(Add(Xor(temp[2], LoadKey<176>(subkeys)), Xor(temp[3], LoadKey<177>(subkeys)))); + temp[2] = RotateLeft<9>(Add(Xor(temp[1], LoadKey<174>(subkeys)), Xor(temp[2], LoadKey<175>(subkeys)))); + temp[1] = RotateRight<3>(Add(Xor(temp[0], LoadKey<184>(subkeys)), Xor(temp[1], LoadKey<185>(subkeys)))); + temp[0] = RotateRight<5>(Add(Xor(temp[3], LoadKey<182>(subkeys)), Xor(temp[0], LoadKey<183>(subkeys)))); + temp[3] = RotateLeft<9>(Add(Xor(temp[2], LoadKey<180>(subkeys)), Xor(temp[3], LoadKey<181>(subkeys)))); + temp[2] = RotateRight<3>(Add(Xor(temp[1], LoadKey<190>(subkeys)), Xor(temp[2], LoadKey<191>(subkeys)))); + temp[1] = RotateRight<5>(Add(Xor(temp[0], LoadKey<188>(subkeys)), Xor(temp[1], LoadKey<189>(subkeys)))); + temp[0] = RotateLeft<9>(Add(Xor(temp[3], LoadKey<186>(subkeys)), Xor(temp[0], LoadKey<187>(subkeys)))); + } +} + +// *************************** LEA Decryption ***************************// + +template +inline void LEA_Decryption(W temp[4], const word32 *subkeys, unsigned int rounds) +{ + if(rounds > 28) + { + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<186>(subkeys))), LoadKey<187>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<188>(subkeys))), LoadKey<189>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<190>(subkeys))), LoadKey<191>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<180>(subkeys))), LoadKey<181>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<182>(subkeys))), LoadKey<183>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<184>(subkeys))), LoadKey<185>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<174>(subkeys))), LoadKey<175>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<176>(subkeys))), LoadKey<177>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<178>(subkeys))), LoadKey<179>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<168>(subkeys))), LoadKey<169>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<170>(subkeys))), LoadKey<171>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<172>(subkeys))), LoadKey<173>(subkeys)); + } + + if(rounds > 24) + { + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<162>(subkeys))), LoadKey<163>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<164>(subkeys))), LoadKey<165>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<166>(subkeys))), LoadKey<167>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<156>(subkeys))), LoadKey<157>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<158>(subkeys))), LoadKey<159>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<160>(subkeys))), LoadKey<161>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<150>(subkeys))), LoadKey<151>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<152>(subkeys))), LoadKey<153>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<154>(subkeys))), LoadKey<155>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<144>(subkeys))), LoadKey<145>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<146>(subkeys))), LoadKey<147>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<148>(subkeys))), LoadKey<149>(subkeys)); + } + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<138>(subkeys))), LoadKey<139>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<140>(subkeys))), LoadKey<141>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<142>(subkeys))), LoadKey<143>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<132>(subkeys))), LoadKey<133>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<134>(subkeys))), LoadKey<135>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<136>(subkeys))), LoadKey<137>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<126>(subkeys))), LoadKey<127>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<128>(subkeys))), LoadKey<129>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<130>(subkeys))), LoadKey<131>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<120>(subkeys))), LoadKey<121>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<122>(subkeys))), LoadKey<123>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<124>(subkeys))), LoadKey<125>(subkeys)); + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<114>(subkeys))), LoadKey<115>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<116>(subkeys))), LoadKey<117>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<118>(subkeys))), LoadKey<119>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<108>(subkeys))), LoadKey<109>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<110>(subkeys))), LoadKey<111>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<112>(subkeys))), LoadKey<113>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<102>(subkeys))), LoadKey<103>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<104>(subkeys))), LoadKey<105>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<106>(subkeys))), LoadKey<107>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<96>(subkeys))), LoadKey<97>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<98>(subkeys))), LoadKey<99>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<100>(subkeys))), LoadKey<101>(subkeys)); + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<90>(subkeys))), LoadKey<91>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<92>(subkeys))), LoadKey<93>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<94>(subkeys))), LoadKey<95>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<84>(subkeys))), LoadKey<85>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<86>(subkeys))), LoadKey<87>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<88>(subkeys))), LoadKey<89>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<78>(subkeys))), LoadKey<79>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<80>(subkeys))), LoadKey<81>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<82>(subkeys))), LoadKey<83>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<72>(subkeys))), LoadKey<73>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<74>(subkeys))), LoadKey<75>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<76>(subkeys))), LoadKey<77>(subkeys)); + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<66>(subkeys))), LoadKey<67>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<68>(subkeys))), LoadKey<69>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<70>(subkeys))), LoadKey<71>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<60>(subkeys))), LoadKey<61>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<62>(subkeys))), LoadKey<63>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<64>(subkeys))), LoadKey<65>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<54>(subkeys))), LoadKey<55>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<56>(subkeys))), LoadKey<57>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<58>(subkeys))), LoadKey<59>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<48>(subkeys))), LoadKey<49>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<50>(subkeys))), LoadKey<51>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<52>(subkeys))), LoadKey<53>(subkeys)); + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<42>(subkeys))), LoadKey<43>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<44>(subkeys))), LoadKey<45>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<46>(subkeys))), LoadKey<47>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<36>(subkeys))), LoadKey<37>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<38>(subkeys))), LoadKey<39>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<40>(subkeys))), LoadKey<41>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<30>(subkeys))), LoadKey<31>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<32>(subkeys))), LoadKey<33>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<34>(subkeys))), LoadKey<35>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<24>(subkeys))), LoadKey<25>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<26>(subkeys))), LoadKey<27>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<28>(subkeys))), LoadKey<29>(subkeys)); + + temp[0] = Xor(Sub(RotateRight<9>(temp[0]), Xor(temp[3], LoadKey<18>(subkeys))), LoadKey<19>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<5>(temp[1]), Xor(temp[0], LoadKey<20>(subkeys))), LoadKey<21>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<3>(temp[2]), Xor(temp[1], LoadKey<22>(subkeys))), LoadKey<23>(subkeys)); + temp[3] = Xor(Sub(RotateRight<9>(temp[3]), Xor(temp[2], LoadKey<12>(subkeys))), LoadKey<13>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<5>(temp[0]), Xor(temp[3], LoadKey<14>(subkeys))), LoadKey<15>(subkeys)); + temp[1] = Xor(Sub(RotateLeft<3>(temp[1]), Xor(temp[0], LoadKey<16>(subkeys))), LoadKey<17>(subkeys)); + temp[2] = Xor(Sub(RotateRight<9>(temp[2]), Xor(temp[1], LoadKey<6>(subkeys))), LoadKey<7>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<5>(temp[3]), Xor(temp[2], LoadKey<8>(subkeys))), LoadKey<9>(subkeys)); + temp[0] = Xor(Sub(RotateLeft<3>(temp[0]), Xor(temp[3], LoadKey<10>(subkeys))), LoadKey<11>(subkeys)); + temp[1] = Xor(Sub(RotateRight<9>(temp[1]), Xor(temp[0], LoadKey<0>(subkeys))), LoadKey<1>(subkeys)); + temp[2] = Xor(Sub(RotateLeft<5>(temp[2]), Xor(temp[1], LoadKey<2>(subkeys))), LoadKey<3>(subkeys)); + temp[3] = Xor(Sub(RotateLeft<3>(temp[3]), Xor(temp[2], LoadKey<4>(subkeys))), LoadKey<5>(subkeys)); +} + +#endif // LEA Encryption and Decryption + +// *************************** ARM NEON ***************************// + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +inline void LEA_Enc_Block(uint32x4_t &block0, + const word32 *subkeys, unsigned int rounds) +{ + uint32x4_t temp[4]; + temp[0] = UnpackNEON<0>(block0); + temp[1] = UnpackNEON<1>(block0); + temp[2] = UnpackNEON<2>(block0); + temp[3] = UnpackNEON<3>(block0); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackNEON<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_Block(uint32x4_t &block0, + const word32 *subkeys, unsigned int rounds) +{ + uint32x4_t temp[4]; + temp[0] = UnpackNEON<0>(block0); + temp[1] = UnpackNEON<1>(block0); + temp[2] = UnpackNEON<2>(block0); + temp[3] = UnpackNEON<3>(block0); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackNEON<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Enc_4_Blocks(uint32x4_t &block0, uint32x4_t &block1, + uint32x4_t &block2, uint32x4_t &block3, const word32 *subkeys, unsigned int rounds) +{ + uint32x4_t temp[4]; + temp[0] = UnpackNEON<0>(block0, block1, block2, block3); + temp[1] = UnpackNEON<1>(block0, block1, block2, block3); + temp[2] = UnpackNEON<2>(block0, block1, block2, block3); + temp[3] = UnpackNEON<3>(block0, block1, block2, block3); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackNEON<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackNEON<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackNEON<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackNEON<3>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_4_Blocks(uint32x4_t &block0, uint32x4_t &block1, + uint32x4_t &block2, uint32x4_t &block3, const word32 *subkeys, unsigned int rounds) +{ + uint32x4_t temp[4]; + temp[0] = UnpackNEON<0>(block0, block1, block2, block3); + temp[1] = UnpackNEON<1>(block0, block1, block2, block3); + temp[2] = UnpackNEON<2>(block0, block1, block2, block3); + temp[3] = UnpackNEON<3>(block0, block1, block2, block3); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackNEON<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackNEON<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackNEON<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackNEON<3>(temp[0], temp[1], temp[2], temp[3]); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// *************************** IA-32 ***************************// + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +inline void LEA_Enc_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + __m128i temp[4]; + temp[0] = UnpackXMM<0>(block0); + temp[1] = UnpackXMM<1>(block0); + temp[2] = UnpackXMM<2>(block0); + temp[3] = UnpackXMM<3>(block0); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackXMM<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_Block(__m128i &block0, + const word32 *subkeys, unsigned int rounds) +{ + __m128i temp[4]; + temp[0] = UnpackXMM<0>(block0); + temp[1] = UnpackXMM<1>(block0); + temp[2] = UnpackXMM<2>(block0); + temp[3] = UnpackXMM<3>(block0); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackXMM<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Enc_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + __m128i temp[4]; + temp[0] = UnpackXMM<0>(block0, block1, block2, block3); + temp[1] = UnpackXMM<1>(block0, block1, block2, block3); + temp[2] = UnpackXMM<2>(block0, block1, block2, block3); + temp[3] = UnpackXMM<3>(block0, block1, block2, block3); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackXMM<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackXMM<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackXMM<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackXMM<3>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int rounds) +{ + __m128i temp[4]; + temp[0] = UnpackXMM<0>(block0, block1, block2, block3); + temp[1] = UnpackXMM<1>(block0, block1, block2, block3); + temp[2] = UnpackXMM<2>(block0, block1, block2, block3); + temp[3] = UnpackXMM<3>(block0, block1, block2, block3); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackXMM<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackXMM<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackXMM<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackXMM<3>(temp[0], temp[1], temp[2], temp[3]); +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// *************************** Power8 ***************************// + +#if (CRYPTOPP_POWER8_AVAILABLE) + +inline void LEA_Enc_Block(uint32x4_p &block0, + const word32 *subkeys, unsigned int rounds) +{ + uint32x4_p temp[4]; + temp[0] = UnpackSIMD<0>(block0); + temp[1] = UnpackSIMD<1>(block0); + temp[2] = UnpackSIMD<2>(block0); + temp[3] = UnpackSIMD<3>(block0); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackSIMD<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_Block(uint32x4_p &block0, + const word32 *subkeys, unsigned int rounds) +{ + uint32x4_p temp[4]; + temp[0] = UnpackSIMD<0>(block0); + temp[1] = UnpackSIMD<1>(block0); + temp[2] = UnpackSIMD<2>(block0); + temp[3] = UnpackSIMD<3>(block0); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackSIMD<0>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Enc_4_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, const word32 *subkeys, unsigned int rounds) +{ + uint32x4_p temp[4]; + temp[0] = UnpackSIMD<0>(block0, block1, block2, block3); + temp[1] = UnpackSIMD<1>(block0, block1, block2, block3); + temp[2] = UnpackSIMD<2>(block0, block1, block2, block3); + temp[3] = UnpackSIMD<3>(block0, block1, block2, block3); + + LEA_Encryption(temp, subkeys, rounds); + + block0 = RepackSIMD<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackSIMD<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackSIMD<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackSIMD<3>(temp[0], temp[1], temp[2], temp[3]); +} + +inline void LEA_Dec_4_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, const word32 *subkeys, unsigned int rounds) +{ + uint32x4_p temp[4]; + temp[0] = UnpackSIMD<0>(block0, block1, block2, block3); + temp[1] = UnpackSIMD<1>(block0, block1, block2, block3); + temp[2] = UnpackSIMD<2>(block0, block1, block2, block3); + temp[3] = UnpackSIMD<3>(block0, block1, block2, block3); + + LEA_Decryption(temp, subkeys, rounds); + + block0 = RepackSIMD<0>(temp[0], temp[1], temp[2], temp[3]); + block1 = RepackSIMD<1>(temp[0], temp[1], temp[2], temp[3]); + block2 = RepackSIMD<2>(temp[0], temp[1], temp[2], temp[3]); + block3 = RepackSIMD<3>(temp[0], temp[1], temp[2], temp[3]); +} + +#endif // CRYPTOPP_POWER8_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +// *************************** SIMD Templates ***************************// + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) +size_t LEA_Enc_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_SSE(LEA_Enc_Block, LEA_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t LEA_Dec_AdvancedProcessBlocks_SSSE3(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_SSE(LEA_Dec_Block, LEA_Dec_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SSSE3_AVAILABLE + +#if defined(CRYPTOPP_ARM_NEON_AVAILABLE) +size_t LEA_Enc_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_NEON(LEA_Enc_Block, LEA_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t LEA_Dec_AdvancedProcessBlocks_NEON(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_NEON(LEA_Dec_Block, LEA_Dec_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +#if defined(CRYPTOPP_POWER8_AVAILABLE) +size_t LEA_Enc_AdvancedProcessBlocks_POWER8(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_ALTIVEC(LEA_Enc_Block, LEA_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t LEA_Dec_AdvancedProcessBlocks_POWER8(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_ALTIVEC(LEA_Dec_Block, LEA_Dec_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_POWER8_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/lubyrack.h b/extension/third_party/cryptopp/lubyrack.h new file mode 100644 index 00000000..a5d6a18d --- /dev/null +++ b/extension/third_party/cryptopp/lubyrack.h @@ -0,0 +1,137 @@ +// lubyrack.h - originally written and placed in the public domain by Wei Dai + +/// \file lubyrack.h +/// \brief Classes for the Luby-Rackoff block cipher + +#ifndef CRYPTOPP_LUBYRACK_H +#define CRYPTOPP_LUBYRACK_H + +#include "simple.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Luby-Rackoff block cipher information +template +struct LR_Info : public VariableKeyLength<16, 0, 2*(INT_MAX/2), 2>, public FixedBlockSize<2*T::DIGESTSIZE> +{ + static std::string StaticAlgorithmName() {return std::string("LR/")+T::StaticAlgorithmName();} +}; + +/// \brief Luby-Rackoff block cipher +template +class LR : public LR_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl > + { + public: + // VC60 workaround: have to define these functions within class definition + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + this->AssertValidKeyLength(length); + + L = length/2; + buffer.New(2*S); + digest.New(S); + key.Assign(userKey, 2*L); + } + + protected: + CRYPTOPP_CONSTANT(S=T::DIGESTSIZE); + unsigned int L; // key length / 2 + SecByteBlock key; + + mutable T hm; + mutable SecByteBlock buffer, digest; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + +#define KL this->key +#define KR this->key+this->L +#define BL this->buffer +#define BR this->buffer+this->S +#define IL inBlock +#define IR inBlock+this->S +#define OL outBlock +#define OR outBlock+this->S + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KL, this->L); + this->hm.Update(IL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(OR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + memcpy_s(outBlock, 2*this->S, this->buffer, 2*this->S); + } + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KR, this->L); + this->hm.Update(IR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(OL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + memcpy(outBlock, this->buffer, 2*this->S); + } +#undef KL +#undef KR +#undef BL +#undef BR +#undef IL +#undef IR +#undef OL +#undef OR + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/luc.cpp b/extension/third_party/cryptopp/luc.cpp new file mode 100644 index 00000000..9a25662c --- /dev/null +++ b/extension/third_party/cryptopp/luc.cpp @@ -0,0 +1,231 @@ +// luc.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "luc.h" +#include "asn.h" +#include "sha.h" +#include "integer.h" +#include "nbtheory.h" +#include "algparam.h" +#include "pkcspad.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void LUC_TestInstantiations() +{ + LUC_HMP::Signer t1; + LUCFunction t2; + InvertibleLUCFunction t3; +} +#endif + +void DL_Algorithm_LUC_HMP::Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const +{ + const Integer &q = params.GetSubgroupOrder(); + r = params.ExponentiateBase(k); + s = (k + x*(r+e)) % q; +} + +bool DL_Algorithm_LUC_HMP::Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const +{ + const Integer p = params.GetGroupOrder()-1; + const Integer &q = params.GetSubgroupOrder(); + + Integer Vsg = params.ExponentiateBase(s); + Integer Vry = publicKey.ExponentiatePublicElement((r+e)%q); + return (Vsg*Vsg + Vry*Vry + r*r) % p == (Vsg * Vry * r + 4) % p; +} + +Integer DL_BasePrecomputation_LUC::Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const +{ + return Lucas(exponent, m_g, static_cast(group).GetModulus()); +} + +void DL_GroupParameters_LUC::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const +{ + for (unsigned int i=0; i Integer::One() && m_n.IsOdd(); + CRYPTOPP_ASSERT(pass); + pass = pass && m_e > Integer::One() && m_e.IsOdd() && m_e < m_n; + CRYPTOPP_ASSERT(pass); + return pass; +} + +bool LUCFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void LUCFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** +// private key operations: + +class LUCPrimeSelector : public PrimeSelector +{ +public: + LUCPrimeSelector(const Integer &e) : m_e(e) {} + bool IsAcceptable(const Integer &candidate) const + { + return RelativelyPrime(m_e, candidate+1) && RelativelyPrime(m_e, candidate-1); + } + Integer m_e; +}; + +void InvertibleLUCFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleLUCFunction: specified modulus size is too small"); + + m_e = alg.GetValueWithDefault("PublicExponent", Integer(17)); + + if (m_e < 5 || m_e.IsEven()) + throw InvalidArgument("InvertibleLUCFunction: invalid public exponent"); + + LUCPrimeSelector selector(m_e); + AlgorithmParameters primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + ("PointerToPrimeSelector", selector.GetSelectorPointer()); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); +} + +void InvertibleLUCFunction::Initialize(RandomNumberGenerator &rng, unsigned int keybits, const Integer &e) +{ + GenerateRandom(rng, MakeParameters("ModulusSize", (int)keybits)("PublicExponent", e)); +} + +void InvertibleLUCFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + + Integer version(seq); + if (!!version) // make sure version is 0 + BERDecodeError(); + + m_n.BERDecode(seq); + m_e.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); +} + +void InvertibleLUCFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + + const byte version[] = {INTEGER, 1, 0}; + seq.Put(version, sizeof(version)); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +Integer InvertibleLUCFunction::CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + // not clear how to do blinding with LUC + CRYPTOPP_UNUSED(rng); + DoQuickSanityCheck(); + return InverseLucas(m_e, x, m_q, m_p, m_u); +} + +bool InvertibleLUCFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = LUCFunction::Validate(rng, level); + CRYPTOPP_ASSERT(pass); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u.IsPositive() && m_u < m_p; + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && RelativelyPrime(m_e, m_p+1); + CRYPTOPP_ASSERT(pass); + pass = pass && RelativelyPrime(m_e, m_p-1); + CRYPTOPP_ASSERT(pass); + pass = pass && RelativelyPrime(m_e, m_q+1); + CRYPTOPP_ASSERT(pass); + pass = pass && RelativelyPrime(m_e, m_q-1); + CRYPTOPP_ASSERT(pass); + pass = pass && m_u * m_q % m_p == 1; + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool InvertibleLUCFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleLUCFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/luc.h b/extension/third_party/cryptopp/luc.h new file mode 100644 index 00000000..9483a6d8 --- /dev/null +++ b/extension/third_party/cryptopp/luc.h @@ -0,0 +1,338 @@ +// luc.h - originally written and placed in the public domain by Wei Dai + +/// \file luc.h +/// \brief Classes for the LUC cryptosystem +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_LUC_H +#define CRYPTOPP_LUC_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "pkcspad.h" +#include "integer.h" +#include "oaep.h" +#include "dh.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The LUC function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class LUCFunction : public TrapdoorFunction, public PublicKey +{ + typedef LUCFunction ThisClass; + +public: + virtual ~LUCFunction() {} + + /// \brief Initialize a LUC public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief The LUC inverse function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class InvertibleLUCFunction : public LUCFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleLUCFunction ThisClass; + +public: + virtual ~InvertibleLUCFunction() {} + + /// \brief Create a LUC private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param eStart the desired starting public exponent + /// \details Initialize() creates a new keypair using a starting public exponent of 17. + /// \details This function overload of Initialize() creates a new keypair because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &eStart=17); + + /// \brief Initialize a LUC private key with {n,e,p,q,dp,dq,u} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_e = e; m_p = p; m_q = q; m_u = u;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize, PublicExponent (default 17)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief LUC cryptosystem +/// \since Crypto++ 2.1 +struct LUC +{ + static std::string StaticAlgorithmName() {return "LUC";} + typedef LUCFunction PublicKey; + typedef InvertibleLUCFunction PrivateKey; +}; + +/// \brief LUC encryption scheme +/// \tparam STANDARD signature standard +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCES : public TF_ES +{ +}; + +/// \brief LUC signature scheme with appendix +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCSS : public TF_SS +{ +}; + +// analogous to the RSA schemes defined in PKCS #1 v2.0 +typedef LUCES >::Decryptor LUCES_OAEP_SHA_Decryptor; +typedef LUCES >::Encryptor LUCES_OAEP_SHA_Encryptor; + +typedef LUCSS::Signer LUCSSA_PKCS1v15_SHA_Signer; +typedef LUCSS::Verifier LUCSSA_PKCS1v15_SHA_Verifier; + +// ******************************************************** + +/// \brief LUC GroupParameters precomputation +/// \details No actual precomputation is performed +/// \since Crypto++ 2.1 +class DL_GroupPrecomputation_LUC : public DL_GroupPrecomputation +{ +public: + virtual ~DL_GroupPrecomputation_LUC() {} + + const AbstractGroup & GetGroup() const {CRYPTOPP_ASSERT(false); throw 0;} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_p = v;} + const Integer & GetModulus() const {return m_p;} + +private: + Integer m_p; +}; + +/// \brief LUC Precomputation +/// \since Crypto++ 2.1 +class DL_BasePrecomputation_LUC : public DL_FixedBasePrecomputation +{ +public: + virtual ~DL_BasePrecomputation_LUC() {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const {return m_g.NotZero();} + void SetBase(const DL_GroupPrecomputation &group, const Integer &base) + {CRYPTOPP_UNUSED(group); m_g = base;} + const Integer & GetBase(const DL_GroupPrecomputation &group) const + {CRYPTOPP_UNUSED(group); return m_g;} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(maxExpBits); CRYPTOPP_UNUSED(storage);} + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + Integer Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Integer CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(exponent); CRYPTOPP_UNUSED(pc2); CRYPTOPP_UNUSED(exponent2); + // shouldn't be called + throw NotImplemented("DL_BasePrecomputation_LUC: CascadeExponentiate not implemented"); + } + +private: + Integer m_g; +}; + +/// \brief LUC GroupParameters specialization +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC : public DL_GroupParameters_IntegerBasedImpl +{ +public: + virtual ~DL_GroupParameters_LUC() {} + + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::Two();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + Element MultiplyElements(const Element &a, const Element &b) const + { + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(element1); CRYPTOPP_UNUSED(exponent1); CRYPTOPP_UNUSED(element2); CRYPTOPP_UNUSED(exponent2); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue).Assignable(); + } + +private: + int GetFieldType() const {return 2;} +}; + +/// \brief GF(p) group parameters that default to safe primes +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC_DefaultSafePrime : public DL_GroupParameters_LUC +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +/// \brief LUC HMP signature algorithm +/// \since Crypto++ 2.1 +class DL_Algorithm_LUC_HMP : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-HMP";} + + virtual ~DL_Algorithm_LUC_HMP() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const; + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const; + + size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetGroupOrder().ByteCount();} +}; + +/// \brief LUC signature keys +/// \since Crypto++ 2.1 +struct DL_SignatureKeys_LUC +{ + typedef DL_GroupParameters_LUC GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC-HMP, based on "Digital signature schemes based on Lucas functions" by Patrick Horster, Markus Michels, Holger Petersen +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUC_HMP : public DL_SS +{ +}; + +/// \brief LUC encryption keys +/// \since Crypto++ 2.1 +struct DL_CryptoKeys_LUC +{ + typedef DL_GroupParameters_LUC_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \sa CofactorMultiplicationOption +/// \since Crypto++ 2.1, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct LUC_IES + : public DL_ES< + DL_CryptoKeys_LUC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + LUC_IES<> > +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-IES";} // non-standard name +}; + +// ******************************************************** + +/// \brief LUC-DH +typedef DH_Domain LUC_DH; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/mars.cpp b/extension/third_party/cryptopp/mars.cpp new file mode 100644 index 00000000..a8d69439 --- /dev/null +++ b/extension/third_party/cryptopp/mars.cpp @@ -0,0 +1,154 @@ +// mars.cpp - originally written and placed in the public domain by Wei Dai + +// includes IBM's key setup "tweak" proposed in August 1999 (http://www.research.ibm.com/security/key-setup.txt) + +#include "pch.h" +#include "mars.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +void MARS::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + // Initialize T[] with the key data + FixedSizeSecBlock T; + GetUserKey(LITTLE_ENDIAN_ORDER, T.begin(), 15, userKey, length); + T[length/4] = length/4; + + for (unsigned int j=0; j<4; j++) // compute 10 words of K[] in each iteration + { + unsigned int i; + // Do linear transformation + for (i=0; i<15; i++) + T[i] = T[i] ^ rotlConstant<3>(T[(i + 8) % 15] ^ T[(i + 13) % 15]) ^ (4 * i + j); + + // Do four rounds of stirring + for (unsigned int k=0; k<4; k++) + for (i=0; i<15; i++) + T[i] = rotlConstant<9>(T[i] + Sbox[T[(i + 14) % 15] % 512]); + + // Store next 10 key words into K[] + for (i=0; i<10; i++) + m_k[10*j+i] = T[4*i%15]; + } + + // Modify multiplication key-words + for(unsigned int i = 5; i < 37; i += 2) + { + word32 m, w = m_k[i] | 3; + m = (~w ^ (w<<1)) & (~w ^ (w>>1)) & 0x7ffffffe; + m &= m>>1; m &= m>>2; m &= m>>4; + m |= m<<1; m |= m<<2; m |= m<<4; + m &= 0x7ffffffc; + w ^= rotlMod(Sbox[265 + (m_k[i] & 3)], m_k[i-1]) & m; + m_k[i] = w; + } +} + +#define S(a) Sbox[(a)&0x1ff] +#define S0(a) Sbox[(a)&0xff] +#define S1(a) Sbox[((a)&0xff) + 256] + +typedef BlockGetAndPut Block; + +void MARS::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + unsigned int i; + word32 a, b, c, d, l, m, r, t; + const word32 *k = m_k; + + Block::Get(inBlock)(a)(b)(c)(d); + + a += k[0]; b += k[1]; c += k[2]; d += k[3]; + + for (i=0; i<8; i++) + { + b = (b ^ S0(a)) + S1(a>>8); + c += S0(a>>16); + a = rotrConstant<24>(a); + d ^= S1(a); + a += (i%4==0) ? d : 0; + a += (i%4==1) ? b : 0; + t = a; a = b; b = c; c = d; d = t; + } + + for (i=0; i<16; i++) + { + t = rotlConstant<13>(a); + r = rotlConstant<10>(t * k[2 * i + 5]); + m = a + k[2*i+4]; + l = rotlMod((S(m) ^ rotrConstant<5>(r) ^ r), r); + c += rotlMod(m, rotrConstant<5>(r)); + (i<8 ? b : d) += l; + (i<8 ? d : b) ^= r; + a = b; b = c; c = d; d = t; + } + + for (i=0; i<8; i++) + { + a -= (i%4==2) ? d : 0; + a -= (i%4==3) ? b : 0; + b ^= S1(a); + c -= S0(a>>24); + t = rotlConstant<24>(a); + d = (d - S1(a>>16)) ^ S0(t); + a = b; b = c; c = d; d = t; + } + + a -= k[36]; b -= k[37]; c -= k[38]; d -= k[39]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +void MARS::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + unsigned int i; + word32 a, b, c, d, l, m, r, t; + const word32 *k = m_k; + + Block::Get(inBlock)(d)(c)(b)(a); + + d += k[36]; c += k[37]; b += k[38]; a += k[39]; + + for (i=0; i<8; i++) + { + b = (b ^ S0(a)) + S1(a>>8); + c += S0(a>>16); + a = rotrConstant<24>(a); + d ^= S1(a); + a += (i%4==0) ? d : 0; + a += (i%4==1) ? b : 0; + t = a; a = b; b = c; c = d; d = t; + } + + for (i=0; i<16; i++) + { + t = rotrConstant<13>(a); + r = rotlConstant<10>(a * k[35 - 2 * i]); + m = t + k[34-2*i]; + l = rotlMod((S(m) ^ rotrConstant<5>(r) ^ r), r); + c -= rotlMod(m, rotrConstant<5>(r)); + (i<8 ? b : d) -= l; + (i<8 ? d : b) ^= r; + a = b; b = c; c = d; d = t; + } + + for (i=0; i<8; i++) + { + a -= (i%4==2) ? d : 0; + a -= (i%4==3) ? b : 0; + b ^= S1(a); + c -= S0(a>>24); + t = rotlConstant<24>(a); + d = (d - S1(a>>16)) ^ S0(t); + a = b; b = c; c = d; d = t; + } + + d -= k[0]; c -= k[1]; b -= k[2]; a -= k[3]; + + Block::Put(xorBlock, outBlock)(d)(c)(b)(a); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/mars.h b/extension/third_party/cryptopp/mars.h new file mode 100644 index 00000000..1a1f2019 --- /dev/null +++ b/extension/third_party/cryptopp/mars.h @@ -0,0 +1,60 @@ +// mars.h - originally written and placed in the public domain by Wei Dai + +/// \file mars.h +/// \brief Classes for the MARS block cipher (IBM AES submission) +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MARS_H +#define CRYPTOPP_MARS_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MARS block cipher information +/// \since Crypto++ 3.0 +struct MARS_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 56, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARS";} +}; + +/// \brief MARS block cipher +/// \sa MARS +/// \since Crypto++ 3.0 +class MARS : public MARS_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static const word32 Sbox[512]; + + FixedSizeSecBlock m_k; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef MARS::Encryption MARSEncryption; +typedef MARS::Decryption MARSDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/marss.cpp b/extension/third_party/cryptopp/marss.cpp new file mode 100644 index 00000000..25c40d6c --- /dev/null +++ b/extension/third_party/cryptopp/marss.cpp @@ -0,0 +1,140 @@ +// MARS S-Box + +#include "pch.h" +#include "mars.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 MARS::Base::Sbox[512] = { + 0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, + 0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93, + 0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d, + 0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4, + 0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, + 0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac, + 0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4, + 0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26, + 0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, + 0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086, + 0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c, + 0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253, + 0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, + 0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e, + 0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b, + 0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a, + 0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, + 0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb, + 0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958, + 0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215, + 0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, + 0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c, + 0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462, + 0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44, + 0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, + 0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df, + 0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8, + 0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae, + 0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, + 0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365, + 0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3, + 0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55, + 0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, + 0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7, + 0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8, + 0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063, + 0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, + 0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371, + 0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6, + 0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b, + 0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, + 0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1, + 0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd, + 0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294, + 0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, + 0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98, + 0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f, + 0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d, + 0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, + 0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48, + 0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149, + 0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9, + 0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, + 0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e, + 0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3, + 0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52, + 0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, + 0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f, + 0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59, + 0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8, + 0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, + 0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca, + 0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3, + 0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030, + 0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, + 0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734, + 0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b, + 0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03, + 0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, + 0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3, + 0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf, + 0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568, + 0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, + 0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10, + 0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce, + 0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047, + 0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, + 0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158, + 0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969, + 0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f, + 0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, + 0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05, + 0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3, + 0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33, + 0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, + 0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd, + 0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e, + 0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246, + 0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, + 0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e, + 0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2, + 0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b, + 0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, + 0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba, + 0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c, + 0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5, + 0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, + 0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47, + 0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54, + 0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72, + 0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, + 0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6, + 0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9, + 0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68, + 0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, + 0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f, + 0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4, + 0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7, + 0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, + 0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038, + 0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c, + 0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53, + 0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, + 0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336, + 0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235, + 0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185, + 0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, + 0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558, + 0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830, + 0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85, + 0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, + 0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6, + 0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319, + 0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469, + 0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, + 0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b, + 0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0, + 0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee +}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/md2.cpp b/extension/third_party/cryptopp/md2.cpp new file mode 100644 index 00000000..b0dc7e8b --- /dev/null +++ b/extension/third_party/cryptopp/md2.cpp @@ -0,0 +1,120 @@ +// md2.cpp - modified by Wei Dai from Andrew M. Kuchling's md2.c +// The original code and all modifications are in the public domain. + +// This is the original introductory comment: + +/* + * md2.c : MD2 hash algorithm. + * + * Part of the Python Cryptography Toolkit, version 1.1 + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +#include "pch.h" +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include "md2.h" + +NAMESPACE_BEGIN(CryptoPP) +namespace Weak1 { + +MD2::MD2() + : m_X(48), m_C(16), m_buf(16) +{ + Init(); +} + +void MD2::Init() +{ + memset(m_X, 0, 48); + memset(m_C, 0, 16); + memset(m_buf, 0, 16); + m_count = 0; +} + +void MD2::Update(const byte *buf, size_t len) +{ + static const byte S[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + }; + + while (len) + { + unsigned int L = UnsignedMin(16U-m_count, len); + memcpy(m_buf+m_count, buf, L); + m_count+=L; + buf+=L; + len-=L; + if (m_count==16) + { + byte t; + int i,j; + + m_count=0; + memcpy(m_X+16, m_buf, 16); + t=m_C[15]; + for(i=0; i<16; i++) + { + m_X[32+i]=m_X[16+i]^m_X[i]; + t=m_C[i]^=S[m_buf[i]^t]; + } + + t=0; + for(i=0; i<18; i++) + { + for(j=0; j<48; j+=8) + { + t=m_X[j+0]^=S[t]; + t=m_X[j+1]^=S[t]; + t=m_X[j+2]^=S[t]; + t=m_X[j+3]^=S[t]; + t=m_X[j+4]^=S[t]; + t=m_X[j+5]^=S[t]; + t=m_X[j+6]^=S[t]; + t=m_X[j+7]^=S[t]; + } + t = byte((t+i) & 0xFF); + } + } + } +} + +void MD2::TruncatedFinal(byte *hash, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte padding[16]; + word32 padlen; + unsigned int i; + + padlen= 16-m_count; + for(i=0; iMD2 +/// \since Crypto++ 3.0 +class MD2 : public HashTransformation +{ +public: + MD2(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + unsigned int BlockSize() const {return BLOCKSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD2";} + + CRYPTOPP_CONSTANT(DIGESTSIZE = 16); + CRYPTOPP_CONSTANT(BLOCKSIZE = 16); + +private: + void Transform(); + void Init(); + SecByteBlock m_X, m_C, m_buf; + unsigned int m_count; +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/md4.cpp b/extension/third_party/cryptopp/md4.cpp new file mode 100644 index 00000000..f14588cc --- /dev/null +++ b/extension/third_party/cryptopp/md4.cpp @@ -0,0 +1,110 @@ +// md4.cpp - modified by Wei Dai from Andrew M. Kuchling's md4.c +// The original code and all modifications are in the public domain. + +// This is the original introductory comment: + +/* + * md4.c : MD4 hash algorithm. + * + * Part of the Python Cryptography Toolkit, version 1.1 + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +#include "pch.h" +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include "md4.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) +namespace Weak1 { + +void MD4::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; +} + +void MD4::Transform (word32 *digest, const word32 *in) +{ +// #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + + word32 A, B, C, D; + + A=digest[0]; + B=digest[1]; + C=digest[2]; + D=digest[3]; + +#define function(a,b,c,d,k,s) a=rotlVariable(a+F(b,c,d)+in[k],s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 1, 7); + function(C,D,A,B, 2,11); + function(B,C,D,A, 3,19); + function(A,B,C,D, 4, 3); + function(D,A,B,C, 5, 7); + function(C,D,A,B, 6,11); + function(B,C,D,A, 7,19); + function(A,B,C,D, 8, 3); + function(D,A,B,C, 9, 7); + function(C,D,A,B,10,11); + function(B,C,D,A,11,19); + function(A,B,C,D,12, 3); + function(D,A,B,C,13, 7); + function(C,D,A,B,14,11); + function(B,C,D,A,15,19); + +#undef function +#define function(a,b,c,d,k,s) a=rotlVariable(a+G(b,c,d)+in[k]+0x5a827999,s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 4, 5); + function(C,D,A,B, 8, 9); + function(B,C,D,A,12,13); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 5, 5); + function(C,D,A,B, 9, 9); + function(B,C,D,A,13,13); + function(A,B,C,D, 2, 3); + function(D,A,B,C, 6, 5); + function(C,D,A,B,10, 9); + function(B,C,D,A,14,13); + function(A,B,C,D, 3, 3); + function(D,A,B,C, 7, 5); + function(C,D,A,B,11, 9); + function(B,C,D,A,15,13); + +#undef function +#define function(a,b,c,d,k,s) a=rotlVariable(a+H(b,c,d)+in[k]+0x6ed9eba1,s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 8, 9); + function(C,D,A,B, 4,11); + function(B,C,D,A,12,15); + function(A,B,C,D, 2, 3); + function(D,A,B,C,10, 9); + function(C,D,A,B, 6,11); + function(B,C,D,A,14,15); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 9, 9); + function(C,D,A,B, 5,11); + function(B,C,D,A,13,15); + function(A,B,C,D, 3, 3); + function(D,A,B,C,11, 9); + function(C,D,A,B, 7,11); + function(B,C,D,A,15,15); + + digest[0]+=A; + digest[1]+=B; + digest[2]+=C; + digest[3]+=D; +} + +} +NAMESPACE_END diff --git a/extension/third_party/cryptopp/md4.h b/extension/third_party/cryptopp/md4.h new file mode 100644 index 00000000..8edb166d --- /dev/null +++ b/extension/third_party/cryptopp/md4.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD4_H +#define CRYPTOPP_MD4_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// MD4 +/*! \warning MD4 is considered insecure, and should not be used + unless you absolutely need it for compatibility. */ +class MD4 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD4";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/md5.cpp b/extension/third_party/cryptopp/md5.cpp new file mode 100644 index 00000000..99a0e34b --- /dev/null +++ b/extension/third_party/cryptopp/md5.cpp @@ -0,0 +1,124 @@ +// md5.cpp - modified by Wei Dai from Colin Plumb's public domain md5.c +// any modifications are placed in the public domain + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include "md5.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Weak1) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void MD5_TestInstantiations() +{ + MD5 x; +} +#endif + +void MD5::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; +} + +void MD5::Transform (word32 *digest, const word32 *data) +{ + CRYPTOPP_ASSERT(digest); + CRYPTOPP_ASSERT(data); + +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + w = rotlFixed(w + f(x, y, z) + data, s) + x + + word32 a, b, c, d; + + a=digest[0]; + b=digest[1]; + c=digest[2]; + d=digest[3]; + + MD5STEP(F1, a, b, c, d, data[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, data[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, data[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, data[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, data[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, data[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, data[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, data[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, data[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, data[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, data[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, data[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, data[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, data[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, data[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, data[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, data[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, data[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, data[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, data[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, data[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, data[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, data[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, data[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, data[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, data[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, data[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, data[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, data[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, data[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, data[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, data[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, data[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, data[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, data[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, data[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, data[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, data[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, data[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, data[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, data[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, data[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, data[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, data[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, data[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, data[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, data[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, data[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, data[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, data[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, data[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, data[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, data[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, data[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, data[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, data[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, data[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, data[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, data[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, data[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, data[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, data[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, data[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, data[9] + 0xeb86d391, 21); + + digest[0]+=a; + digest[1]+=b; + digest[2]+=c; + digest[3]+=d; +} + +NAMESPACE_END // Weak +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/md5.h b/extension/third_party/cryptopp/md5.h new file mode 100644 index 00000000..b64c8304 --- /dev/null +++ b/extension/third_party/cryptopp/md5.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD5_H +#define CRYPTOPP_MD5_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief MD5 message digest +/// \sa MD5 +/// \since Crypto++ 1.0 +class MD5 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD5";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/mdc.h b/extension/third_party/cryptopp/mdc.h new file mode 100644 index 00000000..e6926fcc --- /dev/null +++ b/extension/third_party/cryptopp/mdc.h @@ -0,0 +1,84 @@ +// mdc.h - originally written and placed in the public domain by Wei Dai + +/// \file mdc.h +/// \brief Classes for the MDC message digest + +#ifndef CRYPTOPP_MDC_H +#define CRYPTOPP_MDC_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +// GCC cast warning +#define HashWordPtr(x) ((HashWordType*)(void*)(x)) +#define ConstHashWordPtr(x) ((const HashWordType*)(const void*)(x)) + +NAMESPACE_BEGIN(CryptoPP) + +/// \tparam B BlockCipher derived class +/// \brief MDC_Info cipher information +template +struct MDC_Info : public FixedBlockSize, public FixedKeyLength +{ + static std::string StaticAlgorithmName() {return std::string("MDC/")+B::StaticAlgorithmName();} +}; + +/// \brief MDC cipher +/// \tparam H HashTransformation derived class +/// \details MDC() is a construction by Peter Gutmann to turn an iterated hash function into a PRF +/// \sa MDC +template +class MDC : public MDC_Info +{ + /// \brief MDC cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public BlockCipherImpl > + { + typedef typename H::HashWordType HashWordType; + + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + this->AssertValidKeyLength(length); + ConditionalByteReverse(BIG_ENDIAN_ORDER, Key(), ConstHashWordPtr(userKey), this->KEYLENGTH); + } + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), ConstHashWordPtr(inBlock), this->BLOCKSIZE); + H::Transform(Buffer(), Key()); + + if (xorBlock) + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), Buffer(), this->BLOCKSIZE); + xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE); + } + else + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, HashWordPtr(outBlock), Buffer(), this->BLOCKSIZE); + } + } + + bool IsPermutation() const {return false;} + + unsigned int OptimalDataAlignment() const {return sizeof(HashWordType);} + + private: + HashWordType *Key() {return HashWordPtr(m_key.data());} + const HashWordType *Key() const {return ConstHashWordPtr(m_key.data());} + HashWordType *Buffer() const {return HashWordPtr(m_buffer.data());} + + // VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup + FixedSizeSecBlock::KEYLENGTH, AllocatorWithCleanup > m_key; + mutable FixedSizeSecBlock::BLOCKSIZE, AllocatorWithCleanup > m_buffer; + }; + +public: + // use BlockCipher interface + typedef BlockCipherFinal Encryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/mersenne.h b/extension/third_party/cryptopp/mersenne.h new file mode 100644 index 00000000..96f22940 --- /dev/null +++ b/extension/third_party/cryptopp/mersenne.h @@ -0,0 +1,233 @@ +// mersenne.h - written and placed in public domain by Jeffrey Walton. + +/// \file mersenne.h +/// \brief Class file for Mersenne Twister +/// \warning MersenneTwister is suitable for Monte-Carlo simulations, where uniformaly distrubuted +/// numbers are required quickly. It should not be used for cryptographic purposes. +/// \since Crypto++ 5.6.3 +#ifndef CRYPTOPP_MERSENNE_TWISTER_H +#define CRYPTOPP_MERSENNE_TWISTER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Mersenne Twister class for Monte-Carlo simulations +/// \tparam K Magic constant +/// \tparam M Period parameter +/// \tparam N Size of the state vector +/// \tparam F Multiplier constant +/// \tparam S Initial seed +/// \details Provides the MersenneTwister implementation. The class is a header-only implementation. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \warning MersenneTwister is suitable for simulations, where uniformaly distrubuted numbers are +/// required quickly. It should not be used for cryptographic purposes. +/// \sa MT19937, MT19937ar +/// \since Crypto++ 5.6.3 +template +class MersenneTwister : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return (S==5489 ? "MT19937ar" : (S==4537 ? "MT19937" : "MT19937x")); } + + ~MersenneTwister() {} + + /// \brief Construct a Mersenne Twister + /// \param seed 32-bit seed + /// \details Defaults to template parameter S due to changing algorithm + /// parameters over time + MersenneTwister(word32 seed = S) : m_seed(seed), m_idx(N) + { + Reset(seed); + } + + bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \details MersenneTwister uses the first 32-bits of input to reseed the + /// generator. If fewer bytes are provided, then the seed is padded with 0's. + void IncorporateEntropy(const byte *input, size_t length) + { + word32 temp = 0; + ::memcpy(&temp, input, STDMIN(sizeof(temp), length)); + Reset(temp); + + // Wipe temp + SecureWipeArray(&temp, 1); + } + + /// \brief Generate random array of bytes + /// \param output byte buffer + /// \param size length of the buffer, in bytes + /// \details Bytes are written to output in big endian order. If output length + /// is not a multiple of word32, then unused bytes are not accumulated for subsequent + /// calls to GenerateBlock. Rather, the unused tail bytes are discarded, and the + /// stream is continued at the next word32 boundary from the state array. + void GenerateBlock(byte *output, size_t size) + { + // Handle word32 size blocks + word32 temp; + for (size_t i=0; i < size/4; i++, output += 4) + { + temp = NextMersenneWord(); + memcpy(output, &temp, 4); + } + + // No tail bytes + if (size%4 == 0) + { + // Wipe temp + SecureWipeArray(&temp, 1); + return; + } + + // Handle tail bytes + temp = NextMersenneWord(); + switch (size%4) + { + case 3: output[2] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 1); /* fall through */ + case 2: output[1] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 2); /* fall through */ + case 1: output[0] = CRYPTOPP_GET_BYTE_AS_BYTE(temp, 3); break; + + default: CRYPTOPP_ASSERT(0); ; + } + + // Wipe temp + SecureWipeArray(&temp, 1); + } + + /// \brief Generate a random 32-bit word in the range min to max, inclusive + /// \return random 32-bit word in the range min to max, inclusive + /// \details If the 32-bit candidate is not within the range, then it is discarded + /// and a new candidate is used. + word32 GenerateWord32(word32 min=0, word32 max=0xffffffffL) + { + const word32 range = max-min; + if (range == 0xffffffffL) + return NextMersenneWord(); + + const int maxBits = BitPrecision(range); + word32 value; + + do{ + value = Crop(NextMersenneWord(), maxBits); + } while (value > range); + + return value+min; + } + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to discard, rounded up to a word32 size + /// \details If n is not a multiple of word32, then unused bytes are + /// not accumulated for subsequent calls to GenerateBlock. Rather, the unused + /// tail bytes are discarded, and the stream is continued at the next + /// word32 boundary from the state array. + void DiscardBytes(size_t n) + { + for(size_t i=0; i < RoundUpToMultipleOf(n, 4U); i++) + NextMersenneWord(); + } + +protected: + + void Reset(word32 seed) + { + m_seed = seed; + m_idx = N; + + m_state[0] = seed; + for (unsigned int i = 1; i < N+1; i++) + m_state[i] = word32(F * (m_state[i-1] ^ (m_state[i-1] >> 30)) + i); + } + + /// \brief Returns the next 32-bit word from the state array + /// \return the next 32-bit word from the state array + /// \details fetches the next word frm the state array, performs bit operations on + /// it, and then returns the value to the caller. + word32 NextMersenneWord() + { + if (m_idx >= N) { Twist(); } + + word32 temp = m_state[m_idx++]; + + temp ^= (temp >> 11); + temp ^= (temp << 7) & 0x9D2C5680; // 0x9D2C5680 (2636928640) + temp ^= (temp << 15) & 0xEFC60000; // 0xEFC60000 (4022730752) + + return temp ^ (temp >> 18); + } + + /// \brief Performs the twist operaton on the state array + void Twist() + { + static const word32 magic[2]={0x0UL, K}; + word32 kk, temp; + + CRYPTOPP_ASSERT(N >= M); + for (kk=0;kk> 1) ^ magic[temp & 0x1UL]; + } + + for (;kk> 1) ^ magic[temp & 0x1UL]; + } + + temp = (m_state[N-1] & 0x80000000)|(m_state[0] & 0x7FFFFFFF); + m_state[N-1] = m_state[M-1] ^ (temp >> 1) ^ magic[temp & 0x1UL]; + + // Reset index + m_idx = 0; + + // Wipe temp + SecureWipeArray(&temp, 1); + } + +private: + + /// \brief 32-bit word state array of size N + FixedSizeSecBlock m_state; + /// \brief the value used to seed the generator + word32 m_seed; + /// \brief the current index into the state array + word32 m_idx; +}; + +/// \brief Original MT19937 generator provided in the ACM paper. +/// \details MT19937 uses 4537 as default initial seed. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa MT19937ar, Mersenne twister: +/// a 623-dimensionally equidistributed uniform pseudo-random number generator +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937 : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> MT19937; +#endif + +/// \brief Updated MT19937 generator adapted to provide an array for initialization. +/// \details MT19937 uses 5489 as default initial seed. Use this generator when interoperating with C++11's +/// mt19937 class. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa MT19937, Mersenne Twister +/// with improved initialization +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937ar : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> MT19937ar; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_MERSENNE_TWISTER_H diff --git a/extension/third_party/cryptopp/misc.cpp b/extension/third_party/cryptopp/misc.cpp new file mode 100644 index 00000000..26bfbc6e --- /dev/null +++ b/extension/third_party/cryptopp/misc.cpp @@ -0,0 +1,284 @@ +// misc.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4189) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6237) +# endif +#endif + +#ifndef CRYPTOPP_IMPORTS + +#include "misc.h" +#include "trap.h" +#include "words.h" +#include "stdcpp.h" +#include "integer.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +byte* BytePtr(SecByteBlock& str) +{ + // Caller wants a writeable pointer + CRYPTOPP_ASSERT(str.empty() == false); + + if (str.empty()) + return NULLPTR; + return reinterpret_cast(str.data()); +} + +const byte* ConstBytePtr(const SecByteBlock& str) +{ + if (str.empty()) + return NULLPTR; + return reinterpret_cast(str.data()); +} + +size_t BytePtrSize(const SecByteBlock& str) +{ + return str.size(); +} + +void xorbuf(byte *buf, const byte *mask, size_t count) +{ + CRYPTOPP_ASSERT(buf != NULLPTR); + CRYPTOPP_ASSERT(mask != NULLPTR); + CRYPTOPP_ASSERT(count > 0); + + size_t i=0; + if (IsAligned(buf) && IsAligned(mask)) + { + if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned(buf) && IsAligned(mask)) + { + for (i=0; i 0); + + size_t i=0; + if (IsAligned(output) && IsAligned(input) && IsAligned(mask)) + { + if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned(output) && IsAligned(input) && IsAligned(mask)) + { + for (i=0; i 0); + + size_t i=0; + byte acc8 = 0; + + if (IsAligned(buf) && IsAligned(mask) && count) + { + word32 acc32 = 0; + if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned(buf) && IsAligned(mask)) + { + word64 acc64 = 0; + for (i=0; i>32); + } + + for (i=0; i>8) | byte(acc32>>16) | byte(acc32>>24); + } + + for (i=0; i= 1400) + size_t len=0, size=0; + errno_t err = 0; + + //const wchar_t* ptr = str; + //while (*ptr++) len++; + len = wcslen(str)+1; + + err = wcstombs_s(&size, NULLPTR, 0, str, len*sizeof(wchar_t)); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::string(); + } + + result.resize(size); + err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t)); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::string(); + } + + // The safe routine's size includes the NULL. + if (!result.empty() && result[size - 1] == '\0') + result.erase(size - 1); +#else + size_t size = wcstombs(NULLPTR, str, 0); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs() call failed"); + else + return std::string(); + } + + result.resize(size); + size = wcstombs(&result[0], str, size); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs() call failed"); + else + return std::string(); + } +#endif + + return result; +} + +std::wstring StringWiden(const char *str, bool throwOnError) +{ + CRYPTOPP_ASSERT(str); + std::wstring result; + + // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55 +#if (CRYPTOPP_MSC_VERSION >= 1400) + size_t len=0, size=0; + errno_t err = 0; + + //const char* ptr = str; + //while (*ptr++) len++; + len = std::strlen(str)+1; + + err = mbstowcs_s(&size, NULLPTR, 0, str, len); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringWiden: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::wstring(); + } + + result.resize(size); + err = mbstowcs_s(&size, &result[0], size, str, len); + CRYPTOPP_ASSERT(err == 0); + if (err != 0) + { + if (throwOnError) + throw InvalidArgument("StringWiden: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::wstring(); + } + + // The safe routine's size includes the NULL. + if (!result.empty() && result[size - 1] == '\0') + result.erase(size - 1); +#else + size_t size = mbstowcs(NULLPTR, str, 0); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringWiden: mbstowcs() call failed"); + else + return std::wstring(); + } + + result.resize(size); + size = mbstowcs(&result[0], str, size); + CRYPTOPP_ASSERT(size != (size_t)-1); + if (size == (size_t)-1) + { + if (throwOnError) + throw InvalidArgument("StringWiden: mbstowcs() call failed"); + else + return std::wstring(); + } +#endif + + return result; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/misc.h b/extension/third_party/cryptopp/misc.h new file mode 100644 index 00000000..5f9e6eed --- /dev/null +++ b/extension/third_party/cryptopp/misc.h @@ -0,0 +1,2756 @@ +// misc.h - originally written and placed in the public domain by Wei Dai + +/// \file misc.h +/// \brief Utility functions for the Crypto++ library. + +#ifndef CRYPTOPP_MISC_H +#define CRYPTOPP_MISC_H + +#include "cryptlib.h" +#include "secblockfwd.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "trap.h" + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(push) +# pragma warning(disable: 4146 4514) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6326) +# endif +#endif + +// Issue 340 and Issue 793 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifdef _MSC_VER + #if _MSC_VER >= 1400 + // VC2005 workaround: disable declarations that conflict with winnt.h + #define _interlockedbittestandset CRYPTOPP_DISABLED_INTRINSIC_1 + #define _interlockedbittestandreset CRYPTOPP_DISABLED_INTRINSIC_2 + #define _interlockedbittestandset64 CRYPTOPP_DISABLED_INTRINSIC_3 + #define _interlockedbittestandreset64 CRYPTOPP_DISABLED_INTRINSIC_4 + #include + #undef _interlockedbittestandset + #undef _interlockedbittestandreset + #undef _interlockedbittestandset64 + #undef _interlockedbittestandreset64 + #define CRYPTOPP_FAST_ROTATE(x) 1 + #elif _MSC_VER >= 1300 + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32 | (x) == 64) + #else + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) + #endif +#elif (defined(__MWERKS__) && TARGET_CPU_PPC) || \ + (defined(__GNUC__) && (defined(_ARCH_PWR2) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_ARCH_COM))) + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) +#elif defined(__GNUC__) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) // depend on GCC's peephole optimization to generate rotate instructions + #define CRYPTOPP_FAST_ROTATE(x) 1 +#else + #define CRYPTOPP_FAST_ROTATE(x) 0 +#endif + +#ifdef __BORLANDC__ +#include +#include +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && defined(__linux__) +#define CRYPTOPP_BYTESWAP_AVAILABLE 1 +#include +#endif + +// Limit to ARM A-32. Aarch64 is failing self tests. +#if defined(__arm__) && (defined(__GNUC__) || defined(__clang__)) && (__ARM_ARCH >= 6) +#define CRYPTOPP_ARM_BYTEREV_AVAILABLE 1 +#endif + +// Limit to ARM A-32. Aarch64 is failing self tests. +#if defined(__arm__) && (defined(__GNUC__) || defined(__clang__)) && (__ARM_ARCH >= 7) +#define CRYPTOPP_ARM_BITREV_AVAILABLE 1 +#endif + +#if defined(__BMI__) +# include +# include +#endif // GCC and BMI + +// More LLVM bullshit. Apple Clang 6.0 does not define them. +// Later version of Clang defines them and results in warnings. +#if defined(__clang__) +# ifndef _blsr_u32 +# define _blsr_u32 __blsr_u32 +# endif +# ifndef _blsr_u64 +# define _blsr_u64 __blsr_u64 +# endif +# ifndef _tzcnt_u32 +# define _tzcnt_u32 __tzcnt_u32 +# endif +# ifndef _tzcnt_u64 +# define _tzcnt_u64 __tzcnt_u64 +# endif +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief The maximum value of a machine word +/// \details SIZE_MAX provides the maximum value of a machine word. The value +/// is 0xffffffff on 32-bit targets, and 0xffffffffffffffff on 64-bit +/// targets. +/// \details If SIZE_MAX is not defined, then __SIZE_MAX__ is used if +/// defined. If not defined, then SIZE_T_MAX is used if defined. If not defined, +/// then the library uses std::numeric_limits::max(). +/// \details The library prefers __SIZE_MAX__ or __SIZE_T_MAX__ because +/// they are effectively constexpr that is optimized well by all compilers. +/// std::numeric_limits::max() is not always a constexpr, and +/// it is not always optimized well. +# define SIZE_MAX ... +#else +// Its amazing portability problems still plague this simple concept in 2015. +// http://stackoverflow.com/questions/30472731/which-c-standard-header-defines-size-max +// Avoid NOMINMAX macro on Windows. http://support.microsoft.com/en-us/kb/143208 +#ifndef SIZE_MAX +# if defined(__SIZE_MAX__) +# define SIZE_MAX __SIZE_MAX__ +# elif defined(SIZE_T_MAX) +# define SIZE_MAX SIZE_T_MAX +# elif defined(__SIZE_TYPE__) +# define SIZE_MAX (~(__SIZE_TYPE__)0) +# else +# define SIZE_MAX ((std::numeric_limits::max)()) +# endif +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_BEGIN(CryptoPP) + +// Forward declaration for IntToString specialization +class Integer; + +// ************** compile-time assertion *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compile time assertion +/// \param expr the expression to evaluate +/// \details Asserts the expression expr during compile. If C++14 and +/// N3928 are available, then C++14 static_assert is used. Otherwise, +/// a CompileAssert structure is used. When the structure is used +/// a negative-sized array triggers the assert at compile time. +# define CRYPTOPP_COMPILE_ASSERT(expr) { ... } +#elif defined(CRYPTOPP_CXX17_STATIC_ASSERT) +# define CRYPTOPP_COMPILE_ASSERT(expr) static_assert(expr) +#else // CRYPTOPP_DOXYGEN_PROCESSING +template +struct CompileAssert +{ + static char dummy[2*b-1]; +}; + +#define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) +#define CRYPTOPP_ASSERT_JOIN(X, Y) CRYPTOPP_DO_ASSERT_JOIN(X, Y) +#define CRYPTOPP_DO_ASSERT_JOIN(X, Y) X##Y + +#if defined(CRYPTOPP_EXPORTS) || defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) +#else +# if defined(__GNUC__) || defined(__clang__) +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) __attribute__ ((unused)) +# else +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) +# endif // GCC or Clang +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** count elements in an array *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Counts elements in an array +/// \param arr an array of elements +/// \details COUNTOF counts elements in an array. On Windows COUNTOF(x) is defined +/// to _countof(x) to ensure correct results for pointers. +/// \note COUNTOF does not produce correct results with pointers, and an array must be used. +/// sizeof(x)/sizeof(x[0]) suffers the same problem. The risk is eliminated by using +/// _countof(x) on Windows. Windows will provide the immunity for other platforms. +# define COUNTOF(arr) +#else +// VS2005 added _countof +#ifndef COUNTOF +# if defined(_MSC_VER) && (_MSC_VER >= 1400) +# define COUNTOF(x) _countof(x) +# else +# define COUNTOF(x) (sizeof(x)/sizeof(x[0])) +# endif +#endif // COUNTOF +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** misc classes *************** + +/// \brief An Empty class +/// \details The Empty class can be used as a template parameter BASE when no base class exists. +class CRYPTOPP_DLL Empty +{ +}; + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) +template +class CRYPTOPP_NO_VTABLE TwoBases : public BASE1, public BASE2 +{ +}; + +template +class CRYPTOPP_NO_VTABLE ThreeBases : public BASE1, public BASE2, public BASE3 +{ +}; +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \tparam T class or type +/// \brief Uses encapsulation to hide an object in derived classes +/// \details The object T is declared as protected. +template +class ObjectHolder +{ +protected: + T m_object; +}; + +/// \brief Ensures an object is not copyable +/// \details NotCopyable ensures an object is not copyable by making the +/// copy constructor and assignment operator private. Deleters are used +/// under C++11. +/// \sa Clonable class +class NotCopyable +{ +public: + NotCopyable() {} +#if CRYPTOPP_CXX11_DELETED_FUNCTIONS + NotCopyable(const NotCopyable &) = delete; + void operator=(const NotCopyable &) = delete; +#else +private: + NotCopyable(const NotCopyable &); + void operator=(const NotCopyable &); +#endif +}; + +/// \brief An object factory function +/// \tparam T class or type +/// \details NewObject overloads operator()(). +template +struct NewObject +{ + T* operator()() const {return new T;} +}; + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief A memory barrier +/// \details MEMORY_BARRIER attempts to ensure reads and writes are completed +/// in the absence of a language synchronization point. It is used by the +/// Singleton class if the compiler supports it. The barrier is provided at the +/// customary places in a double-checked initialization. +/// \details Internally, MEMORY_BARRIER uses std::atomic_thread_fence if +/// C++11 atomics are available. Otherwise, intrinsic(_ReadWriteBarrier), +/// _ReadWriteBarrier() or __asm__("" ::: "memory") is used. +#define MEMORY_BARRIER ... +#else +#if defined(CRYPTOPP_CXX11_ATOMIC) +# define MEMORY_BARRIER() std::atomic_thread_fence(std::memory_order_acq_rel) +#elif (_MSC_VER >= 1400) +# pragma intrinsic(_ReadWriteBarrier) +# define MEMORY_BARRIER() _ReadWriteBarrier() +#elif defined(__INTEL_COMPILER) +# define MEMORY_BARRIER() __memory_barrier() +#elif defined(__GNUC__) || defined(__clang__) +# define MEMORY_BARRIER() __asm__ __volatile__ ("" ::: "memory") +#else +# define MEMORY_BARRIER() +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \brief Restricts the instantiation of a class to one static object without locks +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details This class safely initializes a static object in a multithreaded environment. For C++03 +/// and below it will do so without using locks for portability. If two threads call Ref() at the same +/// time, they may get back different references, and one object may end up being memory leaked. This +/// is by design and it avoids a subltle initialization problem ina multithreaded environment with thread +/// local storage on early Windows platforms, like Windows XP and Windows 2003. +/// \details For C++11 and above, a standard double-checked locking pattern with thread fences +/// are used. The locks and fences are standard and do not hinder portability. +/// \details Microsoft's C++11 implementation provides the necessary primitive support on Windows Vista and +/// above when using Visual Studio 2015 (cl.exe version 19.00). If C++11 is desired, you should +/// set WINVER or _WIN32_WINNT to 0x600 (or above), and compile with Visual Studio 2015. +/// \sa Double-Checked Locking +/// is Fixed In C++11, Dynamic +/// Initialization and Destruction with Concurrency and +/// Thread Local Storage (TLS) on MSDN. +/// \since Crypto++ 5.2 +template , int instance=0> +class Singleton +{ +public: + Singleton(F objectFactory = F()) : m_objectFactory(objectFactory) {} + + // prevent this function from being inlined + CRYPTOPP_NOINLINE const T & Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const; + +private: + F m_objectFactory; +}; + +/// \brief Return a reference to the inner Singleton object +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details Ref() is used to create the object using the object factory. The +/// object is only created once with the limitations discussed in the class documentation. +/// \sa Double-Checked Locking is Fixed In C++11 +/// \since Crypto++ 5.2 +template + const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const +{ +#if defined(CRYPTOPP_CXX11_ATOMIC) && defined(CRYPTOPP_CXX11_SYNCHRONIZATION) && defined(CRYPTOPP_CXX11_STATIC_INIT) + static std::mutex s_mutex; + static std::atomic s_pObject; + + T *p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + std::lock_guard lock(s_mutex); + p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + s_pObject.store(newObject, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + + return *newObject; +#else + static volatile simple_ptr s_pObject; + T *p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + { + delete newObject; + return *p; + } + + s_pObject.m_p = newObject; + MEMORY_BARRIER(); + + return *newObject; +#endif +} + +// ************** misc functions *************** + +/// \brief Create a pointer with an offset +/// \tparam PTR a pointer type +/// \tparam OFF a size type +/// \param pointer a pointer +/// \param offset a offset into the pointer +/// \details PtrAdd can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +template +inline PTR PtrAdd(PTR pointer, OFF offset) +{ + return pointer+static_cast(offset); +} + +/// \brief Create a pointer with an offset +/// \tparam PTR a pointer type +/// \tparam OFF a size type +/// \param pointer a pointer +/// \param offset a offset into the pointer +/// \details PtrSub can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +template +inline PTR PtrSub(PTR pointer, OFF offset) +{ + return pointer-static_cast(offset); +} + +/// \brief Determine pointer difference +/// \tparam PTR a pointer type +/// \param pointer1 the first pointer +/// \param pointer2 the second pointer +/// \details PtrDiff can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +/// pointer1 and pointer2 must point to the same object or +/// array (or one past the end), and yields the number of +/// elements (not bytes) difference. +template +inline ptrdiff_t PtrDiff(const PTR pointer1, const PTR pointer2) +{ + return pointer1 - pointer2; +} + +/// \brief Determine pointer difference +/// \tparam PTR a pointer type +/// \param pointer1 the first pointer +/// \param pointer2 the second pointer +/// \details PtrByteDiff can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +/// pointer1 and pointer2 must point to the same object or +/// array (or one past the end), and yields the number of +/// bytes (not elements) difference. +template +inline size_t PtrByteDiff(const PTR pointer1, const PTR pointer2) +{ + return (size_t)(reinterpret_cast(pointer1) - reinterpret_cast(pointer2)); +} + +/// \brief Pointer to the first element of a string +/// \param str std::string +/// \details BytePtr returns NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.0 +inline byte* BytePtr(std::string& str) +{ + // Caller wants a writeable pointer + CRYPTOPP_ASSERT(str.empty() == false); + + if (str.empty()) + return NULLPTR; + return reinterpret_cast(&str[0]); +} + +/// \brief Pointer to the first element of a string +/// \param str SecByteBlock +/// \details BytePtr returns NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.3 +byte* BytePtr(SecByteBlock& str); + +/// \brief Const pointer to the first element of a string +/// \param str std::string +/// \details ConstBytePtr returns non-NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.0 +inline const byte* ConstBytePtr(const std::string& str) +{ + if (str.empty()) + return NULLPTR; + return reinterpret_cast(&str[0]); +} + +/// \brief Const pointer to the first element of a string +/// \param str SecByteBlock +/// \details ConstBytePtr returns non-NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.3 +const byte* ConstBytePtr(const SecByteBlock& str); + +/// \brief Size of a string +/// \param str std::string +/// \return size of a string +inline size_t BytePtrSize(const std::string& str) +{ + return str.size(); +} + +/// \brief Size of a string +/// \param str SecByteBlock +/// \return size of a string +size_t BytePtrSize(const SecByteBlock& str); + +#if (!__STDC_WANT_SECURE_LIB__ && !defined(_MEMORY_S_DEFINED)) || defined(CRYPTOPP_WANT_SECURE_LIB) + +/// \brief Bounds checking replacement for memcpy() +/// \param dest pointer to the desination memory block +/// \param sizeInBytes size of the desination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throw InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memcpy_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memcpy_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Restricted pointers. We want to check ranges, but it is not clear how to do it. + CRYPTOPP_ASSERT(src != dest); + // Destination buffer must be large enough to satsify request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memcpy_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + if (src != NULLPTR && dest != NULLPTR) + std::memcpy(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +/// \brief Bounds checking replacement for memmove() +/// \param dest pointer to the desination memory block +/// \param sizeInBytes size of the desination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throw InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memmove_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memmove_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memmove_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Destination buffer must be large enough to satsify request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memmove_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + if (src != NULLPTR && dest != NULLPTR) + std::memmove(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +#if __BORLANDC__ >= 0x620 +// C++Builder 2010 workaround: can't use std::memcpy_s because it doesn't allow 0 lengths +# define memcpy_s CryptoPP::memcpy_s +# define memmove_s CryptoPP::memmove_s +#endif + +#endif // __STDC_WANT_SECURE_LIB__ + +/// \brief Swaps two variables which are arrays +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \details C++03 does not provide support for std::swap(__m128i a, __m128i b) +/// because __m128i is an unsigned long long[2]. Most compilers +/// support it out of the box, but Sun Studio C++ compilers 12.2 and 12.3 do not. +/// \sa How to swap two __m128i variables +/// in C++03 given its an opaque type and an array? on Stack Overflow. +template +inline void vec_swap(T& a, T& b) +{ + // __m128i is an unsigned long long[2], and support for swapping it was + // not added until C++11. SunCC 12.1 - 12.3 fail to consume the swap; while + // SunCC 12.4 consumes it without -std=c++11. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) + T t; + t=a, a=b, b=t; +#else + std::swap(a, b); +#endif +} + +/// \brief Memory block initializer +/// \param ptr pointer to the memory block being written +/// \param val the integer value to write for each byte +/// \param num the size of the source memory block, in bytes +/// \details Internally the function calls memset with the value val. +/// memset_z can be used to initialize a freshly allocated memory block. +/// To zeroize a memory block on destruction use SecureWipeBuffer. +/// \return the pointer to the memory block +/// \sa SecureWipeBuffer +inline void * memset_z(void *ptr, int val, size_t num) +{ +// avoid extranous warning on GCC 4.3.2 Ubuntu 8.10 +#if CRYPTOPP_GCC_VERSION >= 30001 || CRYPTOPP_LLVM_CLANG_VERSION >= 20800 || \ + CRYPTOPP_APPLE_CLANG_VERSION >= 30000 + if (__builtin_constant_p(num) && num==0) + return ptr; +#endif + return std::memset(ptr, val, num); +} + +/// \brief Replacement function for std::min +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison of b \< a using operator\< +/// \details STDMIN was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMIN(const T& a, const T& b) +{ + return b < a ? b : a; +} + +/// \brief Replacement function for std::max +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison of a \< b using operator\< +/// \details STDMAX was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMAX(const T& a, const T& b) +{ + return a < b ? b : a; +} + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4389) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-compare" +# pragma GCC diagnostic ignored "-Wstrict-overflow" +# if (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) +# pragma GCC diagnostic ignored "-Wtautological-compare" +# elif (CRYPTOPP_GCC_VERSION >= 40300) +# pragma GCC diagnostic ignored "-Wtype-limits" +# endif +#endif + +/// \brief Safe comparison of values that could be neagtive and incorrectly promoted +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison a and b using operator<. +/// \details The comparison b \< a is performed and the value returned is a's type T1. +template inline const T1 UnsignedMin(const T1& a, const T2& b) +{ + CRYPTOPP_COMPILE_ASSERT((sizeof(T1)<=sizeof(T2) && T2(-1)>0) || (sizeof(T1)>sizeof(T2) && T1(-1)>0)); + if (sizeof(T1)<=sizeof(T2)) + return b < (T2)a ? (T1)b : a; + else + return (T1)b < a ? (T1)b : a; +} + +/// \brief Tests whether a conversion from -> to is safe to perform +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from into to, false otherwise. +template +inline bool SafeConvert(T1 from, T2 &to) +{ + to = static_cast(from); + if (from != to || (from > 0) != (to > 0)) + return false; + return true; +} + +/// \brief Converts a value to a string +/// \tparam T class or type +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +template +std::string IntToString(T value, unsigned int base = 10) +{ + // Hack... set the high bit for uppercase. + const unsigned int HIGH_BIT = (1U << 31); + const char CH = !!(base & HIGH_BIT) ? 'A' : 'a'; + base &= ~HIGH_BIT; + + CRYPTOPP_ASSERT(base >= 2); + if (value == 0) + return "0"; + + bool negate = false; + if (value < 0) + { + negate = true; + value = 0-value; // VC .NET does not like -a + } + std::string result; + while (value > 0) + { + T digit = value % base; + result = char((digit < 10 ? '0' : (CH - 10)) + digit) + result; + value /= base; + } + if (negate) + result = "-" + result; + return result; +} + +/// \brief Converts an unsigned value to a string +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +/// \details this template function specialization was added to suppress +/// Coverity findings on IntToString() with unsigned types. +template <> CRYPTOPP_DLL +std::string IntToString(word64 value, unsigned int base); + +/// \brief Converts an Integer to a string +/// \param value the Integer to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +/// \details This is a template specialization of IntToString(). Use it +/// like IntToString(): +///
+///  // Print integer in base 10
+///  Integer n...
+///  std::string s = IntToString(n, 10);
+/// 
+/// \details The string is presented with lowercase letters by default. A +/// hack is available to switch to uppercase letters without modifying +/// the function signature. +///
+///  // Print integer in base 16, uppercase letters
+///  Integer n...
+///  const unsigned int UPPER = (1 << 31);
+///  std::string s = IntToString(n, (UPPER | 16));
+template <> CRYPTOPP_DLL +std::string IntToString(Integer value, unsigned int base); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#define RETURN_IF_NONZERO(x) size_t returnedValue = x; if (returnedValue) return returnedValue + +// this version of the macro is fastest on Pentium 3 and Pentium 4 with MSVC 6 SP5 w/ Processor Pack +#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) +// these may be faster on other CPUs/compilers +// #define GETBYTE(x, y) (unsigned int)(((x)>>(8*(y)))&255) +// #define GETBYTE(x, y) (((byte *)&(x))[y]) + +#define CRYPTOPP_GET_BYTE_AS_BYTE(x, y) byte((x)>>(8*(y))) + +/// \brief Returns the parity of a value +/// \tparam T class or type +/// \param value the value to provide the parity +/// \return 1 if the number 1-bits in the value is odd, 0 otherwise +template +unsigned int Parity(T value) +{ + for (unsigned int i=8*sizeof(value)/2; i>0; i/=2) + value ^= value >> i; + return (unsigned int)value&1; +} + +/// \brief Returns the number of 8-bit bytes or octets required for a value +/// \tparam T class or type +/// \param value the value to test +/// \return the minimum number of 8-bit bytes or octets required to represent a value +template +unsigned int BytePrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + while (h-l > 8) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h/8; +} + +/// \brief Returns the number of bits required for a value +/// \tparam T class or type +/// \param value the value to test +/// \return the maximum number of bits required to represent a value. +template +unsigned int BitPrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + + while (h-l > 1) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h; +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 32-bit value to test +/// \return the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word32 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) + return (unsigned int)_tzcnt_u32(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctz(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + unsigned long result; + _BitScanForward(&result, v); + return static_cast(result); +#else + // from http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup + static const int MultiplyDeBruijnBitPosition[32] = + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return MultiplyDeBruijnBitPosition[((word32)((v & -v) * 0x077CB531U)) >> 27]; +#endif +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 64-bit value to test +/// \return the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word64 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) && defined(__x86_64__) + return (unsigned int)_tzcnt_u64(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctzll(v); +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && (defined(_M_X64) || defined(_M_IA64)) + unsigned long result; + _BitScanForward64(&result, v); + return static_cast(result); +#else + return word32(v) ? TrailingZeros(word32(v)) : 32 + TrailingZeros(word32(v>>32)); +#endif +} + +/// \brief Truncates the value to the specified number of bits. +/// \tparam T class or type +/// \param value the value to truncate or mask +/// \param bits the number of bits to truncate or mask +/// \return the value truncated to the specified number of bits, starting at the least +/// significant bit position +/// \details This function masks the low-order bits of value and returns the result. The +/// mask is created with (1 << bits) - 1. +template +inline T Crop(T value, size_t bits) +{ + if (bits < 8*sizeof(value)) + return T(value & ((T(1) << bits) - 1)); + else + return value; +} + +/// \brief Returns the number of 8-bit bytes or octets required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of 8-bit bytes or octets required by bitCount +/// \details BitsToBytes is effectively a ceiling function based on 8-bit bytes. +inline size_t BitsToBytes(size_t bitCount) +{ + return ((bitCount+7)/(8)); +} + +/// \brief Returns the number of words required for the specified number of bytes +/// \param byteCount the number of bytes +/// \return the minimum number of words required by byteCount +/// \details BytesToWords is effectively a ceiling function based on WORD_SIZE. +/// WORD_SIZE is defined in config.h +inline size_t BytesToWords(size_t byteCount) +{ + return ((byteCount+WORD_SIZE-1)/WORD_SIZE); +} + +/// \brief Returns the number of words required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of words required by bitCount +/// \details BitsToWords is effectively a ceiling function based on WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToWords(size_t bitCount) +{ + return ((bitCount+WORD_BITS-1)/(WORD_BITS)); +} + +/// \brief Returns the number of double words required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of double words required by bitCount +/// \details BitsToDwords is effectively a ceiling function based on 2*WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToDwords(size_t bitCount) +{ + return ((bitCount+2*WORD_BITS-1)/(2*WORD_BITS)); +} + +/// Performs an XOR of a buffer with a mask +/// \param buf the buffer to XOR with the mask +/// \param mask the mask to XOR with the buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// buf[i] ^= mask[i]. buf and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *buf, const byte *mask, size_t count); + +/// Performs an XOR of an input buffer with a mask and stores the result in an output buffer +/// \param output the destination buffer +/// \param input the source buffer to XOR with the mask +/// \param mask the mask buffer to XOR with the input buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// output[i] = input[i] ^ mask[i]. output, input and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *output, const byte *input, const byte *mask, size_t count); + +/// \brief Performs a near constant-time comparison of two equally sized buffers +/// \param buf1 the first buffer +/// \param buf2 the second buffer +/// \param count the size of the buffers, in bytes +/// \details VerifyBufsEqual performs an XOR of the elements in two equally sized +/// buffers and retruns a result based on the XOR operation. A count of 0 returns +/// true because two empty buffers are considered equal. +/// \details The function is near constant-time because CPU micro-code timings could +/// affect the "constant-ness". Calling code is responsible for mitigating timing +/// attacks if the buffers are not equally sized. +/// \sa ModPowerOf2 +CRYPTOPP_DLL bool CRYPTOPP_API VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count); + +/// \brief Tests whether a value is a power of 2 +/// \param value the value to test +/// \return true if value is a power of 2, false otherwise +/// \details The function creates a mask of value - 1 and returns the result +/// of an AND operation compared to 0. If value is 0 or less than 0, then the function +/// returns false. +template +inline bool IsPowerOf2(const T &value) +{ + return value > 0 && (value & (value-1)) == 0; +} + +#if defined(__BMI__) +template <> +inline bool IsPowerOf2(const word32 &value) +{ + return value > 0 && _blsr_u32(value) == 0; +} + +# if defined(__x86_64__) +template <> +inline bool IsPowerOf2(const word64 &value) +{ + return value > 0 && _blsr_u64(value) == 0; +} +# endif // __x86_64__ +#endif // __BMI__ + +/// \brief Provide the minimum value for a type +/// \tparam T type of class +/// \return the minimum value of the type or class +/// \details NumericLimitsMin() was introduced for Clang at Issue 364, +/// Apple Clang 6.0 and numeric_limits::max() returns 0. +/// \details NumericLimitsMin() requires a specialization for T, +/// meaning std::numeric_limits::is_specialized must return +/// true. In the case of word128 Clang did not specialize +/// numeric_limits for the type. +/// \since Crypto++ 8.1 +template +inline T NumericLimitsMin() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::min)(); +} + +/// \brief Provide the maximum value for a type +/// \tparam T type of class +/// \return the maximum value of the type or class +/// \details NumericLimitsMax() was introduced for Clang at Issue 364, +/// Apple Clang 6.0 and numeric_limits::max() returns 0. +/// \details NumericLimitsMax() requires a specialization for T, +/// meaning std::numeric_limits::is_specialized must return +/// true. In the case of word128 Clang did not specialize +/// numeric_limits for the type. +/// \since Crypto++ 8.1 +template +inline T NumericLimitsMax() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::max)(); +} + +// NumericLimitsMin and NumericLimitsMax added for word128 types, +// see http://github.com/weidai11/cryptopp/issues/364 +#if defined(CRYPTOPP_WORD128_AVAILABLE) +template<> +inline word128 NumericLimitsMin() +{ + return 0; +} +template<> +inline word128 NumericLimitsMax() +{ + return (static_cast(LWORD_MAX) << 64U) | LWORD_MAX; +} +#endif + +/// \brief Performs a saturating subtract clamped at 0 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \return the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are +/// less than 0 are clamped at 0. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 0); +} + +/// \brief Performs a saturating subtract clamped at 1 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \return the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are +/// less than 1 are clamped at 1. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract1(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 1); +} + +/// \brief Reduces a value to a power of 2 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \return ModPowerOf2() returns a & (b-1). b must be a power of 2. +/// Use IsPowerOf2() to determine if b is a suitable candidate. +/// \sa IsPowerOf2 +template +inline T2 ModPowerOf2(const T1 &a, const T2 &b) +{ + CRYPTOPP_ASSERT(IsPowerOf2(b)); + // Coverity finding CID 170383 Overflowed return value (INTEGER_OVERFLOW) + return T2(a) & SaturatingSubtract(b,1U); +} + +/// \brief Rounds a value down to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce n to a multiple +/// \return the possibly unmodified value \n +/// \details RoundDownToMultipleOf is effectively a floor function based on m. The function returns +/// the value n - n\%m. If n is a multiple of m, then the original value is returned. +/// \note T1 and T2 should be usigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundDownToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (IsPowerOf2(m)) + return n - ModPowerOf2(n, m); + else + return n - n%m; +} + +/// \brief Rounds a value up to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce n to a multiple +/// \return the possibly unmodified value \n +/// \details RoundUpToMultipleOf is effectively a ceiling function based on m. The function +/// returns the value n + n\%m. If n is a multiple of m, then the original value is +/// returned. If the value n would overflow, then an InvalidArgument exception is thrown. +/// \note T1 and T2 should be usigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundUpToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (NumericLimitsMax() - m + 1 < n) + throw InvalidArgument("RoundUpToMultipleOf: integer overflow"); + return RoundDownToMultipleOf(T1(n+m-1), m); +} + +/// \brief Returns the minimum alignment requirements of a type +/// \tparam T class or type +/// \return the minimum alignment requirements of T, in bytes +/// \details Internally the function calls C++11's alignof if +/// available. If not available, then the function uses compiler +/// specific extensions such as __alignof and _alignof_. +/// If an extension is not available, then the function uses +/// sizeof(T). +template +inline unsigned int GetAlignmentOf() +{ +#if defined(CRYPTOPP_CXX11_ALIGNOF) + return alignof(T); +#elif (_MSC_VER >= 1300) + return __alignof(T); +#elif defined(__GNUC__) + return __alignof__(T); +#elif defined(__SUNPRO_CC) + return __alignof__(T); +#elif defined(__IBM_ALIGNOF__) + return __alignof__(T); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return UnsignedMin(4U, sizeof(T)); +#else + return sizeof(T); +#endif +} + +/// \brief Determines whether ptr is aligned to a minimum value +/// \param ptr the pointer being checked for alignment +/// \param alignment the alignment value to test the pointer against +/// \return true if ptr is aligned on at least alignment +/// boundary, false otherwise +/// \details Internally the function tests whether alignment is 1. If so, +/// the function returns true. If not, then the function effectively +/// performs a modular reduction and returns true if the residue is 0. +inline bool IsAlignedOn(const void *ptr, unsigned int alignment) +{ + const uintptr_t x = reinterpret_cast(ptr); + return alignment==1 || (IsPowerOf2(alignment) ? ModPowerOf2(x, alignment) == 0 : x % alignment == 0); +} + +/// \brief Determines whether ptr is minimally aligned +/// \tparam T class or type +/// \param ptr the pointer to check for alignment +/// \return true if ptr is aligned to at least T +/// boundary, false otherwise +/// \details Internally the function calls IsAlignedOn with a second +/// parameter of GetAlignmentOf. +template +inline bool IsAligned(const void *ptr) +{ + return IsAlignedOn(ptr, GetAlignmentOf()); +} + +#if (CRYPTOPP_LITTLE_ENDIAN) +typedef LittleEndian NativeByteOrder; +#elif (CRYPTOPP_BIG_ENDIAN) +typedef BigEndian NativeByteOrder; +#else +# error "Unable to determine endianness" +#endif + +/// \brief Returns NativeByteOrder as an enumerated ByteOrder value +/// \return LittleEndian if the native byte order is little-endian, +/// and BigEndian if the native byte order is big-endian +/// \details NativeByteOrder is a typedef depending on the platform. +/// If CRYPTOPP_LITTLE_ENDIAN is set in config.h, then +/// GetNativeByteOrder returns LittleEndian. If CRYPTOPP_BIG_ENDIAN +/// is set, then GetNativeByteOrder returns BigEndian. +/// \note There are other byte orders besides little- and big-endian, +/// and they include bi-endian and PDP-endian. If a system is neither +/// little-endian nor big-endian, then a compile time error occurs. +inline ByteOrder GetNativeByteOrder() +{ + return NativeByteOrder::ToEnum(); +} + +/// \brief Determines whether order follows native byte ordering +/// \param order the ordering being tested against native byte ordering +/// \return true if order follows native byte ordering, false otherwise +inline bool NativeByteOrderIs(ByteOrder order) +{ + return order == GetNativeByteOrder(); +} + +/// \brief Returns the direction the cipher is being operated +/// \tparam T class or type +/// \param obj the cipher object being queried +/// \return ENCRYPTION if the cipher obj is being operated in its forward direction, +/// DECRYPTION otherwise +/// \details A cipher can be operated in a "forward" direction (encryption) or a "reverse" +/// direction (decryption). The operations do not have to be symmetric, meaning a second +/// application of the transformation does not necessariy return the original message. +/// That is, E(D(m)) may not equal E(E(m)); and D(E(m)) may not +/// equal D(D(m)). +template +inline CipherDir GetCipherDir(const T &obj) +{ + return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; +} + +/// \brief Performs an addition with carry on a block of bytes +/// \param inout the byte block +/// \param size the size of the block, in bytes +/// \details Performs an addition with carry by adding 1 on a block of bytes starting at the least +/// significant byte. Once carry is 0, the function terminates and returns to the caller. +/// \note The function is not constant time because it stops processing when the carry is 0. +inline void IncrementCounterByOne(byte *inout, unsigned int size) +{ + CRYPTOPP_ASSERT(inout != NULLPTR); + + unsigned int carry=1; + while (carry && size != 0) + { + // On carry inout[n] equals 0 + carry = ! ++inout[size-1]; + size--; + } +} + +/// \brief Performs an addition with carry on a block of bytes +/// \param output the destination block of bytes +/// \param input the source block of bytes +/// \param size the size of the block +/// \details Performs an addition with carry on a block of bytes starting at the least significant +/// byte. Once carry is 0, the remaining bytes from input are copied to output using memcpy. +/// \details The function is close to near-constant time because it operates on all the bytes in the blocks. +inline void IncrementCounterByOne(byte *output, const byte *input, unsigned int size) +{ + CRYPTOPP_ASSERT(output != NULLPTR); + CRYPTOPP_ASSERT(input != NULLPTR); + + unsigned int carry=1; + while (carry && size != 0) + { + // On carry output[n] equals 0 + carry = ! (output[size-1] = input[size-1] + 1); + size--; + } + + while (size != 0) + { + output[size-1] = input[size-1]; + size--; + } +} + +/// \brief Performs a branchless swap of values a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first value +/// \param b the second value +template +inline void ConditionalSwap(bool c, T &a, T &b) +{ + T t = c * (a ^ b); + a ^= t; + b ^= t; +} + +/// \brief Performs a branchless swap of pointers a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first pointer +/// \param b the second pointer +template +inline void ConditionalSwapPointers(bool c, T &a, T &b) +{ + ptrdiff_t t = size_t(c) * (a - b); + a -= t; + b += t; +} + +// see http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html +// and http://www.securecoding.cert.org/confluence/display/cplusplus/MSC06-CPP.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template +void SecureWipeBuffer(T *buf, size_t n) +{ + // GCC 4.3.2 on Cygwin optimizes away the first store if this + // loop is done in the forward direction + volatile T *p = buf+n; + while (n--) + *(--p) = 0; +} + +#if !defined(CRYPTOPP_DISABLE_ASM) && \ + (_MSC_VER >= 1400 || defined(__GNUC__)) && \ + (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) + +/// \brief Sets each byte of an array to 0 +/// \param buf an array of bytes +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + volatile byte *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosb" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosb(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 16-bit element of an array to 0 +/// \param buf an array of 16-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + volatile word16 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosw" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosw(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 32-bit element of an array to 0 +/// \param buf an array of 32-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + volatile word32 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosl" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosd(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 64-bit element of an array to 0 +/// \param buf an array of 64-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ +#if CRYPTOPP_BOOL_X64 + volatile word64 *p = buf; +# ifdef __GNUC__ + asm volatile("rep stosq" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +# else + __stosq(const_cast(p), 0, n); +# endif +#else + SecureWipeBuffer(reinterpret_cast(buf), 2*n); +#endif +} + +#endif // CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86 + +#if !defined(CRYPTOPP_DISABLE_ASM) && (_MSC_VER >= 1700) && defined(_M_ARM) +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + char *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store8(--p, 0); +} + +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + short *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store16(--p, 0); +} + +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + int *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store32(--p, 0); +} + +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ + __int64 *p = reinterpret_cast<__int64*>(buf+n); + while (n--) + __iso_volatile_store64(--p, 0); +} +#endif + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template +inline void SecureWipeArray(T *buf, size_t n) +{ + if (sizeof(T) % 8 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/8)); + else if (sizeof(T) % 4 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/4)); + else if (sizeof(T) % 2 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/2)); + else + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * sizeof(T)); +} + +/// \brief Converts a wide character C-string to a multibyte string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \return str converted to a multibyte string or an empty string. +/// \details StringNarrow() converts a wide string to a narrow string using C++ std::wcstombs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-16 (0x9AA8) to UTF-8 +/// (0xE9 0xAA 0xA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::string StringNarrow(const wchar_t *str, bool throwOnError = true); + +/// \brief Converts a multibyte C-string to a wide character string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \return str converted to a multibyte string or an empty string. +/// \details StringWiden() converts a narrow string to a wide string using C++ std::mbstowcs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-8 (0xE9 0xAA 0xA8) +/// to UTF-16 (0x9AA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::wstring StringWiden(const char *str, bool throwOnError = true); + +// ************** rotate functions *************** + +/// \brief Performs a left rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount R is outside the range. +/// \details Use rotlConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotlFixed failed to compile on occasion. +/// \note rotlConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(R) < THIS_SIZE); + return T((x<>(-R&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount R is outside the range. +/// \details Use rotrConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotrFixed failed to compile on occasion. +/// \note rotrConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +template inline T rotrConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(R) < THIS_SIZE); + return T((x >> R)|(x<<(-R&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotlConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotrConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x >> y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlVariable(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrVariable(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x>>y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlMod(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + return T((x<<(y&MASK))|(x>>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrMod(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + return T((x>>(y&MASK))|(x<<(-y&MASK))); +} + +#ifdef _MSC_VER + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotl(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotr(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotr(x, static_cast(y)); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotr(x, static_cast(y)); +} + +#endif // #ifdef _MSC_VER + +#if (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) +// Intel C++ Compiler 10.0 calls a function instead of using the rotate instruction when using these instructions + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _rotl64(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotlMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotrMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +#endif // #if _MSC_VER >= 1310 + +#if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) +// Intel C++ Compiler 10.0 gives undefined externals with these +template<> inline word16 rotlFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlVariable(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrVariable(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlMod(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrMod(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline byte rotlFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlVariable(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrVariable(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlMod(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrMod(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +#endif // #if _MSC_VER >= 1400 + +#if (defined(__MWERKS__) && TARGET_CPU_PPC) + +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,y,0,31) : x; +} + +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,32-y,0,31) : x; +} + +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,32-y,0,31)); +} + +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,32-y,0,31)); +} + +#endif // __MWERKS__ && TARGET_CPU_PPC + +// ************** endian reversal *************** + +/// \brief Gets a byte from a value +/// \param order the ByteOrder of the value +/// \param value the value to retrieve the byte +/// \param index the location of the byte to retrieve +template +inline unsigned int GetByte(ByteOrder order, T value, unsigned int index) +{ + if (order == LITTLE_ENDIAN_ORDER) + return GETBYTE(value, index); + else + return GETBYTE(value, sizeof(T)-index-1); +} + +/// \brief Reverses bytes in a 8-bit value +/// \param value the 8-bit value to reverse +/// \note ByteReverse returns the value passed to it since there is nothing to +/// reverse. +inline byte ByteReverse(byte value) +{ + return value; +} + +/// \brief Reverses bytes in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function +/// performs a 8-bit rotate on the word16. +inline word16 ByteReverse(word16 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_16(value); +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_ushort(value); +#else + return rotlFixed(value, 8U); +#endif +} + +/// \brief Reverses bytes in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses +/// a combination of rotates on the word32. +inline word32 ByteReverse(word32 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_32(value); +#elif defined(CRYPTOPP_ARM_BYTEREV_AVAILABLE) + word32 rvalue; + __asm__ ("rev %0, %1" : "=r" (rvalue) : "r" (value)); + return rvalue; +#elif defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(__MWERKS__) && TARGET_CPU_PPC + return (word32)__lwbrx(&value,0); +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_ulong(value); +#elif CRYPTOPP_FAST_ROTATE(32) && !defined(__xlC__) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + +/// \brief Reverses bytes in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses +/// a combination of rotates on the word64. +inline word64 ByteReverse(word64 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_64(value); +#elif defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__x86_64__) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif (_MSC_VER >= 1400) || (defined(_MSC_VER) && !defined(_DLL)) + return _byteswap_uint64(value); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed(value, 32U); +#endif +} + +/// \brief Reverses bits in a 8-bit value +/// \param value the 8-bit value to reverse +/// \details BitReverse performs a combination of shifts on the byte. +inline byte BitReverse(byte value) +{ + value = byte((value & 0xAA) >> 1) | byte((value & 0x55) << 1); + value = byte((value & 0xCC) >> 2) | byte((value & 0x33) << 2); + return rotlFixed(value, 4U); +} + +/// \brief Reverses bits in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word16. +inline word16 BitReverse(word16 value) +{ +#if defined(CRYPTOPP_ARM_BITREV_AVAILABLE) + // 4 instructions on ARM. + word32 rvalue; + __asm__ ("rbit %0, %1" : "=r" (rvalue) : "r" (value)); + return word16(rvalue >> 16); +#else + // 15 instructions on ARM. + value = word16((value & 0xAAAA) >> 1) | word16((value & 0x5555) << 1); + value = word16((value & 0xCCCC) >> 2) | word16((value & 0x3333) << 2); + value = word16((value & 0xF0F0) >> 4) | word16((value & 0x0F0F) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word32. +inline word32 BitReverse(word32 value) +{ +#if defined(CRYPTOPP_ARM_BITREV_AVAILABLE) + // 2 instructions on ARM. + word32 rvalue; + __asm__ ("rbit %0, %1" : "=r" (rvalue) : "r" (value)); + return rvalue; +#else + // 19 instructions on ARM. + value = word32((value & 0xAAAAAAAA) >> 1) | word32((value & 0x55555555) << 1); + value = word32((value & 0xCCCCCCCC) >> 2) | word32((value & 0x33333333) << 2); + value = word32((value & 0xF0F0F0F0) >> 4) | word32((value & 0x0F0F0F0F) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word64. +inline word64 BitReverse(word64 value) +{ +#if CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(BitReverse(word32(value))) << 32) | BitReverse(word32(value>>32)); +#else + value = word64((value & W64LIT(0xAAAAAAAAAAAAAAAA)) >> 1) | word64((value & W64LIT(0x5555555555555555)) << 1); + value = word64((value & W64LIT(0xCCCCCCCCCCCCCCCC)) >> 2) | word64((value & W64LIT(0x3333333333333333)) << 2); + value = word64((value & W64LIT(0xF0F0F0F0F0F0F0F0)) >> 4) | word64((value & W64LIT(0x0F0F0F0F0F0F0F0F)) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a value +/// \param value the value to reverse +/// \details The template overload of BitReverse operates on signed and unsigned values. +/// Internally the size of T is checked, and then value is cast to a byte, +/// word16, word32 or word64. After the cast, the appropriate BitReverse +/// overload is called. +template +inline T BitReverse(T value) +{ + if (sizeof(T) == 1) + return (T)BitReverse((byte)value); + else if (sizeof(T) == 2) + return (T)BitReverse((word16)value); + else if (sizeof(T) == 4) + return (T)BitReverse((word32)value); + else if (sizeof(T) == 8) + return (T)BitReverse((word64)value); + else + { + CRYPTOPP_ASSERT(0); + return (T)BitReverse((word64)value); + } +} + +/// \brief Reverses bytes in a value depending upon endianness +/// \tparam T the class or type +/// \param order the ByteOrder of the data +/// \param value the value to conditionally reverse +/// \details Internally, the ConditionalByteReverse calls NativeByteOrderIs. +/// If order matches native byte order, then the original value is returned. +/// If not, then ByteReverse is called on the value before returning to the caller. +template +inline T ConditionalByteReverse(ByteOrder order, T value) +{ + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +/// \brief Reverses bytes in an element from an array of elements +/// \tparam T the class or type +/// \param out the output array of elements +/// \param in the input array of elements +/// \param byteCount the total number of bytes in the array +/// \details Internally, ByteReverse visits each element in the in array +/// calls ByteReverse on it, and writes the result to out. +/// \details ByteReverse does not process tail byes, or bytes that are +/// not part of a full element. If T is int (and int is 4 bytes), then +/// byteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \details The following program should help illustrate the behavior. +///
vector v1, v2;
+///
+/// v1.push_back(1);
+/// v1.push_back(2);
+/// v1.push_back(3);
+/// v1.push_back(4);
+///
+/// v2.resize(v1.size());
+/// ByteReverse(&v2[0], &v1[0], 16);
+///
+/// cout << "V1: ";
+/// for(unsigned int i = 0; i < v1.size(); i++)
+///  cout << std::hex << v1[i] << " ";
+/// cout << endl;
+///
+/// cout << "V2: ";
+/// for(unsigned int i = 0; i < v2.size(); i++)
+///  cout << std::hex << v2[i] << " ";
+/// cout << endl;
+/// The program above results in the following output. +///
V1: 00000001 00000002 00000003 00000004
+/// V2: 01000000 02000000 03000000 04000000
+/// \sa ConditionalByteReverse +template +void ByteReverse(T *out, const T *in, size_t byteCount) +{ + // Alignment check due to Issues 690 + CRYPTOPP_ASSERT(byteCount % sizeof(T) == 0); + CRYPTOPP_ASSERT(IsAligned(in)); + CRYPTOPP_ASSERT(IsAligned(out)); + + size_t count = byteCount/sizeof(T); + for (size_t i=0; ibyteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \sa ByteReverse +template +inline void ConditionalByteReverse(ByteOrder order, T *out, const T *in, size_t byteCount) +{ + if (!NativeByteOrderIs(order)) + ByteReverse(out, in, byteCount); + else if (in != out) + memcpy_s(out, byteCount, in, byteCount); +} + +template +inline void GetUserKey(ByteOrder order, T *out, size_t outlen, const byte *in, size_t inlen) +{ + const size_t U = sizeof(T); + CRYPTOPP_ASSERT(inlen <= outlen*U); + memcpy_s(out, outlen*U, in, inlen); + memset_z((byte *)out+inlen, 0, outlen*U-inlen); + ConditionalByteReverse(order, out, out, RoundUpToMultipleOf(inlen, U)); +} + +inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const byte *) +{ + CRYPTOPP_UNUSED(order); + return block[0]; +} + +inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word16 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? block[1] | (block[0] << 8) + : block[0] | (block[1] << 8); +} + +inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word32 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) | (word32(block[0]) << 24) + : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) | (word32(block[3]) << 24); +} + +inline word64 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word64 *) +{ + return (order == BIG_ENDIAN_ORDER) + ? + (word64(block[7]) | + (word64(block[6]) << 8) | + (word64(block[5]) << 16) | + (word64(block[4]) << 24) | + (word64(block[3]) << 32) | + (word64(block[2]) << 40) | + (word64(block[1]) << 48) | + (word64(block[0]) << 56)) + : + (word64(block[0]) | + (word64(block[1]) << 8) | + (word64(block[2]) << 16) | + (word64(block[3]) << 24) | + (word64(block[4]) << 32) | + (word64(block[5]) << 40) | + (word64(block[6]) << 48) | + (word64(block[7]) << 56)); +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, byte value, const byte *xorBlock) +{ + CRYPTOPP_UNUSED(order); + block[0] = static_cast(xorBlock ? (value ^ xorBlock[0]) : value); +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word16 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + } +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word32 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + } +} + +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word64 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + } +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the byte buffer to be processed +/// \return the word in the specified byte order +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///   word32 w;
+///   byte buffer[4] = {0,1,2,3};
+///   w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + CRYPTOPP_UNUSED(assumeAligned); + + T temp = 0; + if (block != NULLPTR) {std::memcpy(&temp, block, sizeof(T));} + return ConditionalByteReverse(order, temp); +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param result the word in the specified byte order +/// \param block the byte buffer to be processed +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///   word32 w;
+///   byte buffer[4] = {0,1,2,3};
+///   w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) +{ + result = GetWord(assumeAligned, order, block); +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the destination byte buffer +/// \param value the word in the specified byte order +/// \param xorBlock an optional byte buffer to xor +/// \details PutWord() provides alternate write access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +template +inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULLPTR) +{ + CRYPTOPP_UNUSED(assumeAligned); + + T t1, t2; + t1 = ConditionalByteReverse(order, value); + if (xorBlock != NULLPTR) {std::memcpy(&t2, xorBlock, sizeof(T)); t1 ^= t2;} + if (block != NULLPTR) {std::memcpy(block, &t1, sizeof(T));} +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details GetBlock() provides alternate read access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of reading two word32 values from a block of memory is shown below. w1 +/// will be 0x03020100 and w1 will be 0x07060504. +///
+///   word32 w1, w2;
+///   byte buffer[8] = {0,1,2,3,4,5,6,7};
+///   GetBlock block(buffer);
+///   block(w1)(w2);
+/// 
+template +class GetBlock +{ +public: + /// \brief Construct a GetBlock + /// \param block the memory block + GetBlock(const void *block) + : m_block((const byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to read + /// \return pointer to the remainder of the block after reading x + template + inline GetBlock & operator()(U &x) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details PutBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of writing two word32 values from a block of memory is shown below. After the code +/// executes, the byte buffer will be {0,1,2,3,4,5,6,7}. +///
+///   word32 w1=0x03020100, w2=0x07060504;
+///   byte buffer[8];
+///   PutBlock block(NULLPTR, buffer);
+///   block(w1)(w2);
+/// 
+template +class PutBlock +{ +public: + /// \brief Construct a PutBlock + /// \param block the memory block + /// \param xorBlock optional mask + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to write + /// \return pointer to the remainder of the block after writing x + template + inline PutBlock & operator()(U x) + { + PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); + m_block += sizeof(T); + if (m_xorBlock) + m_xorBlock += sizeof(T); + return *this; + } + +private: + const byte *m_xorBlock; + byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam GA flag indicating alignment for the Get operation +/// \tparam PA flag indicating alignment for the Put operation +/// \details GetBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// \sa GetBlock() and PutBlock(). +template +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between expression-statements and declarations + static inline GetBlock Get(const void *block) {return GetBlock(block);} + typedef PutBlock Put; +}; + +/// \brief Convert a word to a string +/// \tparam T class or type +/// \param value the word to convert +/// \param order byte order +/// \return a string representing the value of the word +template +std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) +{ + if (!NativeByteOrderIs(order)) + value = ByteReverse(value); + + return std::string((char *)&value, sizeof(value)); +} + +/// \brief Convert a string to a word +/// \tparam T class or type +/// \param str the string to convert +/// \param order byte order +/// \return a word representing the value of the string +template +T StringToWord(const std::string &str, ByteOrder order = BIG_ENDIAN_ORDER) +{ + T value = 0; + memcpy_s(&value, sizeof(value), str.data(), UnsignedMin(str.size(), sizeof(value))); + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +// ************** help remove warning on g++ *************** + +/// \brief Safely shift values when undefined behavior could occur +/// \tparam overflow boolean flag indicating if overflow is present +/// \details SafeShifter safely shifts values when undefined behavior could occur under C/C++ rules. +/// The class behaves much like a saturating arithmetic class, clamping values rather than allowing +/// the compiler to remove undefined behavior. +/// \sa SafeShifter, SafeShifter +template struct SafeShifter; + +/// \brief Shifts a value in the presence of overflow +/// \details the true template parameter indicates overflow would occur. +/// In this case, SafeShifter clamps the value and returns 0. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } + + /// \brief Left shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } +}; + +/// \brief Shifts a value in the absence of overflow +/// \details the false template parameter indicates overflow would not occur. +/// In this case, SafeShifter returns the shfted value. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + /// \brief Left shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +/// \brief Safely right shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to right shift +/// \result the shifted value or 0 +/// \details SafeRightShift safely shifts the value to the right when undefined behavior +/// could occur under C/C++ rules. SafeRightShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +/// \brief Safely left shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to left shift +/// \result the shifted value or 0 +/// \details SafeLeftShift safely shifts the value to the left when undefined behavior +/// could occur under C/C++ rules. SafeLeftShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + +/// \brief Finds first element not in a range +/// \tparam InputIt Input iterator type +/// \tparam T class or type +/// \param first iterator to first element +/// \param last iterator to last element +/// \param value the value used as a predicate +/// \return iterator to the first element in the range that is not value +template +inline InputIt FindIfNot(InputIt first, InputIt last, const T &value) { +#ifdef CRYPTOPP_CXX11_LAMBDA + return std::find_if(first, last, [&value](const T &o) { + return value!=o; + }); +#else + return std::find_if(first, last, std::bind2nd(std::not_equal_to(), value)); +#endif +} + +// ************** use one buffer for multiple data members *************** + +#define CRYPTOPP_BLOCK_1(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+0);} size_t SS1() {return sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_2(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS1());} size_t SS2() {return SS1()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_3(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS2());} size_t SS3() {return SS2()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_4(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS3());} size_t SS4() {return SS3()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_5(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS4());} size_t SS5() {return SS4()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_6(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS5());} size_t SS6() {return SS5()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_7(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS6());} size_t SS7() {return SS6()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_8(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS7());} size_t SS8() {return SS7()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCKS_END(i) size_t SST() {return SS##i();} void AllocateBlocks() {m_aggregate.New(SST());} AlignedSecByteBlock m_aggregate; + +NAMESPACE_END + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/extension/third_party/cryptopp/modarith.h b/extension/third_party/cryptopp/modarith.h new file mode 100644 index 00000000..a92aafe9 --- /dev/null +++ b/extension/third_party/cryptopp/modarith.h @@ -0,0 +1,344 @@ +// modarith.h - originally written and placed in the public domain by Wei Dai + +/// \file modarith.h +/// \brief Class file for performing modular arithmetic. + +#ifndef CRYPTOPP_MODARITH_H +#define CRYPTOPP_MODARITH_H + +// implementations are in integer.cpp + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain; + +/// \brief Ring of congruence classes modulo n +/// \details This implementation represents each congruence class as +/// the smallest non-negative integer in that class. +/// \details const Element& returned by member functions are +/// references to internal data members. Since each object may have +/// only one such data member for holding results, you should use the +/// class like this: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+/// The following code will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// \details If a ModularArithmetic() is copied or assigned the modulus +/// is copied, but not the internal data members. The internal data +/// members are undefined after copy or assignment. +/// \sa Integer on the +/// Crypto++ wiki. +class CRYPTOPP_DLL ModularArithmetic : public AbstractRing +{ +public: + + typedef int RandomizationParameter; + typedef Integer Element; + + virtual ~ModularArithmetic() {} + + /// \brief Construct a ModularArithmetic + /// \param modulus congruence class modulus + ModularArithmetic(const Integer &modulus = Integer::One()) + : m_modulus(modulus), m_result(static_cast(0), modulus.reg.size()) {} + + /// \brief Copy construct a ModularArithmetic + /// \param ma other ModularArithmetic + ModularArithmetic(const ModularArithmetic &ma) + : AbstractRing(ma), m_modulus(ma.m_modulus), m_result(static_cast(0), m_modulus.reg.size()) {} + + /// \brief Assign a ModularArithmetic + /// \param ma other ModularArithmetic + ModularArithmetic& operator=(const ModularArithmetic &ma) { + if (this != &ma) + { + m_modulus = ma.m_modulus; + m_result = Integer(static_cast(0), m_modulus.reg.size()); + } + return *this; + } + + /// \brief Construct a ModularArithmetic + /// \param bt BER encoded ModularArithmetic + ModularArithmetic(BufferedTransformation &bt); // construct from BER encoded parameters + + /// \brief Clone a ModularArithmetic + /// \return pointer to a new ModularArithmetic + /// \details Clone effectively copy constructs a new ModularArithmetic. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);} + + /// \brief Encodes in DER format + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encodes element in DER format + /// \param out BufferedTransformation object + /// \param a Element to encode + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + + /// \brief Decodes element in DER format + /// \param in BufferedTransformation object + /// \param a Element to decode + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + /// \brief Retrieves the modulus + /// \return the modulus + const Integer& GetModulus() const {return m_modulus;} + + /// \brief Sets the modulus + /// \param newModulus the new modulus + void SetModulus(const Integer &newModulus) + {m_modulus = newModulus; m_result.reg.resize(m_modulus.reg.size());} + + /// \brief Retrieves the representation + /// \return true if the if the modulus is in Montgomery form for multiplication, false otherwise + virtual bool IsMontgomeryRepresentation() const {return false;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \return the reduced element + /// \details ConvertIn is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertIn(const Integer &a) const + {return a%m_modulus;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \return the reduced element + /// \details ConvertOut is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertOut(const Integer &a) const + {return a;} + + /// \brief Divides an element by 2 + /// \param a element to convert + const Integer& Half(const Integer &a) const; + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \return true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + bool Equal(const Integer &a, const Integer &b) const + {return a==b;} + + /// \brief Provides the Identity element + /// \return the Identity element + const Integer& Identity() const + {return Integer::Zero();} + + /// \brief Adds elements in the ring + /// \param a first element + /// \param b second element + /// \return the sum of a and b + const Integer& Add(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + Integer& Accumulate(Integer &a, const Integer &b) const; + + /// \brief Inverts the element in the ring + /// \param a first element + /// \return the inverse of the element + const Integer& Inverse(const Integer &a) const; + + /// \brief Subtracts elements in the ring + /// \param a first element + /// \param b second element + /// \return the difference of a and b. The element a must provide a Subtract member function. + const Integer& Subtract(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + Integer& Reduce(Integer &a, const Integer &b) const; + + /// \brief Doubles an element in the ring + /// \param a the element + /// \return the element doubled + /// \details Double returns Add(a, a). The element a must provide an Add member function. + const Integer& Double(const Integer &a) const + {return Add(a, a);} + + /// \brief Retrieves the multiplicative identity + /// \return the multiplicative identity + /// \details the base class implementations returns 1. + const Integer& MultiplicativeIdentity() const + {return Integer::One();} + + /// \brief Multiplies elements in the ring + /// \param a the multiplicand + /// \param b the multiplier + /// \return the product of a and b + /// \details Multiply returns a*b\%n. + const Integer& Multiply(const Integer &a, const Integer &b) const + {return m_result1 = a*b%m_modulus;} + + /// \brief Square an element in the ring + /// \param a the element + /// \return the element squared + /// \details Square returns a*a\%n. The element a must provide a Square member function. + const Integer& Square(const Integer &a) const + {return m_result1 = a.Squared()%m_modulus;} + + /// \brief Determines whether an element is a unit in the ring + /// \param a the element + /// \return true if the element is a unit after reduction, false otherwise. + bool IsUnit(const Integer &a) const + {return Integer::Gcd(a, m_modulus).IsUnit();} + + /// \brief Calculate the multiplicative inverse of an element in the ring + /// \param a the element + /// \details MultiplicativeInverse returns a-1\%n. The element a must + /// provide a InverseMod member function. + const Integer& MultiplicativeInverse(const Integer &a) const + {return m_result1 = a.InverseMod(m_modulus);} + + /// \brief Divides elements in the ring + /// \param a the dividend + /// \param b the divisor + /// \return the quotient + /// \details Divide returns a*b-1\%n. + const Integer& Divide(const Integer &a, const Integer &b) const + {return Multiply(a, MultiplicativeInverse(b));} + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \return TODO + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Provides the maximum bit size of an element in the ring + /// \return maximum bit size of an element + unsigned int MaxElementBitLength() const + {return (m_modulus-1).BitCount();} + + /// \brief Provides the maximum byte size of an element in the ring + /// \return maximum byte size of an element + unsigned int MaxElementByteLength() const + {return (m_modulus-1).ByteCount();} + + /// \brief Provides a random element in the ring + /// \param rng RandomNumberGenerator used to generate material + /// \param ignore_for_now unused + /// \return a random element that is uniformly distributed + /// \details RandomElement constructs a new element in the range [0,n-1], inclusive. + /// The element's class must provide a constructor with the signature Element(RandomNumberGenerator rng, + /// Element min, Element max). + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter &ignore_for_now = 0) const + // left RandomizationParameter arg as ref in case RandomizationParameter becomes a more complicated struct + { + CRYPTOPP_UNUSED(ignore_for_now); + return Element(rng, Integer::Zero(), m_modulus - Integer::One()) ; + } + + /// \brief Compares two ModularArithmetic for equality + /// \param rhs other ModularArithmetic + /// \return true if this is equal to the other, false otherwise + /// \details The operator tests for equality using this.m_modulus == rhs.m_modulus. + bool operator==(const ModularArithmetic &rhs) const + {return m_modulus == rhs.m_modulus;} + + static const RandomizationParameter DefaultRandomizationParameter; + +private: + // TODO: Clang on OS X needs a real operator=. + // Squash warning on missing assignment operator. + // ModularArithmetic& operator=(const ModularArithmetic &ma); + +protected: + Integer m_modulus; + mutable Integer m_result, m_result1; +}; + +// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ; + +/// \brief Performs modular arithmetic in Montgomery representation for increased speed +/// \details The Montgomery representation represents each congruence class [a] as +/// a*r\%n, where r is a convenient power of 2. +/// \details const Element& returned by member functions are references to +/// internal data members. Since each object may have only one such data member for holding +/// results, the following code will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+class CRYPTOPP_DLL MontgomeryRepresentation : public ModularArithmetic +{ +public: + virtual ~MontgomeryRepresentation() {} + + /// \brief Construct a MontgomeryRepresentation + /// \param modulus congruence class modulus + /// \note The modulus must be odd. + MontgomeryRepresentation(const Integer &modulus); + + /// \brief Clone a MontgomeryRepresentation + /// \return pointer to a new MontgomeryRepresentation + /// \details Clone effectively copy constructs a new MontgomeryRepresentation. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);} + + bool IsMontgomeryRepresentation() const {return true;} + + Integer ConvertIn(const Integer &a) const + {return (a<<(WORD_BITS*m_modulus.reg.size()))%m_modulus;} + + Integer ConvertOut(const Integer &a) const; + + const Integer& MultiplicativeIdentity() const + {return m_result1 = Integer::Power2(WORD_BITS*m_modulus.reg.size())%m_modulus;} + + const Integer& Multiply(const Integer &a, const Integer &b) const; + + const Integer& Square(const Integer &a) const; + + const Integer& MultiplicativeInverse(const Integer &a) const; + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const + {return AbstractRing::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing::SimultaneousExponentiate(results, base, exponents, exponentsCount);} + +private: + Integer m_u; + mutable IntegerSecBlock m_workspace; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/modes.cpp b/extension/third_party/cryptopp/modes.cpp new file mode 100644 index 00000000..f307b353 --- /dev/null +++ b/extension/third_party/cryptopp/modes.cpp @@ -0,0 +1,306 @@ +// modes.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "modes.h" +#include "misc.h" + +#if defined(CRYPTOPP_DEBUG) +#include "des.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void Modes_TestInstantiations() +{ + CFB_Mode::Encryption m0; + CFB_Mode::Decryption m1; + OFB_Mode::Encryption m2; + CTR_Mode::Encryption m3; + ECB_Mode::Encryption m4; + CBC_Mode::Encryption m5; +} +#endif + +void CipherModeBase::ResizeBuffers() +{ + m_register.New(m_cipher->BlockSize()); +} + +void CFB_ModePolicy::Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) +{ + CRYPTOPP_ASSERT(input); CRYPTOPP_ASSERT(output); + CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + CRYPTOPP_ASSERT(m_temp.size() == BlockSize()); + CRYPTOPP_ASSERT(iterationCount > 0); + + const unsigned int s = BlockSize(); + if (dir == ENCRYPTION) + { + m_cipher->ProcessAndXorBlock(m_register, input, output); + if (iterationCount > 1) + m_cipher->AdvancedProcessBlocks(output, PtrAdd(input,s), PtrAdd(output,s), (iterationCount-1)*s, 0); + memcpy(m_register, PtrAdd(output,(iterationCount-1)*s), s); + } + else + { + // make copy first in case of in-place decryption + memcpy(m_temp, PtrAdd(input,(iterationCount-1)*s), s); + if (iterationCount > 1) + m_cipher->AdvancedProcessBlocks(input, PtrAdd(input,s), PtrAdd(output,s), (iterationCount-1)*s, BlockTransformation::BT_ReverseDirection); + m_cipher->ProcessAndXorBlock(m_register, input, output); + memcpy(m_register, m_temp, s); + } +} + +void CFB_ModePolicy::TransformRegister() +{ + CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + CRYPTOPP_ASSERT(m_temp.size() == BlockSize()); + + const ptrdiff_t updateSize = BlockSize()-m_feedbackSize; + m_cipher->ProcessBlock(m_register, m_temp); + memmove_s(m_register, m_register.size(), PtrAdd(m_register.begin(),m_feedbackSize), updateSize); + memcpy_s(PtrAdd(m_register.begin(),updateSize), m_register.size()-updateSize, m_temp, m_feedbackSize); +} + +void CFB_ModePolicy::CipherResynchronize(const byte *iv, size_t length) +{ + CRYPTOPP_ASSERT(length == BlockSize()); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + + CopyOrZero(m_register, m_register.size(), iv, length); + TransformRegister(); +} + +void CFB_ModePolicy::SetFeedbackSize(unsigned int feedbackSize) +{ + if (feedbackSize > BlockSize()) + throw InvalidArgument("CFB_Mode: invalid feedback size"); + m_feedbackSize = feedbackSize ? feedbackSize : BlockSize(); +} + +void CFB_ModePolicy::ResizeBuffers() +{ + CipherModeBase::ResizeBuffers(); + m_temp.New(BlockSize()); +} + +byte* CFB_ModePolicy::GetRegisterBegin() +{ + CRYPTOPP_ASSERT(!m_register.empty()); + CRYPTOPP_ASSERT(BlockSize() >= m_feedbackSize); + return PtrAdd(m_register.begin(), BlockSize() - m_feedbackSize); +} + +void OFB_ModePolicy::WriteKeystream(byte *keystreamBuffer, size_t iterationCount) +{ + CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + CRYPTOPP_ASSERT(iterationCount > 0); + + const unsigned int s = BlockSize(); + m_cipher->ProcessBlock(m_register, keystreamBuffer); + if (iterationCount > 1) + m_cipher->AdvancedProcessBlocks(keystreamBuffer, NULLPTR, PtrAdd(keystreamBuffer, s), s*(iterationCount-1), 0); + memcpy(m_register, PtrAdd(keystreamBuffer, (iterationCount-1)*s), s); +} + +void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + CRYPTOPP_ASSERT(length == BlockSize()); + + CopyOrZero(m_register, m_register.size(), iv, length); +} + +void CTR_ModePolicy::SeekToIteration(lword iterationCount) +{ + int carry=0; + for (int i=BlockSize()-1; i>=0; i--) + { + unsigned int sum = m_register[i] + (byte)iterationCount + carry; + m_counterArray[i] = byte(sum & 0xff); + carry = sum >> 8; + iterationCount >>= 8; + } +} + +void CTR_ModePolicy::IncrementCounterBy256() +{ + IncrementCounterByOne(m_counterArray, BlockSize()-1); +} + +void CTR_ModePolicy::OperateKeystream(KeystreamOperation /*operation*/, byte *output, const byte *input, size_t iterationCount) +{ + CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); + CRYPTOPP_ASSERT(m_counterArray.size() == BlockSize()); + + const unsigned int s = BlockSize(); + const unsigned int inputIncrement = input ? s : 0; + + while (iterationCount) + { + const byte lsb = m_counterArray[s-1]; + const size_t blocks = UnsignedMin(iterationCount, 256U-lsb); + + m_cipher->AdvancedProcessBlocks(m_counterArray, input, output, blocks*s, BlockTransformation::BT_InBlockIsCounter|BlockTransformation::BT_AllowParallel); + if ((m_counterArray[s-1] = byte(lsb + blocks)) == 0) + IncrementCounterBy256(); + + output = PtrAdd(output, blocks*s); + input = PtrAdd(input, blocks*inputIncrement); + iterationCount -= blocks; + } +} + +void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + CRYPTOPP_ASSERT(length == BlockSize()); + + CopyOrZero(m_register, m_register.size(), iv, length); + m_counterArray.Assign(m_register.begin(), m_register.size()); +} + +void BlockOrientedCipherModeBase::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + if (IsResynchronizable()) + { + size_t ivLength; + const byte *iv = GetIVAndThrowIfInvalid(params, ivLength); + Resynchronize(iv, (int)ivLength); + } +} + +void BlockOrientedCipherModeBase::ResizeBuffers() +{ + CipherModeBase::ResizeBuffers(); + m_buffer.New(BlockSize()); +} + +void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(length%BlockSize()==0); + m_cipher->AdvancedProcessBlocks(inString, NULLPTR, outString, length, BlockTransformation::BT_AllowParallel); +} + +void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(length%BlockSize()==0); + CRYPTOPP_ASSERT(m_register.size() == BlockSize()); + if (!length) return; + + const unsigned int blockSize = BlockSize(); + m_cipher->AdvancedProcessBlocks(inString, m_register, outString, blockSize, BlockTransformation::BT_XorInput); + if (length > blockSize) + m_cipher->AdvancedProcessBlocks(PtrAdd(inString,blockSize), outString, PtrAdd(outString,blockSize), length-blockSize, BlockTransformation::BT_XorInput); + memcpy(m_register, PtrAdd(outString, length - blockSize), blockSize); +} + +size_t CBC_CTS_Encryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + CRYPTOPP_UNUSED(outLength); + const size_t used = inLength; + const unsigned int blockSize = BlockSize(); + + if (inLength <= blockSize) + { + if (!m_stolenIV) + throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing"); + + // steal from IV + memcpy(outString, m_register, inLength); + outString = m_stolenIV; + } + else + { + // steal from next to last block + xorbuf(m_register, inString, blockSize); + m_cipher->ProcessBlock(m_register); + inString = PtrAdd(inString, blockSize); + inLength -= blockSize; + memcpy(PtrAdd(outString, blockSize), m_register, inLength); + } + + // output last full ciphertext block + xorbuf(m_register, inString, inLength); + m_cipher->ProcessBlock(m_register); + memcpy(outString, m_register, blockSize); + + return used; +} + +void CBC_Decryption::ResizeBuffers() +{ + BlockOrientedCipherModeBase::ResizeBuffers(); + m_temp.New(BlockSize()); +} + +void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(length%BlockSize()==0); + if (!length) {return;} + + // save copy now in case of in-place decryption + const unsigned int blockSize = BlockSize(); + memcpy(m_temp, PtrAdd(inString,length-blockSize), blockSize); + if (length > blockSize) + m_cipher->AdvancedProcessBlocks(PtrAdd(inString,blockSize), inString, PtrAdd(outString,blockSize), length-blockSize, BlockTransformation::BT_ReverseDirection|BlockTransformation::BT_AllowParallel); + m_cipher->ProcessAndXorBlock(inString, m_register, outString); + m_register.swap(m_temp); +} + +size_t CBC_CTS_Decryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + CRYPTOPP_UNUSED(outLength); + const byte *pn1, *pn2; + const size_t used = inLength; + const bool stealIV = inLength <= BlockSize(); + const unsigned int blockSize = BlockSize(); + + if (stealIV) + { + pn1 = inString; + pn2 = m_register; + } + else + { + pn1 = PtrAdd(inString, blockSize); + pn2 = inString; + inLength -= blockSize; + } + + // decrypt last partial plaintext block + memcpy(m_temp, pn2, blockSize); + m_cipher->ProcessBlock(m_temp); + xorbuf(m_temp, pn1, inLength); + + if (stealIV) + { + memcpy(outString, m_temp, inLength); + } + else + { + memcpy(PtrAdd(outString, blockSize), m_temp, inLength); + // decrypt next to last plaintext block + memcpy(m_temp, pn1, inLength); + m_cipher->ProcessBlock(m_temp); + xorbuf(outString, m_temp, m_register, blockSize); + } + + return used; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/modes.h b/extension/third_party/cryptopp/modes.h new file mode 100644 index 00000000..0bf1131d --- /dev/null +++ b/extension/third_party/cryptopp/modes.h @@ -0,0 +1,609 @@ +// modes.h - originally written and placed in the public domain by Wei Dai + +/// \file modes.h +/// \brief Classes for block cipher modes of operation + +#ifndef CRYPTOPP_MODES_H +#define CRYPTOPP_MODES_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "strciphr.h" +#include "argnames.h" +#include "algparam.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Block cipher mode of operation information +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. +/// For each mode there are two classes, one of which is a template class, +/// and the other one has a name that ends in "_ExternalCipher". +/// The "external cipher" mode objects hold a reference to the underlying block cipher, +/// instead of holding an instance of it. The reference must be passed in to the constructor. +/// For the "cipher holder" classes, the CIPHER template parameter should be a class +/// derived from BlockCipherDocumentation, for example DES or AES. +/// \details See NIST SP 800-38A for definitions of these modes. See +/// AuthenticatedSymmetricCipherDocumentation for authenticated encryption modes. +struct CipherModeDocumentation : public SymmetricCipherDocumentation +{ +}; + +/// \brief Block cipher mode of operation information +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CipherModeBase : public SymmetricCipher +{ +public: + virtual ~CipherModeBase() {} + + // Algorithm class + std::string AlgorithmProvider() const { + return m_cipher != NULLPTR ? m_cipher->AlgorithmProvider() : "C++"; + } + + /// \brief Returns smallest valid key length + /// \return the minimum key length, in bytes + size_t MinKeyLength() const {return m_cipher->MinKeyLength();} + + /// \brief Returns largest valid key length + /// \return the maximum key length, in bytes + size_t MaxKeyLength() const {return m_cipher->MaxKeyLength();} + + /// \brief Returns default key length + /// \return the default key length, in bytes + size_t DefaultKeyLength() const {return m_cipher->DefaultKeyLength();} + + /// \brief Returns a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + size_t GetValidKeyLength(size_t keylength) const {return m_cipher->GetValidKeyLength(keylength);} + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + bool IsValidKeyLength(size_t keylength) const {return m_cipher->IsValidKeyLength(keylength);} + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return m_cipher->OptimalDataAlignment();} + + /// \brief Returns length of the IV accepted by this object + /// \return the size of an IV, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + /// \details The default implementation throws NotImplemented + unsigned int IVSize() const {return BlockSize();} + + /// \brief Minimal requirement for secure IVs + /// \return the secure IV requirement of the algorithm + virtual IV_Requirement IVRequirement() const =0; + + /// \brief Set external block cipher + /// \param cipher An external block cipher + /// \details The cipher should be keyed. + void SetCipher(BlockCipher &cipher) + { + this->ThrowIfResynchronizable(); + this->m_cipher = &cipher; + this->ResizeBuffers(); + } + + /// \brief Set external block cipher and IV + /// \param cipher An external block cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details The cipher should be keyed. + void SetCipherWithIV(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + { + this->ThrowIfInvalidIV(iv); + this->m_cipher = &cipher; + this->ResizeBuffers(); + this->SetFeedbackSize(feedbackSize); + if (this->IsResynchronizable()) + this->Resynchronize(iv); + } + +protected: + CipherModeBase() : m_cipher(NULLPTR) {} + inline unsigned int BlockSize() const + { + CRYPTOPP_ASSERT(m_register.size() > 0); + return static_cast(m_register.size()); + } + virtual void SetFeedbackSize(unsigned int feedbackSize) + { + if (!(feedbackSize == 0 || feedbackSize == BlockSize())) + throw InvalidArgument("CipherModeBase: feedback size cannot be specified for this cipher mode"); + } + + virtual void ResizeBuffers(); + + BlockCipher *m_cipher; + SecByteBlock m_register; +}; + +/// \brief Block cipher mode of operation common operations +/// \tparam POLICY_INTERFACE common operations +template +class CRYPTOPP_NO_VTABLE ModePolicyCommonTemplate : public CipherModeBase, public POLICY_INTERFACE +{ + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); +}; + +template +void ModePolicyCommonTemplate::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + int feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0); + SetFeedbackSize(feedbackSize); +} + +/// \brief CFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CFB";} + + virtual ~CFB_ModePolicy() {} + CFB_ModePolicy() : m_feedbackSize(0) {} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return m_feedbackSize;} + bool CanIterate() const {return m_feedbackSize == BlockSize();} + void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount); + void TransformRegister(); + void CipherResynchronize(const byte *iv, size_t length); + void SetFeedbackSize(unsigned int feedbackSize); + void ResizeBuffers(); + byte * GetRegisterBegin(); + + SecByteBlock m_temp; + unsigned int m_feedbackSize; +}; + +/// \brief Initialize a block of memory +/// \param dest the destination block of memory +/// \param dsize the size of the destination block, in bytes +/// \param src the source block of memory +/// \param ssize the size of the source block, in bytes +/// \details CopyOrZero copies ssize bytes from source to destination if +/// src is not NULL. If src is NULL then dest is zero'd. Bounds are not +/// checked at runtime. Debug builds assert if ssize exceeds dsize. +inline void CopyOrZero(void *dest, size_t dsize, const void *src, size_t ssize) +{ + CRYPTOPP_ASSERT(dest); + CRYPTOPP_ASSERT(dsize >= ssize); + + if (src != NULLPTR) + memcpy_s(dest, dsize, src, ssize); + else + memset(dest, 0, dsize); +} + +/// \brief OFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE OFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "OFB";} + + bool CipherIsRandomAccess() const {return false;} + IV_Requirement IVRequirement() const {return UNIQUE_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *keystreamBuffer, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); +}; + +/// \brief CTR block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CTR_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CTR";} + + virtual ~CTR_ModePolicy() {} + bool CipherIsRandomAccess() const {return true;} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + virtual void IncrementCounterBy256(); + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *buffer, size_t iterationCount) + {OperateKeystream(WRITE_KEYSTREAM, buffer, NULLPTR, iterationCount);} + bool CanOperateKeystream() const {return true;} + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + void SeekToIteration(lword iterationCount); + + // adv_simd.h increments the counter + mutable SecByteBlock m_counterArray; +}; + +/// \brief Block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockOrientedCipherModeBase : public CipherModeBase +{ +public: + virtual ~BlockOrientedCipherModeBase() {} + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + unsigned int MandatoryBlockSize() const {return BlockSize();} + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return false;} + bool IsForwardTransformation() const + {return m_cipher->IsForwardTransformation();} + void Resynchronize(const byte *iv, int length=-1) + {memcpy_s(m_register, m_register.size(), iv, ThrowIfInvalidIVLength(length));} + +protected: + bool RequireAlignedInput() const {return true;} + virtual void ResizeBuffers(); + + SecByteBlock m_buffer; +}; + +/// \brief ECB block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ECB_OneWay : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECB";} + + void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs) + {m_cipher->SetKey(key, length, params); BlockOrientedCipherModeBase::ResizeBuffers();} + IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;} + unsigned int OptimalBlockSize() const {return static_cast(BlockSize() * m_cipher->OptimalNumberOfParallelBlocks());} + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_ModeBase : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC";} + + IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;} + bool RequireAlignedInput() const {return false;} + unsigned int MinLastBlockSize() const {return 0;} +}; + +/// \brief CBC block cipher mode of operation encryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Encryption : public CBC_ModeBase +{ +public: + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC-CTS block cipher mode of operation encryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Encryption : public CBC_Encryption +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC/CTS";} + + void SetStolenIV(byte *iv) {m_stolenIV = iv;} + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CBC_Encryption::UncheckedSetKey(key, length, params); + m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), static_cast(NULLPTR)); + } + + byte *m_stolenIV; +}; + +/// \brief CBC block cipher mode of operation decryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Decryption : public CBC_ModeBase +{ +public: + virtual ~CBC_Decryption() {} + void ProcessData(byte *outString, const byte *inString, size_t length); + +protected: + virtual void ResizeBuffers(); + + SecByteBlock m_temp; +}; + +/// \brief CBC-CTS block cipher mode of operation decryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption +{ +public: + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); +}; + +/// \brief Block cipher mode of operation aggregate +template +class CipherModeFinalTemplate_CipherHolder : protected ObjectHolder, public AlgorithmImpl > +{ +public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + static std::string CRYPTOPP_API StaticAlgorithmName() + {return CIPHER::StaticAlgorithmName() + "/" + BASE::StaticAlgorithmName();} + + /// \brief Construct a CipherModeFinalTemplate + CipherModeFinalTemplate_CipherHolder() + { + this->m_cipher = &this->m_object; + this->ResizeBuffers(); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \param iv a byte array used to resynchronize the cipher + /// \details key must be at least DEFAULT_KEYLENGTH in length. iv must be IVSize() or + /// BLOCKSIZE in length. Internally, the function calls SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details key must be at least DEFAULT_KEYLENGTH in length. iv must be IVSize() or + /// BLOCKSIZE in length. Internally, the function calls SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv, int feedbackSize) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))(Name::FeedbackSize(), feedbackSize)); + } + + // Algorithm class + std::string AlgorithmProvider() const { + return this->m_cipher->AlgorithmProvider(); + } +}; + +/// \tparam BASE CipherModeFinalTemplate_CipherHolder base class +/// \details Base class for external mode cipher combinations +template +class CipherModeFinalTemplate_ExternalCipher : public BASE +{ +public: + /// \brief Construct a default CipherModeFinalTemplate + /// \details The cipher is not keyed. + CipherModeFinalTemplate_ExternalCipher() {} + + /// \brief Construct a CipherModeFinalTemplate + /// \param cipher An external block cipher + /// \details The cipher should be keyed. + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher) + {this->SetCipher(cipher);} + + /// \brief Construct a CipherModeFinalTemplate + /// \param cipher An external block cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details The cipher should be keyed. + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + {this->SetCipherWithIV(cipher, iv, feedbackSize);} + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + /// \note AlgorithmName is not universally implemented yet + std::string AlgorithmName() const + {return (this->m_cipher ? this->m_cipher->AlgorithmName() + "/" : std::string("")) + BASE::StaticAlgorithmName();} + + // Algorithm class + std::string AlgorithmProvider() const + {return this->m_cipher->AlgorithmProvider();} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +/// \brief CFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > Decryption; +}; + +/// \brief CFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > Decryption; +}; + +/// \brief CFB block cipher mode of operation providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_FIPS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > > Decryption; +}; + +/// \brief CFB mode, external cipher, providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_FIPS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > > Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; + +/// \brief OFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct OFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief OFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct OFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher > > >; + +/// \brief CTR block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CTR_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief CTR mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CTR_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief ECB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct ECB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief ECB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct ECB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef Encryption Decryption; +}; + +/// \brief CBC block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CBC_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CBC_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +/// \brief CBC-CTS block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +template +struct CBC_CTS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode with ciphertext stealing, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/extension/third_party/cryptopp/modexppc.h b/extension/third_party/cryptopp/modexppc.h new file mode 100644 index 00000000..5e8dd676 --- /dev/null +++ b/extension/third_party/cryptopp/modexppc.h @@ -0,0 +1,48 @@ +#ifndef CRYPTOPP_MODEXPPC_H +#define CRYPTOPP_MODEXPPC_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; + +class ModExpPrecomputation : public DL_GroupPrecomputation +{ +public: + virtual ~ModExpPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &v) const {return m_mr->ConvertIn(v);} + virtual Element ConvertOut(const Element &v) const {return m_mr->ConvertOut(v);} + const AbstractGroup & GetGroup() const {return m_mr->MultiplicativeGroup();} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_mr.reset(new MontgomeryRepresentation(v));} + const Integer & GetModulus() const {return m_mr->GetModulus();} + +private: + value_ptr m_mr; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/mqueue.cpp b/extension/third_party/cryptopp/mqueue.cpp new file mode 100644 index 00000000..814c459d --- /dev/null +++ b/extension/third_party/cryptopp/mqueue.cpp @@ -0,0 +1,175 @@ +// mqueue.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "mqueue.h" + +NAMESPACE_BEGIN(CryptoPP) + +MessageQueue::MessageQueue(unsigned int nodeSize) + : m_queue(nodeSize), m_lengths(1, 0U), m_messageCounts(1, 0U) +{ +} + +size_t MessageQueue::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + if (begin >= MaxRetrievable()) + return 0; + + return m_queue.CopyRangeTo2(target, begin, STDMIN(MaxRetrievable(), end), channel, blocking); +} + +size_t MessageQueue::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + transferBytes = STDMIN(MaxRetrievable(), transferBytes); + size_t blockedBytes = m_queue.TransferTo2(target, transferBytes, channel, blocking); + m_lengths.front() -= transferBytes; + return blockedBytes; +} + +bool MessageQueue::GetNextMessage() +{ + if (NumberOfMessages() > 0 && !AnyRetrievable()) + { + m_lengths.pop_front(); + if (m_messageCounts[0] == 0 && m_messageCounts.size() > 1) + m_messageCounts.pop_front(); + return true; + } + else + return false; +} + +unsigned int MessageQueue::CopyMessagesTo(BufferedTransformation &target, unsigned int count, const std::string &channel) const +{ + ByteQueue::Walker walker(m_queue); + std::deque::const_iterator it = m_lengths.begin(); + unsigned int i; + for (i=0; i 0 && q2.AnyRetrievable()) + { + size_t len = length; + const byte *data = q2.Spy(len); + len = STDMIN(len, length); + if (memcmp(inString, data, len) != 0) + goto mismatch; + inString += len; + length -= len; + q2.Skip(len); + } + + q1.Put(inString, length); + + if (messageEnd) + { + if (q2.AnyRetrievable()) + goto mismatch; + else if (q2.AnyMessages()) + q2.GetNextMessage(); + else if (q2.NumberOfMessageSeries() > 0) + goto mismatch; + else + q1.MessageEnd(); + } + + return 0; + +mismatch: + return HandleMismatchDetected(blocking); + } +} + +bool EqualityComparisonFilter::ChannelMessageSeriesEnd(const std::string &channel, int propagation, bool blocking) +{ + unsigned int i = MapChannel(channel); + + if (i == 2) + { + OutputMessageSeriesEnd(4, propagation, blocking, channel); + return false; + } + else if (m_mismatchDetected) + return false; + else + { + MessageQueue &q1 = m_q[i], &q2 = m_q[1-i]; + + if (q2.AnyRetrievable() || q2.AnyMessages()) + goto mismatch; + else if (q2.NumberOfMessageSeries() > 0) + return Output(2, (const byte *)"\1", 1, 0, blocking) != 0; + else + q1.MessageSeriesEnd(); + + return false; + +mismatch: + return HandleMismatchDetected(blocking); + } +} + +bool EqualityComparisonFilter::HandleMismatchDetected(bool blocking) +{ + m_mismatchDetected = true; + if (m_throwIfNotEqual) + throw MismatchDetected(); + const byte b[1] = {0}; + return Output(1, b, 1, 0, blocking) != 0; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/mqueue.h b/extension/third_party/cryptopp/mqueue.h new file mode 100644 index 00000000..1225a3ad --- /dev/null +++ b/extension/third_party/cryptopp/mqueue.h @@ -0,0 +1,105 @@ +#ifndef CRYPTOPP_MQUEUE_H +#define CRYPTOPP_MQUEUE_H + +#include "cryptlib.h" +#include "queue.h" +#include "filters.h" +#include "misc.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// Message Queue +class CRYPTOPP_DLL MessageQueue : public AutoSignaling +{ +public: + MessageQueue(unsigned int nodeSize=256); + + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_queue.IsolatedInitialize(parameters); m_lengths.assign(1, 0U); m_messageCounts.assign(1, 0U);} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(blocking); + m_queue.Put(begin, length); + m_lengths.back() += length; + if (messageEnd) + { + m_lengths.push_back(0); + m_messageCounts.back()++; + } + return 0; + } + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking); return false;} + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); m_messageCounts.push_back(0); return false;} + + lword MaxRetrievable() const + {return m_lengths.front();} + bool AnyRetrievable() const + {return m_lengths.front() > 0;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + lword TotalBytesRetrievable() const + {return m_queue.MaxRetrievable();} + unsigned int NumberOfMessages() const + {return (unsigned int)m_lengths.size()-1;} + bool GetNextMessage(); + + unsigned int NumberOfMessagesInThisSeries() const + {return m_messageCounts[0];} + unsigned int NumberOfMessageSeries() const + {return (unsigned int)m_messageCounts.size()-1;} + + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + const byte * Spy(size_t &contiguousSize) const; + + void swap(MessageQueue &rhs); + +private: + ByteQueue m_queue; + std::deque m_lengths; + std::deque m_messageCounts; +}; + + +/// A filter that checks messages on two channels for equality +class CRYPTOPP_DLL EqualityComparisonFilter : public Unflushable > +{ +public: + struct MismatchDetected : public Exception {MismatchDetected() : Exception(DATA_INTEGRITY_CHECK_FAILED, "EqualityComparisonFilter: did not receive the same data on two channels") {}}; + + /*! if throwIfNotEqual is false, this filter will output a '\\0' byte when it detects a mismatch, '\\1' otherwise */ + EqualityComparisonFilter(BufferedTransformation *attachment=NULLPTR, bool throwIfNotEqual=true, const std::string &firstChannel="0", const std::string &secondChannel="1") + : m_throwIfNotEqual(throwIfNotEqual), m_mismatchDetected(false) + , m_firstChannel(firstChannel), m_secondChannel(secondChannel) + {Detach(attachment);} + + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + +private: + unsigned int MapChannel(const std::string &channel) const; + bool HandleMismatchDetected(bool blocking); + + bool m_throwIfNotEqual, m_mismatchDetected; + std::string m_firstChannel, m_secondChannel; + MessageQueue m_q[2]; +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::MessageQueue &a, CryptoPP::MessageQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/extension/third_party/cryptopp/mqv.cpp b/extension/third_party/cryptopp/mqv.cpp new file mode 100644 index 00000000..ef886251 --- /dev/null +++ b/extension/third_party/cryptopp/mqv.cpp @@ -0,0 +1,46 @@ +// mqv.cpp - originally written and placed in the public domain by Wei Dai +// HMQV provided by Jeffrey Walton, Ray Clayton and Uri Blumenthal. +// FHMQV provided by Uri Blumenthal. + +#include "pch.h" +#include "config.h" +#include "mqv.h" +#include "hmqv.h" +#include "fhmqv.h" +#include "eccrypto.h" + +// Squash MS LNK4221 and libtool warnings +extern const char MQV_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void TestInstantiations_MQV() +{ + MQV mqv; + ECMQV ecmqv; + + CRYPTOPP_UNUSED(mqv); + CRYPTOPP_UNUSED(ecmqv); +} + +void TestInstantiations_HMQV() +{ + HMQV hmqv; + ECHMQV echmqv; + + CRYPTOPP_UNUSED(hmqv); + CRYPTOPP_UNUSED(echmqv); +} + +void TestInstantiations_FHMQV() +{ + FHMQV fhmqv; + ECFHMQV ecfhmqv; + + CRYPTOPP_UNUSED(fhmqv); + CRYPTOPP_UNUSED(ecfhmqv); +} +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/mqv.h b/extension/third_party/cryptopp/mqv.h new file mode 100644 index 00000000..7ab18e55 --- /dev/null +++ b/extension/third_party/cryptopp/mqv.h @@ -0,0 +1,268 @@ +// mqv.h - originally written and placed in the public domain by Wei Dai + +/// \file mqv.h +/// \brief Classes for Menezes–Qu–Vanstone (MQV) key agreement +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MQV_H +#define CRYPTOPP_MQV_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MQV domain for performing authenticated key agreement +/// \tparam GROUP_PARAMETERS doamin parameters +/// \tparam COFACTOR_OPTION cofactor option +/// \details GROUP_PARAMETERS parameters include the curve coefcients and the base point. +/// Binary curves use a polynomial to represent its characteristic, while prime curves +/// use a prime number. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +template +class MQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef MQV_Domain Domain; + + /// \brief Construct a MQV domain + MQV_Domain() {} + + /// \brief Construct a MQV domain + /// \param params group parameters and options + MQV_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a MQV domain + /// \param bt BufferedTransformation with group parameters and options + MQV_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV = params.DecodeElement(ephemeralOtherPublicKey, true); + + Integer s(staticPrivateKey, StaticPrivateKeyLength()); + Integer u(ephemeralPrivateKey, StaticPrivateKeyLength()); + Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false); + + const Integer &r = params.GetSubgroupOrder(); + Integer h2 = Integer::Power2((r.BitCount()+1)/2); + Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r; + Integer tt = h2 + params.ConvertElementToInteger(VV) % h2; + + if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION) + { + Element P = params.ExponentiateElement(WW, tt); + P = m_groupParameters.MultiplyElements(P, VV); + Element R[2]; + const Integer e2[2] = {r, e}; + params.SimultaneousExponentiate(R, P, e2, 2); + if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1])) + return false; + params.EncodeElement(false, R[1], agreedValue); + } + else + { + const Integer &k = params.GetCofactor(); + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + e = ModularArithmetic(r).Divide(e, k); + Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r)); + if (params.IsIdentity(P)) + return false; + params.EncodeElement(false, P, agreedValue); + } + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +private: + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +/// Menezes-Qu-Vanstone in GF(p) with key validation, AKA MQV +/// \sa MQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +typedef MQV_Domain MQV; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/naclite.h b/extension/third_party/cryptopp/naclite.h new file mode 100644 index 00000000..58689720 --- /dev/null +++ b/extension/third_party/cryptopp/naclite.h @@ -0,0 +1,438 @@ +// naclite.h - written and placed in the public domain by Jeffrey Walton +// based on public domain NaCl source code written by +// Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, +// Tanja Lange, Peter Schwabe and Sjaak Smetsers. + +// The Tweet API was added to the Crypto++ library to cross-validate results. +// We debated over putting it in the Test namespace, but settled for the NaCl +// namespace to segregate it from other parts of the library. + +/// \file naclite.h +/// \brief Crypto++ interface to TweetNaCl library (20140917) +/// \details TweetNaCl is a compact reimplementation of the NaCl library +/// by Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, Tanja +/// Lange, Peter Schwabe and Sjaak Smetsers. The library is less than +/// 20 KB in size and provides 25 of the NaCl library functions. +/// \details The compact library uses curve25519, XSalsa20, Poly1305 and +/// SHA-512 as default primitives, and includes both x25519 key exchange +/// and ed25519 signatures. The complete list of functions can be found +/// in TweetNaCl: +/// A crypto library in 100 tweets (20140917), Table 1, page 5. +/// \details Crypto++ rejects small order elements using libsodium's +/// blacklist. The TweetNaCl library allowed them but the library predated +/// the attack. If you wish to allow small elements then use the "unchecked" +/// versions of crypto_box_unchecked, crypto_box_open_unchecked and +/// crypto_box_beforenm_unchecked. +/// \details TweetNaCl is well written but not well optimzed. It runs about +/// 10x slower than optimized routines from libsodium. However, the library +/// is still 2x to 4x faster than the algorithms NaCl was designed to replace +/// and allows cross-checking results from an independent implementation. +/// \details The Crypto++ wrapper for TweetNaCl requires OS features. That is, +/// NO_OS_DEPENDENCE cannot be defined. It is due to TweetNaCl's +/// internal function randombytes. Crypto++ used +/// DefaultAutoSeededRNG within randombytes, so OS +/// integration must be enabled. You can use another generator like +/// RDRAND to avoid the restriction. +/// \sa The security +/// impact of a new cryptographic library, TweetNaCl: +/// A crypto library in 100 tweets (20140917), May the Fourth Be With You: +/// A Microarchitectural Side Channel Attack on Several Real-World +/// Applications of Curve25519, libsodium +/// commit afabd7e7386e1194 and RFC 7748, Elliptic Curves for +/// Security, Section 6. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NACL_H +#define CRYPTOPP_NACL_H + +#include "config.h" +#include "stdcpp.h" + +#if defined(NO_OS_DEPENDENCE) || !defined(OS_RNG_AVAILABLE) +# define CRYPTOPP_DISABLE_NACL 1 +#endif + +#ifndef CRYPTOPP_DISABLE_NACL + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(NaCl) + +/// \brief Hash size in bytes +/// \sa NaCl crypto_hash documentation +CRYPTOPP_CONSTANT(crypto_hash_BYTES = 64); + +/// \brief Key size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_KEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_NONCEBYTES = 24); + +/// \brief Key size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_KEYBYTES = 32); +/// \brief Tag size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_BYTES = 16); + +/// \brief Key size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_KEYBYTES = 32); +/// \brief Tag size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_BYTES = 16); + +/// \brief Key size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_KEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_NONCEBYTES = 24); +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_ZEROBYTES = 32); +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_BOXZEROBYTES = 16); + +/// \brief Private key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_SECRETKEYBYTES = 32); +/// \brief Public key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_PUBLICKEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_NONCEBYTES = 24); +/// \brief Message 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_ZEROBYTES = 32); +/// \brief Open box 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BOXZEROBYTES = 16); +/// \brief Precomputation 0-byte prefix in bytes in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BEFORENMBYTES = 32); +/// \brief MAC size in bytes +/// \details crypto_box_MACBYTES was missing from tweetnacl.h. Its is defined as +/// crypto_box_curve25519xsalsa20poly1305_MACBYTES, which is defined as 16U. +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_MACBYTES = 16); + +/// \brief Private key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SECRETKEYBYTES = 64); +/// \brief Public key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_PUBLICKEYBYTES = 32); +/// \brief Seed size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SEEDBYTES = 32); +/// \brief Signature size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_BYTES = 64); + +/// \brief Group element size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_BYTES = 32); +/// \brief Integer size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_SCALARBYTES = 32); + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Generate a keypair for encryption +/// \param y public key byte buffer +/// \param x private key byte buffer +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_keypair(byte *y,byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_beforenm(byte *k,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_afternm() +/// can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_afternm(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_open_afternm() +/// can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open_afternm(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_unchecked(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box_open() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box_open() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_open_unchecked(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \details This version of crypto_box_beforenm() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box_beforenm() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_beforenm_unchecked(byte *k,const byte *y,const byte *x); + +/// \brief TODO +int crypto_core_salsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief TODO +/// \return 0 on success, non-0 otherwise +/// \since Crypto++ 6.0 +int crypto_core_hsalsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief Hash multiple blocks +/// \details crypto_hashblocks() uses crypto_hashblocks_sha512. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hashblocks(byte *x,const byte *m,word64 n); + +/// \brief Hash a message +/// \details crypto_hash() uses crypto_hash_sha512. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hash(byte *out,const byte *m,word64 n); + +/// \brief Create an authentication tag for a message +/// \details crypto_onetimeauth() uses crypto_onetimeauth_poly1305. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth(byte *out,const byte *m,word64 n,const byte *k); + +/// \brief Verify an authentication tag on a message +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth_verify(const byte *h,const byte *m,word64 n,const byte *k); + +/// \brief Scalar multiplication of a point +/// \details crypto_scalarmult() uses crypto_scalarmult_curve25519 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult(byte *q,const byte *n,const byte *p); + +/// \brief Scalar multiplication of base point +/// \details crypto_scalarmult_base() uses crypto_scalarmult_curve25519 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult_base(byte *q,const byte *n); + +/// \brief Encrypt and authenticate a message +/// \details crypto_secretbox() uses a symmetric key to encrypt and authenticate a message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox_open(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Sign a message +/// \param sm output byte buffer +/// \param smlen size of the output byte buffer +/// \param m input byte buffer +/// \param n size of the input byte buffer +/// \param sk private key +/// \details crypto_sign() uses crypto_sign_ed25519. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign(byte *sm,word64 *smlen,const byte *m,word64 n,const byte *sk); + +/// \brief Verify a message +/// \param m output byte buffer +/// \param mlen size of the output byte buffer +/// \param sm input byte buffer +/// \param n size of the input byte buffer +/// \param pk public key +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_open(byte *m,word64 *mlen,const byte *sm,word64 n,const byte *pk); + +/// \brief Generate a keypair for signing +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_keypair() creates an ed25519 keypair. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_keypair(byte *pk, byte *sk); + +/// \brief Calculate a public key from a secret key +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_sk2pk() creates an ed25519 public key from an existing +/// 32-byte secret key. The function does not backfill the tail bytes of the +/// secret key with the calculated public key. +/// \details crypto_sign_sk2pk() is not part of libsodium or Tweet API. It was +/// added for interop with some anonymous routing protocols. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 8.0 +int crypto_sign_sk2pk(byte *pk, const byte *sk); + +/// \brief Produce a keystream using XSalsa20 +/// \details crypto_stream() uses crypto_stream_xsalsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using XSalsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_xor(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Produce a keystream using Salsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using Salsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20_xor(byte *c,const byte *m,word64 b,const byte *n,const byte *k); + +/// \brief Compare 16-byte buffers +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_16(const byte *x,const byte *y); + +/// \brief Compare 32-byte buffers +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_32(const byte *x,const byte *y); + +NAMESPACE_END // CryptoPP +NAMESPACE_END // NaCl + +#endif // CRYPTOPP_DISABLE_NACL +#endif // CRYPTOPP_NACL_H diff --git a/extension/third_party/cryptopp/nbtheory.cpp b/extension/third_party/cryptopp/nbtheory.cpp new file mode 100644 index 00000000..b7a50306 --- /dev/null +++ b/extension/third_party/cryptopp/nbtheory.cpp @@ -0,0 +1,1141 @@ +// nbtheory.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "nbtheory.h" +#include "integer.h" +#include "modarith.h" +#include "algparam.h" +#include "smartptr.h" +#include "misc.h" +#include "stdcpp.h" + +#ifdef _OPENMP +# include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +const word s_lastSmallPrime = 32719; + +struct NewPrimeTable +{ + std::vector * operator()() const + { + const unsigned int maxPrimeTableSize = 3511; + + member_ptr > pPrimeTable(new std::vector); + std::vector &primeTable = *pPrimeTable; + primeTable.reserve(maxPrimeTableSize); + + primeTable.push_back(2); + unsigned int testEntriesEnd = 1; + + for (unsigned int p=3; p<=s_lastSmallPrime; p+=2) + { + unsigned int j; + for (j=1; j &primeTable = Singleton, NewPrimeTable>().Ref(); + size = (unsigned int)primeTable.size(); + return &primeTable[0]; +} + +bool IsSmallPrime(const Integer &p) +{ + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + if (p.IsPositive() && p <= primeTable[primeTableSize-1]) + return std::binary_search(primeTable, primeTable+primeTableSize, (word16)p.ConvertToLong()); + else + return false; +} + +bool TrialDivision(const Integer &p, unsigned bound) +{ + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + CRYPTOPP_ASSERT(primeTable[primeTableSize-1] >= bound); + + unsigned int i; + for (i = 0; primeTable[i]3 && b>1 && b3 && b>1 && b>a; + + Integer z = a_exp_b_mod_c(b, m, n); + if (z==1 || z==nminus1) + return true; + for (unsigned j=1; j3); + + Integer b; + for (unsigned int i=0; i2); + + Integer b=3; + unsigned int i=0; + int j; + + while ((j=Jacobi(b.Squared()-4, n)) == 1) + { + if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square + return false; + ++b; ++b; + } + + if (j==0) + return false; + else + return Lucas(n+1, b, n)==2; +} + +bool IsStrongLucasProbablePrime(const Integer &n) +{ + if (n <= 1) + return false; + + if (n.IsEven()) + return n==2; + + CRYPTOPP_ASSERT(n>2); + + Integer b=3; + unsigned int i=0; + int j; + + while ((j=Jacobi(b.Squared()-4, n)) == 1) + { + if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square + return false; + ++b; ++b; + } + + if (j==0) + return false; + + Integer n1 = n+1; + unsigned int a; + + // calculate a = largest power of 2 that divides n1 + for (a=0; ; a++) + if (n1.GetBit(a)) + break; + Integer m = n1>>a; + + Integer z = Lucas(m, b, n); + if (z==2 || z==n-2) + return true; + for (i=1; i().Ref()) + return SmallDivisorsTest(p); + else + return SmallDivisorsTest(p) && IsStrongProbablePrime(p, 3) && IsStrongLucasProbablePrime(p); +} + +bool VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level) +{ + bool pass = IsPrime(p) && RabinMillerTest(rng, p, 1); + if (level >= 1) + pass = pass && RabinMillerTest(rng, p, 10); + return pass; +} + +unsigned int PrimeSearchInterval(const Integer &max) +{ + return max.BitCount(); +} + +static inline bool FastProbablePrimeTest(const Integer &n) +{ + return IsStrongProbablePrime(n,2); +} + +AlgorithmParameters MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength) +{ + if (productBitLength < 16) + throw InvalidArgument("invalid bit length"); + + Integer minP, maxP; + + if (productBitLength%2==0) + { + minP = Integer(182) << (productBitLength/2-8); + maxP = Integer::Power2(productBitLength/2)-1; + } + else + { + minP = Integer::Power2((productBitLength-1)/2); + maxP = Integer(181) << ((productBitLength+1)/2-8); + } + + return MakeParameters("RandomNumberType", Integer::PRIME)("Min", minP)("Max", maxP); +} + +class PrimeSieve +{ +public: + // delta == 1 or -1 means double sieve with p = 2*q + delta + PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta=0); + bool NextCandidate(Integer &c); + + void DoSieve(); + static void SieveSingle(std::vector &sieve, word16 p, const Integer &first, const Integer &step, word16 stepInv); + + Integer m_first, m_last, m_step; + signed int m_delta; + word m_next; + std::vector m_sieve; +}; + +PrimeSieve::PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta) + : m_first(first), m_last(last), m_step(step), m_delta(delta), m_next(0) +{ + DoSieve(); +} + +bool PrimeSieve::NextCandidate(Integer &c) +{ + bool safe = SafeConvert(std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(), m_next); + CRYPTOPP_UNUSED(safe); CRYPTOPP_ASSERT(safe); + if (m_next == m_sieve.size()) + { + m_first += long(m_sieve.size())*m_step; + if (m_first > m_last) + return false; + else + { + m_next = 0; + DoSieve(); + return NextCandidate(c); + } + } + else + { + c = m_first + long(m_next)*m_step; + ++m_next; + return true; + } +} + +void PrimeSieve::SieveSingle(std::vector &sieve, word16 p, const Integer &first, const Integer &step, word16 stepInv) +{ + if (stepInv) + { + size_t sieveSize = sieve.size(); + size_t j = (word32(p-(first%p))*stepInv) % p; + // if the first multiple of p is p, skip it + if (first.WordCount() <= 1 && first + step*long(j) == p) + j += p; + for (; j < sieveSize; j += p) + sieve[j] = true; + } +} + +void PrimeSieve::DoSieve() +{ + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + const unsigned int maxSieveSize = 32768; + unsigned int sieveSize = STDMIN(Integer(maxSieveSize), (m_last-m_first)/m_step+1).ConvertToLong(); + + m_sieve.clear(); + m_sieve.resize(sieveSize, false); + + if (m_delta == 0) + { + for (unsigned int i = 0; i < primeTableSize; ++i) + SieveSingle(m_sieve, primeTable[i], m_first, m_step, (word16)m_step.InverseMod(primeTable[i])); + } + else + { + CRYPTOPP_ASSERT(m_step%2==0); + Integer qFirst = (m_first-m_delta) >> 1; + Integer halfStep = m_step >> 1; + for (unsigned int i = 0; i < primeTableSize; ++i) + { + word16 p = primeTable[i]; + word16 stepInv = (word16)m_step.InverseMod(p); + SieveSingle(m_sieve, p, m_first, m_step, stepInv); + + word16 halfStepInv = 2*stepInv < p ? 2*stepInv : 2*stepInv-p; + SieveSingle(m_sieve, p, qFirst, halfStep, halfStepInv); + } + } +} + +bool FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector) +{ + CRYPTOPP_ASSERT(!equiv.IsNegative() && equiv < mod); + + Integer gcd = GCD(equiv, mod); + if (gcd != Integer::One()) + { + // the only possible prime p such that p%mod==equiv where GCD(mod,equiv)!=1 is GCD(mod,equiv) + if (p <= gcd && gcd <= max && IsPrime(gcd) && (!pSelector || pSelector->IsAcceptable(gcd))) + { + p = gcd; + return true; + } + else + return false; + } + + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + if (p <= primeTable[primeTableSize-1]) + { + const word16 *pItr; + + --p; + if (p.IsPositive()) + pItr = std::upper_bound(primeTable, primeTable+primeTableSize, (word)p.ConvertToLong()); + else + pItr = primeTable; + + while (pItr < primeTable+primeTableSize && !(*pItr%mod == equiv && (!pSelector || pSelector->IsAcceptable(*pItr)))) + ++pItr; + + if (pItr < primeTable+primeTableSize) + { + p = *pItr; + return p <= max; + } + + p = primeTable[primeTableSize-1]+1; + } + + CRYPTOPP_ASSERT(p > primeTable[primeTableSize-1]); + + if (mod.IsOdd()) + return FirstPrime(p, max, CRT(equiv, mod, 1, 2, 1), mod<<1, pSelector); + + p += (equiv-p)%mod; + + if (p>max) + return false; + + PrimeSieve sieve(p, max, mod); + + while (sieve.NextCandidate(p)) + { + if ((!pSelector || pSelector->IsAcceptable(p)) && FastProbablePrimeTest(p) && IsPrime(p)) + return true; + } + + return false; +} + +// the following two functions are based on code and comments provided by Preda Mihailescu +static bool ProvePrime(const Integer &p, const Integer &q) +{ + CRYPTOPP_ASSERT(p < q*q*q); + CRYPTOPP_ASSERT(p % q == 1); + +// this is the Quisquater test. Numbers p having passed the Lucas - Lehmer test +// for q and verifying p < q^3 can only be built up of two factors, both = 1 mod q, +// or be prime. The next two lines build the discriminant of a quadratic equation +// which holds iff p is built up of two factors (exercise ... ) + + Integer r = (p-1)/q; + if (((r%q).Squared()-4*(r/q)).IsSquare()) + return false; + + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + CRYPTOPP_ASSERT(primeTableSize >= 50); + for (int i=0; i<50; i++) + { + Integer b = a_exp_b_mod_c(primeTable[i], r, p); + if (b != 1) + return a_exp_b_mod_c(b, q, p) == 1; + } + return false; +} + +Integer MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int pbits) +{ + Integer p; + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + + if (maxP <= Integer(s_lastSmallPrime).Squared()) + { + // Randomize() will generate a prime provable by trial division + p.Randomize(rng, minP, maxP, Integer::PRIME); + return p; + } + + unsigned int qbits = (pbits+2)/3 + 1 + rng.GenerateWord32(0, pbits/36); + Integer q = MihailescuProvablePrime(rng, qbits); + Integer q2 = q<<1; + + while (true) + { + // this initializes the sieve to search in the arithmetic + // progression p = p_0 + \lambda * q2 = p_0 + 2 * \lambda * q, + // with q the recursively generated prime above. We will be able + // to use Lucas tets for proving primality. A trick of Quisquater + // allows taking q > cubic_root(p) rather then square_root: this + // decreases the recursion. + + p.Randomize(rng, minP, maxP, Integer::ANY, 1, q2); + PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*q2, maxP), q2); + + while (sieve.NextCandidate(p)) + { + if (FastProbablePrimeTest(p) && ProvePrime(p, q)) + return p; + } + } + + // not reached + return p; +} + +Integer MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits) +{ + const unsigned smallPrimeBound = 29, c_opt=10; + Integer p; + + unsigned int primeTableSize; + const word16 * primeTable = GetPrimeTable(primeTableSize); + + if (bits < smallPrimeBound) + { + do + p.Randomize(rng, Integer::Power2(bits-1), Integer::Power2(bits)-1, Integer::ANY, 1, 2); + while (TrialDivision(p, 1 << ((bits+1)/2))); + } + else + { + const unsigned margin = bits > 50 ? 20 : (bits-10)/2; + double relativeSize; + do + relativeSize = std::pow(2.0, double(rng.GenerateWord32())/0xffffffff - 1); + while (bits * relativeSize >= bits - margin); + + Integer a,b; + Integer q = MaurerProvablePrime(rng, unsigned(bits*relativeSize)); + Integer I = Integer::Power2(bits-2)/q; + Integer I2 = I << 1; + unsigned int trialDivisorBound = (unsigned int)STDMIN((unsigned long)primeTable[primeTableSize-1], (unsigned long)bits*bits/c_opt); + bool success = false; + while (!success) + { + p.Randomize(rng, I, I2, Integer::ANY); + p *= q; p <<= 1; ++p; + if (!TrialDivision(p, trialDivisorBound)) + { + a.Randomize(rng, 2, p-1, Integer::ANY); + b = a_exp_b_mod_c(a, (p-1)/q, p); + success = (GCD(b-1, p) == 1) && (a_exp_b_mod_c(b, q, p) == 1); + } + } + } + return p; +} + +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u) +{ + // isn't operator overloading great? + return p * (u * (xq-xp) % q) + xp; +/* + Integer t1 = xq-xp; + cout << hex << t1 << endl; + Integer t2 = u * t1; + cout << hex << t2 << endl; + Integer t3 = t2 % q; + cout << hex << t3 << endl; + Integer t4 = p * t3; + cout << hex << t4 << endl; + Integer t5 = t4 + xp; + cout << hex << t5 << endl; + return t5; +*/ +} + +Integer ModularSquareRoot(const Integer &a, const Integer &p) +{ + if (p%4 == 3) + return a_exp_b_mod_c(a, (p+1)/4, p); + + Integer q=p-1; + unsigned int r=0; + while (q.IsEven()) + { + r++; + q >>= 1; + } + + Integer n=2; + while (Jacobi(n, p) != -1) + ++n; + + Integer y = a_exp_b_mod_c(n, q, p); + Integer x = a_exp_b_mod_c(a, (q-1)/2, p); + Integer b = (x.Squared()%p)*a%p; + x = a*x%p; + Integer tempb, t; + + while (b != 1) + { + unsigned m=0; + tempb = b; + do + { + m++; + b = b.Squared()%p; + if (m==r) + return Integer::Zero(); + } + while (b != 1); + + t = y; + for (unsigned i=0; i>= 1; + b >>= 1; + k++; + } + + while (a[0]==0) + a >>= 1; + + while (b[0]==0) + b >>= 1; + + while (1) + { + switch (a.Compare(b)) + { + case -1: + b -= a; + while (b[0]==0) + b >>= 1; + break; + + case 0: + return (a <<= k); + + case 1: + a -= b; + while (a[0]==0) + a >>= 1; + break; + + default: + CRYPTOPP_ASSERT(false); + } + } +} + +Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) +{ + CRYPTOPP_ASSERT(b.Positive()); + + if (a.Negative()) + return EuclideanMultiplicativeInverse(a%b, b); + + if (b[0]==0) + { + if (!b || a[0]==0) + return Integer::Zero(); // no inverse + if (a==1) + return 1; + Integer u = EuclideanMultiplicativeInverse(b, a); + if (!u) + return Integer::Zero(); // no inverse + else + return (b*(a-u)+1)/a; + } + + Integer u=1, d=a, v1=b, v3=b, t1, t3, b2=(b+1)>>1; + + if (a[0]) + { + t1 = Integer::Zero(); + t3 = -b; + } + else + { + t1 = b2; + t3 = a>>1; + } + + while (!!t3) + { + while (t3[0]==0) + { + t3 >>= 1; + if (t1[0]==0) + t1 >>= 1; + else + { + t1 >>= 1; + t1 += b2; + } + } + if (t3.Positive()) + { + u = t1; + d = t3; + } + else + { + v1 = b-t1; + v3 = -t3; + } + t1 = u-v1; + t3 = d-v3; + if (t1.Negative()) + t1 += b; + } + if (d==1) + return u; + else + return Integer::Zero(); // no inverse +} +*/ + +int Jacobi(const Integer &aIn, const Integer &bIn) +{ + CRYPTOPP_ASSERT(bIn.IsOdd()); + + Integer b = bIn, a = aIn%bIn; + int result = 1; + + while (!!a) + { + unsigned i=0; + while (a.GetBit(i)==0) + i++; + a>>=i; + + if (i%2==1 && (b%8==3 || b%8==5)) + result = -result; + + if (a%4==3 && b%4==3) + result = -result; + + std::swap(a, b); + a %= b; + } + + return (b==1) ? result : 0; +} + +Integer Lucas(const Integer &e, const Integer &pIn, const Integer &n) +{ + unsigned i = e.BitCount(); + if (i==0) + return Integer::Two(); + + MontgomeryRepresentation m(n); + Integer p=m.ConvertIn(pIn%n), two=m.ConvertIn(Integer::Two()); + Integer v=p, v1=m.Subtract(m.Square(p), two); + + i--; + while (i--) + { + if (e.GetBit(i)) + { + // v = (v*v1 - p) % m; + v = m.Subtract(m.Multiply(v,v1), p); + // v1 = (v1*v1 - 2) % m; + v1 = m.Subtract(m.Square(v1), two); + } + else + { + // v1 = (v*v1 - p) % m; + v1 = m.Subtract(m.Multiply(v,v1), p); + // v = (v*v - 2) % m; + v = m.Subtract(m.Square(v), two); + } + } + return m.ConvertOut(v); +} + +// This is Peter Montgomery's unpublished Lucas sequence evalutation algorithm. +// The total number of multiplies and squares used is less than the binary +// algorithm (see above). Unfortunately I can't get it to run as fast as +// the binary algorithm because of the extra overhead. +/* +Integer Lucas(const Integer &n, const Integer &P, const Integer &modulus) +{ + if (!n) + return 2; + +#define f(A, B, C) m.Subtract(m.Multiply(A, B), C) +#define X2(A) m.Subtract(m.Square(A), two) +#define X3(A) m.Multiply(A, m.Subtract(m.Square(A), three)) + + MontgomeryRepresentation m(modulus); + Integer two=m.ConvertIn(2), three=m.ConvertIn(3); + Integer A=m.ConvertIn(P), B, C, p, d=n, e, r, t, T, U; + + while (d!=1) + { + p = d; + unsigned int b = WORD_BITS * p.WordCount(); + Integer alpha = (Integer(5)<<(2*b-2)).SquareRoot() - Integer::Power2(b-1); + r = (p*alpha)>>b; + e = d-r; + B = A; + C = two; + d = r; + + while (d!=e) + { + if (d>2)) + if ((dm3+em3==0 || dm3+em3==3) && (t = e, t >>= 2, t += e, d <= t)) + { + // #1 +// t = (d+d-e)/3; +// t = d; t += d; t -= e; t /= 3; +// e = (e+e-d)/3; +// e += e; e -= d; e /= 3; +// d = t; + +// t = (d+e)/3 + t = d; t += e; t /= 3; + e -= t; + d -= t; + + T = f(A, B, C); + U = f(T, A, B); + B = f(T, B, A); + A = U; + continue; + } + +// if (dm6 == em6 && d <= e + (e>>2)) + if (dm3 == em3 && dm2 == em2 && (t = e, t >>= 2, t += e, d <= t)) + { + // #2 +// d = (d-e)>>1; + d -= e; d >>= 1; + B = f(A, B, C); + A = X2(A); + continue; + } + +// if (d <= (e<<2)) + if (d <= (t = e, t <<= 2)) + { + // #3 + d -= e; + C = f(A, B, C); + swap(B, C); + continue; + } + + if (dm2 == em2) + { + // #4 +// d = (d-e)>>1; + d -= e; d >>= 1; + B = f(A, B, C); + A = X2(A); + continue; + } + + if (dm2 == 0) + { + // #5 + d >>= 1; + C = f(A, C, B); + A = X2(A); + continue; + } + + if (dm3 == 0) + { + // #6 +// d = d/3 - e; + d /= 3; d -= e; + T = X2(A); + C = f(T, f(A, B, C), C); + swap(B, C); + A = f(T, A, A); + continue; + } + + if (dm3+em3==0 || dm3+em3==3) + { + // #7 +// d = (d-e-e)/3; + d -= e; d -= e; d /= 3; + T = f(A, B, C); + B = f(T, A, B); + A = X3(A); + continue; + } + + if (dm3 == em3) + { + // #8 +// d = (d-e)/3; + d -= e; d /= 3; + T = f(A, B, C); + C = f(A, C, B); + B = T; + A = X3(A); + continue; + } + + CRYPTOPP_ASSERT(em2 == 0); + // #9 + e >>= 1; + C = f(C, B, A); + B = X2(B); + } + + A = f(A, B, C); + } + +#undef f +#undef X2 +#undef X3 + + return m.ConvertOut(A); +} +*/ + +Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u) +{ + + // GCC warning bug, https://stackoverflow.com/q/12842306/608639 +#ifdef _OPENMP + Integer d = (m*m-4), p2, q2; + #pragma omp parallel + #pragma omp sections + { + #pragma omp section + { + p2 = p-Jacobi(d,p); + p2 = Lucas(EuclideanMultiplicativeInverse(e,p2), m, p); + } + #pragma omp section + { + q2 = q-Jacobi(d,q); + q2 = Lucas(EuclideanMultiplicativeInverse(e,q2), m, q); + } + } +#else + const Integer d = (m*m-4); + const Integer t1 = p-Jacobi(d,p); + const Integer p2 = Lucas(EuclideanMultiplicativeInverse(e,t1), m, p); + + const Integer t2 = q-Jacobi(d,q); + const Integer q2 = Lucas(EuclideanMultiplicativeInverse(e,t2), m, q); +#endif + + return CRT(p2, p, q2, q, u); +} + +unsigned int FactoringWorkFactor(unsigned int n) +{ + // extrapolated from the table in Odlyzko's "The Future of Integer Factorization" + // updated to reflect the factoring of RSA-130 + if (n<5) return 0; + else return (unsigned int)(2.4 * std::pow((double)n, 1.0/3.0) * std::pow(log(double(n)), 2.0/3.0) - 5); +} + +unsigned int DiscreteLogWorkFactor(unsigned int n) +{ + // assuming discrete log takes about the same time as factoring + if (n<5) return 0; + else return (unsigned int)(2.4 * std::pow((double)n, 1.0/3.0) * std::pow(log(double(n)), 2.0/3.0) - 5); +} + +// ******************************************************** + +void PrimeAndGenerator::Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits) +{ + // no prime exists for delta = -1, qbits = 4, and pbits = 5 + CRYPTOPP_ASSERT(qbits > 4); + CRYPTOPP_ASSERT(pbits > qbits); + + if (qbits+1 == pbits) + { + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + bool success = false; + + while (!success) + { + p.Randomize(rng, minP, maxP, Integer::ANY, 6+5*delta, 12); + PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*12, maxP), 12, delta); + + while (sieve.NextCandidate(p)) + { + CRYPTOPP_ASSERT(IsSmallPrime(p) || SmallDivisorsTest(p)); + q = (p-delta) >> 1; + CRYPTOPP_ASSERT(IsSmallPrime(q) || SmallDivisorsTest(q)); + if (FastProbablePrimeTest(q) && FastProbablePrimeTest(p) && IsPrime(q) && IsPrime(p)) + { + success = true; + break; + } + } + } + + if (delta == 1) + { + // find g such that g is a quadratic residue mod p, then g has order q + // g=4 always works, but this way we get the smallest quadratic residue (other than 1) + for (g=2; Jacobi(g, p) != 1; ++g) {} + // contributed by Walt Tuvell: g should be the following according to the Law of Quadratic Reciprocity + CRYPTOPP_ASSERT((p%8==1 || p%8==7) ? g==2 : (p%12==1 || p%12==11) ? g==3 : g==4); + } + else + { + CRYPTOPP_ASSERT(delta == -1); + // find g such that g*g-4 is a quadratic non-residue, + // and such that g has order q + for (g=3; ; ++g) + if (Jacobi(g*g-4, p)==-1 && Lucas(q, g, p)==2) + break; + } + } + else + { + Integer minQ = Integer::Power2(qbits-1); + Integer maxQ = Integer::Power2(qbits) - 1; + Integer minP = Integer::Power2(pbits-1); + Integer maxP = Integer::Power2(pbits) - 1; + + do + { + q.Randomize(rng, minQ, maxQ, Integer::PRIME); + } while (!p.Randomize(rng, minP, maxP, Integer::PRIME, delta%q, q)); + + // find a random g of order q + if (delta==1) + { + do + { + Integer h(rng, 2, p-2, Integer::ANY); + g = a_exp_b_mod_c(h, (p-1)/q, p); + } while (g <= 1); + CRYPTOPP_ASSERT(a_exp_b_mod_c(g, q, p)==1); + } + else + { + CRYPTOPP_ASSERT(delta==-1); + do + { + Integer h(rng, 3, p-1, Integer::ANY); + if (Jacobi(h*h-4, p)==1) + continue; + g = Lucas((p+1)/q, h, p); + } while (g <= 2); + CRYPTOPP_ASSERT(Lucas(q, g, p) == 2); + } + } +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/nbtheory.h b/extension/third_party/cryptopp/nbtheory.h new file mode 100644 index 00000000..22bafa3c --- /dev/null +++ b/extension/third_party/cryptopp/nbtheory.h @@ -0,0 +1,317 @@ +// nbtheory.h - originally written and placed in the public domain by Wei Dai + +/// \file nbtheory.h +/// \brief Classes and functions for number theoretic operations + +#ifndef CRYPTOPP_NBTHEORY_H +#define CRYPTOPP_NBTHEORY_H + +#include "cryptlib.h" +#include "integer.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The Small Prime table +/// \details GetPrimeTable obtains pointer to small prime table and provides the size of the table. +CRYPTOPP_DLL const word16 * CRYPTOPP_API GetPrimeTable(unsigned int &size); + +// ************ primality testing **************** + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \return Integer() meeting Maurer's tests for primality +CRYPTOPP_DLL Integer CRYPTOPP_API MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \return Integer() meeting Mihailescu's tests for primality +/// \details Mihailescu's methods performs a search using algorithmic progressions. +CRYPTOPP_DLL Integer CRYPTOPP_API MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Tests whether a number is a small prime +/// \param p a candidate prime to test +/// \return true if p is a small prime, false otherwise +/// \details Internally, the library maintains a table of the first 32719 prime numbers +/// in sorted order. IsSmallPrime searches the table and returns true if p is +/// in the table. +CRYPTOPP_DLL bool CRYPTOPP_API IsSmallPrime(const Integer &p); + +/// \brief Tests whether a number is divisible by a small prime +/// \return true if p is divisible by some prime less than bound. +/// \details TrialDivision() returns true if p is divisible by some prime less +/// than bound. bound should not be greater than the largest entry in the +/// prime table, which is 32719. +CRYPTOPP_DLL bool CRYPTOPP_API TrialDivision(const Integer &p, unsigned bound); + +/// \brief Tests whether a number is divisible by a small prime +/// \return true if p is NOT divisible by small primes. +/// \details SmallDivisorsTest() returns true if p is NOT divisible by some +/// prime less than 32719. +CRYPTOPP_DLL bool CRYPTOPP_API SmallDivisorsTest(const Integer &p); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \return true if the number n is probably prime, false otherwise. +/// \details IsFermatProbablePrime raises b to the n-1 power and checks if +/// the result is congruent to 1 modulo n. +/// \details These is no reason to use IsFermatProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsFermatProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \return true if the number n is probably prime, false otherwise. +/// \details These is no reason to use IsLucasProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \return true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \return true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param n the number to test +/// \param rounds the number of tests to perform +/// \details This is the Rabin-Miller primality test, i.e. repeating the strong probable prime +/// test for several rounds with random bases +/// \sa Trial divisions before +/// Miller-Rabin checks? on Crypto Stack Exchange +CRYPTOPP_DLL bool CRYPTOPP_API RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds); + +/// \brief Verifies a number is probably prime +/// \param p a candidate prime to test +/// \return true if p is a probable prime, false otherwise +/// \details IsPrime() is suitable for testing candidate primes when creating them. Internally, +/// IsPrime() utilizes SmallDivisorsTest(), IsStrongProbablePrime() and IsStrongLucasProbablePrime(). +CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p); + +/// \brief Verifies a number is probably prime +/// \param rng a RandomNumberGenerator for randomized testing +/// \param p a candidate prime to test +/// \param level the level of thoroughness of testing +/// \return true if p is a strong probable prime, false otherwise +/// \details VerifyPrime() is suitable for testing candidate primes created by others. Internally, +/// VerifyPrime() utilizes IsPrime() and one-round RabinMillerTest(). If the candiate passes and +/// level is greater than 1, then 10 round RabinMillerTest() primality testing is performed. +CRYPTOPP_DLL bool CRYPTOPP_API VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1); + +/// \brief Application callback to signal suitability of a cabdidate prime +class CRYPTOPP_DLL PrimeSelector +{ +public: + virtual ~PrimeSelector() {} + const PrimeSelector *GetSelectorPointer() const {return this;} + virtual bool IsAcceptable(const Integer &candidate) const =0; +}; + +/// \brief Finds a random prime of special form +/// \param p an Integer reference to receive the prime +/// \param max the maximum value +/// \param equiv the equivalence class based on the parameter mod +/// \param mod the modulus used to reduce the equivalence class +/// \param pSelector pointer to a PrimeSelector function for the application to signal suitability +/// \return true if and only if FirstPrime() finds a prime and returns the prime through p. If FirstPrime() +/// returns false, then no such prime exists and the value of p is undefined +/// \details FirstPrime() uses a fast sieve to find the first probable prime +/// in {x | p<=x<=max and x%mod==equiv} +CRYPTOPP_DLL bool CRYPTOPP_API FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector); + +CRYPTOPP_DLL unsigned int CRYPTOPP_API PrimeSearchInterval(const Integer &max); + +CRYPTOPP_DLL AlgorithmParameters CRYPTOPP_API MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength); + +// ********** other number theoretic functions ************ + +/// \brief Calculate the greatest common divisor +/// \param a the first term +/// \param b the second term +/// \return the greatest common divisor if one exists, 0 otherwise. +inline Integer GCD(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b);} + +/// \brief Determine relative primality +/// \param a the first term +/// \param b the second term +/// \return true if a and b are relatively prime, false otherwise. +inline bool RelativelyPrime(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b) == Integer::One();} + +/// \brief Calculate the least common multiple +/// \param a the first term +/// \param b the second term +/// \return the least common multiple of a and b. +inline Integer LCM(const Integer &a, const Integer &b) + {return a/Integer::Gcd(a,b)*b;} + +/// \brief Calculate multiplicative inverse +/// \param a the number to test +/// \param b the modulus +/// \return an Integer (a ^ -1) % n or 0 if none exists. +/// \details EuclideanMultiplicativeInverse returns the multiplicative inverse of the Integer +/// *a modulo the Integer b. If no Integer exists then Integer 0 is returned. +inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) + {return a.InverseMod(b);} + + +/// \brief Chinese Remainder Theorem +/// \param xp the first number, mod p +/// \param p the first prime modulus +/// \param xq the second number, mod q +/// \param q the second prime modulus +/// \param u inverse of p mod q +/// \return the CRT value of the parameters +/// \details CRT uses the Chinese Remainder Theorem to calculate x given +/// x mod p and x mod q, and u the inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u); + +/// \brief Calculate the Jacobi symbol +/// \param a the first term +/// \param b the second term +/// \return the the Jacobi symbol. +/// \details Jacobi symbols are calculated using the following rules: +/// -# if b is prime, then Jacobi(a, b), then return 0 +/// -# if a%b==0 AND a is quadratic residue mod b, then return 1 +/// -# return -1 otherwise +/// \details Refer to a number theory book for what Jacobi symbol means when b is not prime. +CRYPTOPP_DLL int CRYPTOPP_API Jacobi(const Integer &a, const Integer &b); + +/// \brief Calculate the Lucas value +/// \return the Lucas value +/// \details Lucas() calculates the Lucas function V_e(p, 1) mod n. +CRYPTOPP_DLL Integer CRYPTOPP_API Lucas(const Integer &e, const Integer &p, const Integer &n); + +/// \brief Calculate the inverse Lucas value +/// \return the inverse Lucas value +/// \details InverseLucas() calculates x such that m==Lucas(e, x, p*q), +/// p q primes, u is inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Modular multiplication +/// \param x the first term +/// \param y the second term +/// \param m the modulus +/// \return an Integer (x * y) % m. +inline Integer ModularMultiplication(const Integer &x, const Integer &y, const Integer &m) + {return a_times_b_mod_c(x, y, m);} + +/// \brief Modular exponentiation +/// \param x the base +/// \param e the exponent +/// \param m the modulus +/// \return an Integer (a ^ b) % m. +inline Integer ModularExponentiation(const Integer &x, const Integer &e, const Integer &m) + {return a_exp_b_mod_c(x, e, m);} + +/// \brief Extract a modular square root +/// \param a the number to extract square root +/// \param p the prime modulus +/// \return the modular square root if it exists +/// \details ModularSquareRoot returns x such that x*x%p == a, p prime +CRYPTOPP_DLL Integer CRYPTOPP_API ModularSquareRoot(const Integer &a, const Integer &p); + +/// \brief Extract a modular root +/// \return a modular root if it exists +/// \details ModularRoot returns x such that a==ModularExponentiation(x, e, p*q), +/// p q primes, and e relatively prime to (p-1)*(q-1), +/// dp=d%(p-1), dq=d%(q-1), (d is inverse of e mod (p-1)*(q-1)) +/// and u=inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Solve a Modular Quadratic Equation +/// \param r1 the first residue +/// \param r2 the second residue +/// \param a the first coefficient +/// \param b the second coefficient +/// \param c the third constant +/// \param p the prime modulus +/// \return true if solutions exist +/// \details SolveModularQuadraticEquation() finds r1 and r2 such that ax^2 + +/// bx + c == 0 (mod p) for x in {r1, r2}, p prime. +CRYPTOPP_DLL bool CRYPTOPP_API SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \return the estimated work factor, in operations +/// \details DiscreteLogWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API DiscreteLogWorkFactor(unsigned int bitlength); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \return the estimated work factor, in operations +/// \details FactoringWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API FactoringWorkFactor(unsigned int bitlength); + +// ******************************************************** + +/// \brief Generator of prime numbers of special forms +class CRYPTOPP_DLL PrimeAndGenerator +{ +public: + /// \brief Construct a PrimeAndGenerator + PrimeAndGenerator() {} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \details PrimeAndGenerator() generates a random prime p of the form 2*q+delta, where delta is 1 or -1 and q is + /// also prime. Internally the constructor calls Generate(delta, rng, pbits, pbits-1). + /// \pre pbits > 5 + /// \warning This PrimeAndGenerator() is slow because primes of this form are harder to find. + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits) + {Generate(delta, rng, pbits, pbits-1);} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details PrimeAndGenerator() generates a random prime p of the form 2*r*q+delta, where q is also prime. + /// Internally the constructor calls Generate(delta, rng, pbits, qbits). + /// \pre qbits > 4 && pbits > qbits + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits) + {Generate(delta, rng, pbits, qbits);} + + /// \brief Generate a Prime and Generator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details Generate() generates a random prime p of the form 2*r*q+delta, where q is also prime. + void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits); + + /// \brief Retrieve first prime + /// \return Prime() returns the prime p. + const Integer& Prime() const {return p;} + + /// \brief Retrieve second prime + /// \return SubPrime() returns the prime q. + const Integer& SubPrime() const {return q;} + + /// \brief Retrieve the generator + /// \return Generator() returns the the generator g. + const Integer& Generator() const {return g;} + +private: + Integer p, q, g; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/neon_simd.cpp b/extension/third_party/cryptopp/neon_simd.cpp new file mode 100644 index 00000000..602ba0e9 --- /dev/null +++ b/extension/third_party/cryptopp/neon_simd.cpp @@ -0,0 +1,197 @@ + +// crc_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to ARMv7a and +// ARMv8a NEON instructions. A separate source file is needed +// because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. +// For Linux and Unix additional flags are not required. + +#include "pch.h" +#include "config.h" +#include "stdcpp.h" + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char NEON_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +bool CPU_ProbeARMv7() +{ +#if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) + return false; +#elif defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif CRYPTOPP_ARM_NEON_AVAILABLE +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + // Modern MS hardware is ARMv7 + result = true; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + +#if 0 + // ARMv7 added movt and movw + int a; + asm volatile("movw %0,%1 \n" + "movt %0,%1 \n" + : "=r"(a) : "i"(0x1234)); + +00000010 <_Z5test2v>: // ARM + 10: e3010234 movw r0, #4660 ; 0x1234 + 14: e3410234 movt r0, #4660 ; 0x1234 + 18: e12fff1e bx lr + +0000001c <_Z5test3v>: // Thumb + 1c: f241 2034 movw r0, #4660 ; 0x1234 + 20: f2c1 2034 movt r0, #4660 ; 0x1234 + 24: e12fff1e bx lr +#endif + + unsigned int a; + asm volatile ( +#if defined(__thumb__) + ".inst.n 0xf241, 0x2034 \n\t" // movw r0, 0x1234 + ".inst.n 0xf2c1, 0x2034 \n\t" // movt r0, 0x1234 + "mov %0, r0 \n\t" // mov [a], r0 +#else + ".inst 0xe3010234 \n\t" // movw r0, 0x1234 + ".inst 0xe3410234 \n\t" // movt r0, 0x1234 + "mov %0, r0 \n\t" // mov [a], r0 +#endif + : "=r" (a) : : "r0"); + + result = (a == 0x12341234); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_NEON_AVAILABLE +} + +bool CPU_ProbeNEON() +{ +#if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) + return true; +#elif defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif CRYPTOPP_ARM_NEON_AVAILABLE +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + uint32x4_t x = vdupq_n_u32(1); + uint32x4_t y = vshlq_n_u32(x, 4); + + word32 z[4]; vst1q_u32(z, y); + return (z[0] & z[1] & z[2] & z[3]) == 16; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // This is risky... When we hand encode the instructions + // for vmov.u32 and vshl.u32 we get a SIGILL. Apparently + // we need more than just the instructions. Using + // intrinsics introduces the risk because the whole + // file gets built with ISA options, and the higher ISA + // may escape the try block with the SIGILL guard. + uint32x4_t x = vdupq_n_u32(1); + uint32x4_t y = vshlq_n_u32(x, 4); + + word32 z[4]; vst1q_u32(z, y); + result = (z[0] & z[1] & z[2] & z[3]) == 16; + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_NEON_AVAILABLE +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/nr.h b/extension/third_party/cryptopp/nr.h new file mode 100644 index 00000000..101f9106 --- /dev/null +++ b/extension/third_party/cryptopp/nr.h @@ -0,0 +1,11 @@ +// nr.h - originally written and placed in the public domain by Wei Dai + +/// \file nr.h +/// \brief Classes for Nyberg-Rueppel signature scheme + +#ifndef CRYPTOPP_NR_H +#define CRYPTOPP_NR_H + +#include "gfpcrypt.h" + +#endif diff --git a/extension/third_party/cryptopp/oaep.cpp b/extension/third_party/cryptopp/oaep.cpp new file mode 100644 index 00000000..fb9e31a0 --- /dev/null +++ b/extension/third_party/cryptopp/oaep.cpp @@ -0,0 +1,98 @@ +// oaep.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "oaep.h" +#include "stdcpp.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +// ******************************************************** + +size_t OAEP_Base::MaxUnpaddedLength(size_t paddedLength) const +{ + return SaturatingSubtract(paddedLength/8, 1+2*DigestSize()); +} + +void OAEP_Base::Pad(RandomNumberGenerator &rng, const byte *input, size_t inputLength, byte *oaepBlock, size_t oaepBlockLen, const NameValuePairs ¶meters) const +{ + CRYPTOPP_ASSERT (inputLength <= MaxUnpaddedLength(oaepBlockLen)); + + // convert from bit length to byte length + if (oaepBlockLen % 8 != 0) + { + oaepBlock[0] = 0; + oaepBlock++; + } + oaepBlockLen /= 8; + + member_ptr pHash(NewHash()); + const size_t hLen = pHash->DigestSize(); + const size_t seedLen = hLen, dbLen = oaepBlockLen-seedLen; + byte *const maskedSeed = oaepBlock; + byte *const maskedDB = oaepBlock+seedLen; + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + // DB = pHash || 00 ... || 01 || M + pHash->CalculateDigest(maskedDB, encodingParameters.begin(), encodingParameters.size()); + memset(maskedDB+hLen, 0, dbLen-hLen-inputLength-1); + maskedDB[dbLen-inputLength-1] = 0x01; + memcpy(maskedDB+dbLen-inputLength, input, inputLength); + + rng.GenerateBlock(maskedSeed, seedLen); + member_ptr pMGF(NewMGF()); + pMGF->GenerateAndMask(*pHash, maskedDB, dbLen, maskedSeed, seedLen); + pMGF->GenerateAndMask(*pHash, maskedSeed, seedLen, maskedDB, dbLen); +} + +DecodingResult OAEP_Base::Unpad(const byte *oaepBlock, size_t oaepBlockLen, byte *output, const NameValuePairs ¶meters) const +{ + bool invalid = false; + + // convert from bit length to byte length + if (oaepBlockLen % 8 != 0) + { + invalid = (oaepBlock[0] != 0) || invalid; + oaepBlock++; + } + oaepBlockLen /= 8; + + member_ptr pHash(NewHash()); + const size_t hLen = pHash->DigestSize(); + const size_t seedLen = hLen, dbLen = oaepBlockLen-seedLen; + + invalid = (oaepBlockLen < 2*hLen+1) || invalid; + + SecByteBlock t(oaepBlock, oaepBlockLen); + byte *const maskedSeed = t; + byte *const maskedDB = t+seedLen; + + member_ptr pMGF(NewMGF()); + pMGF->GenerateAndMask(*pHash, maskedSeed, seedLen, maskedDB, dbLen); + pMGF->GenerateAndMask(*pHash, maskedDB, dbLen, maskedSeed, seedLen); + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + // DB = pHash' || 00 ... || 01 || M + byte *M = std::find(maskedDB+hLen, maskedDB+dbLen, 0x01); + invalid = (M == maskedDB+dbLen) || invalid; + invalid = (FindIfNot(maskedDB+hLen, M, byte(0)) != M) || invalid; + invalid = !pHash->VerifyDigest(maskedDB, encodingParameters.begin(), encodingParameters.size()) || invalid; + + if (invalid) + return DecodingResult(); + + M++; + memcpy(output, M, maskedDB+dbLen-M); + return DecodingResult(maskedDB+dbLen-M); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/oaep.h b/extension/third_party/cryptopp/oaep.h new file mode 100644 index 00000000..76be7f24 --- /dev/null +++ b/extension/third_party/cryptopp/oaep.h @@ -0,0 +1,54 @@ +// oaep.h - originally written and placed in the public domain by Wei Dai + +/// \file oaep.h +/// \brief Classes for optimal asymmetric encryption padding +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_OAEP_H +#define CRYPTOPP_OAEP_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief OAEP padding base class +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL OAEP_Base : public PK_EncryptionMessageEncodingMethod +{ +public: + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; + +protected: + virtual unsigned int DigestSize() const =0; + virtual HashTransformation * NewHash() const =0; + virtual MaskGeneratingFunction * NewMGF() const =0; +}; + +/// \brief OAEP padding +/// \tparam H HashTransformation derived class +/// \tparam MGF MaskGeneratingFunction derived class +/// \sa EME-OAEP, for use with classes derived from TF_ES +/// \since Crypto++ 2.1 +template +class OAEP : public OAEP_Base, public EncryptionStandard +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("OAEP-") + MGF::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + typedef OAEP EncryptionMessageEncodingMethod; + +protected: + unsigned int DigestSize() const {return H::DIGESTSIZE;} + HashTransformation * NewHash() const {return new H;} + MaskGeneratingFunction * NewMGF() const {return new MGF;} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS OAEP; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/oids.h b/extension/third_party/cryptopp/oids.h new file mode 100644 index 00000000..030483aa --- /dev/null +++ b/extension/third_party/cryptopp/oids.h @@ -0,0 +1,194 @@ +// oids.h - originally written and placed in the public domain by Wei Dai + +/// \file oids.h +/// \brief ASN.1 object identifiers for algorthms and schemes +/// \details Most OIDs can be found at http://www.oid-info.com/. The Chinese OIDs +/// are assigned in GM/T 0006-2012, Cryptographic Application Identifier Criterion +/// Specification. A reproduction can be found at http://gmssl.org/docs/oid.html. +/// There seems to be some confusion between the text of GmSSL's oid.html web page +/// and the actual OID used in the code. We used the same OIDs that were detailed in +/// http://github.com/guanzhi/GmSSL/blob/master/crypto/objects/objects.txt. + +#ifndef CRYPTOPP_OIDS_H +#define CRYPTOPP_OIDS_H + +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +NAMESPACE_BEGIN(ASN1) + +#define DEFINE_OID(value, name) inline OID name() {return value;} + +DEFINE_OID(1, iso) + DEFINE_OID(iso()+2, member_body) + DEFINE_OID(member_body()+156, iso_cn) + DEFINE_OID(iso_cn()+10197, oscca) + DEFINE_OID(oscca()+1, sm_scheme) + DEFINE_OID(sm_scheme()+104, sms4) + DEFINE_OID(sm_scheme()+301, sm2p256v1) + DEFINE_OID(sm2p256v1()+1, sm2sign) + DEFINE_OID(sm2p256v1()+2, sm2exchange) + DEFINE_OID(sm2p256v1()+3, sm2encrypt) + DEFINE_OID(sm2encrypt()+1, sm2encrypt_recommendedParameters) + DEFINE_OID(sm2encrypt()+2, sm2encrypt_specifiedParameters) + DEFINE_OID(member_body()+840, iso_us) + DEFINE_OID(iso_us()+10040, ansi_x9_57) + DEFINE_OID(ansi_x9_57()+4, ansi_x9cm) + DEFINE_OID(ansi_x9cm()+1, id_dsa) + DEFINE_OID(iso_us()+10045, ansi_x9_62) + DEFINE_OID(ansi_x9_62()+1, id_fieldType) + DEFINE_OID(id_fieldType()+1, prime_field) + DEFINE_OID(id_fieldType()+2, characteristic_two_field) + DEFINE_OID(characteristic_two_field()+3, id_characteristic_two_basis) + DEFINE_OID(id_characteristic_two_basis()+1, gnBasis) + DEFINE_OID(id_characteristic_two_basis()+2, tpBasis) + DEFINE_OID(id_characteristic_two_basis()+3, ppBasis) + DEFINE_OID(ansi_x9_62()+2, id_publicKeyType) + DEFINE_OID(id_publicKeyType()+1, id_ecPublicKey) + DEFINE_OID(ansi_x9_62()+3, ansi_x9_62_curves) + DEFINE_OID(ansi_x9_62_curves()+1, ansi_x9_62_curves_prime) + // ANSI X9.62 + DEFINE_OID(ansi_x9_62_curves_prime()+1, secp192r1) // secp192v1 + //DEFINE_OID(ansi_x9_62_curves_prime()+2, secp192v2) + //DEFINE_OID(ansi_x9_62_curves_prime()+3, secp192v3) + //DEFINE_OID(ansi_x9_62_curves_prime()+4, secp239v1) + //DEFINE_OID(ansi_x9_62_curves_prime()+5, secp239v2) + //DEFINE_OID(ansi_x9_62_curves_prime()+6, secp239v3) + DEFINE_OID(ansi_x9_62_curves_prime()+7, secp256r1) // secp256v1 + DEFINE_OID(ansi_x9_62()+4, ansi_signatures) + DEFINE_OID(ansi_signatures()+3, ecdsa_with_sha2) + DEFINE_OID(ecdsa_with_sha2()+1, ecdsa_with_sha224) + DEFINE_OID(ecdsa_with_sha2()+2, ecdsa_with_sha256) + DEFINE_OID(ecdsa_with_sha2()+3, ecdsa_with_sha384) + DEFINE_OID(ecdsa_with_sha2()+4, ecdsa_with_sha512) + DEFINE_OID(iso_us()+113549, rsadsi) + DEFINE_OID(rsadsi()+1, pkcs) + DEFINE_OID(pkcs()+1, pkcs_1) + // Arc from PKCS #1 and RFC 2459 + DEFINE_OID(pkcs_1()+1, rsaEncryption) + DEFINE_OID(pkcs_1()+2, md2WithRSAEncryption) + DEFINE_OID(pkcs_1()+3, md4withRSAEncryption) + DEFINE_OID(pkcs_1()+4, md5WithRSAEncryption) + DEFINE_OID(pkcs_1()+5, sha1WithRSAEncryption) + DEFINE_OID(pkcs_1()+10, rsassa_pss) + DEFINE_OID(pkcs_1()+11, sha256WithRSAEncryption) + DEFINE_OID(pkcs_1()+12, sha384WithRSAEncryption) + DEFINE_OID(pkcs_1()+13, sha512WithRSAEncryption) + DEFINE_OID(pkcs_1()+14, sha224WithRSAEncryption) + DEFINE_OID(pkcs_1()+15, sha512_224WithRSAEncryption) + DEFINE_OID(pkcs_1()+16, sha512_256WithRSAEncryption) + DEFINE_OID(rsadsi()+2, rsadsi_digestAlgorithm) + DEFINE_OID(rsadsi_digestAlgorithm()+2, id_md2) + DEFINE_OID(rsadsi_digestAlgorithm()+5, id_md5) + DEFINE_OID(iso()+3, identified_organization) + // Arc from http://tools.ietf.org/html/draft-josefsson-pkix-newcurves + DEFINE_OID(identified_organization()+6, dod) + DEFINE_OID(dod()+1, internet) + DEFINE_OID(internet()+4, internet_private) + DEFINE_OID(internet_private()+1, enterprise) + DEFINE_OID(enterprise()+11591,gnu) + DEFINE_OID(gnu()+15,ellipticCurve) + DEFINE_OID(ellipticCurve()+1,curve25519) + DEFINE_OID(ellipticCurve()+2,curve448) + DEFINE_OID(ellipticCurve()+3,curve25519ph) + DEFINE_OID(ellipticCurve()+4,curve448ph) + DEFINE_OID(identified_organization()+14, oiw) + DEFINE_OID(oiw()+3, oiw_secsig) + DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms) + DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1) + DEFINE_OID(oiw()+7, dssig) + DEFINE_OID(dssig()+2, algorithm) + DEFINE_OID(algorithm()+1, encryptionAlgorithm) + DEFINE_OID(encryptionAlgorithm()+1, elGamal) + DEFINE_OID(identified_organization()+36, teletrust) + DEFINE_OID(teletrust()+3, teletrust_algorithm) + DEFINE_OID(teletrust_algorithm()+2+1, id_ripemd160) + DEFINE_OID(teletrust_algorithm()+3+2+8+1, teletrust_ellipticCurve) + DEFINE_OID(teletrust_ellipticCurve()+1+1, brainpoolP160r1) + DEFINE_OID(teletrust_ellipticCurve()+1+3, brainpoolP192r1) + DEFINE_OID(teletrust_ellipticCurve()+1+5, brainpoolP224r1) + DEFINE_OID(teletrust_ellipticCurve()+1+7, brainpoolP256r1) + DEFINE_OID(teletrust_ellipticCurve()+1+9, brainpoolP320r1) + DEFINE_OID(teletrust_ellipticCurve()+1+11, brainpoolP384r1) + DEFINE_OID(teletrust_ellipticCurve()+1+13, brainpoolP512r1) + // https://tools.ietf.org/html/draft-ietf-curdle-pkix-07 + DEFINE_OID(identified_organization()+101, thawte) + DEFINE_OID(thawte()+110, X25519) + DEFINE_OID(thawte()+111, X448) + DEFINE_OID(thawte()+112, Ed25519) + DEFINE_OID(thawte()+113, Ed448) + DEFINE_OID(identified_organization()+132, certicom) + DEFINE_OID(certicom()+0, certicom_ellipticCurve) + // these are sorted by curve type and then by OID + // first curves based on GF(p) + DEFINE_OID(certicom_ellipticCurve()+6, secp112r1) + DEFINE_OID(certicom_ellipticCurve()+7, secp112r2) + DEFINE_OID(certicom_ellipticCurve()+8, secp160r1) + DEFINE_OID(certicom_ellipticCurve()+9, secp160k1) + DEFINE_OID(certicom_ellipticCurve()+10, secp256k1) + DEFINE_OID(certicom_ellipticCurve()+28, secp128r1) + DEFINE_OID(certicom_ellipticCurve()+29, secp128r2) + DEFINE_OID(certicom_ellipticCurve()+30, secp160r2) + DEFINE_OID(certicom_ellipticCurve()+31, secp192k1) + DEFINE_OID(certicom_ellipticCurve()+32, secp224k1) + DEFINE_OID(certicom_ellipticCurve()+33, secp224r1) + DEFINE_OID(certicom_ellipticCurve()+34, secp384r1) + DEFINE_OID(certicom_ellipticCurve()+35, secp521r1) + // then curves based on GF(2^n) + DEFINE_OID(certicom_ellipticCurve()+1, sect163k1) + DEFINE_OID(certicom_ellipticCurve()+2, sect163r1) + DEFINE_OID(certicom_ellipticCurve()+3, sect239k1) + DEFINE_OID(certicom_ellipticCurve()+4, sect113r1) + DEFINE_OID(certicom_ellipticCurve()+5, sect113r2) + DEFINE_OID(certicom_ellipticCurve()+15, sect163r2) + DEFINE_OID(certicom_ellipticCurve()+16, sect283k1) + DEFINE_OID(certicom_ellipticCurve()+17, sect283r1) + DEFINE_OID(certicom_ellipticCurve()+22, sect131r1) + DEFINE_OID(certicom_ellipticCurve()+23, sect131r2) + DEFINE_OID(certicom_ellipticCurve()+24, sect193r1) + DEFINE_OID(certicom_ellipticCurve()+25, sect193r2) + DEFINE_OID(certicom_ellipticCurve()+26, sect233k1) + DEFINE_OID(certicom_ellipticCurve()+27, sect233r1) + DEFINE_OID(certicom_ellipticCurve()+36, sect409k1) + DEFINE_OID(certicom_ellipticCurve()+37, sect409r1) + DEFINE_OID(certicom_ellipticCurve()+38, sect571k1) + DEFINE_OID(certicom_ellipticCurve()+39, sect571r1) +DEFINE_OID(2, joint_iso_ccitt) + DEFINE_OID(joint_iso_ccitt()+16, country) + DEFINE_OID(country()+840, joint_iso_ccitt_us) + DEFINE_OID(joint_iso_ccitt_us()+1, us_organization) + DEFINE_OID(us_organization()+101, us_gov) + DEFINE_OID(us_gov()+3, csor) + DEFINE_OID(csor()+4, nistalgorithms) + DEFINE_OID(nistalgorithms()+1, aes) + DEFINE_OID(aes()+1, id_aes128_ECB) + DEFINE_OID(aes()+2, id_aes128_cbc) + DEFINE_OID(aes()+3, id_aes128_ofb) + DEFINE_OID(aes()+4, id_aes128_cfb) + DEFINE_OID(aes()+21, id_aes192_ECB) + DEFINE_OID(aes()+22, id_aes192_cbc) + DEFINE_OID(aes()+23, id_aes192_ofb) + DEFINE_OID(aes()+24, id_aes192_cfb) + DEFINE_OID(aes()+41, id_aes256_ECB) + DEFINE_OID(aes()+42, id_aes256_cbc) + DEFINE_OID(aes()+43, id_aes256_ofb) + DEFINE_OID(aes()+44, id_aes256_cfb) + DEFINE_OID(nistalgorithms()+2, nist_hashalgs) + DEFINE_OID(nist_hashalgs()+1, id_sha256) + DEFINE_OID(nist_hashalgs()+2, id_sha384) + DEFINE_OID(nist_hashalgs()+3, id_sha512) + DEFINE_OID(nist_hashalgs()+4, id_sha224) + DEFINE_OID(nist_hashalgs()+7, id_sha3_224) + DEFINE_OID(nist_hashalgs()+8, id_sha3_256) + DEFINE_OID(nist_hashalgs()+9, id_sha3_384) + DEFINE_OID(nist_hashalgs()+10, id_sha3_512) + DEFINE_OID(joint_iso_ccitt_us()+10046, ansi_x942) + DEFINE_OID(ansi_x942()+2, number_type) + DEFINE_OID(number_type()+1, dhpublicnumber) + +NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/osrng.cpp b/extension/third_party/cryptopp/osrng.cpp new file mode 100644 index 00000000..5121ac1e --- /dev/null +++ b/extension/third_party/cryptopp/osrng.cpp @@ -0,0 +1,300 @@ +// osrng.cpp - originally written and placed in the public domain by Wei Dai + +// Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool. + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +// Win32 has CryptoAPI and . Windows 10 and Windows Store 10 have CNG and . +// There's a hole for Windows Phone 8 and Windows Store 8. There is no userland RNG available. +// Also see http://www.drdobbs.com/windows/using-c-and-com-with-winrt/240168150 and +// http://stackoverflow.com/questions/36974545/random-numbers-for-windows-phone-8-and-windows-store-8 and +// https://social.msdn.microsoft.com/Forums/vstudio/en-US/25b83e13-c85f-4aa1-a057-88a279ea3fd6/what-crypto-random-generator-c-code-could-use-on-wp81 +#if defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(OS_RNG_AVAILABLE) +# pragma message("WARNING: Compiling for Windows but an OS RNG is not available. This is likely a Windows Phone 8 or Windows Store 8 app.") +#endif + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + +#include "osrng.h" +#include "rng.h" + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#define WIN32_LEAN_AND_MEAN +#include +#ifndef ERROR_INCORRECT_SIZE +# define ERROR_INCORRECT_SIZE 0x000005B6 +#endif +#if defined(USE_MS_CRYPTOAPI) +#include +#ifndef CRYPT_NEWKEYSET +# define CRYPT_NEWKEYSET 0x00000008 +#endif +#ifndef CRYPT_MACHINE_KEYSET +# define CRYPT_MACHINE_KEYSET 0x00000020 +#endif +#elif defined(USE_MS_CNGAPI) +#include +#ifndef BCRYPT_SUCCESS +# define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif +#ifndef STATUS_INVALID_PARAMETER +# define STATUS_INVALID_PARAMETER 0xC000000D +#endif +#ifndef STATUS_INVALID_HANDLE +# define STATUS_INVALID_HANDLE 0xC0000008 +#endif +#endif +#endif // Win32 + +#ifdef CRYPTOPP_UNIX_AVAILABLE +#include +#include +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE) +OS_RNG_Err::OS_RNG_Err(const std::string &operation) + : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " + +#ifdef CRYPTOPP_WIN32_AVAILABLE + "0x" + IntToString(GetLastError(), 16) +#else + IntToString(errno) +#endif + ) +{ +} +#endif + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE + +#if defined(USE_MS_CNGAPI) +inline DWORD NtStatusToErrorCode(NTSTATUS status) +{ + if (status == STATUS_INVALID_PARAMETER) + return ERROR_INVALID_PARAMETER; + else if (status == STATUS_INVALID_HANDLE) + return ERROR_INVALID_HANDLE; + else + return (DWORD)status; +} +#endif + +#if defined(UNICODE) || defined(_UNICODE) +# define CRYPTOPP_CONTAINER L"Crypto++ RNG" +#else +# define CRYPTOPP_CONTAINER "Crypto++ RNG" +#endif + +MicrosoftCryptoProvider::MicrosoftCryptoProvider() : m_hProvider(0) +{ +#if defined(USE_MS_CRYPTOAPI) + // See http://support.microsoft.com/en-us/kb/238187 for CRYPT_NEWKEYSET fallback strategy + if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + const DWORD firstErr = GetLastError(); + if (!CryptAcquireContext(&m_hProvider, CRYPTOPP_CONTAINER, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET /*user*/) && + !CryptAcquireContext(&m_hProvider, CRYPTOPP_CONTAINER, 0, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET)) + { + // Set original error with original code + SetLastError(firstErr); + throw OS_RNG_Err("CryptAcquireContext"); + } + } +#elif defined(USE_MS_CNGAPI) + NTSTATUS ret = BCryptOpenAlgorithmProvider(&m_hProvider, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); + if (!(BCRYPT_SUCCESS(ret))) + { + // Hack... OS_RNG_Err calls GetLastError() + SetLastError(NtStatusToErrorCode(ret)); + throw OS_RNG_Err("BCryptOpenAlgorithmProvider"); + } +#endif +} + +MicrosoftCryptoProvider::~MicrosoftCryptoProvider() +{ +#if defined(USE_MS_CRYPTOAPI) + if (m_hProvider) + CryptReleaseContext(m_hProvider, 0); +#elif defined(USE_MS_CNGAPI) + if (m_hProvider) + BCryptCloseAlgorithmProvider(m_hProvider, 0); +#endif +} + +#endif // CRYPTOPP_WIN32_AVAILABLE + +NonblockingRng::NonblockingRng() +{ +#ifndef CRYPTOPP_WIN32_AVAILABLE + m_fd = open("/dev/urandom",O_RDONLY); + if (m_fd == -1) + throw OS_RNG_Err("open /dev/urandom"); + + // Do some OSes return -NNN instead of -1? + CRYPTOPP_ASSERT(m_fd >= 0); +#endif +} + +NonblockingRng::~NonblockingRng() +{ +#ifndef CRYPTOPP_WIN32_AVAILABLE + close(m_fd); +#endif +} + +void NonblockingRng::GenerateBlock(byte *output, size_t size) +{ +#ifdef CRYPTOPP_WIN32_AVAILABLE + // Acquiring a provider is expensive. Do it once and retain the reference. +# if defined(CRYPTOPP_CXX11_STATIC_INIT) + static const MicrosoftCryptoProvider hProvider = MicrosoftCryptoProvider(); +# else + const MicrosoftCryptoProvider &hProvider = Singleton().Ref(); +# endif +# if defined(USE_MS_CRYPTOAPI) + DWORD dwSize; + CRYPTOPP_ASSERT(SafeConvert(size, dwSize)); + if (!SafeConvert(size, dwSize)) + { + SetLastError(ERROR_INCORRECT_SIZE); + throw OS_RNG_Err("GenerateBlock size"); + } + BOOL ret = CryptGenRandom(hProvider.GetProviderHandle(), dwSize, output); + CRYPTOPP_ASSERT(ret != FALSE); + if (ret == FALSE) + throw OS_RNG_Err("CryptGenRandom"); +# elif defined(USE_MS_CNGAPI) + ULONG ulSize; + CRYPTOPP_ASSERT(SafeConvert(size, ulSize)); + if (!SafeConvert(size, ulSize)) + { + SetLastError(ERROR_INCORRECT_SIZE); + throw OS_RNG_Err("GenerateBlock size"); + } + NTSTATUS ret = BCryptGenRandom(hProvider.GetProviderHandle(), output, ulSize, 0); + CRYPTOPP_ASSERT(BCRYPT_SUCCESS(ret)); + if (!(BCRYPT_SUCCESS(ret))) + { + // Hack... OS_RNG_Err calls GetLastError() + SetLastError(NtStatusToErrorCode(ret)); + throw OS_RNG_Err("BCryptGenRandom"); + } +# endif +#else + while (size) + { + ssize_t len = read(m_fd, output, size); + if (len < 0) + { + // /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well) + if (errno != EINTR && errno != EAGAIN) + throw OS_RNG_Err("read /dev/urandom"); + + continue; + } + + output += len; + size -= len; + } +#endif // CRYPTOPP_WIN32_AVAILABLE +} + +#endif // NONBLOCKING_RNG_AVAILABLE + +// ************************************************************* + +#ifdef BLOCKING_RNG_AVAILABLE + +#ifndef CRYPTOPP_BLOCKING_RNG_FILENAME +#ifdef __OpenBSD__ +#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom" +#else +#define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random" +#endif +#endif + +BlockingRng::BlockingRng() +{ + m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY); + if (m_fd == -1) + throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME); + + // Do some OSes return -NNN instead of -1? + CRYPTOPP_ASSERT(m_fd >= 0); +} + +BlockingRng::~BlockingRng() +{ + close(m_fd); +} + +void BlockingRng::GenerateBlock(byte *output, size_t size) +{ + while (size) + { + // on some systems /dev/random will block until all bytes + // are available, on others it returns immediately + ssize_t len = read(m_fd, output, size); + if (len < 0) + { + // /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well) + if (errno != EINTR && errno != EAGAIN) + throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME); + + continue; + } + + size -= len; + output += len; + if (size) + sleep(1); + } +} + +#endif // BLOCKING_RNG_AVAILABLE + +// ************************************************************* + +void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size) +{ +#ifdef NONBLOCKING_RNG_AVAILABLE + if (blocking) +#endif + { +#ifdef BLOCKING_RNG_AVAILABLE + BlockingRng rng; + rng.GenerateBlock(output, size); +#endif + } + +#ifdef BLOCKING_RNG_AVAILABLE + if (!blocking) +#endif + { +#ifdef NONBLOCKING_RNG_AVAILABLE + NonblockingRng rng; + rng.GenerateBlock(output, size); +#endif + } +} + +void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize) +{ + SecByteBlock seed(seedSize); + OS_GenerateRandomBlock(blocking, seed, seedSize); + IncorporateEntropy(seed, seedSize); +} + +NAMESPACE_END + +#endif // OS_RNG_AVAILABLE + +#endif // CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/osrng.h b/extension/third_party/cryptopp/osrng.h new file mode 100644 index 00000000..69bccf20 --- /dev/null +++ b/extension/third_party/cryptopp/osrng.h @@ -0,0 +1,304 @@ +// osrng.h - originally written and placed in the public domain by Wei Dai + +/// \file osrng.h +/// \brief Classes for access to the operating system's random number generators + +#ifndef CRYPTOPP_OSRNG_H +#define CRYPTOPP_OSRNG_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + +#include "cryptlib.h" +#include "randpool.h" +#include "smartptr.h" +#include "fips140.h" +#include "hkdf.h" +#include "rng.h" +#include "aes.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when an operating system error is encountered +class CRYPTOPP_DLL OS_RNG_Err : public Exception +{ +public: + /// \brief Constructs an OS_RNG_Err + /// \param operation the operation or API call when the error occurs + OS_RNG_Err(const std::string &operation); +}; + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE +/// \brief Wrapper for Microsoft crypto service provider +/// \sa \def USE_MS_CRYPTOAPI, \def USE_MS_CNGAPI +class CRYPTOPP_DLL MicrosoftCryptoProvider +{ +public: + /// \brief Construct a MicrosoftCryptoProvider + MicrosoftCryptoProvider(); + ~MicrosoftCryptoProvider(); + +// type HCRYPTPROV and BCRYPT_ALG_HANDLE, avoid #include +#if defined(USE_MS_CRYPTOAPI) +# if defined(__CYGWIN__) && defined(__x86_64__) + typedef unsigned long long ProviderHandle; +# elif defined(WIN64) || defined(_WIN64) + typedef unsigned __int64 ProviderHandle; +# else + typedef unsigned long ProviderHandle; +# endif +#elif defined(USE_MS_CNGAPI) + typedef void *PVOID; + typedef PVOID ProviderHandle; +#endif // USE_MS_CRYPTOAPI or USE_MS_CNGAPI + + /// \brief Retrieves the provider handle + /// \return CryptoAPI provider handle + /// \details If USE_MS_CRYPTOAPI is in effect, then CryptAcquireContext() + /// acquires then handle and CryptReleaseContext() releases the handle + /// upon destruction. If USE_MS_CNGAPI is in effect, then + /// BCryptOpenAlgorithmProvider() acquires then handle and + /// BCryptCloseAlgorithmProvider() releases the handle upon destruction. + ProviderHandle GetProviderHandle() const {return m_hProvider;} + +private: + ProviderHandle m_hProvider; +}; + +#if defined(_MSC_VER) && defined(USE_MS_CRYPTOAPI) +# pragma comment(lib, "advapi32.lib") +#endif + +#if defined(_MSC_VER) && defined(USE_MS_CNGAPI) +# pragma comment(lib, "bcrypt.lib") +#endif + +#endif // CRYPTOPP_WIN32_AVAILABLE + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates CryptoAPI's CryptGenRandom() or CryptoNG's BCryptGenRandom() +/// on Windows, or /dev/urandom on Unix and compatibles. +class CRYPTOPP_DLL NonblockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "NonblockingRng"; } + + ~NonblockingRng(); + + /// \brief Construct a NonblockingRng + NonblockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: +#ifdef CRYPTOPP_WIN32_AVAILABLE + MicrosoftCryptoProvider m_Provider; +#else + int m_fd; +#endif +}; + +#endif + +#if defined(BLOCKING_RNG_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates /dev/random on Linux, OS X and Unix; and /dev/srandom on the BSDs. +/// \note On Linux the /dev/random interface is effectively deprecated. According to the +/// Kernel Crypto developers, /dev/urandom or getrandom(2) should be used instead. Also +/// see [RFC PATCH v12 3/4] Linux Random +/// Number Generator on the kernel-crypto mailing list. +class CRYPTOPP_DLL BlockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "BlockingRng"; } + + ~BlockingRng(); + + /// \brief Construct a BlockingRng + BlockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: + int m_fd; +}; + +#endif + +/// OS_GenerateRandomBlock +/// \brief Generate random array of bytes +/// \param blocking specifies whther a bobcking or non-blocking generator should be used +/// \param output the byte buffer +/// \param size the length of the buffer, in bytes +/// \details OS_GenerateRandomBlock() uses the underlying operating system's +/// random number generator. On Windows, CryptGenRandom() is called using NonblockingRng. +/// \details On Unix and compatibles, /dev/urandom is called if blocking is false using +/// NonblockingRng. If blocking is true, then either /dev/randomd or /dev/srandom is used +/// by way of BlockingRng, if available. +CRYPTOPP_DLL void CRYPTOPP_API OS_GenerateRandomBlock(bool blocking, byte *output, size_t size); + +/// \brief Automatically Seeded Randomness Pool +/// \details This class seeds itself using an operating system provided RNG. +/// AutoSeededRandomPool was suggested by Leonard Janke. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class CRYPTOPP_DLL AutoSeededRandomPool : public RandomPool +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "AutoSeededRandomPool"; } + + ~AutoSeededRandomPool() {} + + /// \brief Construct an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + explicit AutoSeededRandomPool(bool blocking = false, unsigned int seedSize = 32) + {Reseed(blocking, seedSize);} + + /// \brief Reseed an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + void Reseed(bool blocking = false, unsigned int seedSize = 32); +}; + +/// \tparam BLOCK_CIPHER a block cipher +/// \brief Automatically Seeded X9.17 RNG +/// \details AutoSeededX917RNG is from ANSI X9.17 Appendix C, seeded using an OS provided RNG. +/// If 3-key TripleDES (DES_EDE3) is used, then its a X9.17 conforming generator. If AES is +/// used, then its a X9.31 conforming generator. +/// \details Though ANSI X9 prescribes 3-key TripleDES, the template parameter BLOCK_CIPHER +/// can be any BlockTransformation derived class. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa X917RNG, DefaultAutoSeededRNG +template +class AutoSeededX917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + static std::string StaticAlgorithmName() { + return std::string("AutoSeededX917RNG(") + BLOCK_CIPHER::StaticAlgorithmName() + std::string(")"); + } + + ~AutoSeededX917RNG() {} + + /// \brief Construct an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param autoSeed controls auto seeding of the generator + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + /// \sa X917RNG + explicit AutoSeededX917RNG(bool blocking = false, bool autoSeed = true) + {if (autoSeed) Reseed(blocking);} + + /// \brief Reseed an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param input additional entropy to add to the generator + /// \param length the size of the additional entropy, in bytes + /// \details Internally, the generator uses SHA256 to extract the entropy from + /// from the seed and then stretch the material for the block cipher's key + /// and initialization vector. + void Reseed(bool blocking = false, const byte *input = NULLPTR, size_t length = 0); + + /// \brief Deterministically reseed an AutoSeededX917RNG for testing + /// \param key the key to use for the deterministic reseeding + /// \param keylength the size of the key, in bytes + /// \param seed the seed to use for the deterministic reseeding + /// \param timeVector a time vector to use for deterministic reseeding + /// \details This is a testing interface for testing purposes, and should \a NOT + /// be used in production. + void Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length) {Reseed(false, input, length);} + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length) + {m_rng->GenerateIntoBufferedTransformation(target, channel, length);} + + std::string AlgorithmProvider() const; + +private: + member_ptr m_rng; +}; + +template +void AutoSeededX917RNG::Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector) +{ + m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector)); +} + +template +void AutoSeededX917RNG::Reseed(bool blocking, const byte *input, size_t length) +{ + enum {BlockSize=BLOCK_CIPHER::BLOCKSIZE}; + enum {KeyLength=BLOCK_CIPHER::DEFAULT_KEYLENGTH}; + enum {SeedSize=BlockSize + KeyLength}; + + SecByteBlock seed(SeedSize), temp(SeedSize); + const byte label[] = "X9.17 key generation"; + const byte *key=NULLPTR; + + do + { + OS_GenerateRandomBlock(blocking, temp, temp.size()); + + HKDF hkdf; + hkdf.DeriveKey( + seed, seed.size(), // derived secret + temp, temp.size(), // instance secret + input, length, // user secret + label, 20 // unique label + ); + + key = seed + BlockSize; + } // check that seed and key don't have same value + while (memcmp(key, seed, STDMIN((size_t)BlockSize, (size_t)KeyLength)) == 0); + + Reseed(key, KeyLength, seed, NULLPTR); +} + +template +std::string AutoSeededX917RNG::AlgorithmProvider() const +{ + // Hack for now... We need to instantiate one + typename BLOCK_CIPHER::Encryption bc; + return bc.AlgorithmProvider(); +} + +CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief A typedef providing a default generator +/// \details DefaultAutoSeededRNG is a typedef of either AutoSeededX917RNG or AutoSeededRandomPool. +/// If CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined, then DefaultAutoSeededRNG is +/// AutoSeededX917RNG. Otherwise, DefaultAutoSeededRNG is AutoSeededRandomPool. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class DefaultAutoSeededRNG {} +#else +// AutoSeededX917RNG in FIPS mode, otherwise it's AutoSeededRandomPool +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +typedef AutoSeededX917RNG DefaultAutoSeededRNG; +#else +typedef AutoSeededRandomPool DefaultAutoSeededRNG; +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif + +#endif diff --git a/extension/third_party/cryptopp/ossig.h b/extension/third_party/cryptopp/ossig.h new file mode 100644 index 00000000..3b48af5d --- /dev/null +++ b/extension/third_party/cryptopp/ossig.h @@ -0,0 +1,128 @@ +// ossig.h - written and placed in the public domain by Jeffrey Walton +// +/// \file ossig.h +/// \brief Utility class for trapping OS signals. +/// \since Crypto++ 5.6.5 + +#ifndef CRYPTOPP_OS_SIGNAL_H +#define CRYPTOPP_OS_SIGNAL_H + +#include "config.h" + +#if defined(UNIX_SIGNALS_AVAILABLE) +# include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** Unix and Linux compatibles *************** + +#if defined(UNIX_SIGNALS_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Signal handler function pointer +/// \details SignalHandlerFn is provided as a stand alone function pointer with external "C" linkage +/// \sa SignalHandler, NullSignalHandler +extern "C" { + typedef void (*SignalHandlerFn) (int); +} + +/// \brief Null signal handler function +/// \param unused the signal number +/// \details NullSignalHandler is provided as a stand alone function with external "C" linkage +/// and not a static member function due to the the member function's implicit +/// external "C++" linkage. +/// \sa SignalHandler, SignalHandlerFn +extern "C" { + inline void NullSignalHandler(int unused) {CRYPTOPP_UNUSED(unused);} +} + +/// Signal handler for Linux and Unix compatibles +/// \tparam S Signal number +/// \tparam O Flag indicating if an existing handler should be overwritten +/// \details SignalHandler() can be used to install a signal handler with the signature +/// void handler_fn(int). If SignalHandlerFn is not NULL, then +/// the sigaction is set to the function and the sigaction flags is set to the flags. +/// If SignalHandlerFn is NULL, then a default handler is installed +/// using sigaction flags set to 0. The default handler only returns from the call. +/// \details Upon destruction the previous signal handler is restored if the former signal handler +/// was replaced. +/// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or +/// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If +/// you compile with -std=c++03, -std=c++11 or similar, then define +/// _XOPEN_SOURCE=700. +/// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp +/// because the destructor may not run. +/// \since Crypto++ 5.6.5 +/// \sa NullSignalHandler, SignalHandlerFn, \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", DebugTrapHandler +template +struct SignalHandler +{ + /// \brief Construct a signal handler + /// \param pfn Pointer to a signal handler function + /// \param flags Flags to use with the signal handler + /// \details SignalHandler() installs a signal handler with the signature + /// void handler_fn(int). If SignalHandlerFn is not NULL, then + /// the sigaction is set to the function and the sigaction flags is set to the flags. + /// If SignalHandlerFn is NULL, then a default handler is installed + /// using sigaction flags set to 0. The default handler only returns from the call. + /// \details Upon destruction the previous signal handler is restored if the former signal handler + /// was overwritten. + /// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or + /// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If + /// you compile with -std=c++03, -std=c++11 or similar, then define + /// _XOPEN_SOURCE=700. + /// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp + /// because the destructor may not run. setjmp is why cpu.cpp does not use SignalHandler + /// during CPU feature testing. + /// \since Crypto++ 5.6.5 + SignalHandler(SignalHandlerFn pfn = NULLPTR, int flags = 0) : m_installed(false) + { + // http://pubs.opengroup.org/onlinepubs/007908799/xsh/sigaction.html + struct sigaction new_handler; + + do + { + int ret = 0; + + ret = sigaction (S, 0, &m_old); + if (ret != 0) break; // Failed + + // Don't step on another's handler if Overwrite=false + if (m_old.sa_handler != 0 && !O) break; + + // Cygwin/Newlib requires -D_XOPEN_SOURCE=700 + ret = sigemptyset (&new_handler.sa_mask); + if (ret != 0) break; // Failed + + new_handler.sa_handler = (pfn ? pfn : &NullSignalHandler); + new_handler.sa_flags = (pfn ? flags : 0); + + // Install it + ret = sigaction (S, &new_handler, 0); + if (ret != 0) break; // Failed + + m_installed = true; + + } while(0); + } + + ~SignalHandler() + { + if (m_installed) + sigaction (S, &m_old, 0); + } + +private: + struct sigaction m_old; + bool m_installed; + +private: + // Not copyable + SignalHandler(const SignalHandler &); + void operator=(const SignalHandler &); +}; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_OS_SIGNAL_H diff --git a/extension/third_party/cryptopp/padlkrng.cpp b/extension/third_party/cryptopp/padlkrng.cpp new file mode 100644 index 00000000..2c776c53 --- /dev/null +++ b/extension/third_party/cryptopp/padlkrng.cpp @@ -0,0 +1,105 @@ +// via-rng.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. + +#include "pch.h" +#include "config.h" +#include "cryptlib.h" +#include "secblock.h" +#include "padlkrng.h" +#include "cpu.h" + +// The Padlock Security Engine RNG has a few items to be aware of. You can +// find copies of the Programmer's manual, Cryptography Research Inc audit +// report, and other goodies at http://www.cryptopp.com/wiki/VIA_Padlock. + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +std::string PadlockRNG::AlgorithmProvider() const +{ + return "Padlock"; +} + +PadlockRNG::PadlockRNG(word32 divisor) + : m_divisor(DivisorHelper(divisor)), m_msr(0) +{ +#if defined(CRYPTOPP_X86_ASM_AVAILABLE) + if (!HasPadlockRNG()) +#endif + throw PadlockRNG_Err("PadlockRNG", "PadlockRNG generator not available"); +} + +void PadlockRNG::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); +#if defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__GNUC__) + while (size) + { + __asm__ __volatile__ + ( +#if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + "mov %1, %%rdi ;\n" + "movl %2, %%edx ;\n" +#else + "mov %1, %%edi ;\n" + "movl %2, %%edx ;\n" +#endif + + // xstore-rng + ".byte 0x0f, 0xa7, 0xc0 ;\n" + "movl %%eax, %0 ;\n" + + : "=g" (m_msr) : "g" (m_buffer.data()), "g" (m_divisor) +#if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + : "rax", "rdx", "rdi", "cc" +#else + : "eax", "edx", "edi", "cc" +#endif + ); + + const size_t ret = m_msr & 0x1f; + const size_t rem = STDMIN(ret, STDMIN(size, 16U /*buffer size*/)); + std::memcpy(output, m_buffer, rem); + size -= rem; output += rem; + } +#elif defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(_MSC_VER) && defined(_M_IX86) + while (size) + { + word32 result, divisor = m_divisor; + byte *buffer = reinterpret_cast(m_buffer.data()); + __asm { + mov edi, buffer + mov edx, divisor + _emit 0x0f + _emit 0xa7 + _emit 0xc0 + mov result, eax + } + + const size_t ret = (m_msr = result) & 0x1f; + const size_t rem = STDMIN(ret, STDMIN(size, 16U /*buffer size*/)); + std::memcpy(output, buffer, rem); + size -= rem; output += rem; + } +#else + throw PadlockRNG_Err("GenerateBlock", "PadlockRNG generator not available"); +#endif // CRYPTOPP_X86_ASM_AVAILABLE +} + +void PadlockRNG::DiscardBytes(size_t n) +{ + FixedSizeSecBlock discard; + n = RoundUpToMultipleOf(n, sizeof(word32)); + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/padlkrng.h b/extension/third_party/cryptopp/padlkrng.h new file mode 100644 index 00000000..fda1d66b --- /dev/null +++ b/extension/third_party/cryptopp/padlkrng.h @@ -0,0 +1,138 @@ +// via-rng.h - written and placed in public domain by Jeffrey Walton + +/// \file padlkrng.h +/// \brief Classes for VIA Padlock RNG +/// \since Crypto++ 6.0 +/// \sa VIA +/// Padlock on the Crypto++ wiki + +#ifndef CRYPTOPP_PADLOCK_RNG_H +#define CRYPTOPP_PADLOCK_RNG_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a PadlockRNG generator encounters +/// a generator related error. +/// \since Crypto++ 6.0 +class PadlockRNG_Err : public Exception +{ +public: + PadlockRNG_Err(const std::string &operation) + : Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {} + PadlockRNG_Err(const std::string &component, const std::string &message) + : Exception(OTHER_ERROR, component + ": " + message) {} +}; + +/// \brief Hardware generated random numbers using VIA XSTORE +/// \details Some VIA processors provide a Security Engine called Padlock. The Padlock +/// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access +/// to the RNG. +/// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The +/// generator can be configured to discard bits from the buffer to resist analysis. +/// The divisor controls the number of bytes discarded. The formula for +/// the discard amount is 2**divisor - 1. When divisor=0 no bits +/// are discarded and the entire 8 byte buffer is read. If divisor=3 then +/// 7 bytes are discarded and 1 byte is read. TheVIA SDK samples use divisor=1. +/// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine +/// in 2003. CRI provided recommendations to operate the generator for secure and +/// non-secure applications. Additionally, the Programmers Guide and SDK provided a +/// different configuration in the sample code. +/// \details You can operate the generator according to CRI recommendations by setting +/// divisor, reading one word (or partial word) at a time from the FIFO, and +/// then inspecting the MSR after each read. +/// \details The audit report with recommendations is available on the Crypto++ wiki +/// at VIA Padlock. +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 6.0 +class PadlockRNG : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "PadlockRNG"; } + + virtual ~PadlockRNG() {} + + /// \brief Construct a PadlockRNG generator + /// \param divisor the XSTORE divisor + /// \details Some VIA processors provide a Security Engine called Padlock. The Padlock + /// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access + /// to the RNG. + /// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The + /// generator can be configured to discard bits from the buffer to resist analysis. + /// The divisor controls the number of bytes discarded. The formula for + /// the discard amount is 2**divisor - 1. When divisor=0 no bits + /// are discarded and the entire 8 byte buffer is read. If divisor=3 then + /// 7 bytes are discarded and 1 byte is read. VIA SDK samples use divisor=1. + /// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine + /// in 2003. CRI provided recommendations to operate the generator for secure and + /// non-secure applications. Additionally, the Programmers SDK provided a different + /// configuration in the sample code. + /// \details The audit report with recommendations is available on the Crypto++ wiki + /// at VIA Padlock. + /// \sa SetDivisor, GetDivisor + PadlockRNG(word32 divisor=1); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the Padlock generator discards words, not bytes. If n is + /// not a multiple of a 32-bit word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const; + + /// \brief Set the XSTORE divisor + /// \param divisor the XSTORE divisor + /// \return the old XSTORE divisor + word32 SetDivisor(word32 divisor) + { + word32 old = m_divisor; + m_divisor = DivisorHelper(divisor); + return old; + } + + /// \brief Get the XSTORE divisor + /// \return the current XSTORE divisor + word32 GetDivisor() const + { + return m_divisor; + } + + /// \brief Get the MSR for the last operation + /// \return the MSR for the last read operation + word32 GetMSR() const + { + return m_msr; + } + +protected: + inline word32 DivisorHelper(word32 divisor) + { + return divisor > 3 ? 3 : divisor; + } + +private: + FixedSizeAlignedSecBlock m_buffer; + word32 m_divisor, m_msr; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_PADLOCK_RNG_H diff --git a/extension/third_party/cryptopp/panama.cpp b/extension/third_party/cryptopp/panama.cpp new file mode 100644 index 00000000..b6d6a0b6 --- /dev/null +++ b/extension/third_party/cryptopp/panama.cpp @@ -0,0 +1,533 @@ +// panama.cpp - originally written and placed in the public domain by Wei Dai + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM panama.cpp" to generate MASM code + +#include "pch.h" + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#include "panama.h" +#include "secblock.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4731) +#endif + +template +std::string Panama::AlgorithmProvider() const +{ +#ifndef CRYPTOPP_DISABLE_PANAMA_ASM +# if CRYPTOPP_SSSE3_ASM_AVAILABLE + if(HasSSSE3()) + return "SSSE3"; +# elif CRYPTOPP_SSE2_ASM_AVAILABLE + if(HasSSE2()) + return "SSE2"; +# endif +#endif + return "C++"; +} + +template +void Panama::Reset() +{ + memset(m_state, 0, m_state.SizeInBytes()); +#if CRYPTOPP_SSSE3_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_PANAMA_ASM) + m_state[17] = HasSSSE3(); +#endif +} + +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void Panama_SSE2_Pull(size_t count, word32 *state, word32 *z, const word32 *y); +} +#elif CRYPTOPP_SSE2_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_PANAMA_ASM) + +#ifdef CRYPTOPP_GENERATE_X64_MASM + Panama_SSE2_Pull PROC FRAME + rex_push_reg rdi + alloc_stack(2*16) + save_xmm128 xmm6, 0h + save_xmm128 xmm7, 10h + .endprolog +#else +void CRYPTOPP_NOINLINE Panama_SSE2_Pull(size_t count, word32 *state, word32 *z, const word32 *y) +{ +#if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + asm __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86( bx) +#else + AS2( mov AS_REG_1, count) + AS2( mov AS_REG_2, state) + AS2( mov AS_REG_3, z) + AS2( mov AS_REG_4, y) +#endif +#endif // #ifdef CRYPTOPP_GENERATE_X64_MASM + +#if CRYPTOPP_BOOL_X86 + #define REG_loopEnd [esp] +#elif defined(CRYPTOPP_GENERATE_X64_MASM) + #define REG_loopEnd rdi +#else + #define REG_loopEnd r8 +#endif + + AS2( shl AS_REG_1, 5) + ASJ( jz, 5, f) + AS2( mov AS_REG_6d, [AS_REG_2+4*17]) + AS2( add AS_REG_1, AS_REG_6) + + #if CRYPTOPP_BOOL_X64 + AS2( mov REG_loopEnd, AS_REG_1) + #else + AS_PUSH_IF86( bp) + AS1( push AS_REG_1) + #endif + + AS2( movdqa xmm0, XMMWORD_PTR [AS_REG_2+0*16]) + AS2( movdqa xmm1, XMMWORD_PTR [AS_REG_2+1*16]) + AS2( movdqa xmm2, XMMWORD_PTR [AS_REG_2+2*16]) + AS2( movdqa xmm3, XMMWORD_PTR [AS_REG_2+3*16]) + AS2( mov eax, dword ptr [AS_REG_2+4*16]) + + ASL(4) + // gamma and pi +#if CRYPTOPP_SSSE3_ASM_AVAILABLE + AS2( test AS_REG_6, 1) + ASJ( jnz, 6, f) +#endif + AS2( movdqa xmm6, xmm2) + AS2( movss xmm6, xmm3) + ASS( pshufd xmm5, xmm6, 0, 3, 2, 1) + AS2( movd xmm6, eax) + AS2( movdqa xmm7, xmm3) + AS2( movss xmm7, xmm6) + ASS( pshufd xmm6, xmm7, 0, 3, 2, 1) +#if CRYPTOPP_SSSE3_ASM_AVAILABLE + ASJ( jmp, 7, f) + ASL(6) + AS2( movdqa xmm5, xmm3) + AS3( palignr xmm5, xmm2, 4) + AS2( movd xmm6, eax) + AS3( palignr xmm6, xmm3, 4) + ASL(7) +#endif + + AS2( movd AS_REG_1d, xmm2) + AS1( not AS_REG_1d) + AS2( movd AS_REG_7d, xmm3) + AS2( or AS_REG_1d, AS_REG_7d) + AS2( xor eax, AS_REG_1d) + +#define SSE2_Index(i) ASM_MOD(((i)*13+16), 17) + +#define pi(i) \ + AS2( movd AS_REG_1d, xmm7)\ + AS2( rol AS_REG_1d, ASM_MOD((ASM_MOD(5*i,17)*(ASM_MOD(5*i,17)+1)/2), 32))\ + AS2( mov [AS_REG_2+SSE2_Index(ASM_MOD(5*(i), 17))*4], AS_REG_1d) + +#define pi4(x, y, z, a, b, c, d) \ + AS2( pcmpeqb xmm7, xmm7)\ + AS2( pxor xmm7, x)\ + AS2( por xmm7, y)\ + AS2( pxor xmm7, z)\ + pi(a)\ + ASS( pshuflw xmm7, xmm7, 1, 0, 3, 2)\ + pi(b)\ + AS2( punpckhqdq xmm7, xmm7)\ + pi(c)\ + ASS( pshuflw xmm7, xmm7, 1, 0, 3, 2)\ + pi(d) + + pi4(xmm1, xmm2, xmm3, 1, 5, 9, 13) + pi4(xmm0, xmm1, xmm2, 2, 6, 10, 14) + pi4(xmm6, xmm0, xmm1, 3, 7, 11, 15) + pi4(xmm5, xmm6, xmm0, 4, 8, 12, 16) + + // output keystream and update buffer here to hide partial memory stalls between pi and theta + AS2( movdqa xmm4, xmm3) + AS2( punpcklqdq xmm3, xmm2) // 1 5 2 6 + AS2( punpckhdq xmm4, xmm2) // 9 10 13 14 + AS2( movdqa xmm2, xmm1) + AS2( punpcklqdq xmm1, xmm0) // 3 7 4 8 + AS2( punpckhdq xmm2, xmm0) // 11 12 15 16 + + // keystream + AS2( test AS_REG_3, AS_REG_3) + ASJ( jz, 0, f) + AS2( movdqa xmm6, xmm4) + AS2( punpcklqdq xmm4, xmm2) + AS2( punpckhqdq xmm6, xmm2) + AS2( test AS_REG_4, 15) + ASJ( jnz, 2, f) + AS2( test AS_REG_4, AS_REG_4) + ASJ( jz, 1, f) + AS2( pxor xmm4, [AS_REG_4]) + AS2( pxor xmm6, [AS_REG_4+16]) + AS2( add AS_REG_4, 32) + ASJ( jmp, 1, f) + ASL(2) + AS2( movdqu xmm0, [AS_REG_4]) + AS2( movdqu xmm2, [AS_REG_4+16]) + AS2( pxor xmm4, xmm0) + AS2( pxor xmm6, xmm2) + AS2( add AS_REG_4, 32) + ASL(1) + AS2( test AS_REG_3, 15) + ASJ( jnz, 3, f) + AS2( movdqa XMMWORD_PTR [AS_REG_3], xmm4) + AS2( movdqa XMMWORD_PTR [AS_REG_3+16], xmm6) + AS2( add AS_REG_3, 32) + ASJ( jmp, 0, f) + ASL(3) + AS2( movdqu XMMWORD_PTR [AS_REG_3], xmm4) + AS2( movdqu XMMWORD_PTR [AS_REG_3+16], xmm6) + AS2( add AS_REG_3, 32) + ASL(0) + + // buffer update + AS2( lea AS_REG_1, [AS_REG_6 + 32]) + AS2( and AS_REG_1, 31*32) + AS2( lea AS_REG_7, [AS_REG_6 + (32-24)*32]) + AS2( and AS_REG_7, 31*32) + + AS2( movdqa xmm0, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+0*8]) + AS2( pxor xmm3, xmm0) + ASS( pshufd xmm0, xmm0, 2, 3, 0, 1) + AS2( movdqa XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+0*8], xmm3) + AS2( pxor xmm0, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+2*8]) + AS2( movdqa XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+2*8], xmm0) + + AS2( movdqa xmm4, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+2*8]) + AS2( pxor xmm1, xmm4) + AS2( movdqa XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+2*8], xmm1) + AS2( pxor xmm4, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+0*8]) + AS2( movdqa XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+0*8], xmm4) + + // theta + AS2( movdqa xmm3, XMMWORD_PTR [AS_REG_2+3*16]) + AS2( movdqa xmm2, XMMWORD_PTR [AS_REG_2+2*16]) + AS2( movdqa xmm1, XMMWORD_PTR [AS_REG_2+1*16]) + AS2( movdqa xmm0, XMMWORD_PTR [AS_REG_2+0*16]) + +#if CRYPTOPP_SSSE3_ASM_AVAILABLE + AS2( test AS_REG_6, 1) + ASJ( jnz, 8, f) +#endif + AS2( movd xmm6, eax) + AS2( movdqa xmm7, xmm3) + AS2( movss xmm7, xmm6) + AS2( movdqa xmm6, xmm2) + AS2( movss xmm6, xmm3) + AS2( movdqa xmm5, xmm1) + AS2( movss xmm5, xmm2) + AS2( movdqa xmm4, xmm0) + AS2( movss xmm4, xmm1) + ASS( pshufd xmm7, xmm7, 0, 3, 2, 1) + ASS( pshufd xmm6, xmm6, 0, 3, 2, 1) + ASS( pshufd xmm5, xmm5, 0, 3, 2, 1) + ASS( pshufd xmm4, xmm4, 0, 3, 2, 1) +#if CRYPTOPP_SSSE3_ASM_AVAILABLE + ASJ( jmp, 9, f) + ASL(8) + AS2( movd xmm7, eax) + AS3( palignr xmm7, xmm3, 4) + AS2( movq xmm6, xmm3) + AS3( palignr xmm6, xmm2, 4) + AS2( movq xmm5, xmm2) + AS3( palignr xmm5, xmm1, 4) + AS2( movq xmm4, xmm1) + AS3( palignr xmm4, xmm0, 4) + ASL(9) +#endif + + AS2( xor eax, 1) + AS2( movd AS_REG_1d, xmm0) + AS2( xor eax, AS_REG_1d) + AS2( movd AS_REG_1d, xmm3) + AS2( xor eax, AS_REG_1d) + + AS2( pxor xmm3, xmm2) + AS2( pxor xmm2, xmm1) + AS2( pxor xmm1, xmm0) + AS2( pxor xmm0, xmm7) + AS2( pxor xmm3, xmm7) + AS2( pxor xmm2, xmm6) + AS2( pxor xmm1, xmm5) + AS2( pxor xmm0, xmm4) + + // sigma + AS2( lea AS_REG_1, [AS_REG_6 + (32-4)*32]) + AS2( and AS_REG_1, 31*32) + AS2( lea AS_REG_7, [AS_REG_6 + 16*32]) + AS2( and AS_REG_7, 31*32) + + AS2( movdqa xmm4, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+0*16]) + AS2( movdqa xmm5, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+0*16]) + AS2( movdqa xmm6, xmm4) + AS2( punpcklqdq xmm4, xmm5) + AS2( punpckhqdq xmm6, xmm5) + AS2( pxor xmm3, xmm4) + AS2( pxor xmm2, xmm6) + + AS2( movdqa xmm4, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_1+1*16]) + AS2( movdqa xmm5, XMMWORD_PTR [AS_REG_2+20*4+AS_REG_7+1*16]) + AS2( movdqa xmm6, xmm4) + AS2( punpcklqdq xmm4, xmm5) + AS2( punpckhqdq xmm6, xmm5) + AS2( pxor xmm1, xmm4) + AS2( pxor xmm0, xmm6) + + // loop + AS2( add AS_REG_6, 32) + AS2( cmp AS_REG_6, REG_loopEnd) + ASJ( jne, 4, b) + + // save state + AS2( mov [AS_REG_2+4*16], eax) + AS2( movdqa XMMWORD_PTR [AS_REG_2+3*16], xmm3) + AS2( movdqa XMMWORD_PTR [AS_REG_2+2*16], xmm2) + AS2( movdqa XMMWORD_PTR [AS_REG_2+1*16], xmm1) + AS2( movdqa XMMWORD_PTR [AS_REG_2+0*16], xmm0) + + #if CRYPTOPP_BOOL_X86 + AS2( add esp, 4) + AS_POP_IF86( bp) + #endif + ASL(5) + +#if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + AS_POP_IF86( bx) + ATT_PREFIX + : + #if CRYPTOPP_BOOL_X64 + : "D" (count), "S" (state), "d" (z), "c" (y) + : "%r8", "%r9", "r10", "%eax", "memory", "cc", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" + #else + : "c" (count), "d" (state), "S" (z), "D" (y) + : "%eax", "memory", "cc" + #endif + ); +#endif + +#ifdef CRYPTOPP_GENERATE_X64_MASM + movdqa xmm6, [rsp + 0h] + movdqa xmm7, [rsp + 10h] + add rsp, 2*16 + pop rdi + ret + Panama_SSE2_Pull ENDP +#else +} +#endif +#endif // CRYPTOPP_SSE2_ASM_AVAILABLE + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +template +void Panama::Iterate(size_t count, const word32 *p, byte *output, const byte *input, KeystreamOperation operation) +{ + word32 bstart = m_state[17]; + word32 *const aPtr = m_state; + word32 cPtr[17]; + +#define bPtr ((byte *)(aPtr+20)) + +// reorder the state for SSE2 +// a and c: 4 8 12 16 | 3 7 11 15 | 2 6 10 14 | 1 5 9 13 | 0 | +// xmm0 xmm1 xmm2 xmm3 eax +#define a(i) aPtr[((i)*13+16) % 17] // 13 is inverse of 4 mod 17 +#define c(i) cPtr[((i)*13+16) % 17] +// b: 0 4 | 1 5 | 2 6 | 3 7 +#define b(i, j) b##i[(j)*2%8 + (j)/4] + +// buffer update +#define US(i) {word32 t=b(0,i); b(0,i)=ConditionalByteReverse(B::ToEnum(), p[i])^t; b(25,(i+6)%8)^=t;} +#define UL(i) {word32 t=b(0,i); b(0,i)=a(i+1)^t; b(25,(i+6)%8)^=t;} +// gamma and pi +#define GP(i) c(5*i%17) = rotlFixed(a(i) ^ (a((i+1)%17) | ~a((i+2)%17)), ((5*i%17)*((5*i%17)+1)/2)%32) +// theta and sigma +#define T(i,x) a(i) = c(i) ^ c((i+1)%17) ^ c((i+4)%17) ^ x +#define TS1S(i) T(i+1, ConditionalByteReverse(B::ToEnum(), p[i])) +#define TS1L(i) T(i+1, b(4,i)) +#define TS2(i) T(i+9, b(16,i)) + + while (count--) + { + if (output) + { +#define PANAMA_OUTPUT(x) \ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 0, a(0+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 1, a(1+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 2, a(2+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 3, a(3+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 4, a(4+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 5, a(5+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 6, a(6+9));\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 7, a(7+9)); + + typedef word32 WordType; + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(PANAMA_OUTPUT, 4*8); + } + + word32 *const b16 = (word32 *)(void *)(bPtr+((bstart+16*32) & 31*32)); + word32 *const b4 = (word32 *)(void *)(bPtr+((bstart+(32-4)*32) & 31*32)); + bstart += 32; + word32 *const b0 = (word32 *)(void *)(bPtr+((bstart) & 31*32)); + word32 *const b25 = (word32 *)(void *)(bPtr+((bstart+(32-25)*32) & 31*32)); + + if (p) + { + US(0); US(1); US(2); US(3); US(4); US(5); US(6); US(7); + } + else + { + UL(0); UL(1); UL(2); UL(3); UL(4); UL(5); UL(6); UL(7); + } + + GP(0); + GP(1); + GP(2); + GP(3); + GP(4); + GP(5); + GP(6); + GP(7); + GP(8); + GP(9); + GP(10); + GP(11); + GP(12); + GP(13); + GP(14); + GP(15); + GP(16); + + T(0,1); + + if (p) + { + TS1S(0); TS1S(1); TS1S(2); TS1S(3); TS1S(4); TS1S(5); TS1S(6); TS1S(7); + p += 8; + } + else + { + TS1L(0); TS1L(1); TS1L(2); TS1L(3); TS1L(4); TS1L(5); TS1L(6); TS1L(7); + } + + TS2(0); TS2(1); TS2(2); TS2(3); TS2(4); TS2(5); TS2(6); TS2(7); + } + m_state[17] = bstart; +} + +NAMESPACE_BEGIN(Weak) +template +size_t PanamaHash::HashMultipleBlocks(const word32 *input, size_t length) +{ + this->Iterate(length / this->BLOCKSIZE, input); + return length % this->BLOCKSIZE; +} + +template +void PanamaHash::TruncatedFinal(byte *hash, size_t size) +{ + this->ThrowIfInvalidTruncatedSize(size); + + this->PadLastBlock(this->BLOCKSIZE, 0x01); + + this->HashEndianCorrectedBlock(this->m_data); + + this->Iterate(32); // pull + + this->Iterate(1, NULLPTR, m_buf.BytePtr(), NULLPTR); + + memcpy(hash, m_buf, size); + + this->Restart(); // reinit for next use +} +NAMESPACE_END + +template +void PanamaCipherPolicy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==32); + memcpy(m_key, key, 32); +} + +template +void PanamaCipherPolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(iv); + CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(length==32); + + this->Reset(); + this->Iterate(1, m_key); + if (iv && IsAligned(iv)) + this->Iterate(1, reinterpret_cast(iv)); + else + { + if (iv) + memcpy(m_buf, iv, 32); + else + memset(m_buf, 0, 32); + this->Iterate(1, m_buf); + } + +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_PANAMA_ASM) + if (B::ToEnum() == LITTLE_ENDIAN_ORDER && HasSSE2() && !IsP4()) // SSE2 code is slower on P4 Prescott + Panama_SSE2_Pull(32, this->m_state, NULLPTR, NULLPTR); + else +#endif + this->Iterate(32); +} + +template +std::string PanamaCipherPolicy::AlgorithmProvider() const +{ + return Panama::AlgorithmProvider(); +} + +template +unsigned int PanamaCipherPolicy::GetAlignment() const +{ +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_PANAMA_ASM) + if (B::ToEnum() == LITTLE_ENDIAN_ORDER && HasSSE2()) + return 16; + else +#endif + return 1; +} + +template +void PanamaCipherPolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_PANAMA_ASM) + if (B::ToEnum() == LITTLE_ENDIAN_ORDER && HasSSE2()) + Panama_SSE2_Pull(iterationCount, this->m_state, + reinterpret_cast(output), reinterpret_cast(input)); + else +#endif + this->Iterate(iterationCount, NULLPTR, output, input, operation); +} + +template class Panama; +template class Panama; + +template class Weak::PanamaHash; +template class Weak::PanamaHash; + +template class PanamaCipherPolicy; +template class PanamaCipherPolicy; + +NAMESPACE_END + +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM diff --git a/extension/third_party/cryptopp/panama.h b/extension/third_party/cryptopp/panama.h new file mode 100644 index 00000000..b3d50a04 --- /dev/null +++ b/extension/third_party/cryptopp/panama.h @@ -0,0 +1,169 @@ +// panama.h - originally written and placed in the public domain by Wei Dai + +/// \file panama.h +/// \brief Classes for Panama hash and stream cipher + +#ifndef CRYPTOPP_PANAMA_H +#define CRYPTOPP_PANAMA_H + +#include "strciphr.h" +#include "iterhash.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler error with .intel_syntax +//#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +//# define CRYPTOPP_DISABLE_PANAMA_ASM +//#endif + +// https://github.com/weidai11/cryptopp/issues/758 +#define CRYPTOPP_DISABLE_PANAMA_ASM 1 + +NAMESPACE_BEGIN(CryptoPP) + +// Base class, do not use directly +template +class CRYPTOPP_NO_VTABLE Panama +{ +public: + virtual ~Panama() {} + std::string AlgorithmProvider() const; + void Reset(); + void Iterate(size_t count, const word32 *p=NULLPTR, byte *output=NULLPTR, const byte *input=NULLPTR, KeystreamOperation operation=WRITE_KEYSTREAM); + +protected: + typedef word32 Stage[8]; + CRYPTOPP_CONSTANT(STAGES = 32); + + FixedSizeAlignedSecBlock m_state; +}; + +namespace Weak { +/// \brief Panama hash +/// \sa Panama Hash +template +class PanamaHash : protected Panama, public AlgorithmImpl, PanamaHash > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + virtual ~PanamaHash() {} + PanamaHash() {Panama::Reset();} + unsigned int DigestSize() const {return DIGESTSIZE;} + void TruncatedFinal(byte *hash, size_t size); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} + std::string AlgorithmProvider() const {return Panama::AlgorithmProvider();} // Fix https://github.com/weidai11/cryptopp/issues/801 + +protected: + void Init() {Panama::Reset();} + void HashEndianCorrectedBlock(const word32 *data) {this->Iterate(1, data);} // push + size_t HashMultipleBlocks(const word32 *input, size_t length); + word32* StateBuf() {return NULLPTR;} + + FixedSizeSecBlock m_buf; +}; +} + +/// \brief MAC construction using a hermetic hash function +template +class HermeticHashFunctionMAC : public AlgorithmImpl > >, T_Info> +{ +public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + + m_key.Assign(key, length); + Restart(); + } + + void Restart() + { + m_hash.Restart(); + m_keyed = false; + } + + void Update(const byte *input, size_t length) + { + if (!m_keyed) + KeyHash(); + m_hash.Update(input, length); + } + + void TruncatedFinal(byte *digest, size_t digestSize) + { + if (!m_keyed) + KeyHash(); + m_hash.TruncatedFinal(digest, digestSize); + m_keyed = false; + } + + unsigned int DigestSize() const + {return m_hash.DigestSize();} + unsigned int BlockSize() const + {return m_hash.BlockSize();} + unsigned int OptimalBlockSize() const + {return m_hash.OptimalBlockSize();} + unsigned int OptimalDataAlignment() const + {return m_hash.OptimalDataAlignment();} + +protected: + void KeyHash() + { + m_hash.Update(m_key, m_key.size()); + m_keyed = true; + } + + T_Hash m_hash; + bool m_keyed; + SecByteBlock m_key; +}; + +namespace Weak { +/// \brief Panama message authentication code +template +class PanamaMAC : public HermeticHashFunctionMAC > +{ +public: + PanamaMAC() {} + PanamaMAC(const byte *key, unsigned int length) + {this->SetKey(key, length);} +}; +} + +/// \brief Panama stream cipher information +template +struct PanamaCipherInfo : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} +}; + +/// \brief Panama stream cipher operation +template +class PanamaCipherPolicy : public AdditiveCipherConcretePolicy, + public PanamaCipherInfo, + protected Panama +{ +protected: + virtual ~PanamaCipherPolicy() {} + std::string AlgorithmProvider() const; + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + unsigned int GetAlignment() const; + + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_buf; +}; + +/// \brief Panama stream cipher +/// \sa Panama Stream Cipher +template +struct PanamaCipher : public PanamaCipherInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, PanamaCipherInfo > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/pch.cpp b/extension/third_party/cryptopp/pch.cpp new file mode 100644 index 00000000..9e6b2e07 --- /dev/null +++ b/extension/third_party/cryptopp/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/extension/third_party/cryptopp/pch.h b/extension/third_party/cryptopp/pch.h new file mode 100644 index 00000000..f158399c --- /dev/null +++ b/extension/third_party/cryptopp/pch.h @@ -0,0 +1,31 @@ +// pch.h - originally written and placed in the public domain by Wei Dai + +/// \file pch.h +/// \brief Precompiled header file +/// \details The precompiled header files are used Windows. + +#ifndef CRYPTOPP_PCH_H +#define CRYPTOPP_PCH_H + +# ifdef CRYPTOPP_GENERATE_X64_MASM + #include "cpu.h" + +# else + #include "config.h" + + #ifdef USE_PRECOMPILED_HEADERS + #include "simple.h" + #include "secblock.h" + #include "misc.h" + #include "smartptr.h" + #include "stdcpp.h" + #endif +# endif + +// Enable file and line numbers, if available. +// #if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_PRECOMPILED_HEADERS) +// # define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +// # define new DEBUG_NEW +// #endif + +#endif // CRYPTOPP_PCH_H diff --git a/extension/third_party/cryptopp/pkcspad.cpp b/extension/third_party/cryptopp/pkcspad.cpp new file mode 100644 index 00000000..5192c109 --- /dev/null +++ b/extension/third_party/cryptopp/pkcspad.cpp @@ -0,0 +1,160 @@ +// pkcspad.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_PKCSPAD_CPP // SunCC workaround: compiler could cause this file to be included twice +#define CRYPTOPP_PKCSPAD_CPP + +#include "pkcspad.h" +#include "emsa2.h" +#include "hashfwd.h" +#include "misc.h" +#include "trap.h" + +NAMESPACE_BEGIN(CryptoPP) + +// Typedef/cast change due to Clang, http://github.com/weidai11/cryptopp/issues/300 +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x29,0x30,0x0D,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0C,0x02,0x05,0x00,0x04,0x18}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +// Inclusion based on DLL due to Clang, http://github.com/weidai11/cryptopp/issues/300 +#ifndef CRYPTOPP_IS_DLL +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x51,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x03,0x05, 0x00,0x04,0x40}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +// http://github.com/weidai11/cryptopp/issues/517. OIDs and encoded prefixes found at +// http://www.ietf.org/archive/id/draft-jivsov-openpgp-sha3-01.txt +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x31,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x08,0x05, 0x00,0x04,0x20}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x41,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x09,0x05, 0x00,0x04,0x30}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); + +template<> const byte PKCS_DigestDecoration::decoration[] = {0x30,0x51,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x0a,0x05, 0x00,0x04,0x40}; +template<> const unsigned int PKCS_DigestDecoration::length = (unsigned int)sizeof(PKCS_DigestDecoration::decoration); +#endif + +size_t PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(size_t paddedLength) const +{ + return SaturatingSubtract(paddedLength/8, 10U); +} + +void PKCS_EncryptionPaddingScheme::Pad(RandomNumberGenerator& rng, const byte *input, size_t inputLen, byte *pkcsBlock, size_t pkcsBlockLen, const NameValuePairs& parameters) const +{ + CRYPTOPP_UNUSED(parameters); + CRYPTOPP_ASSERT (inputLen <= MaxUnpaddedLength(pkcsBlockLen)); // this should be checked by caller + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + pkcsBlock[0] = 0; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + pkcsBlock[0] = 2; // block type 2 + + // pad with non-zero random bytes + for (unsigned i = 1; i < pkcsBlockLen-inputLen-1; i++) + pkcsBlock[i] = (byte)rng.GenerateWord32(1, 0xff); + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator + memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + +DecodingResult PKCS_EncryptionPaddingScheme::Unpad(const byte *pkcsBlock, size_t pkcsBlockLen, byte *output, const NameValuePairs& parameters) const +{ + CRYPTOPP_UNUSED(parameters); + bool invalid = false; + size_t maxOutputLen = MaxUnpaddedLength(pkcsBlockLen); + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + invalid = (pkcsBlock[0] != 0) || invalid; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + // Require block type 2. + invalid = (pkcsBlock[0] != 2) || invalid; + + // skip past the padding until we find the separator + size_t i=1; + while (i maxOutputLen) || invalid; + + if (invalid) + return DecodingResult(); + + memcpy (output, pkcsBlock+i, outputLen); + return DecodingResult(outputLen); +} + +// ******************************************************** + +#ifndef CRYPTOPP_IMPORTS + +void PKCS1v15_SignatureMessageEncodingMethod::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + CRYPTOPP_ASSERT(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize())); + + size_t pkcsBlockLen = representativeBitLength; + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + representative[0] = 0; + representative++; + } + pkcsBlockLen /= 8; + + representative[0] = 1; // block type 1 + + unsigned int digestSize = hash.DigestSize(); + byte *pPadding = representative + 1; + byte *pDigest = representative + pkcsBlockLen - digestSize; + byte *pHashId = pDigest - hashIdentifier.second; + byte *pSeparator = pHashId - 1; + + // pad with 0xff + memset(pPadding, 0xff, pSeparator-pPadding); + *pSeparator = 0; + memcpy(pHashId, hashIdentifier.first, hashIdentifier.second); + hash.Final(pDigest); +} + +#endif + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/pkcspad.h b/extension/third_party/cryptopp/pkcspad.h new file mode 100644 index 00000000..88d9d735 --- /dev/null +++ b/extension/third_party/cryptopp/pkcspad.h @@ -0,0 +1,123 @@ +// pkcspad.h - originally written and placed in the public domain by Wei Dai + +/// \file pkcspad.h +/// \brief Classes for PKCS padding schemes +/// \details PKCS #1 v1.5, v2.0 and P1363a allow MD2, MD5, SHA1, SHA224, SHA256, SHA384, +/// SHA512, Tiger and RipeMd-160 to be instantiated. + +#ifndef CRYPTOPP_PKCSPAD_H +#define CRYPTOPP_PKCSPAD_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PKCS #1 v1.5 Encryption Padding Scheme +/// \sa EME-PKCS1-v1_5 +class PKCS_EncryptionPaddingScheme : public PK_EncryptionMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EME-PKCS1-v1_5";} + + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; +}; + +/// \brief PKCS #1 decoration data structure +template class PKCS_DigestDecoration +{ +public: + static const byte decoration[]; + static const unsigned int length; +}; + +// PKCS_DigestDecoration can be instantiated with the following +// classes as specified in PKCS #1 v2.0 and P1363a +// SHA1, SHA224, SHA256, SHA384, SHA512, Tiger, RIPEMD160, MD2, MD5 + +#if defined(CRYPTOPP_IS_DLL) +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +// http://github.com/weidai11/cryptopp/issues/517 +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +// http://github.com/weidai11/cryptopp/issues/517 +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +#endif + +/// \brief PKCS #1 v1.5 Signature Encoding Scheme +/// \sa EMSA-PKCS1-v1_5 +class CRYPTOPP_DLL PKCS1v15_SignatureMessageEncodingMethod : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA-PKCS1-v1_5";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierSize, size_t digestSize) const + {return 8 * (digestSize + hashIdentifierSize + 10);} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(PKCS_DigestDecoration::decoration, PKCS_DigestDecoration::length); + } + }; + }; +}; + +/// \brief PKCS #1 version 1.5, for use with RSAES and RSASS +/// \dontinclude pkcspad.h + +struct PKCS1v15 : public SignatureStandard, public EncryptionStandard +{ + typedef PKCS_EncryptionPaddingScheme EncryptionMessageEncodingMethod; + typedef PKCS1v15_SignatureMessageEncodingMethod SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/poly1305.cpp b/extension/third_party/cryptopp/poly1305.cpp new file mode 100644 index 00000000..354d76c4 --- /dev/null +++ b/extension/third_party/cryptopp/poly1305.cpp @@ -0,0 +1,403 @@ +// poly1305.cpp - written and placed in the public domain by Jeffrey Walton and Jean-Pierre Munch +// Based on Andy Polyakov's Base-2^26 scalar multiplication implementation. +// For more information, see https://www.openssl.org/~appro/cryptogams/. + +// Copyright (c) 2006-2017, CRYPTOGAMS by +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain copyright notices, +// this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the CRYPTOGAMS nor the names of its copyright +// holder and contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. + +#include "pch.h" +#include "cryptlib.h" +#include "poly1305.h" +#include "aes.h" +#include "cpu.h" + +////////////////////////////// Common Poly1305 ////////////////////////////// + +ANONYMOUS_NAMESPACE_BEGIN + +using namespace CryptoPP; + +inline word32 CONSTANT_TIME_CARRY(word32 a, word32 b) +{ + return ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)); +} + +void Poly1305_HashBlocks(word32 h[5], word32 r[4], const byte *input, size_t length, word32 padbit) +{ + word32 r0, r1, r2, r3; + word32 s1, s2, s3; + word32 h0, h1, h2, h3, h4, c; + word64 d0, d1, d2, d3; + + r0 = r[0]; r1 = r[1]; + r2 = r[2]; r3 = r[3]; + + s1 = r1 + (r1 >> 2); + s2 = r2 + (r2 >> 2); + s3 = r3 + (r3 >> 2); + + h0 = h[0]; h1 = h[1]; h2 = h[2]; + h3 = h[3]; h4 = h[4]; + + while (length >= 16) + { + // h += m[i] + h0 = (word32)(d0 = (word64)h0 + GetWord(false, LITTLE_ENDIAN_ORDER, input + 0)); + h1 = (word32)(d1 = (word64)h1 + (d0 >> 32) + GetWord(false, LITTLE_ENDIAN_ORDER, input + 4)); + h2 = (word32)(d2 = (word64)h2 + (d1 >> 32) + GetWord(false, LITTLE_ENDIAN_ORDER, input + 8)); + h3 = (word32)(d3 = (word64)h3 + (d2 >> 32) + GetWord(false, LITTLE_ENDIAN_ORDER, input + 12)); + h4 += (word32)(d3 >> 32) + padbit; + + // h *= r "%" p + d0 = ((word64)h0 * r0) + + ((word64)h1 * s3) + + ((word64)h2 * s2) + + ((word64)h3 * s1); + d1 = ((word64)h0 * r1) + + ((word64)h1 * r0) + + ((word64)h2 * s3) + + ((word64)h3 * s2) + + (h4 * s1); + d2 = ((word64)h0 * r2) + + ((word64)h1 * r1) + + ((word64)h2 * r0) + + ((word64)h3 * s3) + + (h4 * s2); + d3 = ((word64)h0 * r3) + + ((word64)h1 * r2) + + ((word64)h2 * r1) + + ((word64)h3 * r0) + + (h4 * s3); + h4 = (h4 * r0); + + // a) h4:h0 = h4<<128 + d3<<96 + d2<<64 + d1<<32 + d0 + h0 = (word32)d0; + h1 = (word32)(d1 += d0 >> 32); + h2 = (word32)(d2 += d1 >> 32); + h3 = (word32)(d3 += d2 >> 32); + h4 += (word32)(d3 >> 32); + + // b) (h4:h0 += (h4:h0>>130) * 5) %= 2^130 + c = (h4 >> 2) + (h4 & ~3U); + h4 &= 3; + h0 += c; + h1 += (c = CONSTANT_TIME_CARRY(h0,c)); + h2 += (c = CONSTANT_TIME_CARRY(h1,c)); + h3 += (c = CONSTANT_TIME_CARRY(h2,c)); + h4 += CONSTANT_TIME_CARRY(h3,c); + + input += 16; + length -= 16; + } + + h[0] = h0; h[1] = h1; h[2] = h2; + h[3] = h3; h[4] = h4; +} + +void Poly1305_HashFinal(word32 h[5], word32 n[4], byte *mac, size_t size) +{ + word32 h0, h1, h2, h3, h4; + word32 g0, g1, g2, g3, g4; + word32 mask; + word64 t; + + h0 = h[0]; + h1 = h[1]; + h2 = h[2]; + h3 = h[3]; + h4 = h[4]; + + // compare to modulus by computing h + -p + g0 = (word32)(t = (word64)h0 + 5); + g1 = (word32)(t = (word64)h1 + (t >> 32)); + g2 = (word32)(t = (word64)h2 + (t >> 32)); + g3 = (word32)(t = (word64)h3 + (t >> 32)); + g4 = h4 + (word32)(t >> 32); + + // if there was carry into 131st bit, h3:h0 = g3:g0 + mask = 0 - (g4 >> 2); + g0 &= mask; g1 &= mask; + g2 &= mask; g3 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; h3 = (h3 & mask) | g3; + + // mac = (h + nonce) % (2^128) + h0 = (word32)(t = (word64)h0 + n[0]); + h1 = (word32)(t = (word64)h1 + (t >> 32) + n[1]); + h2 = (word32)(t = (word64)h2 + (t >> 32) + n[2]); + h3 = (word32)(t = (word64)h3 + (t >> 32) + n[3]); + + if (size >= 16) + { + PutWord(false, LITTLE_ENDIAN_ORDER, mac + 0, h0); + PutWord(false, LITTLE_ENDIAN_ORDER, mac + 4, h1); + PutWord(false, LITTLE_ENDIAN_ORDER, mac + 8, h2); + PutWord(false, LITTLE_ENDIAN_ORDER, mac + 12, h3); + } + else + { + FixedSizeAlignedSecBlock m; + PutWord(false, LITTLE_ENDIAN_ORDER, m + 0, h0); + PutWord(false, LITTLE_ENDIAN_ORDER, m + 4, h1); + PutWord(false, LITTLE_ENDIAN_ORDER, m + 8, h2); + PutWord(false, LITTLE_ENDIAN_ORDER, m + 12, h3); + std::memcpy(mac, m, size); + } +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein Poly1305 ////////////////////////////// + +// TODO: No longer needed. Remove at next major version bump +template +void Poly1305_Base::HashBlocks(const byte *input, size_t length, word32 padbit) { + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(padbit); + CRYPTOPP_ASSERT(0); +} + +// TODO: No longer needed. Remove at next major version bump +template +void Poly1305_Base::HashFinal(byte *mac, size_t length) { + CRYPTOPP_UNUSED(mac); CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(0); +} + +template +std::string Poly1305_Base::AlgorithmProvider() const +{ + return m_cipher.AlgorithmProvider(); +} + +template +void Poly1305_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(key && length >= 32); + + // key is {k,r} pair. k is AES key, r is the additional key that gets clamped + length = SaturatingSubtract(length, (unsigned)BLOCKSIZE); + m_cipher.SetKey(key, length); + key += length; + + // Rbar is clamped and little endian + m_r[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 0) & 0x0fffffff; + m_r[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 4) & 0x0ffffffc; + m_r[2] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 8) & 0x0ffffffc; + m_r[3] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 12) & 0x0ffffffc; + + // Mark the nonce as dirty, meaning we need a new one + m_used = true; + + ConstByteArrayParameter t; + if (params.GetValue(Name::IV(), t) && t.begin() && t.size()) + { + CRYPTOPP_ASSERT(t.size() == m_nk.size()); + Resynchronize(t.begin(), (int)t.size()); + } + + Restart(); +} + +template +void Poly1305_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !length); + if (!length) return; + + size_t rem, num = m_idx; + if (num) + { + rem = BLOCKSIZE - num; + if (length >= rem) + { + // Process + memcpy_s(m_acc + num, BLOCKSIZE - num, input, rem); + Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 1); + input += rem; length -= rem; + } + else + { + // Accumulate + memcpy_s(m_acc + num, BLOCKSIZE - num, input, length); + m_idx = num + length; + return; + } + } + + rem = length % BLOCKSIZE; + length -= rem; + + if (length >= BLOCKSIZE) { + Poly1305_HashBlocks(m_h, m_r, input, length, 1); + input += length; + } + + if (rem) + memcpy(m_acc, input, rem); + + m_idx = rem; +} + +template +void Poly1305_Base::TruncatedFinal(byte *mac, size_t size) +{ + CRYPTOPP_ASSERT(mac); // Pointer is valid + CRYPTOPP_ASSERT(!m_used); // Nonce is fresh + + ThrowIfInvalidTruncatedSize(size); + + size_t num = m_idx; + if (num) + { + m_acc[num++] = 1; /* pad bit */ + while (num < BLOCKSIZE) + m_acc[num++] = 0; + Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 0); + } + + Poly1305_HashFinal(m_h, m_n, mac, size); + + // Restart + m_used = true; + Restart(); +} + +template +void Poly1305_Base::Resynchronize(const byte *nonce, int nonceLength) +{ + CRYPTOPP_ASSERT(nonceLength == -1 || nonceLength == (int)BLOCKSIZE); + if (nonceLength == -1) { nonceLength = BLOCKSIZE; } + + // Encrypt the nonce, stash in m_nk + m_cipher.ProcessBlock(nonce, m_nk.begin()); + + m_n[0] = GetWord(false, LITTLE_ENDIAN_ORDER, m_nk + 0); + m_n[1] = GetWord(false, LITTLE_ENDIAN_ORDER, m_nk + 4); + m_n[2] = GetWord(false, LITTLE_ENDIAN_ORDER, m_nk + 8); + m_n[3] = GetWord(false, LITTLE_ENDIAN_ORDER, m_nk + 12); + + // Mark nonce as unused, meaning it is fresh + m_used = false; +} + +template +void Poly1305_Base::GetNextIV(RandomNumberGenerator &rng, byte *iv) +{ + rng.GenerateBlock(iv, BLOCKSIZE); +} + +template +void Poly1305_Base::Restart() +{ + m_h[0] = m_h[1] = m_h[2] = m_h[3] = m_h[4] = 0; + m_idx = 0; +} + +////////////////////////////// IETF Poly1305 ////////////////////////////// + +void Poly1305TLS_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(key && length >= 32); + + // key is {r,s} pair. r is the additional key that gets clamped, s is the nonce. + m_r[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 0) & 0x0fffffff; + m_r[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 4) & 0x0ffffffc; + m_r[2] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 8) & 0x0ffffffc; + m_r[3] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 12) & 0x0ffffffc; + + key += 16; + m_n[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 0); + m_n[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 4); + m_n[2] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 8); + m_n[3] = GetWord(false, LITTLE_ENDIAN_ORDER, key + 12); + + Restart(); +} + +void Poly1305TLS_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !length); + if (!length) return; + + size_t rem, num = m_idx; + if (num) + { + rem = BLOCKSIZE - num; + if (length >= rem) + { + // Process + memcpy_s(m_acc + num, BLOCKSIZE - num, input, rem); + Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 1); + input += rem; length -= rem; + } + else + { + // Accumulate + memcpy_s(m_acc + num, BLOCKSIZE - num, input, length); + m_idx = num + length; + return; + } + } + + rem = length % BLOCKSIZE; + length -= rem; + + if (length >= BLOCKSIZE) { + Poly1305_HashBlocks(m_h, m_r, input, length, 1); + input += length; + } + + if (rem) + memcpy(m_acc, input, rem); + + m_idx = rem; +} + +void Poly1305TLS_Base::TruncatedFinal(byte *mac, size_t size) +{ + CRYPTOPP_ASSERT(mac); // Pointer is valid + + ThrowIfInvalidTruncatedSize(size); + + size_t num = m_idx; + if (num) + { + m_acc[num++] = 1; /* pad bit */ + while (num < BLOCKSIZE) + m_acc[num++] = 0; + Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 0); + } + + Poly1305_HashFinal(m_h, m_n, mac, size); + + Restart(); +} + +void Poly1305TLS_Base::Restart() +{ + m_h[0] = m_h[1] = m_h[2] = m_h[3] = m_h[4] = 0; + m_idx = 0; +} + +template class Poly1305_Base; +template class Poly1305; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/poly1305.h b/extension/third_party/cryptopp/poly1305.h new file mode 100644 index 00000000..0745d935 --- /dev/null +++ b/extension/third_party/cryptopp/poly1305.h @@ -0,0 +1,241 @@ +// poly1305.h - written and placed in the public domain by Jeffrey Walton and Jean-Pierre Munch +// Based on Andy Polyakov's Base-2^26 scalar multiplication implementation. +// For more information, see https://www.openssl.org/~appro/cryptogams/. + +// The library added Bernstein's Poly1305 classses at Crypto++ 6.0. The IETF +// uses a slightly different implementation than Bernstein, and the IETF +// classes were added at Crypto++ 8.1. We wanted to maintain ABI compatibility +// at the 8.1 release so the original Poly1305 classes were not disturbed. +// Instead new classes were added for IETF Poly1305. The back-end implementation +// shares code as expected, however. + +/// \file poly1305.h +/// \brief Classes for Poly1305 message authentication code +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details Crypto++ also supplies the IETF's version of Poly1305. It is a slightly different +/// algorithm than Bernstein's version. +/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329), RFC +/// 8439, ChaCha20 and Poly1305 for IETF Protocols and Andy Polyakov Poly1305 Revised +/// \since Poly1305 since Crypto++ 6.0, Poly1305TLS since Crypto++ 8.1 + +#ifndef CRYPTOPP_POLY1305_H +#define CRYPTOPP_POLY1305_H + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein Poly1305 ////////////////////////////// + +/// \brief Poly1305 message authentication code base class +/// \tparam T BlockCipherDocumentation derived class with 16-byte key and 16-byte blocksize +/// \details Poly1305_Base is the base class of Bernstein's Poly1305 algorithm. +/// \since Crypto++ 6.0 +template +class CRYPTOPP_NO_VTABLE Poly1305_Base : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 16>, public MessageAuthenticationCode +{ + CRYPTOPP_COMPILE_ASSERT(T::DEFAULT_KEYLENGTH == 16); + CRYPTOPP_COMPILE_ASSERT(T::BLOCKSIZE == 16); + +public: + static std::string StaticAlgorithmName() {return std::string("Poly1305(") + T::StaticAlgorithmName() + ")";} + + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE); + + virtual ~Poly1305_Base() {} + Poly1305_Base() : m_idx(0), m_used(true) {} + + void Resynchronize (const byte *iv, int ivLength=-1); + void GetNextIV (RandomNumberGenerator &rng, byte *iv); + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + void Restart(); + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return DIGESTSIZE;} + + std::string AlgorithmProvider() const; + +protected: + // TODO: No longer needed. Remove at next major version bump + void HashBlocks(const byte *input, size_t length, word32 padbit); + void HashFinal(byte *mac, size_t length); + + typename T::Encryption m_cipher; + + // Accumulated hash, clamped r-key, and encrypted nonce + FixedSizeAlignedSecBlock m_h; + FixedSizeAlignedSecBlock m_r; + FixedSizeAlignedSecBlock m_n; + + // Accumulated message bytes and index + FixedSizeAlignedSecBlock m_acc, m_nk; + size_t m_idx; + + // Track nonce reuse; assert in debug but continue + bool m_used; +}; + +/// \brief Poly1305 message authentication code +/// \tparam T class derived from BlockCipherDocumentation with 16-byte key and 16-byte blocksize +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details The key is 32 bytes and a concatenation key = {k,s}, where +/// k is the AES key and r is additional key that gets clamped. +/// The key is clamped internally so there is no need to perform the operation +/// before setting the key. +/// \details Each message must have a unique security context, which means either the key or nonce +/// must be changed after each message. It can be accomplished in one of two ways. First, you +/// can create a new Poly1305 object each time its needed. +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   Poly1305 poly1305(key, key.size(), nonce, nonce.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, reuse the key, and set a fresh nonce +/// for each message. The second and subsequent nonces can be generated using GetNextIV(). +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   // First message
+///   Poly1305 poly1305(key, key.size());
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   poly1305.GetNextIV(prng, nonce);
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \warning Each message must have a unique security context. The Poly1305 class does not +/// enforce a fresh key or nonce for each message. The source code will assert in debug +/// builds to alert of nonce reuse. No action is taken in release builds. +/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329) and Andy Polyakov Poly1305 Revised +/// \since Crypto++ 6.0 +template +class Poly1305 : public MessageAuthenticationCodeFinal > +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=Poly1305_Base::DEFAULT_KEYLENGTH); + + /// \brief Construct a Poly1305 + Poly1305() {} + + /// \brief Construct a Poly1305 + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array, in bytes + /// \param nonce a byte array used to key the cipher + /// \param nonceLength the size of the byte array, in bytes + /// \details The key is 32 bytes and a concatenation key = {k,s}, where + /// k is the AES key and r is additional key that gets clamped. + /// The key is clamped internally so there is no need to perform the operation + /// before setting the key. + /// \details Each message requires a unique security context. You can use GetNextIV() + /// and Resynchronize() to set a new nonce under a key for a message. + Poly1305(const byte *key, size_t keyLength=DEFAULT_KEYLENGTH, const byte *nonce=NULLPTR, size_t nonceLength=0) + {this->SetKey(key, keyLength, MakeParameters(Name::IV(), ConstByteArrayParameter(nonce, nonceLength)));} +}; + +////////////////////////////// IETF Poly1305 ////////////////////////////// + +/// \brief Poly1305-TLS message authentication code base class +/// \details Poly1305TLS_Base is the base class of the IETF's Poly1305 algorithm. +/// \since Crypto++ 8.1 +class Poly1305TLS_Base : public FixedKeyLength<32>, public MessageAuthenticationCode +{ +public: + static std::string StaticAlgorithmName() {return std::string("Poly1305TLS");} + CRYPTOPP_CONSTANT(DIGESTSIZE=16); + CRYPTOPP_CONSTANT(BLOCKSIZE=16); + + virtual ~Poly1305TLS_Base() {} + Poly1305TLS_Base() {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + void Restart(); + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return DIGESTSIZE;} + +protected: + // Accumulated hash, clamped r-key, and encrypted nonce + FixedSizeAlignedSecBlock m_h; + FixedSizeAlignedSecBlock m_r; + FixedSizeAlignedSecBlock m_n; + + // Accumulated message bytes and index + FixedSizeAlignedSecBlock m_acc; + size_t m_idx; +}; + +/// \brief Poly1305-TLS message authentication code +/// \details This is the IETF's variant of Bernstein's Poly1305 from RFC 8439. +/// IETF Poly1305 is called Poly1305TLS in the Crypto++ library. It is +/// _slightly_ different from the Bernstein implementation. Poly1305-TLS +/// can be used for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and +/// TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \details The key is 32 bytes and a concatenation key = {r,s}, where +/// r is additional key that gets clamped and s is the nonce. +/// The key is clamped internally so there is no need to perform the operation +/// before setting the key. +/// \details Each message must have a unique security context, which means the key +/// must be changed after each message. It can be accomplished in one of two ways. +/// First, you can create a new Poly1305 object with a new key each time its needed. +///
  SecByteBlock key(32);
+///   prng.GenerateBlock(key, key.size());
+///
+///   Poly1305TLS poly1305(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, and use a new key for each +/// message. The keys can be generated directly using a RandomNumberGenerator() +/// derived class. +///
  SecByteBlock key(32);
+///   prng.GenerateBlock(key, key.size());
+///
+///   // First message
+///   Poly1305TLS poly1305(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   prng.GenerateBlock(key, key.size());
+///   poly1305.SetKey(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \warning Each message must have a unique security context. The Poly1305-TLS class +/// does not enforce a fresh key or nonce for each message. +/// \since Crypto++ 8.1 +/// \sa MessageAuthenticationCode(), RFC +/// 8439, ChaCha20 and Poly1305 for IETF Protocols +DOCUMENTED_TYPEDEF(MessageAuthenticationCodeFinal, Poly1305TLS); + +NAMESPACE_END + +#endif // CRYPTOPP_POLY1305_H diff --git a/extension/third_party/cryptopp/polynomi.cpp b/extension/third_party/cryptopp/polynomi.cpp new file mode 100644 index 00000000..2305f80a --- /dev/null +++ b/extension/third_party/cryptopp/polynomi.cpp @@ -0,0 +1,577 @@ +// polynomi.cpp - originally written and placed in the public domain by Wei Dai + +// Part of the code for polynomial evaluation and interpolation +// originally came from Hal Finney's public domain secsplit.c. + +#include "pch.h" +#include "polynomi.h" +#include "secblock.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +template +void PolynomialOver::Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) +{ + m_coefficients.resize(parameter.m_coefficientCount); + for (unsigned int i=0; i +void PolynomialOver::FromStr(const char *str, const Ring &ring) +{ + std::istringstream in((char *)str); + bool positive = true; + CoefficientType coef; + unsigned int power; + + while (in) + { + std::ws(in); + if (in.peek() == 'x') + coef = ring.MultiplicativeIdentity(); + else + in >> coef; + + std::ws(in); + if (in.peek() == 'x') + { + in.get(); + std::ws(in); + if (in.peek() == '^') + { + in.get(); + in >> power; + } + else + power = 1; + } + else + power = 0; + + if (!positive) + coef = ring.Inverse(coef); + + SetCoefficient(power, coef, ring); + + std::ws(in); + switch (in.get()) + { + case '+': + positive = true; + break; + case '-': + positive = false; + break; + default: + return; // something's wrong with the input string + } + } +} + +template +unsigned int PolynomialOver::CoefficientCount(const Ring &ring) const +{ + unsigned count = m_coefficients.size(); + while (count && ring.Equal(m_coefficients[count-1], ring.Identity())) + count--; + const_cast &>(m_coefficients).resize(count); + return count; +} + +template +typename PolynomialOver::CoefficientType PolynomialOver::GetCoefficient(unsigned int i, const Ring &ring) const +{ + return (i < m_coefficients.size()) ? m_coefficients[i] : ring.Identity(); +} + +template +PolynomialOver& PolynomialOver::operator=(const PolynomialOver& t) +{ + if (this != &t) + { + m_coefficients.resize(t.m_coefficients.size()); + for (unsigned int i=0; i +PolynomialOver& PolynomialOver::Accumulate(const PolynomialOver& t, const Ring &ring) +{ + unsigned int count = t.CoefficientCount(ring); + + if (count > CoefficientCount(ring)) + m_coefficients.resize(count, ring.Identity()); + + for (unsigned int i=0; i +PolynomialOver& PolynomialOver::Reduce(const PolynomialOver& t, const Ring &ring) +{ + unsigned int count = t.CoefficientCount(ring); + + if (count > CoefficientCount(ring)) + m_coefficients.resize(count, ring.Identity()); + + for (unsigned int i=0; i +typename PolynomialOver::CoefficientType PolynomialOver::EvaluateAt(const CoefficientType &x, const Ring &ring) const +{ + int degree = Degree(ring); + + if (degree < 0) + return ring.Identity(); + + CoefficientType result = m_coefficients[degree]; + for (int j=degree-1; j>=0; j--) + { + result = ring.Multiply(result, x); + ring.Accumulate(result, m_coefficients[j]); + } + return result; +} + +template +PolynomialOver& PolynomialOver::ShiftLeft(unsigned int n, const Ring &ring) +{ + unsigned int i = CoefficientCount(ring) + n; + m_coefficients.resize(i, ring.Identity()); + while (i > n) + { + i--; + m_coefficients[i] = m_coefficients[i-n]; + } + while (i) + { + i--; + m_coefficients[i] = ring.Identity(); + } + return *this; +} + +template +PolynomialOver& PolynomialOver::ShiftRight(unsigned int n, const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + if (count > n) + { + for (unsigned int i=0; i +void PolynomialOver::SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring) +{ + if (i >= m_coefficients.size()) + m_coefficients.resize(i+1, ring.Identity()); + m_coefficients[i] = value; +} + +template +void PolynomialOver::Negate(const Ring &ring) +{ + unsigned int count = CoefficientCount(ring); + for (unsigned int i=0; i +void PolynomialOver::swap(PolynomialOver &t) +{ + m_coefficients.swap(t.m_coefficients); +} + +template +bool PolynomialOver::Equals(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + + if (count != t.CoefficientCount(ring)) + return false; + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::Plus(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver result(ring, count); + + for (i=0; i result(ring, tCount); + + for (i=0; i +PolynomialOver PolynomialOver::Minus(const PolynomialOver& t, const Ring &ring) const +{ + unsigned int i; + unsigned int count = CoefficientCount(ring); + unsigned int tCount = t.CoefficientCount(ring); + + if (count > tCount) + { + PolynomialOver result(ring, count); + + for (i=0; i result(ring, tCount); + + for (i=0; i +PolynomialOver PolynomialOver::Inverse(const Ring &ring) const +{ + unsigned int count = CoefficientCount(ring); + PolynomialOver result(ring, count); + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::Times(const PolynomialOver& t, const Ring &ring) const +{ + if (IsZero(ring) || t.IsZero(ring)) + return PolynomialOver(); + + unsigned int count1 = CoefficientCount(ring), count2 = t.CoefficientCount(ring); + PolynomialOver result(ring, count1 + count2 - 1); + + for (unsigned int i=0; i +PolynomialOver PolynomialOver::DividedBy(const PolynomialOver& t, const Ring &ring) const +{ + PolynomialOver remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return quotient; +} + +template +PolynomialOver PolynomialOver::Modulo(const PolynomialOver& t, const Ring &ring) const +{ + PolynomialOver remainder, quotient; + Divide(remainder, quotient, *this, t, ring); + return remainder; +} + +template +PolynomialOver PolynomialOver::MultiplicativeInverse(const Ring &ring) const +{ + return Degree(ring)==0 ? ring.MultiplicativeInverse(m_coefficients[0]) : ring.Identity(); +} + +template +bool PolynomialOver::IsUnit(const Ring &ring) const +{ + return Degree(ring)==0 && ring.IsUnit(m_coefficients[0]); +} + +template +std::istream& PolynomialOver::Input(std::istream &in, const Ring &ring) +{ + char c; + unsigned int length = 0; + SecBlock str(length + 16); + bool paren = false; + + std::ws(in); + + if (in.peek() == '(') + { + paren = true; + in.get(); + } + + do + { + in.read(&c, 1); + str[length++] = c; + if (length >= str.size()) + str.Grow(length + 16); + } + // if we started with a left paren, then read until we find a right paren, + // otherwise read until the end of the line + while (in && ((paren && c != ')') || (!paren && c != '\n'))); + + str[length-1] = '\0'; + *this = PolynomialOver(str, ring); + + return in; +} + +template +std::ostream& PolynomialOver::Output(std::ostream &out, const Ring &ring) const +{ + unsigned int i = CoefficientCount(ring); + if (i) + { + bool firstTerm = true; + + while (i--) + { + if (m_coefficients[i] != ring.Identity()) + { + if (firstTerm) + { + firstTerm = false; + if (!i || !ring.Equal(m_coefficients[i], ring.MultiplicativeIdentity())) + out << m_coefficients[i]; + } + else + { + CoefficientType inverse = ring.Inverse(m_coefficients[i]); + std::ostringstream pstr, nstr; + + pstr << m_coefficients[i]; + nstr << inverse; + + if (pstr.str().size() <= nstr.str().size()) + { + out << " + "; + if (!i || !ring.Equal(m_coefficients[i], ring.MultiplicativeIdentity())) + out << m_coefficients[i]; + } + else + { + out << " - "; + if (!i || !ring.Equal(inverse, ring.MultiplicativeIdentity())) + out << inverse; + } + } + + switch (i) + { + case 0: + break; + case 1: + out << "x"; + break; + default: + out << "x^" << i; + } + } + } + } + else + { + out << ring.Identity(); + } + return out; +} + +template +void PolynomialOver::Divide(PolynomialOver &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &d, const Ring &ring) +{ + unsigned int i = a.CoefficientCount(ring); + const int dDegree = d.Degree(ring); + + if (dDegree < 0) + throw DivideByZero(); + + r = a; + q.m_coefficients.resize(STDMAX(0, int(i - dDegree))); + + while (i > (unsigned int)dDegree) + { + --i; + q.m_coefficients[i-dDegree] = ring.Divide(r.m_coefficients[i], d.m_coefficients[dDegree]); + for (int j=0; j<=dDegree; j++) + ring.Reduce(r.m_coefficients[i-dDegree+j], ring.Multiply(q.m_coefficients[i-dDegree], d.m_coefficients[j])); + } + + r.CoefficientCount(ring); // resize r.m_coefficients +} + +// ******************************************************** + +// helper function for Interpolate() and InterpolateAt() +template +void RingOfPolynomialsOver::CalculateAlpha(std::vector &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + for (unsigned int j=0; j=k; --j) + { + m_ring.Reduce(alpha[j], alpha[j-1]); + + CoefficientType d = m_ring.Subtract(x[j], x[j-k]); + if (!m_ring.IsUnit(d)) + throw InterpolationFailed(); + alpha[j] = m_ring.Divide(alpha[j], d); + } + } +} + +template +typename RingOfPolynomialsOver::Element RingOfPolynomialsOver::Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + CRYPTOPP_ASSERT(n > 0); + + std::vector alpha(n); + CalculateAlpha(alpha, x, y, n); + + std::vector coefficients((size_t)n, m_ring.Identity()); + coefficients[0] = alpha[n-1]; + + for (int j=n-2; j>=0; --j) + { + for (unsigned int i=n-j-1; i>0; i--) + coefficients[i] = m_ring.Subtract(coefficients[i-1], m_ring.Multiply(coefficients[i], x[j])); + + coefficients[0] = m_ring.Subtract(alpha[j], m_ring.Multiply(coefficients[0], x[j])); + } + + return PolynomialOver(coefficients.begin(), coefficients.end()); +} + +template +typename RingOfPolynomialsOver::CoefficientType RingOfPolynomialsOver::InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const +{ + CRYPTOPP_ASSERT(n > 0); + + std::vector alpha(n); + CalculateAlpha(alpha, x, y, n); + + CoefficientType result = alpha[n-1]; + for (int j=n-2; j>=0; --j) + { + result = m_ring.Multiply(result, m_ring.Subtract(position, x[j])); + m_ring.Accumulate(result, alpha[j]); + } + return result; +} + +template +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n) +{ + for (unsigned int i=0; i +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n) +{ + CRYPTOPP_ASSERT(n > 0); + + std::vector a(2*n-1); + unsigned int i; + + for (i=0; i1; i--) + a[i-1] = ring.Multiply(a[2*i], a[2*i-1]); + + a[0] = ring.MultiplicativeIdentity(); + + for (i=0; i +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n) +{ + Element result = ring.Identity(); + for (unsigned int i=0; i +const PolynomialOverFixedRing &PolynomialOverFixedRing::Zero() +{ + return Singleton().Ref(); +} + +template +const PolynomialOverFixedRing &PolynomialOverFixedRing::One() +{ + return Singleton().Ref(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/polynomi.h b/extension/third_party/cryptopp/polynomi.h new file mode 100644 index 00000000..025ee67b --- /dev/null +++ b/extension/third_party/cryptopp/polynomi.h @@ -0,0 +1,463 @@ +// polynomi.h - originally written and placed in the public domain by Wei Dai + +/// \file polynomi.h +/// \brief Classes for polynomial basis and operations + +#ifndef CRYPTOPP_POLYNOMI_H +#define CRYPTOPP_POLYNOMI_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// represents single-variable polynomials over arbitrary rings +/*! \nosubgrouping */ +template class PolynomialOver +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialOver: division by zero") {} + }; + + /// specify the distribution for randomization functions + class RandomizationParameter + { + public: + RandomizationParameter(unsigned int coefficientCount, const typename T::RandomizationParameter &coefficientParameter ) + : m_coefficientCount(coefficientCount), m_coefficientParameter(coefficientParameter) {} + + private: + unsigned int m_coefficientCount; + typename T::RandomizationParameter m_coefficientParameter; + friend class PolynomialOver; + }; + + typedef T Ring; + typedef typename T::Element CoefficientType; + //@} + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOver() {} + + /// + PolynomialOver(const Ring &ring, unsigned int count) + : m_coefficients((size_t)count, ring.Identity()) {} + + /// copy constructor + PolynomialOver(const PolynomialOver &t) + : m_coefficients(t.m_coefficients.size()) {*this = t;} + + /// construct constant polynomial + PolynomialOver(const CoefficientType &element) + : m_coefficients(1, element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOver(Iterator begin, Iterator end) + : m_coefficients(begin, end) {} + + /// convert from string + PolynomialOver(const char *str, const Ring &ring) {FromStr(str, ring);} + + /// convert from big-endian byte array + PolynomialOver(const byte *encodedPolynomialOver, unsigned int byteCount); + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOver(const byte *BEREncodedPolynomialOver); + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOver(BufferedTransformation &bt); + + /// create a random PolynomialOver + PolynomialOver(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) + {Randomize(rng, parameter, ring);} + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree(const Ring &ring) const {return int(CoefficientCount(ring))-1;} + /// + unsigned int CoefficientCount(const Ring &ring) const; + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i, const Ring &ring) const; + //@} + + /// \name MANIPULATORS + //@{ + /// + PolynomialOver& operator=(const PolynomialOver& t); + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring); + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring); + + /// + void Negate(const Ring &ring); + + /// + void swap(PolynomialOver &t); + //@} + + + /// \name BASIC ARITHMETIC ON POLYNOMIALS + //@{ + bool Equals(const PolynomialOver &t, const Ring &ring) const; + bool IsZero(const Ring &ring) const {return CoefficientCount(ring)==0;} + + PolynomialOver Plus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Minus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Inverse(const Ring &ring) const; + + PolynomialOver Times(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver DividedBy(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Modulo(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver MultiplicativeInverse(const Ring &ring) const; + bool IsUnit(const Ring &ring) const; + + PolynomialOver& Accumulate(const PolynomialOver& t, const Ring &ring); + PolynomialOver& Reduce(const PolynomialOver& t, const Ring &ring); + + /// + PolynomialOver Doubled(const Ring &ring) const {return Plus(*this, ring);} + /// + PolynomialOver Squared(const Ring &ring) const {return Times(*this, ring);} + + CoefficientType EvaluateAt(const CoefficientType &x, const Ring &ring) const; + + PolynomialOver& ShiftLeft(unsigned int n, const Ring &ring); + PolynomialOver& ShiftRight(unsigned int n, const Ring &ring); + + /// calculate r and q such that (a == d*q + r) && (0 <= degree of r < degree of d) + static void Divide(PolynomialOver &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &d, const Ring &ring); + //@} + + /// \name INPUT/OUTPUT + //@{ + std::istream& Input(std::istream &in, const Ring &ring); + std::ostream& Output(std::ostream &out, const Ring &ring) const; + //@} + +private: + void FromStr(const char *str, const Ring &ring); + + std::vector m_coefficients; +}; + +/// Polynomials over a fixed ring +/*! Having a fixed ring allows overloaded operators */ +template class PolynomialOverFixedRing : private PolynomialOver +{ + typedef PolynomialOver B; + typedef PolynomialOverFixedRing ThisType; + +public: + typedef T Ring; + typedef typename T::Element CoefficientType; + typedef typename B::DivideByZero DivideByZero; + typedef typename B::RandomizationParameter RandomizationParameter; + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOverFixedRing(unsigned int count = 0) : B(ms_fixedRing, count) {} + + /// copy constructor + PolynomialOverFixedRing(const ThisType &t) : B(t) {} + + explicit PolynomialOverFixedRing(const B &t) : B(t) {} + + /// construct constant polynomial + PolynomialOverFixedRing(const CoefficientType &element) : B(element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOverFixedRing(Iterator first, Iterator last) + : B(first, last) {} + + /// convert from string + explicit PolynomialOverFixedRing(const char *str) : B(str, ms_fixedRing) {} + + /// convert from big-endian byte array + PolynomialOverFixedRing(const byte *encodedPoly, unsigned int byteCount) : B(encodedPoly, byteCount) {} + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOverFixedRing(const byte *BEREncodedPoly) : B(BEREncodedPoly) {} + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOverFixedRing(BufferedTransformation &bt) : B(bt) {} + + /// create a random PolynomialOverFixedRing + PolynomialOverFixedRing(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) : B(rng, parameter, ms_fixedRing) {} + + static const ThisType &Zero(); + static const ThisType &One(); + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree() const {return B::Degree(ms_fixedRing);} + /// degree + 1 + unsigned int CoefficientCount() const {return B::CoefficientCount(ms_fixedRing);} + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + /// return coefficient for x^i + CoefficientType operator[](unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + //@} + + /// \name MANIPULATORS + //@{ + /// + ThisType& operator=(const ThisType& t) {B::operator=(t); return *this;} + /// + ThisType& operator+=(const ThisType& t) {Accumulate(t, ms_fixedRing); return *this;} + /// + ThisType& operator-=(const ThisType& t) {Reduce(t, ms_fixedRing); return *this;} + /// + ThisType& operator*=(const ThisType& t) {return *this = *this*t;} + /// + ThisType& operator/=(const ThisType& t) {return *this = *this/t;} + /// + ThisType& operator%=(const ThisType& t) {return *this = *this%t;} + + /// + ThisType& operator<<=(unsigned int n) {ShiftLeft(n, ms_fixedRing); return *this;} + /// + ThisType& operator>>=(unsigned int n) {ShiftRight(n, ms_fixedRing); return *this;} + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value) {B::SetCoefficient(i, value, ms_fixedRing);} + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) {B::Randomize(rng, parameter, ms_fixedRing);} + + /// + void Negate() {B::Negate(ms_fixedRing);} + + void swap(ThisType &t) {B::swap(t);} + //@} + + /// \name UNARY OPERATORS + //@{ + /// + bool operator!() const {return CoefficientCount()==0;} + /// + ThisType operator+() const {return *this;} + /// + ThisType operator-() const {return ThisType(Inverse(ms_fixedRing));} + //@} + + /// \name BINARY OPERATORS + //@{ + /// + friend ThisType operator>>(ThisType a, unsigned int n) {return ThisType(a>>=n);} + /// + friend ThisType operator<<(ThisType a, unsigned int n) {return ThisType(a<<=n);} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// + ThisType MultiplicativeInverse() const {return ThisType(B::MultiplicativeInverse(ms_fixedRing));} + /// + bool IsUnit() const {return B::IsUnit(ms_fixedRing);} + + /// + ThisType Doubled() const {return ThisType(B::Doubled(ms_fixedRing));} + /// + ThisType Squared() const {return ThisType(B::Squared(ms_fixedRing));} + + CoefficientType EvaluateAt(const CoefficientType &x) const {return B::EvaluateAt(x, ms_fixedRing);} + + /// calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + static void Divide(ThisType &r, ThisType &q, const ThisType &a, const ThisType &d) + {B::Divide(r, q, a, d, ms_fixedRing);} + //@} + + /// \name INPUT/OUTPUT + //@{ + /// + friend std::istream& operator>>(std::istream& in, ThisType &a) + {return a.Input(in, ms_fixedRing);} + /// + friend std::ostream& operator<<(std::ostream& out, const ThisType &a) + {return a.Output(out, ms_fixedRing);} + //@} + +private: + struct NewOnePolynomial + { + ThisType * operator()() const + { + return new ThisType(ms_fixedRing.MultiplicativeIdentity()); + } + }; + + static const Ring ms_fixedRing; +}; + +/// Ring of polynomials over another ring +template class RingOfPolynomialsOver : public AbstractEuclideanDomain > +{ +public: + typedef T CoefficientRing; + typedef PolynomialOver Element; + typedef typename Element::CoefficientType CoefficientType; + typedef typename Element::RandomizationParameter RandomizationParameter; + + RingOfPolynomialsOver(const CoefficientRing &ring) : m_ring(ring) {} + + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) + {return Element(rng, parameter, m_ring);} + + bool Equal(const Element &a, const Element &b) const + {return a.Equals(b, m_ring);} + + const Element& Identity() const + {return this->result = m_ring.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return this->result = a.Plus(b, m_ring);} + + Element& Accumulate(Element &a, const Element &b) const + {a.Accumulate(b, m_ring); return a;} + + const Element& Inverse(const Element &a) const + {return this->result = a.Inverse(m_ring);} + + const Element& Subtract(const Element &a, const Element &b) const + {return this->result = a.Minus(b, m_ring);} + + Element& Reduce(Element &a, const Element &b) const + {return a.Reduce(b, m_ring);} + + const Element& Double(const Element &a) const + {return this->result = a.Doubled(m_ring);} + + const Element& MultiplicativeIdentity() const + {return this->result = m_ring.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return this->result = a.Times(b, m_ring);} + + const Element& Square(const Element &a) const + {return this->result = a.Squared(m_ring);} + + bool IsUnit(const Element &a) const + {return a.IsUnit(m_ring);} + + const Element& MultiplicativeInverse(const Element &a) const + {return this->result = a.MultiplicativeInverse(m_ring);} + + const Element& Divide(const Element &a, const Element &b) const + {return this->result = a.DividedBy(b, m_ring);} + + const Element& Mod(const Element &a, const Element &b) const + {return this->result = a.Modulo(b, m_ring);} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d, m_ring);} + + class InterpolationFailed : public Exception + { + public: + InterpolationFailed() : Exception(OTHER_ERROR, "RingOfPolynomialsOver: interpolation failed") {} + }; + + Element Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + // a faster version of Interpolate(x, y, n).EvaluateAt(position) + CoefficientType InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; +/* + void PrepareBulkInterpolation(CoefficientType *w, const CoefficientType x[], unsigned int n) const; + void PrepareBulkInterpolationAt(CoefficientType *v, const CoefficientType &position, const CoefficientType x[], const CoefficientType w[], unsigned int n) const; + CoefficientType BulkInterpolateAt(const CoefficientType y[], const CoefficientType v[], unsigned int n) const; +*/ +protected: + void CalculateAlpha(std::vector &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + CoefficientRing m_ring; +}; + +template +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n); +template +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n); +template +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n); + +/// +template +inline bool operator==(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Equals(b, a.ms_fixedRing);} +/// +template +inline bool operator!=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return !(a==b);} + +/// +template +inline bool operator> (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() > b.Degree();} +/// +template +inline bool operator>=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() >= b.Degree();} +/// +template +inline bool operator< (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() < b.Degree();} +/// +template +inline bool operator<=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() <= b.Degree();} + +/// +template +inline CryptoPP::PolynomialOverFixedRing operator+(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Plus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator-(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Minus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator*(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Times(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator/(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.DividedBy(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator%(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Modulo(b, a.ms_fixedRing));} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template inline void swap(CryptoPP::PolynomialOver &a, CryptoPP::PolynomialOver &b) +{ + a.swap(b); +} +template inline void swap(CryptoPP::PolynomialOverFixedRing &a, CryptoPP::PolynomialOverFixedRing &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ppc_power7.cpp b/extension/third_party/cryptopp/ppc_power7.cpp new file mode 100644 index 00000000..84a7275a --- /dev/null +++ b/extension/third_party/cryptopp/ppc_power7.cpp @@ -0,0 +1,93 @@ +// ppc_power7.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics and built-ins to gain access to +// Power7 instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate +// instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#if defined(__ALTIVEC__) || defined(_ARCH_PWR7) +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char PPC_POWER7_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ************************* Feature Probes ************************* // + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool CPU_ProbePower7() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif defined(CRYPTOPP_POWER7_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = false; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // POWER7 added unaligned loads and store operations + byte b1[19] = {255, 255, 255, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, b2[17]; + + // See comments in ppc_simd.h for some of these defines. + #if defined(_AIX) && defined(_ARCH_PWR7) && ((__xlC__ & 0xff00) == 0x0c00) + vec_xstw4(vec_xlw4(0, (unsigned int*)(b1+3)), 0, (unsigned int*)(b2+1)); + result = (0 == std::memcmp(b1+3, b2+1, 16)); + #elif defined(_ARCH_PWR7) && defined(__VSX__) + vec_xst(vec_xl(0, (unsigned int*)(b1+3)), 0, (unsigned int*)(b2+1)); + result = (0 == std::memcmp(b1+3, b2+1, 16)); + #else + result = false; + #endif + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // _ARCH_PWR7 +} + +#endif // PPC32 or PPC64 + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ppc_power8.cpp b/extension/third_party/cryptopp/ppc_power8.cpp new file mode 100644 index 00000000..7e287ee5 --- /dev/null +++ b/extension/third_party/cryptopp/ppc_power8.cpp @@ -0,0 +1,246 @@ +// ppc_power8.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics and built-ins to gain access to +// Power8 instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate +// instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#if defined(_ARCH_PWR8) || defined(__CRYPTO__) +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char PPC_POWER8_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ************************* Feature Probes ************************* // + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +bool CPU_ProbePower8() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (_ARCH_PWR8) && defined(CRYPTOPP_POWER8_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // POWER8 added 64-bit SIMD operations + const word64 x = W64LIT(0xffffffffffffffff); + word64 w1[2] = {x, x}, w2[2] = {4, 6}, w3[2]; + + // Specifically call the VSX loads and stores with 64-bit types + #if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) || defined(__clang__) + const uint64x2_p v1 = vec_xl(0, (unsigned long long*)w1); + const uint64x2_p v2 = vec_xl(0, (unsigned long long*)w2); + const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add + vec_xst(v3, 0, (unsigned long long*)w3); + #else + const uint64x2_p v1 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w1); + const uint64x2_p v2 = (uint64x2_p)vec_vsx_ld(0, (const byte*)w2); + const uint64x2_p v3 = vec_add(v1, v2); // 64-bit add + vec_vsx_st((uint8x16_p)v3, 0, (byte*)w3); + #endif + + // Relies on integer wrap + result = (w3[0] == 3 && w3[1] == 5); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // _ARCH_PWR8 +} + +bool CPU_ProbeAES() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_AES_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + byte key[16] = {0xA0, 0xFA, 0xFE, 0x17, 0x88, 0x54, 0x2c, 0xb1, + 0x23, 0xa3, 0x39, 0x39, 0x2a, 0x6c, 0x76, 0x05}; + byte state[16] = {0x19, 0x3d, 0xe3, 0xb3, 0xa0, 0xf4, 0xe2, 0x2b, + 0x9a, 0xc6, 0x8d, 0x2a, 0xe9, 0xf8, 0x48, 0x08}; + byte r[16] = {255}, z[16] = {}; + + uint8x16_p k = (uint8x16_p)VecLoad(0, key); + uint8x16_p s = (uint8x16_p)VecLoad(0, state); + s = VecEncrypt(s, k); + s = VecEncryptLast(s, k); + s = VecDecrypt(s, k); + s = VecDecryptLast(s, k); + VecStore(s, r); + + result = (0 != std::memcmp(r, z, 16)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // __CRYPTO__ +} + +bool CPU_ProbeSHA256() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = false; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + byte r[16], z[16] = {0}; + uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + x = VecSHA256<0,0>(x); + x = VecSHA256<0,0xf>(x); + x = VecSHA256<1,0>(x); + x = VecSHA256<1,0xf>(x); + VecStore(x, r); + + result = (0 == std::memcmp(r, z, 16)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ALTIVEC_AVAILABLE +} + +bool CPU_ProbeSHA512() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (__CRYPTO__) && defined(CRYPTOPP_POWER8_SHA_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = false; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + byte r[16], z[16] = {0}; + uint8x16_p x = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + x = VecSHA512<0,0>(x); + x = VecSHA512<0,0xf>(x); + x = VecSHA512<1,0>(x); + x = VecSHA512<1,0xf>(x); + VecStore(x, r); + + result = (0 == std::memcmp(r, z, 16)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_POWER8_AVAILABLE +} + +#endif // PPC32 or PPC64 + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ppc_power9.cpp b/extension/third_party/cryptopp/ppc_power9.cpp new file mode 100644 index 00000000..b7288f7c --- /dev/null +++ b/extension/third_party/cryptopp/ppc_power9.cpp @@ -0,0 +1,136 @@ +// ppc_power9.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics and built-ins to gain access to +// Power9 instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate +// instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#if defined(_ARCH_PWR9) +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char PPC_POWER9_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ************************* Feature Probes ************************* // + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +bool CPU_ProbePower9() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif defined(CRYPTOPP_POWER9_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721954 + volatile int result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // This is "darn r3, 0" from POWER9. We cannot use __builtin_darn + // and friends because Clang and IBM XL C/C++ does not offer them. +#if CRYPTOPP_BIG_ENDIAN + __asm__ __volatile__ (".byte 0x7c, 0x60, 0x05, 0xe6 \n" : : : "r3"); +#else + __asm__ __volatile__ (".byte 0xe6, 0x05, 0x60, 0x7c \n" : : : "r3"); +#endif + result = true; + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // _ARCH_PWR9 +} + +// The DARN probe is not guarded with a preprocessor macro at the moment. We +// don't use CRYPTOPP_POWER9_AVAILABLE because old compilers, like GCC 4.8 on +// CentOS 7, will report NO even though we can produce the random numbers. +// Other Power9 implementations which use builtins will use the preprocessor +// macro guard. This strategy also gets into a situation where Power9 is not +// available but DARN is. +bool CPU_ProbeDARN() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#else +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721954 + volatile int result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + // This is "darn r3, 0" from POWER9. We cannot use __builtin_darn + // and friends because Clang and IBM XL C/C++ does not offer them. +#if CRYPTOPP_BIG_ENDIAN + __asm__ __volatile__ (".byte 0x7c, 0x60, 0x05, 0xe6 \n" : : : "r3"); +#else + __asm__ __volatile__ (".byte 0xe6, 0x05, 0x60, 0x7c \n" : : : "r3"); +#endif + result = true; + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#endif // DARN +} + +#endif // PPC32 or PPC64 + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ppc_simd.cpp b/extension/third_party/cryptopp/ppc_simd.cpp new file mode 100644 index 00000000..081d0515 --- /dev/null +++ b/extension/third_party/cryptopp/ppc_simd.cpp @@ -0,0 +1,96 @@ +// ppc_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to AltiVec, +// Power8 and in-core crypto instructions. A separate source file +// is needed because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "stdcpp.h" + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char PPC_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool CPU_ProbeAltivec() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (_ARCH_PWR3) && (CRYPTOPP_ALTIVEC_AVAILABLE) +# if defined(CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY) + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile int result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + CRYPTOPP_ALIGN_DATA(16) + const byte b1[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + CRYPTOPP_ALIGN_DATA(16) + const byte b2[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + CRYPTOPP_ALIGN_DATA(16) byte b3[16]; + + // Specifically call the Altivec loads and stores + const uint8x16_p v1 = (uint8x16_p)vec_ld(0, (byte*)b1); + const uint8x16_p v2 = (uint8x16_p)vec_ld(0, (byte*)b2); + const uint8x16_p v3 = (uint8x16_p)VecXor(v1, v2); + vec_st(v3, 0, b3); + + result = (0 == std::memcmp(b2, b3, 16)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ALTIVEC_AVAILABLE +} + +# endif // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ppc_simd.h b/extension/third_party/cryptopp/ppc_simd.h new file mode 100644 index 00000000..65008066 --- /dev/null +++ b/extension/third_party/cryptopp/ppc_simd.h @@ -0,0 +1,2764 @@ +// ppc_simd.h - written and placed in public domain by Jeffrey Walton + +/// \file ppc_simd.h +/// \brief Support functions for PowerPC and vector operations +/// \details This header provides an agnostic interface into Clang, GCC +/// and IBM XL C/C++ compilers modulo their different built-in functions +/// for accessing vector intructions. +/// \details The abstractions are necesssary to support back to GCC 4.8 and +/// XLC 11 and 12. GCC 4.8 and 4.9 are still popular, and they are the +/// default compiler for GCC112, GCC119 and others on the compile farm. +/// Older IBM XL C/C++ compilers also have the need due to lack of +/// vec_xl and vec_xst support on some platforms. Modern +/// compilers provide best support and don't need many of the hacks +/// below. +/// \details The library is tested with the following PowerPC machines and +/// compilers. GCC110, GCC111, GCC112, GCC119 and GCC135 are provided by +/// the GCC Compile Farm +/// - PowerMac G5, OSX 10.5, POWER4, Apple GCC 4.0 +/// - PowerMac G5, OSX 10.5, POWER4, Macports GCC 5.0 +/// - GCC110, Linux, POWER7, GCC 4.8.5 +/// - GCC110, Linux, POWER7, XLC 12.01 +/// - GCC111, AIX, POWER7, GCC 4.8.1 +/// - GCC111, AIX, POWER7, XLC 12.01 +/// - GCC112, Linux, POWER8, GCC 4.8.5 +/// - GCC112, Linux, POWER8, XLC 13.01 +/// - GCC112, Linux, POWER8, Clang 7.0 +/// - GCC119, AIX, POWER8, GCC 7.2.0 +/// - GCC119, AIX, POWER8, XLC 13.01 +/// - GCC135, Linux, POWER9, GCC 7.0 +/// \details 12 machines are used for testing because the three compilers form +/// five or six profiles. The profiles are listed below. +/// - GCC (Linux GCC, Macports GCC, etc. Consistent across machines) +/// - XLC 13.0 and earlier (all IBM components) +/// - XLC 13.1 and later on Linux (LLVM front-end, no compatibility macros) +/// - XLC 13.1 and later on Linux (LLVM front-end, -qxlcompatmacros option) +/// - early LLVM Clang (traditional Clang compiler) +/// - late LLVM Clang (traditional Clang compiler) +/// \details The LLVM front-end makes it tricky to write portable code because +/// LLVM pretends to be other compilers but cannot consume other compiler's +/// builtins. When using XLC with -qxlcompatmacros the compiler pretends to +/// be GCC, Clang and XLC all at once but it can only consume it's variety +/// of builtins. +/// \details At Crypto++ 8.0 the various Vector{FuncName} were +/// renamed to Vec{FuncName}. For example, VectorAnd was +/// changed to VecAnd. The name change helped consolidate two +/// slightly different implementations. +/// \details At Crypto++ 8.3 the library added select 64-bit functions for +/// 32-bit Altivec. For example, VecAdd64 and VecSub64 +/// take 32-bit vectors and adds or subtracts them as if there were vectors +/// with two 64-bit elements. The functions dramtically improve performance +/// for some algorithms on some platforms, like SIMON128 and SPECK128 on +/// Power6 and earlier. For example, SPECK128 improved from 70 cpb to +/// 10 cpb on an old PowerMac. Use the functions like shown below. +///
+///    \#if defined(_ARCH_PWR8)
+///    \#  define speck128_t uint64x2_p
+///    \#else
+///    \#  define speck128_t uint32x4_p
+///    \#endif
+///
+///    speck128_t rk, x1, x2, y1, y2;
+///    rk = (speck128_t)VecLoadAligned(ptr);
+///    x1 = VecRotateRight64<8>(x1);
+///    x1 = VecAdd64(x1, y1);
+///    ...
+/// \since Crypto++ 6.0, LLVM Clang compiler support since Crypto++ 8.0 + +// Use __ALTIVEC__, _ARCH_PWR7, __VSX__, and _ARCH_PWR8 when detecting +// actual availaibility of the feature for the source file being compiled. +// The preprocessor macros depend on compiler options like -maltivec; and +// not compiler versions. + +// For GCC see https://gcc.gnu.org/onlinedocs/gcc/Basic-PowerPC-Built-in-Functions.html +// For XLC see the Compiler Reference manual. For Clang you have to experiment. +// Clang does not document the compiler options, does not reject options it does +// not understand, and pretends to be other compilers even though it cannot +// process the builtins and intrinsics. Clang will waste hours of your time. + +// DO NOT USE this pattern in VecLoad and VecStore. We have to use the +// code paths guarded by preprocessor macros because XLC 12 generates +// bad code in some places. To verify the bad code generation test on +// GCC111 with XLC 12.01 installed. XLC 13.01 on GCC112 and GCC119 are OK. +// +// inline uint32x4_p VecLoad(const byte src[16]) +// { +// #if defined(__VSX__) || defined(_ARCH_PWR8) +// return (uint32x4_p) *(uint8x16_p*)((byte*)src); +// #else +// return VecLoad_ALTIVEC(src); +// #endif +// } + +// We should be able to perform the load using inline asm on Power7 with +// VSX or Power8. The inline asm will avoid C undefined behavior due to +// casting from byte* to word32*. We are safe because our byte* are +// 16-byte aligned for Altivec. Below is the big endian load. Little +// endian would need to follow with xxpermdi for the reversal. +// +// __asm__ ("lxvw4x %x0, %1, %2" : "=wa"(v) : "r"(0), "r"(src) : ); + +// GCC and XLC use integer math for the address (D-form or byte-offset +// in the ISA manual). LLVM uses pointer math for the address (DS-form +// or indexed in the ISA manual). To keep them consistent we calculate +// the address from the offset and pass to a load or store function +// using a 0 offset. + +#ifndef CRYPTOPP_PPC_CRYPTO_H +#define CRYPTOPP_PPC_CRYPTO_H + +#include "config.h" +#include "misc.h" + +#if defined(__ALTIVEC__) +# include +# undef vector +# undef pixel +# undef bool +#endif + +// XL C++ on AIX does not define VSX and does not +// provide an option to set it. We have to set it +// for the code below. This define must stay in +// sync with the define in test_ppc_power7.cxx. +#ifndef CRYPTOPP_DISABLE_POWER7 +# if defined(_AIX) && defined(_ARCH_PWR7) && defined(__xlC__) +# define __VSX__ 1 +# endif +#endif + +// XL C++ on AIX does not define CRYPTO and does not +// provide an option to set it. We have to set it +// for the code below. This define must stay in +// sync with the define in test_ppc_power8.cxx +#ifndef CRYPTOPP_DISABLE_POWER8 +# if defined(_AIX) && defined(_ARCH_PWR8) && defined(__xlC__) +# define __CRYPTO__ 1 +# endif +#endif + +/// \brief Cast array to vector pointer +/// \details CONST_V8_CAST casts a const array to a vector +/// pointer for a byte array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V8_CAST(x) ((unsigned char*)(x)) +/// \brief Cast array to vector pointer +/// \details CONST_V32_CAST casts a const array to a vector +/// pointer for a word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V32_CAST(x) ((unsigned int*)(x)) +/// \brief Cast array to vector pointer +/// \details CONST_V64_CAST casts a const array to a vector +/// pointer for a double word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V64_CAST(x) ((unsigned long long*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V8_CAST casts an array to a vector +/// pointer for a byte array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V8_CAST(x) ((unsigned char*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V32_CAST casts an array to a vector +/// pointer for a word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V32_CAST(x) ((unsigned int*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V64_CAST casts an array to a vector +/// pointer for a double word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V64_CAST(x) ((unsigned long long*)(x)) + +// VecLoad_ALTIVEC and VecStore_ALTIVEC are +// too noisy on modern compilers +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(__ALTIVEC__) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Vector of 8-bit elements +/// \par Wraps +/// __vector unsigned char +/// \since Crypto++ 6.0 +typedef __vector unsigned char uint8x16_p; +/// \brief Vector of 16-bit elements +/// \par Wraps +/// __vector unsigned short +/// \since Crypto++ 6.0 +typedef __vector unsigned short uint16x8_p; +/// \brief Vector of 32-bit elements +/// \par Wraps +/// __vector unsigned int +/// \since Crypto++ 6.0 +typedef __vector unsigned int uint32x4_p; + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Vector of 64-bit elements +/// \details uint64x2_p is available on POWER7 with VSX and above. Most +/// supporting functions, like 64-bit vec_add (vaddudm) +/// and vec_sub (vsubudm), did not arrive until POWER8. +/// \par Wraps +/// __vector unsigned long long +/// \since Crypto++ 6.0 +typedef __vector unsigned long long uint64x2_p; +#endif // VSX or ARCH_PWR8 + +/// \brief The 0 vector +/// \return a 32-bit vector of 0's +/// \since Crypto++ 8.0 +inline uint32x4_p VecZero() +{ + const uint32x4_p v = {0,0,0,0}; + return v; +} + +/// \brief The 1 vector +/// \return a 32-bit vector of 1's +/// \since Crypto++ 8.0 +inline uint32x4_p VecOne() +{ + const uint32x4_p v = {1,1,1,1}; + return v; +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverse() reverses the bytes in a vector +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverse(const T data) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + const uint8x16_p mask = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return (T)vec_perm(data, data, mask); +#endif +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverseLE() reverses the bytes in a vector on +/// little-endian systems. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverseLE(const T data) +{ +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + return data; +#endif +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverseBE() reverses the bytes in a vector on +/// big-endian systems. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverseBE(const T data) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + return data; +#endif +} + +/// \name LOAD OPERATIONS +//@{ + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details Loads a vector in native endian format from a byte array. +/// \details VecLoad_ALTIVEC() uses vec_ld if the effective address +/// of src is aligned. If unaligned it uses vec_lvsl, +/// vec_ld, vec_perm and src. The fixups using +/// vec_lvsl and vec_perm are relatively expensive so +/// you should provide aligned memory adresses. +/// \par Wraps +/// vec_ld, vec_lvsl, vec_perm +/// \sa VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad_ALTIVEC(const byte src[16]) +{ + // Avoid IsAlignedOn for convenience. + const uintptr_t addr = reinterpret_cast(src); + if (addr % 16 == 0) + { + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p perm = vec_lvsl(0, CONST_V8_CAST(addr)); + const uint8x16_p low = vec_ld(0, CONST_V8_CAST(addr)); + const uint8x16_p high = vec_ld(15, CONST_V8_CAST(addr)); + return (uint32x4_p)vec_perm(low, high, perm); + } +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details Loads a vector in native endian format from a byte array. +/// \details VecLoad_ALTIVEC() uses vec_ld if the effective address +/// of src is aligned. If unaligned it uses vec_lvsl, +/// vec_ld, vec_perm and src. +/// \details The fixups using vec_lvsl and vec_perm are +/// relatively expensive so you should provide aligned memory adresses. +/// \par Wraps +/// vec_ld, vec_lvsl, vec_perm +/// \sa VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad_ALTIVEC(int off, const byte src[16]) +{ + // Avoid IsAlignedOn for convenience. + const uintptr_t addr = reinterpret_cast(src)+off; + if (addr % 16 == 0) + { + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p perm = vec_lvsl(0, CONST_V8_CAST(addr)); + const uint8x16_p low = vec_ld(0, CONST_V8_CAST(addr)); + const uint8x16_p high = vec_ld(15, CONST_V8_CAST(addr)); + return (uint32x4_p)vec_perm(low, high, perm); + } +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details VecLoad() loads a vector from a byte array. +/// \details VecLoad() uses POWER9's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER9 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER9 and above, Altivec load on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoad() loads a vector from a byte array. +/// \details VecLoad() uses POWER9's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER9 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER9 and above, Altivec load on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a word array +/// \param src the word array +/// \details VecLoad() loads a vector from a word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoad(const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a word array +/// \param src the word array +/// \param off offset into the word array +/// \details VecLoad() loads a vector from a word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoad(int off, const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Loads a vector from a double word array +/// \param src the double word array +/// \details VecLoad() loads a vector from a double word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 and VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecLoad() with 64-bit elements is available on POWER7 and above. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoad(const word64 src[2]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a double word array +/// \param src the double word array +/// \param off offset into the double word array +/// \details VecLoad() loads a vector from a double word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 and VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecLoad() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoad(int off, const word64 src[2]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +#endif // VSX or ARCH_PWR8 + +/// \brief Loads a vector from an aligned byte array +/// \param src the byte array +/// \details VecLoadAligned() loads a vector from an aligned byte array. +/// \details VecLoadAligned() uses POWER9's vec_xl if available. +/// vec_ld is used if POWER9 is not available. The effective +/// address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on POWER9, vec_ld on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoadAligned() loads a vector from an aligned byte array. +/// \details VecLoadAligned() uses POWER9's vec_xl if available. +/// vec_ld is used if POWER9 is not available. The effective +/// address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on POWER9, vec_ld on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#else + return (uint32x4_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned word array +/// \param src the word array +/// \details VecLoadAligned() loads a vector from an aligned word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(src)); +#else + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned word array +/// \param src the word array +/// \param off offset into the src word array +/// \details VecLoadAligned() loads a vector from an aligned word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(int off, const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Loads a vector from an aligned double word array +/// \param src the double word array +/// \details VecLoadAligned() loads a vector from an aligned double word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoadAligned(const word64 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(src)); +#else + return (uint64x2_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned double word array +/// \param src the double word array +/// \param off offset into the src double word array +/// \details VecLoadAligned() loads a vector from an aligned double word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoadAligned(int off, const word64 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +#endif + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details VecLoadBE() loads a vector from a byte array. VecLoadBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecLoadBE() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER8, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoadBE(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + // CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + return (uint32x4_p)vec_xl_be(0, CONST_V8_CAST(src)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + return (uint32x4_p)VecLoad_ALTIVEC(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecReverseLE(VecLoad_ALTIVEC(CONST_V8_CAST(src))); +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoadBE() loads a vector from a byte array. VecLoadBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecLoadBE() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER8, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoadBE(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + // CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + return (uint32x4_p)vec_xl_be(off, CONST_V8_CAST(src)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#else + return (uint32x4_p)VecReverseLE(VecLoad_ALTIVEC(CONST_V8_CAST(addr))); +#endif +} + +//@} + +/// \name STORE OPERATIONS +//@{ + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStore_ALTIVEC() stores a vector to a byte array. +/// \details VecStore_ALTIVEC() uses vec_st if the effective address +/// of dest is aligned, and uses vec_ste otherwise. +/// vec_ste is relatively expensive so you should provide aligned +/// memory adresses. +/// \details VecStore_ALTIVEC() is used when POWER7 or above +/// and unaligned loads is not available. +/// \par Wraps +/// vec_st, vec_ste, vec_lvsr, vec_perm +/// \sa VecStore, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore_ALTIVEC(const T data, byte dest[16]) +{ + // Avoid IsAlignedOn for convenience. + uintptr_t addr = reinterpret_cast(dest); + if (addr % 16 == 0) + { + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + uint8x16_p perm = (uint8x16_p)vec_perm(data, data, vec_lvsr(0, NCONST_V8_CAST(addr))); + vec_ste((uint8x16_p) perm, 0, (unsigned char*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 1, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 3, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 4, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 8, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 12, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 14, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint8x16_p) perm, 15, (unsigned char*) NCONST_V8_CAST(addr)); + } +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStore_ALTIVEC() stores a vector to a byte array. +/// \details VecStore_ALTIVEC() uses vec_st if the effective address +/// of dest is aligned, and uses vec_ste otherwise. +/// vec_ste is relatively expensive so you should provide aligned +/// memory adresses. +/// \details VecStore_ALTIVEC() is used when POWER7 or above +/// and unaligned loads is not available. +/// \par Wraps +/// vec_st, vec_ste, vec_lvsr, vec_perm +/// \sa VecStore, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore_ALTIVEC(const T data, int off, byte dest[16]) +{ + // Avoid IsAlignedOn for convenience. + uintptr_t addr = reinterpret_cast(dest)+off; + if (addr % 16 == 0) + { + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + uint8x16_p perm = (uint8x16_p)vec_perm(data, data, vec_lvsr(0, NCONST_V8_CAST(addr))); + vec_ste((uint8x16_p) perm, 0, (unsigned char*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 1, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 3, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 4, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 8, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 12, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 14, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint8x16_p) perm, 15, (unsigned char*) NCONST_V8_CAST(addr)); + } +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStore() stores a vector to a byte array. +/// \details VecStore() uses POWER9's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER9 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on POWER9 and above, Altivec store on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStore(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(dest)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStore() stores a vector to a byte array. +/// \details VecStore() uses POWER9's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER9 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on POWER9 and above, Altivec store on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStore(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecStore() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, word64 dest[2]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // 32-bit cast is not a typo. Compiler workaround. + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecStore() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, int off, word64 dest[2]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // 32-bit cast is not a typo. Compiler workaround. + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStoreAligned() stores a vector from an aligned byte array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// vec_st is used if POWER9 is not available. The effective +/// address of dest must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on POWER9 or above, vec_st on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStoreAligned() stores a vector from an aligned byte array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// vec_st is used if POWER9 is not available. The effective +/// address of dest must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on POWER9 or above, vec_st on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStoreAligned() stores a vector from an aligned word array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// POWER7 vec_xst is used if POWER9 is not available. vec_st +/// is used if POWER7 is not available. The effective address of dest +/// must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStoreAligned() stores a vector from an aligned word array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// POWER7 vec_xst is used if POWER9 is not available. vec_st +/// is used if POWER7 is not available. The effective address of dest +/// must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStoreBE() stores a vector to a byte array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStoreBE(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint8x16_p)data, NCONST_V8_CAST(addr)); +#else + VecStore((uint8x16_p)VecReverseLE(data), NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStoreBE() stores a vector to a byte array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStoreBE(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint8x16_p)data, NCONST_V8_CAST(addr)); +#else + VecStore((uint8x16_p)VecReverseLE(data), NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStoreBE() stores a vector to a word array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStoreBE(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint32x4_p)data, NCONST_V32_CAST(addr)); +#else + VecStore((uint32x4_p)VecReverseLE(data), NCONST_V32_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStoreBE() stores a vector to a word array. VecStoreBE +/// will reverse all words in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStoreBE(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint32x4_p)data, NCONST_V32_CAST(addr)); +#else + VecStore((uint32x4_p)VecReverseLE(data), NCONST_V32_CAST(addr)); +#endif +} + +//@} + +/// \name LOGICAL OPERATIONS +//@{ + +/// \brief AND two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAnd() performs vec1 & vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_and +/// \sa VecAnd64 +/// \since Crypto++ 6.0 +template +inline T1 VecAnd(const T1 vec1, const T2 vec2) +{ + return (T1)vec_and(vec1, (T1)vec2); +} + +/// \brief OR two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecOr() performs vec1 | vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_or +/// \sa VecOr64 +/// \since Crypto++ 6.0 +template +inline T1 VecOr(const T1 vec1, const T2 vec2) +{ + return (T1)vec_or(vec1, (T1)vec2); +} + +/// \brief XOR two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecXor() performs vec1 ^ vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_xor +/// \sa VecXor64 +/// \since Crypto++ 6.0 +template +inline T1 VecXor(const T1 vec1, const T2 vec2) +{ + return (T1)vec_xor(vec1, (T1)vec2); +} + +//@} + +/// \name ARITHMETIC OPERATIONS +//@{ + +/// \brief Add two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd() performs vec1 + vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_add +/// \sa VecAdd64 +/// \since Crypto++ 6.0 +template +inline T1 VecAdd(const T1 vec1, const T2 vec2) +{ + return (T1)vec_add(vec1, (T1)vec2); +} + +/// \brief Subtract two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub() performs vec1 - vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_sub +/// \sa VecSub64 +/// \since Crypto++ 6.0 +template +inline T1 VecSub(const T1 vec1, const T2 vec2) +{ + return (T1)vec_sub(vec1, (T1)vec2); +} + +//@} + +/// \name PERMUTE OPERATIONS +//@{ + +/// \brief Permutes a vector +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec the vector +/// \param mask vector mask +/// \return vector +/// \details VecPermute() creates a new vector from vec according to mask. +/// mask is an uint8x16_p vector. The return vector is the same type as vec. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T1 VecPermute(const T1 vec, const T2 mask) +{ + return (T1)vec_perm(vec, vec, (uint8x16_p)mask); +} + +/// \brief Permutes two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \param mask vector mask +/// \return vector +/// \details VecPermute() creates a new vector from vec1 and vec2 according to mask. +/// mask is an uint8x16_p vector. The return vector is the same type as vec. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T1 VecPermute(const T1 vec1, const T1 vec2, const T2 mask) +{ + return (T1)vec_perm(vec1, (T1)vec2, (uint8x16_p)mask); +} + +//@} + +/// \name SHIFT AND ROTATE OPERATIONS +//@{ + +/// \brief Shift a vector left +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecShiftLeftOctet() returns a new vector after shifting the +/// concatenation of the zero vector and the source vector by the specified +/// number of bytes. The return vector is the same type as vec. +/// \details On big endian machines VecShiftLeftOctet() is vec_sld(a, z, +/// c). On little endian machines VecShiftLeftOctet() is translated to +/// vec_sld(z, a, 16-c). You should always call the function as +/// if on a big endian machine as shown below. +///
+///   uint8x16_p x = VecLoad(ptr);
+///   uint8x16_p y = VecShiftLeftOctet<12>(x);
+/// 
+/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecShiftLeftOctet(const T vec) +{ + const T zero = {0}; + if (C >= 16) + { + // Out of range + return zero; + } + else if (C == 0) + { + // Noop + return vec; + } + else + { +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)zero, R); +#else + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)zero, (uint8x16_p)vec, R); +#endif + } +} + +/// \brief Shift a vector right +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecShiftRightOctet() returns a new vector after shifting the +/// concatenation of the zero vector and the source vector by the specified +/// number of bytes. The return vector is the same type as vec. +/// \details On big endian machines VecShiftRightOctet() is vec_sld(a, z, +/// c). On little endian machines VecShiftRightOctet() is translated to +/// vec_sld(z, a, 16-c). You should always call the function as +/// if on a big endian machine as shown below. +///
+///   uint8x16_p x = VecLoad(ptr);
+///   uint8x16_p y = VecShiftRightOctet<12>(y);
+/// 
+/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecShiftRightOctet(const T vec) +{ + const T zero = {0}; + if (C >= 16) + { + // Out of range + return zero; + } + else if (C == 0) + { + // Noop + return vec; + } + else + { +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)zero, (uint8x16_p)vec, R); +#else + enum { R=C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)zero, R); +#endif + } +} + +/// \brief Rotate a vector left +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecRotateLeftOctet() returns a new vector after rotating the +/// concatenation of the source vector with itself by the specified +/// number of bytes. The return vector is the same type as vec. +/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecRotateLeftOctet(const T vec) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R = C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#else + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#endif +} + +/// \brief Rotate a vector right +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecRotateRightOctet() returns a new vector after rotating the +/// concatenation of the source vector with itself by the specified +/// number of bytes. The return vector is the same type as vec. +/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecRotateRightOctet(const T vec) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#else + enum { R = C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#endif +} + +/// \brief Rotate a vector left +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector by +/// bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 7.0 +template +inline uint32x4_p VecRotateLeft(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_rl(vec, m); +} + +/// \brief Rotate a vector right +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 7.0 +template +inline uint32x4_p VecRotateRight(const uint32x4_p vec) +{ + const uint32x4_p m = {32-C, 32-C, 32-C, 32-C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector left +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_sl +/// \since Crypto++ 8.1 +template +inline uint32x4_p VecShiftLeft(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_sl(vec, m); +} + +/// \brief Shift a vector right +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.1 +template +inline uint32x4_p VecShiftRight(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_sr(vec, m); +} + +// 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Rotate a vector left +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecRotateLeft() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.0 +template +inline uint64x2_p VecRotateLeft(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector left +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecShiftLeft() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_sl +/// \since Crypto++ 8.1 +template +inline uint64x2_p VecShiftLeft(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_sl(vec, m); +} + +/// \brief Rotate a vector right +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecRotateRight() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.0 +template +inline uint64x2_p VecRotateRight(const uint64x2_p vec) +{ + const uint64x2_p m = {64-C, 64-C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector right +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecShiftRight() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_sr +/// \since Crypto++ 8.1 +template +inline uint64x2_p VecShiftRight(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_sr(vec, m); +} + +#endif // ARCH_PWR8 + +//@} + +/// \name OTHER OPERATIONS +//@{ + +/// \brief Merge two vectors +/// \tparam T vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \par Wraps +/// vec_mergel +/// \since Crypto++ 8.1 +template +inline T VecMergeLow(const T vec1, const T vec2) +{ + return vec_mergel(vec1, vec2); +} + +/// \brief Merge two vectors +/// \tparam T vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \par Wraps +/// vec_mergeh +/// \since Crypto++ 8.1 +template +inline T VecMergeHigh(const T vec1, const T vec2) +{ + return vec_mergeh(vec1, vec2); +} + +/// \brief Broadcast 32-bit word to a vector +/// \param val the 32-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint32x4_p VecSplatWord(word32 val) +{ + // Fix spurious GCC warning??? + CRYPTOPP_UNUSED(val); + + // Apple Altivec and XL C++ do not offer vec_splats. + // GCC offers vec_splats back to -mcpu=power4. +#if defined(_ARCH_PWR4) && defined(__GNUC__) + return vec_splats(val); +#else + //const word32 x[4] = {val,val,val,val}; + //return VecLoad(x); + const word32 x[4] = {val}; + return vec_splat(VecLoad(x),0); +#endif +} + +/// \brief Broadcast 32-bit element to a vector +/// \tparam the element number +/// \param val the 32-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecSplatElement(const uint32x4_p val) +{ + return vec_splat(val, N); +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Broadcast 64-bit double word to a vector +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint64x2_p VecSplatWord(word64 val) +{ + // The PPC64 ABI says so. + return vec_splats((unsigned long long)val); +} + +/// \brief Broadcast 64-bit element to a vector +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecSplatElement(const uint64x2_p val) +{ +#if defined(__VSX__) || defined(_ARCH_PWR8) + return vec_splat(val, N); +#else + enum {E=N&1}; + if (E == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7}; + return vec_perm(val, val, m); + } + else // (E == 1) + { + const uint8x16_p m = {8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15}; + return vec_perm(val, val, m); + } +#endif +} +#endif + +/// \brief Extract a dword from a vector +/// \tparam T vector type +/// \param val the vector +/// \return vector created from low dword +/// \details VecGetLow() extracts the low dword from a vector. The low dword +/// is composed of the least significant bits and occupies bytes 8 through 15 +/// when viewed as a big endian array. The return vector is the same type as +/// the original vector and padded with 0's in the most significant bit positions. +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecGetLow(const T val) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) && (defined(__VSX__) || defined(_ARCH_PWR8)) + const T zero = {0}; + return (T)VecMergeLow((uint64x2_p)zero, (uint64x2_p)val); +#else + return VecShiftRightOctet<8>(VecShiftLeftOctet<8>(val)); +#endif +} + +/// \brief Extract a dword from a vector +/// \tparam T vector type +/// \param val the vector +/// \return vector created from high dword +/// \details VecGetHigh() extracts the high dword from a vector. The high dword +/// is composed of the most significant bits and occupies bytes 0 through 7 +/// when viewed as a big endian array. The return vector is the same type as +/// the original vector and padded with 0's in the most significant bit positions. +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecGetHigh(const T val) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) && (defined(__VSX__) || defined(_ARCH_PWR8)) + const T zero = {0}; + return (T)VecMergeHigh((uint64x2_p)zero, (uint64x2_p)val); +#else + return VecShiftRightOctet<8>(val); +#endif +} + +/// \brief Exchange high and low double words +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecSwapWords(const T vec) +{ + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, 8); +} + +//@} + +/// \name COMPARISON +//@{ + +/// \brief Compare two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return true if vec1 equals vec2, false otherwise +/// \details VecEqual() performs a bitwise compare. The vector element types do +/// not matter. +/// \par Wraps +/// vec_all_eq +/// \since Crypto++ 8.0 +template +inline bool VecEqual(const T1 vec1, const T2 vec2) +{ + return 1 == vec_all_eq((uint32x4_p)vec1, (uint32x4_p)vec2); +} + +/// \brief Compare two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return true if vec1 does not equal vec2, false otherwise +/// \details VecNotEqual() performs a bitwise compare. The vector element types do +/// not matter. +/// \par Wraps +/// vec_all_eq +/// \since Crypto++ 8.0 +template +inline bool VecNotEqual(const T1 vec1, const T2 vec2) +{ + return 0 == vec_all_eq((uint32x4_p)vec1, (uint32x4_p)vec2); +} + +//@} + +////////////////// 32-bit Altivec ///////////////// + +/// \name 32-BIT ALTIVEC +//@{ + +/// \brief Add two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd64() performs vec1 + vec2. VecAdd64() performs as +/// if adding two uint64x2_p vectors. On POWER7 and below VecAdd64() manages +/// the carries from the elements. +/// \par Wraps +/// vec_add for POWER8, vec_addc, vec_perm, vec_add for Altivec +/// \since Crypto++ 8.3 +inline uint32x4_p VecAdd64(const uint32x4_p& vec1, const uint32x4_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but addudm requires POWER8 +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + return (uint32x4_p)vec_add((uint64x2_p)vec1, (uint64x2_p)vec2); +#else + // The carry mask selects carrys for elements 1 and 3 and sets + // remaining elements to 0. The results is then shifted so the + // carried values are added to elements 0 and 2. +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {0, 1, 0, 1}; +#else + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {1, 0, 1, 0}; +#endif + + uint32x4_p cy = vec_addc(vec1, vec2); + uint32x4_p res = vec_add(vec1, vec2); + cy = vec_and(mask, cy); + cy = vec_sld (cy, zero, 4); + return vec_add(res, cy); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Add two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd64() performs vec1 + vec2. VecAdd64() performs as +/// if adding two uint64x2_p vectors. On POWER7 and below VecAdd64() manages +/// the carries from the elements. +/// \par Wraps +/// vec_add for POWER8 +/// \since Crypto++ 8.3 +inline uint64x2_p VecAdd64(const uint64x2_p& vec1, const uint64x2_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but addudm requires POWER8 + const uint64x2_p res = vec_add(vec1, vec2); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit add in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec1; + const uint32x4_p y = (uint32x4_p)vec2; + const uint32x4_p r = VecAdd64(x, y); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Subtract two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub64() performs vec1 - vec2. VecSub64() performs as +/// if subtracting two uint64x2_p vectors. On POWER7 and below VecSub64() +/// manages the borrows from the elements. +/// \par Wraps +/// vec_sub for POWER8, vec_subc, vec_andc, vec_perm, vec_sub for Altivec +/// \since Crypto++ 8.3 +inline uint32x4_p VecSub64(const uint32x4_p& vec1, const uint32x4_p& vec2) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but subudm requires POWER8 + return (uint32x4_p)vec_sub((uint64x2_p)vec1, (uint64x2_p)vec2); +#else + // The borrow mask selects borrows for elements 1 and 3 and sets + // remaining elements to 0. The results is then shifted so the + // borrowed values are subtracted from elements 0 and 2. +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {0, 1, 0, 1}; +#else + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {1, 0, 1, 0}; +#endif + + // subc sets the complement of borrow, so we have to + // un-complement it using andc. + uint32x4_p bw = vec_subc(vec1, vec2); + uint32x4_p res = vec_sub(vec1, vec2); + bw = vec_andc(mask, bw); + bw = vec_sld (bw, zero, 4); + return vec_sub(res, bw); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Subtract two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub64() performs vec1 - vec2. VecSub64() performs as +/// if subtracting two uint64x2_p vectors. On POWER7 and below VecSub64() +/// manages the borrows from the elements. +/// \par Wraps +/// vec_sub for POWER8 +/// \since Crypto++ 8.3 +inline uint64x2_p VecSub64(const uint64x2_p& vec1, const uint64x2_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but subudm requires POWER8 + const uint64x2_p res = vec_sub(vec1, vec2); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit sub in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec1; + const uint32x4_p y = (uint32x4_p)vec2; + const uint32x4_p r = VecSub64(x, y); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Rotate a vector left as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector by bit count. +/// vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecRotateLeft64(const uint32x4_p vec) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + return (uint32x4_p)VecRotateLeft((uint64x2_p)vec); +#else + // C=0, 32, or 64 needs special handling. That is S32 and S64 below. + enum {S64=C&63, S32=C&31, BR=(S64>=32)}; + + // Get the low bits, shift them to high bits + uint32x4_p t1 = VecShiftLeft(vec); + // Get the high bits, shift them to low bits + uint32x4_p t2 = VecShiftRight<32-S32>(vec); + + if (S64 == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return VecPermute(vec, m); + } + else if (S64 == 32) + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + return VecPermute(vec, m); + } + else if (BR) // Big rotate amount? + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t1 = VecPermute(t1, m); + } + else + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t2 = VecPermute(t2, m); + } + + return vec_or(t1, t2); +#endif +} + +/// \brief Rotate a vector left as if uint64x2_p +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft<8>() rotates each element in a vector +/// by 8-bits. vec is rotated as if uint64x2_p. This specialization +/// is used by algorithms like Speck128. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template<> +inline uint32x4_p VecRotateLeft64<8>(const uint32x4_p vec) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + return VecPermute(vec, m); +#else + const uint8x16_p m = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + return VecPermute(vec, m); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Rotate a vector left as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecRotateLeft64(const uint64x2_p vec) +{ + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + const uint64x2_p res = VecRotateLeft(vec); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit rotate in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec; + const uint32x4_p r = VecRotateLeft64(x); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Rotate a vector right as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecRotateRight64(const uint32x4_p vec) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + return (uint32x4_p)VecRotateRight((uint64x2_p)vec); +#else + // C=0, 32, or 64 needs special handling. That is S32 and S64 below. + enum {S64=C&63, S32=C&31, BR=(S64>=32)}; + + // Get the low bits, shift them to high bits + uint32x4_p t1 = VecShiftRight(vec); + // Get the high bits, shift them to low bits + uint32x4_p t2 = VecShiftLeft<32-S32>(vec); + + if (S64 == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return VecPermute(vec, m); + } + else if (S64 == 32) + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + return VecPermute(vec, m); + } + else if (BR) // Big rotate amount? + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t1 = VecPermute(t1, m); + } + else + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t2 = VecPermute(t2, m); + } + + return vec_or(t1, t2); +#endif +} + +/// \brief Rotate a vector right as if uint64x2_p +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64<8>() rotates each element in a vector +/// by 8-bits. vec is rotated as if uint64x2_p. This specialization +/// is used by algorithms like Speck128. +/// \details vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template<> +inline uint32x4_p VecRotateRight64<8>(const uint32x4_p vec) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + return VecPermute(vec, m); +#else + const uint8x16_p m = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + return VecPermute(vec, m); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Rotate a vector right as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecRotateRight64(const uint64x2_p vec) +{ + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + const uint64x2_p res = VecRotateRight(vec); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit rotate in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec; + const uint32x4_p r = VecRotateRight64(x); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief AND two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAnd64() performs vec1 & vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecAnd64() is a convenience function that simply performs a VecAnd(). +/// \par Wraps +/// vec_and +/// \since Crypto++ 8.3 +template +inline T1 VecAnd64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_and(vec1, (T1)vec2); +} + +/// \brief OR two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecOr64() performs vec1 | vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecOr64() is a convenience function that simply performs a VecOr(). +/// \par Wraps +/// vec_or +/// \since Crypto++ 8.3 +template +inline T1 VecOr64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_or(vec1, (T1)vec2); +} + +/// \brief XOR two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecXor64() performs vec1 ^ vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecXor64() is a convenience function that simply performs a VecXor(). +/// \par Wraps +/// vec_xor +/// \since Crypto++ 8.3 +template +inline T1 VecXor64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_xor(vec1, (T1)vec2); +} + +/// \brief Broadcast 64-bit double word to a vector +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint32x4_p VecSplatWord64(word64 val) +{ +#if defined(_ARCH_PWR8) + // The PPC64 ABI says so. + return (uint32x4_p)vec_splats((unsigned long long)val); +#else + const word64 x[2] = {val,val}; + return (uint32x4_p)VecLoad((const word32*)x); +#endif +} + +/// \brief Broadcast 64-bit element to a vector as if uint64x2_p +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecSplatElement64(const uint32x4_p val) +{ +#if defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_splat((uint64x2_p)val, N); +#else + enum {E=N&1}; + if (E == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7}; + return (uint32x4_p)vec_perm(val, val, m); + } + else // (E == 1) + { + const uint8x16_p m = {8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15}; + return (uint32x4_p)vec_perm(val, val, m); + } +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Broadcast 64-bit element to a vector +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecSplatElement64(const uint64x2_p val) +{ + return vec_splat(val, N); +} +#endif + +//@} + +//////////////////////// Power8 Crypto //////////////////////// + +// __CRYPTO__ alone is not enough. Clang will define __CRYPTO__ +// when it is not available, like with Power7. Sigh... +#if (defined(_ARCH_PWR8) && defined(__CRYPTO__)) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \name POLYNOMIAL MULTIPLICATION +//@{ + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecPolyMultiply() performs polynomial multiplication. POWER8 +/// polynomial multiplication multiplies the high and low terms, and then +/// XOR's the high and low products. That is, the result is ah*bh XOR +/// al*bl. It is different behavior than Intel polynomial +/// multiplication. To obtain a single product without the XOR, then set +/// one of the high or low terms to 0. For example, setting ah=0 +/// results in 0*bh XOR al*bl = al*bl. +/// \par Wraps +/// __vpmsumw, __builtin_altivec_crypto_vpmsumw and __builtin_crypto_vpmsumw. +/// \since Crypto++ 8.1 +inline uint32x4_p VecPolyMultiply(const uint32x4_p& a, const uint32x4_p& b) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return __vpmsumw (a, b); +#elif defined(__clang__) + return __builtin_altivec_crypto_vpmsumw (a, b); +#else + return __builtin_crypto_vpmsumw (a, b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecPolyMultiply() performs polynomial multiplication. POWER8 +/// polynomial multiplication multiplies the high and low terms, and then +/// XOR's the high and low products. That is, the result is ah*bh XOR +/// al*bl. It is different behavior than Intel polynomial +/// multiplication. To obtain a single product without the XOR, then set +/// one of the high or low terms to 0. For example, setting ah=0 +/// results in 0*bh XOR al*bl = al*bl. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.1 +inline uint64x2_p VecPolyMultiply(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return __vpmsumd (a, b); +#elif defined(__clang__) + return __builtin_altivec_crypto_vpmsumd (a, b); +#else + return __builtin_crypto_vpmsumd (a, b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply00() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x00). +/// The 0x00 indicates the low 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply00(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetHigh(a), VecGetHigh(b))); +#else + return VecPolyMultiply(VecGetHigh(a), VecGetHigh(b)); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply01 performs() polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x01). +/// The 0x01 indicates the low 64-bits of a and high +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply01(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(a, VecGetHigh(b))); +#else + return VecPolyMultiply(a, VecGetHigh(b)); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply10() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x10). +/// The 0x10 indicates the high 64-bits of a and low +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply10(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetHigh(a), b)); +#else + return VecPolyMultiply(VecGetHigh(a), b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply11() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x11). +/// The 0x11 indicates the high 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply11(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetLow(a), b)); +#else + return VecPolyMultiply(VecGetLow(a), b); +#endif +} + +//@} + +/// \name AES ENCRYPTION +//@{ + +/// \brief One round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecEncrypt() performs one round of AES encryption of state +/// using subkey key. The return vector is the same type as state. +/// \details VecEncrypt() is available on POWER8 and above. +/// \par Wraps +/// __vcipher, __builtin_altivec_crypto_vcipher, __builtin_crypto_vcipher +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecEncrypt(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vcipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vcipher((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vcipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecEncryptLast() performs the final round of AES encryption +/// of state using subkey key. The return vector is the same type as state. +/// \details VecEncryptLast() is available on POWER8 and above. +/// \par Wraps +/// __vcipherlast, __builtin_altivec_crypto_vcipherlast, __builtin_crypto_vcipherlast +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecEncryptLast(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vcipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vcipherlast((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vcipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief One round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecDecrypt() performs one round of AES decryption of state +/// using subkey key. The return vector is the same type as state. +/// \details VecDecrypt() is available on POWER8 and above. +/// \par Wraps +/// __vncipher, __builtin_altivec_crypto_vncipher, __builtin_crypto_vncipher +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecDecrypt(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vncipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vncipher((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vncipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecDecryptLast() performs the final round of AES decryption +/// of state using subkey key. The return vector is the same type as state. +/// \details VecDecryptLast() is available on POWER8 and above. +/// \par Wraps +/// __vncipherlast, __builtin_altivec_crypto_vncipherlast, __builtin_crypto_vncipherlast +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecDecryptLast(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vncipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vncipherlast((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vncipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +//@} + +/// \name SHA DIGESTS +//@{ + +/// \brief SHA256 Sigma functions +/// \tparam func function +/// \tparam fmask function mask +/// \tparam T vector type +/// \param data the block to transform +/// \details VecSHA256() selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and fmask. The return vector is the same type as data. +/// \details VecSHA256() is available on POWER8 and above. +/// \par Wraps +/// __vshasigmaw, __builtin_altivec_crypto_vshasigmaw, __builtin_crypto_vshasigmaw +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T VecSHA256(const T data) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T)__vshasigmaw((uint32x4_p)data, func, fmask); +#elif defined(__clang__) + return (T)__builtin_altivec_crypto_vshasigmaw((uint32x4_p)data, func, fmask); +#elif defined(__GNUC__) + return (T)__builtin_crypto_vshasigmaw((uint32x4_p)data, func, fmask); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief SHA512 Sigma functions +/// \tparam func function +/// \tparam fmask function mask +/// \tparam T vector type +/// \param data the block to transform +/// \details VecSHA512() selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and fmask. The return vector is the same type as data. +/// \details VecSHA512() is available on POWER8 and above. +/// \par Wraps +/// __vshasigmad, __builtin_altivec_crypto_vshasigmad, __builtin_crypto_vshasigmad +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T VecSHA512(const T data) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T)__vshasigmad((uint64x2_p)data, func, fmask); +#elif defined(__clang__) + return (T)__builtin_altivec_crypto_vshasigmad((uint64x2_p)data, func, fmask); +#elif defined(__GNUC__) + return (T)__builtin_crypto_vshasigmad((uint64x2_p)data, func, fmask); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +//@} + +#endif // __CRYPTO__ + +#endif // _ALTIVEC_ + +NAMESPACE_END + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif // CRYPTOPP_PPC_CRYPTO_H diff --git a/extension/third_party/cryptopp/pssr.cpp b/extension/third_party/cryptopp/pssr.cpp new file mode 100644 index 00000000..753797ba --- /dev/null +++ b/extension/third_party/cryptopp/pssr.cpp @@ -0,0 +1,163 @@ +// pssr.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "pssr.h" +#include "emsa2.h" +#include "ripemd.h" +#include "whrlpool.h" +#include "misc.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +template<> const byte EMSA2HashId::id = 0x31; +template<> const byte EMSA2HashId::id = 0x32; +template<> const byte EMSA2HashId::id = 0x37; + +#ifndef CRYPTOPP_IMPORTS + +size_t PSSR_MEM_Base::MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const +{ + size_t saltLen = SaltLen(digestLength); + size_t minPadLen = MinPadLen(digestLength); + return 9 + 8*(minPadLen + saltLen + digestLength + hashIdentifierLength); +} + +size_t PSSR_MEM_Base::MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const +{ + if (AllowRecovery()) + return SaturatingSubtract(representativeBitLength, MinRepresentativeBitLength(hashIdentifierLength, digestLength)) / 8; + return 0; +} + +bool PSSR_MEM_Base::IsProbabilistic() const +{ + return SaltLen(1) > 0; +} + +bool PSSR_MEM_Base::AllowNonrecoverablePart() const +{ + return true; +} + +bool PSSR_MEM_Base::RecoverablePartFirst() const +{ + return false; +} + +void PSSR_MEM_Base::ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + CRYPTOPP_ASSERT(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize())); + + const size_t u = hashIdentifier.second + 1; + const size_t representativeByteLength = BitsToBytes(representativeBitLength); + const size_t digestSize = hash.DigestSize(); + const size_t saltSize = SaltLen(digestSize); + byte *const h = representative + representativeByteLength - u - digestSize; + + SecByteBlock digest(digestSize), salt(saltSize); + hash.Final(digest); + rng.GenerateBlock(salt, saltSize); + + // compute H = hash of M' + byte c[8]; + PutWord(false, BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength)); + PutWord(false, BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3)); + hash.Update(c, 8); + hash.Update(recoverableMessage, recoverableMessageLength); + hash.Update(digest, digestSize); + hash.Update(salt, saltSize); + hash.Final(h); + + // compute representative + GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize, false); + byte *xorStart = representative + representativeByteLength - u - digestSize - salt.size() - recoverableMessageLength - 1; + xorStart[0] ^= 1; + if (recoverableMessage && recoverableMessageLength) + xorbuf(xorStart + 1, recoverableMessage, recoverableMessageLength); + xorbuf(xorStart + 1 + recoverableMessageLength, salt, salt.size()); + if (hashIdentifier.first && hashIdentifier.second) + { + memcpy(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second); + representative[representativeByteLength - 1] = 0xcc; + } + else + { + representative[representativeByteLength - 1] = 0xbc; + } + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); +} + +DecodingResult PSSR_MEM_Base::RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoverableMessage) const +{ + CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + CRYPTOPP_ASSERT(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize())); + + const size_t u = hashIdentifier.second + 1; + const size_t representativeByteLength = BitsToBytes(representativeBitLength); + const size_t digestSize = hash.DigestSize(); + const size_t saltSize = SaltLen(digestSize); + const byte *const h = representative + representativeByteLength - u - digestSize; + + SecByteBlock digest(digestSize); + hash.Final(digest); + + DecodingResult result(0); + bool &valid = result.isValidCoding; + size_t &recoverableMessageLength = result.messageLength; + + valid = (representative[representativeByteLength - 1] == (hashIdentifier.second ? 0xcc : 0xbc)) && valid; + + if (hashIdentifier.first && hashIdentifier.second) + valid = VerifyBufsEqual(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second) && valid; + + GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize); + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); + + // extract salt and recoverableMessage from DB = 00 ... || 01 || M || salt + byte *salt = representative + representativeByteLength - u - digestSize - saltSize; + byte *M = FindIfNot(representative, salt-1, byte(0)); + recoverableMessageLength = salt-M-1; + if (*M == 0x01 && + (size_t)(M - representative - (representativeBitLength % 8 != 0)) >= MinPadLen(digestSize) && + recoverableMessageLength <= MaxRecoverableLength(representativeBitLength, hashIdentifier.second, digestSize)) + { + if (recoverableMessage) + memcpy(recoverableMessage, M+1, recoverableMessageLength); + } + else + { + recoverableMessageLength = 0; + valid = false; + } + + // verify H = hash of M' + byte c[8]; + PutWord(false, BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength)); + PutWord(false, BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3)); + hash.Update(c, 8); + hash.Update(recoverableMessage, recoverableMessageLength); + hash.Update(digest, digestSize); + hash.Update(salt, saltSize); + valid = hash.Verify(h) && valid; + + if (!AllowRecovery() && valid && recoverableMessageLength != 0) + {throw NotImplemented("PSSR_MEM: message recovery disabled");} + + return result; +} + +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/pssr.h b/extension/third_party/cryptopp/pssr.h new file mode 100644 index 00000000..7122549d --- /dev/null +++ b/extension/third_party/cryptopp/pssr.h @@ -0,0 +1,105 @@ +// pssr.h - originally written and placed in the public domain by Wei Dai + +/// \file pssr.h +/// \brief Classes for probablistic signature schemes +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_PSSR_H +#define CRYPTOPP_PSSR_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "emsa2.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PSSR Message Encoding Method interface +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL PSSR_MEM_Base : public PK_RecoverableSignatureMessageEncodingMethod +{ +public: + virtual ~PSSR_MEM_Base() {} + +protected: + virtual bool AllowRecovery() const =0; + virtual size_t SaltLen(size_t hashLen) const =0; + virtual size_t MinPadLen(size_t hashLen) const =0; + virtual const MaskGeneratingFunction & GetMGF() const =0; + +private: + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const; + size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const; + bool IsProbabilistic() const; + bool AllowNonrecoverablePart() const; + bool RecoverablePartFirst() const; + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + DecodingResult RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoverableMessage) const; +}; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \since Crypto++ 2.1 +template class PSSR_MEM_BaseWithHashId; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \details If USE_HASH_ID is true, then EMSA2HashIdLookup is used for the base class +template<> class PSSR_MEM_BaseWithHashId : public EMSA2HashIdLookup {}; + +/// \brief PSSR Message Encoding Method without Hash Identifier +/// \details If USE_HASH_ID is false, then PSSR_MEM_Base is used for the base class +/// \since Crypto++ 2.1 +template<> class PSSR_MEM_BaseWithHashId : public PSSR_MEM_Base {}; + +/// \brief PSSR Message Encoding Method +/// \tparam ALLOW_RECOVERY flag indicating whether the scheme provides message recovery +/// \tparam MGF mask generation function +/// \tparam SALT_LEN length of the salt +/// \tparam MIN_PAD_LEN minimum length of the pad +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \details If ALLOW_RECOVERY is true, the the signature scheme provides message recovery. If +/// ALLOW_RECOVERY is false, the the signature scheme is appendix, and the message must be +/// provided during verification. +/// \since Crypto++ 2.1 +template +class PSSR_MEM : public PSSR_MEM_BaseWithHashId +{ + virtual bool AllowRecovery() const {return ALLOW_RECOVERY;} + virtual size_t SaltLen(size_t hashLen) const {return SALT_LEN < 0 ? hashLen : SALT_LEN;} + virtual size_t MinPadLen(size_t hashLen) const {return MIN_PAD_LEN < 0 ? hashLen : MIN_PAD_LEN;} + virtual const MaskGeneratingFunction & GetMGF() const {static MGF mgf; return mgf;} + +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(ALLOW_RECOVERY ? "PSSR-" : "PSS-") + MGF::StaticAlgorithmName();} +}; + +/// \brief Probabilistic Signature Scheme with Recovery +/// \details Signature Schemes with Recovery encode the message with the signature. +/// \sa PSSR-MGF1 +/// \since Crypto++ 2.1 +struct PSSR : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +/// \brief Probabilistic Signature Scheme with Appendix +/// \details Signature Schemes with Appendix require the message to be provided during verification. +/// \sa PSS-MGF1 +/// \since Crypto++ 2.1 +struct PSS : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/pubkey.cpp b/extension/third_party/cryptopp/pubkey.cpp new file mode 100644 index 00000000..3a600906 --- /dev/null +++ b/extension/third_party/cryptopp/pubkey.cpp @@ -0,0 +1,170 @@ +// pubkey.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "pubkey.h" +#include "integer.h" +#include "filters.h" + +NAMESPACE_BEGIN(CryptoPP) + +void P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength, bool mask, unsigned int counterStart) +{ + ArraySink *sink; + HashFilter filter(hash, sink = mask ? new ArrayXorSink(output, outputLength) : new ArraySink(output, outputLength)); + word32 counter = counterStart; + while (sink->AvailableSize() > 0) + { + filter.Put(input, inputLength); + filter.PutWord32(counter++); + filter.Put(derivationParams, derivationParamsLength); + filter.MessageEnd(); + } +} + +bool PK_DeterministicSignatureMessageEncodingMethod::VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + SecByteBlock computedRepresentative(BitsToBytes(representativeBitLength)); + ComputeMessageRepresentative(NullRNG(), NULLPTR, 0, hash, hashIdentifier, messageEmpty, computedRepresentative, representativeBitLength); + return VerifyBufsEqual(representative, computedRepresentative, computedRepresentative.size()); +} + +bool PK_RecoverableSignatureMessageEncodingMethod::VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const +{ + SecByteBlock recoveredMessage(MaxRecoverableLength(representativeBitLength, hashIdentifier.second, hash.DigestSize())); + DecodingResult result = RecoverMessageFromRepresentative( + hash, hashIdentifier, messageEmpty, representative, representativeBitLength, recoveredMessage); + return result.isValidCoding && result.messageLength == 0; +} + +void TF_SignerBase::InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + HashIdentifier id = GetHashIdentifier(); + const MessageEncodingInterface &encoding = GetMessageEncodingInterface(); + + if (MessageRepresentativeBitLength() < encoding.MinRepresentativeBitLength(id.second, ma.AccessHash().DigestSize())) + throw PK_SignatureScheme::KeyTooShort(); + + size_t maxRecoverableLength = encoding.MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, ma.AccessHash().DigestSize()); + + if (maxRecoverableLength == 0) + {throw NotImplemented("TF_SignerBase: this algorithm does not support message recovery or the key is too short");} + if (recoverableMessageLength > maxRecoverableLength) + throw InvalidArgument("TF_SignerBase: the recoverable message part is too long for the given key and algorithm"); + + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + encoding.ProcessRecoverableMessage( + ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + NULLPTR, 0, ma.m_semisignature); +} + +size_t TF_SignerBase::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const +{ + CRYPTOPP_UNUSED(restart); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + HashIdentifier id = GetHashIdentifier(); + const MessageEncodingInterface &encoding = GetMessageEncodingInterface(); + + if (MessageRepresentativeBitLength() < encoding.MinRepresentativeBitLength(id.second, ma.AccessHash().DigestSize())) + throw PK_SignatureScheme::KeyTooShort(); + + SecByteBlock representative(MessageRepresentativeLength()); + encoding.ComputeMessageRepresentative(rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), id, ma.m_empty, + representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + + Integer r(representative, representative.size()); + size_t signatureLength = SignatureLength(); + GetTrapdoorFunctionInterface().CalculateRandomizedInverse(rng, r).Encode(signature, signatureLength); + return signatureLength; +} + +void TF_VerifierBase::InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + HashIdentifier id = GetHashIdentifier(); + const MessageEncodingInterface &encoding = GetMessageEncodingInterface(); + + if (MessageRepresentativeBitLength() < encoding.MinRepresentativeBitLength(id.second, ma.AccessHash().DigestSize())) + throw PK_SignatureScheme::KeyTooShort(); + + ma.m_representative.New(MessageRepresentativeLength()); + Integer x = GetTrapdoorFunctionInterface().ApplyFunction(Integer(signature, signatureLength)); + if (x.BitCount() > MessageRepresentativeBitLength()) + x = Integer::Zero(); // don't return false here to prevent timing attack + x.Encode(ma.m_representative, ma.m_representative.size()); +} + +bool TF_VerifierBase::VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + HashIdentifier id = GetHashIdentifier(); + const MessageEncodingInterface &encoding = GetMessageEncodingInterface(); + + if (MessageRepresentativeBitLength() < encoding.MinRepresentativeBitLength(id.second, ma.AccessHash().DigestSize())) + throw PK_SignatureScheme::KeyTooShort(); + + bool result = encoding.VerifyMessageRepresentative( + ma.AccessHash(), id, ma.m_empty, ma.m_representative, MessageRepresentativeBitLength()); + ma.m_empty = true; + return result; +} + +DecodingResult TF_VerifierBase::RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const +{ + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + HashIdentifier id = GetHashIdentifier(); + const MessageEncodingInterface &encoding = GetMessageEncodingInterface(); + + if (MessageRepresentativeBitLength() < encoding.MinRepresentativeBitLength(id.second, ma.AccessHash().DigestSize())) + throw PK_SignatureScheme::KeyTooShort(); + + DecodingResult result = encoding.RecoverMessageFromRepresentative( + ma.AccessHash(), id, ma.m_empty, ma.m_representative, MessageRepresentativeBitLength(), recoveredMessage); + ma.m_empty = true; + return result; +} + +DecodingResult TF_DecryptorBase::Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const +{ + if (ciphertextLength != FixedCiphertextLength()) + throw InvalidArgument(AlgorithmName() + ": ciphertext length of " + IntToString(ciphertextLength) + " doesn't match the required length of " + IntToString(FixedCiphertextLength()) + " for this key"); + + SecByteBlock paddedBlock(PaddedBlockByteLength()); + Integer x = GetTrapdoorFunctionInterface().CalculateInverse(rng, Integer(ciphertext, ciphertextLength)); + if (x.ByteCount() > paddedBlock.size()) + x = Integer::Zero(); // don't return false here to prevent timing attack + x.Encode(paddedBlock, paddedBlock.size()); + return GetMessageEncodingInterface().Unpad(paddedBlock, PaddedBlockBitLength(), plaintext, parameters); +} + +void TF_EncryptorBase::Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const +{ + if (plaintextLength > FixedMaxPlaintextLength()) + { + if (FixedMaxPlaintextLength() < 1) + throw InvalidArgument(AlgorithmName() + ": this key is too short to encrypt any messages"); + else + throw InvalidArgument(AlgorithmName() + ": message length of " + IntToString(plaintextLength) + " exceeds the maximum of " + IntToString(FixedMaxPlaintextLength()) + " for this public key"); + } + + SecByteBlock paddedBlock(PaddedBlockByteLength()); + GetMessageEncodingInterface().Pad(rng, plaintext, plaintextLength, paddedBlock, PaddedBlockBitLength(), parameters); + GetTrapdoorFunctionInterface().ApplyRandomizedFunction(rng, Integer(paddedBlock, paddedBlock.size())).Encode(ciphertext, FixedCiphertextLength()); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/pubkey.h b/extension/third_party/cryptopp/pubkey.h new file mode 100644 index 00000000..b959cd00 --- /dev/null +++ b/extension/third_party/cryptopp/pubkey.h @@ -0,0 +1,2368 @@ +// pubkey.h - originally written and placed in the public domain by Wei Dai + +/// \file pubkey.h +/// \brief This file contains helper classes/functions for implementing public key algorithms. +/// \details The class hierachies in this header file tend to look like this: +/// +///
+///                   x1
+///                  +--+
+///                  |  |
+///                 y1  z1
+///                  |  |
+///             x2  x2
+///                  |  |
+///                 y2  z2
+///                  |  |
+///             x3  x3
+///                  |  |
+///                 y3  z3
+/// 
+/// +///
    +///
  • x1, y1, z1 are abstract interface classes defined in cryptlib.h +///
  • x2, y2, z2 are implementations of the interfaces using "abstract policies", which +/// are pure virtual functions that should return interfaces to interchangeable algorithms. +/// These classes have Base suffixes. +///
  • x3, y3, z3 hold actual algorithms and implement those virtual functions. +/// These classes have Impl suffixes. +///
+/// +/// \details The TF_ prefix means an implementation using trapdoor functions on integers. +/// \details The DL_ prefix means an implementation using group operations in groups where discrete log is hard. + +#ifndef CRYPTOPP_PUBKEY_H +#define CRYPTOPP_PUBKEY_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "filters.h" +#include "eprecomp.h" +#include "fips140.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if defined(__SUNPRO_CC) +# define MAYBE_RETURN(x) return x +#else +# define MAYBE_RETURN(x) CRYPTOPP_UNUSED(x) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Provides range for plaintext and ciphertext lengths +/// \details A trapdoor function is a function that is easy to compute in one direction, +/// but difficult to compute in the opposite direction without special knowledge. +/// The special knowledge is usually the private key. +/// \details Trapdoor functions only handle messages of a limited length or size. +/// MaxPreimage is the plaintext's maximum length, and MaxImage is the +/// ciphertext's maximum length. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionBounds +{ +public: + virtual ~TrapdoorFunctionBounds() {} + + /// \brief Returns the maximum size of a message before the trapdoor function is applied + /// \return the maximum size of a message before the trapdoor function is applied + /// \details Derived classes must implement PreimageBound(). + virtual Integer PreimageBound() const =0; + /// \brief Returns the maximum size of a message after the trapdoor function is applied + /// \return the maximum size of a message after the trapdoor function is applied + /// \details Derived classes must implement ImageBound(). + virtual Integer ImageBound() const =0; + /// \brief Returns the maximum size of a message before the trapdoor function is applied bound to a public key + /// \return the maximum size of a message before the trapdoor function is applied bound to a public key + /// \details The default implementation returns PreimageBound() - 1. + virtual Integer MaxPreimage() const {return --PreimageBound();} + /// \brief Returns the maximum size of a message after the trapdoor function is applied bound to a public key + /// \return the the maximum size of a message after the trapdoor function is applied bound to a public key + /// \details The default implementation returns ImageBound() - 1. + virtual Integer MaxImage() const {return --ImageBound();} +}; + +/// \brief Applies the trapdoor function, using random data if required +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunction : public TrapdoorFunctionBounds +{ +public: + virtual ~RandomizedTrapdoorFunction() {} + + /// \brief Applies the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \return the message x encrypted under the public key + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// Derived classes must implement it. + virtual Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the encryption algorithm is randomized + /// \return true if the encryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the trapdoor function +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunction : public RandomizedTrapdoorFunction +{ +public: + virtual ~TrapdoorFunction() {} + + /// \brief Applies the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// \details Internally, ApplyRandomizedFunction() calls ApplyFunction() \a + /// without the RandomNumberGenerator. + Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const + {CRYPTOPP_UNUSED(rng); return ApplyFunction(x);} + bool IsRandomized() const {return false;} + + /// \brief Applies the trapdoor + /// \param x the message on which the encryption function is applied + /// \return the message x encrypted under the public key + /// \details ApplyFunction is a generalization of encryption under a public key + /// cryptosystem. Derived classes must implement it. + virtual Integer ApplyFunction(const Integer &x) const =0; +}; + +/// \brief Applies the inverse of the trapdoor function, using random data if required +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~RandomizedTrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \return the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// The RandomNumberGenerator may (or may not) be required. Derived classes must implement it. + virtual Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the decryption algorithm is randomized + /// \return true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the inverse of the trapdoor function +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionInverse : public RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~TrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \return the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// \details Internally, CalculateRandomizedInverse() calls CalculateInverse() \a + /// without the RandomNumberGenerator. + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const + {return CalculateInverse(rng, x);} + + /// \brief Determines if the decryption algorithm is randomized + /// \return true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + bool IsRandomized() const {return false;} + + /// \brief Calculates the inverse of an element + /// \param rng a RandomNumberGenerator derived class + /// \param x the element + /// \return the inverse of the element in the group + virtual Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +// ******************************************************** + +/// \brief Message encoding method for public key encryption +class CRYPTOPP_NO_VTABLE PK_EncryptionMessageEncodingMethod +{ +public: + virtual ~PK_EncryptionMessageEncodingMethod() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + + /// max size of unpadded message in bytes, given max size of padded message in bits (1 less than size of modulus) + virtual size_t MaxUnpaddedLength(size_t paddedLength) const =0; + + virtual void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedBitLength, const NameValuePairs ¶meters) const =0; + + virtual DecodingResult Unpad(const byte *padded, size_t paddedBitLength, byte *raw, const NameValuePairs ¶meters) const =0; +}; + +// ******************************************************** + +/// \brief The base for trapdoor based cryptosystems +/// \tparam TFI trapdoor function interface derived class +/// \tparam MEI message encoding interface derived class +template +class CRYPTOPP_NO_VTABLE TF_Base +{ +protected: + virtual ~TF_Base() {} + + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; + + typedef TFI TrapdoorFunctionInterface; + virtual const TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const =0; + + typedef MEI MessageEncodingInterface; + virtual const MessageEncodingInterface & GetMessageEncodingInterface() const =0; +}; + +// ******************************************************** + +/// \brief Public key trapdoor function default implementation +/// \tparam BASE public key cryptosystem with a fixed length +template +class CRYPTOPP_NO_VTABLE PK_FixedLengthCryptoSystemImpl : public BASE +{ +public: + virtual ~PK_FixedLengthCryptoSystemImpl() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + {return ciphertextLength == FixedCiphertextLength() ? FixedMaxPlaintextLength() : 0;} + size_t CiphertextLength(size_t plaintextLength) const + {return plaintextLength <= FixedMaxPlaintextLength() ? FixedCiphertextLength() : 0;} + + virtual size_t FixedMaxPlaintextLength() const =0; + virtual size_t FixedCiphertextLength() const =0; +}; + +/// \brief Trapdoor function cryptosystem base class +/// \tparam INTFACE public key cryptosystem base interface +/// \tparam BASE public key cryptosystem implementation base +template +class CRYPTOPP_NO_VTABLE TF_CryptoSystemBase : public PK_FixedLengthCryptoSystemImpl, protected BASE +{ +public: + virtual ~TF_CryptoSystemBase() {} + + bool ParameterSupported(const char *name) const {return this->GetMessageEncodingInterface().ParameterSupported(name);} + size_t FixedMaxPlaintextLength() const {return this->GetMessageEncodingInterface().MaxUnpaddedLength(PaddedBlockBitLength());} + size_t FixedCiphertextLength() const {return this->GetTrapdoorFunctionBounds().MaxImage().ByteCount();} + +protected: + size_t PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + // Coverity finding on potential overflow/underflow. + size_t PaddedBlockBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().PreimageBound().BitCount(),1U);} +}; + +/// \brief Trapdoor function cryptosystems decryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_DecryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Trapdoor function cryptosystems encryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_EncryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +// ******************************************************** + +// Typedef change due to Clang, http://github.com/weidai11/cryptopp/issues/300 +typedef std::pair HashIdentifier; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_SignatureMessageEncodingMethod provides interfaces for message +/// encoding method for public key signature schemes. The methods support both +/// trapdoor functions (TF_*) and discrete logarithm (DL_*) +/// based schemes. +class CRYPTOPP_NO_VTABLE PK_SignatureMessageEncodingMethod +{ +public: + virtual ~PK_SignatureMessageEncodingMethod() {} + + virtual size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + virtual size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + + /// \brief Determines whether an encoding method requires a random number generator + /// \return true if the encoding method requires a RandomNumberGenerator() + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + /// \sa Bellare and RogawayPSS: + /// Provably Secure Encoding Method for Digital Signatures + bool IsProbabilistic() const + {return true;} + bool AllowNonrecoverablePart() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + virtual bool RecoverablePartFirst() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // for verification, DL + virtual void ProcessSemisignature(HashTransformation &hash, const byte *semisignature, size_t semisignatureLength) const + {CRYPTOPP_UNUSED(hash); CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength);} + + // for signature + virtual void ProcessRecoverableMessage(HashTransformation &hash, + const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *presignature, size_t presignatureLength, + SecByteBlock &semisignature) const + { + CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(recoverableMessage); CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); CRYPTOPP_UNUSED(semisignature); + if (RecoverablePartFirst()) + CRYPTOPP_ASSERT(!"ProcessRecoverableMessage() not implemented"); + } + + virtual void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual DecodingResult RecoverMessageFromRepresentative( // for TF + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(messageEmpty); + CRYPTOPP_UNUSED(representative); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + virtual DecodingResult RecoverMessageFromSemisignature( // for DL + HashTransformation &hash, HashIdentifier hashIdentifier, + const byte *presignature, size_t presignatureLength, + const byte *semisignature, size_t semisignatureLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); + CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // VC60 workaround + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier CRYPTOPP_API Lookup() + { + return HashIdentifier(static_cast(NULLPTR), 0); + } + }; + }; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_DeterministicSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_DeterministicSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_RecoverableSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_RecoverableSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_DSA provides interfaces +/// for message encoding method for DSA. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_DSA : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_NR provides interfaces +/// for message encoding method for Nyberg-Rueppel. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_NR : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +#if 0 +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_SM2 provides interfaces +/// for message encoding method for SM2. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_SM2 : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; +#endif + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulatorBase : public PK_MessageAccumulator +{ +public: + PK_MessageAccumulatorBase() : m_empty(true) {} + + virtual HashTransformation & AccessHash() =0; + + void Update(const byte *input, size_t length) + { + AccessHash().Update(input, length); + m_empty = m_empty && length == 0; + } + + SecByteBlock m_recoverableMessage, m_representative, m_presignature, m_semisignature; + Integer m_k, m_s; + bool m_empty; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +template +class PK_MessageAccumulatorImpl : public PK_MessageAccumulatorBase, protected ObjectHolder +{ +public: + HashTransformation & AccessHash() {return this->m_object;} +}; + +/// \brief Trapdoor Function (TF) Signature Scheme base class +/// \tparam INTFACE interface +/// \tparam BASE base class +template +class CRYPTOPP_NO_VTABLE TF_SignatureSchemeBase : public INTFACE, protected BASE +{ +public: + virtual ~TF_SignatureSchemeBase() {} + + size_t SignatureLength() const + {return this->GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + size_t MaxRecoverableLength() const + {return this->GetMessageEncodingInterface().MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, GetDigestSize());} + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); return this->MaxRecoverableLength();} + + bool IsProbabilistic() const + {return this->GetTrapdoorFunctionInterface().IsRandomized() || this->GetMessageEncodingInterface().IsProbabilistic();} + bool AllowNonrecoverablePart() const + {return this->GetMessageEncodingInterface().AllowNonrecoverablePart();} + bool RecoverablePartFirst() const + {return this->GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + // Coverity finding on potential overflow/underflow. + size_t MessageRepresentativeBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().ImageBound().BitCount(),1U);} + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Trapdoor Function (TF) Signer base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_SignerBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_SignerBase() {} + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const; + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const; +}; + +/// \brief Trapdoor Function (TF) Verifier base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_VerifierBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const; + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &recoveryAccumulator) const; +}; + +// ******************************************************** + +/// \brief Trapdoor Function (TF) scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +template +struct TF_CryptoSchemeOptions +{ + typedef T1 AlgorithmInfo; + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; + typedef T3 MessageEncodingMethod; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +/// \tparam T4 HashTransformation class +template +struct TF_SignatureSchemeOptions : public TF_CryptoSchemeOptions +{ + typedef T4 HashFunction; +}; + +/// \brief Trapdoor Function (TF) base implementation +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +template +class CRYPTOPP_NO_VTABLE TF_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImplBase() {} + + PublicKey & AccessPublicKey() {return AccessKey();} + const PublicKey & GetPublicKey() const {return GetKey();} + + PrivateKey & AccessPrivateKey() {return AccessKey();} + const PrivateKey & GetPrivateKey() const {return GetKey();} + + virtual const KeyClass & GetKey() const =0; + virtual KeyClass & AccessKey() =0; + + const KeyClass & GetTrapdoorFunction() const {return GetKey();} + + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + CRYPTOPP_UNUSED(rng); + return new PK_MessageAccumulatorImpl; + } + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } + +protected: + const typename BASE::MessageEncodingInterface & GetMessageEncodingInterface() const + {return Singleton().Ref();} + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const + {return GetKey();} + const typename BASE::TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const + {return GetKey();} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup::template HashIdentifierLookup2 L; + return L::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } +}; + +/// \brief Trapdoor Function (TF) signature with external reference +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY key class +/// \details TF_ObjectImplExtRef() holds a pointer to an external key structure +template +class TF_ObjectImplExtRef : public TF_ObjectImplBase +{ +public: + virtual ~TF_ObjectImplExtRef() {} + + TF_ObjectImplExtRef(const KEY *pKey = NULLPTR) : m_pKey(pKey) {} + void SetKeyPtr(const KEY *pKey) {m_pKey = pKey;} + + const KEY & GetKey() const {return *m_pKey;} + KEY & AccessKey() {throw NotImplemented("TF_ObjectImplExtRef: cannot modify refererenced key");} + +private: + const KEY * m_pKey; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +/// \details TF_ObjectImpl() holds a reference to a trapdoor function +template +class CRYPTOPP_NO_VTABLE TF_ObjectImpl : public TF_ObjectImplBase +{ +public: + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImpl() {} + + const KeyClass & GetKey() const {return m_trapdoorFunction;} + KeyClass & AccessKey() {return m_trapdoorFunction;} + +private: + KeyClass m_trapdoorFunction; +}; + +/// \brief Trapdoor Function (TF) decryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_DecryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_EncryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_SignerImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_VerifierImpl : public TF_ObjectImpl +{ +}; + +// ******************************************************** + +/// \brief Mask generation function interface +/// \sa P1363_KDF2, P1363_MGF1 +/// \since Crypto++ 2.0 +class CRYPTOPP_NO_VTABLE MaskGeneratingFunction +{ +public: + virtual ~MaskGeneratingFunction() {} + + /// \brief Generate and apply mask + /// \param hash HashTransformation derived class + /// \param output the destination byte array + /// \param outputLength the size fo the the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param mask flag indicating whether to apply the mask + virtual void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const =0; +}; + +/// \fn P1363_MGF1KDF2_Common +/// \brief P1363 mask generation function +/// \param hash HashTransformation derived class +/// \param output the destination byte array +/// \param outputLength the size fo the the destination byte array +/// \param input the message to hash +/// \param inputLength the size of the message +/// \param derivationParams additional derivation parameters +/// \param derivationParamsLength the size of the additional derivation parameters +/// \param mask flag indicating whether to apply the mask +/// \param counterStart starting counter value used in generation function +CRYPTOPP_DLL void CRYPTOPP_API P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength, bool mask, unsigned int counterStart); + +/// \brief P1363 mask generation function +/// \sa P1363_KDF2, MaskGeneratingFunction +/// \since Crypto++ 2.0 +class P1363_MGF1 : public MaskGeneratingFunction +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "MGF1";} + + /// \brief P1363 mask generation function + /// \param hash HashTransformation derived class + /// \param output the destination byte array + /// \param outputLength the size fo the the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param mask flag indicating whether to apply the mask + void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const + { + P1363_MGF1KDF2_Common(hash, output, outputLength, input, inputLength, NULLPTR, 0, mask, 0); + } +}; + +// ******************************************************** + +/// \brief P1363 key derivation function +/// \tparam H hash function used in the derivation +/// \sa P1363_MGF1, KeyDerivationFunction, P1363_KDF2 +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class P1363_KDF2 +{ +public: + /// \brief P1363 key derivation function + /// \param output the destination byte array + /// \param outputLength the size fo the the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param derivationParams additional derivation parameters + /// \param derivationParamsLength the size of the additional derivation parameters + /// \details DeriveKey calls P1363_MGF1KDF2_Common + static void CRYPTOPP_API DeriveKey(byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength) + { + H h; + P1363_MGF1KDF2_Common(h, output, outputLength, input, inputLength, derivationParams, derivationParamsLength, false, 1); + } +}; + +// ******************************************************** + +/// \brief Exception thrown when an invalid group element is encountered +/// \details Thrown by DecodeElement and AgreeWithStaticPrivateKey +class DL_BadElement : public InvalidDataFormat +{ +public: + DL_BadElement() : InvalidDataFormat("CryptoPP: invalid group element") {} +}; + +/// \brief Interface for Discrete Log (DL) group parameters +/// \tparam T element in the group +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_GroupParameters : public CryptoParameters +{ + typedef DL_GroupParameters ThisClass; + +public: + typedef T Element; + + virtual ~DL_GroupParameters() {} + + DL_GroupParameters() : m_validationLevel(0) {} + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + if (!GetBasePrecomputation().IsInitialized()) + return false; + + if (m_validationLevel > level) + return true; + + CRYPTOPP_ASSERT(ValidateGroup(rng, level)); + bool pass = ValidateGroup(rng, level); + CRYPTOPP_ASSERT(ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation())); + pass = pass && ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation()); + + m_validationLevel = pass ? level+1 : 0; + + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; + } + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + bool SupportsPrecomputation() const {return true;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throw NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + void Precompute(unsigned int precomputationStorage=16) + { + AccessBasePrecomputation().Precompute(GetGroupPrecomputation(), GetSubgroupOrder().BitCount(), precomputationStorage); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessBasePrecomputation().Load(GetGroupPrecomputation(), storedPrecomputation); + m_validationLevel = 0; + } + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetBasePrecomputation().Save(GetGroupPrecomputation(), storedPrecomputation); + } + + /// \brief Retrieves the subgroup generator + /// \return the subgroup generator + /// \details The subgroup generator is retrieved from the base precomputation + virtual const Element & GetSubgroupGenerator() const {return GetBasePrecomputation().GetBase(GetGroupPrecomputation());} + + /// \brief Sets the subgroup generator + /// \param base the new subgroup generator + /// \details The subgroup generator is set in the base precomputation + virtual void SetSubgroupGenerator(const Element &base) {AccessBasePrecomputation().SetBase(GetGroupPrecomputation(), base);} + + /// \brief Exponentiates the base + /// \return the element after exponentiation + /// \details ExponentiateBase() calls GetBasePrecomputation() and then exponentiates. + virtual Element ExponentiateBase(const Integer &exponent) const + { + return GetBasePrecomputation().Exponentiate(GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param base the base elemenet + /// \param exponent the exponent to raise the base + /// \return the result of the exponentiation + /// \details Internally, ExponentiateElement() calls SimultaneousExponentiate(). + virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const + { + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; + } + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + virtual const DL_GroupPrecomputation & GetGroupPrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + virtual const DL_FixedBasePrecomputation & GetBasePrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + virtual DL_FixedBasePrecomputation & AccessBasePrecomputation() =0; + + /// \brief Retrieves the subgroup order + /// \return the order of subgroup generated by the base element + virtual const Integer & GetSubgroupOrder() const =0; + + /// \brief Retrieves the maximum exponent for the group + /// \return the maximum exponent for the group + virtual Integer GetMaxExponent() const =0; + + /// \brief Retrieves the order of the group + /// \return the order of the group + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetGroupOrder() const {return GetSubgroupOrder()*GetCofactor();} + + /// \brief Retrieves the cofactor + /// \return the cofactor + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetCofactor() const {return GetGroupOrder()/GetSubgroupOrder();} + + /// \brief Retrieves the encoded element's size + /// \param reversible flag indicating the encoding format + /// \return encoded element's size, in bytes + /// \details The format of the encoded element varies by the underlying type of the element and the + /// reversible flag. GetEncodedElementSize() must be implemented in a derived class. + /// \sa GetEncodedElementSize(), EncodeElement(), DecodeElement() + virtual unsigned int GetEncodedElementSize(bool reversible) const =0; + + /// \brief Encodes the element + /// \param reversible flag indicating the encoding format + /// \param element reference to the element to encode + /// \param encoded destination byte array for the encoded element + /// \details EncodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0; + + /// \brief Decodes the element + /// \param encoded byte array with the encoded element + /// \param checkForGroupMembership flag indicating if the element should be validated + /// \return Element after decoding + /// \details DecodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0; + + /// \brief Converts an element to an Integer + /// \param element the element to convert to an Integer + /// \return Element after converting to an Integer + /// \details ConvertElementToInteger() must be implemented in a derived class. + virtual Integer ConvertElementToInteger(const Element &element) const =0; + + /// \brief Check the group for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \details ValidateGroup() must be implemented in a derived class. + virtual bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check the element for errors + /// \param level level of thoroughness + /// \param element element to check + /// \param precomp optional pointer to DL_FixedBasePrecomputation + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 performs group membership checks. Level 1 may not check for weak keys and such. + /// Levels 2 and 3 are recommended. + /// \details ValidateElement() must be implemented in a derived class. + virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const =0; + + virtual bool FastSubgroupCheckAvailable() const =0; + + /// \brief Determines if an element is an identity + /// \param element element to check + /// \return true if the element is an identity, false otherwise + /// \details The identity element or or neutral element is a special element in a group that leaves + /// other elements unchanged when combined with it. + /// \details IsIdentity() must be implemented in a derived class. + virtual bool IsIdentity(const Element &element) const =0; + + /// \brief Exponentiates a base to multiple exponents + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const =0; + +protected: + void ParametersChanged() {m_validationLevel = 0;} + +private: + mutable unsigned int m_validationLevel; +}; + +/// \brief Base implementation of Discrete Log (DL) group parameters +/// \tparam GROUP_PRECOMP group precomputation class +/// \tparam BASE_PRECOMP fixed base precomputation class +/// \tparam BASE class or type of an element +template , class BASE = DL_GroupParameters > +class DL_GroupParametersImpl : public BASE +{ +public: + typedef GROUP_PRECOMP GroupPrecomputation; + typedef typename GROUP_PRECOMP::Element Element; + typedef BASE_PRECOMP BasePrecomputation; + + virtual ~DL_GroupParametersImpl() {} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + const DL_GroupPrecomputation & GetGroupPrecomputation() const {return m_groupPrecomputation;} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return m_gpc;} + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return m_gpc;} + +protected: + GROUP_PRECOMP m_groupPrecomputation; + BASE_PRECOMP m_gpc; +}; + +/// \brief Base class for a Discrete Log (DL) key +/// \tparam T class or type of an element +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_Key +{ +public: + virtual ~DL_Key() {} + + /// \brief Retrieves abstract group parameters + /// \return a const reference to the group parameters + virtual const DL_GroupParameters & GetAbstractGroupParameters() const =0; + /// \brief Retrieves abstract group parameters + /// \return a non-const reference to the group parameters + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; +}; + +/// \brief Interface for Discrete Log (DL) public keys +template +class CRYPTOPP_NO_VTABLE DL_PublicKey : public DL_Key +{ + typedef DL_PublicKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PublicKey(); + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicElement); + } + + /// \brief Initialize or reinitialize this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source); + + /// \brief Retrieves the public element + /// \return the public element + virtual const Element & GetPublicElement() const {return GetPublicPrecomputation().GetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation());} + + /// \brief Sets the public element + /// \param y the public element + virtual void SetPublicElement(const Element &y) {AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + /// \brief Exponentiates this element + /// \param exponent the exponent to raise the base + /// \return the public element raised to the exponent + virtual Element ExponentiatePublicElement(const Integer &exponent) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return GetPublicPrecomputation().Exponentiate(params.GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param baseExp the first exponent + /// \param publicExp the second exponent + /// \return the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiateBaseAndPublicElement(const Integer &baseExp, const Integer &publicExp) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return params.GetBasePrecomputation().CascadeExponentiate(params.GetGroupPrecomputation(), baseExp, GetPublicPrecomputation(), publicExp); + } + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual const DL_FixedBasePrecomputation & GetPublicPrecomputation() const =0; + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual DL_FixedBasePrecomputation & AccessPublicPrecomputation() =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKey::~DL_PublicKey() {} + +/// \brief Interface for Discrete Log (DL) private keys +template +class CRYPTOPP_NO_VTABLE DL_PrivateKey : public DL_Key +{ + typedef DL_PrivateKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PrivateKey(); + + /// \brief Initializes a public key from this key + /// \param pub reference to a public key + void MakePublicKey(DL_PublicKey &pub) const + { + pub.AccessAbstractGroupParameters().AssignFrom(this->GetAbstractGroupParameters()); + pub.SetPublicElement(this->GetAbstractGroupParameters().ExponentiateBase(GetPrivateExponent())); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Initialize or reinitialize this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source) + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Retrieves the private exponent + /// \return the private exponent + /// \details Must be overridden in derived classes. + virtual const Integer & GetPrivateExponent() const =0; + /// \brief Sets the private exponent + /// \param x the private exponent + /// \details Must be overridden in derived classes. + virtual void SetPrivateExponent(const Integer &x) =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey::~DL_PrivateKey() {} + +template +void DL_PublicKey::AssignFrom(const NameValuePairs &source) +{ + DL_PrivateKey *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } +} + +class OID; + +/// \brief Discrete Log (DL) key base implementation +/// \tparam PK Key class +/// \tparam GP GroupParameters class +/// \tparam O OID class +template +class DL_KeyImpl : public PK +{ +public: + typedef GP GroupParameters; + + virtual ~DL_KeyImpl() {} + + O GetAlgorithmID() const {return GetGroupParameters().GetAlgorithmID();} + bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {AccessGroupParameters().BERDecode(bt); return true;} + bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {GetGroupParameters().DEREncode(bt); return true;} + + const GP & GetGroupParameters() const {return m_groupParameters;} + GP & AccessGroupParameters() {return m_groupParameters;} + +private: + GP m_groupParameters; +}; + +class X509PublicKey; +class PKCS8PrivateKey; + +/// \brief Discrete Log (DL) private key base implementation +/// \tparam GP GroupParameters class +template +class DL_PrivateKeyImpl : public DL_PrivateKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PrivateKeyImpl() {} + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + CRYPTOPP_ASSERT(GetAbstractGroupParameters().Validate(rng, level)); + bool pass = GetAbstractGroupParameters().Validate(rng, level); + + const Integer &q = GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = GetPrivateExponent(); + + CRYPTOPP_ASSERT(x.IsPositive()); + CRYPTOPP_ASSERT(x < q); + pass = pass && x.IsPositive() && x < q; + + if (level >= 1) + { + CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One()); + pass = pass && Integer::Gcd(x, q) == Integer::One(); + } + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + if (!params.GetThisObject(this->AccessGroupParameters())) + this->AccessGroupParameters().GenerateRandom(rng, params); + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + SetPrivateExponent(x); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + {AccessAbstractGroupParameters().Precompute(precomputationStorage);} + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation);} + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation);} + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PrivateKey + const Integer & GetPrivateExponent() const {return m_x;} + void SetPrivateExponent(const Integer &x) {m_x = x;} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool, size_t) + {m_x.BERDecode(bt);} + void DEREncodePrivateKey(BufferedTransformation &bt) const + {m_x.DEREncode(bt);} + +private: + Integer m_x; +}; + +template +class DL_PrivateKey_WithSignaturePairwiseConsistencyTest : public BASE +{ +public: + virtual ~DL_PrivateKey_WithSignaturePairwiseConsistencyTest() {} + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + BASE::GenerateRandom(rng, params); + + if (FIPS_140_2_ComplianceEnabled()) + { + typename SIGNATURE_SCHEME::Signer signer(*this); + typename SIGNATURE_SCHEME::Verifier verifier(signer); + SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier); + } + } +}; + +/// \brief Discrete Log (DL) public key base implementation +/// \tparam GP GroupParameters class +template +class DL_PublicKeyImpl : public DL_PublicKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PublicKeyImpl(); + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + CRYPTOPP_ASSERT(GetAbstractGroupParameters().Validate(rng, level)); + bool pass = GetAbstractGroupParameters().Validate(rng, level); + CRYPTOPP_ASSERT(GetAbstractGroupParameters().ValidateElement(level, this->GetPublicElement(), &GetPublicPrecomputation())); + pass = pass && GetAbstractGroupParameters().ValidateElement(level, this->GetPublicElement(), &GetPublicPrecomputation()); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + { + AccessAbstractGroupParameters().Precompute(precomputationStorage); + AccessPublicPrecomputation().Precompute(GetAbstractGroupParameters().GetGroupPrecomputation(), GetAbstractGroupParameters().GetSubgroupOrder().BitCount(), precomputationStorage); + } + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation); + AccessPublicPrecomputation().Load(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation); + GetPublicPrecomputation().Save(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PublicKey + const DL_FixedBasePrecomputation & GetPublicPrecomputation() const {return m_ypc;} + DL_FixedBasePrecomputation & AccessPublicPrecomputation() {return m_ypc;} + + // non-inherited + bool operator==(const DL_PublicKeyImpl &rhs) const + {return this->GetGroupParameters() == rhs.GetGroupParameters() && this->GetPublicElement() == rhs.GetPublicElement();} + +private: + typename GP::BasePrecomputation m_ypc; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKeyImpl::~DL_PublicKeyImpl() {} + +/// \brief Interface for Elgamal-like signature algorithms +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_ElgamalLikeSignatureAlgorithm +{ +public: + virtual ~DL_ElgamalLikeSignatureAlgorithm() {} + + /// \brief Sign a message using a private key + /// \param params GroupParameters + /// \param privateKey private key + /// \param k signing exponent + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual void Sign(const DL_GroupParameters ¶ms, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; + + /// \brief Verify a message using a public key + /// \param params GroupParameters + /// \param publicKey public key + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0; + + /// \brief Recover a Presignature + /// \param params GroupParameters + /// \param publicKey public key + /// \param r r part of signature + /// \param s s part of signature + virtual Integer RecoverPresignature(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &r, const Integer &s) const + { + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(publicKey); CRYPTOPP_UNUSED(r); CRYPTOPP_UNUSED(s); + throw NotImplemented("DL_ElgamalLikeSignatureAlgorithm: this signature scheme does not support message recovery"); + MAYBE_RETURN(Integer::Zero()); + } + + /// \brief Retrieve R length + /// \param params GroupParameters + virtual size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Retrieve S length + /// \param params GroupParameters + virtual size_t SLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Signature scheme flag + /// \return true if the signature scheme is deterministic, false otherwise + /// \details IsDeterministic() is provided for DL signers. It is used by RFC 6979 signature schemes. + virtual bool IsDeterministic() const + {return false;} +}; + +/// \brief Interface for deterministic signers +/// \details RFC 6979 signers which generate k based on the encoded message and private key +class CRYPTOPP_NO_VTABLE DeterministicSignatureAlgorithm +{ +public: + virtual ~DeterministicSignatureAlgorithm() {} + + /// \brief Generate k + /// \param x private key + /// \param q subgroup generator + /// \param e encoded message + virtual Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const =0; +}; + +/// \brief Interface for DL key agreement algorithms +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_KeyAgreementAlgorithm +{ +public: + typedef T Element; + + virtual ~DL_KeyAgreementAlgorithm() {} + + virtual Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const =0; + virtual Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const =0; +}; + +/// \brief Interface for key derivation algorithms used in DL cryptosystems +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs &derivationParams) const =0; +}; + +/// \brief Interface for symmetric encryption algorithms used in DL cryptosystems +class CRYPTOPP_NO_VTABLE DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_SymmetricEncryptionAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual size_t GetSymmetricKeyLength(size_t plaintextLength) const =0; + virtual size_t GetSymmetricCiphertextLength(size_t plaintextLength) const =0; + virtual size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const =0; + virtual void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const =0; + virtual DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const =0; +}; + +/// \brief Discrete Log (DL) base interface +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_Base +{ +protected: + typedef KI KeyInterface; + typedef typename KI::Element Element; + + virtual ~DL_Base() {} + + const DL_GroupParameters & GetAbstractGroupParameters() const {return GetKeyInterface().GetAbstractGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return AccessKeyInterface().AccessAbstractGroupParameters();} + + virtual KeyInterface & AccessKeyInterface() =0; + virtual const KeyInterface & GetKeyInterface() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme base implementation +/// \tparam INTFACE PK_Signer or PK_Verifier derived class +/// \tparam KEY_INTFACE DL_Base key base used in the scheme +/// \details DL_SignatureSchemeBase provides common functions for signers and verifiers. +/// DL_Base is used for signers, and DL_Base is used for verifiers. +template +class CRYPTOPP_NO_VTABLE DL_SignatureSchemeBase : public INTFACE, public DL_Base +{ +public: + virtual ~DL_SignatureSchemeBase() {} + + /// \brief Provides the signature length + /// \return signature length, in bytes + /// \details SignatureLength returns the size required for r+s. + size_t SignatureLength() const + { + return GetSignatureAlgorithm().RLen(this->GetAbstractGroupParameters()) + + GetSignatureAlgorithm().SLen(this->GetAbstractGroupParameters()); + } + + /// \brief Provides the maximum recoverable length + /// \return maximum recoverable length, in bytes + size_t MaxRecoverableLength() const + {return GetMessageEncodingInterface().MaxRecoverableLength(0, GetHashIdentifier().second, GetDigestSize());} + + /// \brief Provides the maximum recoverable length + /// \param signatureLength the size fo the signature + /// \return maximum recoverable length based on signature length, in bytes + /// \details this function is not implemented and always returns 0. + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); CRYPTOPP_ASSERT(false); return 0;} // TODO + + /// \brief Determines if the scheme is probabilistic + /// \return true if the scheme is probabilistic, false otherwise + bool IsProbabilistic() const + {return true;} + + /// \brief Determines if the scheme has non-recoverable part + /// \return true if the message encoding has a non-recoverable part, false otherwise. + bool AllowNonrecoverablePart() const + {return GetMessageEncodingInterface().AllowNonrecoverablePart();} + + /// \brief Determines if the scheme allows recoverable part first + /// \return true if the message encoding allows the recoverable part, false otherwise. + bool RecoverablePartFirst() const + {return GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + size_t MessageRepresentativeBitLength() const {return this->GetAbstractGroupParameters().GetSubgroupOrder().BitCount();} + + // true if the scheme conforms to RFC 6979 + virtual bool IsDeterministic() const {return false;} + + virtual const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const =0; + virtual const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const =0; + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme signer base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_SignerBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_SignerBase() {} + + /// \brief Testing interface + /// \param k Integer + /// \param e Integer + /// \param r Integer + /// \param s Integer + void RawSign(const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + r = params.ConvertElementToInteger(params.ExponentiateBase(k)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + this->GetMessageEncodingInterface().ProcessRecoverableMessage(ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature); + } + + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + // hash message digest into random number k to prevent reusing the same k on + // different messages after virtual machine rollback + if (rng.CanIncorporateEntropy()) + rng.IncorporateEntropy(representative, representative.size()); + + Integer k, ks; + const Integer& q = params.GetSubgroupOrder(); + if (alg.IsDeterministic()) + { + const Integer& x = key.GetPrivateExponent(); + const DeterministicSignatureAlgorithm& det = dynamic_cast(alg); + k = det.GenerateRandom(x, q, e); + } + else + { + k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + } + + // Due to timing attack on nonce length by Jancar + // https://github.com/weidai11/cryptopp/issues/869 + ks = k + q; + if (ks.BitCount() == q.BitCount()) { + ks += q; + } + + Integer r, s; + r = params.ConvertElementToInteger(params.ExponentiateBase(ks)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + + /* + Integer r, s; + if (this->MaxRecoverableLength() > 0) + r.Decode(ma.m_semisignature, ma.m_semisignature.size()); + else + r.Decode(ma.m_presignature, ma.m_presignature.size()); + alg.Sign(params, key.GetPrivateExponent(), ma.m_k, e, r, s); + */ + + const size_t rLen = alg.RLen(params); + r.Encode(signature, rLen); + s.Encode(signature+rLen, alg.SLen(params)); + + if (restart) + RestartMessageAccumulator(rng, ma); + + return this->SignatureLength(); + } + +protected: + void RestartMessageAccumulator(RandomNumberGenerator &rng, PK_MessageAccumulatorBase &ma) const + { + // k needs to be generated before hashing for signature schemes with recovery + // but to defend against VM rollbacks we need to generate k after hashing. + // so this code is commented out, since no DL-based signature scheme with recovery + // has been implemented in Crypto++ anyway + /* + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + ma.m_k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + ma.m_presignature.New(params.GetEncodedElementSize(false)); + params.ConvertElementToInteger(params.ExponentiateBase(ma.m_k)).Encode(ma.m_presignature, ma.m_presignature.size()); + */ + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(ma); + } +}; + +/// \brief Discret Log (DL) Verifier base class +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_VerifierBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + + // Validation due to https://github.com/weidai11/cryptopp/issues/981 + // We allow a caller to provide R and S in oversized buffer. R and S + // are read based on the field element size, and not the buffer size. + const size_t rLen = alg.RLen(params); + const size_t sLen = alg.SLen(params); + CRYPTOPP_ASSERT(signatureLength >= rLen + sLen); + if (signatureLength < rLen + sLen) + throw InvalidDataFormat("DL_VerifierBase: signature length is not valid."); + + ma.m_semisignature.Assign(signature, rLen); + ma.m_s.Decode(signature+rLen, sLen); + + this->GetMessageEncodingInterface().ProcessSemisignature(ma.AccessHash(), ma.m_semisignature, ma.m_semisignature.size()); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative(NullRNG(), ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + return alg.Verify(params, key, e, r, ma.m_s); + } + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + NullRNG(), + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + ma.m_presignature.New(params.GetEncodedElementSize(false)); + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + alg.RecoverPresignature(params, key, r, ma.m_s).Encode(ma.m_presignature, ma.m_presignature.size()); + + return this->GetMessageEncodingInterface().RecoverMessageFromSemisignature( + ma.AccessHash(), this->GetHashIdentifier(), + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature, ma.m_semisignature.size(), + recoveredMessage); + } +}; + +/// \brief Discrete Log (DL) cryptosystem base implementation +/// \tparam PK field element type +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_CryptoSystemBase : public PK, public DL_Base +{ +public: + typedef typename DL_Base::Element Element; + + virtual ~DL_CryptoSystemBase() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + { + unsigned int minLen = this->GetAbstractGroupParameters().GetEncodedElementSize(true); + return ciphertextLength < minLen ? 0 : GetSymmetricEncryptionAlgorithm().GetMaxSymmetricPlaintextLength(ciphertextLength - minLen); + } + + size_t CiphertextLength(size_t plaintextLength) const + { + size_t len = GetSymmetricEncryptionAlgorithm().GetSymmetricCiphertextLength(plaintextLength); + return len == 0 ? 0 : this->GetAbstractGroupParameters().GetEncodedElementSize(true) + len; + } + + bool ParameterSupported(const char *name) const + {return GetKeyDerivationAlgorithm().ParameterSupported(name) || GetSymmetricEncryptionAlgorithm().ParameterSupported(name);} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const =0; + virtual const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const =0; +}; + +/// \brief Discrete Log (DL) decryptor base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_DecryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + try + { + CRYPTOPP_UNUSED(rng); + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + Element q = params.DecodeElement(ciphertext, true); + size_t elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + ciphertextLength -= elementSize; + + Element z = agreeAlg.AgreeWithStaticPrivateKey(params, q, true, key.GetPrivateExponent()); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(encAlg.GetMaxSymmetricPlaintextLength(ciphertextLength))); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + return encAlg.SymmetricDecrypt(derivedKey, ciphertext, ciphertextLength, plaintext, parameters); + } + catch (DL_BadElement &) + { + return DecodingResult(); + } + } +}; + +/// \brief Discrete Log (DL) encryptor base implementation +/// \tparam T Field element +template +class CRYPTOPP_NO_VTABLE DL_EncryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + Integer x(rng, Integer::One(), params.GetMaxExponent()); + Element q = params.ExponentiateBase(x); + params.EncodeElement(true, q, ciphertext); + unsigned int elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + + Element z = agreeAlg.AgreeWithEphemeralPrivateKey(params, key.GetPublicPrecomputation(), x); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(plaintextLength)); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + encAlg.SymmetricEncrypt(rng, derivedKey, plaintext, plaintextLength, ciphertext, parameters); + } +}; + +/// \brief Discrete Log (DL) scheme options +/// \tparam T1 algorithm information +/// \tparam T2 group parameters for the scheme +template +struct DL_SchemeOptionsBase +{ + typedef T1 AlgorithmInfo; + typedef T2 GroupParameters; + typedef typename GroupParameters::Element Element; +}; + +/// \brief Discrete Log (DL) key options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +template +struct DL_KeyedSchemeOptions : public DL_SchemeOptionsBase +{ + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; +}; + +/// \brief Discrete Log (DL) signature scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 signature algorithm +/// \tparam T4 message encoding method +/// \tparam T5 hash function +template +struct DL_SignatureSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 SignatureAlgorithm; + typedef T4 MessageEncodingMethod; + typedef T5 HashFunction; +}; + +/// \brief Discrete Log (DL) crypto scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 key agreement algorithm +/// \tparam T4 key derivation algorithm +/// \tparam T5 symmetric encryption algorithm +template +struct DL_CryptoSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 KeyAgreementAlgorithm; + typedef T4 KeyDerivationAlgorithm; + typedef T5 SymmetricEncryptionAlgorithm; +}; + +/// \brief Discrete Log (DL) base object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImplBase() {} + + PrivateKey & AccessPrivateKey() {return m_key;} + PublicKey & AccessPublicKey() {return m_key;} + + // KeyAccessor + const KEY & GetKey() const {return m_key;} + KEY & AccessKey() {return m_key;} + +protected: + typename BASE::KeyInterface & AccessKeyInterface() {return m_key;} + const typename BASE::KeyInterface & GetKeyInterface() const {return m_key;} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup HashLookup; + return HashLookup::template HashIdentifierLookup2::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } + +private: + KEY m_key; +}; + +/// \brief Discrete Log (DL) object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImpl : public DL_ObjectImplBase +{ +public: + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImpl() {} + +protected: + const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const + {return Singleton().Ref();} + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const + {return Singleton().Ref();} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const + {return Singleton().Ref();} + HashIdentifier GetHashIdentifier() const + {return HashIdentifier();} + const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const + {return Singleton().Ref();} +}; + +/// \brief Discrete Log (DL) signer implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_SignerImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +public: + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + member_ptr p(new PK_MessageAccumulatorImpl); + this->RestartMessageAccumulator(rng, *p); + return p.release(); + } +}; + +/// \brief Discrete Log (DL) verifier implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_VerifierImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +public: + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } +}; + +/// \brief Discrete Log (DL) encryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_EncryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +}; + +/// \brief Discrete Log (DL) decryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_DecryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +}; + +// ******************************************************** + +/// \brief Discrete Log (DL) simple key agreement base implementation +/// \tparam T class or type +template +class CRYPTOPP_NO_VTABLE DL_SimpleKeyAgreementDomainBase : public SimpleKeyAgreementDomain +{ +public: + typedef T Element; + + virtual ~DL_SimpleKeyAgreementDomainBase() {} + + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + unsigned int PrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + unsigned int PublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, PrivateKeyLength()); + } + + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element w = params.DecodeElement(otherPublicKey, validateOtherPublicKey); + + Element z = GetKeyAgreementAlgorithm().AgreeWithStaticPrivateKey( + GetAbstractGroupParameters(), w, validateOtherPublicKey, x); + params.EncodeElement(false, z, agreedValue); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + + /// \brief Retrieves a reference to the group generator + /// \return const reference to the group generator + const Element &GetGenerator() const {return GetAbstractGroupParameters().GetSubgroupGenerator();} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; + const DL_GroupParameters & GetAbstractGroupParameters() const {return const_cast *>(this)->AccessAbstractGroupParameters();} +}; + +/// \brief Methods for avoiding "Small-Subgroup" attacks on Diffie-Hellman Key Agreement +/// \details Additional methods exist and include public key validation and choice of prime p. +/// \sa Methods for Avoiding the "Small-Subgroup" Attacks on the +/// Diffie-Hellman Key Agreement Method for S/MIME +enum CofactorMultiplicationOption { + /// \brief No cofactor multiplication applied + NO_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication compatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations and is + /// compatible with ordinary Diffie-Hellman. + COMPATIBLE_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication incompatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations but is + /// not compatible with ordinary Diffie-Hellman. + INCOMPATIBLE_COFACTOR_MULTIPLICTION}; + +typedef EnumToType NoCofactorMultiplication; +typedef EnumToType CompatibleCofactorMultiplication; +typedef EnumToType IncompatibleCofactorMultiplication; + +/// \brief Diffie-Hellman key agreement algorithm +template +class DL_KeyAgreementAlgorithm_DH : public DL_KeyAgreementAlgorithm +{ +public: + typedef ELEMENT Element; + + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() + {return COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? "DHC" : "DH";} + + virtual ~DL_KeyAgreementAlgorithm_DH() {} + + Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const + { + return publicPrecomputation.Exponentiate(params.GetGroupPrecomputation(), + COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? privateExponent*params.GetCofactor() : privateExponent); + } + + Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const + { + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + { + const Integer &k = params.GetCofactor(); + return params.ExponentiateElement(publicElement, + ModularArithmetic(params.GetSubgroupOrder()).Divide(privateExponent, k)*k); + } + else if (COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION) + return params.ExponentiateElement(publicElement, privateExponent*params.GetCofactor()); + else + { + CRYPTOPP_ASSERT(COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION); + + if (!validateOtherPublicKey) + return params.ExponentiateElement(publicElement, privateExponent); + + if (params.FastSubgroupCheckAvailable()) + { + if (!params.ValidateElement(2, publicElement, NULLPTR)) + throw DL_BadElement(); + return params.ExponentiateElement(publicElement, privateExponent); + } + else + { + const Integer e[2] = {params.GetSubgroupOrder(), privateExponent}; + Element r[2]; + params.SimultaneousExponentiate(r, publicElement, e, 2); + if (!params.IsIdentity(r[0])) + throw DL_BadElement(); + return r[1]; + } + } + } +}; + +// ******************************************************** + +/// \brief Template implementing constructors for public key algorithm classes +template +class CRYPTOPP_NO_VTABLE PK_FinalTemplate : public BASE +{ +public: + PK_FinalTemplate() {} + + PK_FinalTemplate(const CryptoMaterial &key) + {this->AccessKey().AssignFrom(key);} + + PK_FinalTemplate(BufferedTransformation &bt) + {this->AccessKey().BERDecode(bt);} + + PK_FinalTemplate(const AsymmetricAlgorithm &algorithm) + {this->AccessKey().AssignFrom(algorithm.GetMaterial());} + + PK_FinalTemplate(const Integer &v1) + {this->AccessKey().Initialize(v1);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} +}; + +/// \brief Base class for public key encryption standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct EncryptionStandard {}; + +/// \brief Base class for public key signature standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct SignatureStandard {}; + +/// \brief Trapdoor Function (TF) encryption scheme +/// \tparam STANDARD standard +/// \tparam KEYS keys used in the encryption scheme +/// \tparam ALG_INFO algorithm information +template +class TF_ES; + +template > +class TF_ES : public KEYS +{ + typedef typename STANDARD::EncryptionMessageEncodingMethod MessageEncodingMethod; + +public: + /// see EncryptionStandard for a list of standards + typedef STANDARD Standard; + typedef TF_CryptoSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName();} + + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +/// \brief Trapdoor Function (TF) Signature Scheme +/// \tparam STANDARD standard +/// \tparam H hash function +/// \tparam KEYS keys used in the signature scheme +/// \tparam ALG_INFO algorithm information +template +class TF_SS; + +template > +class TF_SS : public KEYS +{ +public: + /// see SignatureStandard for a list of standards + typedef STANDARD Standard; + typedef typename Standard::SignatureMessageEncodingMethod MessageEncodingMethod; + typedef TF_SignatureSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) signature scheme +/// \tparam KEYS keys used in the signature scheme +/// \tparam SA signature algorithm +/// \tparam MEM message encoding method +/// \tparam H hash function +/// \tparam ALG_INFO algorithm information +template +class DL_SS; + +template > +class DL_SS : public KEYS +{ + typedef DL_SignatureSchemeOptions SchemeOptions; + +public: + static std::string StaticAlgorithmName() {return SA::StaticAlgorithmName() + std::string("/EMSA1(") + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) encryption scheme +/// \tparam KEYS keys used in the encryption scheme +/// \tparam AA key agreement algorithm +/// \tparam DA key derivation algorithm +/// \tparam EA encryption algorithm +/// \tparam ALG_INFO algorithm information +template +class DL_ES : public KEYS +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + +public: + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/pwdbased.h b/extension/third_party/cryptopp/pwdbased.h new file mode 100644 index 00000000..f1e2c79f --- /dev/null +++ b/extension/third_party/cryptopp/pwdbased.h @@ -0,0 +1,481 @@ +// pwdbased.h - originally written and placed in the public domain by Wei Dai +// Cutover to KeyDerivationFunction interface by Uri Blumenthal +// Marcel Raad and Jeffrey Walton in March 2018. + +/// \file pwdbased.h +/// \brief Password based key derivation functions + +#ifndef CRYPTOPP_PWDBASED_H +#define CRYPTOPP_PWDBASED_H + +#include "cryptlib.h" +#include "hrtimer.h" +#include "integer.h" +#include "argnames.h" +#include "algparam.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +// ******************** PBKDF1 ******************** + +/// \brief PBKDF1 from PKCS #5 +/// \tparam T a HashTransformation class +/// \sa PasswordBasedKeyDerivationFunction, PKCS5_PBKDF1 +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF1() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF1(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(T::DIGESTSIZE); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + /// \details PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation + /// allows salts of any length. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF1::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + T hash; + hash.Update(secret, secretLen); + hash.Update(salt, saltLen); + + SecByteBlock buffer(hash.DigestSize()); + hash.Final(buffer); + + unsigned int i; + ThreadUserTimer timer; + + if (timeInSeconds) + timer.StartTimer(); + + for (i=1; iPKCS5_PBKDF2_HMAC +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF2_HMAC() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF2_HMAC(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + // should multiply by T::DIGESTSIZE, but gets overflow that way + size_t MaxDerivedKeyLength() const { + return 0xffffffffU; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF2_HMAC::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + // DigestSize check due to https://github.com/weidai11/cryptopp/issues/855 + HMAC hmac(secret, secretLen); + if (hmac.DigestSize() == 0) + throw InvalidArgument("PKCS5_PBKDF2_HMAC: DigestSize cannot be 0"); + + SecByteBlock buffer(hmac.DigestSize()); + ThreadUserTimer timer; + + unsigned int i=1; + while (derivedLen > 0) + { + hmac.Update(salt, saltLen); + unsigned int j; + for (j=0; j<4; j++) + { + byte b = byte(i >> ((3-j)*8)); + hmac.Update(&b, 1); + } + hmac.Final(buffer); + +#if CRYPTOPP_MSC_VERSION + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + std::memcpy(derived, buffer, segmentLen); +#endif + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size()); + timer.StartTimer(); + } + + for (j=1; jPKCS12_PBKDF +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS12_PBKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF_PKCS12(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // TODO - check this + size_t MaxDerivedKeyLength() const { + return static_cast(-1); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS12_PBKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + // NULL or 0 length salt OK + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12 + const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v); + const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen; + SecByteBlock buffer(DLen + SLen + PLen); + byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S; + + if (D) // GCC analyzer + std::memset(D, purpose, DLen); + + size_t i; + for (i=0; i 0) + { + hash.CalculateDigest(Ai, buffer, buffer.size()); + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size()); + timer.StartTimer(); + } + + for (i=1; i(), m_autoNodeSize(!nodeSize), m_nodeSize(nodeSize) + , m_head(NULLPTR), m_tail(NULLPTR), m_lazyString(NULLPTR), m_lazyLength(0), m_lazyStringModifiable(false) +{ + // See GH #962 for the reason for this assert. + CRYPTOPP_ASSERT(nodeSize != SIZE_MAX); + + SetNodeSize(nodeSize); + m_head = m_tail = new ByteQueueNode(m_nodeSize); +} + +void ByteQueue::SetNodeSize(size_t nodeSize) +{ + m_autoNodeSize = !nodeSize; + m_nodeSize = m_autoNodeSize ? 256 : nodeSize; +} + +ByteQueue::ByteQueue(const ByteQueue ©) + : Bufferless(copy), m_lazyString(NULLPTR), m_lazyLength(0) +{ + CopyFrom(copy); +} + +void ByteQueue::CopyFrom(const ByteQueue ©) +{ + m_lazyLength = 0; + m_autoNodeSize = copy.m_autoNodeSize; + m_nodeSize = copy.m_nodeSize; + m_head = m_tail = new ByteQueueNode(*copy.m_head); + + for (ByteQueueNode *current=copy.m_head->m_next; current; current=current->m_next) + { + m_tail->m_next = new ByteQueueNode(*current); + m_tail = m_tail->m_next; + } + + m_tail->m_next = NULLPTR; + + Put(copy.m_lazyString, copy.m_lazyLength); +} + +ByteQueue::~ByteQueue() +{ + Destroy(); +} + +void ByteQueue::Destroy() +{ + for (ByteQueueNode *next, *current=m_head; current; current=next) + { + next=current->m_next; + delete current; + } +} + +void ByteQueue::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256); + Clear(); +} + +lword ByteQueue::CurrentSize() const +{ + lword size=0; + + for (ByteQueueNode *current=m_head; current; current=current->m_next) + size += current->CurrentSize(); + + return size + m_lazyLength; +} + +bool ByteQueue::IsEmpty() const +{ + return m_head==m_tail && m_head->CurrentSize()==0 && m_lazyLength==0; +} + +void ByteQueue::Clear() +{ + for (ByteQueueNode *next, *current=m_head->m_next; current; current=next) + { + next=current->m_next; + delete current; + } + + m_tail = m_head; + m_head->Clear(); + m_head->m_next = NULLPTR; + m_lazyLength = 0; +} + +size_t ByteQueue::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + CRYPTOPP_UNUSED(messageEnd), CRYPTOPP_UNUSED(blocking); + + if (m_lazyLength > 0) + FinalizeLazyPut(); + + size_t len; + while ((len=m_tail->Put(inString, length)) < length) + { + inString = PtrAdd(inString, len); + length -= len; + if (m_autoNodeSize && m_nodeSize < s_maxAutoNodeSize) + { + do + { + m_nodeSize *= 2; + } + while (m_nodeSize < length && m_nodeSize < s_maxAutoNodeSize); + } + m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, length)); + m_tail = m_tail->m_next; + } + + return 0; +} + +void ByteQueue::CleanupUsedNodes() +{ + // Test for m_head due to Enterprise Anlysis finding + while (m_head && m_head != m_tail && m_head->UsedUp()) + { + ByteQueueNode *temp=m_head; + m_head=m_head->m_next; + delete temp; + } + + // Test for m_head due to Enterprise Anlysis finding + if (m_head && m_head->CurrentSize() == 0) + m_head->Clear(); +} + +void ByteQueue::LazyPut(const byte *inString, size_t size) +{ + if (m_lazyLength > 0) + FinalizeLazyPut(); + + if (inString == m_tail->m_buf+m_tail->m_tail) + Put(inString, size); + else + { + m_lazyString = const_cast(inString); + m_lazyLength = size; + m_lazyStringModifiable = false; + } +} + +void ByteQueue::LazyPutModifiable(byte *inString, size_t size) +{ + if (m_lazyLength > 0) + FinalizeLazyPut(); + m_lazyString = inString; + m_lazyLength = size; + m_lazyStringModifiable = true; +} + +void ByteQueue::UndoLazyPut(size_t size) +{ + if (m_lazyLength < size) + throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large"); + + m_lazyLength -= size; +} + +void ByteQueue::FinalizeLazyPut() +{ + size_t len = m_lazyLength; + m_lazyLength = 0; + if (len) + Put(m_lazyString, len); +} + +size_t ByteQueue::Get(byte &outByte) +{ + if (m_head->Get(outByte)) + { + if (m_head->UsedUp()) + CleanupUsedNodes(); + return 1; + } + else if (m_lazyLength > 0) + { + outByte = *m_lazyString++; + m_lazyLength--; + return 1; + } + else + return 0; +} + +size_t ByteQueue::Get(byte *outString, size_t getMax) +{ + ArraySink sink(outString, getMax); + return (size_t)TransferTo(sink, getMax); +} + +size_t ByteQueue::Peek(byte &outByte) const +{ + if (m_head->Peek(outByte)) + return 1; + else if (m_lazyLength > 0) + { + outByte = *m_lazyString; + return 1; + } + else + return 0; +} + +size_t ByteQueue::Peek(byte *outString, size_t peekMax) const +{ + ArraySink sink(outString, peekMax); + return (size_t)CopyTo(sink, peekMax); +} + +size_t ByteQueue::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + // No need for CRYPTOPP_ASSERT on transferBytes here. + // TransferTo2 handles LWORD_MAX as expected. + + if (blocking) + { + lword bytesLeft = transferBytes; + for (ByteQueueNode *current=m_head; bytesLeft && current; current=current->m_next) + bytesLeft -= current->TransferTo(target, bytesLeft, channel); + CleanupUsedNodes(); + + size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength); + if (len) + { + if (m_lazyStringModifiable) + target.ChannelPutModifiable(channel, m_lazyString, len); + else + target.ChannelPut(channel, m_lazyString, len); + m_lazyString = PtrAdd(m_lazyString, len); + m_lazyLength -= len; + bytesLeft -= len; + } + transferBytes -= bytesLeft; + return 0; + } + else + { + Walker walker(*this); + size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + Skip(transferBytes); + return blockedBytes; + } +} + +size_t ByteQueue::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + Walker walker(*this); + walker.Skip(begin); + lword transferBytes = end-begin; + + size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + begin += transferBytes; + return blockedBytes; +} + +void ByteQueue::Unget(byte inByte) +{ + Unget(&inByte, 1); +} + +void ByteQueue::Unget(const byte *inString, size_t length) +{ + // See GH #962 for the reason for this assert. + CRYPTOPP_ASSERT(length != SIZE_MAX); + + size_t len = STDMIN(length, m_head->m_head); + length -= len; + m_head->m_head = m_head->m_head - len; + memcpy(m_head->m_buf + m_head->m_head, inString + length, len); + + if (length > 0) + { + ByteQueueNode *newHead = new ByteQueueNode(length); + newHead->m_next = m_head; + m_head = newHead; + m_head->Put(inString, length); + } +} + +const byte * ByteQueue::Spy(size_t &contiguousSize) const +{ + contiguousSize = m_head->m_tail - m_head->m_head; + if (contiguousSize == 0 && m_lazyLength > 0) + { + contiguousSize = m_lazyLength; + return m_lazyString; + } + else + return m_head->m_buf + m_head->m_head; +} + +byte * ByteQueue::CreatePutSpace(size_t &size) +{ + // See GH #962 for the reason for this assert. + CRYPTOPP_ASSERT(size != SIZE_MAX); + // Sanity check for a reasonable size + CRYPTOPP_ASSERT(size <= 16U*1024*1024); + + if (m_lazyLength > 0) + FinalizeLazyPut(); + + if (m_tail->m_tail == m_tail->MaxSize()) + { + m_tail->m_next = new ByteQueueNode(STDMAX(m_nodeSize, size)); + m_tail = m_tail->m_next; + } + + size = m_tail->MaxSize() - m_tail->m_tail; + return PtrAdd(m_tail->m_buf.begin(), m_tail->m_tail); +} + +ByteQueue & ByteQueue::operator=(const ByteQueue &rhs) +{ + Destroy(); + CopyFrom(rhs); + return *this; +} + +bool ByteQueue::operator==(const ByteQueue &rhs) const +{ + const lword currentSize = CurrentSize(); + + if (currentSize != rhs.CurrentSize()) + return false; + + Walker walker1(*this), walker2(rhs); + byte b1, b2; + + while (walker1.Get(b1) && walker2.Get(b2)) + if (b1 != b2) + return false; + + return true; +} + +byte ByteQueue::operator[](lword i) const +{ + for (ByteQueueNode *current=m_head; current; current=current->m_next) + { + if (i < current->CurrentSize()) + return (*current)[(size_t)i]; + + i -= current->CurrentSize(); + } + + CRYPTOPP_ASSERT(i < m_lazyLength); + return m_lazyString[i]; +} + +void ByteQueue::swap(ByteQueue &rhs) +{ + std::swap(m_autoNodeSize, rhs.m_autoNodeSize); + std::swap(m_nodeSize, rhs.m_nodeSize); + std::swap(m_head, rhs.m_head); + std::swap(m_tail, rhs.m_tail); + std::swap(m_lazyString, rhs.m_lazyString); + std::swap(m_lazyLength, rhs.m_lazyLength); + std::swap(m_lazyStringModifiable, rhs.m_lazyStringModifiable); +} + +// ******************************************************** + +void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs ¶meters) +{ + CRYPTOPP_UNUSED(parameters); + + m_node = m_queue.m_head; + m_position = 0; + m_offset = 0; + m_lazyString = m_queue.m_lazyString; + m_lazyLength = m_queue.m_lazyLength; +} + +size_t ByteQueue::Walker::Get(byte &outByte) +{ + ArraySink sink(&outByte, 1); + return (size_t)TransferTo(sink, 1); +} + +size_t ByteQueue::Walker::Get(byte *outString, size_t getMax) +{ + ArraySink sink(outString, getMax); + return (size_t)TransferTo(sink, getMax); +} + +size_t ByteQueue::Walker::Peek(byte &outByte) const +{ + ArraySink sink(&outByte, 1); + return (size_t)CopyTo(sink, 1); +} + +size_t ByteQueue::Walker::Peek(byte *outString, size_t peekMax) const +{ + ArraySink sink(outString, peekMax); + return (size_t)CopyTo(sink, peekMax); +} + +size_t ByteQueue::Walker::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + // No need for CRYPTOPP_ASSERT on transferBytes here. + // TransferTo2 handles LWORD_MAX as expected. + + lword bytesLeft = transferBytes; + size_t blockedBytes = 0; + + while (m_node) + { + size_t len = (size_t)STDMIN(bytesLeft, (lword)m_node->CurrentSize()-m_offset); + blockedBytes = target.ChannelPut2(channel, m_node->m_buf+m_node->m_head+m_offset, len, 0, blocking); + + if (blockedBytes) + goto done; + + m_position += len; + bytesLeft -= len; + + if (!bytesLeft) + { + m_offset += len; + goto done; + } + + m_node = m_node->m_next; + m_offset = 0; + } + + if (bytesLeft && m_lazyLength) + { + size_t len = (size_t)STDMIN(bytesLeft, (lword)m_lazyLength); + blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking); + if (blockedBytes) + goto done; + + m_lazyString = PtrAdd(m_lazyString, len); + m_lazyLength -= len; + bytesLeft -= len; + } + +done: + transferBytes -= bytesLeft; + return blockedBytes; +} + +size_t ByteQueue::Walker::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + Walker walker(*this); + walker.Skip(begin); + lword transferBytes = end-begin; + + size_t blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking); + begin += transferBytes; + return blockedBytes; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/queue.h b/extension/third_party/cryptopp/queue.h new file mode 100644 index 00000000..f3f56002 --- /dev/null +++ b/extension/third_party/cryptopp/queue.h @@ -0,0 +1,158 @@ +// queue.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for an unlimited queue to store bytes + +#ifndef CRYPTOPP_QUEUE_H +#define CRYPTOPP_QUEUE_H + +#include "cryptlib.h" +#include "simple.h" + +NAMESPACE_BEGIN(CryptoPP) + +class ByteQueueNode; + +/// \brief Data structure used to store byte strings +/// \details The queue is implemented as a linked list of byte arrays +class CRYPTOPP_DLL ByteQueue : public Bufferless +{ +public: + /// \brief Construct a ByteQueue + /// \param nodeSize the initial node size + /// \details Internally, ByteQueue uses a ByteQueueNode to store bytes, and \p nodeSize determines the + /// size of the ByteQueueNode. A value of 0 indicates the ByteQueueNode should be automatically sized, + /// which means a value of 256 is used. + ByteQueue(size_t nodeSize=0); + + /// \brief Copy construct a ByteQueue + /// \param copy the other ByteQueue + ByteQueue(const ByteQueue ©); + ~ByteQueue(); + + lword MaxRetrievable() const + {return CurrentSize();} + bool AnyRetrievable() const + {return !IsEmpty();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + // these member functions are not inherited + void SetNodeSize(size_t nodeSize); + + lword CurrentSize() const; + bool IsEmpty() const; + + void Clear(); + + void Unget(byte inByte); + void Unget(const byte *inString, size_t length); + + const byte * Spy(size_t &contiguousSize) const; + + void LazyPut(const byte *inString, size_t size); + void LazyPutModifiable(byte *inString, size_t size); + void UndoLazyPut(size_t size); + void FinalizeLazyPut(); + + ByteQueue & operator=(const ByteQueue &rhs); + bool operator==(const ByteQueue &rhs) const; + bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);} + byte operator[](lword i) const; + void swap(ByteQueue &rhs); + + /// \brief A ByteQueue iterator + class Walker : public InputRejecting + { + public: + /// \brief Construct a ByteQueue Walker + /// \param queue a ByteQueue + Walker(const ByteQueue &queue) + : m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0) + {Initialize();} + + lword GetCurrentPosition() {return m_position;} + + lword MaxRetrievable() const + {return m_queue.CurrentSize() - m_position;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + private: + const ByteQueue &m_queue; + const ByteQueueNode *m_node; + lword m_position; + size_t m_offset; + const byte *m_lazyString; + size_t m_lazyLength; + }; + + friend class Walker; + +private: + void CleanupUsedNodes(); + void CopyFrom(const ByteQueue ©); + void Destroy(); + + bool m_autoNodeSize; + size_t m_nodeSize; + ByteQueueNode *m_head, *m_tail; + byte *m_lazyString; + size_t m_lazyLength; + bool m_lazyStringModifiable; +}; + +/// use this to make sure LazyPut is finalized in event of exception +class CRYPTOPP_DLL LazyPutter +{ +public: + LazyPutter(ByteQueue &bq, const byte *inString, size_t size) + : m_bq(bq) {bq.LazyPut(inString, size);} + ~LazyPutter() + {try {m_bq.FinalizeLazyPut();} catch(const Exception&) {CRYPTOPP_ASSERT(0);}} +protected: + LazyPutter(ByteQueue &bq) : m_bq(bq) {} +private: + ByteQueue &m_bq; +}; + +/// like LazyPutter, but does a LazyPutModifiable instead +class LazyPutterModifiable : public LazyPutter +{ +public: + LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size) + : LazyPutter(bq) {bq.LazyPutModifiable(inString, size);} +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/extension/third_party/cryptopp/rabbit.cpp b/extension/third_party/cryptopp/rabbit.cpp new file mode 100644 index 00000000..ef146259 --- /dev/null +++ b/extension/third_party/cryptopp/rabbit.cpp @@ -0,0 +1,259 @@ +// rabbit.cpp - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Martin Boesgaard, Mette Vesterager, +// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-rabbit.html. + +#include "pch.h" +#include "config.h" + +#include "rabbit.h" +#include "secblock.h" +#include "misc.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::rotlConstant; + +word32 G_func(word32 x) +{ +#if 0 + /* Temporary variables */ + word32 a, b, h, l; + + /* Construct high and low argument for squaring */ + a = x & 0xFFFF; + b = x >> 16; + + /* Calculate high and low result of squaring */ + h = (((static_cast(a*a) >> 17U) + static_cast(a*b)) >> 15U) + b*b; + l = x*x; + + /* Return high XOR low */ + return static_cast(h^l); +#endif + + // Thanks to Jack Lloyd for suggesting the 64-bit multiply. + word64 z = x; + z *= x; + return static_cast((z >> 32) ^ z); +} + +word32 NextState(word32 c[8], word32 x[8], word32 carry) +{ + /* Temporary variables */ + word32 g[8], c_old[8], i; + + /* Save old counter values */ + for (i = 0; i<8; i++) + c_old[i] = c[i]; + + /* Calculate new counter values */ + c[0] = static_cast(c[0] + 0x4D34D34D + carry); + c[1] = static_cast(c[1] + 0xD34D34D3 + (c[0] < c_old[0])); + c[2] = static_cast(c[2] + 0x34D34D34 + (c[1] < c_old[1])); + c[3] = static_cast(c[3] + 0x4D34D34D + (c[2] < c_old[2])); + c[4] = static_cast(c[4] + 0xD34D34D3 + (c[3] < c_old[3])); + c[5] = static_cast(c[5] + 0x34D34D34 + (c[4] < c_old[4])); + c[6] = static_cast(c[6] + 0x4D34D34D + (c[5] < c_old[5])); + c[7] = static_cast(c[7] + 0xD34D34D3 + (c[6] < c_old[6])); + carry = (c[7] < c_old[7]); + + /* Calculate the g-values */ + for (i = 0; i<8; i++) + g[i] = G_func(static_cast(x[i] + c[i])); + + /* Calculate new state values */ + x[0] = static_cast(g[0] + rotlConstant<16>(g[7]) + rotlConstant<16>(g[6])); + x[1] = static_cast(g[1] + rotlConstant<8>(g[0]) + g[7]); + x[2] = static_cast(g[2] + rotlConstant<16>(g[1]) + rotlConstant<16>(g[0])); + x[3] = static_cast(g[3] + rotlConstant<8>(g[2]) + g[1]); + x[4] = static_cast(g[4] + rotlConstant<16>(g[3]) + rotlConstant<16>(g[2])); + x[5] = static_cast(g[5] + rotlConstant<8>(g[4]) + g[3]); + x[6] = static_cast(g[6] + rotlConstant<16>(g[5]) + rotlConstant<16>(g[4])); + x[7] = static_cast(g[7] + rotlConstant<8>(g[6]) + g[5]); + + return carry; +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void RabbitPolicy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) +{ + /* Generate four subkeys */ + CRYPTOPP_UNUSED(params); + GetUserKey(LITTLE_ENDIAN_ORDER, m_t.begin(), 4, userKey, keylen); + + /* Generate initial state variables */ + m_mx[0] = m_t[0]; + m_mx[2] = m_t[1]; + m_mx[4] = m_t[2]; + m_mx[6] = m_t[3]; + m_mx[1] = static_cast(m_t[3] << 16) | (m_t[2] >> 16); + m_mx[3] = static_cast(m_t[0] << 16) | (m_t[3] >> 16); + m_mx[5] = static_cast(m_t[1] << 16) | (m_t[0] >> 16); + m_mx[7] = static_cast(m_t[2] << 16) | (m_t[1] >> 16); + + /* Generate initial counter values */ + m_mc[0] = rotlConstant<16>(m_t[2]); + m_mc[2] = rotlConstant<16>(m_t[3]); + m_mc[4] = rotlConstant<16>(m_t[0]); + m_mc[6] = rotlConstant<16>(m_t[1]); + m_mc[1] = (m_t[0] & 0xFFFF0000) | (m_t[1] & 0xFFFF); + m_mc[3] = (m_t[1] & 0xFFFF0000) | (m_t[2] & 0xFFFF); + m_mc[5] = (m_t[2] & 0xFFFF0000) | (m_t[3] & 0xFFFF); + m_mc[7] = (m_t[3] & 0xFFFF0000) | (m_t[0] & 0xFFFF); + + /* Clear carry bit */ + m_mcy = 0; + + /* Iterate the system four times */ + for (unsigned int i = 0; i<4; i++) + m_mcy = NextState(m_mc, m_mx, m_mcy); + + /* Modify the counters */ + for (unsigned int i = 0; i<8; i++) + m_mc[i] ^= m_mx[(i + 4) & 0x7]; + + /* Copy master instance to work instance */ + for (unsigned int i = 0; i<8; i++) + { + m_wx[i] = m_mx[i]; + m_wc[i] = m_mc[i]; + } + m_wcy = m_mcy; +} + +void RabbitPolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + byte* out = output; + for (size_t i = 0; i> 16) ^ (m_wx[3] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 4, m_wx[2] ^ (m_wx[7] >> 16) ^ (m_wx[5] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 8, m_wx[4] ^ (m_wx[1] >> 16) ^ (m_wx[7] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 12, m_wx[6] ^ (m_wx[3] >> 16) ^ (m_wx[1] << 16)); + } + + // If AdditiveCipherTemplate does not have an accumulated keystream + // then it will ask OperateKeystream to generate one. Optionally it + // will ask for an XOR of the input with the keystream while + // writing the result to the output buffer. In all cases the + // keystream is written to the output buffer. The optional part is + // adding the input buffer and keystream. + if ((operation & INPUT_NULL) != INPUT_NULL) + xorbuf(output, input, GetBytesPerIteration() * iterationCount); +} + +void RabbitWithIVPolicy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) +{ + /* Generate four subkeys */ + CRYPTOPP_UNUSED(params); + GetUserKey(LITTLE_ENDIAN_ORDER, m_t.begin(), 4, userKey, keylen); + + /* Generate initial state variables */ + m_mx[0] = m_t[0]; + m_mx[2] = m_t[1]; + m_mx[4] = m_t[2]; + m_mx[6] = m_t[3]; + m_mx[1] = static_cast(m_t[3] << 16) | (m_t[2] >> 16); + m_mx[3] = static_cast(m_t[0] << 16) | (m_t[3] >> 16); + m_mx[5] = static_cast(m_t[1] << 16) | (m_t[0] >> 16); + m_mx[7] = static_cast(m_t[2] << 16) | (m_t[1] >> 16); + + /* Generate initial counter values */ + m_mc[0] = rotlConstant<16>(m_t[2]); + m_mc[2] = rotlConstant<16>(m_t[3]); + m_mc[4] = rotlConstant<16>(m_t[0]); + m_mc[6] = rotlConstant<16>(m_t[1]); + m_mc[1] = (m_t[0] & 0xFFFF0000) | (m_t[1] & 0xFFFF); + m_mc[3] = (m_t[1] & 0xFFFF0000) | (m_t[2] & 0xFFFF); + m_mc[5] = (m_t[2] & 0xFFFF0000) | (m_t[3] & 0xFFFF); + m_mc[7] = (m_t[3] & 0xFFFF0000) | (m_t[0] & 0xFFFF); + + /* Clear carry bit */ + m_mcy = 0; + + /* Iterate the system four times */ + for (unsigned int i = 0; i<4; i++) + m_mcy = NextState(m_mc, m_mx, m_mcy); + + /* Modify the counters */ + for (unsigned int i = 0; i<8; i++) + m_mc[i] ^= m_mx[(i + 4) & 0x7]; + + /* Copy master instance to work instance */ + for (unsigned int i = 0; i<8; i++) + { + m_wx[i] = m_mx[i]; + m_wc[i] = m_mc[i]; + } + m_wcy = m_mcy; +} + +void RabbitWithIVPolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer); + CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length == 8); + + /* Generate four subvectors */ + GetBlock v(iv); v(m_t[0])(m_t[2]); + m_t[1] = (m_t[0] >> 16) | (m_t[2] & 0xFFFF0000); + m_t[3] = (m_t[2] << 16) | (m_t[0] & 0x0000FFFF); + + /* Modify counter values */ + m_wc[0] = m_mc[0] ^ m_t[0]; + m_wc[1] = m_mc[1] ^ m_t[1]; + m_wc[2] = m_mc[2] ^ m_t[2]; + m_wc[3] = m_mc[3] ^ m_t[3]; + m_wc[4] = m_mc[4] ^ m_t[0]; + m_wc[5] = m_mc[5] ^ m_t[1]; + m_wc[6] = m_mc[6] ^ m_t[2]; + m_wc[7] = m_mc[7] ^ m_t[3]; + + /* Copy state variables */ + for (unsigned int i = 0; i<8; i++) + m_wx[i] = m_mx[i]; + m_wcy = m_mcy; + + /* Iterate the system four times */ + for (unsigned int i = 0; i<4; i++) + m_wcy = NextState(m_wc, m_wx, m_wcy); +} + +void RabbitWithIVPolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + byte* out = output; + for (unsigned int i = 0; i> 16) ^ (m_wx[3] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 4, m_wx[2] ^ (m_wx[7] >> 16) ^ (m_wx[5] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 8, m_wx[4] ^ (m_wx[1] >> 16) ^ (m_wx[7] << 16)); + PutWord(false, LITTLE_ENDIAN_ORDER, out + 12, m_wx[6] ^ (m_wx[3] >> 16) ^ (m_wx[1] << 16)); + } + + // If AdditiveCipherTemplate does not have an accumulated keystream + // then it will ask OperateKeystream to generate one. Optionally it + // will ask for an XOR of the input with the keystream while + // writing the result to the output buffer. In all cases the + // keystream is written to the output buffer. The optional part is + // adding the input buffer and keystream. + if ((operation & INPUT_NULL) != INPUT_NULL) + xorbuf(output, input, GetBytesPerIteration() * iterationCount); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rabbit.h b/extension/third_party/cryptopp/rabbit.h new file mode 100644 index 00000000..6601dcd1 --- /dev/null +++ b/extension/third_party/cryptopp/rabbit.h @@ -0,0 +1,112 @@ +// rabbit.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Martin Boesgaard, Mette Vesterager, +// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-rabbit.html. + +/// \file rabbit.h +/// \brief Classes for Rabbit stream cipher +/// \sa The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_RABBIT_H +#define CRYPTOPP_RABBIT_H + +#include "strciphr.h" +#include "secblock.h" + +// The library does not have a way to describe an optional IV. Rabbit takes +// an optional IV so two classes are offered to bridge the gap. One provides +// Rabbit without an IV and the second provides Rabbit with an IV. + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabbit stream cipher information +/// \since Crypto++ 8.0 +struct RabbitInfo : public FixedKeyLength<16, SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "Rabbit"; } +}; + +/// \brief Rabbit stream cipher information +/// \since Crypto++ 8.0 +struct RabbitWithIVInfo : public FixedKeyLength<16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RabbitWithIV"; } +}; + +/// \brief Rabbit stream cipher implementation +/// \since Crypto++ 8.0 +class RabbitPolicy : public AdditiveCipherConcretePolicy, public RabbitInfo +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + +private: + // Master and working states + FixedSizeSecBlock m_mx, m_mc, m_wx, m_wc; + // Workspace + FixedSizeSecBlock m_t; + word32 m_mcy, m_wcy; // carry +}; + +/// \brief Rabbit stream cipher implementation +/// \since Crypto++ 8.0 +class RabbitWithIVPolicy : public AdditiveCipherConcretePolicy, public RabbitWithIVInfo +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + +private: + // Master and working states + FixedSizeSecBlock m_mx, m_mc, m_wx, m_wc; + // Workspace + FixedSizeSecBlock m_t; + word32 m_mcy, m_wcy; // carry +}; + +/// \brief Rabbit stream cipher +/// \details Rabbit is a stream cipher developed by Martin Boesgaard, Mette Vesterager, +/// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. Rabbit is one of the final four +/// Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \details Crypto++ provides Rabbit and RabbitWithIV classes. Two classes are necessary +/// because the library lacks the means to describe and manage optional IVs. +/// \sa RabbitWithIV, The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 +struct Rabbit : public RabbitInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, RabbitInfo> Encryption; + typedef Encryption Decryption; +}; + +/// \brief Rabbit stream cipher +/// \details Rabbit is a stream cipher developed by Martin Boesgaard, Mette Vesterager, +/// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. Rabbit is one of the final four +/// Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \details Crypto++ provides Rabbit and RabbitWithIV classes. Two classes are necessary +/// because the library lacks the means to describe and manage optional IVs. +/// \sa Rabbit, The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 +struct RabbitWithIV : public RabbitWithIVInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, RabbitWithIVInfo> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_RABBIT_H diff --git a/extension/third_party/cryptopp/rabin.cpp b/extension/third_party/cryptopp/rabin.cpp new file mode 100644 index 00000000..e112d9b8 --- /dev/null +++ b/extension/third_party/cryptopp/rabin.cpp @@ -0,0 +1,241 @@ +// rabin.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rabin.h" +#include "integer.h" +#include "nbtheory.h" +#include "modarith.h" +#include "asn.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RabinFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_r.BERDecode(seq); + m_s.BERDecode(seq); + seq.MessageEnd(); +} + +void RabinFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_r.DEREncode(seq); + m_s.DEREncode(seq); + seq.MessageEnd(); +} + +Integer RabinFunction::ApplyFunction(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer out = in.Squared()%m_n; + if (in.IsOdd()) + out = out*m_r%m_n; + if (Jacobi(in, m_n)==-1) + out = out*m_s%m_n; + return out; +} + +bool RabinFunction::Validate(RandomNumberGenerator& /*rng*/, unsigned int level) const +{ + bool pass = true; + pass = pass && m_n > Integer::One() && m_n%4 == 1; + CRYPTOPP_ASSERT(pass); + pass = pass && m_r > Integer::One() && m_r < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_s > Integer::One() && m_s < m_n; + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && Jacobi(m_r, m_n) == -1 && Jacobi(m_s, m_n) == -1; + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool RabinFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(QuadraticResidueModPrime1) + CRYPTOPP_GET_FUNCTION_ENTRY(QuadraticResidueModPrime2) + ; +} + +void RabinFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(QuadraticResidueModPrime1) + CRYPTOPP_SET_FUNCTION_ENTRY(QuadraticResidueModPrime2) + ; +} + +// ***************************************************************************** +// private key operations: + +// generate a random private key +void InvertibleRabinFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleRabinFunction: specified modulus size is too small"); + + // VC70 workaround: putting these after primeParam causes overlapped stack allocation + bool rFound=false, sFound=false; + Integer t=2; + + AlgorithmParameters primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + ("EquivalentTo", 3)("Mod", 4); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + while (!(rFound && sFound)) + { + int jp = Jacobi(t, m_p); + int jq = Jacobi(t, m_q); + + if (!rFound && jp==1 && jq==-1) + { + m_r = t; + rFound = true; + } + + if (!sFound && jp==-1 && jq==1) + { + m_s = t; + sFound = true; + } + + ++t; + } + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); +} + +void InvertibleRabinFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_r.BERDecode(seq); + m_s.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); +} + +void InvertibleRabinFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_r.DEREncode(seq); + m_s.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +Integer InvertibleRabinFunction::CalculateInverse(RandomNumberGenerator &rng, const Integer &in) const +{ + DoQuickSanityCheck(); + + ModularArithmetic modn(m_n); + Integer r(rng, Integer::One(), m_n - Integer::One()); + r = modn.Square(r); + Integer r2 = modn.Square(r); + Integer c = modn.Multiply(in, r2); // blind + + Integer cp=c%m_p, cq=c%m_q; + + int jp = Jacobi(cp, m_p); + int jq = Jacobi(cq, m_q); + + if (jq==-1) + { + cp = cp*EuclideanMultiplicativeInverse(m_r, m_p)%m_p; + cq = cq*EuclideanMultiplicativeInverse(m_r, m_q)%m_q; + } + + if (jp==-1) + { + cp = cp*EuclideanMultiplicativeInverse(m_s, m_p)%m_p; + cq = cq*EuclideanMultiplicativeInverse(m_s, m_q)%m_q; + } + + cp = ModularSquareRoot(cp, m_p); + cq = ModularSquareRoot(cq, m_q); + + if (jp==-1) + cp = m_p-cp; + + Integer out = CRT(cq, m_q, cp, m_p, m_u); + + out = modn.Divide(out, r); // unblind + + if ((jq==-1 && out.IsEven()) || (jq==1 && out.IsOdd())) + out = m_n-out; + + return out; +} + +bool InvertibleRabinFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RabinFunction::Validate(rng, level); + CRYPTOPP_ASSERT(pass); + pass = pass && m_p > Integer::One() && m_p%4 == 3 && m_p < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q%4 == 3 && m_q < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u.IsPositive() && m_u < m_p; + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u * m_q % m_p == 1; + CRYPTOPP_ASSERT(pass); + pass = pass && Jacobi(m_r, m_p) == 1; + CRYPTOPP_ASSERT(pass); + pass = pass && Jacobi(m_r, m_q) == -1; + CRYPTOPP_ASSERT(pass); + pass = pass && Jacobi(m_s, m_p) == -1; + CRYPTOPP_ASSERT(pass); + pass = pass && Jacobi(m_s, m_q) == 1; + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool InvertibleRabinFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleRabinFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rabin.h b/extension/third_party/cryptopp/rabin.h new file mode 100644 index 00000000..1cea7d45 --- /dev/null +++ b/extension/third_party/cryptopp/rabin.h @@ -0,0 +1,135 @@ +// rabin.h - originally written and placed in the public domain by Wei Dai + +/// \file rabin.h +/// \brief Classes for Rabin encryption and signature schemes + +#ifndef CRYPTOPP_RABIN_H +#define CRYPTOPP_RABIN_H + +#include "cryptlib.h" +#include "oaep.h" +#include "pssr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin trapdoor function using the public key +/// \since Crypto++ 2.0 +class RabinFunction : public TrapdoorFunction, public PublicKey +{ + typedef RabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin public key + /// \param n the modulus + /// \param r element r + /// \param s element s + void Initialize(const Integer &n, const Integer &r, const Integer &s) + {m_n = n; m_r = r; m_s = s;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + const Integer& GetQuadraticResidueModPrime1() const {return m_r;} + const Integer& GetQuadraticResidueModPrime2() const {return m_s;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetQuadraticResidueModPrime1(const Integer &r) {m_r = r;} + void SetQuadraticResidueModPrime2(const Integer &s) {m_s = s;} + +protected: + Integer m_n, m_r, m_s; +}; + +/// \brief Rabin trapdoor function using the private key +/// \since Crypto++ 2.0 +class InvertibleRabinFunction : public RabinFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin private key + /// \param n modulus + /// \param r element r + /// \param s element s + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &r, const Integer &s, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_r = r; m_s = s; m_p = p; m_q = q; m_u = u;} + + /// \brief Create a Rabin private key + /// \param rng a RandomNumberGenerator derived class + /// \param keybits the size of the key, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int keybits) + {GenerateRandomWithKeySize(rng, keybits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief Rabin keys +struct Rabin +{ + static std::string StaticAlgorithmName() {return "Rabin-Crypto++Variant";} + typedef RabinFunction PublicKey; + typedef InvertibleRabinFunction PrivateKey; +}; + +/// \brief Rabin encryption scheme +/// \tparam STANDARD encryption standard +template +struct RabinES : public TF_ES +{ +}; + +/// \brief Rabin signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +template +struct RabinSS : public TF_SS +{ +}; + +// More typedefs for backwards compatibility +class SHA1; +typedef RabinES >::Decryptor RabinDecryptor; +typedef RabinES >::Encryptor RabinEncryptor; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/randpool.cpp b/extension/third_party/cryptopp/randpool.cpp new file mode 100644 index 00000000..0973bb0d --- /dev/null +++ b/extension/third_party/cryptopp/randpool.cpp @@ -0,0 +1,152 @@ +// randpool.cpp - originally written and placed in the public domain by Wei Dai +// RandomPool used to follow the design of randpool in PGP 2.6.x, +// but as of version 5.5 it has been redesigned to reduce the risk +// of reusing random numbers after state rollback (which may occur +// when running in a virtual machine like VMware). + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "randpool.h" +#include "aes.h" +#include "sha.h" +#include "hrtimer.h" +#include "trap.h" + +// OldRandomPool +#include "mdc.h" +#include "modes.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +RandomPool::RandomPool() + : m_pCipher(new AES::Encryption), m_keySet(false) +{ + std::memset(m_key, 0, m_key.SizeInBytes()); + std::memset(m_seed, 0, m_seed.SizeInBytes()); +} + +void RandomPool::IncorporateEntropy(const byte *input, size_t length) +{ + SHA256 hash; + hash.Update(m_key, 32); + hash.Update(input, length); + hash.Final(m_key); + m_keySet = false; +} + +void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) +{ + if (size > 0) + { + if (!m_keySet) + m_pCipher->SetKey(m_key, 32); + + CRYPTOPP_COMPILE_ASSERT(sizeof(TimerWord) <= 16); + CRYPTOPP_COMPILE_ASSERT(sizeof(time_t) <= 8); + + Timer timer; + TimerWord tw = timer.GetCurrentTimerValue(); + + *(TimerWord *)(void*)m_seed.data() += tw; + time_t t = time(NULLPTR); + + // UBsan finding: signed integer overflow: 1876017710 + 1446085457 cannot be represented in type 'long int' + // *(time_t *)(m_seed.data()+8) += t; + word64 tt1 = 0, tt2 = (word64)t; + std::memcpy(&tt1, m_seed.data()+8, 8); + std::memcpy(m_seed.data()+8, &(tt2 += tt1), 8); + + // Wipe the intermediates + *((volatile TimerWord*)&tw) = 0; + *((volatile word64*)&tt1) = 0; + *((volatile word64*)&tt2) = 0; + + do + { + m_pCipher->ProcessBlock(m_seed); + size_t len = UnsignedMin(16, size); + target.ChannelPut(channel, m_seed, len); + size -= len; + } while (size > 0); + } +} + +// OldRandomPool is provided for backwards compatibility for a migration path +typedef MDC OldRandomPoolCipher; + +OldRandomPool::OldRandomPool(unsigned int poolSize) + : pool(poolSize), key(OldRandomPoolCipher::DEFAULT_KEYLENGTH), addPos(0), getPos(poolSize) +{ + CRYPTOPP_ASSERT(poolSize > key.size()); + std::memset(pool, 0, poolSize); + std::memset(key, 0, key.size()); +} + +void OldRandomPool::IncorporateEntropy(const byte *input, size_t length) +{ + size_t t; + while (length > (t = pool.size() - addPos)) + { + xorbuf(pool+addPos, input, t); + input += t; + length -= t; + Stir(); + } + + if (length) + { + xorbuf(pool+addPos, input, length); + addPos += length; + getPos = pool.size(); // Force stir on get + } +} + +void OldRandomPool::Stir() +{ + CFB_Mode::Encryption cipher; + + for (int i=0; i<2; i++) + { + cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize()); + cipher.ProcessString(pool, pool.size()); + std::memcpy(key, pool, key.size()); + } + + addPos = 0; + getPos = key.size(); +} + +void OldRandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) +{ + while (size > 0) + { + if (getPos == pool.size()) + Stir(); + size_t t = UnsignedMin(pool.size() - getPos, size); + target.ChannelPut(channel, pool+getPos, t); + size -= t; + getPos += t; + } +} + +byte OldRandomPool::GenerateByte() +{ + if (getPos == pool.size()) + Stir(); + + return pool[getPos++]; +} + +void OldRandomPool::GenerateBlock(byte *outString, size_t size) +{ + ArraySink sink(outString, size); + GenerateIntoBufferedTransformation(sink, DEFAULT_CHANNEL, size); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/randpool.h b/extension/third_party/cryptopp/randpool.h new file mode 100644 index 00000000..a24b9dbf --- /dev/null +++ b/extension/third_party/cryptopp/randpool.h @@ -0,0 +1,100 @@ +// randpool.h - originally written and placed in the public domain by Wei Dai +// OldRandPool added by JW in August, 2017. + +/// \file randpool.h +/// \brief Class file for Randomness Pool +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback (which may occur when running in a virtual machine like VMware or a hosted +/// environment). +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. Use RandomPool +/// or AutoSeededRandomPool instead. +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) + +#ifndef CRYPTOPP_RANDPOOL_H +#define CRYPTOPP_RANDPOOL_H + +#include "cryptlib.h" +#include "filters.h" +#include "secblock.h" +#include "smartptr.h" +#include "aes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Randomness Pool based on AES-256 +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback, which may occur when running in a virtual machine like VMware or a hosted +/// environment. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. +/// \sa OldRandomPool +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) +class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a RandomPool + RandomPool(); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + FixedSizeAlignedSecBlock m_seed; + FixedSizeAlignedSecBlock m_key; + member_ptr m_pCipher; + bool m_keySet; +}; + +/// \brief Randomness Pool based on PGP 2.6.x with MDC +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. The +/// OldRandomPool also provides the modern interface, including CanIncorporateEntropy, +/// IncorporateEntropy and GenerateIntoBufferedTransformation. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \details You should migrate away from OldRandomPool at the earliest opportunity. Use a +/// modern random number generator or key derivation function, like AutoSeededRandomPool or +/// HKDF. +/// \warning This class uses an old style PGP 2.6.x with MDC. The generator risks reusing +/// random numbers after state rollback. You should migrate away from OldRandomPool at +/// the earliest opportunity. +/// \sa RandomPool, AutoSeededRandomPool, HKDF, P1363_KDF2, PKCS12_PBKDF, PKCS5_PBKDF2_HMAC +/// \since Crypto++ 6.0 +class CRYPTOPP_DLL OldRandomPool : public RandomNumberGenerator +{ +public: + /// \brief Construct an OldRandomPool + /// \param poolSize internal pool size of the generator + /// \details poolSize must be greater than 16 + OldRandomPool(unsigned int poolSize=384); + + // RandomNumberGenerator interface (Crypto++ 5.5 and above) + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + +protected: + void Stir(); + +private: + SecByteBlock pool, key; + size_t addPos, getPos; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rc2.cpp b/extension/third_party/cryptopp/rc2.cpp new file mode 100644 index 00000000..1469cc59 --- /dev/null +++ b/extension/third_party/cryptopp/rc2.cpp @@ -0,0 +1,118 @@ +// rc2.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rc2.h" +#include "misc.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC2::Base::UncheckedSetKey(const byte *key, unsigned int keyLen, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(keyLen); + + int effectiveLen = params.GetIntValueWithDefault(Name::EffectiveKeyLength(), DEFAULT_EFFECTIVE_KEYLENGTH); + if (effectiveLen > MAX_EFFECTIVE_KEYLENGTH) + throw InvalidArgument("RC2: effective key length parameter exceeds maximum"); + + static const unsigned char PITABLE[256] = { + 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157, + 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162, + 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50, + 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130, + 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220, + 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38, + 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3, + 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215, + 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42, + 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236, + 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57, + 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49, + 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201, + 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169, + 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46, + 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173}; + + SecByteBlock L(128); + memcpy(L, key, keyLen); + + int i; + for (i=keyLen; i<128; i++) + L[i] = PITABLE[(L[i-1] + L[i-keyLen]) & 255]; + + unsigned int T8 = (effectiveLen+7) / 8; + byte TM = byte((int)255 >> ((8-(effectiveLen%8))%8)); + L[128-T8] = PITABLE[L[128-T8] & TM]; + + for (i=127-T8; i>=0; i--) + L[i] = PITABLE[L[i+1] ^ L[i+T8]]; + + for (i=0; i<64; i++) + K[i] = L[2*i] + (L[2*i+1] << 8); +} + +typedef BlockGetAndPut Block; + +void RC2::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 R0, R1, R2, R3; + Block::Get(inBlock)(R0)(R1)(R2)(R3); + + for (int i = 0; i < 16; i++) + { + R0 += (R1 & ~R3) + (R2 & R3) + K[4*i+0]; + R0 = rotlConstant<1>(R0); + + R1 += (R2 & ~R0) + (R3 & R0) + K[4*i+1]; + R1 = rotlConstant<2>(R1); + + R2 += (R3 & ~R1) + (R0 & R1) + K[4*i+2]; + R2 = rotlConstant<3>(R2); + + R3 += (R0 & ~R2) + (R1 & R2) + K[4*i+3]; + R3 = rotlConstant<5>(R3); + + if (i == 4 || i == 10) + { + R0 = word16(R0 + K[R3 & 63]); + R1 = word16(R1 + K[R0 & 63]); + R2 = word16(R2 + K[R1 & 63]); + R3 = word16(R3 + K[R2 & 63]); + } + } + + Block::Put(xorBlock, outBlock)(R0)(R1)(R2)(R3); +} + +void RC2::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 R0, R1, R2, R3; + Block::Get(inBlock)(R0)(R1)(R2)(R3); + + for (int i = 15; i >= 0; i--) + { + if (i == 4 || i == 10) + { + R3 = word16(R3 - K[R2 & 63]); + R2 = word16(R2 - K[R1 & 63]); + R1 = word16(R1 - K[R0 & 63]); + R0 = word16(R0 - K[R3 & 63]); + } + + R3 = rotrConstant<5>(R3); + R3 = word16(R3 - ((R0 & ~R2) + (R1 & R2) + K[4*i+3])); + + R2 = rotrConstant<3>(R2); + R2 = word16(R2 - ((R3 & ~R1) + (R0 & R1) + K[4*i+2])); + + R1 = rotrConstant<2>(R1); + R1 = word16(R1 - ((R2 & ~R0) + (R3 & R0) + K[4*i+1])); + + R0 = rotrConstant<1>(R0); + R0 = word16(R0 - ((R1 & ~R3) + (R2 & R3) + K[4*i+0])); + } + + Block::Put(xorBlock, outBlock)(R0)(R1)(R2)(R3); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rc2.h b/extension/third_party/cryptopp/rc2.h new file mode 100644 index 00000000..50a39ae8 --- /dev/null +++ b/extension/third_party/cryptopp/rc2.h @@ -0,0 +1,90 @@ +// rc2.h - originally written and placed in the public domain by Wei Dai + +/// \file rc2.h +/// \brief Classes for the RC2 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC2_H +#define CRYPTOPP_RC2_H + +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC2 block cipher information +/// \since Crypto++ 3.0 +struct RC2_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 128> +{ + CRYPTOPP_CONSTANT(DEFAULT_EFFECTIVE_KEYLENGTH = 1024); + CRYPTOPP_CONSTANT(MAX_EFFECTIVE_KEYLENGTH = 1024); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC2";} +}; + +/// \brief RC2 block cipher +/// \sa RC2 on the Crypto Lounge. +/// \since Crypto++ 3.0 +class RC2 : public RC2_Info, public BlockCipherDocumentation +{ + /// \brief Class specific methods used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + FixedSizeSecBlock K; // expanded key table + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Encryption apply to \p ENCRYPTION. + class Encryption : public BlockCipherFinal + { + public: + Encryption() {} + Encryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Encryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Decryption apply to \p DECRYPTION. + class Decryption : public BlockCipherFinal + { + public: + Decryption() {} + Decryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Decryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; +}; + +typedef RC2::Encryption RC2Encryption; +typedef RC2::Decryption RC2Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rc5.cpp b/extension/third_party/cryptopp/rc5.cpp new file mode 100644 index 00000000..262c9aec --- /dev/null +++ b/extension/third_party/cryptopp/rc5.cpp @@ -0,0 +1,80 @@ +// rc5.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rc5.h" +#include "misc.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC5::Base::UncheckedSetKey(const byte *k, unsigned int keylen, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(keylen); + + r = GetRoundsAndThrowIfInvalid(params, this); + sTable.New(2*(r+1)); + + static const RC5_WORD MAGIC_P = 0xb7e15163L; // magic constant P for wordsize + static const RC5_WORD MAGIC_Q = 0x9e3779b9L; // magic constant Q for wordsize + static const int U=sizeof(RC5_WORD); + + const unsigned int c = STDMAX((keylen+U-1)/U, 1U); // RC6 paper says c=1 if keylen==0 + SecBlock l(c); + + GetUserKey(LITTLE_ENDIAN_ORDER, l.begin(), c, k, keylen); + + sTable[0] = MAGIC_P; + for (unsigned j=1; j((sTable[h % sTable.size()] + a + b)); + b = l[h % c] = rotlMod((l[h % c] + a + b), (a+b)); + } +} + +typedef BlockGetAndPut Block; + +void RC5::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC5_WORD *sptr = sTable; + RC5_WORD a, b; + + Block::Get(inBlock)(a)(b); + a += sptr[0]; + b += sptr[1]; + sptr += 2; + + for(unsigned i=0; i, public VariableKeyLength<16, 0, 255>, public VariableRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC5";} + typedef word32 RC5_WORD; +}; + +/// \brief RC5 block cipher +/// \sa RC5 +/// \since Crypto++ 1.0 +class RC5 : public RC5_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC5::Encryption RC5Encryption; +typedef RC5::Decryption RC5Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rc6.cpp b/extension/third_party/cryptopp/rc6.cpp new file mode 100644 index 00000000..a03c5108 --- /dev/null +++ b/extension/third_party/cryptopp/rc6.cpp @@ -0,0 +1,96 @@ +// rc6.cpp - written and placed in the public domain by Sean Woods +// based on Wei Dai's RC5 code. + +#include "pch.h" +#include "rc6.h" +#include "misc.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +void RC6::Base::UncheckedSetKey(const byte *k, unsigned int keylen, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(keylen); + + r = GetRoundsAndThrowIfInvalid(params, this); + sTable.New(2*(r+2)); + + static const RC6_WORD MAGIC_P = 0xb7e15163L; // magic constant P for wordsize + static const RC6_WORD MAGIC_Q = 0x9e3779b9L; // magic constant Q for wordsize + static const int U=sizeof(RC6_WORD); + + const unsigned int c = STDMAX((keylen+U-1)/U, 1U); // RC6 paper says c=1 if keylen==0 + SecBlock l(c); + + GetUserKey(LITTLE_ENDIAN_ORDER, l.begin(), c, k, keylen); + + sTable[0] = MAGIC_P; + for (unsigned j=1; j((sTable[h % sTable.size()] + a + b)); + b = l[h % c] = rotlMod((l[h % c] + a + b), (a+b)); + } +} + +typedef BlockGetAndPut Block; + +void RC6::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC6_WORD *sptr = sTable; + RC6_WORD a, b, c, d, t, u; + + Block::Get(inBlock)(a)(b)(c)(d); + b += sptr[0]; + d += sptr[1]; + sptr += 2; + + for(unsigned i=0; i(b*(2*b+1)); + u = rotlConstant<5>(d*(2*d+1)); + a = rotlMod(a^t,u) + sptr[0]; + c = rotlMod(c^u,t) + sptr[1]; + t = a; a = b; b = c; c = d; d = t; + sptr += 2; + } + + a += sptr[0]; + c += sptr[1]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +void RC6::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + const RC6_WORD *sptr = sTable.end(); + RC6_WORD a, b, c, d, t, u; + + Block::Get(inBlock)(a)(b)(c)(d); + + sptr -= 2; + c -= sptr[1]; + a -= sptr[0]; + + for (unsigned i=0; i < r; i++) + { + sptr -= 2; + t = a; a = d; d = c; c = b; b = t; + u = rotlConstant<5>(d*(2 * d + 1)); + t = rotlConstant<5>(b*(2 * b + 1)); + c = rotrMod(c-sptr[1], t) ^ u; + a = rotrMod(a-sptr[0], u) ^ t; + } + + d -= sTable[1]; + b -= sTable[0]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rc6.h b/extension/third_party/cryptopp/rc6.h new file mode 100644 index 00000000..1a41ab2c --- /dev/null +++ b/extension/third_party/cryptopp/rc6.h @@ -0,0 +1,60 @@ +// rc6.h - originally written and placed in the public domain by Wei Dai + +/// \file rc6.h +/// \brief Classes for the RC6 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC6_H +#define CRYPTOPP_RC6_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC6 block cipher information +/// \since Crypto++ 3.0 +struct RC6_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public VariableRounds<20> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC6";} + typedef word32 RC6_WORD; +}; + +/// \brief RC6 block cipher +/// \sa RC6 +/// \since Crypto++ 3.0 +class RC6 : public RC6_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC6::Encryption RC6Encryption; +typedef RC6::Decryption RC6Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rdrand.cpp b/extension/third_party/cryptopp/rdrand.cpp new file mode 100644 index 00000000..f8ebe82b --- /dev/null +++ b/extension/third_party/cryptopp/rdrand.cpp @@ -0,0 +1,327 @@ +// rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. + +#include "pch.h" +#include "config.h" +#include "cryptlib.h" +#include "secblock.h" +#include "rdrand.h" +#include "cpu.h" + +// This file (and friends) provides both RDRAND and RDSEED. They were added +// at Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64} +// to select an implementation or throws "NotImplemented". Users of the +// classes should call HasRDRAND() or HasRDSEED() to determine if a +// generator is available at runtime. +// The original classes accepted a retry count. Retries were superflous for +// RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending +// on the processor. Retries were removed at Crypto++ 6.0 because +// GenerateBlock unconditionally retries and always fulfills the request. +// Intel recommends using a retry count in case RDRAND or RDSEED circuit +// is bad. This implemenation does not follow the advice and requires +// good silicon. If the circuit or processor is bad then the user has +// bigger problems than generating random numbers. + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702) +#endif + +#if defined(CRYPTOPP_RDRAND_AVAILABLE) +# if defined(CRYPTOPP_MSC_VERSION) +# define MASM_RDRAND_ASM_AVAILABLE 1 +# endif +# if (__SUNPRO_CC >= 0x5100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_GCC_VERSION >= 30200) +# define GCC_RDRAND_ASM_AVAILABLE 1 +# endif +#endif // CRYPTOPP_RDRAND_AVAILABLE + +#if defined(CRYPTOPP_RDSEED_AVAILABLE) +# if defined(CRYPTOPP_MSC_VERSION) +# define MASM_RDSEED_ASM_AVAILABLE 1 +# endif +# if (__SUNPRO_CC >= 0x5100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_GCC_VERSION >= 30200) +# define GCC_RDSEED_ASM_AVAILABLE 1 +# endif +#endif // CRYPTOPP_RDSEED_AVAILABLE + +typedef unsigned char byte; + +#if MASM_RDRAND_ASM_AVAILABLE +extern "C" void CRYPTOPP_FASTCALL MASM_RDRAND_GenerateBlock(byte*, size_t); +#endif + +#if MASM_RDSEED_ASM_AVAILABLE +extern "C" void CRYPTOPP_FASTCALL MASM_RDSEED_GenerateBlock(byte*, size_t); +#endif + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_RDRAND_AVAILABLE) + +// Fills 4 bytes +inline void RDRAND32(void* output) +{ + CRYPTOPP_UNUSED(output); // MSC warning +# if defined(GCC_RDRAND_ASM_AVAILABLE) + __asm__ __volatile__ + ( + "1:\n" + ".byte 0x0f, 0xc7, 0xf0;\n" + "jnc 1b;\n" + : "=a" (*reinterpret_cast(output)) + : : "cc" + ); +# endif +} + +# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) +// Fills 8 bytes +inline void RDRAND64(void* output) +{ + CRYPTOPP_UNUSED(output); // MSC warning +# if defined(GCC_RDRAND_ASM_AVAILABLE) + __asm__ __volatile__ + ( + "1:\n" + ".byte 0x48, 0x0f, 0xc7, 0xf0;\n" + "jnc 1b;\n" + : "=a" (*reinterpret_cast(output)) + : : "cc" + ); +# endif +} +# endif // RDRAND64 + +RDRAND::RDRAND() +{ + if (!HasRDRAND()) + throw RDRAND_Err("HasRDRAND"); +} + +void RDRAND::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_ASSERT((output && size) || !(output || size)); + if (size == 0) return; + +# if defined(MASM_RDRAND_ASM_AVAILABLE) + + MASM_RDRAND_GenerateBlock(output, size); + +# elif defined(GCC_RDRAND_ASM_AVAILABLE) + +# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) + size_t i = 0; + for (i = 0; i < size/8; i++) + RDRAND64(output+i*8); + + output += i*8; + size -= i*8; + + if (size) + { + word64 val; + RDRAND64(&val); + std::memcpy(output, &val, size); + } +# else + size_t i = 0; + for (i = 0; i < size/4; i++) + RDRAND32(output+i*4); + + output += i*4; + size -= i*4; + + if (size) + { + word32 val; + RDRAND32(&val); + std::memcpy(output, &val, size); + } +# endif +# else + // No suitable compiler found + CRYPTOPP_UNUSED(output); + throw NotImplemented("RDRAND: failed to find a suitable implementation"); +# endif +} + +void RDRAND::DiscardBytes(size_t n) +{ + // RoundUpToMultipleOf is used because a full word is read, and its cheaper + // to discard full words. There's no sense in dealing with tail bytes. + FixedSizeSecBlock discard; + n = RoundUpToMultipleOf(n, sizeof(word64)); + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} + +#endif // CRYPTOPP_RDRAND_AVAILABLE + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +#if defined(CRYPTOPP_RDSEED_AVAILABLE) + +// Fills 4 bytes +inline void RDSEED32(void* output) +{ + CRYPTOPP_UNUSED(output); // MSC warning +# if defined(GCC_RDSEED_ASM_AVAILABLE) + __asm__ __volatile__ + ( + "1:\n" + ".byte 0x0f, 0xc7, 0xf8;\n" + "jnc 1b;\n" + : "=a" (*reinterpret_cast(output)) + : : "cc" + ); +# endif +} + +# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) +// Fills 8 bytes +inline void RDSEED64(void* output) +{ + CRYPTOPP_UNUSED(output); // MSC warning +# if defined(GCC_RDSEED_ASM_AVAILABLE) + __asm__ __volatile__ + ( + "1:\n" + ".byte 0x48, 0x0f, 0xc7, 0xf8;\n" + "jnc 1b;\n" + : "=a" (*reinterpret_cast(output)) + : : "cc" + ); +# endif +} +# endif // RDSEED64 + +RDSEED::RDSEED() +{ + if (!HasRDSEED()) + throw RDSEED_Err("HasRDSEED"); +} + +void RDSEED::GenerateBlock(byte *output, size_t size) +{ + CRYPTOPP_ASSERT((output && size) || !(output || size)); + if (size == 0) return; + +# if defined(MASM_RDSEED_ASM_AVAILABLE) + + MASM_RDSEED_GenerateBlock(output, size); + +# elif defined(GCC_RDSEED_ASM_AVAILABLE) +# if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32) + size_t i = 0; + for (i = 0; i < size/8; i++) + RDSEED64(output+i*8); + + output += i*8; + size -= i*8; + + if (size) + { + word64 val; + RDSEED64(&val); + std::memcpy(output, &val, size); + } +# else + size_t i = 0; + for (i = 0; i < size/4; i++) + RDSEED32(output+i*4); + + output += i*4; + size -= i*4; + + if (size) + { + word32 val; + RDSEED32(&val); + std::memcpy(output, &val, size); + } +# endif +# else + // No suitable compiler found + CRYPTOPP_UNUSED(output); + throw NotImplemented("RDSEED: failed to find a suitable implementation"); +# endif // RDSEED64 +} + +void RDSEED::DiscardBytes(size_t n) +{ + // RoundUpToMultipleOf is used because a full word is read, and its cheaper + // to discard full words. There's no sense in dealing with tail bytes. + FixedSizeSecBlock discard; + n = RoundUpToMultipleOf(n, sizeof(word64)); + + size_t count = STDMIN(n, discard.SizeInBytes()); + while (count) + { + GenerateBlock(discard.BytePtr(), count); + n -= count; + count = STDMIN(n, discard.SizeInBytes()); + } +} + +#endif // CRYPTOPP_RDSEED_AVAILABLE + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +#if !defined(CRYPTOPP_RDRAND_AVAILABLE) + +RDRAND::RDRAND() +{ + throw RDRAND_Err("HasRDRAND"); +} + +void RDRAND::GenerateBlock(byte *output, size_t size) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); +} + +void RDRAND::DiscardBytes(size_t n) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(n); +} + +#endif // CRYPTOPP_RDRAND_AVAILABLE + +#if !defined(CRYPTOPP_RDSEED_AVAILABLE) + +RDSEED::RDSEED() +{ + throw RDSEED_Err("HasRDSEED"); +} + +void RDSEED::GenerateBlock(byte *output, size_t size) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size); +} + +void RDSEED::DiscardBytes(size_t n) +{ + // Constructor will throw, should not get here + CRYPTOPP_UNUSED(n); +} + +#endif // CRYPTOPP_RDSEED_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rdrand.h b/extension/third_party/cryptopp/rdrand.h new file mode 100644 index 00000000..93614a62 --- /dev/null +++ b/extension/third_party/cryptopp/rdrand.h @@ -0,0 +1,145 @@ +// rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. + +/// \file rdrand.h +/// \brief Classes for RDRAND and RDSEED +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_RDRAND_H +#define CRYPTOPP_RDRAND_H + +#include "cryptlib.h" + +// This class file provides both RDRAND and RDSEED. They were added at +// Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64} +// to select an implementation or "throw NotImplemented". At runtime the +// constructor will throw RDRAND_Err or RDSEED_Err if a generator is +// is not available. +// The original classes accepted a retry count. Retries were superflous for +// RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending +// on the processor. Retries were removed at Crypto++ 6.0 because +// GenerateBlock unconditionally retries and always fulfills the request. + +// Throughput varies wildly depending on processor and manufacturer. A Core i5 or +// Core i7 RDRAND can generate at over 200 MiB/s. It is below the theroetical +// maximum, but it takes about 5 instructions to generate, retry and store a +// result. A low-end Celeron may perform RDRAND at about 7 MiB/s. RDSEED +// performs at about 1/4 to 1/2 the rate of RDRAND. AMD RDRAND performed poorly +// during testing with Athlon X4 845. The Bulldozer v4 only performed at 1 MiB/s. + +// Microsoft added RDRAND in August 2012, VS2012; RDSEED in October 2013, VS2013. +// GCC added RDRAND in December 2010, GCC 4.6. LLVM added RDRAND in July 2012, +// Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1. + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a RDRAND generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDRAND_Err : public Exception +{ +public: + RDRAND_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDRAND instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDRAND : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDRAND"; } + + virtual ~RDRAND() {} + + /// \brief Construct a RDRAND generator + /// \details According to DJ of Intel, the Intel RDRAND circuit does not underflow. + /// If it did hypothetically underflow, then it would return 0 for the random value. + /// AMD's RDRAND implementation appears to provide the same behavior. + /// \throw RDRAND_Err if the random number generator is not available + RDRAND(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "RDRAND"; + } +}; + +/// \brief Exception thrown when a RDSEED generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDSEED_Err : public Exception +{ +public: + RDSEED_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDSEED instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDSEED : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDSEED"; } + + virtual ~RDSEED() {} + + /// \brief Construct a RDSEED generator + /// \details Empirical testing under a 6th generaton i7 (6200U) shows RDSEED fails + /// to fulfill requests at about once every for every 256 bytes requested. + /// The generator runs about 4 times slower than RDRAND. + /// \throw RDSEED_Err if the random number generator is not available + RDSEED(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "RDSEED"; + } +}; + +NAMESPACE_END + +#endif // CRYPTOPP_RDRAND_H diff --git a/extension/third_party/cryptopp/rdtables.cpp b/extension/third_party/cryptopp/rdtables.cpp new file mode 100644 index 00000000..8ceb800f --- /dev/null +++ b/extension/third_party/cryptopp/rdtables.cpp @@ -0,0 +1,166 @@ +// Rijndael tables + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "rijndael.h" + +NAMESPACE_BEGIN(CryptoPP) + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +*/ + +const byte Rijndael::Base::Se[256] = { + 0x63, 0x7c, 0x77, 0x7b, + 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, + 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, + 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, + 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, + 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, + 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, + 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, + 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, + 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, + 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, + 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, + 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, + 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, + 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, + 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, + 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, + 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, + 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, + 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, + 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16, +}; + +const byte Rijndael::Base::Sd[256] = { + 0x52, 0x09, 0x6a, 0xd5, + 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, + 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, + 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, + 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, + 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, + 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, + 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, + 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, + 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, + 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, + 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, + 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, + 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, + 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, + 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, + 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, + 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, + 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, + 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, + 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, + 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, + 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, + 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, + 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, + 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, + 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, + 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, + 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, + 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, + 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0c, 0x7d, +}; + +/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +const word32 Rijndael::Base::rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/regtest1.cpp b/extension/third_party/cryptopp/regtest1.cpp new file mode 100644 index 00000000..dc9b6324 --- /dev/null +++ b/extension/third_party/cryptopp/regtest1.cpp @@ -0,0 +1,154 @@ +// regtest1.cpp - originally written and placed in the public domain by Wei Dai +// regtest.cpp split into 3 files due to OOM kills by JW +// in April 2017. A second split occurred in July 2018. + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "factory.h" +#include "bench.h" +#include "cpu.h" + +#include "crc.h" +#include "adler32.h" +#include "md2.h" +#include "md5.h" +#include "keccak.h" +#include "sha3.h" +#include "shake.h" +#include "blake2.h" +#include "sha.h" +#include "sha3.h" +#include "sm3.h" +#include "hkdf.h" +#include "tiger.h" +#include "ripemd.h" +#include "panama.h" +#include "whrlpool.h" + +#include "osrng.h" +#include "drbg.h" +#include "darn.h" +#include "mersenne.h" +#include "rdrand.h" +#include "padlkrng.h" + +#include "modes.h" +#include "aes.h" + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +USING_NAMESPACE(CryptoPP) + +// Unkeyed ciphers +void RegisterFactories1(); +// MAC ciphers +void RegisterFactories2(); +// Stream ciphers +void RegisterFactories3(); +// Block ciphers +void RegisterFactories4(); +// Public key ciphers +void RegisterFactories5(); + +void RegisterFactories(Test::TestClass suites) +{ + static bool s_registered = false; + if (s_registered) + return; + + if ((suites & Test::Unkeyed) == Test::Unkeyed) + RegisterFactories1(); + + if ((suites & Test::SharedKeyMAC) == Test::SharedKeyMAC) + RegisterFactories2(); + + if ((suites & Test::SharedKeyStream) == Test::SharedKeyStream) + RegisterFactories3(); + + if ((suites & Test::SharedKeyBlock) == Test::SharedKeyBlock) + RegisterFactories4(); + + if ((suites & Test::PublicKey) == Test::PublicKey) + RegisterFactories5(); + + s_registered = true; +} + +// Unkeyed ciphers +void RegisterFactories1() +{ + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + +#ifdef BLOCKING_RNG_AVAILABLE + RegisterDefaultFactoryFor(); +#endif +#ifdef NONBLOCKING_RNG_AVAILABLE + RegisterDefaultFactoryFor(); +#endif +#ifdef OS_RNG_AVAILABLE + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor >(); +#endif + RegisterDefaultFactoryFor(); +#if (CRYPTOPP_BOOL_X86) + if (HasPadlockRNG()) + RegisterDefaultFactoryFor(); +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + if (HasRDRAND()) + RegisterDefaultFactoryFor(); + if (HasRDSEED()) + RegisterDefaultFactoryFor(); +#endif +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + if (HasDARN()) + RegisterDefaultFactoryFor(); +#endif + RegisterDefaultFactoryFor::Encryption >("AES/OFB RNG"); + RegisterDefaultFactoryFor >("Hash_DRBG(SHA1)"); + RegisterDefaultFactoryFor >("Hash_DRBG(SHA256)"); + RegisterDefaultFactoryFor >("HMAC_DRBG(SHA1)"); + RegisterDefaultFactoryFor >("HMAC_DRBG(SHA256)"); + + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); +} diff --git a/extension/third_party/cryptopp/regtest2.cpp b/extension/third_party/cryptopp/regtest2.cpp new file mode 100644 index 00000000..e379432d --- /dev/null +++ b/extension/third_party/cryptopp/regtest2.cpp @@ -0,0 +1,105 @@ +// regtest2.cpp - originally written and placed in the public domain by Wei Dai +// regtest.cpp split into 3 files due to OOM kills by JW +// in April 2017. A second split occurred in July 2018. + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "factory.h" +#include "bench.h" +#include "cpu.h" + +// For MAC's +#include "hmac.h" +#include "cmac.h" +#include "dmac.h" +#include "vmac.h" +#include "ttmac.h" + +// Ciphers +#include "md5.h" +#include "keccak.h" +#include "sha.h" +#include "sha3.h" +#include "blake2.h" +#include "ripemd.h" +#include "chacha.h" +#include "poly1305.h" +#include "siphash.h" +#include "panama.h" + +// Stream ciphers +#include "arc4.h" +#include "seal.h" +#include "wake.h" +#include "chacha.h" +#include "salsa.h" +#include "rabbit.h" +#include "hc128.h" +#include "hc256.h" +#include "panama.h" +#include "sosemanuk.h" + +// Block for CMAC +#include "aes.h" +#include "des.h" + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +USING_NAMESPACE(CryptoPP) + +// MAC ciphers +void RegisterFactories2() +{ + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor(); + RegisterDefaultFactoryFor >(); + RegisterDefaultFactoryFor >(); +} + +// Stream ciphers +void RegisterFactories3() +{ + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); +} diff --git a/extension/third_party/cryptopp/regtest3.cpp b/extension/third_party/cryptopp/regtest3.cpp new file mode 100644 index 00000000..370756a6 --- /dev/null +++ b/extension/third_party/cryptopp/regtest3.cpp @@ -0,0 +1,155 @@ +// regtest3.cpp - originally written and placed in the public domain by Wei Dai +// regtest.cpp split into 3 files due to OOM kills by JW +// in April 2017. A second split occurred in July 2018. + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "factory.h" +#include "bench.h" +#include "cpu.h" + +#include "modes.h" +#include "aria.h" +#include "seed.h" +#include "hight.h" +#include "camellia.h" +#include "shacal2.h" +#include "tea.h" +#include "aes.h" +#include "tiger.h" +#include "ccm.h" +#include "gcm.h" +#include "eax.h" +#include "xts.h" +#include "twofish.h" +#include "serpent.h" +#include "cast.h" +#include "rc6.h" +#include "mars.h" +#include "kalyna.h" +#include "threefish.h" +#include "cham.h" +#include "lea.h" +#include "simeck.h" +#include "simon.h" +#include "speck.h" +#include "sm4.h" +#include "des.h" +#include "idea.h" +#include "rc5.h" +#include "skipjack.h" +#include "blowfish.h" +#include "chachapoly.h" + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +USING_NAMESPACE(CryptoPP) + +// Shared key ciphers +void RegisterFactories4() +{ + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + + RegisterAuthenticatedSymmetricCipherDefaultFactories >(); + RegisterAuthenticatedSymmetricCipherDefaultFactories >(); + RegisterAuthenticatedSymmetricCipherDefaultFactories >(); + RegisterAuthenticatedSymmetricCipherDefaultFactories(); + RegisterAuthenticatedSymmetricCipherDefaultFactories(); + + RegisterSymmetricCipherDefaultFactories >(); // For test vectors + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + RegisterSymmetricCipherDefaultFactories >(); + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks + + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Test Vectors + RegisterSymmetricCipherDefaultFactories >(); // Benchmarks +} diff --git a/extension/third_party/cryptopp/regtest4.cpp b/extension/third_party/cryptopp/regtest4.cpp new file mode 100644 index 00000000..f4532083 --- /dev/null +++ b/extension/third_party/cryptopp/regtest4.cpp @@ -0,0 +1,58 @@ +// regtest4.cpp - originally written and placed in the public domain by Wei Dai +// regtest.cpp split into 3 files due to OOM kills by JW +// in April 2017. A second split occurred in July 2018. + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "factory.h" +#include "bench.h" +#include "cpu.h" + +#include "dh.h" +#include "nr.h" +#include "rw.h" +#include "rsa.h" +#include "dsa.h" +#include "pssr.h" +#include "esign.h" + +// Hashes +#include "md2.h" +#include "md5.h" +#include "sha.h" + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +USING_NAMESPACE(CryptoPP) + +void RegisterFactories5() +{ + RegisterDefaultFactoryFor(); + RegisterAsymmetricCipherDefaultFactories > >("RSA/OAEP-MGF1(SHA-1)"); + RegisterAsymmetricCipherDefaultFactories >("DLIES(NoCofactorMultiplication, KDF2(SHA-1), XOR, HMAC(SHA-1), DHAES)"); + RegisterSignatureSchemeDefaultFactories(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >("NR(1363)/EMSA1(SHA-1)"); + RegisterSignatureSchemeDefaultFactories >("DSA-1363/EMSA1(SHA-1)"); + RegisterSignatureSchemeDefaultFactories >("RSA/PKCS1-1.5(MD2)"); + RegisterSignatureSchemeDefaultFactories >("RSA/PKCS1-1.5(SHA-1)"); + RegisterSignatureSchemeDefaultFactories >("ESIGN/EMSA5-MGF1(SHA-1)"); + RegisterSignatureSchemeDefaultFactories >("RW/EMSA2(SHA-1)"); + RegisterSignatureSchemeDefaultFactories >("RSA/PSS-MGF1(SHA-1)"); +} diff --git a/extension/third_party/cryptopp/resource.h b/extension/third_party/cryptopp/resource.h new file mode 100644 index 00000000..80f1df1a --- /dev/null +++ b/extension/third_party/cryptopp/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cryptopp.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/extension/third_party/cryptopp/rijndael.cpp b/extension/third_party/cryptopp/rijndael.cpp new file mode 100644 index 00000000..65f6d9e0 --- /dev/null +++ b/extension/third_party/cryptopp/rijndael.cpp @@ -0,0 +1,1334 @@ +// rijndael.cpp - modified by Chris Morgan +// and Wei Dai from Paulo Baretto's Rijndael implementation +// The original code and all modifications are in the public domain. + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM rijndael.cpp" to generate MASM code + +/* +July 2018: Added support for ARMv7 AES instructions via Cryptogams ASM. + See the head notes in aes_armv4.S for copyright and license. +*/ + +/* +September 2017: Added support for Power8 AES instructions via compiler intrinsics. +*/ + +/* +July 2017: Added support for ARMv8 AES instructions via compiler intrinsics. +*/ + +/* +July 2010: Added support for AES-NI instructions via compiler intrinsics. +*/ + +/* +Feb 2009: The x86/x64 assembly code was rewritten in by Wei Dai to do counter mode +caching, which was invented by Hongjun Wu and popularized by Daniel J. Bernstein +and Peter Schwabe in their paper "New AES software speed records". The round +function was also modified to include a trick similar to one in Brian Gladman's +x86 assembly code, doing an 8-bit register move to minimize the number of +register spills. Also switched to compressed tables and copying round keys to +the stack. + +The C++ implementation uses compressed tables if +CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS is defined. +It is defined on x86 platforms by default but no others. +*/ + +/* +July 2006: Defense against timing attacks was added in by Wei Dai. + +The code now uses smaller tables in the first and last rounds, +and preloads them into L1 cache before usage (by loading at least +one element in each cache line). + +We try to delay subsequent accesses to each table (used in the first +and last rounds) until all of the table has been preloaded. Hopefully +the compiler isn't smart enough to optimize that code away. + +After preloading the table, we also try not to access any memory location +other than the table and the stack, in order to prevent table entries from +being unloaded from L1 cache, until that round is finished. +(Some popular CPUs have 2-way associative caches.) +*/ + +// This is the original introductory comment: + +/** + * version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * author Vincent Rijmen + * author Antoon Bosselaers + * author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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. + */ + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_IMPORTS +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#include "rijndael.h" +#include "misc.h" +#include "cpu.h" + +// VS2017 and global optimization bug. TODO, figure out when +// we can re-enable full optimizations for VS2017. Also see +// https://github.com/weidai11/cryptopp/issues/649 +#if (_MSC_VER >= 1910) +# ifndef CRYPTOPP_DEBUG +# pragma optimize("", off) +# pragma optimize("ts", on) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// Hack for http://github.com/weidai11/cryptopp/issues/42 and http://github.com/weidai11/cryptopp/issues/132 +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) +# define CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS 1 +#endif + +// Clang intrinsic casts +#define M128I_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128I_CAST(x) ((const __m128i *)(const void *)(x)) + +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) +# if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) +namespace rdtable {CRYPTOPP_ALIGN_DATA(16) word64 Te[256+2];} +using namespace rdtable; +# else +static word64 Te[256]; +# endif +static word64 Td[256]; +#else // Not CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS +# if defined(CRYPTOPP_X64_MASM_AVAILABLE) +// Unused; avoids linker error on Microsoft X64 non-AESNI platforms +namespace rdtable {CRYPTOPP_ALIGN_DATA(16) word64 Te[256+2];} +# endif +CRYPTOPP_ALIGN_DATA(16) static word32 Te[256*4]; +CRYPTOPP_ALIGN_DATA(16) static word32 Td[256*4]; +#endif // CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS + +static volatile bool s_TeFilled = false, s_TdFilled = false; + +ANONYMOUS_NAMESPACE_BEGIN + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 + +// Determine whether the range between begin and end overlaps +// with the same 4k block offsets as the Te table. Logically, +// the code is trying to create the condition: +// +// Two sepearate memory pages: +// +// +-----+ +-----+ +// |XXXXX| |YYYYY| +// |XXXXX| |YYYYY| +// | | | | +// | | | | +// +-----+ +-----+ +// Te Table Locals +// +// Have a logical cache view of (X and Y may be inverted): +// +// +-----+ +// |XXXXX| +// |XXXXX| +// |YYYYY| +// |YYYYY| +// +-----+ +// +static inline bool AliasedWithTable(const byte *begin, const byte *end) +{ + ptrdiff_t s0 = uintptr_t(begin)%4096, s1 = uintptr_t(end)%4096; + ptrdiff_t t0 = uintptr_t(Te)%4096, t1 = (uintptr_t(Te)+sizeof(Te))%4096; + if (t1 > t0) + return (s0 >= t0 && s0 < t1) || (s1 > t0 && s1 <= t1); + else + return (s0 < t1 || s1 <= t1) || (s0 >= t0 || s1 > t0); +} + +struct Locals +{ + word32 subkeys[4*12], workspace[8]; + const byte *inBlocks, *inXorBlocks, *outXorBlocks; + byte *outBlocks; + size_t inIncrement, inXorIncrement, outXorIncrement, outIncrement; + size_t regSpill, lengthAndCounterFlag, keysBegin; +}; + +const size_t s_aliasPageSize = 4096; +const size_t s_aliasBlockSize = 256; +const size_t s_sizeToAllocate = s_aliasPageSize + s_aliasBlockSize + sizeof(Locals); + +#endif // CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 + +ANONYMOUS_NAMESPACE_END + +// ************************* Portable Code ************************************ + +#define QUARTER_ROUND(L, T, t, a, b, c, d) \ + a ^= L(T, 3, byte(t)); t >>= 8;\ + b ^= L(T, 2, byte(t)); t >>= 8;\ + c ^= L(T, 1, byte(t)); t >>= 8;\ + d ^= L(T, 0, t); + +#define QUARTER_ROUND_LE(t, a, b, c, d) \ + tempBlock[a] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\ + tempBlock[b] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\ + tempBlock[c] = ((byte *)(Te+byte(t)))[1]; t >>= 8;\ + tempBlock[d] = ((byte *)(Te+t))[1]; + +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + #define QUARTER_ROUND_LD(t, a, b, c, d) \ + tempBlock[a] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\ + tempBlock[b] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\ + tempBlock[c] = ((byte *)(Td+byte(t)))[GetNativeByteOrder()*7]; t >>= 8;\ + tempBlock[d] = ((byte *)(Td+t))[GetNativeByteOrder()*7]; +#else + #define QUARTER_ROUND_LD(t, a, b, c, d) \ + tempBlock[a] = Sd[byte(t)]; t >>= 8;\ + tempBlock[b] = Sd[byte(t)]; t >>= 8;\ + tempBlock[c] = Sd[byte(t)]; t >>= 8;\ + tempBlock[d] = Sd[t]; +#endif + +#define QUARTER_ROUND_E(t, a, b, c, d) QUARTER_ROUND(TL_M, Te, t, a, b, c, d) +#define QUARTER_ROUND_D(t, a, b, c, d) QUARTER_ROUND(TL_M, Td, t, a, b, c, d) + +#if (CRYPTOPP_LITTLE_ENDIAN) + #define QUARTER_ROUND_FE(t, a, b, c, d) QUARTER_ROUND(TL_F, Te, t, d, c, b, a) + #define QUARTER_ROUND_FD(t, a, b, c, d) QUARTER_ROUND(TL_F, Td, t, d, c, b, a) + #if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + #define TL_F(T, i, x) (*(word32 *)(void *)((byte *)T + x*8 + (6-i)%4+1)) + #define TL_M(T, i, x) (*(word32 *)(void *)((byte *)T + x*8 + (i+3)%4+1)) + #else + #define TL_F(T, i, x) rotrFixed(T[x], (3-i)*8) + #define TL_M(T, i, x) T[i*256 + x] + #endif +#else + #define QUARTER_ROUND_FE(t, a, b, c, d) QUARTER_ROUND(TL_F, Te, t, a, b, c, d) + #define QUARTER_ROUND_FD(t, a, b, c, d) QUARTER_ROUND(TL_F, Td, t, a, b, c, d) + #if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + #define TL_F(T, i, x) (*(word32 *)(void *)((byte *)T + x*8 + (4-i)%4)) + #define TL_M TL_F + #else + #define TL_F(T, i, x) rotrFixed(T[x], i*8) + #define TL_M(T, i, x) T[i*256 + x] + #endif +#endif + + +#define f2(x) ((x<<1)^(((x>>7)&1)*0x11b)) +#define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b)) +#define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b)) + +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +unsigned int Rijndael::Base::OptimalDataAlignment() const +{ +#if (CRYPTOPP_AESNI_AVAILABLE) + if (HasAESNI()) + return 16; // load __m128i +#endif +#if (CRYPTOPP_ARM_AES_AVAILABLE) + if (HasAES()) + return 4; // load uint32x4_t +#endif +#if (CRYPTOGAMS_ARM_AES) + // Must use 1 here for Cryptogams AES. Also see + // https://github.com/weidai11/cryptopp/issues/683 + if (HasARMv7()) + return 1; +#endif +#if (CRYPTOPP_POWER8_AES_AVAILABLE) + if (HasAES()) + return 16; // load uint32x4_p +#endif + return BlockTransformation::OptimalDataAlignment(); +} + +void Rijndael::Base::FillEncTable() +{ + for (int i=0; i<256; i++) + { + byte x = Se[i]; +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + word32 y = word32(x)<<8 | word32(x)<<16 | word32(f2(x))<<24; + Te[i] = word64(y | f3(x))<<32 | y; +#else + word32 y = f3(x) | word32(x)<<8 | word32(x)<<16 | word32(f2(x))<<24; + for (int j=0; j<4; j++) + { + Te[i+j*256] = y; + y = rotrConstant<8>(y); + } +#endif + } +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) + Te[256] = Te[257] = 0; +#endif + s_TeFilled = true; +} + +void Rijndael::Base::FillDecTable() +{ + for (int i=0; i<256; i++) + { + byte x = Sd[i]; +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + word32 y = word32(fd(x))<<8 | word32(f9(x))<<16 | word32(fe(x))<<24; + Td[i] = word64(y | fb(x))<<32 | y | x; +#else + word32 y = fb(x) | word32(fd(x))<<8 | word32(f9(x))<<16 | word32(fe(x))<<24; + for (int j=0; j<4; j++) + { + Td[i+j*256] = y; + y = rotrConstant<8>(y); + } +#endif + } + s_TdFilled = true; +} + +#if (CRYPTOPP_AESNI_AVAILABLE) +extern void Rijndael_UncheckedSetKey_SSE4_AESNI(const byte *userKey, size_t keyLen, word32* rk); +extern void Rijndael_UncheckedSetKeyRev_AESNI(word32 *key, unsigned int rounds); + +extern size_t Rijndael_Enc_AdvancedProcessBlocks_AESNI(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +extern size_t Rijndael_Dec_AdvancedProcessBlocks_AESNI(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_ARM_AES_AVAILABLE) +extern size_t Rijndael_Enc_AdvancedProcessBlocks_ARMV8(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +extern size_t Rijndael_Dec_AdvancedProcessBlocks_ARMV8(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOGAMS_ARM_AES) +extern "C" int cryptogams_AES_set_encrypt_key(const unsigned char *userKey, const int bitLen, word32 *rkey); +extern "C" int cryptogams_AES_set_decrypt_key(const unsigned char *userKey, const int bitLen, word32 *rkey); +extern "C" void cryptogams_AES_encrypt_block(const unsigned char *in, unsigned char *out, const word32 *rkey); +extern "C" void cryptogams_AES_decrypt_block(const unsigned char *in, unsigned char *out, const word32 *rkey); +#endif + +#if (CRYPTOPP_POWER8_AES_AVAILABLE) +extern void Rijndael_UncheckedSetKey_POWER8(const byte* userKey, size_t keyLen, + word32* rk, const byte* Se); + +extern size_t Rijndael_Enc_AdvancedProcessBlocks128_6x1_ALTIVEC(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +extern size_t Rijndael_Dec_AdvancedProcessBlocks128_6x1_ALTIVEC(const word32 *subkeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOGAMS_ARM_AES) +int CRYPTOGAMS_set_encrypt_key(const byte *userKey, const int bitLen, word32 *rkey) +{ + return cryptogams_AES_set_encrypt_key(userKey, bitLen, rkey); +} +int CRYPTOGAMS_set_decrypt_key(const byte *userKey, const int bitLen, word32 *rkey) +{ + return cryptogams_AES_set_decrypt_key(userKey, bitLen, rkey); +} +void CRYPTOGAMS_encrypt(const byte *inBlock, const byte *xorBlock, byte *outBlock, const word32 *rkey) +{ + cryptogams_AES_encrypt_block(inBlock, outBlock, rkey); + if (xorBlock) + xorbuf (outBlock, xorBlock, 16); +} +void CRYPTOGAMS_decrypt(const byte *inBlock, const byte *xorBlock, byte *outBlock, const word32 *rkey) +{ + cryptogams_AES_decrypt_block(inBlock, outBlock, rkey); + if (xorBlock) + xorbuf (outBlock, xorBlock, 16); +} +#endif + +std::string Rijndael::Base::AlgorithmProvider() const +{ +#if (CRYPTOPP_AESNI_AVAILABLE) + if (HasAESNI()) + return "AESNI"; +#endif +#if CRYPTOPP_SSE2_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) + if (HasSSE2()) + return "SSE2"; +#endif +#if (CRYPTOPP_ARM_AES_AVAILABLE) + if (HasAES()) + return "ARMv8"; +#endif +#if (CRYPTOGAMS_ARM_AES) + if (HasARMv7()) + return "ARMv7"; +#endif +#if (CRYPTOPP_POWER8_AES_AVAILABLE) + if (HasAES()) + return "Power8"; +#endif + return "C++"; +} + +void Rijndael::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLen, const NameValuePairs &) +{ + AssertValidKeyLength(keyLen); + +#if (CRYPTOGAMS_ARM_AES) + if (HasARMv7()) + { + m_rounds = keyLen/4 + 6; + m_key.New(4*(14+1)+4); + + if (IsForwardTransformation()) + CRYPTOGAMS_set_encrypt_key(userKey, keyLen*8, m_key.begin()); + else + CRYPTOGAMS_set_decrypt_key(userKey, keyLen*8, m_key.begin()); + return; + } +#endif + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 + m_aliasBlock.New(s_sizeToAllocate); + // The alias block is only used on IA-32 when unaligned data access is in effect. + // Setting the low water mark to 0 avoids zeroization when m_aliasBlock is unused. + m_aliasBlock.SetMark(0); +#endif + + m_rounds = keyLen/4 + 6; + m_key.New(4*(m_rounds+1)); + word32 *rk = m_key; + +#if (CRYPTOPP_AESNI_AVAILABLE && CRYPTOPP_SSE41_AVAILABLE && (!defined(_MSC_VER) || _MSC_VER >= 1600 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32)) + // MSVC 2008 SP1 generates bad code for _mm_extract_epi32() when compiling for X64 + if (HasAESNI() && HasSSE41()) + { + // TODO: Add non-SSE4.1 variant for low-end Atoms. The low-end + // Atoms have SSE2-SSSE3 and AES-NI, but not SSE4.1 or SSE4.2. + Rijndael_UncheckedSetKey_SSE4_AESNI(userKey, keyLen, rk); + if (!IsForwardTransformation()) + Rijndael_UncheckedSetKeyRev_AESNI(m_key, m_rounds); + + return; + } +#endif + +#if CRYPTOPP_POWER8_AES_AVAILABLE + if (HasAES()) + { + // We still need rcon and Se to fallback to C/C++ for AES-192 and AES-256. + // The IBM docs on AES sucks. Intel's docs on AESNI puts IBM to shame. + Rijndael_UncheckedSetKey_POWER8(userKey, keyLen, rk, Se); + return; + } +#endif + + GetUserKey(BIG_ENDIAN_ORDER, rk, keyLen/4, userKey, keyLen); + const word32 *rc = rcon; + word32 temp; + + while (true) + { + temp = rk[keyLen/4-1]; + word32 x = (word32(Se[GETBYTE(temp, 2)]) << 24) ^ (word32(Se[GETBYTE(temp, 1)]) << 16) ^ + (word32(Se[GETBYTE(temp, 0)]) << 8) ^ Se[GETBYTE(temp, 3)]; + rk[keyLen/4] = rk[0] ^ x ^ *(rc++); + rk[keyLen/4+1] = rk[1] ^ rk[keyLen/4]; + rk[keyLen/4+2] = rk[2] ^ rk[keyLen/4+1]; + rk[keyLen/4+3] = rk[3] ^ rk[keyLen/4+2]; + + if (rk + keyLen/4 + 4 == m_key.end()) + break; + + if (keyLen == 24) + { + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + } + else if (keyLen == 32) + { + temp = rk[11]; + rk[12] = rk[ 4] ^ (word32(Se[GETBYTE(temp, 3)]) << 24) ^ (word32(Se[GETBYTE(temp, 2)]) << 16) ^ (word32(Se[GETBYTE(temp, 1)]) << 8) ^ Se[GETBYTE(temp, 0)]; + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + } + rk += keyLen/4; + } + + rk = m_key; + + if (IsForwardTransformation()) + { + if (!s_TeFilled) + FillEncTable(); + + ConditionalByteReverse(BIG_ENDIAN_ORDER, rk, rk, 16); + ConditionalByteReverse(BIG_ENDIAN_ORDER, rk + m_rounds*4, rk + m_rounds*4, 16); + } + else + { + if (!s_TdFilled) + FillDecTable(); + + #define InverseMixColumn(x) \ + TL_M(Td, 0, Se[GETBYTE(x, 3)]) ^ TL_M(Td, 1, Se[GETBYTE(x, 2)]) ^ \ + TL_M(Td, 2, Se[GETBYTE(x, 1)]) ^ TL_M(Td, 3, Se[GETBYTE(x, 0)]) + + unsigned int i, j; + for (i = 4, j = 4*m_rounds-4; i < j; i += 4, j -= 4) + { + temp = InverseMixColumn(rk[i ]); rk[i ] = InverseMixColumn(rk[j ]); rk[j ] = temp; + temp = InverseMixColumn(rk[i + 1]); rk[i + 1] = InverseMixColumn(rk[j + 1]); rk[j + 1] = temp; + temp = InverseMixColumn(rk[i + 2]); rk[i + 2] = InverseMixColumn(rk[j + 2]); rk[j + 2] = temp; + temp = InverseMixColumn(rk[i + 3]); rk[i + 3] = InverseMixColumn(rk[j + 3]); rk[j + 3] = temp; + } + + rk[i+0] = InverseMixColumn(rk[i+0]); + rk[i+1] = InverseMixColumn(rk[i+1]); + rk[i+2] = InverseMixColumn(rk[i+2]); + rk[i+3] = InverseMixColumn(rk[i+3]); + + temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[0]); rk[0] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+0]); rk[4*m_rounds+0] = temp; + temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[1]); rk[1] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+1]); rk[4*m_rounds+1] = temp; + temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[2]); rk[2] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+2]); rk[4*m_rounds+2] = temp; + temp = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[3]); rk[3] = ConditionalByteReverse(BIG_ENDIAN_ORDER, rk[4*m_rounds+3]); rk[4*m_rounds+3] = temp; + } + +#if CRYPTOPP_AESNI_AVAILABLE + if (HasAESNI()) + ConditionalByteReverse(BIG_ENDIAN_ORDER, rk+4, rk+4, (m_rounds-1)*16); +#endif +#if CRYPTOPP_ARM_AES_AVAILABLE + if (HasAES()) + ConditionalByteReverse(BIG_ENDIAN_ORDER, rk+4, rk+4, (m_rounds-1)*16); +#endif +} + +void Rijndael::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) || CRYPTOPP_AESNI_AVAILABLE +# if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) + if (HasSSE2()) +# else + if (HasAESNI()) +# endif + { + (void)Rijndael::Enc::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + +#if (CRYPTOPP_ARM_AES_AVAILABLE) + if (HasAES()) + { + (void)Rijndael::Enc::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + +#if (CRYPTOGAMS_ARM_AES) + if (HasARMv7()) + { + CRYPTOGAMS_encrypt(inBlock, xorBlock, outBlock, m_key.begin()); + return; + } +#endif + +#if (CRYPTOPP_POWER8_AES_AVAILABLE) + if (HasAES()) + { + (void)Rijndael::Enc::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + + typedef BlockGetAndPut Block; + + word32 s0, s1, s2, s3, t0, t1, t2, t3; + Block::Get(inBlock)(s0)(s1)(s2)(s3); + + const word32 *rk = m_key; + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + t0 = rk[4]; + t1 = rk[5]; + t2 = rk[6]; + t3 = rk[7]; + rk += 8; + + // timing attack countermeasure. see comments at top for more details. + // also see http://github.com/weidai11/cryptopp/issues/146 + const int cacheLineSize = GetCacheLineSize(); + unsigned int i; + volatile word32 _u = 0; + word32 u = _u; +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + for (i=0; i<2048; i+=cacheLineSize) +#else + for (i=0; i<1024; i+=cacheLineSize) +#endif + u &= *(const word32 *)(const void *)(((const byte *)Te)+i); + u &= Te[255]; + s0 |= u; s1 |= u; s2 |= u; s3 |= u; + + QUARTER_ROUND_FE(s3, t0, t1, t2, t3) + QUARTER_ROUND_FE(s2, t3, t0, t1, t2) + QUARTER_ROUND_FE(s1, t2, t3, t0, t1) + QUARTER_ROUND_FE(s0, t1, t2, t3, t0) + + // Nr - 2 full rounds: + unsigned int r = m_rounds/2 - 1; + do + { + s0 = rk[0]; s1 = rk[1]; s2 = rk[2]; s3 = rk[3]; + + QUARTER_ROUND_E(t3, s0, s1, s2, s3) + QUARTER_ROUND_E(t2, s3, s0, s1, s2) + QUARTER_ROUND_E(t1, s2, s3, s0, s1) + QUARTER_ROUND_E(t0, s1, s2, s3, s0) + + t0 = rk[4]; t1 = rk[5]; t2 = rk[6]; t3 = rk[7]; + + QUARTER_ROUND_E(s3, t0, t1, t2, t3) + QUARTER_ROUND_E(s2, t3, t0, t1, t2) + QUARTER_ROUND_E(s1, t2, t3, t0, t1) + QUARTER_ROUND_E(s0, t1, t2, t3, t0) + + rk += 8; + } while (--r); + + word32 tbw[4]; + byte *const tempBlock = (byte *)tbw; + + QUARTER_ROUND_LE(t2, 15, 2, 5, 8) + QUARTER_ROUND_LE(t1, 11, 14, 1, 4) + QUARTER_ROUND_LE(t0, 7, 10, 13, 0) + QUARTER_ROUND_LE(t3, 3, 6, 9, 12) + + Block::Put(xorBlock, outBlock)(tbw[0]^rk[0])(tbw[1]^rk[1])(tbw[2]^rk[2])(tbw[3]^rk[3]); +} + +void Rijndael::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ +#if CRYPTOPP_AESNI_AVAILABLE + if (HasAESNI()) + { + (void)Rijndael::Dec::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + +#if (CRYPTOPP_ARM_AES_AVAILABLE) + if (HasAES()) + { + (void)Rijndael::Dec::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + +#if (CRYPTOGAMS_ARM_AES) + if (HasARMv7()) + { + CRYPTOGAMS_decrypt(inBlock, xorBlock, outBlock, m_key.begin()); + return; + } +#endif + +#if (CRYPTOPP_POWER8_AES_AVAILABLE) + if (HasAES()) + { + (void)Rijndael::Dec::AdvancedProcessBlocks(inBlock, xorBlock, outBlock, 16, 0); + return; + } +#endif + + typedef BlockGetAndPut Block; + + word32 s0, s1, s2, s3, t0, t1, t2, t3; + Block::Get(inBlock)(s0)(s1)(s2)(s3); + + const word32 *rk = m_key; + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + t0 = rk[4]; + t1 = rk[5]; + t2 = rk[6]; + t3 = rk[7]; + rk += 8; + + // timing attack countermeasure. see comments at top for more details. + // also see http://github.com/weidai11/cryptopp/issues/146 + const int cacheLineSize = GetCacheLineSize(); + unsigned int i; + volatile word32 _u = 0; + word32 u = _u; +#if defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS) + for (i=0; i<2048; i+=cacheLineSize) +#else + for (i=0; i<1024; i+=cacheLineSize) +#endif + u &= *(const word32 *)(const void *)(((const byte *)Td)+i); + u &= Td[255]; + s0 |= u; s1 |= u; s2 |= u; s3 |= u; + + QUARTER_ROUND_FD(s3, t2, t1, t0, t3) + QUARTER_ROUND_FD(s2, t1, t0, t3, t2) + QUARTER_ROUND_FD(s1, t0, t3, t2, t1) + QUARTER_ROUND_FD(s0, t3, t2, t1, t0) + + // Nr - 2 full rounds: + unsigned int r = m_rounds/2 - 1; + do + { + s0 = rk[0]; s1 = rk[1]; s2 = rk[2]; s3 = rk[3]; + + QUARTER_ROUND_D(t3, s2, s1, s0, s3) + QUARTER_ROUND_D(t2, s1, s0, s3, s2) + QUARTER_ROUND_D(t1, s0, s3, s2, s1) + QUARTER_ROUND_D(t0, s3, s2, s1, s0) + + t0 = rk[4]; t1 = rk[5]; t2 = rk[6]; t3 = rk[7]; + + QUARTER_ROUND_D(s3, t2, t1, t0, t3) + QUARTER_ROUND_D(s2, t1, t0, t3, t2) + QUARTER_ROUND_D(s1, t0, t3, t2, t1) + QUARTER_ROUND_D(s0, t3, t2, t1, t0) + + rk += 8; + } while (--r); + +#if !(defined(CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS)) + // timing attack countermeasure. see comments at top for more details + // If CRYPTOPP_ALLOW_RIJNDAEL_UNALIGNED_DATA_ACCESS is defined, + // QUARTER_ROUND_LD will use Td, which is already preloaded. + u = _u; + for (i=0; i<256; i+=cacheLineSize) + u &= *(const word32 *)(const void *)(Sd+i); + u &= *(const word32 *)(const void *)(Sd+252); + t0 |= u; t1 |= u; t2 |= u; t3 |= u; +#endif + + word32 tbw[4]; + byte *const tempBlock = (byte *)tbw; + + QUARTER_ROUND_LD(t2, 7, 2, 13, 8) + QUARTER_ROUND_LD(t1, 3, 14, 9, 4) + QUARTER_ROUND_LD(t0, 15, 10, 5, 0) + QUARTER_ROUND_LD(t3, 11, 6, 1, 12) + + Block::Put(xorBlock, outBlock)(tbw[0]^rk[0])(tbw[1]^rk[1])(tbw[2]^rk[2])(tbw[3]^rk[3]); +} + +// ************************* Assembly Code ************************************ + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code +#endif + +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM + +#if CRYPTOPP_SSE2_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) + +CRYPTOPP_NAKED void CRYPTOPP_FASTCALL Rijndael_Enc_AdvancedProcessBlocks_SSE2(void *locals, const word32 *k) +{ + CRYPTOPP_UNUSED(locals); CRYPTOPP_UNUSED(k); + +#if CRYPTOPP_BOOL_X86 + +#define L_REG esp +#define L_INDEX(i) (L_REG+768+i) +#define L_INXORBLOCKS L_INBLOCKS+4 +#define L_OUTXORBLOCKS L_INBLOCKS+8 +#define L_OUTBLOCKS L_INBLOCKS+12 +#define L_INCREMENTS L_INDEX(16*15) +#define L_SP L_INDEX(16*16) +#define L_LENGTH L_INDEX(16*16+4) +#define L_KEYS_BEGIN L_INDEX(16*16+8) + +#define MOVD movd +#define MM(i) mm##i + +#define MXOR(a,b,c) \ + AS2( movzx esi, b)\ + AS2( movd mm7, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + AS2( pxor MM(a), mm7)\ + +#define MMOV(a,b,c) \ + AS2( movzx esi, b)\ + AS2( movd MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + +#else + +#define L_REG r8 +#define L_INDEX(i) (L_REG+i) +#define L_INXORBLOCKS L_INBLOCKS+8 +#define L_OUTXORBLOCKS L_INBLOCKS+16 +#define L_OUTBLOCKS L_INBLOCKS+24 +#define L_INCREMENTS L_INDEX(16*16) +#define L_LENGTH L_INDEX(16*18+8) +#define L_KEYS_BEGIN L_INDEX(16*19) + +#define MOVD mov +#define MM_0 r9d +#define MM_1 r12d +#ifdef __GNUC__ +#define MM_2 r11d +#else +#define MM_2 r10d +#endif +#define MM(i) MM_##i + +#define MXOR(a,b,c) \ + AS2( movzx esi, b)\ + AS2( xor MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + +#define MMOV(a,b,c) \ + AS2( movzx esi, b)\ + AS2( mov MM(a), DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + +#endif + +#define L_SUBKEYS L_INDEX(0) +#define L_SAVED_X L_SUBKEYS +#define L_KEY12 L_INDEX(16*12) +#define L_LASTROUND L_INDEX(16*13) +#define L_INBLOCKS L_INDEX(16*14) +#define MAP0TO4(i) (ASM_MOD(i+3,4)+1) + +#define XOR(a,b,c) \ + AS2( movzx esi, b)\ + AS2( xor a, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + +#define MOV(a,b,c) \ + AS2( movzx esi, b)\ + AS2( mov a, DWORD PTR [AS_REG_7+8*WORD_REG(si)+MAP0TO4(c)])\ + +#ifdef CRYPTOPP_GENERATE_X64_MASM + ALIGN 8 + Rijndael_Enc_AdvancedProcessBlocks PROC FRAME + rex_push_reg rsi + push_reg rdi + push_reg rbx + push_reg r12 + .endprolog + mov L_REG, rcx + mov AS_REG_7, ?Te@rdtable@CryptoPP@@3PA_KA + mov edi, DWORD PTR [?g_cacheLineSize@CryptoPP@@3IA] +#elif defined(__GNUC__) + __asm__ __volatile__ + ( + INTEL_NOPREFIX + #if CRYPTOPP_BOOL_X64 + AS2( mov L_REG, rcx) + #endif + AS_PUSH_IF86(bx) + AS_PUSH_IF86(bp) + AS2( mov AS_REG_7, WORD_REG(si)) +#else + AS_PUSH_IF86(si) + AS_PUSH_IF86(di) + AS_PUSH_IF86(bx) + AS_PUSH_IF86(bp) + AS2( lea AS_REG_7, [Te]) + AS2( mov edi, [g_cacheLineSize]) +#endif + +#if CRYPTOPP_BOOL_X86 + AS2( mov [ecx+16*12+16*4], esp) // save esp to L_SP + AS2( lea esp, [ecx-768]) +#endif + + // copy subkeys to stack + AS2( mov WORD_REG(si), [L_KEYS_BEGIN]) + AS2( mov WORD_REG(ax), 16) + AS2( and WORD_REG(ax), WORD_REG(si)) + AS2( movdqa xmm3, XMMWORD_PTR [WORD_REG(dx)+16+WORD_REG(ax)]) // subkey 1 (non-counter) or 2 (counter) + AS2( movdqa [L_KEY12], xmm3) + AS2( lea WORD_REG(ax), [WORD_REG(dx)+WORD_REG(ax)+2*16]) + AS2( sub WORD_REG(ax), WORD_REG(si)) + ASL(0) + AS2( movdqa xmm0, [WORD_REG(ax)+WORD_REG(si)]) + AS2( movdqa XMMWORD_PTR [L_SUBKEYS+WORD_REG(si)], xmm0) + AS2( add WORD_REG(si), 16) + AS2( cmp WORD_REG(si), 16*12) + ATT_NOPREFIX + ASJ( jl, 0, b) + INTEL_NOPREFIX + + // read subkeys 0, 1 and last + AS2( movdqa xmm4, [WORD_REG(ax)+WORD_REG(si)]) // last subkey + AS2( movdqa xmm1, [WORD_REG(dx)]) // subkey 0 + AS2( MOVD MM(1), [WORD_REG(dx)+4*4]) // 0,1,2,3 + AS2( mov ebx, [WORD_REG(dx)+5*4]) // 4,5,6,7 + AS2( mov ecx, [WORD_REG(dx)+6*4]) // 8,9,10,11 + AS2( mov edx, [WORD_REG(dx)+7*4]) // 12,13,14,15 + + // load table into cache + AS2( xor WORD_REG(ax), WORD_REG(ax)) + ASL(9) + AS2( mov esi, [AS_REG_7+WORD_REG(ax)]) + AS2( add WORD_REG(ax), WORD_REG(di)) + AS2( mov esi, [AS_REG_7+WORD_REG(ax)]) + AS2( add WORD_REG(ax), WORD_REG(di)) + AS2( mov esi, [AS_REG_7+WORD_REG(ax)]) + AS2( add WORD_REG(ax), WORD_REG(di)) + AS2( mov esi, [AS_REG_7+WORD_REG(ax)]) + AS2( add WORD_REG(ax), WORD_REG(di)) + AS2( cmp WORD_REG(ax), 2048) + ATT_NOPREFIX + ASJ( jl, 9, b) + INTEL_NOPREFIX + AS1( lfence) + + AS2( test DWORD PTR [L_LENGTH], 1) + ATT_NOPREFIX + ASJ( jz, 8, f) + INTEL_NOPREFIX + + // counter mode one-time setup + AS2( mov WORD_REG(si), [L_INBLOCKS]) + AS2( movdqu xmm2, [WORD_REG(si)]) // counter + AS2( pxor xmm2, xmm1) + AS2( psrldq xmm1, 14) + AS2( movd eax, xmm1) + AS2( mov al, BYTE PTR [WORD_REG(si)+15]) + AS2( MOVD MM(2), eax) +#if CRYPTOPP_BOOL_X86 + AS2( mov eax, 1) + AS2( movd mm3, eax) +#endif + + // partial first round, in: xmm2(15,14,13,12;11,10,9,8;7,6,5,4;3,2,1,0), out: mm1, ebx, ecx, edx + AS2( movd eax, xmm2) + AS2( psrldq xmm2, 4) + AS2( movd edi, xmm2) + AS2( psrldq xmm2, 4) + MXOR( 1, al, 0) // 0 + XOR( edx, ah, 1) // 1 + AS2( shr eax, 16) + XOR( ecx, al, 2) // 2 + XOR( ebx, ah, 3) // 3 + AS2( mov eax, edi) + AS2( movd edi, xmm2) + AS2( psrldq xmm2, 4) + XOR( ebx, al, 0) // 4 + MXOR( 1, ah, 1) // 5 + AS2( shr eax, 16) + XOR( edx, al, 2) // 6 + XOR( ecx, ah, 3) // 7 + AS2( mov eax, edi) + AS2( movd edi, xmm2) + XOR( ecx, al, 0) // 8 + XOR( ebx, ah, 1) // 9 + AS2( shr eax, 16) + MXOR( 1, al, 2) // 10 + XOR( edx, ah, 3) // 11 + AS2( mov eax, edi) + XOR( edx, al, 0) // 12 + XOR( ecx, ah, 1) // 13 + AS2( shr eax, 16) + XOR( ebx, al, 2) // 14 + AS2( psrldq xmm2, 3) + + // partial second round, in: ebx(4,5,6,7), ecx(8,9,10,11), edx(12,13,14,15), out: eax, ebx, edi, mm0 + AS2( mov eax, [L_KEY12+0*4]) + AS2( mov edi, [L_KEY12+2*4]) + AS2( MOVD MM(0), [L_KEY12+3*4]) + MXOR( 0, cl, 3) /* 11 */ + XOR( edi, bl, 3) /* 7 */ + MXOR( 0, bh, 2) /* 6 */ + AS2( shr ebx, 16) /* 4,5 */ + XOR( eax, bl, 1) /* 5 */ + MOV( ebx, bh, 0) /* 4 */ + AS2( xor ebx, [L_KEY12+1*4]) + XOR( eax, ch, 2) /* 10 */ + AS2( shr ecx, 16) /* 8,9 */ + XOR( eax, dl, 3) /* 15 */ + XOR( ebx, dh, 2) /* 14 */ + AS2( shr edx, 16) /* 12,13 */ + XOR( edi, ch, 0) /* 8 */ + XOR( ebx, cl, 1) /* 9 */ + XOR( edi, dl, 1) /* 13 */ + MXOR( 0, dh, 0) /* 12 */ + + AS2( movd ecx, xmm2) + AS2( MOVD edx, MM(1)) + AS2( MOVD [L_SAVED_X+3*4], MM(0)) + AS2( mov [L_SAVED_X+0*4], eax) + AS2( mov [L_SAVED_X+1*4], ebx) + AS2( mov [L_SAVED_X+2*4], edi) + ATT_NOPREFIX + ASJ( jmp, 5, f) + INTEL_NOPREFIX + ASL(3) + // non-counter mode per-block setup + AS2( MOVD MM(1), [L_KEY12+0*4]) // 0,1,2,3 + AS2( mov ebx, [L_KEY12+1*4]) // 4,5,6,7 + AS2( mov ecx, [L_KEY12+2*4]) // 8,9,10,11 + AS2( mov edx, [L_KEY12+3*4]) // 12,13,14,15 + ASL(8) + AS2( mov WORD_REG(ax), [L_INBLOCKS]) + AS2( movdqu xmm2, [WORD_REG(ax)]) + AS2( mov WORD_REG(si), [L_INXORBLOCKS]) + AS2( movdqu xmm5, [WORD_REG(si)]) + AS2( pxor xmm2, xmm1) + AS2( pxor xmm2, xmm5) + + // first round, in: xmm2(15,14,13,12;11,10,9,8;7,6,5,4;3,2,1,0), out: eax, ebx, ecx, edx + AS2( movd eax, xmm2) + AS2( psrldq xmm2, 4) + AS2( movd edi, xmm2) + AS2( psrldq xmm2, 4) + MXOR( 1, al, 0) // 0 + XOR( edx, ah, 1) // 1 + AS2( shr eax, 16) + XOR( ecx, al, 2) // 2 + XOR( ebx, ah, 3) // 3 + AS2( mov eax, edi) + AS2( movd edi, xmm2) + AS2( psrldq xmm2, 4) + XOR( ebx, al, 0) // 4 + MXOR( 1, ah, 1) // 5 + AS2( shr eax, 16) + XOR( edx, al, 2) // 6 + XOR( ecx, ah, 3) // 7 + AS2( mov eax, edi) + AS2( movd edi, xmm2) + XOR( ecx, al, 0) // 8 + XOR( ebx, ah, 1) // 9 + AS2( shr eax, 16) + MXOR( 1, al, 2) // 10 + XOR( edx, ah, 3) // 11 + AS2( mov eax, edi) + XOR( edx, al, 0) // 12 + XOR( ecx, ah, 1) // 13 + AS2( shr eax, 16) + XOR( ebx, al, 2) // 14 + MXOR( 1, ah, 3) // 15 + AS2( MOVD eax, MM(1)) + + AS2( add L_REG, [L_KEYS_BEGIN]) + AS2( add L_REG, 4*16) + ATT_NOPREFIX + ASJ( jmp, 2, f) + INTEL_NOPREFIX + ASL(1) + // counter-mode per-block setup + AS2( MOVD ecx, MM(2)) + AS2( MOVD edx, MM(1)) + AS2( mov eax, [L_SAVED_X+0*4]) + AS2( mov ebx, [L_SAVED_X+1*4]) + AS2( xor cl, ch) + AS2( and WORD_REG(cx), 255) + ASL(5) +#if CRYPTOPP_BOOL_X86 + AS2( paddb MM(2), mm3) +#else + AS2( add MM(2), 1) +#endif + // remaining part of second round, in: edx(previous round),esi(keyed counter byte) eax,ebx,[L_SAVED_X+2*4],[L_SAVED_X+3*4], out: eax,ebx,ecx,edx + AS2( xor edx, DWORD PTR [AS_REG_7+WORD_REG(cx)*8+3]) + XOR( ebx, dl, 3) + MOV( ecx, dh, 2) + AS2( shr edx, 16) + AS2( xor ecx, [L_SAVED_X+2*4]) + XOR( eax, dh, 0) + MOV( edx, dl, 1) + AS2( xor edx, [L_SAVED_X+3*4]) + + AS2( add L_REG, [L_KEYS_BEGIN]) + AS2( add L_REG, 3*16) + ATT_NOPREFIX + ASJ( jmp, 4, f) + INTEL_NOPREFIX + +// in: eax(0,1,2,3), ebx(4,5,6,7), ecx(8,9,10,11), edx(12,13,14,15) +// out: eax, ebx, edi, mm0 +#define ROUND() \ + MXOR( 0, cl, 3) /* 11 */\ + AS2( mov cl, al) /* 8,9,10,3 */\ + XOR( edi, ah, 2) /* 2 */\ + AS2( shr eax, 16) /* 0,1 */\ + XOR( edi, bl, 3) /* 7 */\ + MXOR( 0, bh, 2) /* 6 */\ + AS2( shr ebx, 16) /* 4,5 */\ + MXOR( 0, al, 1) /* 1 */\ + MOV( eax, ah, 0) /* 0 */\ + XOR( eax, bl, 1) /* 5 */\ + MOV( ebx, bh, 0) /* 4 */\ + XOR( eax, ch, 2) /* 10 */\ + XOR( ebx, cl, 3) /* 3 */\ + AS2( shr ecx, 16) /* 8,9 */\ + XOR( eax, dl, 3) /* 15 */\ + XOR( ebx, dh, 2) /* 14 */\ + AS2( shr edx, 16) /* 12,13 */\ + XOR( edi, ch, 0) /* 8 */\ + XOR( ebx, cl, 1) /* 9 */\ + XOR( edi, dl, 1) /* 13 */\ + MXOR( 0, dh, 0) /* 12 */\ + + ASL(2) // 2-round loop + AS2( MOVD MM(0), [L_SUBKEYS-4*16+3*4]) + AS2( mov edi, [L_SUBKEYS-4*16+2*4]) + ROUND() + AS2( mov ecx, edi) + AS2( xor eax, [L_SUBKEYS-4*16+0*4]) + AS2( xor ebx, [L_SUBKEYS-4*16+1*4]) + AS2( MOVD edx, MM(0)) + + ASL(4) + AS2( MOVD MM(0), [L_SUBKEYS-4*16+7*4]) + AS2( mov edi, [L_SUBKEYS-4*16+6*4]) + ROUND() + AS2( mov ecx, edi) + AS2( xor eax, [L_SUBKEYS-4*16+4*4]) + AS2( xor ebx, [L_SUBKEYS-4*16+5*4]) + AS2( MOVD edx, MM(0)) + + AS2( add L_REG, 32) + AS2( test L_REG, 255) + ATT_NOPREFIX + ASJ( jnz, 2, b) + INTEL_NOPREFIX + AS2( sub L_REG, 16*16) + +#define LAST(a, b, c) \ + AS2( movzx esi, a )\ + AS2( movzx edi, BYTE PTR [AS_REG_7+WORD_REG(si)*8+1] )\ + AS2( movzx esi, b )\ + AS2( xor edi, DWORD PTR [AS_REG_7+WORD_REG(si)*8+0] )\ + AS2( mov WORD PTR [L_LASTROUND+c], di )\ + + // last round + LAST(ch, dl, 2) + LAST(dh, al, 6) + AS2( shr edx, 16) + LAST(ah, bl, 10) + AS2( shr eax, 16) + LAST(bh, cl, 14) + AS2( shr ebx, 16) + LAST(dh, al, 12) + AS2( shr ecx, 16) + LAST(ah, bl, 0) + LAST(bh, cl, 4) + LAST(ch, dl, 8) + + AS2( mov WORD_REG(ax), [L_OUTXORBLOCKS]) + AS2( mov WORD_REG(bx), [L_OUTBLOCKS]) + + AS2( mov WORD_REG(cx), [L_LENGTH]) + AS2( sub WORD_REG(cx), 16) + + AS2( movdqu xmm2, [WORD_REG(ax)]) + AS2( pxor xmm2, xmm4) + +#if CRYPTOPP_BOOL_X86 + AS2( movdqa xmm0, [L_INCREMENTS]) + AS2( paddd xmm0, [L_INBLOCKS]) + AS2( movdqa [L_INBLOCKS], xmm0) +#else + AS2( movdqa xmm0, [L_INCREMENTS+16]) + AS2( paddq xmm0, [L_INBLOCKS+16]) + AS2( movdqa [L_INBLOCKS+16], xmm0) +#endif + + AS2( pxor xmm2, [L_LASTROUND]) + AS2( movdqu [WORD_REG(bx)], xmm2) + + ATT_NOPREFIX + ASJ( jle, 7, f) + INTEL_NOPREFIX + AS2( mov [L_LENGTH], WORD_REG(cx)) + AS2( test WORD_REG(cx), 1) + ATT_NOPREFIX + ASJ( jnz, 1, b) + INTEL_NOPREFIX +#if CRYPTOPP_BOOL_X64 + AS2( movdqa xmm0, [L_INCREMENTS]) + AS2( paddq xmm0, [L_INBLOCKS]) + AS2( movdqa [L_INBLOCKS], xmm0) +#endif + ATT_NOPREFIX + ASJ( jmp, 3, b) + INTEL_NOPREFIX + + ASL(7) + // erase keys on stack + AS2( xorps xmm0, xmm0) + AS2( lea WORD_REG(ax), [L_SUBKEYS+7*16]) + AS2( movaps [WORD_REG(ax)-7*16], xmm0) + AS2( movaps [WORD_REG(ax)-6*16], xmm0) + AS2( movaps [WORD_REG(ax)-5*16], xmm0) + AS2( movaps [WORD_REG(ax)-4*16], xmm0) + AS2( movaps [WORD_REG(ax)-3*16], xmm0) + AS2( movaps [WORD_REG(ax)-2*16], xmm0) + AS2( movaps [WORD_REG(ax)-1*16], xmm0) + AS2( movaps [WORD_REG(ax)+0*16], xmm0) + AS2( movaps [WORD_REG(ax)+1*16], xmm0) + AS2( movaps [WORD_REG(ax)+2*16], xmm0) + AS2( movaps [WORD_REG(ax)+3*16], xmm0) + AS2( movaps [WORD_REG(ax)+4*16], xmm0) + AS2( movaps [WORD_REG(ax)+5*16], xmm0) + AS2( movaps [WORD_REG(ax)+6*16], xmm0) +#if CRYPTOPP_BOOL_X86 + AS2( mov esp, [L_SP]) + AS1( emms) +#endif + AS_POP_IF86(bp) + AS_POP_IF86(bx) +#if defined(_MSC_VER) && CRYPTOPP_BOOL_X86 + AS_POP_IF86(di) + AS_POP_IF86(si) + AS1(ret) +#endif +#ifdef CRYPTOPP_GENERATE_X64_MASM + pop r12 + pop rbx + pop rdi + pop rsi + ret + Rijndael_Enc_AdvancedProcessBlocks ENDP +#endif +#ifdef __GNUC__ + ATT_PREFIX + : + : "c" (locals), "d" (k), "S" (Te), "D" (g_cacheLineSize) + : "memory", "cc", "%eax" + #if CRYPTOPP_BOOL_X64 + , "%rbx", "%r8", "%r9", "%r10", "%r11", "%r12" + #endif + ); +#endif +} + +#endif + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void Rijndael_Enc_AdvancedProcessBlocks_SSE2(void *locals, const word32 *k); +} +#endif + +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS +size_t Rijndael::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const +{ +#if CRYPTOPP_AESNI_AVAILABLE + if (HasAESNI()) + return Rijndael_Enc_AdvancedProcessBlocks_AESNI(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if CRYPTOPP_ARM_AES_AVAILABLE + if (HasAES()) + return Rijndael_Enc_AdvancedProcessBlocks_ARMV8(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if CRYPTOPP_POWER8_AES_AVAILABLE + if (HasAES()) + return Rijndael_Enc_AdvancedProcessBlocks128_6x1_ALTIVEC(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif + +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)) && !defined(CRYPTOPP_DISABLE_RIJNDAEL_ASM) + if (HasSSE2()) + { + if (length < BLOCKSIZE) + return length; + + static const byte *zeros = (const byte*)(Te+256); + m_aliasBlock.SetMark(m_aliasBlock.size()); + byte *space = NULLPTR, *originalSpace = const_cast(m_aliasBlock.data()); + + // round up to nearest 256 byte boundary + space = originalSpace + (s_aliasBlockSize - (uintptr_t)originalSpace % s_aliasBlockSize) % s_aliasBlockSize; + while (AliasedWithTable(space, space + sizeof(Locals))) + { + space += 256; + CRYPTOPP_ASSERT(space < (originalSpace + s_aliasPageSize)); + } + + size_t increment = BLOCKSIZE; + if (flags & BT_ReverseDirection) + { + CRYPTOPP_ASSERT(length % BLOCKSIZE == 0); + inBlocks += length - BLOCKSIZE; + xorBlocks += length - BLOCKSIZE; + outBlocks += length - BLOCKSIZE; + increment = 0-increment; + } + + Locals &locals = *(Locals *)(void *)space; + + locals.inBlocks = inBlocks; + locals.inXorBlocks = (flags & BT_XorInput) && xorBlocks ? xorBlocks : zeros; + locals.outXorBlocks = (flags & BT_XorInput) || !xorBlocks ? zeros : xorBlocks; + locals.outBlocks = outBlocks; + + locals.inIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : increment; + locals.inXorIncrement = (flags & BT_XorInput) && xorBlocks ? increment : 0; + locals.outXorIncrement = (flags & BT_XorInput) || !xorBlocks ? 0 : increment; + locals.outIncrement = (flags & BT_DontIncrementInOutPointers) ? 0 : increment; + + locals.lengthAndCounterFlag = length - (length%16) - bool(flags & BT_InBlockIsCounter); + int keysToCopy = m_rounds - (flags & BT_InBlockIsCounter ? 3 : 2); + locals.keysBegin = (12-keysToCopy)*16; + + Rijndael_Enc_AdvancedProcessBlocks_SSE2(&locals, m_key); + + return length % BLOCKSIZE; + } +#endif + + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t Rijndael::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const +{ +#if CRYPTOPP_AESNI_AVAILABLE + if (HasAESNI()) + return Rijndael_Dec_AdvancedProcessBlocks_AESNI(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if CRYPTOPP_ARM_AES_AVAILABLE + if (HasAES()) + return Rijndael_Dec_AdvancedProcessBlocks_ARMV8(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if CRYPTOPP_POWER8_AES_AVAILABLE + if (HasAES()) + return Rijndael_Dec_AdvancedProcessBlocks128_6x1_ALTIVEC(m_key, m_rounds, inBlocks, xorBlocks, outBlocks, length, flags); +#endif + + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END + +#endif +#endif diff --git a/extension/third_party/cryptopp/rijndael.h b/extension/third_party/cryptopp/rijndael.h new file mode 100644 index 00000000..bfb80fa1 --- /dev/null +++ b/extension/third_party/cryptopp/rijndael.h @@ -0,0 +1,109 @@ +// rijndael.h - originally written and placed in the public domain by Wei Dai + +/// \file rijndael.h +/// \brief Classes for Rijndael encryption algorithm +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + +#ifndef CRYPTOPP_RIJNDAEL_H +#define CRYPTOPP_RIJNDAEL_H + +#include "seckey.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_RIJNDAEL_ASM 1 +#endif + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || \ + CRYPTOPP_BOOL_ARMV8 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# define CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rijndael block cipher information +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 +struct Rijndael_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "AES";} +}; + +/// \brief Rijndael block cipher +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 +/// \sa Rijndael +class CRYPTOPP_DLL Rijndael : public Rijndael_Info, public BlockCipherDocumentation +{ + /// \brief Rijndael block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + unsigned int OptimalDataAlignment() const; + + protected: + static void FillEncTable(); + static void FillDecTable(); + + // VS2005 workaround: have to put these on separate lines, or error C2487 is triggered in DLL build + static const byte Se[256]; + static const byte Sd[256]; + + static const word32 rcon[]; + + unsigned int m_rounds; + SecBlock > m_key; + mutable SecByteBlock m_aliasBlock; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Rijndael::Encryption RijndaelEncryption; +typedef Rijndael::Decryption RijndaelDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rijndael_simd.cpp b/extension/third_party/cryptopp/rijndael_simd.cpp new file mode 100644 index 00000000..f7dfe6cf --- /dev/null +++ b/extension/third_party/cryptopp/rijndael_simd.cpp @@ -0,0 +1,737 @@ +// rijndael_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// AES-NI code originally written by Wei Dai. +// +// This source file uses intrinsics and built-ins to gain access to +// AES-NI, ARMv8a AES and Power8 AES instructions. A separate source +// file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. +// +// ARMv8a AES code based on CriticalBlue code from Johannes Schneiders, +// Skip Hovsmith and Barry O'Rourke for the mbedTLS project. Stepping +// mbedTLS under a debugger was helped for us to determine problems +// with our subkey generation and scheduling. +// +// AltiVec and Power8 code based on http://github.com/noloader/AES-Intrinsics and +// http://www.ibm.com/developerworks/library/se-power8-in-core-cryptography/ +// For Power8 do not remove the casts, even when const-ness is cast away. It causes +// failed compiles and a 0.3 to 0.6 cpb drop in performance. The IBM documentation +// absolutely sucks. Thanks to Andy Polyakov, Paul R and Trudeaun for answering +// questions and filling the gaps in the IBM documentation. +// + +#include "pch.h" +#include "config.h" +#include "misc.h" + +#if (CRYPTOPP_AESNI_AVAILABLE) +# include "adv_simd.h" +# include +# include +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include "adv_simd.h" +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include "adv_simd.h" +# include +# include +#endif + +#if defined(_M_ARM64) +# include "adv_simd.h" +#endif + +#if defined(CRYPTOPP_POWER8_AES_AVAILABLE) +# include "adv_simd.h" +# include "ppc_simd.h" +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char RIJNDAEL_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ************************* Feature Probes ************************* // + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) +bool CPU_ProbeAES() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_ARM_AES_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + // AES encrypt and decrypt + uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0); + uint8x16_t r1 = vaeseq_u8(data, key); + uint8x16_t r2 = vaesdq_u8(data, key); + r1 = vaesmcq_u8(r1); + r2 = vaesimcq_u8(r2); + + result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0); + uint8x16_t r1 = vaeseq_u8(data, key); + uint8x16_t r2 = vaesdq_u8(data, key); + r1 = vaesmcq_u8(r1); + r2 = vaesimcq_u8(r2); + + // Hack... GCC optimizes away the code and returns true + result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_AES_AVAILABLE +} +#endif // ARM32 or ARM64 + +// ***************************** ARMv8 ***************************** // + +#if (CRYPTOPP_ARM_AES_AVAILABLE) + +ANONYMOUS_NAMESPACE_BEGIN + +inline void ARMV8_Enc_Block(uint64x2_t &data, const word32 *subkeys, unsigned int rounds) +{ + CRYPTOPP_ASSERT(subkeys); + const byte *keys = reinterpret_cast(subkeys); + uint8x16_t block = vreinterpretq_u8_u64(data); + + // AES single round encryption + block = vaeseq_u8(block, vld1q_u8(keys+0*16)); + // AES mix columns + block = vaesmcq_u8(block); + + for (unsigned int i=1; i(subkeys); + + uint8x16_t block0 = vreinterpretq_u8_u64(data0); + uint8x16_t block1 = vreinterpretq_u8_u64(data1); + uint8x16_t block2 = vreinterpretq_u8_u64(data2); + uint8x16_t block3 = vreinterpretq_u8_u64(data3); + uint8x16_t block4 = vreinterpretq_u8_u64(data4); + uint8x16_t block5 = vreinterpretq_u8_u64(data5); + + uint8x16_t key; + for (unsigned int i=0; i(subkeys); + uint8x16_t block = vreinterpretq_u8_u64(data); + + // AES single round decryption + block = vaesdq_u8(block, vld1q_u8(keys+0*16)); + // AES inverse mix columns + block = vaesimcq_u8(block); + + for (unsigned int i=1; i(subkeys); + + uint8x16_t block0 = vreinterpretq_u8_u64(data0); + uint8x16_t block1 = vreinterpretq_u8_u64(data1); + uint8x16_t block2 = vreinterpretq_u8_u64(data2); + uint8x16_t block3 = vreinterpretq_u8_u64(data3); + uint8x16_t block4 = vreinterpretq_u8_u64(data4); + uint8x16_t block5 = vreinterpretq_u8_u64(data5); + + uint8x16_t key; + for (unsigned int i=0; i(subkeys); + + block = _mm_xor_si128(block, skeys[0]); + for (unsigned int i=1; i(subkeys); + + __m128i rk = skeys[0]; + block0 = _mm_xor_si128(block0, rk); + block1 = _mm_xor_si128(block1, rk); + block2 = _mm_xor_si128(block2, rk); + block3 = _mm_xor_si128(block3, rk); + for (unsigned int i=1; i(subkeys); + + block = _mm_xor_si128(block, skeys[0]); + for (unsigned int i=1; i(subkeys); + + __m128i rk = skeys[0]; + block0 = _mm_xor_si128(block0, rk); + block1 = _mm_xor_si128(block1, rk); + block2 = _mm_xor_si128(block2, rk); + block3 = _mm_xor_si128(block3, rk); + for (unsigned int i=1; i(subkeys); + + uint32x4_p k = VecLoadAligned(keys); + block = VecXor(block, k); + + for (size_t i=1; i(subkeys); + + uint32x4_p k = VecLoadAligned(keys); + block0 = VecXor(block0, k); + block1 = VecXor(block1, k); + block2 = VecXor(block2, k); + block3 = VecXor(block3, k); + block4 = VecXor(block4, k); + block5 = VecXor(block5, k); + + for (size_t i=1; i(subkeys); + + uint32x4_p k = VecLoadAligned(rounds*16, keys); + block = VecXor(block, k); + + for (size_t i=rounds-1; i>1; i-=2) + { + block = VecDecrypt(block, VecLoadAligned( i*16, keys)); + block = VecDecrypt(block, VecLoadAligned((i-1)*16, keys)); + } + + block = VecDecrypt(block, VecLoadAligned(16, keys)); + block = VecDecryptLast(block, VecLoadAligned(0, keys)); +} + +inline void POWER8_Dec_6_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, uint32x4_p &block4, + uint32x4_p &block5, const word32 *subkeys, unsigned int rounds) +{ + CRYPTOPP_ASSERT(IsAlignedOn(subkeys, 16)); + const byte *keys = reinterpret_cast(subkeys); + + uint32x4_p k = VecLoadAligned(rounds*16, keys); + block0 = VecXor(block0, k); + block1 = VecXor(block1, k); + block2 = VecXor(block2, k); + block3 = VecXor(block3, k); + block4 = VecXor(block4, k); + block5 = VecXor(block5, k); + + for (size_t i=rounds-1; i>0; --i) + { + k = VecLoadAligned(i*16, keys); + block0 = VecDecrypt(block0, k); + block1 = VecDecrypt(block1, k); + block2 = VecDecrypt(block2, k); + block3 = VecDecrypt(block3, k); + block4 = VecDecrypt(block4, k); + block5 = VecDecrypt(block5, k); + } + + k = VecLoadAligned(0, keys); + block0 = VecDecryptLast(block0, k); + block1 = VecDecryptLast(block1, k); + block2 = VecDecryptLast(block2, k); + block3 = VecDecryptLast(block3, k); + block4 = VecDecryptLast(block4, k); + block5 = VecDecryptLast(block5, k); +} + +ANONYMOUS_NAMESPACE_END + +void Rijndael_UncheckedSetKey_POWER8(const byte* userKey, size_t keyLen, word32* rk, const byte* Se) +{ + const size_t rounds = keyLen / 4 + 6; + const word32 *rc = s_rconBE; + word32 *rkey = rk, temp; + + GetUserKey(BIG_ENDIAN_ORDER, rkey, keyLen/4, userKey, keyLen); + + // keySize: m_key allocates 4*(rounds+1) word32's. + const size_t keySize = 4*(rounds+1); + const word32* end = rkey + keySize; + + while (true) + { + temp = rkey[keyLen/4-1]; + word32 x = (word32(Se[GETBYTE(temp, 2)]) << 24) ^ (word32(Se[GETBYTE(temp, 1)]) << 16) ^ + (word32(Se[GETBYTE(temp, 0)]) << 8) ^ Se[GETBYTE(temp, 3)]; + rkey[keyLen/4] = rkey[0] ^ x ^ *(rc++); + rkey[keyLen/4+1] = rkey[1] ^ rkey[keyLen/4]; + rkey[keyLen/4+2] = rkey[2] ^ rkey[keyLen/4+1]; + rkey[keyLen/4+3] = rkey[3] ^ rkey[keyLen/4+2]; + + if (rkey + keyLen/4 + 4 == end) + break; + + if (keyLen == 24) + { + rkey[10] = rkey[ 4] ^ rkey[ 9]; + rkey[11] = rkey[ 5] ^ rkey[10]; + } + else if (keyLen == 32) + { + temp = rkey[11]; + rkey[12] = rkey[ 4] ^ (word32(Se[GETBYTE(temp, 3)]) << 24) ^ (word32(Se[GETBYTE(temp, 2)]) << 16) ^ (word32(Se[GETBYTE(temp, 1)]) << 8) ^ Se[GETBYTE(temp, 0)]; + rkey[13] = rkey[ 5] ^ rkey[12]; + rkey[14] = rkey[ 6] ^ rkey[13]; + rkey[15] = rkey[ 7] ^ rkey[14]; + } + rkey += keyLen/4; + } + +#if (CRYPTOPP_LITTLE_ENDIAN) + rkey = rk; + const uint8x16_p mask = {12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; + + unsigned int i=0; + for (i=0; i((word32)c) + +void RIPEMD160::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; + state[4] = 0xc3d2e1f0L; +} + +void RIPEMD160::Transform (word32 *digest, const word32 *X) +{ + unsigned long a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + a1 = a2 = digest[0]; + b1 = b2 = digest[1]; + c1 = c2 = digest[2]; + d1 = d2 = digest[3]; + e1 = e2 = digest[4]; + + Subround(F, a1, b1, c1, d1, e1, X[ 0], 11, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 1], 14, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 2], 15, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 3], 12, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, X[ 5], 8, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 6], 7, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 7], 9, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 8], 11, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 9], 13, k0); + Subround(F, a1, b1, c1, d1, e1, X[10], 14, k0); + Subround(F, e1, a1, b1, c1, d1, X[11], 15, k0); + Subround(F, d1, e1, a1, b1, c1, X[12], 6, k0); + Subround(F, c1, d1, e1, a1, b1, X[13], 7, k0); + Subround(F, b1, c1, d1, e1, a1, X[14], 9, k0); + Subround(F, a1, b1, c1, d1, e1, X[15], 8, k0); + + Subround(G, e1, a1, b1, c1, d1, X[ 7], 7, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, X[13], 8, k1); + Subround(G, b1, c1, d1, e1, a1, X[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, e1, X[10], 11, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 6], 9, k1); + Subround(G, d1, e1, a1, b1, c1, X[15], 7, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 3], 15, k1); + Subround(G, b1, c1, d1, e1, a1, X[12], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[ 0], 12, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 9], 15, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 5], 9, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 2], 11, k1); + Subround(G, b1, c1, d1, e1, a1, X[14], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[11], 13, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 8], 12, k1); + + Subround(H, d1, e1, a1, b1, c1, X[ 3], 11, k2); + Subround(H, c1, d1, e1, a1, b1, X[10], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[14], 6, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 9], 14, k2); + Subround(H, d1, e1, a1, b1, c1, X[15], 9, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 8], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 2], 14, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 7], 8, k2); + Subround(H, d1, e1, a1, b1, c1, X[ 0], 13, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 6], 6, k2); + Subround(H, b1, c1, d1, e1, a1, X[13], 5, k2); + Subround(H, a1, b1, c1, d1, e1, X[11], 12, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 5], 7, k2); + Subround(H, d1, e1, a1, b1, c1, X[12], 5, k2); + + Subround(I, c1, d1, e1, a1, b1, X[ 1], 11, k3); + Subround(I, b1, c1, d1, e1, a1, X[ 9], 12, k3); + Subround(I, a1, b1, c1, d1, e1, X[11], 14, k3); + Subround(I, e1, a1, b1, c1, d1, X[10], 15, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 0], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 8], 15, k3); + Subround(I, b1, c1, d1, e1, a1, X[12], 9, k3); + Subround(I, a1, b1, c1, d1, e1, X[ 4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[13], 9, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 3], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 7], 5, k3); + Subround(I, b1, c1, d1, e1, a1, X[15], 6, k3); + Subround(I, a1, b1, c1, d1, e1, X[14], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[ 5], 6, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 6], 5, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 2], 12, k3); + + Subround(J, b1, c1, d1, e1, a1, X[ 4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 0], 15, k4); + Subround(J, e1, a1, b1, c1, d1, X[ 5], 5, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 9], 11, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 7], 6, k4); + Subround(J, b1, c1, d1, e1, a1, X[12], 8, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 2], 13, k4); + Subround(J, e1, a1, b1, c1, d1, X[10], 12, k4); + Subround(J, d1, e1, a1, b1, c1, X[14], 5, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 1], 12, k4); + Subround(J, b1, c1, d1, e1, a1, X[ 3], 13, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 8], 14, k4); + Subround(J, e1, a1, b1, c1, d1, X[11], 11, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 6], 8, k4); + Subround(J, c1, d1, e1, a1, b1, X[15], 5, k4); + Subround(J, b1, c1, d1, e1, a1, X[13], 6, k4); + + Subround(J, a2, b2, c2, d2, e2, X[ 5], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[14], 9, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 7], 9, k5); + Subround(J, c2, d2, e2, a2, b2, X[ 0], 11, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 9], 13, k5); + Subround(J, a2, b2, c2, d2, e2, X[ 2], 15, k5); + Subround(J, e2, a2, b2, c2, d2, X[11], 15, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, X[13], 7, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 6], 7, k5); + Subround(J, a2, b2, c2, d2, e2, X[15], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[ 8], 11, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 1], 14, k5); + Subround(J, c2, d2, e2, a2, b2, X[10], 14, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 3], 12, k5); + Subround(J, a2, b2, c2, d2, e2, X[12], 6, k5); + + Subround(I, e2, a2, b2, c2, d2, X[ 6], 9, k6); + Subround(I, d2, e2, a2, b2, c2, X[11], 13, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 3], 15, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 7], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 0], 12, k6); + Subround(I, e2, a2, b2, c2, d2, X[13], 8, k6); + Subround(I, d2, e2, a2, b2, c2, X[ 5], 9, k6); + Subround(I, c2, d2, e2, a2, b2, X[10], 11, k6); + Subround(I, b2, c2, d2, e2, a2, X[14], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[15], 7, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 8], 12, k6); + Subround(I, d2, e2, a2, b2, c2, X[12], 7, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 9], 15, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 1], 13, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 2], 11, k6); + + Subround(H, d2, e2, a2, b2, c2, X[15], 9, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 5], 7, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 1], 15, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 3], 11, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 7], 8, k7); + Subround(H, d2, e2, a2, b2, c2, X[14], 6, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 6], 6, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 9], 14, k7); + Subround(H, a2, b2, c2, d2, e2, X[11], 12, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 8], 13, k7); + Subround(H, d2, e2, a2, b2, c2, X[12], 5, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 2], 14, k7); + Subround(H, b2, c2, d2, e2, a2, X[10], 13, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 0], 13, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, X[13], 5, k7); + + Subround(G, c2, d2, e2, a2, b2, X[ 8], 15, k8); + Subround(G, b2, c2, d2, e2, a2, X[ 6], 5, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 1], 11, k8); + Subround(G, d2, e2, a2, b2, c2, X[ 3], 14, k8); + Subround(G, c2, d2, e2, a2, b2, X[11], 14, k8); + Subround(G, b2, c2, d2, e2, a2, X[15], 6, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 0], 14, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 5], 6, k8); + Subround(G, d2, e2, a2, b2, c2, X[12], 9, k8); + Subround(G, c2, d2, e2, a2, b2, X[ 2], 12, k8); + Subround(G, b2, c2, d2, e2, a2, X[13], 9, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 9], 12, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 7], 5, k8); + Subround(G, d2, e2, a2, b2, c2, X[10], 15, k8); + Subround(G, c2, d2, e2, a2, b2, X[14], 8, k8); + + Subround(F, b2, c2, d2, e2, a2, X[12], 8, k9); + Subround(F, a2, b2, c2, d2, e2, X[15], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[10], 12, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 1], 12, k9); + Subround(F, b2, c2, d2, e2, a2, X[ 5], 5, k9); + Subround(F, a2, b2, c2, d2, e2, X[ 8], 14, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 7], 6, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 6], 8, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 2], 13, k9); + Subround(F, b2, c2, d2, e2, a2, X[13], 6, k9); + Subround(F, a2, b2, c2, d2, e2, X[14], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 0], 15, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 3], 13, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 9], 11, k9); + Subround(F, b2, c2, d2, e2, a2, X[11], 11, k9); + + c1 = digest[1] + c1 + d2; + digest[1] = digest[2] + d1 + e2; + digest[2] = digest[3] + e1 + a2; + digest[3] = digest[4] + a1 + b2; + digest[4] = digest[0] + b1 + c2; + digest[0] = c1; +} + +// ************************************************************* + +void RIPEMD320::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; + state[4] = 0xc3d2e1f0L; + state[5] = 0x76543210L; + state[6] = 0xfedcba98L; + state[7] = 0x89abcdefL; + state[8] = 0x01234567L; + state[9] = 0x3c2d1e0fL; +} + +void RIPEMD320::Transform (word32 *digest, const word32 *X) +{ + unsigned long a1, b1, c1, d1, e1, a2, b2, c2, d2, e2, t; + a1 = digest[0]; + b1 = digest[1]; + c1 = digest[2]; + d1 = digest[3]; + e1 = digest[4]; + a2 = digest[5]; + b2 = digest[6]; + c2 = digest[7]; + d2 = digest[8]; + e2 = digest[9]; + + Subround(F, a1, b1, c1, d1, e1, X[ 0], 11, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 1], 14, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 2], 15, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 3], 12, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, X[ 5], 8, k0); + Subround(F, e1, a1, b1, c1, d1, X[ 6], 7, k0); + Subround(F, d1, e1, a1, b1, c1, X[ 7], 9, k0); + Subround(F, c1, d1, e1, a1, b1, X[ 8], 11, k0); + Subround(F, b1, c1, d1, e1, a1, X[ 9], 13, k0); + Subround(F, a1, b1, c1, d1, e1, X[10], 14, k0); + Subround(F, e1, a1, b1, c1, d1, X[11], 15, k0); + Subround(F, d1, e1, a1, b1, c1, X[12], 6, k0); + Subround(F, c1, d1, e1, a1, b1, X[13], 7, k0); + Subround(F, b1, c1, d1, e1, a1, X[14], 9, k0); + Subround(F, a1, b1, c1, d1, e1, X[15], 8, k0); + + Subround(J, a2, b2, c2, d2, e2, X[ 5], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[14], 9, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 7], 9, k5); + Subround(J, c2, d2, e2, a2, b2, X[ 0], 11, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 9], 13, k5); + Subround(J, a2, b2, c2, d2, e2, X[ 2], 15, k5); + Subround(J, e2, a2, b2, c2, d2, X[11], 15, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, X[13], 7, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 6], 7, k5); + Subround(J, a2, b2, c2, d2, e2, X[15], 8, k5); + Subround(J, e2, a2, b2, c2, d2, X[ 8], 11, k5); + Subround(J, d2, e2, a2, b2, c2, X[ 1], 14, k5); + Subround(J, c2, d2, e2, a2, b2, X[10], 14, k5); + Subround(J, b2, c2, d2, e2, a2, X[ 3], 12, k5); + Subround(J, a2, b2, c2, d2, e2, X[12], 6, k5); + + t = a1; a1 = a2; a2 = t; + + Subround(G, e1, a1, b1, c1, d1, X[ 7], 7, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, X[13], 8, k1); + Subround(G, b1, c1, d1, e1, a1, X[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, e1, X[10], 11, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 6], 9, k1); + Subround(G, d1, e1, a1, b1, c1, X[15], 7, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 3], 15, k1); + Subround(G, b1, c1, d1, e1, a1, X[12], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[ 0], 12, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 9], 15, k1); + Subround(G, d1, e1, a1, b1, c1, X[ 5], 9, k1); + Subround(G, c1, d1, e1, a1, b1, X[ 2], 11, k1); + Subround(G, b1, c1, d1, e1, a1, X[14], 7, k1); + Subround(G, a1, b1, c1, d1, e1, X[11], 13, k1); + Subround(G, e1, a1, b1, c1, d1, X[ 8], 12, k1); + + Subround(I, e2, a2, b2, c2, d2, X[ 6], 9, k6); + Subround(I, d2, e2, a2, b2, c2, X[11], 13, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 3], 15, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 7], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 0], 12, k6); + Subround(I, e2, a2, b2, c2, d2, X[13], 8, k6); + Subround(I, d2, e2, a2, b2, c2, X[ 5], 9, k6); + Subround(I, c2, d2, e2, a2, b2, X[10], 11, k6); + Subround(I, b2, c2, d2, e2, a2, X[14], 7, k6); + Subround(I, a2, b2, c2, d2, e2, X[15], 7, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 8], 12, k6); + Subround(I, d2, e2, a2, b2, c2, X[12], 7, k6); + Subround(I, c2, d2, e2, a2, b2, X[ 4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, X[ 9], 15, k6); + Subround(I, a2, b2, c2, d2, e2, X[ 1], 13, k6); + Subround(I, e2, a2, b2, c2, d2, X[ 2], 11, k6); + + t = b1; b1 = b2; b2 = t; + + Subround(H, d1, e1, a1, b1, c1, X[ 3], 11, k2); + Subround(H, c1, d1, e1, a1, b1, X[10], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[14], 6, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 9], 14, k2); + Subround(H, d1, e1, a1, b1, c1, X[15], 9, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 8], 13, k2); + Subround(H, b1, c1, d1, e1, a1, X[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, e1, X[ 2], 14, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 7], 8, k2); + Subround(H, d1, e1, a1, b1, c1, X[ 0], 13, k2); + Subround(H, c1, d1, e1, a1, b1, X[ 6], 6, k2); + Subround(H, b1, c1, d1, e1, a1, X[13], 5, k2); + Subround(H, a1, b1, c1, d1, e1, X[11], 12, k2); + Subround(H, e1, a1, b1, c1, d1, X[ 5], 7, k2); + Subround(H, d1, e1, a1, b1, c1, X[12], 5, k2); + + Subround(H, d2, e2, a2, b2, c2, X[15], 9, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 5], 7, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 1], 15, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 3], 11, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 7], 8, k7); + Subround(H, d2, e2, a2, b2, c2, X[14], 6, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 6], 6, k7); + Subround(H, b2, c2, d2, e2, a2, X[ 9], 14, k7); + Subround(H, a2, b2, c2, d2, e2, X[11], 12, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 8], 13, k7); + Subround(H, d2, e2, a2, b2, c2, X[12], 5, k7); + Subround(H, c2, d2, e2, a2, b2, X[ 2], 14, k7); + Subround(H, b2, c2, d2, e2, a2, X[10], 13, k7); + Subround(H, a2, b2, c2, d2, e2, X[ 0], 13, k7); + Subround(H, e2, a2, b2, c2, d2, X[ 4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, X[13], 5, k7); + + t = c1; c1 = c2; c2 = t; + + Subround(I, c1, d1, e1, a1, b1, X[ 1], 11, k3); + Subround(I, b1, c1, d1, e1, a1, X[ 9], 12, k3); + Subround(I, a1, b1, c1, d1, e1, X[11], 14, k3); + Subround(I, e1, a1, b1, c1, d1, X[10], 15, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 0], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 8], 15, k3); + Subround(I, b1, c1, d1, e1, a1, X[12], 9, k3); + Subround(I, a1, b1, c1, d1, e1, X[ 4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[13], 9, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 3], 14, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 7], 5, k3); + Subround(I, b1, c1, d1, e1, a1, X[15], 6, k3); + Subround(I, a1, b1, c1, d1, e1, X[14], 8, k3); + Subround(I, e1, a1, b1, c1, d1, X[ 5], 6, k3); + Subround(I, d1, e1, a1, b1, c1, X[ 6], 5, k3); + Subround(I, c1, d1, e1, a1, b1, X[ 2], 12, k3); + + Subround(G, c2, d2, e2, a2, b2, X[ 8], 15, k8); + Subround(G, b2, c2, d2, e2, a2, X[ 6], 5, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 1], 11, k8); + Subround(G, d2, e2, a2, b2, c2, X[ 3], 14, k8); + Subround(G, c2, d2, e2, a2, b2, X[11], 14, k8); + Subround(G, b2, c2, d2, e2, a2, X[15], 6, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 0], 14, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 5], 6, k8); + Subround(G, d2, e2, a2, b2, c2, X[12], 9, k8); + Subround(G, c2, d2, e2, a2, b2, X[ 2], 12, k8); + Subround(G, b2, c2, d2, e2, a2, X[13], 9, k8); + Subround(G, a2, b2, c2, d2, e2, X[ 9], 12, k8); + Subround(G, e2, a2, b2, c2, d2, X[ 7], 5, k8); + Subround(G, d2, e2, a2, b2, c2, X[10], 15, k8); + Subround(G, c2, d2, e2, a2, b2, X[14], 8, k8); + + t = d1; d1 = d2; d2 = t; + + Subround(J, b1, c1, d1, e1, a1, X[ 4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 0], 15, k4); + Subround(J, e1, a1, b1, c1, d1, X[ 5], 5, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 9], 11, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 7], 6, k4); + Subround(J, b1, c1, d1, e1, a1, X[12], 8, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 2], 13, k4); + Subround(J, e1, a1, b1, c1, d1, X[10], 12, k4); + Subround(J, d1, e1, a1, b1, c1, X[14], 5, k4); + Subround(J, c1, d1, e1, a1, b1, X[ 1], 12, k4); + Subround(J, b1, c1, d1, e1, a1, X[ 3], 13, k4); + Subround(J, a1, b1, c1, d1, e1, X[ 8], 14, k4); + Subround(J, e1, a1, b1, c1, d1, X[11], 11, k4); + Subround(J, d1, e1, a1, b1, c1, X[ 6], 8, k4); + Subround(J, c1, d1, e1, a1, b1, X[15], 5, k4); + Subround(J, b1, c1, d1, e1, a1, X[13], 6, k4); + + Subround(F, b2, c2, d2, e2, a2, X[12], 8, k9); + Subround(F, a2, b2, c2, d2, e2, X[15], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[10], 12, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 1], 12, k9); + Subround(F, b2, c2, d2, e2, a2, X[ 5], 5, k9); + Subround(F, a2, b2, c2, d2, e2, X[ 8], 14, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 7], 6, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 6], 8, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 2], 13, k9); + Subround(F, b2, c2, d2, e2, a2, X[13], 6, k9); + Subround(F, a2, b2, c2, d2, e2, X[14], 5, k9); + Subround(F, e2, a2, b2, c2, d2, X[ 0], 15, k9); + Subround(F, d2, e2, a2, b2, c2, X[ 3], 13, k9); + Subround(F, c2, d2, e2, a2, b2, X[ 9], 11, k9); + Subround(F, b2, c2, d2, e2, a2, X[11], 11, k9); + + t = e1; e1 = e2; e2 = t; + + digest[0] += a1; + digest[1] += b1; + digest[2] += c1; + digest[3] += d1; + digest[4] += e1; + digest[5] += a2; + digest[6] += b2; + digest[7] += c2; + digest[8] += d2; + digest[9] += e2; +} + +#undef Subround + +// ************************************************************* + +// for 128 and 256 +#define Subround(f, a, b, c, d, x, s, k) \ + a += f(b, c, d) + x + k;\ + a = rotlVariable((word32)a, s); + +void RIPEMD128::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; +} + +void RIPEMD128::Transform (word32 *digest, const word32 *X) +{ + unsigned long a1, b1, c1, d1, a2, b2, c2, d2; + a1 = a2 = digest[0]; + b1 = b2 = digest[1]; + c1 = c2 = digest[2]; + d1 = d2 = digest[3]; + + Subround(F, a1, b1, c1, d1, X[ 0], 11, k0); + Subround(F, d1, a1, b1, c1, X[ 1], 14, k0); + Subround(F, c1, d1, a1, b1, X[ 2], 15, k0); + Subround(F, b1, c1, d1, a1, X[ 3], 12, k0); + Subround(F, a1, b1, c1, d1, X[ 4], 5, k0); + Subround(F, d1, a1, b1, c1, X[ 5], 8, k0); + Subround(F, c1, d1, a1, b1, X[ 6], 7, k0); + Subround(F, b1, c1, d1, a1, X[ 7], 9, k0); + Subround(F, a1, b1, c1, d1, X[ 8], 11, k0); + Subround(F, d1, a1, b1, c1, X[ 9], 13, k0); + Subround(F, c1, d1, a1, b1, X[10], 14, k0); + Subround(F, b1, c1, d1, a1, X[11], 15, k0); + Subround(F, a1, b1, c1, d1, X[12], 6, k0); + Subround(F, d1, a1, b1, c1, X[13], 7, k0); + Subround(F, c1, d1, a1, b1, X[14], 9, k0); + Subround(F, b1, c1, d1, a1, X[15], 8, k0); + + Subround(G, a1, b1, c1, d1, X[ 7], 7, k1); + Subround(G, d1, a1, b1, c1, X[ 4], 6, k1); + Subround(G, c1, d1, a1, b1, X[13], 8, k1); + Subround(G, b1, c1, d1, a1, X[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, X[10], 11, k1); + Subround(G, d1, a1, b1, c1, X[ 6], 9, k1); + Subround(G, c1, d1, a1, b1, X[15], 7, k1); + Subround(G, b1, c1, d1, a1, X[ 3], 15, k1); + Subround(G, a1, b1, c1, d1, X[12], 7, k1); + Subround(G, d1, a1, b1, c1, X[ 0], 12, k1); + Subround(G, c1, d1, a1, b1, X[ 9], 15, k1); + Subround(G, b1, c1, d1, a1, X[ 5], 9, k1); + Subround(G, a1, b1, c1, d1, X[ 2], 11, k1); + Subround(G, d1, a1, b1, c1, X[14], 7, k1); + Subround(G, c1, d1, a1, b1, X[11], 13, k1); + Subround(G, b1, c1, d1, a1, X[ 8], 12, k1); + + Subround(H, a1, b1, c1, d1, X[ 3], 11, k2); + Subround(H, d1, a1, b1, c1, X[10], 13, k2); + Subround(H, c1, d1, a1, b1, X[14], 6, k2); + Subround(H, b1, c1, d1, a1, X[ 4], 7, k2); + Subround(H, a1, b1, c1, d1, X[ 9], 14, k2); + Subround(H, d1, a1, b1, c1, X[15], 9, k2); + Subround(H, c1, d1, a1, b1, X[ 8], 13, k2); + Subround(H, b1, c1, d1, a1, X[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, X[ 2], 14, k2); + Subround(H, d1, a1, b1, c1, X[ 7], 8, k2); + Subround(H, c1, d1, a1, b1, X[ 0], 13, k2); + Subround(H, b1, c1, d1, a1, X[ 6], 6, k2); + Subround(H, a1, b1, c1, d1, X[13], 5, k2); + Subround(H, d1, a1, b1, c1, X[11], 12, k2); + Subround(H, c1, d1, a1, b1, X[ 5], 7, k2); + Subround(H, b1, c1, d1, a1, X[12], 5, k2); + + Subround(I, a1, b1, c1, d1, X[ 1], 11, k3); + Subround(I, d1, a1, b1, c1, X[ 9], 12, k3); + Subround(I, c1, d1, a1, b1, X[11], 14, k3); + Subround(I, b1, c1, d1, a1, X[10], 15, k3); + Subround(I, a1, b1, c1, d1, X[ 0], 14, k3); + Subround(I, d1, a1, b1, c1, X[ 8], 15, k3); + Subround(I, c1, d1, a1, b1, X[12], 9, k3); + Subround(I, b1, c1, d1, a1, X[ 4], 8, k3); + Subround(I, a1, b1, c1, d1, X[13], 9, k3); + Subround(I, d1, a1, b1, c1, X[ 3], 14, k3); + Subround(I, c1, d1, a1, b1, X[ 7], 5, k3); + Subround(I, b1, c1, d1, a1, X[15], 6, k3); + Subround(I, a1, b1, c1, d1, X[14], 8, k3); + Subround(I, d1, a1, b1, c1, X[ 5], 6, k3); + Subround(I, c1, d1, a1, b1, X[ 6], 5, k3); + Subround(I, b1, c1, d1, a1, X[ 2], 12, k3); + + Subround(I, a2, b2, c2, d2, X[ 5], 8, k5); + Subround(I, d2, a2, b2, c2, X[14], 9, k5); + Subround(I, c2, d2, a2, b2, X[ 7], 9, k5); + Subround(I, b2, c2, d2, a2, X[ 0], 11, k5); + Subround(I, a2, b2, c2, d2, X[ 9], 13, k5); + Subround(I, d2, a2, b2, c2, X[ 2], 15, k5); + Subround(I, c2, d2, a2, b2, X[11], 15, k5); + Subround(I, b2, c2, d2, a2, X[ 4], 5, k5); + Subround(I, a2, b2, c2, d2, X[13], 7, k5); + Subround(I, d2, a2, b2, c2, X[ 6], 7, k5); + Subround(I, c2, d2, a2, b2, X[15], 8, k5); + Subround(I, b2, c2, d2, a2, X[ 8], 11, k5); + Subround(I, a2, b2, c2, d2, X[ 1], 14, k5); + Subround(I, d2, a2, b2, c2, X[10], 14, k5); + Subround(I, c2, d2, a2, b2, X[ 3], 12, k5); + Subround(I, b2, c2, d2, a2, X[12], 6, k5); + + Subround(H, a2, b2, c2, d2, X[ 6], 9, k6); + Subround(H, d2, a2, b2, c2, X[11], 13, k6); + Subround(H, c2, d2, a2, b2, X[ 3], 15, k6); + Subround(H, b2, c2, d2, a2, X[ 7], 7, k6); + Subround(H, a2, b2, c2, d2, X[ 0], 12, k6); + Subround(H, d2, a2, b2, c2, X[13], 8, k6); + Subround(H, c2, d2, a2, b2, X[ 5], 9, k6); + Subround(H, b2, c2, d2, a2, X[10], 11, k6); + Subround(H, a2, b2, c2, d2, X[14], 7, k6); + Subround(H, d2, a2, b2, c2, X[15], 7, k6); + Subround(H, c2, d2, a2, b2, X[ 8], 12, k6); + Subround(H, b2, c2, d2, a2, X[12], 7, k6); + Subround(H, a2, b2, c2, d2, X[ 4], 6, k6); + Subround(H, d2, a2, b2, c2, X[ 9], 15, k6); + Subround(H, c2, d2, a2, b2, X[ 1], 13, k6); + Subround(H, b2, c2, d2, a2, X[ 2], 11, k6); + + Subround(G, a2, b2, c2, d2, X[15], 9, k7); + Subround(G, d2, a2, b2, c2, X[ 5], 7, k7); + Subround(G, c2, d2, a2, b2, X[ 1], 15, k7); + Subround(G, b2, c2, d2, a2, X[ 3], 11, k7); + Subround(G, a2, b2, c2, d2, X[ 7], 8, k7); + Subround(G, d2, a2, b2, c2, X[14], 6, k7); + Subround(G, c2, d2, a2, b2, X[ 6], 6, k7); + Subround(G, b2, c2, d2, a2, X[ 9], 14, k7); + Subround(G, a2, b2, c2, d2, X[11], 12, k7); + Subround(G, d2, a2, b2, c2, X[ 8], 13, k7); + Subround(G, c2, d2, a2, b2, X[12], 5, k7); + Subround(G, b2, c2, d2, a2, X[ 2], 14, k7); + Subround(G, a2, b2, c2, d2, X[10], 13, k7); + Subround(G, d2, a2, b2, c2, X[ 0], 13, k7); + Subround(G, c2, d2, a2, b2, X[ 4], 7, k7); + Subround(G, b2, c2, d2, a2, X[13], 5, k7); + + Subround(F, a2, b2, c2, d2, X[ 8], 15, k9); + Subround(F, d2, a2, b2, c2, X[ 6], 5, k9); + Subround(F, c2, d2, a2, b2, X[ 4], 8, k9); + Subround(F, b2, c2, d2, a2, X[ 1], 11, k9); + Subround(F, a2, b2, c2, d2, X[ 3], 14, k9); + Subround(F, d2, a2, b2, c2, X[11], 14, k9); + Subround(F, c2, d2, a2, b2, X[15], 6, k9); + Subround(F, b2, c2, d2, a2, X[ 0], 14, k9); + Subround(F, a2, b2, c2, d2, X[ 5], 6, k9); + Subround(F, d2, a2, b2, c2, X[12], 9, k9); + Subround(F, c2, d2, a2, b2, X[ 2], 12, k9); + Subround(F, b2, c2, d2, a2, X[13], 9, k9); + Subround(F, a2, b2, c2, d2, X[ 9], 12, k9); + Subround(F, d2, a2, b2, c2, X[ 7], 5, k9); + Subround(F, c2, d2, a2, b2, X[10], 15, k9); + Subround(F, b2, c2, d2, a2, X[14], 8, k9); + + c1 = digest[1] + c1 + d2; + digest[1] = digest[2] + d1 + a2; + digest[2] = digest[3] + a1 + b2; + digest[3] = digest[0] + b1 + c2; + digest[0] = c1; +} + +// ************************************************************* + +void RIPEMD256::InitState(HashWordType *state) +{ + state[0] = 0x67452301L; + state[1] = 0xefcdab89L; + state[2] = 0x98badcfeL; + state[3] = 0x10325476L; + state[4] = 0x76543210L; + state[5] = 0xfedcba98L; + state[6] = 0x89abcdefL; + state[7] = 0x01234567L; +} + +void RIPEMD256::Transform (word32 *digest, const word32 *X) +{ + unsigned long a1, b1, c1, d1, a2, b2, c2, d2, t; + a1 = digest[0]; + b1 = digest[1]; + c1 = digest[2]; + d1 = digest[3]; + a2 = digest[4]; + b2 = digest[5]; + c2 = digest[6]; + d2 = digest[7]; + + Subround(F, a1, b1, c1, d1, X[ 0], 11, k0); + Subround(F, d1, a1, b1, c1, X[ 1], 14, k0); + Subround(F, c1, d1, a1, b1, X[ 2], 15, k0); + Subround(F, b1, c1, d1, a1, X[ 3], 12, k0); + Subround(F, a1, b1, c1, d1, X[ 4], 5, k0); + Subround(F, d1, a1, b1, c1, X[ 5], 8, k0); + Subround(F, c1, d1, a1, b1, X[ 6], 7, k0); + Subround(F, b1, c1, d1, a1, X[ 7], 9, k0); + Subround(F, a1, b1, c1, d1, X[ 8], 11, k0); + Subround(F, d1, a1, b1, c1, X[ 9], 13, k0); + Subround(F, c1, d1, a1, b1, X[10], 14, k0); + Subround(F, b1, c1, d1, a1, X[11], 15, k0); + Subround(F, a1, b1, c1, d1, X[12], 6, k0); + Subround(F, d1, a1, b1, c1, X[13], 7, k0); + Subround(F, c1, d1, a1, b1, X[14], 9, k0); + Subround(F, b1, c1, d1, a1, X[15], 8, k0); + + Subround(I, a2, b2, c2, d2, X[ 5], 8, k5); + Subround(I, d2, a2, b2, c2, X[14], 9, k5); + Subround(I, c2, d2, a2, b2, X[ 7], 9, k5); + Subround(I, b2, c2, d2, a2, X[ 0], 11, k5); + Subround(I, a2, b2, c2, d2, X[ 9], 13, k5); + Subround(I, d2, a2, b2, c2, X[ 2], 15, k5); + Subround(I, c2, d2, a2, b2, X[11], 15, k5); + Subround(I, b2, c2, d2, a2, X[ 4], 5, k5); + Subround(I, a2, b2, c2, d2, X[13], 7, k5); + Subround(I, d2, a2, b2, c2, X[ 6], 7, k5); + Subround(I, c2, d2, a2, b2, X[15], 8, k5); + Subround(I, b2, c2, d2, a2, X[ 8], 11, k5); + Subround(I, a2, b2, c2, d2, X[ 1], 14, k5); + Subround(I, d2, a2, b2, c2, X[10], 14, k5); + Subround(I, c2, d2, a2, b2, X[ 3], 12, k5); + Subround(I, b2, c2, d2, a2, X[12], 6, k5); + + t = a1; a1 = a2; a2 = t; + + Subround(G, a1, b1, c1, d1, X[ 7], 7, k1); + Subround(G, d1, a1, b1, c1, X[ 4], 6, k1); + Subround(G, c1, d1, a1, b1, X[13], 8, k1); + Subround(G, b1, c1, d1, a1, X[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, X[10], 11, k1); + Subround(G, d1, a1, b1, c1, X[ 6], 9, k1); + Subround(G, c1, d1, a1, b1, X[15], 7, k1); + Subround(G, b1, c1, d1, a1, X[ 3], 15, k1); + Subround(G, a1, b1, c1, d1, X[12], 7, k1); + Subround(G, d1, a1, b1, c1, X[ 0], 12, k1); + Subround(G, c1, d1, a1, b1, X[ 9], 15, k1); + Subround(G, b1, c1, d1, a1, X[ 5], 9, k1); + Subround(G, a1, b1, c1, d1, X[ 2], 11, k1); + Subround(G, d1, a1, b1, c1, X[14], 7, k1); + Subround(G, c1, d1, a1, b1, X[11], 13, k1); + Subround(G, b1, c1, d1, a1, X[ 8], 12, k1); + + Subround(H, a2, b2, c2, d2, X[ 6], 9, k6); + Subround(H, d2, a2, b2, c2, X[11], 13, k6); + Subround(H, c2, d2, a2, b2, X[ 3], 15, k6); + Subround(H, b2, c2, d2, a2, X[ 7], 7, k6); + Subround(H, a2, b2, c2, d2, X[ 0], 12, k6); + Subround(H, d2, a2, b2, c2, X[13], 8, k6); + Subround(H, c2, d2, a2, b2, X[ 5], 9, k6); + Subround(H, b2, c2, d2, a2, X[10], 11, k6); + Subround(H, a2, b2, c2, d2, X[14], 7, k6); + Subround(H, d2, a2, b2, c2, X[15], 7, k6); + Subround(H, c2, d2, a2, b2, X[ 8], 12, k6); + Subround(H, b2, c2, d2, a2, X[12], 7, k6); + Subround(H, a2, b2, c2, d2, X[ 4], 6, k6); + Subround(H, d2, a2, b2, c2, X[ 9], 15, k6); + Subround(H, c2, d2, a2, b2, X[ 1], 13, k6); + Subround(H, b2, c2, d2, a2, X[ 2], 11, k6); + + t = b1; b1 = b2; b2 = t; + + Subround(H, a1, b1, c1, d1, X[ 3], 11, k2); + Subround(H, d1, a1, b1, c1, X[10], 13, k2); + Subround(H, c1, d1, a1, b1, X[14], 6, k2); + Subround(H, b1, c1, d1, a1, X[ 4], 7, k2); + Subround(H, a1, b1, c1, d1, X[ 9], 14, k2); + Subround(H, d1, a1, b1, c1, X[15], 9, k2); + Subround(H, c1, d1, a1, b1, X[ 8], 13, k2); + Subround(H, b1, c1, d1, a1, X[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, X[ 2], 14, k2); + Subround(H, d1, a1, b1, c1, X[ 7], 8, k2); + Subround(H, c1, d1, a1, b1, X[ 0], 13, k2); + Subround(H, b1, c1, d1, a1, X[ 6], 6, k2); + Subround(H, a1, b1, c1, d1, X[13], 5, k2); + Subround(H, d1, a1, b1, c1, X[11], 12, k2); + Subround(H, c1, d1, a1, b1, X[ 5], 7, k2); + Subround(H, b1, c1, d1, a1, X[12], 5, k2); + + Subround(G, a2, b2, c2, d2, X[15], 9, k7); + Subround(G, d2, a2, b2, c2, X[ 5], 7, k7); + Subround(G, c2, d2, a2, b2, X[ 1], 15, k7); + Subround(G, b2, c2, d2, a2, X[ 3], 11, k7); + Subround(G, a2, b2, c2, d2, X[ 7], 8, k7); + Subround(G, d2, a2, b2, c2, X[14], 6, k7); + Subround(G, c2, d2, a2, b2, X[ 6], 6, k7); + Subround(G, b2, c2, d2, a2, X[ 9], 14, k7); + Subround(G, a2, b2, c2, d2, X[11], 12, k7); + Subround(G, d2, a2, b2, c2, X[ 8], 13, k7); + Subround(G, c2, d2, a2, b2, X[12], 5, k7); + Subround(G, b2, c2, d2, a2, X[ 2], 14, k7); + Subround(G, a2, b2, c2, d2, X[10], 13, k7); + Subround(G, d2, a2, b2, c2, X[ 0], 13, k7); + Subround(G, c2, d2, a2, b2, X[ 4], 7, k7); + Subround(G, b2, c2, d2, a2, X[13], 5, k7); + + t = c1; c1 = c2; c2 = t; + + Subround(I, a1, b1, c1, d1, X[ 1], 11, k3); + Subround(I, d1, a1, b1, c1, X[ 9], 12, k3); + Subround(I, c1, d1, a1, b1, X[11], 14, k3); + Subround(I, b1, c1, d1, a1, X[10], 15, k3); + Subround(I, a1, b1, c1, d1, X[ 0], 14, k3); + Subround(I, d1, a1, b1, c1, X[ 8], 15, k3); + Subround(I, c1, d1, a1, b1, X[12], 9, k3); + Subround(I, b1, c1, d1, a1, X[ 4], 8, k3); + Subround(I, a1, b1, c1, d1, X[13], 9, k3); + Subround(I, d1, a1, b1, c1, X[ 3], 14, k3); + Subround(I, c1, d1, a1, b1, X[ 7], 5, k3); + Subround(I, b1, c1, d1, a1, X[15], 6, k3); + Subround(I, a1, b1, c1, d1, X[14], 8, k3); + Subround(I, d1, a1, b1, c1, X[ 5], 6, k3); + Subround(I, c1, d1, a1, b1, X[ 6], 5, k3); + Subround(I, b1, c1, d1, a1, X[ 2], 12, k3); + + Subround(F, a2, b2, c2, d2, X[ 8], 15, k9); + Subround(F, d2, a2, b2, c2, X[ 6], 5, k9); + Subround(F, c2, d2, a2, b2, X[ 4], 8, k9); + Subround(F, b2, c2, d2, a2, X[ 1], 11, k9); + Subround(F, a2, b2, c2, d2, X[ 3], 14, k9); + Subround(F, d2, a2, b2, c2, X[11], 14, k9); + Subround(F, c2, d2, a2, b2, X[15], 6, k9); + Subround(F, b2, c2, d2, a2, X[ 0], 14, k9); + Subround(F, a2, b2, c2, d2, X[ 5], 6, k9); + Subround(F, d2, a2, b2, c2, X[12], 9, k9); + Subround(F, c2, d2, a2, b2, X[ 2], 12, k9); + Subround(F, b2, c2, d2, a2, X[13], 9, k9); + Subround(F, a2, b2, c2, d2, X[ 9], 12, k9); + Subround(F, d2, a2, b2, c2, X[ 7], 5, k9); + Subround(F, c2, d2, a2, b2, X[10], 15, k9); + Subround(F, b2, c2, d2, a2, X[14], 8, k9); + + t = d1; d1 = d2; d2 = t; + + digest[0] += a1; + digest[1] += b1; + digest[2] += c1; + digest[3] += d1; + digest[4] += a2; + digest[5] += b2; + digest[6] += c2; + digest[7] += d2; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ripemd.h b/extension/third_party/cryptopp/ripemd.h new file mode 100644 index 00000000..b5fbb4ae --- /dev/null +++ b/extension/third_party/cryptopp/ripemd.h @@ -0,0 +1,65 @@ +// ripemd.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for RIPEMD message digest + +#ifndef CRYPTOPP_RIPEMD_H +#define CRYPTOPP_RIPEMD_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RIPEMD-160 message digest +/// \details Digest size is 160-bits. +/// \sa RIPEMD-160 +/// \since Crypto++ 2.1 +class RIPEMD160 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-160";} +}; + +/// \brief RIPEMD-320 message digest +/// \details Digest size is 320-bits. +/// \sa RIPEMD-320 +/// \since Crypto++ 2.1 +class RIPEMD320 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-320";} +}; + +/// \brief RIPEMD-128 message digest +/// \details Digest size is 128-bits. +/// \warning RIPEMD-128 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-128 +/// \since Crypto++ 2.1 +class RIPEMD128 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-128";} +}; + +/// \brief RIPEMD-256 message digest +/// \details Digest size is 256-bits. +/// \warning RIPEMD-256 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-256 +/// \since Crypto++ 2.1 +class RIPEMD256 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-256";} +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rng.cpp b/extension/third_party/cryptopp/rng.cpp new file mode 100644 index 00000000..1bb525e9 --- /dev/null +++ b/extension/third_party/cryptopp/rng.cpp @@ -0,0 +1,166 @@ +// rng.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "rng.h" +#include "fips140.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +// linear congruential generator +// originally by William S. England + +// do not use for cryptographic purposes + +/* +** Original_numbers are the original published m and q in the +** ACM article above. John Burton has furnished numbers for +** a reportedly better generator. The new numbers are now +** used in this program by default. +*/ + +#ifndef LCRNG_ORIGINAL_NUMBERS +const word32 LC_RNG::m=2147483647L; +const word32 LC_RNG::q=44488L; + +const word16 LC_RNG::a=(unsigned int)48271L; +const word16 LC_RNG::r=3399; +#else +const word32 LC_RNG::m=2147483647L; +const word32 LC_RNG::q=127773L; + +const word16 LC_RNG::a=16807; +const word16 LC_RNG::r=2836; +#endif + +void LC_RNG::GenerateBlock(byte *output, size_t size) +{ + while (size--) + { + const word32 hi = seed/q; + const word32 lo = seed%q; + const sword64 test = a*lo - r*hi; + + if (test > 0) + seed = static_cast(test); + else + seed = static_cast(test + m); + + *output++ = byte((GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3))); + } +} + +// ******************************************************** + +#ifndef CRYPTOPP_IMPORTS + +X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector) + : m_cipher(c), + m_size(m_cipher->BlockSize()), + m_datetime(m_size), + m_randseed(seed, m_size), + m_lastBlock(m_size), + m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? m_size : 0) +{ + // Valgrind finding, http://github.com/weidai11/cryptopp/issues/105 + // Garbage in the tail creates a non-conforming X9.17 or X9.31 generator. + if (m_size > 8) + { + memset(m_datetime, 0x00, m_size); + memset(m_lastBlock, 0x00, m_size); + } + + if (!deterministicTimeVector) + { + time_t tstamp1 = ::time(NULLPTR); + xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size)); + m_cipher->ProcessBlock(m_datetime); + clock_t tstamp2 = clock(); + xorbuf(m_datetime, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), m_size)); + m_cipher->ProcessBlock(m_datetime); + } + + // for FIPS 140-2 + // GenerateBlock(m_lastBlock, m_size); + + // Make explicit call to avoid virtual-dispatch findings in ctor + ArraySink target(m_lastBlock, m_size); + X917RNG::GenerateIntoBufferedTransformation(target, DEFAULT_CHANNEL, m_size); +} + +void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) +{ + while (size > 0) + { + // calculate new enciphered timestamp + if (m_deterministicTimeVector.size()) + { + m_cipher->ProcessBlock(m_deterministicTimeVector, m_datetime); + IncrementCounterByOne(m_deterministicTimeVector, m_size); + } + else + { + clock_t c = clock(); + xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size)); + time_t t = ::time(NULLPTR); + xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size)); + m_cipher->ProcessBlock(m_datetime); + } + + // combine enciphered timestamp with seed + xorbuf(m_randseed, m_datetime, m_size); + + // generate a new block of random bytes + m_cipher->ProcessBlock(m_randseed); + if (memcmp(m_lastBlock, m_randseed, m_size) == 0) + throw SelfTestFailure("X917RNG: Continuous random number generator test failed."); + + // output random bytes + size_t len = UnsignedMin(m_size, size); + target.ChannelPut(channel, m_randseed, len); + size -= len; + + // compute new seed vector + memcpy(m_lastBlock, m_randseed, m_size); + xorbuf(m_randseed, m_datetime, m_size); + m_cipher->ProcessBlock(m_randseed); + } +} + +#endif + +MaurerRandomnessTest::MaurerRandomnessTest() + : sum(0.0), n(0) +{ + for (unsigned i=0; i= Q) + sum += ::log(double(n - tab[inByte])); + tab[inByte] = n; + n++; + } + return 0; +} + +double MaurerRandomnessTest::GetTestValue() const +{ + if (BytesNeeded() > 0) + throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed"); + + double fTu = (sum/(n-Q))/::log(2.0); // this is the test value defined by Maurer + + double value = fTu * 0.1392; // arbitrarily normalize it to + return value > 1.0 ? 1.0 : value; // a number between 0 and 1 +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/rng.h b/extension/third_party/cryptopp/rng.h new file mode 100644 index 00000000..7f982ab1 --- /dev/null +++ b/extension/third_party/cryptopp/rng.h @@ -0,0 +1,111 @@ +// rng.h - originally written and placed in the public domain by Wei Dai + +/// \file rng.h +/// \brief Miscellaneous classes for RNGs +/// \details This file contains miscellaneous classes for RNGs, including LC_RNG(), +/// X917RNG() and MaurerRandomnessTest() +/// \sa osrng.h, randpool.h + +#ifndef CRYPTOPP_RNG_H +#define CRYPTOPP_RNG_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Linear Congruential Generator (LCG) +/// \details Originally propsed by William S. England. +/// \warning LC_RNG is suitable for simulations, where uniformaly distrubuted numbers are +/// required quickly. It should not be used for cryptographic purposes. +class LC_RNG : public RandomNumberGenerator +{ +public: + /// \brief Construct a Linear Congruential Generator (LCG) + /// \param init_seed the initial value for the generator + LC_RNG(word32 init_seed) + : seed(init_seed) {} + + void GenerateBlock(byte *output, size_t size); + + word32 GetSeed() {return seed;} + +private: + word32 seed; + + static const word32 m; + static const word32 q; + static const word16 a; + static const word16 r; +}; + +/// \brief ANSI X9.17 RNG +/// \details X917RNG is from ANSI X9.17 Appendix C, and it uses a 64-bit block cipher, like TripleDES. +/// If you use a 128-bit block cipher, like AES, then you are effectively using an ANSI X9.31 generator. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa AutoSeededX917RNG, DefaultAutoSeededRNG +class CRYPTOPP_DLL X917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a X917RNG + /// \param cipher the block cipher to use for the generator + /// \param seed a byte buffer to use as a seed + /// \param deterministicTimeVector additional entropy + /// \details cipher will be deleted by the destructor. seed must be at least + /// BlockSize() in length. deterministicTimeVector = 0 means obtain time vector + /// from the system. + /// \details When constructing a X917RNG, the generator must be keyed or an access + /// violation will occur because the time vector is encrypted using the block cipher. + /// To key the generator during constructions, perform the following: + ///
+	///  SecByteBlock key(AES::DEFAULT_KEYLENGTH), seed(AES::BLOCKSIZE);
+	///  OS_GenerateRandomBlock(false, key, key.size());
+	///  OS_GenerateRandomBlock(false, seed, seed.size());
+	///  X917RNG prng(new AES::Encryption(key, AES::DEFAULT_KEYLENGTH), seed, NULLPTR);
+ /// \sa AutoSeededX917RNG + X917RNG(BlockTransformation *cipher, const byte *seed, const byte *deterministicTimeVector = NULLPTR); + + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + member_ptr m_cipher; + const unsigned int m_size; // S, blocksize of cipher + SecByteBlock m_datetime; // DT, buffer for enciphered timestamp + SecByteBlock m_randseed, m_lastBlock, m_deterministicTimeVector; +}; + +/// \brief Maurer's Universal Statistical Test for Random Bit Generators +/// \details This class implements Maurer's Universal Statistical Test for +/// Random Bit Generators. It is intended for measuring the randomness of +/// *PHYSICAL* RNGs. +/// \details For more details see Maurer's paper in Journal of Cryptology, 1992. +class MaurerRandomnessTest : public Bufferless +{ +public: + /// \brief Construct a MaurerRandomnessTest + MaurerRandomnessTest(); + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Provides the number of bytes of input is needed by the test + /// \return how many more bytes of input is needed by the test + // BytesNeeded() returns how many more bytes of input is needed by the test + // GetTestValue() should not be called before BytesNeeded()==0 + unsigned int BytesNeeded() const {return n >= (Q+K) ? 0 : Q+K-n;} + + // returns a number between 0.0 and 1.0, describing the quality of the + // random numbers entered + double GetTestValue() const; + +private: + enum {L=8, V=256, Q=2000, K=2000}; + double sum; + unsigned int n; + unsigned int tab[V]; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rsa.cpp b/extension/third_party/cryptopp/rsa.cpp new file mode 100644 index 00000000..f3e66866 --- /dev/null +++ b/extension/third_party/cryptopp/rsa.cpp @@ -0,0 +1,330 @@ +// rsa.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "rsa.h" +#include "asn.h" +#include "sha.h" +#include "oids.h" +#include "modarith.h" +#include "nbtheory.h" +#include "algparam.h" +#include "fips140.h" +#include "pkcspad.h" + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) && !defined(CRYPTOPP_IS_DLL) +#include "sha3.h" +#include "pssr.h" +NAMESPACE_BEGIN(CryptoPP) +void RSA_TestInstantiations() +{ + RSASS::Verifier x1(1, 1); + RSASS::Signer x2(NullRNG(), 1); + RSASS::Verifier x3(x2); + RSASS::Verifier x4(x2.GetKey()); + RSASS::Verifier x5(x3); +#ifndef __MWERKS__ + RSASS::Signer x6 = x2; + x3 = x2; + x6 = x2; +#endif + RSAES::Encryptor x7(x2); +#ifndef __GNUC__ + RSAES::Encryptor x8(x3); +#endif + RSAES >::Encryptor x9(x2); + x4 = x2.GetKey(); + + RSASS::Verifier x10(1, 1); + RSASS::Signer x11(NullRNG(), 1); + RSASS::Verifier x12(x11); + RSASS::Verifier x13(x11.GetKey()); +} +NAMESPACE_END +#endif + +#ifndef CRYPTOPP_IMPORTS + +NAMESPACE_BEGIN(CryptoPP) + +OID RSAFunction::GetAlgorithmID() const +{ + return ASN1::rsaEncryption(); +} + +void RSAFunction::BERDecodePublicKey(BufferedTransformation &bt, bool, size_t) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_e.BERDecode(seq); + seq.MessageEnd(); +} + +void RSAFunction::DEREncodePublicKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_e.DEREncode(seq); + seq.MessageEnd(); +} + +Integer RSAFunction::ApplyFunction(const Integer &x) const +{ + DoQuickSanityCheck(); + return a_exp_b_mod_c(x, m_e, m_n); +} + +bool RSAFunction::Validate(RandomNumberGenerator& rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(level); + + bool pass = true; + pass = pass && m_n > Integer::One() && m_n.IsOdd(); + CRYPTOPP_ASSERT(pass); + pass = pass && m_e > Integer::One() && m_e.IsOdd() && m_e < m_n; + CRYPTOPP_ASSERT(pass); + return pass; +} + +bool RSAFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent) + ; +} + +void RSAFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent) + ; +} + +// ***************************************************************************** + +class RSAPrimeSelector : public PrimeSelector +{ +public: + RSAPrimeSelector(const Integer &e) : m_e(e) {} + bool IsAcceptable(const Integer &candidate) const {return RelativelyPrime(m_e, candidate-Integer::One());} + Integer m_e; +}; + +void InvertibleRSAFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue(Name::ModulusSize(), modulusSize) || alg.GetIntValue(Name::KeySize(), modulusSize); + + CRYPTOPP_ASSERT(modulusSize >= 16); + if (modulusSize < 16) + throw InvalidArgument("InvertibleRSAFunction: specified modulus size is too small"); + + m_e = alg.GetValueWithDefault(Name::PublicExponent(), Integer(17)); + + CRYPTOPP_ASSERT(m_e >= 3); CRYPTOPP_ASSERT(!m_e.IsEven()); + if (m_e < 3 || m_e.IsEven()) + throw InvalidArgument("InvertibleRSAFunction: invalid public exponent"); + + RSAPrimeSelector selector(m_e); + AlgorithmParameters primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize) + (Name::PointerToPrimeSelector(), selector.GetSelectorPointer()); + m_p.GenerateRandom(rng, primeParam); + m_q.GenerateRandom(rng, primeParam); + + m_d = m_e.InverseMod(LCM(m_p-1, m_q-1)); + CRYPTOPP_ASSERT(m_d.IsPositive()); + + m_dp = m_d % (m_p-1); + m_dq = m_d % (m_q-1); + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); + + if (FIPS_140_2_ComplianceEnabled()) + { + RSASS::Signer signer(*this); + RSASS::Verifier verifier(signer); + SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier); + + RSAES >::Decryptor decryptor(*this); + RSAES >::Encryptor encryptor(decryptor); + EncryptionPairwiseConsistencyTest_FIPS_140_Only(encryptor, decryptor); + } +} + +void InvertibleRSAFunction::Initialize(RandomNumberGenerator &rng, unsigned int keybits, const Integer &e) +{ + GenerateRandom(rng, MakeParameters(Name::ModulusSize(), (int)keybits)(Name::PublicExponent(), e+e.IsEven())); +} + +void InvertibleRSAFunction::Initialize(const Integer &n, const Integer &e, const Integer &d) +{ + if (n.IsEven() || e.IsEven() | d.IsEven()) + throw InvalidArgument("InvertibleRSAFunction: input is not a valid RSA private key"); + + m_n = n; + m_e = e; + m_d = d; + + Integer r = --(d*e); + unsigned int s = 0; + while (r.IsEven()) + { + r >>= 1; + s++; + } + + ModularArithmetic modn(n); + for (Integer i = 2; ; ++i) + { + Integer a = modn.Exponentiate(i, r); + if (a == 1) + continue; + Integer b; + unsigned int j = 0; + while (a != n-1) + { + b = modn.Square(a); + if (b == 1) + { + m_p = GCD(a-1, n); + m_q = n/m_p; + m_dp = m_d % (m_p-1); + m_dq = m_d % (m_q-1); + m_u = m_q.InverseMod(m_p); + return; + } + if (++j == s) + throw InvalidArgument("InvertibleRSAFunction: input is not a valid RSA private key"); + a = b; + } + } +} + +void InvertibleRSAFunction::BERDecodePrivateKey(BufferedTransformation &bt, bool, size_t) +{ + BERSequenceDecoder privateKey(bt); + word32 version; + BERDecodeUnsigned(privateKey, version, INTEGER, 0, 0); // check version + m_n.BERDecode(privateKey); + m_e.BERDecode(privateKey); + m_d.BERDecode(privateKey); + m_p.BERDecode(privateKey); + m_q.BERDecode(privateKey); + m_dp.BERDecode(privateKey); + m_dq.BERDecode(privateKey); + m_u.BERDecode(privateKey); + privateKey.MessageEnd(); +} + +void InvertibleRSAFunction::DEREncodePrivateKey(BufferedTransformation &bt) const +{ + DERSequenceEncoder privateKey(bt); + DEREncodeUnsigned(privateKey, 0); // version + m_n.DEREncode(privateKey); + m_e.DEREncode(privateKey); + m_d.DEREncode(privateKey); + m_p.DEREncode(privateKey); + m_q.DEREncode(privateKey); + m_dp.DEREncode(privateKey); + m_dq.DEREncode(privateKey); + m_u.DEREncode(privateKey); + privateKey.MessageEnd(); +} + +Integer InvertibleRSAFunction::CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + DoQuickSanityCheck(); + ModularArithmetic modn(m_n); + Integer r, rInv; + do { // do this in a loop for people using small numbers for testing + r.Randomize(rng, Integer::One(), m_n - Integer::One()); + rInv = modn.MultiplicativeInverse(r); + } while (rInv.IsZero()); + Integer re = modn.Exponentiate(r, m_e); + re = modn.Multiply(re, x); // blind + // here we follow the notation of PKCS #1 and let u=q inverse mod p + // but in ModRoot, u=p inverse mod q, so we reverse the order of p and q + Integer y = ModularRoot(re, m_dq, m_dp, m_q, m_p, m_u); + y = modn.Multiply(y, rInv); // unblind + if (modn.Exponentiate(y, m_e) != x) // check + throw Exception(Exception::OTHER_ERROR, "InvertibleRSAFunction: computational error during private key operation"); + return y; +} + +bool InvertibleRSAFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RSAFunction::Validate(rng, level); + CRYPTOPP_ASSERT(pass); + pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_d > Integer::One() && m_d.IsOdd() && m_d < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_dp > Integer::One() && m_dp.IsOdd() && m_dp < m_p; + CRYPTOPP_ASSERT(pass); + pass = pass && m_dq > Integer::One() && m_dq.IsOdd() && m_dq < m_q; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u.IsPositive() && m_u < m_p; + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_e*m_d % LCM(m_p-1, m_q-1) == 1; + CRYPTOPP_ASSERT(pass); + pass = pass && m_dp == m_d%(m_p-1) && m_dq == m_d%(m_q-1); + CRYPTOPP_ASSERT(pass); + pass = pass && m_u * m_q % m_p == 1; + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool InvertibleRSAFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime1PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime2PrivateExponent) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleRSAFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime1PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime2PrivateExponent) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +// ***************************************************************************** + +Integer RSAFunction_ISO::ApplyFunction(const Integer &x) const +{ + Integer t = RSAFunction::ApplyFunction(x); + return t % 16 == 12 ? t : m_n - t; +} + +Integer InvertibleRSAFunction_ISO::CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + Integer t = InvertibleRSAFunction::CalculateInverse(rng, x); + return STDMIN(t, m_n-t); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rsa.h b/extension/third_party/cryptopp/rsa.h new file mode 100644 index 00000000..62c1111e --- /dev/null +++ b/extension/third_party/cryptopp/rsa.h @@ -0,0 +1,263 @@ +// rsa.h - originally written and placed in the public domain by Wei Dai + +/// \file rsa.h +/// \brief Classes for the RSA cryptosystem +/// \details This file contains classes that implement the RSA +/// ciphers and signature schemes as defined in PKCS #1 v2.0. + +#ifndef CRYPTOPP_RSA_H +#define CRYPTOPP_RSA_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "pkcspad.h" +#include "oaep.h" +#include "emsa2.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction : public TrapdoorFunction, public X509PublicKey +{ + typedef RSAFunction ThisClass; + +public: + /// \brief Initialize a RSA public key + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // X509PublicKey + OID GetAlgorithmID() const; + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction : public RSAFunction, public TrapdoorFunctionInverse, public PKCS8PrivateKey +{ + typedef InvertibleRSAFunction ThisClass; + +public: + /// \brief Create a RSA private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param e the desired public exponent + /// \details Initialize() creates a new keypair using a public exponent of 17. + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &e = 17); + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param dp d mod p + /// \param dq d mod q + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &d, const Integer &p, const Integer &q, const Integer &dp, const Integer &dq, const Integer &u) + {m_n = n; m_e = e; m_d = d; m_p = p; m_q = q; m_dp = dp; m_dq = dq; m_u = u;} + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + /// Initialize() will factor n using d and populate {p,q,dp,dq,u}. + void Initialize(const Integer &n, const Integer &e, const Integer &d); + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void DEREncode(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + void Load(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void Save(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + OID GetAlgorithmID() const {return RSAFunction::GetAlgorithmID();} + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + // TrapdoorFunctionInverse + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + // parameters: (ModulusSize, PublicExponent (default 17)) + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetPrivateExponent() const {return m_d;} + const Integer& GetModPrime1PrivateExponent() const {return m_dp;} + const Integer& GetModPrime2PrivateExponent() const {return m_dq;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetPrivateExponent(const Integer &d) {m_d = d;} + void SetModPrime1PrivateExponent(const Integer &dp) {m_dp = dp;} + void SetModPrime2PrivateExponent(const Integer &dq) {m_dq = dq;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_d, m_p, m_q, m_dp, m_dq, m_u; +}; + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction_ISO : public RSAFunction +{ +public: + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction_ISO : public InvertibleRSAFunction +{ +public: + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA";} + typedef RSAFunction PublicKey; + typedef InvertibleRSAFunction PrivateKey; +}; + +/// \brief RSA encryption algorithm +/// \tparam STANDARD signature standard +/// \sa RSA cryptosystem +/// \since Crypto++ 1.0 +template +struct RSAES : public TF_ES +{ +}; + +/// \brief RSA signature algorithm +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details See documentation of PKCS1v15 for a list of hash functions that can be used with it. +/// \sa RSA signature scheme with appendix +/// \since Crypto++ 1.0 +template +struct RSASS : public TF_SS +{ +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA_ISO +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA-ISO";} + typedef RSAFunction_ISO PublicKey; + typedef InvertibleRSAFunction_ISO PrivateKey; +}; + +/// \brief RSA signature algorithm +/// \tparam H hash transformation +/// \since Crypto++ 1.0 +template +struct RSASS_ISO : public TF_SS +{ +}; + +/// \brief \ref RSAES "RSAES::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES::Decryptor, RSAES_PKCS1v15_Decryptor); +/// \brief \ref RSAES "RSAES::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES::Encryptor, RSAES_PKCS1v15_Encryptor); + +/// \brief \ref RSAES "RSAES>::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES >::Decryptor, RSAES_OAEP_SHA_Decryptor); +/// \brief \ref RSAES "RSAES>::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +DOCUMENTED_TYPEDEF(RSAES >::Encryptor, RSAES_OAEP_SHA_Encryptor); + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Verifier : public RSASS::Verifier {}; + +namespace Weak { + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Verifier : public RSASS::Verifier {}; + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Verifier : public RSASS::Verifier {}; +} + +#else +typedef RSASS::Signer RSASSA_PKCS1v15_SHA_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_SHA_Verifier; + +namespace Weak { + typedef RSASS::Signer RSASSA_PKCS1v15_MD2_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD2_Verifier; + typedef RSASS::Signer RSASSA_PKCS1v15_MD5_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD5_Verifier; +} +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rw.cpp b/extension/third_party/cryptopp/rw.cpp new file mode 100644 index 00000000..ab79358c --- /dev/null +++ b/extension/third_party/cryptopp/rw.cpp @@ -0,0 +1,314 @@ +// rw.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "rw.h" +#include "asn.h" +#include "integer.h" +#include "nbtheory.h" +#include "modarith.h" +#include "asn.h" + +#ifndef CRYPTOPP_IMPORTS + +#if defined(_OPENMP) +# define CRYPTOPP_RW_USE_OMP 1 +#else +# define CRYPTOPP_RW_USE_OMP 0 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +void RWFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + seq.MessageEnd(); +} + +void RWFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + seq.MessageEnd(); +} + +Integer RWFunction::ApplyFunction(const Integer &in) const +{ + DoQuickSanityCheck(); + + Integer out = in.Squared()%m_n; + const word r = 12; + // this code was written to handle both r = 6 and r = 12, + // but now only r = 12 is used in P1363 + const word r2 = r/2; + const word r3a = (16 + 5 - r) % 16; // n%16 could be 5 or 13 + const word r3b = (16 + 13 - r) % 16; + const word r4 = (8 + 5 - r/2) % 8; // n%8 == 5 + switch (out % 16) + { + case r: + break; + case r2: + case r2+8: + out <<= 1; + break; + case r3a: + case r3b: + out.Negate(); + out += m_n; + break; + case r4: + case r4+8: + out.Negate(); + out += m_n; + out <<= 1; + break; + default: + out = Integer::Zero(); + } + return out; +} + +bool RWFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(level); + bool pass = true; + pass = pass && m_n > Integer::One() && m_n%8 == 5; + CRYPTOPP_ASSERT(pass); + return pass; +} + +bool RWFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + ; +} + +void RWFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + ; +} + +// ***************************************************************************** +// private key operations: + +// generate a random private key +void InvertibleRWFunction::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) +{ + int modulusSize = 2048; + alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); + + if (modulusSize < 16) + throw InvalidArgument("InvertibleRWFunction: specified modulus length is too small"); + + AlgorithmParameters primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize); + m_p.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("EquivalentTo", 3)("Mod", 8))); + m_q.GenerateRandom(rng, CombinedNameValuePairs(primeParam, MakeParameters("EquivalentTo", 7)("Mod", 8))); + + m_n = m_p * m_q; + m_u = m_q.InverseMod(m_p); + + Precompute(); +} + +void InvertibleRWFunction::Initialize(const Integer &n, const Integer &p, const Integer &q, const Integer &u) +{ + m_n = n; m_p = p; m_q = q; m_u = u; + + Precompute(); +} + +void InvertibleRWFunction::PrecomputeTweakedRoots() const +{ + ModularArithmetic modp(m_p), modq(m_q); + + // GCC warning bug, https://stackoverflow.com/q/12842306/608639 +#ifdef _OPENMP + #pragma omp parallel sections if(CRYPTOPP_RW_USE_OMP) + { + #pragma omp section + m_pre_2_9p = modp.Exponentiate(2, (9 * m_p - 11)/8); + #pragma omp section + m_pre_2_3q = modq.Exponentiate(2, (3 * m_q - 5)/8); + #pragma omp section + m_pre_q_p = modp.Exponentiate(m_q, m_p - 2); + } +#else + m_pre_2_9p = modp.Exponentiate(2, (9 * m_p - 11)/8); + m_pre_2_3q = modq.Exponentiate(2, (3 * m_q - 5)/8); + m_pre_q_p = modp.Exponentiate(m_q, m_p - 2); +#endif + + m_precompute = true; +} + +void InvertibleRWFunction::LoadPrecomputation(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_pre_2_9p.BERDecode(seq); + m_pre_2_3q.BERDecode(seq); + m_pre_q_p.BERDecode(seq); + seq.MessageEnd(); + + m_precompute = true; +} + +void InvertibleRWFunction::SavePrecomputation(BufferedTransformation &bt) const +{ + if(!m_precompute) + Precompute(); + + DERSequenceEncoder seq(bt); + m_pre_2_9p.DEREncode(seq); + m_pre_2_3q.DEREncode(seq); + m_pre_q_p.DEREncode(seq); + seq.MessageEnd(); +} + +void InvertibleRWFunction::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_n.BERDecode(seq); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_u.BERDecode(seq); + seq.MessageEnd(); + + m_precompute = false; +} + +void InvertibleRWFunction::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_n.DEREncode(seq); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_u.DEREncode(seq); + seq.MessageEnd(); +} + +// DJB's "RSA signatures and Rabin-Williams signatures..." (http://cr.yp.to/sigs/rwsota-20080131.pdf). +Integer InvertibleRWFunction::CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const +{ + DoQuickSanityCheck(); + + if(!m_precompute) + Precompute(); + + ModularArithmetic modn(m_n), modp(m_p), modq(m_q); + Integer r, rInv; + + do + { + // Do this in a loop for people using small numbers for testing + r.Randomize(rng, Integer::One(), m_n - Integer::One()); + // Fix for CVE-2015-2141. Thanks to Evgeny Sidorov for reporting. + // Squaring to satisfy Jacobi requirements suggested by Jean-Pierre Munch. + r = modn.Square(r); + rInv = modn.MultiplicativeInverse(r); + } while (rInv.IsZero()); + + Integer re = modn.Square(r); + re = modn.Multiply(re, x); // blind + + const Integer &h = re, &p = m_p, &q = m_q; + Integer e, f; + + const Integer U = modq.Exponentiate(h, (q+1)/8); + if(((modq.Exponentiate(U, 4) - h) % q).IsZero()) + e = Integer::One(); + else + e = -1; + + const Integer eh = e*h, V = modp.Exponentiate(eh, (p-3)/8); + if(((modp.Multiply(modp.Exponentiate(V, 4), modp.Exponentiate(eh, 2)) - eh) % p).IsZero()) + f = Integer::One(); + else + f = 2; + +#ifdef _OPENMP + Integer W, X; + #pragma omp parallel sections if(CRYPTOPP_RW_USE_OMP) + { + #pragma omp section + { + W = (f.IsUnit() ? U : modq.Multiply(m_pre_2_3q, U)); + } + #pragma omp section + { + const Integer t = modp.Multiply(modp.Exponentiate(V, 3), eh); + X = (f.IsUnit() ? t : modp.Multiply(m_pre_2_9p, t)); + } + } +#else + const Integer W = (f.IsUnit() ? U : modq.Multiply(m_pre_2_3q, U)); + const Integer t = modp.Multiply(modp.Exponentiate(V, 3), eh); + const Integer X = (f.IsUnit() ? t : modp.Multiply(m_pre_2_9p, t)); +#endif + + const Integer Y = W + q * modp.Multiply(m_pre_q_p, (X - W)); + + // Signature + Integer s = modn.Multiply(modn.Square(Y), rInv); + CRYPTOPP_ASSERT((e * f * s.Squared()) % m_n == x); + + // IEEE P1363, Section 8.2.8 IFSP-RW, p.44 + s = STDMIN(s, m_n - s); + if (ApplyFunction(s) != x) // check + throw Exception(Exception::OTHER_ERROR, "InvertibleRWFunction: computational error during private key operation"); + + return s; +} + +bool InvertibleRWFunction::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = RWFunction::Validate(rng, level); + CRYPTOPP_ASSERT(pass); + pass = pass && m_p > Integer::One() && m_p%8 == 3 && m_p < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q%8 == 7 && m_q < m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u.IsPositive() && m_u < m_p; + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && m_p * m_q == m_n; + CRYPTOPP_ASSERT(pass); + pass = pass && m_u * m_q % m_p == 1; + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool InvertibleRWFunction::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_GET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; +} + +void InvertibleRWFunction::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime1) + CRYPTOPP_SET_FUNCTION_ENTRY(Prime2) + CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1) + ; + + m_precompute = false; +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/rw.h b/extension/third_party/cryptopp/rw.h new file mode 100644 index 00000000..48aa2891 --- /dev/null +++ b/extension/third_party/cryptopp/rw.h @@ -0,0 +1,146 @@ +// rw.h - originally written and placed in the public domain by Wei Dai + +/// \file rw.h +/// \brief Classes for Rabin-Williams signature scheme +/// \details The implementation provides Rabin-Williams signature schemes as defined in +/// IEEE P1363. It uses Bernstein's tweaked square roots in place of square roots to +/// speedup calculations. +/// \sa RSA signatures and Rabin–Williams +/// signatures: the state of the art (20080131), Section 6, The tweaks e and f. +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RW_H +#define CRYPTOPP_RW_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin-Williams trapdoor function using the public key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL RWFunction : public TrapdoorFunction, public PublicKey +{ + typedef RWFunction ThisClass; + +public: + + /// \brief Initialize a Rabin-Williams public key + /// \param n the modulus + void Initialize(const Integer &n) + {m_n = n;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + void SetModulus(const Integer &n) {m_n = n;} + +protected: + Integer m_n; +}; + +/// \brief Rabin-Williams trapdoor function using the private key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL InvertibleRWFunction : public RWFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRWFunction ThisClass; + +public: + /// \brief Construct an InvertibleRWFunction + InvertibleRWFunction() : m_precompute(false) {} + + /// \brief Initialize a Rabin-Williams private key + /// \param n modulus + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &p, const Integer &q, const Integer &u); + + /// \brief Create a Rabin-Williams private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + + virtual bool SupportsPrecomputation() const {return true;} + virtual void Precompute(unsigned int unused = 0) {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + virtual void Precompute(unsigned int unused = 0) const {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation); + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const; + +protected: + void PrecomputeTweakedRoots() const; + +protected: + Integer m_p, m_q, m_u; + + mutable Integer m_pre_2_9p, m_pre_2_3q, m_pre_q_p; + mutable bool m_precompute; +}; + +/// \brief Rabin-Williams keys +/// \since Crypto++ 3.0 +struct RW +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RW";} + typedef RWFunction PublicKey; + typedef InvertibleRWFunction PrivateKey; +}; + +/// \brief Rabin-Williams signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \since Crypto++ 3.0 +template +struct RWSS : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/safer.cpp b/extension/third_party/cryptopp/safer.cpp new file mode 100644 index 00000000..83f41517 --- /dev/null +++ b/extension/third_party/cryptopp/safer.cpp @@ -0,0 +1,157 @@ +// safer.cpp - modified by by Wei Dai from Richard De Moliner's safer.c + +#include "pch.h" +#include "safer.h" +#include "misc.h" +#include "argnames.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +const byte SAFER::Base::exp_tab[256] = + {1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, + 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, + 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, + 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, + 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, + 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, + 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, + 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, + 0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, + 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, + 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, + 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, + 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, + 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, + 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, + 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40}; + +const byte SAFER::Base::log_tab[256] = + {128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248, + 192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130, + 112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37, + 201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15, + 32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198, + 175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84, + 121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188, + 189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217, + 208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158, + 210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42, + 95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219, + 164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29, + 41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14, + 122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104, + 109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66, + 184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48}; + +#define EXP(x) exp_tab[(x)] +#define LOG(x) log_tab[(x)] +#define PHT(x, y) { y += x; x += y; } +#define IPHT(x, y) { x -= y; y -= x; } + +static const unsigned int BLOCKSIZE = 8; +static const unsigned int MAX_ROUNDS = 13; + +void SAFER::Base::UncheckedSetKey(const byte *userkey_1, unsigned int length, const NameValuePairs ¶ms) +{ + bool strengthened = Strengthened(); + unsigned int nof_rounds = params.GetIntValueWithDefault(Name::Rounds(), length == 8 ? (strengthened ? 8 : 6) : 10); + + const byte *userkey_2 = length == 8 ? userkey_1 : userkey_1 + 8; + keySchedule.New(1 + BLOCKSIZE * (1 + 2 * nof_rounds)); + + unsigned int i, j; + byte *key = keySchedule; + SecByteBlock ka(BLOCKSIZE + 1), kb(BLOCKSIZE + 1); + + if (MAX_ROUNDS < nof_rounds) + nof_rounds = MAX_ROUNDS; + *key++ = (unsigned char)nof_rounds; + ka[BLOCKSIZE] = 0; + kb[BLOCKSIZE] = 0; + for (j = 0; j < BLOCKSIZE; j++) + { + ka[BLOCKSIZE] ^= ka[j] = rotlConstant<5>(userkey_1[j]); + kb[BLOCKSIZE] ^= kb[j] = *key++ = userkey_2[j]; + } + + for (i = 1; i <= nof_rounds; i++) + { + for (j = 0; j < BLOCKSIZE + 1; j++) + { + ka[j] = rotlConstant<6>(ka[j]); + kb[j] = rotlConstant<6>(kb[j]); + } + for (j = 0; j < BLOCKSIZE; j++) + if (strengthened) + *key++ = (ka[(j + 2 * i - 1) % (BLOCKSIZE + 1)] + + exp_tab[exp_tab[18 * i + j + 1]]) & 0xFF; + else + *key++ = (ka[j] + exp_tab[exp_tab[18 * i + j + 1]]) & 0xFF; + for (j = 0; j < BLOCKSIZE; j++) + if (strengthened) + *key++ = (kb[(j + 2 * i) % (BLOCKSIZE + 1)] + + exp_tab[exp_tab[18 * i + j + 10]]) & 0xFF; + else + *key++ = (kb[j] + exp_tab[exp_tab[18 * i + j + 10]]) & 0xFF; + } +} + +typedef BlockGetAndPut Block; + +void SAFER::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + byte a, b, c, d, e, f, g, h, t; + const byte *key = keySchedule+1; + unsigned int round = keySchedule[0]; + + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + while(round--) + { + a ^= key[0]; b += key[1]; c += key[2]; d ^= key[3]; + e ^= key[4]; f += key[5]; g += key[6]; h ^= key[7]; + a = EXP(a) + key[ 8]; b = LOG(b) ^ key[ 9]; + c = LOG(c) ^ key[10]; d = EXP(d) + key[11]; + e = EXP(e) + key[12]; f = LOG(f) ^ key[13]; + g = LOG(g) ^ key[14]; h = EXP(h) + key[15]; + key += 16; + PHT(a, b); PHT(c, d); PHT(e, f); PHT(g, h); + PHT(a, c); PHT(e, g); PHT(b, d); PHT(f, h); + PHT(a, e); PHT(b, f); PHT(c, g); PHT(d, h); + t = b; b = e; e = c; c = t; t = d; d = f; f = g; g = t; + } + a ^= key[0]; b += key[1]; c += key[2]; d ^= key[3]; + e ^= key[4]; f += key[5]; g += key[6]; h ^= key[7]; + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +void SAFER::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + byte a, b, c, d, e, f, g, h, t; + unsigned int round = keySchedule[0]; + const byte *key = keySchedule + BLOCKSIZE * (1 + 2 * round) - 7; + + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + h ^= key[7]; g -= key[6]; f -= key[5]; e ^= key[4]; + d ^= key[3]; c -= key[2]; b -= key[1]; a ^= key[0]; + while (round--) + { + key -= 16; + t = e; e = b; b = c; c = t; t = f; f = d; d = g; g = t; + IPHT(a, e); IPHT(b, f); IPHT(c, g); IPHT(d, h); + IPHT(a, c); IPHT(e, g); IPHT(b, d); IPHT(f, h); + IPHT(a, b); IPHT(c, d); IPHT(e, f); IPHT(g, h); + h -= key[15]; g ^= key[14]; f ^= key[13]; e -= key[12]; + d -= key[11]; c ^= key[10]; b ^= key[9]; a -= key[8]; + h = LOG(h) ^ key[7]; g = EXP(g) - key[6]; + f = EXP(f) - key[5]; e = LOG(e) ^ key[4]; + d = LOG(d) ^ key[3]; c = EXP(c) - key[2]; + b = EXP(b) - key[1]; a = LOG(a) ^ key[0]; + } + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/safer.h b/extension/third_party/cryptopp/safer.h new file mode 100644 index 00000000..b28ad82c --- /dev/null +++ b/extension/third_party/cryptopp/safer.h @@ -0,0 +1,98 @@ +// safer.h - originally written and placed in the public domain by Wei Dai + +/// \file safer.h +/// \brief Classes for the SAFER and SAFER-K block ciphers + +#ifndef CRYPTOPP_SAFER_H +#define CRYPTOPP_SAFER_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SAFER block cipher +class SAFER +{ +public: + /// \brief SAFER block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipher + { + public: + unsigned int OptimalDataAlignment() const {return 1;} + void UncheckedSetKey(const byte *userkey, unsigned int length, const NameValuePairs ¶ms); + + protected: + virtual bool Strengthened() const =0; + + SecByteBlock keySchedule; + static const byte exp_tab[256]; + static const byte log_tab[256]; + }; + + /// \brief SAFER block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SAFER block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; +}; + +/// \brief SAFER block cipher default implementation +/// \tparam BASE SAFER::Enc or SAFER::Dec derived base class +/// \tparam INFO SAFER_Info derived class +/// \tparam STR flag indicating a strengthened implementation +/// \details SAFER-K is not strengthened; while SAFER-SK is strengthened. +template +class CRYPTOPP_NO_VTABLE SAFER_Impl : public BlockCipherImpl +{ +protected: + bool Strengthened() const {return STR;} +}; + +/// \brief SAFER-K block cipher information +struct SAFER_K_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-K";} +}; + +/// \brief SAFER-K block cipher +/// \sa SAFER-K +class SAFER_K : public SAFER_K_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +/// \brief SAFER-SK block cipher information +struct SAFER_SK_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-SK";} +}; + +/// \brief SAFER-SK block cipher +/// \sa SAFER-SK +class SAFER_SK : public SAFER_SK_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +typedef SAFER_K::Encryption SAFER_K_Encryption; +typedef SAFER_K::Decryption SAFER_K_Decryption; + +typedef SAFER_SK::Encryption SAFER_SK_Encryption; +typedef SAFER_SK::Decryption SAFER_SK_Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/salsa.cpp b/extension/third_party/cryptopp/salsa.cpp new file mode 100644 index 00000000..987cd302 --- /dev/null +++ b/extension/third_party/cryptopp/salsa.cpp @@ -0,0 +1,759 @@ +// salsa.cpp - originally written and placed in the public domain by Wei Dai + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM salsa.cpp" to generate MASM code + +#include "pch.h" +#include "config.h" + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#include "salsa.h" +#include "argnames.h" +#include "misc.h" +#include "cpu.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702 4740) +#endif + +// Clang due to "Inline assembly operands don't work with .intel_syntax" +// https://llvm.org/bugs/show_bug.cgi?id=24232 +#if defined(CRYPTOPP_DISABLE_SALSA_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +# undef CRYPTOPP_SSSE3_ASM_AVAILABLE +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +// Can't use GetAlignmentOf() because of C++11 and constexpr +// Can use 'const unsigned int' because of MSVC 2013 +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# define ALIGN_SPEC 16 +#else +# define ALIGN_SPEC 4 +#endif + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void Salsa20_TestInstantiations() +{ + Salsa20::Encryption x1; + XSalsa20::Encryption x2; +} +#endif + +void Salsa20_Core(word32* data, unsigned int rounds) +{ + CRYPTOPP_ASSERT(data != NULLPTR); + CRYPTOPP_ASSERT(rounds % 2 == 0); + + CRYPTOPP_ALIGN_DATA(ALIGN_SPEC) word32 x[16]; + + for (size_t i = 0; i < 16; ++i) + x[i] = data[i]; + + // Rounds must be even + for (size_t i = 0; i < rounds; i += 2) + { + x[ 4] ^= rotlConstant< 7>(x[ 0]+x[12]); + x[ 8] ^= rotlConstant< 9>(x[ 4]+x[ 0]); + x[12] ^= rotlConstant<13>(x[ 8]+x[ 4]); + x[ 0] ^= rotlConstant<18>(x[12]+x[ 8]); + + x[ 9] ^= rotlConstant< 7>(x[ 5]+x[ 1]); + x[13] ^= rotlConstant< 9>(x[ 9]+x[ 5]); + x[ 1] ^= rotlConstant<13>(x[13]+x[ 9]); + x[ 5] ^= rotlConstant<18>(x[ 1]+x[13]); + + x[14] ^= rotlConstant< 7>(x[10]+x[ 6]); + x[ 2] ^= rotlConstant< 9>(x[14]+x[10]); + x[ 6] ^= rotlConstant<13>(x[ 2]+x[14]); + x[10] ^= rotlConstant<18>(x[ 6]+x[ 2]); + + x[ 3] ^= rotlConstant< 7>(x[15]+x[11]); + x[ 7] ^= rotlConstant< 9>(x[ 3]+x[15]); + x[11] ^= rotlConstant<13>(x[ 7]+x[ 3]); + x[15] ^= rotlConstant<18>(x[11]+x[ 7]); + + x[ 1] ^= rotlConstant< 7>(x[ 0]+x[ 3]); + x[ 2] ^= rotlConstant< 9>(x[ 1]+x[ 0]); + x[ 3] ^= rotlConstant<13>(x[ 2]+x[ 1]); + x[ 0] ^= rotlConstant<18>(x[ 3]+x[ 2]); + + x[ 6] ^= rotlConstant< 7>(x[ 5]+x[ 4]); + x[ 7] ^= rotlConstant< 9>(x[ 6]+x[ 5]); + x[ 4] ^= rotlConstant<13>(x[ 7]+x[ 6]); + x[ 5] ^= rotlConstant<18>(x[ 4]+x[ 7]); + + x[11] ^= rotlConstant< 7>(x[10]+x[ 9]); + x[ 8] ^= rotlConstant< 9>(x[11]+x[10]); + x[ 9] ^= rotlConstant<13>(x[ 8]+x[11]); + x[10] ^= rotlConstant<18>(x[ 9]+x[ 8]); + + x[12] ^= rotlConstant< 7>(x[15]+x[14]); + x[13] ^= rotlConstant< 9>(x[12]+x[15]); + x[14] ^= rotlConstant<13>(x[13]+x[12]); + x[15] ^= rotlConstant<18>(x[14]+x[13]); + } + +// OpenMP 4.0 released July 2013. +#if _OPENMP >= 201307 + #pragma omp simd + for (size_t i = 0; i < 16; ++i) + data[i] += x[i]; +#else + for (size_t i = 0; i < 16; ++i) + data[i] += x[i]; +#endif +} + +std::string Salsa20_Policy::AlgorithmProvider() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_SALSA_ASM) + if (HasSSE2()) + return "SSE2"; +#endif + return "C++"; +} + +void Salsa20_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + // Use previous rounds as the default value + int rounds = params.GetIntValueWithDefault(Name::Rounds(), m_rounds); + if (rounds != 20 && rounds != 12 && rounds != 8) + throw InvalidRounds(Salsa20::StaticAlgorithmName(), rounds); + + // Latch a good value + m_rounds = rounds; + + // m_state is reordered for SSE2 + GetBlock get1(key); + get1(m_state[13])(m_state[10])(m_state[7])(m_state[4]); + GetBlock get2(key + length - 16); + get2(m_state[15])(m_state[12])(m_state[9])(m_state[6]); + + // "expand 16-byte k" or "expand 32-byte k" + m_state[0] = 0x61707865; + m_state[1] = (length == 16) ? 0x3120646e : 0x3320646e; + m_state[2] = (length == 16) ? 0x79622d36 : 0x79622d32; + m_state[3] = 0x6b206574; +} + +void Salsa20_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==8); + + GetBlock get(IV); + get(m_state[14])(m_state[11]); + m_state[8] = m_state[5] = 0; +} + +void Salsa20_Policy::SeekToIteration(lword iterationCount) +{ + m_state[8] = (word32)iterationCount; + m_state[5] = (word32)SafeRightShift<32>(iterationCount); +} + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +unsigned int Salsa20_Policy::GetAlignment() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return 16; + else +#endif + return GetAlignmentOf(); +} + +unsigned int Salsa20_Policy::GetOptimalBlockSize() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return 4*BYTES_PER_ITERATION; + else +#endif + return BYTES_PER_ITERATION; +} +#endif + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void Salsa20_OperateKeystream(byte *output, const byte *input, size_t iterationCount, int rounds, void *state); +} +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code +#endif + +void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ +#endif // #ifdef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE + Salsa20_OperateKeystream(output, input, iterationCount, m_rounds, m_state.data()); + return; +#endif + +#if CRYPTOPP_SSE2_ASM_AVAILABLE +#ifdef CRYPTOPP_GENERATE_X64_MASM + ALIGN 8 + Salsa20_OperateKeystream PROC FRAME + mov r10, [rsp + 5*8] ; state + alloc_stack(10*16 + 32*16 + 8) + save_xmm128 xmm6, 0200h + save_xmm128 xmm7, 0210h + save_xmm128 xmm8, 0220h + save_xmm128 xmm9, 0230h + save_xmm128 xmm10, 0240h + save_xmm128 xmm11, 0250h + save_xmm128 xmm12, 0260h + save_xmm128 xmm13, 0270h + save_xmm128 xmm14, 0280h + save_xmm128 xmm15, 0290h + .endprolog + + #define REG_output rcx + #define REG_input rdx + #define REG_iterationCount r8 + #define REG_state r10 + #define REG_rounds e9d + #define REG_roundsLeft eax + #define REG_temp32 r11d + #define REG_temp r11 + #define SSE2_WORKSPACE rsp +#else + if (HasSSE2()) + { + #if CRYPTOPP_BOOL_X64 + #define REG_output %1 + #define REG_input %0 + #define REG_iterationCount %2 + #define REG_state %4 /* constant */ + #define REG_rounds %3 /* constant */ + #define REG_roundsLeft eax + #define REG_temp32 edx + #define REG_temp rdx + #define SSE2_WORKSPACE %5 /* constant */ + + CRYPTOPP_ALIGN_DATA(16) byte workspace[16*32]; + #else + #define REG_output edi + #define REG_input eax + #define REG_iterationCount ecx + #define REG_state esi + #define REG_rounds edx + #define REG_roundsLeft ebx + #define REG_temp32 ebp + #define REG_temp ebp + #define SSE2_WORKSPACE esp + WORD_SZ + #endif + + #ifdef __GNUC__ + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86( bx) + #else + void *s = m_state.data(); + word32 r = m_rounds; + + AS2( mov REG_iterationCount, iterationCount) + AS2( mov REG_input, input) + AS2( mov REG_output, output) + AS2( mov REG_state, s) + AS2( mov REG_rounds, r) + #endif +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM + + AS_PUSH_IF86( bp) + AS2( cmp REG_iterationCount, 4) + ASJ( jl, 5, f) + +#if CRYPTOPP_BOOL_X86 + AS2( mov ebx, esp) + AS2( and esp, -16) + AS2( sub esp, 32*16) + AS1( push ebx) +#endif + +#define SSE2_EXPAND_S(i, j) \ + ASS( pshufd xmm4, xmm##i, j, j, j, j) \ + AS2( movdqa [SSE2_WORKSPACE + (i*4+j)*16 + 256], xmm4) + + AS2( movdqa xmm0, [REG_state + 0*16]) + AS2( movdqa xmm1, [REG_state + 1*16]) + AS2( movdqa xmm2, [REG_state + 2*16]) + AS2( movdqa xmm3, [REG_state + 3*16]) + SSE2_EXPAND_S(0, 0) + SSE2_EXPAND_S(0, 1) + SSE2_EXPAND_S(0, 2) + SSE2_EXPAND_S(0, 3) + SSE2_EXPAND_S(1, 0) + SSE2_EXPAND_S(1, 2) + SSE2_EXPAND_S(1, 3) + SSE2_EXPAND_S(2, 1) + SSE2_EXPAND_S(2, 2) + SSE2_EXPAND_S(2, 3) + SSE2_EXPAND_S(3, 0) + SSE2_EXPAND_S(3, 1) + SSE2_EXPAND_S(3, 2) + SSE2_EXPAND_S(3, 3) + +#define SSE2_EXPAND_S85(i) \ + AS2( mov dword ptr [SSE2_WORKSPACE + 8*16 + i*4 + 256], REG_roundsLeft) \ + AS2( mov dword ptr [SSE2_WORKSPACE + 5*16 + i*4 + 256], REG_temp32) \ + AS2( add REG_roundsLeft, 1) \ + AS2( adc REG_temp32, 0) + + ASL(1) + AS2( mov REG_roundsLeft, dword ptr [REG_state + 8*4]) + AS2( mov REG_temp32, dword ptr [REG_state + 5*4]) + SSE2_EXPAND_S85(0) + SSE2_EXPAND_S85(1) + SSE2_EXPAND_S85(2) + SSE2_EXPAND_S85(3) + AS2( mov dword ptr [REG_state + 8*4], REG_roundsLeft) + AS2( mov dword ptr [REG_state + 5*4], REG_temp32) + +#ifdef __XOP__ +#define SSE2_QUARTER_ROUND(a, b, d, i) \ + AS2( movdqa xmm4, xmm##d) \ + AS2( paddd xmm4, xmm##a) \ + AS3( vprotd xmm4, xmm4, i) \ + AS2( pxor xmm##b, xmm4) +#else +#define SSE2_QUARTER_ROUND(a, b, d, i) \ + AS2( movdqa xmm4, xmm##d) \ + AS2( paddd xmm4, xmm##a) \ + AS2( movdqa xmm5, xmm4) \ + AS2( pslld xmm4, i) \ + AS2( psrld xmm5, 32-i) \ + AS2( pxor xmm##b, xmm4) \ + AS2( pxor xmm##b, xmm5) +#endif + +#define L01(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##A, [SSE2_WORKSPACE + d*16 + i*256]) /* y3 */ +#define L02(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##C, [SSE2_WORKSPACE + a*16 + i*256]) /* y0 */ +#define L03(A,B,C,D,a,b,c,d,i) AS2( paddd xmm##A, xmm##C) /* y0+y3 */ + +#ifdef __XOP__ +#define L04(A,B,C,D,a,b,c,d,i) +#define L05(A,B,C,D,a,b,c,d,i) AS3( vprotd xmm##A, xmm##A, 7) +#define L06(A,B,C,D,a,b,c,d,i) +#define L07(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + b*16 + i*256]) +#define L08(A,B,C,D,a,b,c,d,i) +#else +#define L04(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##B, xmm##A) +#define L05(A,B,C,D,a,b,c,d,i) AS2( pslld xmm##A, 7) +#define L06(A,B,C,D,a,b,c,d,i) AS2( psrld xmm##B, 32-7) +#define L07(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + b*16 + i*256]) +#define L08(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##B) /* z1 */ +#endif + +#define L09(A,B,C,D,a,b,c,d,i) AS2( movdqa [SSE2_WORKSPACE + b*16], xmm##A) +#define L10(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##B, xmm##A) +#define L11(A,B,C,D,a,b,c,d,i) AS2( paddd xmm##A, xmm##C) /* z1+y0 */ + +#ifdef __XOP__ +#define L12(A,B,C,D,a,b,c,d,i) +#define L13(A,B,C,D,a,b,c,d,i) AS3( vprotd xmm##A, xmm##A, 9) +#define L14(A,B,C,D,a,b,c,d,i) +#define L15(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + c*16 + i*256]) +#define L16(A,B,C,D,a,b,c,d,i) +#else +#define L12(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##D, xmm##A) +#define L13(A,B,C,D,a,b,c,d,i) AS2( pslld xmm##A, 9) +#define L14(A,B,C,D,a,b,c,d,i) AS2( psrld xmm##D, 32-9) +#define L15(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + c*16 + i*256]) +#define L16(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##D) /* z2 */ +#endif + +#define L17(A,B,C,D,a,b,c,d,i) AS2( movdqa [SSE2_WORKSPACE + c*16], xmm##A) +#define L18(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##D, xmm##A) +#define L19(A,B,C,D,a,b,c,d,i) AS2( paddd xmm##A, xmm##B) /* z2+z1 */ + +#ifdef __XOP__ +#define L20(A,B,C,D,a,b,c,d,i) +#define L21(A,B,C,D,a,b,c,d,i) AS3( vprotd xmm##A, xmm##A, 13) +#define L22(A,B,C,D,a,b,c,d,i) +#define L23(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + d*16 + i*256]) +#define L24(A,B,C,D,a,b,c,d,i) +#else +#define L20(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##B, xmm##A) +#define L21(A,B,C,D,a,b,c,d,i) AS2( pslld xmm##A, 13) +#define L22(A,B,C,D,a,b,c,d,i) AS2( psrld xmm##B, 32-13) +#define L23(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, [SSE2_WORKSPACE + d*16 + i*256]) +#define L24(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##B) /* z3 */ +#endif + +#define L25(A,B,C,D,a,b,c,d,i) AS2( movdqa [SSE2_WORKSPACE + d*16], xmm##A) +#define L26(A,B,C,D,a,b,c,d,i) AS2( paddd xmm##A, xmm##D) /* z3+z2 */ + +#ifdef __XOP__ +#define L27(A,B,C,D,a,b,c,d,i) +#define L28(A,B,C,D,a,b,c,d,i) AS3( vprotd xmm##A, xmm##A, 18) +#define L29(A,B,C,D,a,b,c,d,i) +#define L30(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##C) /* xor y0 */ +#define L31(A,B,C,D,a,b,c,d,i) +#else +#define L27(A,B,C,D,a,b,c,d,i) AS2( movdqa xmm##D, xmm##A) +#define L28(A,B,C,D,a,b,c,d,i) AS2( pslld xmm##A, 18) +#define L29(A,B,C,D,a,b,c,d,i) AS2( psrld xmm##D, 32-18) +#define L30(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##C) /* xor y0 */ +#define L31(A,B,C,D,a,b,c,d,i) AS2( pxor xmm##A, xmm##D) /* z0 */ +#endif + +#define L32(A,B,C,D,a,b,c,d,i) AS2( movdqa [SSE2_WORKSPACE + a*16], xmm##A) + +#define SSE2_QUARTER_ROUND_X8(i, a, b, c, d, e, f, g, h) \ + L01(0,1,2,3, a,b,c,d, i) L01(4,5,6,7, e,f,g,h, i) \ + L02(0,1,2,3, a,b,c,d, i) L02(4,5,6,7, e,f,g,h, i) \ + L03(0,1,2,3, a,b,c,d, i) L03(4,5,6,7, e,f,g,h, i) \ + L04(0,1,2,3, a,b,c,d, i) L04(4,5,6,7, e,f,g,h, i) \ + L05(0,1,2,3, a,b,c,d, i) L05(4,5,6,7, e,f,g,h, i) \ + L06(0,1,2,3, a,b,c,d, i) L06(4,5,6,7, e,f,g,h, i) \ + L07(0,1,2,3, a,b,c,d, i) L07(4,5,6,7, e,f,g,h, i) \ + L08(0,1,2,3, a,b,c,d, i) L08(4,5,6,7, e,f,g,h, i) \ + L09(0,1,2,3, a,b,c,d, i) L09(4,5,6,7, e,f,g,h, i) \ + L10(0,1,2,3, a,b,c,d, i) L10(4,5,6,7, e,f,g,h, i) \ + L11(0,1,2,3, a,b,c,d, i) L11(4,5,6,7, e,f,g,h, i) \ + L12(0,1,2,3, a,b,c,d, i) L12(4,5,6,7, e,f,g,h, i) \ + L13(0,1,2,3, a,b,c,d, i) L13(4,5,6,7, e,f,g,h, i) \ + L14(0,1,2,3, a,b,c,d, i) L14(4,5,6,7, e,f,g,h, i) \ + L15(0,1,2,3, a,b,c,d, i) L15(4,5,6,7, e,f,g,h, i) \ + L16(0,1,2,3, a,b,c,d, i) L16(4,5,6,7, e,f,g,h, i) \ + L17(0,1,2,3, a,b,c,d, i) L17(4,5,6,7, e,f,g,h, i) \ + L18(0,1,2,3, a,b,c,d, i) L18(4,5,6,7, e,f,g,h, i) \ + L19(0,1,2,3, a,b,c,d, i) L19(4,5,6,7, e,f,g,h, i) \ + L20(0,1,2,3, a,b,c,d, i) L20(4,5,6,7, e,f,g,h, i) \ + L21(0,1,2,3, a,b,c,d, i) L21(4,5,6,7, e,f,g,h, i) \ + L22(0,1,2,3, a,b,c,d, i) L22(4,5,6,7, e,f,g,h, i) \ + L23(0,1,2,3, a,b,c,d, i) L23(4,5,6,7, e,f,g,h, i) \ + L24(0,1,2,3, a,b,c,d, i) L24(4,5,6,7, e,f,g,h, i) \ + L25(0,1,2,3, a,b,c,d, i) L25(4,5,6,7, e,f,g,h, i) \ + L26(0,1,2,3, a,b,c,d, i) L26(4,5,6,7, e,f,g,h, i) \ + L27(0,1,2,3, a,b,c,d, i) L27(4,5,6,7, e,f,g,h, i) \ + L28(0,1,2,3, a,b,c,d, i) L28(4,5,6,7, e,f,g,h, i) \ + L29(0,1,2,3, a,b,c,d, i) L29(4,5,6,7, e,f,g,h, i) \ + L30(0,1,2,3, a,b,c,d, i) L30(4,5,6,7, e,f,g,h, i) \ + L31(0,1,2,3, a,b,c,d, i) L31(4,5,6,7, e,f,g,h, i) \ + L32(0,1,2,3, a,b,c,d, i) L32(4,5,6,7, e,f,g,h, i) + +#define SSE2_QUARTER_ROUND_X16(i, a, b, c, d, e, f, g, h, A, B, C, D, E, F, G, H) \ + L01(0,1,2,3, a,b,c,d, i) L01(4,5,6,7, e,f,g,h, i) L01(8,9,10,11, A,B,C,D, i) L01(12,13,14,15, E,F,G,H, i) \ + L02(0,1,2,3, a,b,c,d, i) L02(4,5,6,7, e,f,g,h, i) L02(8,9,10,11, A,B,C,D, i) L02(12,13,14,15, E,F,G,H, i) \ + L03(0,1,2,3, a,b,c,d, i) L03(4,5,6,7, e,f,g,h, i) L03(8,9,10,11, A,B,C,D, i) L03(12,13,14,15, E,F,G,H, i) \ + L04(0,1,2,3, a,b,c,d, i) L04(4,5,6,7, e,f,g,h, i) L04(8,9,10,11, A,B,C,D, i) L04(12,13,14,15, E,F,G,H, i) \ + L05(0,1,2,3, a,b,c,d, i) L05(4,5,6,7, e,f,g,h, i) L05(8,9,10,11, A,B,C,D, i) L05(12,13,14,15, E,F,G,H, i) \ + L06(0,1,2,3, a,b,c,d, i) L06(4,5,6,7, e,f,g,h, i) L06(8,9,10,11, A,B,C,D, i) L06(12,13,14,15, E,F,G,H, i) \ + L07(0,1,2,3, a,b,c,d, i) L07(4,5,6,7, e,f,g,h, i) L07(8,9,10,11, A,B,C,D, i) L07(12,13,14,15, E,F,G,H, i) \ + L08(0,1,2,3, a,b,c,d, i) L08(4,5,6,7, e,f,g,h, i) L08(8,9,10,11, A,B,C,D, i) L08(12,13,14,15, E,F,G,H, i) \ + L09(0,1,2,3, a,b,c,d, i) L09(4,5,6,7, e,f,g,h, i) L09(8,9,10,11, A,B,C,D, i) L09(12,13,14,15, E,F,G,H, i) \ + L10(0,1,2,3, a,b,c,d, i) L10(4,5,6,7, e,f,g,h, i) L10(8,9,10,11, A,B,C,D, i) L10(12,13,14,15, E,F,G,H, i) \ + L11(0,1,2,3, a,b,c,d, i) L11(4,5,6,7, e,f,g,h, i) L11(8,9,10,11, A,B,C,D, i) L11(12,13,14,15, E,F,G,H, i) \ + L12(0,1,2,3, a,b,c,d, i) L12(4,5,6,7, e,f,g,h, i) L12(8,9,10,11, A,B,C,D, i) L12(12,13,14,15, E,F,G,H, i) \ + L13(0,1,2,3, a,b,c,d, i) L13(4,5,6,7, e,f,g,h, i) L13(8,9,10,11, A,B,C,D, i) L13(12,13,14,15, E,F,G,H, i) \ + L14(0,1,2,3, a,b,c,d, i) L14(4,5,6,7, e,f,g,h, i) L14(8,9,10,11, A,B,C,D, i) L14(12,13,14,15, E,F,G,H, i) \ + L15(0,1,2,3, a,b,c,d, i) L15(4,5,6,7, e,f,g,h, i) L15(8,9,10,11, A,B,C,D, i) L15(12,13,14,15, E,F,G,H, i) \ + L16(0,1,2,3, a,b,c,d, i) L16(4,5,6,7, e,f,g,h, i) L16(8,9,10,11, A,B,C,D, i) L16(12,13,14,15, E,F,G,H, i) \ + L17(0,1,2,3, a,b,c,d, i) L17(4,5,6,7, e,f,g,h, i) L17(8,9,10,11, A,B,C,D, i) L17(12,13,14,15, E,F,G,H, i) \ + L18(0,1,2,3, a,b,c,d, i) L18(4,5,6,7, e,f,g,h, i) L18(8,9,10,11, A,B,C,D, i) L18(12,13,14,15, E,F,G,H, i) \ + L19(0,1,2,3, a,b,c,d, i) L19(4,5,6,7, e,f,g,h, i) L19(8,9,10,11, A,B,C,D, i) L19(12,13,14,15, E,F,G,H, i) \ + L20(0,1,2,3, a,b,c,d, i) L20(4,5,6,7, e,f,g,h, i) L20(8,9,10,11, A,B,C,D, i) L20(12,13,14,15, E,F,G,H, i) \ + L21(0,1,2,3, a,b,c,d, i) L21(4,5,6,7, e,f,g,h, i) L21(8,9,10,11, A,B,C,D, i) L21(12,13,14,15, E,F,G,H, i) \ + L22(0,1,2,3, a,b,c,d, i) L22(4,5,6,7, e,f,g,h, i) L22(8,9,10,11, A,B,C,D, i) L22(12,13,14,15, E,F,G,H, i) \ + L23(0,1,2,3, a,b,c,d, i) L23(4,5,6,7, e,f,g,h, i) L23(8,9,10,11, A,B,C,D, i) L23(12,13,14,15, E,F,G,H, i) \ + L24(0,1,2,3, a,b,c,d, i) L24(4,5,6,7, e,f,g,h, i) L24(8,9,10,11, A,B,C,D, i) L24(12,13,14,15, E,F,G,H, i) \ + L25(0,1,2,3, a,b,c,d, i) L25(4,5,6,7, e,f,g,h, i) L25(8,9,10,11, A,B,C,D, i) L25(12,13,14,15, E,F,G,H, i) \ + L26(0,1,2,3, a,b,c,d, i) L26(4,5,6,7, e,f,g,h, i) L26(8,9,10,11, A,B,C,D, i) L26(12,13,14,15, E,F,G,H, i) \ + L27(0,1,2,3, a,b,c,d, i) L27(4,5,6,7, e,f,g,h, i) L27(8,9,10,11, A,B,C,D, i) L27(12,13,14,15, E,F,G,H, i) \ + L28(0,1,2,3, a,b,c,d, i) L28(4,5,6,7, e,f,g,h, i) L28(8,9,10,11, A,B,C,D, i) L28(12,13,14,15, E,F,G,H, i) \ + L29(0,1,2,3, a,b,c,d, i) L29(4,5,6,7, e,f,g,h, i) L29(8,9,10,11, A,B,C,D, i) L29(12,13,14,15, E,F,G,H, i) \ + L30(0,1,2,3, a,b,c,d, i) L30(4,5,6,7, e,f,g,h, i) L30(8,9,10,11, A,B,C,D, i) L30(12,13,14,15, E,F,G,H, i) \ + L31(0,1,2,3, a,b,c,d, i) L31(4,5,6,7, e,f,g,h, i) L31(8,9,10,11, A,B,C,D, i) L31(12,13,14,15, E,F,G,H, i) \ + L32(0,1,2,3, a,b,c,d, i) L32(4,5,6,7, e,f,g,h, i) L32(8,9,10,11, A,B,C,D, i) L32(12,13,14,15, E,F,G,H, i) + +#if CRYPTOPP_BOOL_X64 + SSE2_QUARTER_ROUND_X16(1, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15) +#else + SSE2_QUARTER_ROUND_X8(1, 2, 6, 10, 14, 3, 7, 11, 15) + SSE2_QUARTER_ROUND_X8(1, 0, 4, 8, 12, 1, 5, 9, 13) +#endif + AS2( mov REG_roundsLeft, REG_rounds) + ASJ( jmp, 2, f) + + ASL(SSE2_Salsa_Output) + AS2( movdqa xmm0, xmm4) + AS2( punpckldq xmm4, xmm5) + AS2( movdqa xmm1, xmm6) + AS2( punpckldq xmm6, xmm7) + AS2( movdqa xmm2, xmm4) + AS2( punpcklqdq xmm4, xmm6) // e + AS2( punpckhqdq xmm2, xmm6) // f + AS2( punpckhdq xmm0, xmm5) + AS2( punpckhdq xmm1, xmm7) + AS2( movdqa xmm6, xmm0) + AS2( punpcklqdq xmm0, xmm1) // g + AS2( punpckhqdq xmm6, xmm1) // h + AS_XMM_OUTPUT4(SSE2_Salsa_Output_A, REG_input, REG_output, 4, 2, 0, 6, 1, 0, 4, 8, 12, 1) + AS1( ret) + + ASL(6) +#if CRYPTOPP_BOOL_X64 + SSE2_QUARTER_ROUND_X16(0, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15) + ASL(2) + SSE2_QUARTER_ROUND_X16(0, 0, 13, 10, 7, 1, 14, 11, 4, 2, 15, 8, 5, 3, 12, 9, 6) +#else + SSE2_QUARTER_ROUND_X8(0, 2, 6, 10, 14, 3, 7, 11, 15) + SSE2_QUARTER_ROUND_X8(0, 0, 4, 8, 12, 1, 5, 9, 13) + ASL(2) + SSE2_QUARTER_ROUND_X8(0, 2, 15, 8, 5, 3, 12, 9, 6) + SSE2_QUARTER_ROUND_X8(0, 0, 13, 10, 7, 1, 14, 11, 4) +#endif + AS2( sub REG_roundsLeft, 2) + ASJ( jnz, 6, b) + +#define SSE2_OUTPUT_4(a, b, c, d) \ + AS2( movdqa xmm4, [SSE2_WORKSPACE + a*16 + 256])\ + AS2( paddd xmm4, [SSE2_WORKSPACE + a*16])\ + AS2( movdqa xmm5, [SSE2_WORKSPACE + b*16 + 256])\ + AS2( paddd xmm5, [SSE2_WORKSPACE + b*16])\ + AS2( movdqa xmm6, [SSE2_WORKSPACE + c*16 + 256])\ + AS2( paddd xmm6, [SSE2_WORKSPACE + c*16])\ + AS2( movdqa xmm7, [SSE2_WORKSPACE + d*16 + 256])\ + AS2( paddd xmm7, [SSE2_WORKSPACE + d*16])\ + ASC( call, SSE2_Salsa_Output) + + SSE2_OUTPUT_4(0, 13, 10, 7) + SSE2_OUTPUT_4(4, 1, 14, 11) + SSE2_OUTPUT_4(8, 5, 2, 15) + SSE2_OUTPUT_4(12, 9, 6, 3) + AS2( test REG_input, REG_input) + ASJ( jz, 9, f) + AS2( add REG_input, 12*16) + ASL(9) + AS2( add REG_output, 12*16) + AS2( sub REG_iterationCount, 4) + AS2( cmp REG_iterationCount, 4) + ASJ( jge, 1, b) + AS_POP_IF86( sp) + + ASL(5) + AS2( sub REG_iterationCount, 1) + ASJ( jl, 4, f) + AS2( movdqa xmm0, [REG_state + 0*16]) + AS2( movdqa xmm1, [REG_state + 1*16]) + AS2( movdqa xmm2, [REG_state + 2*16]) + AS2( movdqa xmm3, [REG_state + 3*16]) + AS2( mov REG_roundsLeft, REG_rounds) + + ASL(0) + SSE2_QUARTER_ROUND(0, 1, 3, 7) + SSE2_QUARTER_ROUND(1, 2, 0, 9) + SSE2_QUARTER_ROUND(2, 3, 1, 13) + SSE2_QUARTER_ROUND(3, 0, 2, 18) + ASS( pshufd xmm1, xmm1, 2, 1, 0, 3) + ASS( pshufd xmm2, xmm2, 1, 0, 3, 2) + ASS( pshufd xmm3, xmm3, 0, 3, 2, 1) + SSE2_QUARTER_ROUND(0, 3, 1, 7) + SSE2_QUARTER_ROUND(3, 2, 0, 9) + SSE2_QUARTER_ROUND(2, 1, 3, 13) + SSE2_QUARTER_ROUND(1, 0, 2, 18) + ASS( pshufd xmm1, xmm1, 0, 3, 2, 1) + ASS( pshufd xmm2, xmm2, 1, 0, 3, 2) + ASS( pshufd xmm3, xmm3, 2, 1, 0, 3) + AS2( sub REG_roundsLeft, 2) + ASJ( jnz, 0, b) + + AS2( paddd xmm0, [REG_state + 0*16]) + AS2( paddd xmm1, [REG_state + 1*16]) + AS2( paddd xmm2, [REG_state + 2*16]) + AS2( paddd xmm3, [REG_state + 3*16]) + + AS2( add dword ptr [REG_state + 8*4], 1) + AS2( adc dword ptr [REG_state + 5*4], 0) + + AS2( pcmpeqb xmm6, xmm6) // all ones + AS2( psrlq xmm6, 32) // lo32 mask + ASS( pshufd xmm7, xmm6, 0, 1, 2, 3) // hi32 mask + AS2( movdqa xmm4, xmm0) + AS2( movdqa xmm5, xmm3) + AS2( pand xmm0, xmm7) + AS2( pand xmm4, xmm6) + AS2( pand xmm3, xmm6) + AS2( pand xmm5, xmm7) + AS2( por xmm4, xmm5) // 0,13,2,15 + AS2( movdqa xmm5, xmm1) + AS2( pand xmm1, xmm7) + AS2( pand xmm5, xmm6) + AS2( por xmm0, xmm5) // 4,1,6,3 + AS2( pand xmm6, xmm2) + AS2( pand xmm2, xmm7) + AS2( por xmm1, xmm6) // 8,5,10,7 + AS2( por xmm2, xmm3) // 12,9,14,11 + + AS2( movdqa xmm5, xmm4) + AS2( movdqa xmm6, xmm0) + AS3( shufpd xmm4, xmm1, 2) // 0,13,10,7 + AS3( shufpd xmm0, xmm2, 2) // 4,1,14,11 + AS3( shufpd xmm1, xmm5, 2) // 8,5,2,15 + AS3( shufpd xmm2, xmm6, 2) // 12,9,6,3 + + // output keystream + AS_XMM_OUTPUT4(SSE2_Salsa_Output_B, REG_input, REG_output, 4, 0, 1, 2, 3, 0, 1, 2, 3, 4) + ASJ( jmp, 5, b) + ASL(4) + + AS_POP_IF86( bp) +#ifdef __GNUC__ + AS_POP_IF86( bx) + ATT_PREFIX + #if CRYPTOPP_BOOL_X64 + : "+r" (input), "+r" (output), "+r" (iterationCount) + : "r" (m_rounds), "r" (m_state.begin()), "r" (workspace) + : "%eax", "%rdx", "memory", "cc", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15" + #else + : "+a" (input), "+D" (output), "+c" (iterationCount) + : "d" (m_rounds), "S" (m_state.begin()) + : "memory", "cc" + #endif + ); +#endif +#ifdef CRYPTOPP_GENERATE_X64_MASM + movdqa xmm6, [rsp + 0200h] + movdqa xmm7, [rsp + 0210h] + movdqa xmm8, [rsp + 0220h] + movdqa xmm9, [rsp + 0230h] + movdqa xmm10, [rsp + 0240h] + movdqa xmm11, [rsp + 0250h] + movdqa xmm12, [rsp + 0260h] + movdqa xmm13, [rsp + 0270h] + movdqa xmm14, [rsp + 0280h] + movdqa xmm15, [rsp + 0290h] + add rsp, 10*16 + 32*16 + 8 + ret +Salsa20_OperateKeystream ENDP +#else + } + else +#endif +#endif +#ifndef CRYPTOPP_GENERATE_X64_MASM + { + word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + + while (iterationCount--) + { + x0 = m_state[0]; x1 = m_state[1]; x2 = m_state[2]; x3 = m_state[3]; + x4 = m_state[4]; x5 = m_state[5]; x6 = m_state[6]; x7 = m_state[7]; + x8 = m_state[8]; x9 = m_state[9]; x10 = m_state[10]; x11 = m_state[11]; + x12 = m_state[12]; x13 = m_state[13]; x14 = m_state[14]; x15 = m_state[15]; + + for (int i=m_rounds; i>0; i-=2) + { + #define QUARTER_ROUND(a, b, c, d) \ + b = b ^ rotlConstant<7>(a + d); \ + c = c ^ rotlConstant<9>(b + a); \ + d = d ^ rotlConstant<13>(c + b); \ + a = a ^ rotlConstant<18>(d + c); + + QUARTER_ROUND(x0, x4, x8, x12) + QUARTER_ROUND(x1, x5, x9, x13) + QUARTER_ROUND(x2, x6, x10, x14) + QUARTER_ROUND(x3, x7, x11, x15) + + QUARTER_ROUND(x0, x13, x10, x7) + QUARTER_ROUND(x1, x14, x11, x4) + QUARTER_ROUND(x2, x15, x8, x5) + QUARTER_ROUND(x3, x12, x9, x6) + } + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + #define SALSA_OUTPUT(x) {\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, x0 + m_state[0]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, x13 + m_state[13]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, x10 + m_state[10]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, x7 + m_state[7]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 4, x4 + m_state[4]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 5, x1 + m_state[1]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 6, x14 + m_state[14]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 7, x11 + m_state[11]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 8, x8 + m_state[8]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 9, x5 + m_state[5]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 10, x2 + m_state[2]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 11, x15 + m_state[15]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 12, x12 + m_state[12]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 13, x9 + m_state[9]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 14, x6 + m_state[6]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 15, x3 + m_state[3]);} + + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(SALSA_OUTPUT, BYTES_PER_ITERATION); + #undef SALSA_OUTPUT +#endif + + if (++m_state[8] == 0) + ++m_state[5]; + } + } +} // see comment above if an internal compiler error occurs here + +void XSalsa20_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + m_rounds = params.GetIntValueWithDefault(Name::Rounds(), m_rounds); + if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20)) + throw InvalidRounds(XSalsa20::StaticAlgorithmName(), m_rounds); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_key.begin(), m_key.size(), key, length); + if (length == 16) + memcpy(m_key.begin()+4, m_key.begin(), 16); + + // "expand 32-byte k" + m_state[0] = 0x61707865; + m_state[1] = 0x3320646e; + m_state[2] = 0x79622d32; + m_state[3] = 0x6b206574; +} + +void XSalsa20_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==24); + + word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + + GetBlock get(IV); + get(x14)(x11)(x8)(x5)(m_state[14])(m_state[11]); + + x13 = m_key[0]; x10 = m_key[1]; x7 = m_key[2]; x4 = m_key[3]; + x15 = m_key[4]; x12 = m_key[5]; x9 = m_key[6]; x6 = m_key[7]; + x0 = m_state[0]; x1 = m_state[1]; x2 = m_state[2]; x3 = m_state[3]; + + for (int i=m_rounds; i>0; i-=2) + { + QUARTER_ROUND(x0, x4, x8, x12) + QUARTER_ROUND(x1, x5, x9, x13) + QUARTER_ROUND(x2, x6, x10, x14) + QUARTER_ROUND(x3, x7, x11, x15) + + QUARTER_ROUND(x0, x13, x10, x7) + QUARTER_ROUND(x1, x14, x11, x4) + QUARTER_ROUND(x2, x15, x8, x5) + QUARTER_ROUND(x3, x12, x9, x6) + } + + m_state[13] = x0; m_state[10] = x1; m_state[7] = x2; m_state[4] = x3; + m_state[15] = x14; m_state[12] = x11; m_state[9] = x8; m_state[6] = x5; + m_state[8] = m_state[5] = 0; +} + +NAMESPACE_END + +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM diff --git a/extension/third_party/cryptopp/salsa.h b/extension/third_party/cryptopp/salsa.h new file mode 100644 index 00000000..f421af20 --- /dev/null +++ b/extension/third_party/cryptopp/salsa.h @@ -0,0 +1,95 @@ +// salsa.h - originally written and placed in the public domain by Wei Dai + +/// \file salsa.h +/// \brief Classes for Salsa and Salsa20 stream ciphers + +#ifndef CRYPTOPP_SALSA_H +#define CRYPTOPP_SALSA_H + +#include "strciphr.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SALSA_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Salsa20 core transform +/// \param data the data to transform +/// \param rounds the number of rounds +/// \details Several algorithms, like CryptoBox and Scrypt, require access to +/// the core Salsa20 transform. The current Crypto++ implementation does not +/// lend itself to disgorging the Salsa20 cipher from the Salsa20 core transform. +/// Instead Salsa20_Core is provided with customary accelerations. +void Salsa20_Core(word32* data, unsigned int rounds); + +/// \brief Salsa20 stream cipher information +struct Salsa20_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + static std::string StaticAlgorithmName() {return "Salsa20";} +}; + +/// \brief Salsa20 stream cipher operation +class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy +{ +protected: + Salsa20_Policy() : m_rounds(ROUNDS) {} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + std::string AlgorithmProvider() const; + + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + FixedSizeAlignedSecBlock m_state; + int m_rounds; +}; + +/// \brief Salsa20 stream cipher +/// \details Salsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa XSalsa20 +struct Salsa20 : public Salsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, Salsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +/// \brief XSalsa20 stream cipher information +struct XSalsa20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24> +{ + static std::string StaticAlgorithmName() {return "XSalsa20";} +}; + +/// \brief XSalsa20 stream cipher operation +class CRYPTOPP_NO_VTABLE XSalsa20_Policy : public Salsa20_Policy +{ +public: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + +protected: + FixedSizeSecBlock m_key; +}; + +/// \brief XSalsa20 stream cipher +/// \details XSalsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa XSalsa20 +struct XSalsa20 : public XSalsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, XSalsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/scrypt.cpp b/extension/third_party/cryptopp/scrypt.cpp new file mode 100644 index 00000000..3b995813 --- /dev/null +++ b/extension/third_party/cryptopp/scrypt.cpp @@ -0,0 +1,329 @@ +// scrypt.cpp - written and placed in public domain by Jeffrey Walton. +// Based on reference source code by Colin Percival for +// Scrypt and Daniel Bernstein for Salsa20 core. + +#include "pch.h" + +#include "scrypt.h" +#include "algparam.h" +#include "argnames.h" +#include "pwdbased.h" +#include "stdcpp.h" +#include "salsa.h" +#include "misc.h" +#include "sha.h" + +#include +#include + +#ifdef _OPENMP +# include +#endif + +// https://github.com/weidai11/cryptopp/issues/777 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# if defined(__clang__) +# pragma GCC diagnostic ignored "-Wtautological-compare" +# elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wtype-limits" +# endif +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::GetWord; +using CryptoPP::PutWord; +using CryptoPP::Salsa20_Core; +using CryptoPP::rotlConstant; +using CryptoPP::LITTLE_ENDIAN_ORDER; +using CryptoPP::AlignedSecByteBlock; + +inline void LE32ENC(byte* out, word32 in) +{ + PutWord(false, LITTLE_ENDIAN_ORDER, out, in); +} + +inline word32 LE32DEC(const byte* in) +{ + return GetWord(false, LITTLE_ENDIAN_ORDER, in); +} + +inline word64 LE64DEC(const byte* in) +{ + return GetWord(false, LITTLE_ENDIAN_ORDER, in); +} + +inline void BlockCopy(byte* dest, byte* src, size_t len) +{ +// OpenMP 4.0 released July 2013. +#if _OPENMP >= 201307 + #pragma omp simd + for (size_t i = 0; i < len; ++i) + dest[i] = src[i]; +#else + for (size_t i = 0; i < len; ++i) + dest[i] = src[i]; +#endif +} + +inline void BlockXOR(byte* dest, byte* src, size_t len) +{ +// OpenMP 4.0 released July 2013. +#if _OPENMP >= 201307 + #pragma omp simd + for (size_t i = 0; i < len; ++i) + dest[i] ^= src[i]; +#else + for (size_t i = 0; i < len; ++i) + dest[i] ^= src[i]; +#endif +} + +inline void PBKDF2_SHA256(byte* buf, size_t dkLen, + const byte* passwd, size_t passwdlen, + const byte* salt, size_t saltlen, byte count) +{ + using CryptoPP::SHA256; + using CryptoPP::PKCS5_PBKDF2_HMAC; + + PKCS5_PBKDF2_HMAC pbkdf; + pbkdf.DeriveKey(buf, dkLen, 0, passwd, passwdlen, salt, saltlen, count, 0.0f); +} + +inline void Salsa20_8(byte B[64]) +{ + word32 B32[16]; + + for (size_t i = 0; i < 16; ++i) + B32[i] = LE32DEC(&B[i * 4]); + + Salsa20_Core(B32, 8); + + for (size_t i = 0; i < 16; ++i) + LE32ENC(&B[4 * i], B32[i]); +} + +inline void BlockMix(byte* B, byte* Y, size_t r) +{ + byte X[64]; + + // 1: X <-- B_{2r - 1} + BlockCopy(X, &B[(2 * r - 1) * 64], 64); + + // 2: for i = 0 to 2r - 1 do + for (size_t i = 0; i < 2 * r; ++i) + { + // 3: X <-- H(X \xor B_i) + BlockXOR(X, &B[i * 64], 64); + Salsa20_8(X); + + // 4: Y_i <-- X + BlockCopy(&Y[i * 64], X, 64); + } + + // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) + for (size_t i = 0; i < r; ++i) + BlockCopy(&B[i * 64], &Y[(i * 2) * 64], 64); + + for (size_t i = 0; i < r; ++i) + BlockCopy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); +} + +inline word64 Integerify(byte* B, size_t r) +{ + byte* X = &B[(2 * r - 1) * 64]; + return LE64DEC(X); +} + +inline void Smix(byte* B, size_t r, word64 N, byte* V, byte* XY) +{ + byte* X = XY; + byte* Y = XY+128*r; + + // 1: X <-- B + BlockCopy(X, B, 128 * r); + + // 2: for i = 0 to N - 1 do + for (word64 i = 0; i < N; ++i) + { + // 3: V_i <-- X + BlockCopy(&V[i * (128 * r)], X, 128 * r); + + // 4: X <-- H(X) + BlockMix(X, Y, r); + } + + // 6: for i = 0 to N - 1 do + for (word64 i = 0; i < N; ++i) + { + // 7: j <-- Integerify(X) mod N + word64 j = Integerify(X, r) & (N - 1); + + // 8: X <-- H(X \xor V_j) + BlockXOR(X, &V[j * (128 * r)], 128 * r); + BlockMix(X, Y, r); + } + + // 10: B' <-- X + BlockCopy(B, X, 128 * r); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +size_t Scrypt::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +void Scrypt::ValidateParameters(size_t derivedLen, word64 cost, word64 blockSize, word64 parallelization) const +{ + // https://github.com/weidai11/cryptopp/issues/842 + CRYPTOPP_ASSERT(derivedLen != 0); + CRYPTOPP_ASSERT(cost != 0); + CRYPTOPP_ASSERT(blockSize != 0); + CRYPTOPP_ASSERT(parallelization != 0); + + if (cost == 0) + throw InvalidArgument("Scrypt: cost cannot be 0"); + + if (blockSize == 0) + throw InvalidArgument("Scrypt: block size cannot be 0"); + + if (parallelization == 0) + throw InvalidArgument("Scrypt: parallelization cannot be 0"); + + // Optimizer should remove this on 32-bit platforms + if (std::numeric_limits::max() > std::numeric_limits::max()) + { + const word64 maxLen = ((static_cast(1) << 32) - 1) * 32; + if (derivedLen > maxLen) { + std::ostringstream oss; + oss << "derivedLen " << derivedLen << " is larger than " << maxLen; + throw InvalidArgument("Scrypt: " + oss.str()); + } + } + + // https://github.com/weidai11/cryptopp/issues/787 + CRYPTOPP_ASSERT(parallelization <= static_cast(std::numeric_limits::max())); + if (parallelization > static_cast(std::numeric_limits::max())) + { + std::ostringstream oss; + oss << " parallelization " << parallelization << " is larger than "; + oss << std::numeric_limits::max(); + throw InvalidArgument("Scrypt: " + oss.str()); + } + + CRYPTOPP_ASSERT(IsPowerOf2(cost)); + if (IsPowerOf2(cost) == false) + throw InvalidArgument("Scrypt: cost must be a power of 2"); + + const word64 prod = static_cast(blockSize) * parallelization; + CRYPTOPP_ASSERT(prod < (1U << 30)); + + if (prod >= (1U << 30)) { + std::ostringstream oss; + oss << "r*p " << prod << " is larger than " << (1U << 30); + throw InvalidArgument("Scrypt: " + oss.str()); + } + + // Scrypt has several tests that effectively verify allocations like + // '128 * r * N' and '128 * r * p' do not overflow. They are the tests + // that set errno to ENOMEM. We can make the logic a little more clear + // using word128. At first blush the word128 may seem like overkill. + // However, this alogirthm is dominated by slow moving parts, so a + // one-time check is insignificant in the bigger picture. +#if defined(CRYPTOPP_WORD128_AVAILABLE) + const word128 maxElems = static_cast(SIZE_MAX); + bool bLimit = (maxElems >= static_cast(cost) * blockSize * 128U); + bool xyLimit = (maxElems >= static_cast(parallelization) * blockSize * 128U); + bool vLimit = (maxElems >= static_cast(blockSize) * 256U + 64U); +#else + const word64 maxElems = static_cast(SIZE_MAX); + bool bLimit = (blockSize < maxElems / 128U / cost); + bool xyLimit = (blockSize < maxElems / 128U / parallelization); + bool vLimit = (blockSize < (maxElems - 64U) / 256U); +#endif + + CRYPTOPP_ASSERT(bLimit); CRYPTOPP_ASSERT(xyLimit); CRYPTOPP_ASSERT(vLimit); + if (!bLimit || !xyLimit || !vLimit) + throw std::bad_alloc(); +} + +size_t Scrypt::DeriveKey(byte*derived, size_t derivedLen, + const byte*secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + word64 cost=0, blockSize=0, parallelization=0; + if(params.GetValue("Cost", cost) == false) + cost = defaultCost; + + if(params.GetValue("BlockSize", blockSize) == false) + blockSize = defaultBlockSize; + + if(params.GetValue("Parallelization", parallelization) == false) + parallelization = defaultParallelization; + + ConstByteArrayParameter salt; + (void)params.GetValue("Salt", salt); + + return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), cost, blockSize, parallelization); +} + +size_t Scrypt::DeriveKey(byte*derived, size_t derivedLen, const byte*secret, size_t secretLen, + const byte*salt, size_t saltLen, word64 cost, word64 blockSize, word64 parallel) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + ValidateParameters(derivedLen, cost, blockSize, parallel); + + AlignedSecByteBlock B(static_cast(blockSize * parallel * 128U)); + + // 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) + PBKDF2_SHA256(B, B.size(), secret, secretLen, salt, saltLen, 1); + + // Visual Studio and OpenMP 2.0 fixup. We must use int, not size_t. + int maxParallel=0; + if (!SafeConvert(parallel, maxParallel)) + maxParallel = std::numeric_limits::max(); + + #ifdef _OPENMP + int threads = STDMIN(omp_get_max_threads(), maxParallel); + #endif + + // http://stackoverflow.com/q/49604260/608639 + #pragma omp parallel num_threads(threads) + { + // Each thread gets its own copy + AlignedSecByteBlock XY(static_cast(blockSize * 256U)); + AlignedSecByteBlock V(static_cast(blockSize * cost * 128U)); + + // 2: for i = 0 to p - 1 do + #pragma omp for + for (int i = 0; i < maxParallel; ++i) + { + // 3: B_i <-- MF(B_i, N) + const ptrdiff_t offset = static_cast(blockSize*i*128); + Smix(B+offset, static_cast(blockSize), cost, V, XY); + } + } + + // 5: DK <-- PBKDF2(P, B, 1, dkLen) + PBKDF2_SHA256(derived, derivedLen, secret, secretLen, B, B.size(), 1); + + return 1; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/scrypt.h b/extension/third_party/cryptopp/scrypt.h new file mode 100644 index 00000000..924c1f18 --- /dev/null +++ b/extension/third_party/cryptopp/scrypt.h @@ -0,0 +1,103 @@ +// scrypt.h - written and placed in public domain by Jeffrey Walton. +// Based on reference source code by Colin Percival. + +/// \file scrypt.h +/// \brief Classes for Scrypt from RFC 7914 +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 7.0 + +#ifndef CRYPTOPP_SCRYPT_H +#define CRYPTOPP_SCRYPT_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Scrypt key derivation function +/// \details The Crypto++ implementation uses OpenMP to accelerate the derivation when +/// available. +/// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For +/// example, the library is limited to a derived key length of SIZE_MAX, +/// and not (2^32 - 1) * 32. +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 7.0 +class Scrypt : public KeyDerivationFunction +{ +public: + virtual ~Scrypt() {} + + static std::string StaticAlgorithmName () { + return "scrypt"; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(0)-1; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param cost the CPU/memory cost factor + /// \param blockSize the block size + /// \param parallelization the parallelization factor + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details The CPU/Memory cost parameter ("N" in the documents) must be + /// larger than 1, a power of 2, and less than 2^(128 * r / 8). + /// \details The parameter blockSize ("r" in the documents) specifies the block + /// size. + /// \details The parallelization parameter ("p" in the documents) is a positive + /// integer less than or equal to ((2^32-1) * 32) / (128 * r). Due to Microsoft + /// and its OpenMP 2.0 implementation parallelization is limited to + /// std::numeric_limits::max(). + /// \details Scrypt always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + /// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For + /// example, the library is limited to a derived key length of SIZE_MAX, + /// and not (2^32 - 1) * 32. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, word64 cost=2, word64 blockSize=8, word64 parallelization=1) const; + +protected: + enum {defaultCost=2, defaultBlockSize=8, defaultParallelization=1}; + + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + inline void ValidateParameters(size_t derivedlen, word64 cost, word64 blockSize, word64 parallelization) const; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SCRYPT_H diff --git a/extension/third_party/cryptopp/seal.cpp b/extension/third_party/cryptopp/seal.cpp new file mode 100644 index 00000000..fea047e7 --- /dev/null +++ b/extension/third_party/cryptopp/seal.cpp @@ -0,0 +1,222 @@ +// seal.cpp - originally written and placed in the public domain by Wei Dai +// updated to SEAL 3.0 by Leonard Janke + +#include "pch.h" + +#include "seal.h" +#include "cpu.h" +#include "sha.h" +#include "misc.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void SEAL_TestInstantiations() +{ + SEAL<>::Encryption x; +} +#endif + +struct SEAL_Gamma +{ + SEAL_Gamma(const byte *key) + : H(5), Z(5), D(16), lastIndex(0xffffffff) + { + GetUserKey(BIG_ENDIAN_ORDER, H.begin(), 5, key, 20); + memset(D, 0, 64); + } + + word32 Apply(word32 i); + + SecBlock H, Z, D; + word32 lastIndex; +}; + +word32 SEAL_Gamma::Apply(word32 i) +{ + word32 shaIndex = i/5; + if (shaIndex != lastIndex) + { + memcpy(Z, H, 20); + D[0] = shaIndex; + SHA1::Transform(Z, D); + lastIndex = shaIndex; + } + + return Z[i%5]; +} + +template +void SEAL_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_UNUSED(length); + m_insideCounter = m_outsideCounter = m_startCount = 0; + + unsigned int L = params.GetIntValueWithDefault("NumberOfOutputBitsPerPositionIndex", 32*1024); + m_iterationsPerCount = L / 8192; + + SEAL_Gamma gamma(key); + unsigned int i; + + for (i=0; i<512; i++) + m_T[i] = gamma.Apply(i); + + for (i=0; i<256; i++) + m_S[i] = gamma.Apply(0x1000+i); + + m_R.New(4*(L/8192)); + + for (i=0; i +void SEAL_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(IV), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==4); + + m_outsideCounter = IV ? GetWord(false, BIG_ENDIAN_ORDER, IV) : 0; + m_startCount = m_outsideCounter; + m_insideCounter = 0; +} + +template +void SEAL_Policy::SeekToIteration(lword iterationCount) +{ + m_outsideCounter = m_startCount + (unsigned int)(iterationCount / m_iterationsPerCount); + m_insideCounter = (unsigned int)(iterationCount % m_iterationsPerCount); +} + +template +void SEAL_Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + word32 a, b, c, d, n1, n2, n3, n4; + unsigned int p, q; + + CRYPTOPP_ASSERT(IsAlignedOn(m_T.begin(),GetAlignmentOf())); + for (size_t iteration = 0; iteration < iterationCount; ++iteration) + { + #define Ttab(x) *(word32 *)(void*)((byte *)m_T.begin()+x) + + a = m_outsideCounter ^ m_R[4*m_insideCounter]; + b = rotrConstant<8>(m_outsideCounter) ^ m_R[4*m_insideCounter+1]; + c = rotrConstant<16>(m_outsideCounter) ^ m_R[4 * m_insideCounter + 2]; + d = rotrConstant<24>(m_outsideCounter) ^ m_R[4 * m_insideCounter + 3]; + + for (unsigned int j=0; j<2; j++) + { + p = a & 0x7fc; + b += Ttab(p); + a = rotrConstant<9>(a); + + p = b & 0x7fc; + c += Ttab(p); + b = rotrConstant<9>(b); + + p = c & 0x7fc; + d += Ttab(p); + c = rotrConstant<9>(c); + + p = d & 0x7fc; + a += Ttab(p); + d = rotrConstant<9>(d); + } + + n1 = d, n2 = b, n3 = a, n4 = c; + + p = a & 0x7fc; + b += Ttab(p); + a = rotrConstant<9>(a); + + p = b & 0x7fc; + c += Ttab(p); + b = rotrConstant<9>(b); + + p = c & 0x7fc; + d += Ttab(p); + c = rotrConstant<9>(c); + + p = d & 0x7fc; + a += Ttab(p); + d = rotrConstant<9>(d); + + // generate 8192 bits + for (unsigned int i=0; i<64; i++) + { + p = a & 0x7fc; + a = rotrConstant<9>(a); + b += Ttab(p); + b ^= a; + + q = b & 0x7fc; + b = rotrConstant<9>(b); + c ^= Ttab(q); + c += b; + + p = (p+c) & 0x7fc; + c = rotrConstant<9>(c); + d += Ttab(p); + d ^= c; + + q = (q+d) & 0x7fc; + d = rotrConstant<9>(d); + a ^= Ttab(q); + a += d; + + p = (p+a) & 0x7fc; + b ^= Ttab(p); + a = rotrConstant<9>(a); + + q = (q+b) & 0x7fc; + c += Ttab(q); + b = rotrConstant<9>(b); + + p = (p+c) & 0x7fc; + d ^= Ttab(p); + c = rotrConstant<9>(c); + + q = (q+d) & 0x7fc; + d = rotrConstant<9>(d); + a += Ttab(q); + +#define SEAL_OUTPUT(x) \ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 0, b + m_S[4*i+0]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 1, c ^ m_S[4*i+1]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 2, d + m_S[4*i+2]);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 3, a ^ m_S[4*i+3]); + + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(SEAL_OUTPUT, 4*4); + + if (i & 1) + { + a += n3; + b += n4; + c ^= n3; + d ^= n4; + } + else + { + a += n1; + b += n2; + c ^= n1; + d ^= n2; + } + } + + if (++m_insideCounter == m_iterationsPerCount) + { + ++m_outsideCounter; + m_insideCounter = 0; + } + } + + a = b = c = d = n1 = n2 = n3 = n4 = 0; + p = q = 0; +} + +template class SEAL_Policy; +template class SEAL_Policy; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/seal.h b/extension/third_party/cryptopp/seal.h new file mode 100644 index 00000000..d8826aec --- /dev/null +++ b/extension/third_party/cryptopp/seal.h @@ -0,0 +1,59 @@ +// seal.h - originally written and placed in the public domain by Wei Dai + +/// \file seal.h +/// \brief Classes for SEAL stream cipher +/// \since Crypto++ 2.2 + +#ifndef CRYPTOPP_SEAL_H +#define CRYPTOPP_SEAL_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SEAL stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +struct SEAL_Info : public FixedKeyLength<20, SimpleKeyingInterface::INTERNALLY_GENERATED_IV, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "SEAL-3.0-LE" : "SEAL-3.0-BE";} +}; + +/// \brief SEAL stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +class CRYPTOPP_NO_VTABLE SEAL_Policy : public AdditiveCipherConcretePolicy, public SEAL_Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + +private: + FixedSizeSecBlock m_T; + FixedSizeSecBlock m_S; + SecBlock m_R; + + word32 m_startCount, m_iterationsPerCount; + word32 m_outsideCounter, m_insideCounter; +}; + +/// \brief SEAL stream cipher +/// \tparam B Endianness of the stream cipher +/// \sa SEAL +/// \since Crypto++ 2.2 +template +struct SEAL : public SEAL_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, SEAL_Info > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/secblock.h b/extension/third_party/cryptopp/secblock.h new file mode 100644 index 00000000..810eabf4 --- /dev/null +++ b/extension/third_party/cryptopp/secblock.h @@ -0,0 +1,1198 @@ +// secblock.h - originally written and placed in the public domain by Wei Dai + +/// \file secblock.h +/// \brief Classes and functions for secure memory allocations. + +#ifndef CRYPTOPP_SECBLOCK_H +#define CRYPTOPP_SECBLOCK_H + +#include "config.h" +#include "allocate.h" +#include "misc.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275 4700) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +/// \brief Base class for all allocators used by SecBlock +/// \tparam T the class or type +template +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();} + + /// \brief Returns the maximum number of elements the allocator can provide + /// \details ELEMS_MAX is the maximum number of elements the + /// Allocator can provide. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(_MSC_VER) && (_MSC_VER <= 1400) + static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) + enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Returns the maximum number of elements the allocator can provide + /// \return the maximum number of elements the allocator can provide + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;} + +#if defined(__SUNPRO_CC) + // https://github.com/weidai11/cryptopp/issues/770 + // and https://stackoverflow.com/q/53999461/608639 + CRYPTOPP_CONSTEXPR size_type max_size(size_type n) const {return SIZE_MAX/n;} +#endif + +#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief Constructs a new V using variadic arguments + /// \tparam V the type to be forwarded + /// \tparam Args the arguments to be forwarded + /// \param ptr pointer to type V + /// \param args variadic arguments + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward(args)...);} + + /// \brief Destroys an V constructed with variadic arguments + /// \tparam V the type to be forwarded + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void destroy(V* ptr) {if (ptr) ptr->~V();} + +#endif + +protected: + + /// \brief Verifies the allocator can satisfy a request based on size + /// \param size the size of the allocation, in elements + /// \throw InvalidArgument + /// \details CheckSize verifies the number of elements requested is valid. + /// \details If size is greater than max_size(), then InvalidArgument is thrown. + /// The library throws InvalidArgument if the size is too large to satisfy. + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + /// \details The sizeof(T) != 1 in the condition attempts to help the + /// compiler optimize the check for byte types. Coverity findings for + /// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types, + /// size never exceeded ELEMS_MAX but the code was not removed. + /// \note size is the count of elements, and not the number of bytes + static void CheckSize(size_t size) + { + // Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673. + CRYPTOPP_UNUSED(size); + // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here. + if (sizeof(T) != 1 && size > ELEMS_MAX) + throw InvalidArgument("AllocatorBase: requested size would cause integer overflow"); + } +}; + +#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T_type) \ + typedef typename AllocatorBase::value_type value_type;\ + typedef typename AllocatorBase::size_type size_type;\ + typedef typename AllocatorBase::difference_type difference_type;\ + typedef typename AllocatorBase::pointer pointer;\ + typedef typename AllocatorBase::const_pointer const_pointer;\ + typedef typename AllocatorBase::reference reference;\ + typedef typename AllocatorBase::const_reference const_reference; + +/// \brief Reallocation function +/// \tparam T the class or type +/// \tparam A the class or type's allocator +/// \param alloc the allocator +/// \param oldPtr the previous allocation +/// \param oldSize the size of the previous allocation +/// \param newSize the new, requested size +/// \param preserve flag that indicates if the old allocation should be preserved +/// \note oldSize and newSize are the count of elements, and not the +/// number of bytes. +template +typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) +{ + // Avoid assert on pointer in reallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (oldSize == newSize) + return oldPtr; + + if (preserve) + { + typename A::pointer newPtr = alloc.allocate(newSize, NULLPTR); + const typename A::size_type copySize = STDMIN(oldSize, newSize) * sizeof(T); + + if (oldPtr && newPtr) + memcpy_s(newPtr, copySize, oldPtr, copySize); + + if (oldPtr) + alloc.deallocate(oldPtr, oldSize); + + return newPtr; + } + else + { + if (oldPtr) + alloc.deallocate(oldPtr, oldSize); + + return alloc.allocate(newSize, NULLPTR); + } +} + +/// \brief Allocates a block of memory with cleanup +/// \tparam T class or type +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +/// \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate() +/// for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls +/// UnalignedAllocate() for memory allocations. +/// \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors +/// CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter. +template +class AllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Allocates a block of memory + /// \param ptr the size of the allocation + /// \param size the size of the allocation, in elements + /// \return a memory block + /// \throw InvalidArgument + /// \details allocate() first checks the size of the request. If it is non-0 + /// and less than max_size(), then an attempt is made to fulfill the request + /// using either AlignedAllocate() or UnalignedAllocate(). AlignedAllocate() is + /// used if T_Align16 is true. UnalignedAllocate() used if T_Align16 is false. + /// \details This is the C++ *Placement New* operator. ptr is not used, and the + /// function asserts in Debug builds if ptr is non-NULL. + /// \sa CallNewHandler() for the methods used to recover from a failed + /// allocation attempt. + /// \note size is the count of elements, and not the number of bytes + pointer allocate(size_type size, const void *ptr = NULLPTR) + { + CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR); + this->CheckSize(size); + if (size == 0) + return NULLPTR; + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16) + return reinterpret_cast(AlignedAllocate(size*sizeof(T))); +#endif + + return reinterpret_cast(UnalignedAllocate(size*sizeof(T))); + } + + /// \brief Deallocates a block of memory + /// \param ptr the pointer for the allocation + /// \param size the size of the allocation, in elements + /// \details Internally, SecureWipeArray() is called before deallocating the + /// memory. Once the memory block is wiped or zeroized, AlignedDeallocate() + /// or UnalignedDeallocate() is called. + /// \details AlignedDeallocate() is used if T_Align16 is true. + /// UnalignedDeallocate() used if T_Align16 is false. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr) + { + SecureWipeArray(reinterpret_cast(ptr), size); + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16) + return AlignedDeallocate(ptr); +#endif + + UnalignedDeallocate(ptr); + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should be preserved + /// \return pointer to the new memory block + /// \details Internally, reallocate() calls StandardReallocate(). + /// \details If preserve is true, then index 0 is used to begin copying the + /// old memory block to the new one. If the block grows, then the old array + /// is copied in its entirety. If the block shrinks, then only newSize + /// elements are copied from the old block to the new one. + /// \note oldSize and newSize are the count of elements, and not the + /// number of bytes. + pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize)); + return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve); + } + + /// \brief Template class member Rebind + /// \tparam V bound class or type + /// \details Rebind allows a container class to allocate a different type of object + /// to store elements. For example, a std::list will allocate std::list_node to + /// store elements in the list. + /// \details VS.NET STL enforces the policy of "All STL-compliant allocators + /// have to provide a template class member called rebind". + template struct rebind { typedef AllocatorWithCleanup other; }; +#if _MSC_VER >= 1500 + AllocatorWithCleanup() {} + template AllocatorWithCleanup(const AllocatorWithCleanup &) {} +#endif +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +#if defined(CRYPTOPP_WORD128_AVAILABLE) +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif +#if CRYPTOPP_BOOL_X86 +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif + +/// \brief NULL allocator +/// \tparam T class or type +/// \details A NullAllocator is useful for fixed-size, stack based allocations +/// (i.e., static arrays used by FixedSizeAllocatorWithCleanup). +/// \details A NullAllocator always returns 0 for max_size(), and always returns +/// NULL for allocation requests. Though the allocator does not allocate at +/// runtime, it does perform a secure wipe or zeroization during cleanup. +template +class NullAllocator : public AllocatorBase +{ +public: + //LCOV_EXCL_START + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard + // libraries always throw. And late mode Windows throws. Early model Windows + // (circa VC++ 6.0) returned NULL. + pointer allocate(size_type n, const void* unused = NULLPTR) + { + CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused); + CRYPTOPP_ASSERT(false); return NULLPTR; + } + + void deallocate(void *p, size_type n) + { + CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n); + CRYPTOPP_ASSERT(false); + } + + CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;} + //LCOV_EXCL_STOP +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should +/// be aligned on a 16-byte boundary +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template , bool T_Align16 = false> +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ + // The body of FixedSizeAllocatorWithCleanup is provided in the two + // partial specializations that follow. The two specializations + // pivot on the boolean template parameter T_Align16. +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based + /// allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \param hint an unused hint + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + /// \brief Deallocates a block of memory + /// \param ptr a pointer to the memory block to deallocate + /// \param size the count elements in the memory block + /// \details The memory block is wiped or zeroized before deallocation. + /// If the statically allocated memory block is active, then no + /// additional actions are taken after the wipe. + /// \details If a dynamic memory block is active, then the pointer and + /// size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr == GetAlignedArray()) + { + // If the m_allocated assert fires then the bit twiddling for + // GetAlignedArray() is probably incorrect for the platform. + // Be sure to check CRYPTOPP_ALIGN_DATA(8). The platform may + // not have a way to declaratively align data to 8. + CRYPTOPP_ASSERT(size <= S); + CRYPTOPP_ASSERT(m_allocated); + m_allocated = false; + SecureWipeArray(reinterpret_cast(ptr), size); + } + else + { + if (ptr) + m_fallbackAllocator.deallocate(ptr, size); + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should + /// be preserved + /// \return pointer to the new memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \note size is the count of elements, and not the number of bytes. + /// \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + CRYPTOPP_ASSERT(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPtr = allocate(newSize, NULLPTR); + if (preserve && newSize) + { + const size_type copySize = STDMIN(oldSize, newSize); + if (newPtr && oldPtr) // GCC analyzer warning + memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); + } + deallocate(oldPtr, oldSize); + return newPtr; + } + + CRYPTOPP_CONSTEXPR size_type max_size() const + { + return STDMAX(m_fallbackAllocator.max_size(), S); + } + +private: + +#if CRYPTOPP_BOOL_ALIGN16 + + // There be demons here... We cannot use CRYPTOPP_ALIGN_DATA(16) + // because linkers on 32-bit machines and some 64-bit machines + // align the stack to 8-bytes or less, and not 16-bytes as + // requested. We can only count on a smaller alignment. All + // toolchains tested appear to honor CRYPTOPP_ALIGN_DATA(8). Also + // see http://stackoverflow.com/a/1468656/608639. + // + // The 16-byte alignment is achieved by padding the requested + // size with extra elements so we have at least 8-bytes of slack + // to work with. Then the array pointer is moved to achieve a + // 16-byte alignment. + // + // The additional 8-bytes introduces a small secondary issue. + // The secondary issue is, a large T results in 0 = 8/sizeof(T). + // The library is OK but users may hit it. So we need to guard + // for a large T, and that is what the enum and PAD achieves. + T* GetAlignedArray() { + + // m_array is aligned on 8 byte boundaries due to + // CRYPTOPP_ALIGN_DATA(8). If m_array%16 is 0, then the buffer + // is 16-byte aligned and nothing needs to be done. if + // m_array%16 is 8, then the buffer is not 16-byte aligned and + // we need to add 8. 8 has that nice symmetric property. + // + // If we needed to use CRYPTOPP_ALIGN_DATA(4) due to toolchain + // limitations, then the calculation would be slightly more + // costly: ptr = m_array + (16 - (m_array % 16)) % 16; + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + int off = reinterpret_cast(m_array) % 16; + byte* ptr = reinterpret_cast(m_array) + off; + + // Verify the 16-byte alignment. This is the point + // of these extra gyrations. + CRYPTOPP_ASSERT(IsAlignedOn(ptr, 16)); + // Verify the lower bound. This is Issue 982/988. + CRYPTOPP_ASSERT( + reinterpret_cast(ptr) >= + reinterpret_cast(m_array) + ); + // Verify the upper bound. Allocated array with + // pad is large enough. + CRYPTOPP_ASSERT( + reinterpret_cast(ptr+S*sizeof(T)) <= + reinterpret_cast(m_array+(S+PAD)) + ); + + // void* to silence Clang warnings + return reinterpret_cast( + static_cast(ptr) + ); + } + + // PAD is elements, not bytes, and rounded up to ensure no overflow. + enum { Q = sizeof(T), PAD = (Q >= 8) ? 1 : (Q >= 4) ? 2 : (Q >= 2) ? 4 : 8 }; + // enum { Q = sizeof(T), PAD = (Q >= 16) ? 1 : (Q >= 8) ? 2 : (Q >= 4) ? 4 : (Q >= 2) ? 8 : 16 }; + CRYPTOPP_ALIGN_DATA(8) T m_array[S+PAD]; + +#else + + // CRYPTOPP_BOOL_ALIGN16 is 0. If we are here then the user + // probably compiled with CRYPTOPP_DISABLE_ASM. Normally we + // would use the natural alignment of T. The problem we are + // having is, some toolchains are changing the boundary for + // 64-bit arrays. 64-bit elements require 8-byte alignment, + // but the toolchain is laying the array out on a 4 byte + // boundary. See GH #992 for mystery alignment, + // https://github.com/weidai11/cryptopp/issues/992 + T* GetAlignedArray() {return m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[S]; + +#endif + + A m_fallbackAllocator; + bool m_allocated; +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based + /// allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \param hint an unused hint + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + /// \brief Deallocates a block of memory + /// \param ptr a pointer to the memory block to deallocate + /// \param size the count elements in the memory block + /// \details The memory block is wiped or zeroized before deallocation. + /// If the statically allocated memory block is active, then no + /// additional actions are taken after the wipe. + /// \details If a dynamic memory block is active, then the pointer and + /// size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr == GetAlignedArray()) + { + // If the m_allocated assert fires then + // something overwrote the flag. + CRYPTOPP_ASSERT(size <= S); + CRYPTOPP_ASSERT(m_allocated); + m_allocated = false; + SecureWipeArray((pointer)ptr, size); + } + else + { + if (ptr) + m_fallbackAllocator.deallocate(ptr, size); + m_allocated = false; + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should + /// be preserved + /// \return pointer to the new memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \note size is the count of elements, and not the number of bytes. + /// \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + CRYPTOPP_ASSERT(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPtr = allocate(newSize, NULLPTR); + if (preserve && newSize) + { + const size_type copySize = STDMIN(oldSize, newSize); + if (newPtr && oldPtr) // GCC analyzer warning + memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); + } + deallocate(oldPtr, oldSize); + return newPtr; + } + + CRYPTOPP_CONSTEXPR size_type max_size() const + { + return STDMAX(m_fallbackAllocator.max_size(), S); + } + +private: + + // T_Align16 is false. Normally we would use the natural + // alignment of T. The problem we are having is, some toolchains + // are changing the boundary for 64-bit arrays. 64-bit elements + // require 8-byte alignment, but the toolchain is laying the array + // out on a 4 byte boundary. See GH #992 for mystery alignment, + // https://github.com/weidai11/cryptopp/issues/992 + T* GetAlignedArray() {return m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[S]; + + A m_fallbackAllocator; + bool m_allocated; +}; + +/// \brief Secure memory block with allocator and cleanup +/// \tparam T a class or type +/// \tparam A AllocatorWithCleanup derived class for allocation and cleanup +template > +class SecBlock +{ +public: + typedef typename A::value_type value_type; + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + typedef typename A::size_type size_type; + + /// \brief Returns the maximum number of elements the block can hold + /// \details ELEMS_MAX is the maximum number of elements the + /// SecBlock can hold. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(_MSC_VER) && (_MSC_VER <= 1400) + static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) + enum : size_type {ELEMS_MAX = A::ELEMS_MAX}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Construct a SecBlock with space for size elements. + /// \param size the size of the allocation, in elements + /// \throw std::bad_alloc + /// \details The elements are not initialized. + /// \note size is the count of elements, and not the number of bytes + explicit SecBlock(size_type size=0) + : m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { } + + /// \brief Copy construct a SecBlock from another SecBlock + /// \param t the other SecBlock + /// \throw std::bad_alloc + SecBlock(const SecBlock &t) + : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) { + CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size)); + if (m_ptr && t.m_ptr) + memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + } + + /// \brief Construct a SecBlock from an array of elements. + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \throw std::bad_alloc + /// \details If ptr!=NULL and len!=0, then the block is initialized from the pointer + /// ptr. If ptr==NULL and len!=0, then the block is initialized to 0. + /// Otherwise, the block is empty and not initialized. + /// \note size is the count of elements, and not the number of bytes + SecBlock(const T *ptr, size_type len) + : m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + if (m_ptr && ptr) + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + else if (m_ptr && m_size) + memset(m_ptr, 0, m_size*sizeof(T)); + } + + ~SecBlock() + {m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));} + +#ifdef __BORLANDC__ + /// \brief Cast operator + /// \return block pointer cast to non-const T * + operator T *() const + {return (T*)m_ptr;} +#else + /// \brief Cast operator + /// \return block pointer cast to const void * + operator const void *() const + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to non-const void * + operator void *() + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to const T * + operator const T *() const + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to non-const T * + operator T *() + {return m_ptr;} +#endif + + /// \brief Provides an iterator pointing to the first element in the memory block + /// \return iterator pointing to the first element in the memory block + iterator begin() + {return m_ptr;} + /// \brief Provides a constant iterator pointing to the first element in the memory block + /// \return constant iterator pointing to the first element in the memory block + const_iterator begin() const + {return m_ptr;} + /// \brief Provides an iterator pointing beyond the last element in the memory block + /// \return iterator pointing beyond the last element in the memory block + iterator end() + {return m_ptr+m_size;} + /// \brief Provides a constant iterator pointing beyond the last element in the memory block + /// \return constant iterator pointing beyond the last element in the memory block + const_iterator end() const + {return m_ptr+m_size;} + + /// \brief Provides a pointer to the first element in the memory block + /// \return pointer to the first element in the memory block + typename A::pointer data() {return m_ptr;} + /// \brief Provides a pointer to the first element in the memory block + /// \return constant pointer to the first element in the memory block + typename A::const_pointer data() const {return m_ptr;} + + /// \brief Provides the count of elements in the SecBlock + /// \return number of elements in the memory block + /// \note the return value is the count of elements, and not the number of bytes + size_type size() const {return m_size;} + /// \brief Determines if the SecBlock is empty + /// \return true if number of elements in the memory block is 0, false otherwise + bool empty() const {return m_size == 0;} + + /// \brief Provides a byte pointer to the first element in the memory block + /// \return byte pointer to the first element in the memory block + byte * BytePtr() {return (byte *)m_ptr;} + /// \brief Return a byte pointer to the first element in the memory block + /// \return constant byte pointer to the first element in the memory block + const byte * BytePtr() const {return (const byte *)m_ptr;} + /// \brief Provides the number of bytes in the SecBlock + /// \return the number of bytes in the memory block + /// \note the return value is the number of bytes, and not count of elements. + size_type SizeInBytes() const {return m_size*sizeof(T);} + + /// \brief Sets the number of elements to zeroize + /// \param count the number of elements + /// \details SetMark is a remediation for Issue 346/CVE-2016-9939 while + /// preserving the streaming interface. The count controls the number of + /// elements zeroized, which can be less than size or 0. + /// \details An internal variable, m_mark, is initialized to the maximum number + /// of elements. The maximum number of elements is ELEMS_MAX. Deallocation + /// triggers a zeroization, and the number of elements zeroized is + /// STDMIN(m_size, m_mark). After zeroization, the memory is returned to the + /// system. + /// \details The ASN.1 decoder uses SetMark() to set the element count to 0 + /// before throwing an exception. In this case, the attacker provides a large + /// BER encoded length (say 64MB) but only a small number of content octets + /// (say 16). If the allocator zeroized all 64MB, then a transient DoS could + /// occur as CPU cycles are spent zeroizing unintialized memory. + /// \details Generally speaking, any operation which changes the size of the SecBlock + /// results in the mark being reset to ELEMS_MAX. In particular, if Assign(), + /// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to + /// ELEMS_MAX. The list is not exhaustive. + /// \since Crypto++ 6.0 + /// \sa Issue 346/CVE-2016-9939 + void SetMark(size_t count) {m_mark = count;} + + /// \brief Set contents and size from an array + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// Assign() resets the element count after the previous block is zeroized. + void Assign(const T *ptr, size_type len) + { + New(len); + if (m_ptr && ptr) // GCC analyzer warning + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + m_mark = ELEMS_MAX; + } + + /// \brief Set contents from a value + /// \param count the number of values to copy + /// \param value the value, repeated count times + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// Assign() resets the element count after the previous block is zeroized. + void Assign(size_type count, T value) + { + New(count); + for (size_t i=0; i &t) + { + if (this != &t) + { + New(t.m_size); + if (m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T)); + } + m_mark = ELEMS_MAX; + } + + /// \brief Assign contents from another SecBlock + /// \param t the other SecBlock + /// \details Internally, operator=() calls Assign(). + /// \details If the memory block is reduced in size, then the reclaimed memory is set to 0. + /// If an assignment occurs, then Assign() resets the element count after the previous block + /// is zeroized. + SecBlock& operator=(const SecBlock &t) + { + // Assign guards for self-assignment + Assign(t); + return *this; + } + + /// \brief Append contents from another SecBlock + /// \param t the other SecBlock + /// \details Internally, this SecBlock calls Grow and then appends t. + SecBlock& operator+=(const SecBlock &t) + { + CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); + if (t.m_size) + { + const size_type oldSize = m_size; + if (this != &t) // s += t + { + Grow(m_size+t.m_size); + if (m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + } + else // t += t + { + Grow(m_size*2); + if (m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T)); + } + } + m_mark = ELEMS_MAX; + return *this; + } + + /// \brief Construct a SecBlock from this and another SecBlock + /// \param t the other SecBlock + /// \return a newly constructed SecBlock that is a conacentation of this and t + /// \details Internally, a new SecBlock is created from this and a concatenation of t. + SecBlock operator+(const SecBlock &t) + { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); + if(!t.m_size) return SecBlock(*this); + + SecBlock result(m_size+t.m_size); + if (m_size) + memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T)); + if (result.m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + return result; + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \return true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. The constant time + /// compare is VerifyBufsEqual() found in misc.h. + /// \sa operator!=() + bool operator==(const SecBlock &t) const + { + return m_size == t.m_size && VerifyBufsEqual( + reinterpret_cast(m_ptr), + reinterpret_cast(t.m_ptr), m_size*sizeof(T)); + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \return true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. The constant time + /// compare is VerifyBufsEqual() found in misc.h. + /// \details Internally, operator!=() returns the inverse of operator==(). + /// \sa operator==() + bool operator!=(const SecBlock &t) const + { + return !operator==(t); + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is reduced in size, + /// then the reclaimed memory is set to 0. If the memory block grows in size, then + /// the new memory is not initialized. New() resets the element count after the + /// previous block is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void New(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is reduced in size, + /// then the reclaimed content is set to 0. If the memory block grows in size, then + /// the new memory is initialized to 0. CleanNew() resets the element count after the + /// previous block is zeroized. + /// \details Internally, this SecBlock calls New(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanNew(size_type newSize) + { + New(newSize); + if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));} + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is not initialized. + /// \details Internally, this SecBlock calls reallocate() when size must increase. If the + /// size does not increase, then Grow() does not take action. If the size must + /// change, then use resize(). Grow() resets the element count after the + /// previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void Grow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is initialized to 0. + /// \details Internally, this SecBlock calls reallocate() when size must increase. If the + /// size does not increase, then CleanGrow() does not take action. If the size must + /// change, then use resize(). CleanGrow() resets the element count after the + /// previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void CleanGrow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. If the memory block grows in size, then + /// new memory is not initialized. resize() resets the element count after + /// the previous block is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + void resize(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Swap contents with another SecBlock + /// \param b the other SecBlock + /// \details Internally, std::swap() is called on m_alloc, m_size and m_ptr. + void swap(SecBlock &b) + { + // Swap must occur on the allocator in case its FixedSize that spilled into the heap. + std::swap(m_alloc, b.m_alloc); + std::swap(m_mark, b.m_mark); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); + } + +protected: + A m_alloc; + size_type m_mark, m_size; + T *m_ptr; +}; + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref SecBlock "SecBlock" typedef. +class SecByteBlock : public SecBlock {}; +/// \brief \ref SecBlock "SecBlock" typedef. +class SecWordBlock : public SecBlock {}; +/// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup" typedef +class AlignedSecByteBlock : public SecBlock > {}; +#else +typedef SecBlock SecByteBlock; +typedef SecBlock SecWordBlock; +typedef SecBlock > AlignedSecByteBlock; +#endif + +// No need for move semantics on derived class *if* the class does not add any +// data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}. + +/// \brief Fixed size stack-based SecBlock +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > +class FixedSizeSecBlock : public SecBlock +{ +public: + /// \brief Construct a FixedSizeSecBlock + explicit FixedSizeSecBlock() : SecBlock(S) {} +}; + +/// \brief Fixed size stack-based SecBlock with 16-byte alignment +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +template +class FixedSizeAlignedSecBlock : public FixedSizeSecBlock, T_Align16> > +{ +}; + +/// \brief Stack-based SecBlock that grows into the heap +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > > +class SecBlockWithHint : public SecBlock +{ +public: + /// construct a SecBlockWithHint with a count of elements + explicit SecBlockWithHint(size_t size) : SecBlock(size) {} +}; + +template +inline bool operator==(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (true);} +template +inline bool operator!=(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) + +/// \brief Swap two SecBlocks +/// \tparam T class or type +/// \tparam A AllocatorBase derived class for allocation and cleanup +/// \param a the first SecBlock +/// \param b the second SecBlock +template +inline void swap(CryptoPP::SecBlock &a, CryptoPP::SecBlock &b) +{ + a.swap(b); +} + +#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)) +// working for STLport 5.1.3 and MSVC 6 SP5 +template +inline CryptoPP::AllocatorWithCleanup<_Tp2>& +__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) +{ + return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); +} +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/secblockfwd.h b/extension/third_party/cryptopp/secblockfwd.h new file mode 100644 index 00000000..d17068ee --- /dev/null +++ b/extension/third_party/cryptopp/secblockfwd.h @@ -0,0 +1,29 @@ +// secblockfwd.h - written and placed in the public domain by Jeffrey Walton + +/// \file secblockfwd.h +/// \brief Forward declarations for SecBlock +/// \details secblock.h and misc.h have a circular dependency. secblockfwd.h +/// allows the library to sidestep the circular dependency, and reference +/// SecBlock classes without the full implementation. +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_SECBLOCKFWD_H +#define CRYPTOPP_SECBLOCKFWD_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +template +class SecBlock; + +template +class AllocatorWithCleanup; + +typedef SecBlock > SecByteBlock; +typedef SecBlock > SecWordBlock; +typedef SecBlock > AlignedSecByteBlock; + +NAMESPACE_END + +#endif // CRYPTOPP_SECBLOCKFWD_H diff --git a/extension/third_party/cryptopp/seckey.h b/extension/third_party/cryptopp/seckey.h new file mode 100644 index 00000000..2b0b2b89 --- /dev/null +++ b/extension/third_party/cryptopp/seckey.h @@ -0,0 +1,444 @@ +// seckey.h - originally written and placed in the public domain by Wei Dai + +/// \file seckey.h +/// \brief Classes and functions for implementing secret key algorithms. + +#ifndef CRYPTOPP_SECKEY_H +#define CRYPTOPP_SECKEY_H + +#include "config.h" +#include "cryptlib.h" +#include "misc.h" +#include "simple.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4189 4296) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Inverts the cipher's direction +/// \param dir the cipher's direction +/// \return DECRYPTION if \ref CipherDir "dir" is ENCRYPTION, DECRYPTION otherwise +inline CipherDir ReverseCipherDir(CipherDir dir) +{ + return (dir == ENCRYPTION) ? DECRYPTION : ENCRYPTION; +} + +/// \brief Inherited by algorithms with fixed block size +/// \tparam N the blocksize of the algorithm +template +class FixedBlockSize +{ +public: + /// \brief The block size of the algorithm provided as a constant. + CRYPTOPP_CONSTANT(BLOCKSIZE = N); +}; + +// ************** rounds *************** + +/// \brief Inherited by algorithms with fixed number of rounds +/// \tparam R the number of rounds used by the algorithm +template +class FixedRounds +{ +public: + /// \brief The number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(ROUNDS = R); +}; + +/// \brief Inherited by algorithms with variable number of rounds +/// \tparam D Default number of rounds +/// \tparam N Minimum number of rounds +/// \tparam M Maximum number of rounds +template // use INT_MAX here because enums are treated as signed ints +class VariableRounds +{ +public: + /// \brief The default number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(DEFAULT_ROUNDS = D); + /// \brief The minimum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MIN_ROUNDS = N); + /// \brief The maximum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MAX_ROUNDS = M); + /// \brief The default number of rounds for the algorithm based on key length + /// provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details keylength is unused in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR unsigned int StaticGetDefaultRounds(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(DEFAULT_ROUNDS); + } + +protected: + /// \brief Validates the number of rounds for an algorithm. + /// \param rounds the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \throw InvalidRounds if the number of rounds are invalid + /// \details ThrowIfInvalidRounds() validates the number of rounds and throws if invalid. + inline void ThrowIfInvalidRounds(int rounds, const Algorithm *alg) + { + if (M == INT_MAX) // Coverity and result_independent_of_operands + { + if (rounds < MIN_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + else + { + if (rounds < MIN_ROUNDS || rounds > MAX_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + } + + /// \brief Validates the number of rounds for an algorithm + /// \param param the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \return the number of rounds for the algorithm + /// \throw InvalidRounds if the number of rounds are invalid + /// \details GetRoundsAndThrowIfInvalid() validates the number of rounds and throws if invalid. + inline unsigned int GetRoundsAndThrowIfInvalid(const NameValuePairs ¶m, const Algorithm *alg) + { + int rounds = param.GetIntValueWithDefault("Rounds", DEFAULT_ROUNDS); + ThrowIfInvalidRounds(rounds, alg); + return static_cast(rounds); + } +}; + +// ************** key length *************** + +/// \brief Inherited by keyed algorithms with fixed key length +/// \tparam N Default key length, in bytes +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class FixedKeyLength +{ +public: + /// \brief The default key length used by the algorithm provided as a constant + /// \details KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH=N); + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=N); + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=N); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT = IV_REQ); + /// \brief The default IV length used by the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH = IV_L); + /// \brief The default key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details The default implementation returns KEYLENGTH. keylength is unused + /// in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(KEYLENGTH); + } +}; + +/// \brief Inherited by keyed algorithms with variable key length +/// \tparam D Default key length, in bytes +/// \tparam N Minimum key length, in bytes +/// \tparam M Maximum key length, in bytes +/// \tparam Q Default key length multiple, in bytes. The default multiple is 1. +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes. The default length is 0. +/// \sa SimpleKeyingInterface +template +class VariableKeyLength +{ + // Make these private to avoid Doxygen documenting them in all derived classes + CRYPTOPP_COMPILE_ASSERT(Q > 0); + CRYPTOPP_COMPILE_ASSERT(N % Q == 0); + CRYPTOPP_COMPILE_ASSERT(M % Q == 0); + CRYPTOPP_COMPILE_ASSERT(N < M); + CRYPTOPP_COMPILE_ASSERT(D >= N); + CRYPTOPP_COMPILE_ASSERT(M >= D); + +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=M); + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=D); + /// \brief The key length multiple used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH_MULTIPLE=Q); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ); + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L); + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return (keylength <= N) ? N : + (keylength >= M) ? M : + (keylength+Q-1) - (keylength+Q-1)%Q; + } +}; + +/// \brief Provides key lengths based on another class's key length +/// \tparam T another FixedKeyLength or VariableKeyLength class +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class SameKeyLengthAs +{ +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=T::MIN_KEYLENGTH); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=T::MAX_KEYLENGTH); + /// \brief The default key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=T::DEFAULT_KEYLENGTH); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ); + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L); + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + {return T::StaticGetValidKeyLength(keylength);} +}; + +// ************** implementation helper for SimpleKeyingInterface *************** + +/// \brief Provides a base implementation of SimpleKeyingInterface +/// \tparam BASE a SimpleKeyingInterface derived class +/// \tparam INFO a SimpleKeyingInterface derived class +/// \details SimpleKeyingInterfaceImpl() provides a default implementation for ciphers providing a keying interface. +/// Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface() +template +class CRYPTOPP_NO_VTABLE SimpleKeyingInterfaceImpl : public BASE +{ +public: + /// \brief The minimum key length used by the algorithm + /// \return minimum key length used by the algorithm, in bytes + size_t MinKeyLength() const + {return INFO::MIN_KEYLENGTH;} + + /// \brief The maximum key length used by the algorithm + /// \return maximum key length used by the algorithm, in bytes + size_t MaxKeyLength() const + {return static_cast(INFO::MAX_KEYLENGTH);} + + /// \brief The default key length used by the algorithm + /// \return default key length used by the algorithm, in bytes + size_t DefaultKeyLength() const + {return INFO::DEFAULT_KEYLENGTH;} + + /// \brief Provides a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + size_t GetValidKeyLength(size_t keylength) const {return INFO::StaticGetValidKeyLength(keylength);} + + /// \brief The default IV requirements for the algorithm + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + SimpleKeyingInterface::IV_Requirement IVRequirement() const + {return static_cast(INFO::IV_REQUIREMENT);} + + /// \brief The initialization vector length for the algorithm + /// \details IVSize is provided in bytes, not bits. The default implementation uses + /// IV_LENGTH, which is 0. + unsigned int IVSize() const + {return INFO::IV_LENGTH;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for block ciphers +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details BlockCipherImpl() provides a default implementation for block ciphers using AlgorithmImpl() +/// and SimpleKeyingInterfaceImpl(). Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class CRYPTOPP_NO_VTABLE BlockCipherImpl : public AlgorithmImpl > > +{ +public: + /// Provides the block size of the algorithm + /// \return the block size of the algorithm, in bytes + unsigned int BlockSize() const {return this->BLOCKSIZE;} +}; + +/// \brief Provides class member functions to key a block cipher +/// \tparam DIR a CipherDir +/// \tparam BASE a BlockCipherImpl derived class +template +class BlockCipherFinal : public ClonableImpl, BASE> +{ +public: + /// \brief Construct a default BlockCipherFinal + /// \details The cipher is not keyed. + BlockCipherFinal() {} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \param rounds the number of rounds + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKeyWithRounds. + BlockCipherFinal(const byte *key, size_t length, unsigned int rounds) + {this->SetKeyWithRounds(key, length, rounds);} + + /// \brief Provides the direction of the cipher + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa GetCipherDirection(), IsPermutation() + bool IsForwardTransformation() const {return DIR == ENCRYPTION;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for message authentication codes +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details MessageAuthenticationCodeImpl() provides a default implementation for message authentication codes +/// using AlgorithmImpl() and SimpleKeyingInterfaceImpl(). Functions are virtual and not subject to C++11 +/// constexpr. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class MessageAuthenticationCodeImpl : public AlgorithmImpl, INFO> +{ +}; + +/// \brief Provides class member functions to key a message authentication code +/// \tparam BASE a BlockCipherImpl derived class +/// \details A default implementation for MessageAuthenticationCode +template +class MessageAuthenticationCodeFinal : public ClonableImpl, MessageAuthenticationCodeImpl > +{ +public: + /// \brief Construct a default MessageAuthenticationCodeFinal + /// \details The message authentication code is not keyed. + MessageAuthenticationCodeFinal() {} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key, size_t length) + {this->SetKey(key, length);} +}; + +// ************** documentation *************** + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a block cipher +/// \details These objects usually should not be used directly. See CipherModeDocumentation +/// instead. Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the BlockCipher interface. +struct BlockCipherDocumentation +{ + /// implements the BlockCipher interface + typedef BlockCipher Encryption; + /// implements the BlockCipher interface + typedef BlockCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a symmetric cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. Two types of classes derive +/// from this class: stream ciphers and block cipher modes. Stream ciphers can be used +/// alone, cipher mode classes need to be used with a block cipher. See CipherModeDocumentation +/// for more for information about using cipher modes and block ciphers. +struct SymmetricCipherDocumentation +{ + /// implements the SymmetricCipher interface + typedef SymmetricCipher Encryption; + /// implements the SymmetricCipher interface + typedef SymmetricCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement an authenticated encryption cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the AuthenticatedSymmetricCipher interface. +struct AuthenticatedSymmetricCipherDocumentation +{ + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Encryption; + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Decryption; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/extension/third_party/cryptopp/seed.cpp b/extension/third_party/cryptopp/seed.cpp new file mode 100644 index 00000000..4e99d759 --- /dev/null +++ b/extension/third_party/cryptopp/seed.cpp @@ -0,0 +1,113 @@ +// seed.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "seed.h" +#include "misc.h" +#include "stdcpp.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; + +const word32 s_kc[16] = { + 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc, 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf, + 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1, 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b}; + +const byte s_s0[256] = { + 0xA9, 0x85, 0xD6, 0xD3, 0x54, 0x1D, 0xAC, 0x25, 0x5D, 0x43, 0x18, 0x1E, 0x51, 0xFC, 0xCA, 0x63, 0x28, + 0x44, 0x20, 0x9D, 0xE0, 0xE2, 0xC8, 0x17, 0xA5, 0x8F, 0x03, 0x7B, 0xBB, 0x13, 0xD2, 0xEE, 0x70, 0x8C, + 0x3F, 0xA8, 0x32, 0xDD, 0xF6, 0x74, 0xEC, 0x95, 0x0B, 0x57, 0x5C, 0x5B, 0xBD, 0x01, 0x24, 0x1C, 0x73, + 0x98, 0x10, 0xCC, 0xF2, 0xD9, 0x2C, 0xE7, 0x72, 0x83, 0x9B, 0xD1, 0x86, 0xC9, 0x60, 0x50, 0xA3, 0xEB, + 0x0D, 0xB6, 0x9E, 0x4F, 0xB7, 0x5A, 0xC6, 0x78, 0xA6, 0x12, 0xAF, 0xD5, 0x61, 0xC3, 0xB4, 0x41, 0x52, + 0x7D, 0x8D, 0x08, 0x1F, 0x99, 0x00, 0x19, 0x04, 0x53, 0xF7, 0xE1, 0xFD, 0x76, 0x2F, 0x27, 0xB0, 0x8B, + 0x0E, 0xAB, 0xA2, 0x6E, 0x93, 0x4D, 0x69, 0x7C, 0x09, 0x0A, 0xBF, 0xEF, 0xF3, 0xC5, 0x87, 0x14, 0xFE, + 0x64, 0xDE, 0x2E, 0x4B, 0x1A, 0x06, 0x21, 0x6B, 0x66, 0x02, 0xF5, 0x92, 0x8A, 0x0C, 0xB3, 0x7E, 0xD0, + 0x7A, 0x47, 0x96, 0xE5, 0x26, 0x80, 0xAD, 0xDF, 0xA1, 0x30, 0x37, 0xAE, 0x36, 0x15, 0x22, 0x38, 0xF4, + 0xA7, 0x45, 0x4C, 0x81, 0xE9, 0x84, 0x97, 0x35, 0xCB, 0xCE, 0x3C, 0x71, 0x11, 0xC7, 0x89, 0x75, 0xFB, + 0xDA, 0xF8, 0x94, 0x59, 0x82, 0xC4, 0xFF, 0x49, 0x39, 0x67, 0xC0, 0xCF, 0xD7, 0xB8, 0x0F, 0x8E, 0x42, + 0x23, 0x91, 0x6C, 0xDB, 0xA4, 0x34, 0xF1, 0x48, 0xC2, 0x6F, 0x3D, 0x2D, 0x40, 0xBE, 0x3E, 0xBC, 0xC1, + 0xAA, 0xBA, 0x4E, 0x55, 0x3B, 0xDC, 0x68, 0x7F, 0x9C, 0xD8, 0x4A, 0x56, 0x77, 0xA0, 0xED, 0x46, 0xB5, + 0x2B, 0x65, 0xFA, 0xE3, 0xB9, 0xB1, 0x9F, 0x5E, 0xF9, 0xE6, 0xB2, 0x31, 0xEA, 0x6D, 0x5F, 0xE4, 0xF0, + 0xCD, 0x88, 0x16, 0x3A, 0x58, 0xD4, 0x62, 0x29, 0x07, 0x33, 0xE8, 0x1B, 0x05, 0x79, 0x90, 0x6A, 0x2A, + 0x9A}; + +static const byte s_s1[256] = { + 0x38, 0xE8, 0x2D, 0xA6, 0xCF, 0xDE, 0xB3, 0xB8, 0xAF, 0x60, 0x55, 0xC7, 0x44, 0x6F, 0x6B, 0x5B, 0xC3, + 0x62, 0x33, 0xB5, 0x29, 0xA0, 0xE2, 0xA7, 0xD3, 0x91, 0x11, 0x06, 0x1C, 0xBC, 0x36, 0x4B, 0xEF, 0x88, + 0x6C, 0xA8, 0x17, 0xC4, 0x16, 0xF4, 0xC2, 0x45, 0xE1, 0xD6, 0x3F, 0x3D, 0x8E, 0x98, 0x28, 0x4E, 0xF6, + 0x3E, 0xA5, 0xF9, 0x0D, 0xDF, 0xD8, 0x2B, 0x66, 0x7A, 0x27, 0x2F, 0xF1, 0x72, 0x42, 0xD4, 0x41, 0xC0, + 0x73, 0x67, 0xAC, 0x8B, 0xF7, 0xAD, 0x80, 0x1F, 0xCA, 0x2C, 0xAA, 0x34, 0xD2, 0x0B, 0xEE, 0xE9, 0x5D, + 0x94, 0x18, 0xF8, 0x57, 0xAE, 0x08, 0xC5, 0x13, 0xCD, 0x86, 0xB9, 0xFF, 0x7D, 0xC1, 0x31, 0xF5, 0x8A, + 0x6A, 0xB1, 0xD1, 0x20, 0xD7, 0x02, 0x22, 0x04, 0x68, 0x71, 0x07, 0xDB, 0x9D, 0x99, 0x61, 0xBE, 0xE6, + 0x59, 0xDD, 0x51, 0x90, 0xDC, 0x9A, 0xA3, 0xAB, 0xD0, 0x81, 0x0F, 0x47, 0x1A, 0xE3, 0xEC, 0x8D, 0xBF, + 0x96, 0x7B, 0x5C, 0xA2, 0xA1, 0x63, 0x23, 0x4D, 0xC8, 0x9E, 0x9C, 0x3A, 0x0C, 0x2E, 0xBA, 0x6E, 0x9F, + 0x5A, 0xF2, 0x92, 0xF3, 0x49, 0x78, 0xCC, 0x15, 0xFB, 0x70, 0x75, 0x7F, 0x35, 0x10, 0x03, 0x64, 0x6D, + 0xC6, 0x74, 0xD5, 0xB4, 0xEA, 0x09, 0x76, 0x19, 0xFE, 0x40, 0x12, 0xE0, 0xBD, 0x05, 0xFA, 0x01, 0xF0, + 0x2A, 0x5E, 0xA9, 0x56, 0x43, 0x85, 0x14, 0x89, 0x9B, 0xB0, 0xE5, 0x48, 0x79, 0x97, 0xFC, 0x1E, 0x82, + 0x21, 0x8C, 0x1B, 0x5F, 0x77, 0x54, 0xB2, 0x1D, 0x25, 0x4F, 0x00, 0x46, 0xED, 0x58, 0x52, 0xEB, 0x7E, + 0xDA, 0xC9, 0xFD, 0x30, 0x95, 0x65, 0x3C, 0xB6, 0xE4, 0xBB, 0x7C, 0x0E, 0x50, 0x39, 0x26, 0x32, 0x84, + 0x69, 0x93, 0x37, 0xE7, 0x24, 0xA4, 0xCB, 0x53, 0x0A, 0x87, 0xD9, 0x4C, 0x83, 0x8F, 0xCE, 0x3B, 0x4A, + 0xB7}; + +#define SS0(x) ((s_s0[x]*0x01010101UL) & 0x3FCFF3FC) +#define SS1(x) ((s_s1[x]*0x01010101UL) & 0xFC3FCFF3) +#define SS2(x) ((s_s0[x]*0x01010101UL) & 0xF3FC3FCF) +#define SS3(x) ((s_s1[x]*0x01010101UL) & 0xCFF3FC3F) +#define G(x) (SS0(GETBYTE(x, 0)) ^ SS1(GETBYTE(x, 1)) ^ SS2(GETBYTE(x, 2)) ^ SS3(GETBYTE(x, 3))) + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void SEED::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs& /*params*/) +{ + AssertValidKeyLength(length); + + word64 key01, key23; + GetBlock get(userKey); + get(key01)(key23); + word32 *k = m_k; + ptrdiff_t kInc = 2; + + if (!IsForwardTransformation()) + { + k = k+30; + kInc = 0-kInc; + } + + for (unsigned int i=0; i>32) + word32(key23>>32) - s_kc[i]; + word32 t1 = word32(key01) - word32(key23) + s_kc[i]; + k[0] = G(t0); + k[1] = G(t1); + k+=kInc; + if (i&1) + key23 = rotlConstant<8,word64>(key23); + else + key01 = rotrConstant<8,word64>(key01); + } +} + +void SEED::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + typedef BlockGetAndPut Block; + word32 a0, a1, b0, b1, t0, t1; + Block::Get(inBlock)(a0)(a1)(b0)(b1); + + for (int i=0; i, public FixedKeyLength<16>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SEED";} +}; + +/// \brief SEED block cipher +/// \sa SEED +/// \since Crypto++ 5.6.0 +class SEED : public SEED_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_k; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/serpent.cpp b/extension/third_party/cryptopp/serpent.cpp new file mode 100644 index 00000000..351186ce --- /dev/null +++ b/extension/third_party/cryptopp/serpent.cpp @@ -0,0 +1,125 @@ +// serpent.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "serpent.h" +#include "secblock.h" +#include "misc.h" + +#include "serpentp.h" + +NAMESPACE_BEGIN(CryptoPP) + +void Serpent_KeySchedule(word32 *k, unsigned int rounds, const byte *userKey, size_t keylen) +{ + FixedSizeSecBlock k0; + GetUserKey(LITTLE_ENDIAN_ORDER, k0.begin(), 8, userKey, keylen); + if (keylen < 32) + k0[keylen/4] |= word32(1) << ((keylen%4)*8); + + word32 t = k0[7]; + unsigned int i; + for (i = 0; i < 8; ++i) + k[i] = k0[i] = t = rotlConstant<11>(k0[i] ^ k0[(i + 3) % 8] ^ k0[(i + 5) % 8] ^ t ^ 0x9e3779b9 ^ i); + for (i = 8; i < 4*(rounds+1); ++i) + k[i] = t = rotlConstant<11>(k[i-8] ^ k[i-5] ^ k[i-3] ^ t ^ 0x9e3779b9 ^ i); + k -= 20; + + word32 a,b,c,d,e; + for (i=0; i Block; + +void Serpent::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, e; + + Block::Get(inBlock)(a)(b)(c)(d); + + const word32 *k = m_key; + unsigned int i=1; + + do + { + beforeS0(KX); beforeS0(S0); afterS0(LT); + afterS0(KX); afterS0(S1); afterS1(LT); + afterS1(KX); afterS1(S2); afterS2(LT); + afterS2(KX); afterS2(S3); afterS3(LT); + afterS3(KX); afterS3(S4); afterS4(LT); + afterS4(KX); afterS4(S5); afterS5(LT); + afterS5(KX); afterS5(S6); afterS6(LT); + afterS6(KX); afterS6(S7); + + if (i == 4) + break; + + ++i; + c = b; + b = e; + e = d; + d = a; + a = e; + k += 32; + beforeS0(LT); + } + while (true); + + afterS7(KX); + + Block::Put(xorBlock, outBlock)(d)(e)(b)(a); +} + +void Serpent::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, e=0; + + Block::Get(inBlock)(a)(b)(c)(d); + + const word32 *k = m_key + 96; + unsigned int i=4; + + beforeI7(KX); + goto start; + + do + { + c = b; + b = d; + d = e; + k -= 32; + beforeI7(ILT); +start: + beforeI7(I7); afterI7(KX); + afterI7(ILT); afterI7(I6); afterI6(KX); + afterI6(ILT); afterI6(I5); afterI5(KX); + afterI5(ILT); afterI5(I4); afterI4(KX); + afterI4(ILT); afterI4(I3); afterI3(KX); + afterI3(ILT); afterI3(I2); afterI2(KX); + afterI2(ILT); afterI2(I1); afterI1(KX); + afterI1(ILT); afterI1(I0); afterI0(KX); + } + while (--i != 0); + + Block::Put(xorBlock, outBlock)(a)(d)(b)(e); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/serpent.h b/extension/third_party/cryptopp/serpent.h new file mode 100644 index 00000000..bd3cedbe --- /dev/null +++ b/extension/third_party/cryptopp/serpent.h @@ -0,0 +1,72 @@ +// serpent.h - originally written and placed in the public domain by Wei Dai + +/// \file serpent.h +/// \brief Classes for the Serpent block cipher +/// \sa A +/// Candidate Block Cipher for the Advanced Encryption Standard + +#ifndef CRYPTOPP_SERPENT_H +#define CRYPTOPP_SERPENT_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Serpent block cipher information +/// \since Crypto++ 3.1 +struct Serpent_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public FixedRounds<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Serpent";} +}; + +/// \brief Serpent block cipher +/// \sa Serpent on the +/// Crypto++ wiki, A +/// Candidate Block Cipher for the Advanced Encryption Standard +/// \since Crypto++ 3.1 +class Serpent : public Serpent_Info, public BlockCipherDocumentation +{ + /// \brief Serpen block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_key; + }; + + /// \brief Serpent encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Serpent decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Serpent::Encryption SerpentEncryption; +typedef Serpent::Decryption SerpentDecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_SERPENT_H diff --git a/extension/third_party/cryptopp/serpentp.h b/extension/third_party/cryptopp/serpentp.h new file mode 100644 index 00000000..8df3cb8a --- /dev/null +++ b/extension/third_party/cryptopp/serpentp.h @@ -0,0 +1,439 @@ +// private header for Serpent and Sosemanuk + +#ifndef CRYPTOPP_SERPENTP_H +#define CRYPTOPP_SERPENTP_H + +NAMESPACE_BEGIN(CryptoPP) + +// linear transformation +#define LT(i,a,b,c,d,e) {\ + a = rotlConstant<13>(a); \ + c = rotlConstant<3>(c); \ + d = rotlConstant<7>(d ^ c ^ (a << 3)); \ + b = rotlConstant<1>(b ^ a ^ c); \ + a = rotlConstant<5>(a ^ b ^ d); \ + c = rotlConstant<22>(c ^ d ^ (b << 7));} + +// inverse linear transformation +#define ILT(i,a,b,c,d,e) {\ + c = rotrConstant<22>(c); \ + a = rotrConstant<5>(a); \ + c ^= d ^ (b << 7); \ + a ^= b ^ d; \ + b = rotrConstant<1>(b); \ + d = rotrConstant<7>(d) ^ c ^ (a << 3); \ + b ^= a ^ c; \ + c = rotrConstant<3>(c); \ + a = rotrConstant<13>(a);} + +// order of output from S-box functions +#define beforeS0(f) f(0,a,b,c,d,e) +#define afterS0(f) f(1,b,e,c,a,d) +#define afterS1(f) f(2,c,b,a,e,d) +#define afterS2(f) f(3,a,e,b,d,c) +#define afterS3(f) f(4,e,b,d,c,a) +#define afterS4(f) f(5,b,a,e,c,d) +#define afterS5(f) f(6,a,c,b,e,d) +#define afterS6(f) f(7,a,c,d,b,e) +#define afterS7(f) f(8,d,e,b,a,c) + +// order of output from inverse S-box functions +#define beforeI7(f) f(8,a,b,c,d,e) +#define afterI7(f) f(7,d,a,b,e,c) +#define afterI6(f) f(6,a,b,c,e,d) +#define afterI5(f) f(5,b,d,e,c,a) +#define afterI4(f) f(4,b,c,e,a,d) +#define afterI3(f) f(3,a,b,e,c,d) +#define afterI2(f) f(2,b,d,e,c,a) +#define afterI1(f) f(1,a,b,c,e,d) +#define afterI0(f) f(0,a,d,b,e,c) + +// The instruction sequences for the S-box functions +// come from Dag Arne Osvik's paper "Speeding up Serpent". + +#define S0(i, r0, r1, r2, r3, r4) \ + { \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r4 ^= r2; \ + r1 ^= r0; \ + r0 |= r3; \ + r0 ^= r4; \ + r4 ^= r3; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 ^= r4; \ + r4 = ~r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r1 ^= r4; \ + r3 |= r0; \ + r1 ^= r3; \ + r4 ^= r3; \ + } + +#define I0(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r1; \ + r1 |= r0; \ + r4 = ~r4; \ + r1 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 &= r3; \ + r4 ^= r0; \ + r0 |= r1; \ + r0 ^= r2; \ + r3 ^= r4; \ + r2 ^= r1; \ + r3 ^= r0; \ + r3 ^= r1; \ + r2 &= r3; \ + r4 ^= r2; \ + } + +#define S1(i, r0, r1, r2, r3, r4) \ + { \ + r0 = ~r0; \ + r2 = ~r2; \ + r4 = r0; \ + r0 &= r1; \ + r2 ^= r0; \ + r0 |= r3; \ + r3 ^= r2; \ + r1 ^= r0; \ + r0 ^= r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r2 |= r0; \ + r2 &= r4; \ + r0 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r2; \ + r0 ^= r4; \ + } + +#define I1(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r1; \ + r1 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r3 ^= r0; \ + r0 |= r1; \ + r2 ^= r3; \ + r0 ^= r4; \ + r0 |= r2; \ + r1 ^= r3; \ + r0 ^= r1; \ + r1 |= r3; \ + r1 ^= r0; \ + r4 = ~r4; \ + r4 ^= r1; \ + r1 |= r0; \ + r1 ^= r0; \ + r1 |= r4; \ + r3 ^= r1; \ + } + +#define S2(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 &= r2; \ + r0 ^= r3; \ + r2 ^= r1; \ + r2 ^= r0; \ + r3 |= r4; \ + r3 ^= r1; \ + r4 ^= r2; \ + r1 = r3; \ + r3 |= r4; \ + r3 ^= r0; \ + r0 &= r1; \ + r4 ^= r0; \ + r1 ^= r3; \ + r1 ^= r4; \ + r4 = ~r4; \ + } + +#define I2(i, r0, r1, r2, r3, r4) \ + { \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r3; \ + r3 &= r2; \ + r3 ^= r1; \ + r1 |= r2; \ + r1 ^= r4; \ + r4 &= r3; \ + r2 ^= r3; \ + r4 &= r0; \ + r4 ^= r2; \ + r2 &= r1; \ + r2 |= r0; \ + r3 = ~r3; \ + r2 ^= r3; \ + r0 ^= r3; \ + r0 &= r1; \ + r3 ^= r4; \ + r3 ^= r0; \ + } + +#define S3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 |= r3; \ + r3 ^= r1; \ + r1 &= r4; \ + r4 ^= r2; \ + r2 ^= r3; \ + r3 &= r0; \ + r4 |= r1; \ + r3 ^= r4; \ + r0 ^= r1; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r2; \ + r1 |= r0; \ + r1 ^= r2; \ + r0 ^= r3; \ + r2 = r1; \ + r1 |= r3; \ + r1 ^= r0; \ + } + +#define I3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r4; \ + r4 ^= r3; \ + r3 |= r1; \ + r3 ^= r2; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 |= r3; \ + r0 ^= r1; \ + r4 ^= r2; \ + r2 &= r3; \ + r1 |= r3; \ + r1 ^= r2; \ + r4 ^= r0; \ + r2 ^= r4; \ + } + +#define S4(i, r0, r1, r2, r3, r4) \ + { \ + r1 ^= r3; \ + r3 = ~r3; \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r1 ^= r2; \ + r4 ^= r3; \ + r0 ^= r4; \ + r2 &= r4; \ + r2 ^= r0; \ + r0 &= r1; \ + r3 ^= r0; \ + r4 |= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r2 &= r3; \ + r0 = ~r0; \ + r4 ^= r2; \ + } + +#define I4(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r3; \ + r2 ^= r1; \ + r1 |= r3; \ + r1 &= r0; \ + r4 ^= r2; \ + r4 ^= r1; \ + r1 &= r2; \ + r0 = ~r0; \ + r3 ^= r4; \ + r1 ^= r3; \ + r3 &= r0; \ + r3 ^= r2; \ + r0 ^= r1; \ + r2 &= r0; \ + r3 ^= r0; \ + r2 ^= r4; \ + r2 |= r3; \ + r3 ^= r0; \ + r2 ^= r1; \ + } + +#define S5(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r1; \ + r1 ^= r3; \ + r3 = ~r3; \ + r4 = r1; \ + r1 &= r0; \ + r2 ^= r3; \ + r1 ^= r2; \ + r2 |= r4; \ + r4 ^= r3; \ + r3 &= r1; \ + r3 ^= r0; \ + r4 ^= r1; \ + r4 ^= r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r0 ^= r4; \ + r4 |= r3; \ + r2 ^= r4; \ + } + +#define I5(i, r0, r1, r2, r3, r4) \ + { \ + r1 = ~r1; \ + r4 = r3; \ + r2 ^= r1; \ + r3 |= r0; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 ^= r4; \ + r4 |= r0; \ + r4 ^= r1; \ + r1 &= r2; \ + r1 ^= r3; \ + r4 ^= r2; \ + r3 &= r4; \ + r4 ^= r1; \ + r3 ^= r0; \ + r3 ^= r4; \ + r4 = ~r4; \ + } + +#define S6(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r3; \ + r3 &= r0; \ + r0 ^= r4; \ + r3 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r2 ^= r0; \ + r0 |= r1; \ + r2 ^= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r4 ^= r3; \ + r4 ^= r0; \ + r3 = ~r3; \ + r2 &= r4; \ + r2 ^= r3; \ + } + +#define I6(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r2; \ + r4 = r2; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 = ~r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r4 |= r0; \ + r0 ^= r2; \ + r3 ^= r4; \ + r4 ^= r1; \ + r1 &= r3; \ + r1 ^= r0; \ + r0 ^= r3; \ + r0 |= r2; \ + r3 ^= r1; \ + r4 ^= r0; \ + } + +#define S7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r1; \ + r2 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r2 ^= r1; \ + r1 ^= r0; \ + r0 |= r4; \ + r0 ^= r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r3 &= r0; \ + r3 ^= r4; \ + r4 ^= r2; \ + r2 &= r0; \ + r4 = ~r4; \ + r2 ^= r4; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r1; \ + } + +#define I7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r4 |= r3; \ + r3 ^= r1; \ + r1 |= r0; \ + r0 ^= r2; \ + r2 &= r4; \ + r1 ^= r2; \ + r2 ^= r0; \ + r0 |= r2; \ + r3 &= r4; \ + r0 ^= r3; \ + r4 ^= r1; \ + r3 ^= r4; \ + r4 |= r0; \ + r3 ^= r2; \ + r4 ^= r2; \ + } + +// key xor +#define KX(r, a, b, c, d, e) {\ + a ^= k[4 * r + 0]; \ + b ^= k[4 * r + 1]; \ + c ^= k[4 * r + 2]; \ + d ^= k[4 * r + 3];} + +#define LK(r, a, b, c, d, e) {\ + a = k[(8-r)*4 + 0]; \ + b = k[(8-r)*4 + 1]; \ + c = k[(8-r)*4 + 2]; \ + d = k[(8-r)*4 + 3];} + +#define SK(r, a, b, c, d, e) {\ + k[(8-r)*4 + 4] = a; \ + k[(8-r)*4 + 5] = b; \ + k[(8-r)*4 + 6] = c; \ + k[(8-r)*4 + 7] = d;} + +void Serpent_KeySchedule(word32 *k, unsigned int rounds, const byte *userKey, size_t keylen); + +NAMESPACE_END + +#endif // CRYPTOPP_SERPENTP_H diff --git a/extension/third_party/cryptopp/sha.cpp b/extension/third_party/cryptopp/sha.cpp new file mode 100644 index 00000000..30d6529f --- /dev/null +++ b/extension/third_party/cryptopp/sha.cpp @@ -0,0 +1,1414 @@ +// sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c + +// Steve Reid implemented SHA-1. Wei Dai implemented SHA-2. Jeffrey +// Walton implemented Intel SHA extensions based on Intel articles and code +// by Sean Gulley. Jeffrey Walton implemented ARM SHA-1 and SHA-256 based +// on ARM code and code from Johannes Schneiders, Skip Hovsmith and +// Barry O'Rourke. Jeffrey Walton and Bill Schmidt implemented Power8 +// SHA-256 and SHA-512. All code is in the public domain. + +// In August 2017 JW reworked the internals to align all the +// implementations. Formerly all hashes were software based, IterHashBase +// handled endian conversions, and IterHashBase dispatched a single to +// block SHA{N}::Transform. SHA{N}::Transform then performed the single +// block hashing. It was repeated for multiple blocks. +// +// The rework added SHA{N}::HashMultipleBlocks (class) and +// SHA{N}_HashMultipleBlocks (free standing). There are also hardware +// accelerated variations. Callers enter SHA{N}::HashMultipleBlocks (class) +// and the function calls SHA{N}_HashMultipleBlocks (free standing) or +// SHA{N}_HashBlock (free standing) as a fallback. +// +// An added wrinkle is hardware is little endian, C++ is big endian, and +// callers use big endian, so SHA{N}_HashMultipleBlock accepts a ByteOrder +// for the incoming data arrangement. Hardware based SHA{N}_HashMultipleBlock +// can often perform the endian swap much easier by setting an EPI mask. +// Endian swap incurs no penalty on Intel SHA, and 4-instruction penalty on +// ARM SHA. Under C++ the full software based swap penalty is incurred due +// to use of ReverseBytes(). +// +// In May 2019 JW added Cryptogams ARMv7 and NEON implementations for SHA1, +// SHA256 and SHA512. The Cryptogams code closed a performance gap on modern +// 32-bit ARM devices. Cryptogams is Andy Polyakov's project used to create +// high speed crypto algorithms and share them with other developers. Andy's +// code runs 30% to 50% faster than C/C++ code. The Cryptogams code can be +// disabled in config_asm.h. An example of integrating Andy's code is at +// https://wiki.openssl.org/index.php/Cryptogams_SHA. + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM sha.cpp" to generate MASM code + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4100 4731) +#endif + +#ifndef CRYPTOPP_IMPORTS +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#include "secblock.h" +#include "sha.h" +#include "misc.h" +#include "cpu.h" + +#if defined(CRYPTOPP_DISABLE_SHA_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_SHANI_AVAILABLE +extern void SHA1_HashMultipleBlocks_SHANI(word32 *state, const word32 *data, size_t length, ByteOrder order); +extern void SHA256_HashMultipleBlocks_SHANI(word32 *state, const word32 *data, size_t length, ByteOrder order); +#endif + +#if CRYPTOGAMS_ARM_SHA1 +extern "C" void cryptogams_sha1_block_data_order(word32* state, const word32 *data, size_t blocks); +extern "C" void cryptogams_sha1_block_data_order_neon(word32* state, const word32 *data, size_t blocks); +#endif + +#if CRYPTOPP_ARM_SHA1_AVAILABLE +extern void SHA1_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order); +#endif + +#if CRYPTOPP_ARM_SHA2_AVAILABLE +extern void SHA256_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order); +#endif + +#if CRYPTOGAMS_ARM_SHA256 +extern "C" void cryptogams_sha256_block_data_order(word32* state, const word32 *data, size_t blocks); +extern "C" void cryptogams_sha256_block_data_order_neon(word32* state, const word32 *data, size_t blocks); +#endif + +#if CRYPTOPP_ARM_SHA512_AVAILABLE +extern void SHA512_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order); +#endif + +#if CRYPTOPP_POWER8_SHA_AVAILABLE +extern void SHA256_HashMultipleBlocks_POWER8(word32 *state, const word32 *data, size_t length, ByteOrder order); +extern void SHA512_HashMultipleBlocks_POWER8(word64 *state, const word64 *data, size_t length, ByteOrder order); +#endif + +#if CRYPTOGAMS_ARM_SHA512 +extern "C" void cryptogams_sha512_block_data_order(word64* state, const word64 *data, size_t blocks); +extern "C" void cryptogams_sha512_block_data_order_neon(word64* state, const word64 *data, size_t blocks); +#endif + +// We add extern to export table to sha_simd.cpp, but it +// cleared http://github.com/weidai11/cryptopp/issues/502 +extern const word32 SHA256_K[64]; +extern const word64 SHA512_K[80]; + +CRYPTOPP_ALIGN_DATA(16) +const word64 SHA512_K[80] = { + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) +}; + +CRYPTOPP_ALIGN_DATA(16) +const word32 SHA256_K[64] = { + + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +//////////////////////////////// +// start of Steve Reid's code // +//////////////////////////////// + +ANONYMOUS_NAMESPACE_BEGIN + +#define blk0(i) (W[i] = data[i]) +#define blk1(i) (W[i&15] = rotlConstant<1>(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15])) + +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rotlConstant<5>(v);w=rotlConstant<30>(w); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rotlConstant<5>(v);w=rotlConstant<30>(w); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rotlConstant<5>(v);w=rotlConstant<30>(w); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rotlConstant<5>(v);w=rotlConstant<30>(w); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rotlConstant<5>(v);w=rotlConstant<30>(w); + +void SHA1_HashBlock_CXX(word32 *state, const word32 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + + word32 W[16]; + /* Copy context->state[] to working vars */ + word32 a = state[0]; + word32 b = state[1]; + word32 c = state[2]; + word32 d = state[3]; + word32 e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +#undef blk0 +#undef blk1 +#undef f1 +#undef f2 +#undef f3 +#undef f4 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +ANONYMOUS_NAMESPACE_END + +////////////////////////////// +// end of Steve Reid's code // +////////////////////////////// + +std::string SHA1::AlgorithmProvider() const +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + return "SHANI"; +#endif +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +#endif +#if CRYPTOGAMS_ARM_SHA1 + if (HasNEON()) + return "NEON"; + if (HasARMv7()) + return "ARMv7"; +#endif +#if CRYPTOPP_ARM_SHA1_AVAILABLE + if (HasSHA1()) + return "ARMv8"; +#endif + return "C++"; +} + +void SHA1::InitState(HashWordType *state) +{ + state[0] = 0x67452301; + state[1] = 0xEFCDAB89; + state[2] = 0x98BADCFE; + state[3] = 0x10325476; + state[4] = 0xC3D2E1F0; +} + +void SHA1::Transform(word32 *state, const word32 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHA1_HashMultipleBlocks_SHANI(state, data, SHA1::BLOCKSIZE, LITTLE_ENDIAN_ORDER); + return; + } +#endif +#if CRYPTOGAMS_ARM_SHA1 && 0 + if (HasNEON()) + { +# if defined(CRYPTOPP_LITTLE_ENDIAN) + word32 dataBuf[16]; + ByteReverse(dataBuf, data, SHA1::BLOCKSIZE); + cryptogams_sha1_block_data_order_neon(state, data, 1); +# else + cryptogams_sha1_block_data_order_neon(state, data, 1); +# endif + return; + } + if (HasARMv7()) + { +# if defined(CRYPTOPP_LITTLE_ENDIAN) + word32 dataBuf[16]; + ByteReverse(dataBuf, data, SHA1::BLOCKSIZE); + cryptogams_sha1_block_data_order(state, data, 1); +# else + cryptogams_sha1_block_data_order(state, data, 1); +# endif + return; + } +#endif +#if CRYPTOPP_ARM_SHA1_AVAILABLE + if (HasSHA1()) + { + SHA1_HashMultipleBlocks_ARMV8(state, data, SHA1::BLOCKSIZE, LITTLE_ENDIAN_ORDER); + return; + } +#endif + + SHA1_HashBlock_CXX(state, data); +} + +size_t SHA1::HashMultipleBlocks(const word32 *input, size_t length) +{ + CRYPTOPP_ASSERT(input); + CRYPTOPP_ASSERT(length >= SHA1::BLOCKSIZE); + +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHA1_HashMultipleBlocks_SHANI(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA1::BLOCKSIZE - 1); + } +#endif +#if CRYPTOGAMS_ARM_SHA1 + if (HasNEON()) + { + cryptogams_sha1_block_data_order_neon(m_state, input, length / SHA1::BLOCKSIZE); + return length & (SHA1::BLOCKSIZE - 1); + } + if (HasARMv7()) + { + cryptogams_sha1_block_data_order(m_state, input, length / SHA1::BLOCKSIZE); + return length & (SHA1::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_ARM_SHA1_AVAILABLE + if (HasSHA1()) + { + SHA1_HashMultipleBlocks_ARMV8(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA1::BLOCKSIZE - 1); + } +#endif + + const bool noReverse = NativeByteOrderIs(this->GetByteOrder()); + word32 *dataBuf = this->DataBuf(); + do + { + if (noReverse) + { + SHA1_HashBlock_CXX(m_state, input); + } + else + { + ByteReverse(dataBuf, input, SHA1::BLOCKSIZE); + SHA1_HashBlock_CXX(m_state, dataBuf); + } + + input += SHA1::BLOCKSIZE/sizeof(word32); + length -= SHA1::BLOCKSIZE; + } + while (length >= SHA1::BLOCKSIZE); + return length; +} + +// ************************************************************* + +ANONYMOUS_NAMESPACE_BEGIN + +#define a(i) T[(0-i)&7] +#define b(i) T[(1-i)&7] +#define c(i) T[(2-i)&7] +#define d(i) T[(3-i)&7] +#define e(i) T[(4-i)&7] +#define f(i) T[(5-i)&7] +#define g(i) T[(6-i)&7] +#define h(i) T[(7-i)&7] + +#define blk0(i) (W[i] = data[i]) +#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) (y^((x^y)&(y^z))) + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA256_K[i+j]+(j?blk2(i):blk0(i));\ + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + +// for SHA256 +#define s0(x) (rotrConstant<7>(x)^rotrConstant<18>(x)^(x>>3)) +#define s1(x) (rotrConstant<17>(x)^rotrConstant<19>(x)^(x>>10)) +#define S0(x) (rotrConstant<2>(x)^rotrConstant<13>(x)^rotrConstant<22>(x)) +#define S1(x) (rotrConstant<6>(x)^rotrConstant<11>(x)^rotrConstant<25>(x)) + +void SHA256_HashBlock_CXX(word32 *state, const word32 *data) +{ + word32 W[16]={0}, T[8]; + /* Copy context->state[] to working vars */ + memcpy(T, state, sizeof(T)); + /* 64 operations, partially loop unrolled */ + for (unsigned int j=0; j<64; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + /* Add the working vars back into context.state[] */ + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); +} + +#undef Ch +#undef Maj +#undef s0 +#undef s1 +#undef S0 +#undef S1 +#undef blk0 +#undef blk1 +#undef blk2 +#undef R + +#undef a +#undef b +#undef c +#undef d +#undef e +#undef f +#undef g +#undef h + +ANONYMOUS_NAMESPACE_END + +std::string SHA256_AlgorithmProvider() +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + return "SHANI"; +#endif +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +#endif +#if CRYPTOGAMS_ARM_SHA256 + if (HasNEON()) + return "NEON"; + if (HasARMv7()) + return "ARMv7"; +#endif +#if CRYPTOPP_ARM_SHA2_AVAILABLE + if (HasSHA2()) + return "ARMv8"; +#endif +#if (CRYPTOPP_POWER8_SHA_AVAILABLE) + if (HasSHA256()) + return "Power8"; +#endif + return "C++"; +} + +std::string SHA224::AlgorithmProvider() const +{ + return SHA256_AlgorithmProvider(); +} + +void SHA224::InitState(HashWordType *state) +{ + static const word32 s[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; + memcpy(state, s, sizeof(s)); +} + +void SHA256::InitState(HashWordType *state) +{ + static const word32 s[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + memcpy(state, s, sizeof(s)); +} +#endif // Not CRYPTOPP_GENERATE_X64_MASM + +#if defined(CRYPTOPP_X86_ASM_AVAILABLE) + +ANONYMOUS_NAMESPACE_BEGIN + +void CRYPTOPP_FASTCALL SHA256_HashMultipleBlocks_SSE2(word32 *state, const word32 *data, size_t len) +{ + #define LOCALS_SIZE 8*4 + 16*4 + 4*WORD_SZ + #define H(i) [BASE+ASM_MOD(1024+7-(i),8)*4] + #define G(i) H(i+1) + #define F(i) H(i+2) + #define E(i) H(i+3) + #define D(i) H(i+4) + #define C(i) H(i+5) + #define B(i) H(i+6) + #define A(i) H(i+7) + #define Wt(i) BASE+8*4+ASM_MOD(1024+15-(i),16)*4 + #define Wt_2(i) Wt((i)-2) + #define Wt_15(i) Wt((i)-15) + #define Wt_7(i) Wt((i)-7) + #define K_END [BASE+8*4+16*4+0*WORD_SZ] + #define STATE_SAVE [BASE+8*4+16*4+1*WORD_SZ] + #define DATA_SAVE [BASE+8*4+16*4+2*WORD_SZ] + #define DATA_END [BASE+8*4+16*4+3*WORD_SZ] + #define Kt(i) WORD_REG(si)+(i)*4 +#if CRYPTOPP_BOOL_X86 + #define BASE esp+4 +#elif defined(__GNUC__) + #define BASE r8 +#else + #define BASE rsp +#endif + +#define RA0(i, edx, edi) \ + AS2( add edx, [Kt(i)] )\ + AS2( add edx, [Wt(i)] )\ + AS2( add edx, H(i) )\ + +#define RA1(i, edx, edi) + +#define RB0(i, edx, edi) + +#define RB1(i, edx, edi) \ + AS2( mov AS_REG_7d, [Wt_2(i)] )\ + AS2( mov edi, [Wt_15(i)])\ + AS2( mov ebx, AS_REG_7d )\ + AS2( shr AS_REG_7d, 10 )\ + AS2( ror ebx, 17 )\ + AS2( xor AS_REG_7d, ebx )\ + AS2( ror ebx, 2 )\ + AS2( xor ebx, AS_REG_7d )/* s1(W_t-2) */\ + AS2( add ebx, [Wt_7(i)])\ + AS2( mov AS_REG_7d, edi )\ + AS2( shr AS_REG_7d, 3 )\ + AS2( ror edi, 7 )\ + AS2( add ebx, [Wt(i)])/* s1(W_t-2) + W_t-7 + W_t-16 */\ + AS2( xor AS_REG_7d, edi )\ + AS2( add edx, [Kt(i)])\ + AS2( ror edi, 11 )\ + AS2( add edx, H(i) )\ + AS2( xor AS_REG_7d, edi )/* s0(W_t-15) */\ + AS2( add AS_REG_7d, ebx )/* W_t = s1(W_t-2) + W_t-7 + s0(W_t-15) W_t-16*/\ + AS2( mov [Wt(i)], AS_REG_7d)\ + AS2( add edx, AS_REG_7d )\ + +#define ROUND(i, r, eax, ecx, edi, edx)\ + /* in: edi = E */\ + /* unused: eax, ecx, temp: ebx, AS_REG_7d, out: edx = T1 */\ + AS2( mov edx, F(i) )\ + AS2( xor edx, G(i) )\ + AS2( and edx, edi )\ + AS2( xor edx, G(i) )/* Ch(E,F,G) = (G^(E&(F^G))) */\ + AS2( mov AS_REG_7d, edi )\ + AS2( ror edi, 6 )\ + AS2( ror AS_REG_7d, 25 )\ + RA##r(i, edx, edi )/* H + Wt + Kt + Ch(E,F,G) */\ + AS2( xor AS_REG_7d, edi )\ + AS2( ror edi, 5 )\ + AS2( xor AS_REG_7d, edi )/* S1(E) */\ + AS2( add edx, AS_REG_7d )/* T1 = S1(E) + Ch(E,F,G) + H + Wt + Kt */\ + RB##r(i, edx, edi )/* H + Wt + Kt + Ch(E,F,G) */\ + /* in: ecx = A, eax = B^C, edx = T1 */\ + /* unused: edx, temp: ebx, AS_REG_7d, out: eax = A, ecx = B^C, edx = E */\ + AS2( mov ebx, ecx )\ + AS2( xor ecx, B(i) )/* A^B */\ + AS2( and eax, ecx )\ + AS2( xor eax, B(i) )/* Maj(A,B,C) = B^((A^B)&(B^C) */\ + AS2( mov AS_REG_7d, ebx )\ + AS2( ror ebx, 2 )\ + AS2( add eax, edx )/* T1 + Maj(A,B,C) */\ + AS2( add edx, D(i) )\ + AS2( mov D(i), edx )\ + AS2( ror AS_REG_7d, 22 )\ + AS2( xor AS_REG_7d, ebx )\ + AS2( ror ebx, 11 )\ + AS2( xor AS_REG_7d, ebx )\ + AS2( add eax, AS_REG_7d )/* T1 + S0(A) + Maj(A,B,C) */\ + AS2( mov H(i), eax )\ + +// Unroll the use of CRYPTOPP_BOOL_X64 in assembler math. The GAS assembler on X32 (version 2.25) +// complains "Error: invalid operands (*ABS* and *UND* sections) for `*` and `-`" +#if CRYPTOPP_BOOL_X64 +#define SWAP_COPY(i) \ + AS2( mov WORD_REG(bx), [WORD_REG(dx)+i*WORD_SZ])\ + AS1( bswap WORD_REG(bx))\ + AS2( mov [Wt(i*2+1)], WORD_REG(bx)) +#else // X86 and X32 +#define SWAP_COPY(i) \ + AS2( mov WORD_REG(bx), [WORD_REG(dx)+i*WORD_SZ])\ + AS1( bswap WORD_REG(bx))\ + AS2( mov [Wt(i)], WORD_REG(bx)) +#endif + +#if defined(__GNUC__) + #if CRYPTOPP_BOOL_X64 + FixedSizeAlignedSecBlock workspace; + #endif + __asm__ __volatile__ + ( + #if CRYPTOPP_BOOL_X64 + "lea %4, %%r8;" + #endif + INTEL_NOPREFIX +#elif defined(CRYPTOPP_GENERATE_X64_MASM) + ALIGN 8 + SHA256_HashMultipleBlocks_SSE2 PROC FRAME + rex_push_reg rsi + push_reg rdi + push_reg rbx + push_reg rbp + alloc_stack(LOCALS_SIZE+8) + .endprolog + mov rdi, r8 + lea rsi, [?SHA256_K@CryptoPP@@3QBIB + 48*4] +#endif + +#if CRYPTOPP_BOOL_X86 + #ifndef __GNUC__ + AS2( mov edi, [len]) + AS2( lea WORD_REG(si), [SHA256_K+48*4]) + #endif + #if !defined(_MSC_VER) || (_MSC_VER < 1400) + AS_PUSH_IF86(bx) + #endif + + AS_PUSH_IF86(bp) + AS2( mov ebx, esp) + AS2( and esp, -16) + AS2( sub WORD_REG(sp), LOCALS_SIZE) + AS_PUSH_IF86(bx) +#endif + AS2( mov STATE_SAVE, WORD_REG(cx)) + AS2( mov DATA_SAVE, WORD_REG(dx)) + AS2( lea WORD_REG(ax), [WORD_REG(di) + WORD_REG(dx)]) + AS2( mov DATA_END, WORD_REG(ax)) + AS2( mov K_END, WORD_REG(si)) + +#if CRYPTOPP_SSE2_ASM_AVAILABLE +#if CRYPTOPP_BOOL_X86 + AS2( test edi, 1) + ASJ( jnz, 2, f) + AS1( dec DWORD PTR K_END) +#endif + AS2( movdqu xmm0, XMMWORD_PTR [WORD_REG(cx)+0*16]) + AS2( movdqu xmm1, XMMWORD_PTR [WORD_REG(cx)+1*16]) +#endif + +#if CRYPTOPP_BOOL_X86 +#if CRYPTOPP_SSE2_ASM_AVAILABLE + ASJ( jmp, 0, f) +#endif + ASL(2) // non-SSE2 + AS2( mov esi, ecx) + AS2( lea edi, A(0)) + AS2( mov ecx, 8) +ATT_NOPREFIX + AS1( rep movsd) +INTEL_NOPREFIX + AS2( mov esi, K_END) + ASJ( jmp, 3, f) +#endif + +#if CRYPTOPP_SSE2_ASM_AVAILABLE + ASL(0) + AS2( movdqu E(0), xmm1) + AS2( movdqu A(0), xmm0) +#endif +#if CRYPTOPP_BOOL_X86 + ASL(3) +#endif + AS2( sub WORD_REG(si), 48*4) + SWAP_COPY(0) SWAP_COPY(1) SWAP_COPY(2) SWAP_COPY(3) + SWAP_COPY(4) SWAP_COPY(5) SWAP_COPY(6) SWAP_COPY(7) +#if CRYPTOPP_BOOL_X86 + SWAP_COPY(8) SWAP_COPY(9) SWAP_COPY(10) SWAP_COPY(11) + SWAP_COPY(12) SWAP_COPY(13) SWAP_COPY(14) SWAP_COPY(15) +#endif + AS2( mov edi, E(0)) // E + AS2( mov eax, B(0)) // B + AS2( xor eax, C(0)) // B^C + AS2( mov ecx, A(0)) // A + + ROUND(0, 0, eax, ecx, edi, edx) + ROUND(1, 0, ecx, eax, edx, edi) + ROUND(2, 0, eax, ecx, edi, edx) + ROUND(3, 0, ecx, eax, edx, edi) + ROUND(4, 0, eax, ecx, edi, edx) + ROUND(5, 0, ecx, eax, edx, edi) + ROUND(6, 0, eax, ecx, edi, edx) + ROUND(7, 0, ecx, eax, edx, edi) + ROUND(8, 0, eax, ecx, edi, edx) + ROUND(9, 0, ecx, eax, edx, edi) + ROUND(10, 0, eax, ecx, edi, edx) + ROUND(11, 0, ecx, eax, edx, edi) + ROUND(12, 0, eax, ecx, edi, edx) + ROUND(13, 0, ecx, eax, edx, edi) + ROUND(14, 0, eax, ecx, edi, edx) + ROUND(15, 0, ecx, eax, edx, edi) + + ASL(1) + AS2(add WORD_REG(si), 4*16) + ROUND(0, 1, eax, ecx, edi, edx) + ROUND(1, 1, ecx, eax, edx, edi) + ROUND(2, 1, eax, ecx, edi, edx) + ROUND(3, 1, ecx, eax, edx, edi) + ROUND(4, 1, eax, ecx, edi, edx) + ROUND(5, 1, ecx, eax, edx, edi) + ROUND(6, 1, eax, ecx, edi, edx) + ROUND(7, 1, ecx, eax, edx, edi) + ROUND(8, 1, eax, ecx, edi, edx) + ROUND(9, 1, ecx, eax, edx, edi) + ROUND(10, 1, eax, ecx, edi, edx) + ROUND(11, 1, ecx, eax, edx, edi) + ROUND(12, 1, eax, ecx, edi, edx) + ROUND(13, 1, ecx, eax, edx, edi) + ROUND(14, 1, eax, ecx, edi, edx) + ROUND(15, 1, ecx, eax, edx, edi) + AS2( cmp WORD_REG(si), K_END) + ATT_NOPREFIX + ASJ( jb, 1, b) + INTEL_NOPREFIX + + AS2( mov WORD_REG(dx), DATA_SAVE) + AS2( add WORD_REG(dx), 64) + AS2( mov AS_REG_7, STATE_SAVE) + AS2( mov DATA_SAVE, WORD_REG(dx)) + +#if CRYPTOPP_SSE2_ASM_AVAILABLE +#if CRYPTOPP_BOOL_X86 + AS2( test DWORD PTR K_END, 1) + ASJ( jz, 4, f) +#endif + AS2( movdqu xmm1, XMMWORD_PTR [AS_REG_7+1*16]) + AS2( movdqu xmm0, XMMWORD_PTR [AS_REG_7+0*16]) + AS2( paddd xmm1, E(0)) + AS2( paddd xmm0, A(0)) + AS2( movdqu [AS_REG_7+1*16], xmm1) + AS2( movdqu [AS_REG_7+0*16], xmm0) + AS2( cmp WORD_REG(dx), DATA_END) + ATT_NOPREFIX + ASJ( jb, 0, b) + INTEL_NOPREFIX +#endif + +#if CRYPTOPP_BOOL_X86 +#if CRYPTOPP_SSE2_ASM_AVAILABLE + ASJ( jmp, 5, f) + ASL(4) // non-SSE2 +#endif + AS2( add [AS_REG_7+0*4], ecx) // A + AS2( add [AS_REG_7+4*4], edi) // E + AS2( mov eax, B(0)) + AS2( mov ebx, C(0)) + AS2( mov ecx, D(0)) + AS2( add [AS_REG_7+1*4], eax) + AS2( add [AS_REG_7+2*4], ebx) + AS2( add [AS_REG_7+3*4], ecx) + AS2( mov eax, F(0)) + AS2( mov ebx, G(0)) + AS2( mov ecx, H(0)) + AS2( add [AS_REG_7+5*4], eax) + AS2( add [AS_REG_7+6*4], ebx) + AS2( add [AS_REG_7+7*4], ecx) + AS2( mov ecx, AS_REG_7d) + AS2( cmp WORD_REG(dx), DATA_END) + ASJ( jb, 2, b) +#if CRYPTOPP_SSE2_ASM_AVAILABLE + ASL(5) +#endif +#endif + + AS_POP_IF86(sp) + AS_POP_IF86(bp) + #if !defined(_MSC_VER) || (_MSC_VER < 1400) + AS_POP_IF86(bx) + #endif + +#ifdef CRYPTOPP_GENERATE_X64_MASM + add rsp, LOCALS_SIZE+8 + pop rbp + pop rbx + pop rdi + pop rsi + ret + SHA256_HashMultipleBlocks_SSE2 ENDP +#endif + +#ifdef __GNUC__ + ATT_PREFIX + : + : "c" (state), "d" (data), "S" (SHA256_K+48), "D" (len) + #if CRYPTOPP_BOOL_X64 + , "m" (workspace[0]) + #endif + : "memory", "cc", "%eax" + #if CRYPTOPP_BOOL_X64 + , "%rbx", "%r8", "%r10" + #endif + ); +#endif +} + +ANONYMOUS_NAMESPACE_END + +#endif // CRYPTOPP_X86_ASM_AVAILABLE + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void CRYPTOPP_FASTCALL SHA256_HashMultipleBlocks_SSE2(word32 *state, const word32 *data, size_t len); +} +#endif + +std::string SHA256::AlgorithmProvider() const +{ + return SHA256_AlgorithmProvider(); +} + +void SHA256::Transform(word32 *state, const word32 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHA256_HashMultipleBlocks_SHANI(state, data, SHA256::BLOCKSIZE, LITTLE_ENDIAN_ORDER); + return; + } +#endif +#if CRYPTOGAMS_ARM_SHA256 && 0 + if (HasNEON()) + { +# if defined(CRYPTOPP_LITTLE_ENDIAN) + word32 dataBuf[16]; + ByteReverse(dataBuf, data, SHA256::BLOCKSIZE); + cryptogams_sha256_block_data_order_neon(state, data, 1); +# else + cryptogams_sha256_block_data_order_neon(state, data, 1); +# endif + return; + } + if (HasARMv7()) + { +# if defined(CRYPTOPP_LITTLE_ENDIAN) + word32 dataBuf[16]; + ByteReverse(dataBuf, data, SHA256::BLOCKSIZE); + cryptogams_sha256_block_data_order(state, data, 1); +# else + cryptogams_sha256_block_data_order(state, data, 1); +# endif + return; + } +#endif +#if CRYPTOPP_ARM_SHA2_AVAILABLE + if (HasSHA2()) + { + SHA256_HashMultipleBlocks_ARMV8(state, data, SHA256::BLOCKSIZE, LITTLE_ENDIAN_ORDER); + return; + } +#endif +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (HasSHA256()) + { + SHA256_HashMultipleBlocks_POWER8(state, data, SHA256::BLOCKSIZE, LITTLE_ENDIAN_ORDER); + return; + } +#endif + + SHA256_HashBlock_CXX(state, data); +} + +size_t SHA256::HashMultipleBlocks(const word32 *input, size_t length) +{ + CRYPTOPP_ASSERT(input); + CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE); + +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHA256_HashMultipleBlocks_SHANI(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_SSE2_ASM_AVAILABLE || CRYPTOPP_X64_MASM_AVAILABLE + if (HasSSE2()) + { + const size_t res = length & (SHA256::BLOCKSIZE - 1); + SHA256_HashMultipleBlocks_SSE2(m_state, input, length-res); + return res; + } +#endif +#if CRYPTOGAMS_ARM_SHA256 + if (HasNEON()) + { + cryptogams_sha256_block_data_order_neon(m_state, input, length / SHA256::BLOCKSIZE); + return length & (SHA256::BLOCKSIZE - 1); + } + if (HasARMv7()) + { + cryptogams_sha256_block_data_order(m_state, input, length / SHA256::BLOCKSIZE); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_ARM_SHA2_AVAILABLE + if (HasSHA2()) + { + SHA256_HashMultipleBlocks_ARMV8(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (HasSHA256()) + { + SHA256_HashMultipleBlocks_POWER8(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif + + const bool noReverse = NativeByteOrderIs(this->GetByteOrder()); + word32 *dataBuf = this->DataBuf(); + do + { + if (noReverse) + { + SHA256_HashBlock_CXX(m_state, input); + } + else + { + ByteReverse(dataBuf, input, SHA256::BLOCKSIZE); + SHA256_HashBlock_CXX(m_state, dataBuf); + } + + input += SHA256::BLOCKSIZE/sizeof(word32); + length -= SHA256::BLOCKSIZE; + } + while (length >= SHA256::BLOCKSIZE); + return length; +} + +size_t SHA224::HashMultipleBlocks(const word32 *input, size_t length) +{ + CRYPTOPP_ASSERT(input); + CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE); + +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHA256_HashMultipleBlocks_SHANI(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_SSE2_ASM_AVAILABLE || CRYPTOPP_X64_MASM_AVAILABLE + if (HasSSE2()) + { + const size_t res = length & (SHA256::BLOCKSIZE - 1); + SHA256_HashMultipleBlocks_SSE2(m_state, input, length-res); + return res; + } +#endif +#if CRYPTOGAMS_ARM_SHA256 + if (HasNEON()) + { + cryptogams_sha256_block_data_order_neon(m_state, input, length / SHA256::BLOCKSIZE); + return length & (SHA256::BLOCKSIZE - 1); + } + if (HasARMv7()) + { + cryptogams_sha256_block_data_order(m_state, input, length / SHA256::BLOCKSIZE); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_ARM_SHA2_AVAILABLE + if (HasSHA2()) + { + SHA256_HashMultipleBlocks_ARMV8(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (HasSHA256()) + { + SHA256_HashMultipleBlocks_POWER8(m_state, input, length, BIG_ENDIAN_ORDER); + return length & (SHA256::BLOCKSIZE - 1); + } +#endif + + const bool noReverse = NativeByteOrderIs(this->GetByteOrder()); + word32 *dataBuf = this->DataBuf(); + do + { + if (noReverse) + { + SHA256_HashBlock_CXX(m_state, input); + } + else + { + ByteReverse(dataBuf, input, SHA256::BLOCKSIZE); + SHA256_HashBlock_CXX(m_state, dataBuf); + } + + input += SHA256::BLOCKSIZE/sizeof(word32); + length -= SHA256::BLOCKSIZE; + } + while (length >= SHA256::BLOCKSIZE); + return length; +} + +// ************************************************************* + +std::string SHA512_AlgorithmProvider() +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +#endif +#if CRYPTOGAMS_ARM_SHA512 + if (HasNEON()) + return "NEON"; + if (HasARMv7()) + return "ARMv7"; +#endif +#if (CRYPTOPP_POWER8_SHA_AVAILABLE) + if (HasSHA512()) + return "Power8"; +#endif + return "C++"; +} + +std::string SHA384::AlgorithmProvider() const +{ + return SHA512_AlgorithmProvider(); +} + +std::string SHA512::AlgorithmProvider() const +{ + return SHA512_AlgorithmProvider(); +} + +void SHA384::InitState(HashWordType *state) +{ + const word64 s[8] = { + W64LIT(0xcbbb9d5dc1059ed8), W64LIT(0x629a292a367cd507), + W64LIT(0x9159015a3070dd17), W64LIT(0x152fecd8f70e5939), + W64LIT(0x67332667ffc00b31), W64LIT(0x8eb44a8768581511), + W64LIT(0xdb0c2e0d64f98fa7), W64LIT(0x47b5481dbefa4fa4)}; + memcpy(state, s, sizeof(s)); +} + +void SHA512::InitState(HashWordType *state) +{ + const word64 s[8] = { + W64LIT(0x6a09e667f3bcc908), W64LIT(0xbb67ae8584caa73b), + W64LIT(0x3c6ef372fe94f82b), W64LIT(0xa54ff53a5f1d36f1), + W64LIT(0x510e527fade682d1), W64LIT(0x9b05688c2b3e6c1f), + W64LIT(0x1f83d9abfb41bd6b), W64LIT(0x5be0cd19137e2179)}; + memcpy(state, s, sizeof(s)); +} + +#if CRYPTOPP_SSE2_ASM_AVAILABLE && (CRYPTOPP_BOOL_X86) + +ANONYMOUS_NAMESPACE_BEGIN + +// No inlining due to https://github.com/weidai11/cryptopp/issues/684 +// g++ -DNDEBUG -g2 -O3 -pthread -pipe -c sha.cpp +// sha.cpp: Assembler messages: +// sha.cpp:1155: Error: symbol `SHA512_Round' is already defined +// sha.cpp:1155: Error: symbol `SHA512_Round' is already defined + +CRYPTOPP_NOINLINE CRYPTOPP_NAKED +void CRYPTOPP_FASTCALL SHA512_HashBlock_SSE2(word64 *state, const word64 *data) +{ +#ifdef __GNUC__ + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86( bx) + AS2( mov ebx, eax) +#else + AS1( push ebx) + AS1( push esi) + AS1( push edi) + AS2( lea ebx, SHA512_K) +#endif + + AS2( mov eax, esp) + AS2( and esp, 0xfffffff0) + AS2( sub esp, 27*16) // 17*16 for expanded data, 20*8 for state + AS_PUSH_IF86( ax) + AS2( xor eax, eax) + + AS2( lea edi, [esp+4+8*8]) // start at middle of state buffer. will decrement pointer each round to avoid copying + AS2( lea esi, [esp+4+20*8+8]) // 16-byte alignment, then add 8 + + AS2( movdqu xmm0, [ecx+0*16]) + AS2( movdq2q mm4, xmm0) + AS2( movdqu [edi+0*16], xmm0) + AS2( movdqu xmm0, [ecx+1*16]) + AS2( movdqu [edi+1*16], xmm0) + AS2( movdqu xmm0, [ecx+2*16]) + AS2( movdq2q mm5, xmm0) + AS2( movdqu [edi+2*16], xmm0) + AS2( movdqu xmm0, [ecx+3*16]) + AS2( movdqu [edi+3*16], xmm0) + ASJ( jmp, 0, f) + +#define SSE2_S0_S1(r, a, b, c) \ + AS2( movq mm6, r)\ + AS2( psrlq r, a)\ + AS2( movq mm7, r)\ + AS2( psllq mm6, 64-c)\ + AS2( pxor mm7, mm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor mm7, r)\ + AS2( psllq mm6, c-b)\ + AS2( pxor mm7, mm6)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, mm7)\ + AS2( psllq mm6, b-a)\ + AS2( pxor r, mm6) + +#define SSE2_s0(r, a, b, c) \ + AS2( movdqu xmm6, r)\ + AS2( psrlq r, a)\ + AS2( movdqu xmm7, r)\ + AS2( psllq xmm6, 64-c)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor xmm7, r)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, xmm7)\ + AS2( psllq xmm6, c-a)\ + AS2( pxor r, xmm6) + +#define SSE2_s1(r, a, b, c) \ + AS2( movdqu xmm6, r)\ + AS2( psrlq r, a)\ + AS2( movdqu xmm7, r)\ + AS2( psllq xmm6, 64-c)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, b-a)\ + AS2( pxor xmm7, r)\ + AS2( psllq xmm6, c-b)\ + AS2( pxor xmm7, xmm6)\ + AS2( psrlq r, c-b)\ + AS2( pxor r, xmm7) + ASL(SHA512_Round) + + // k + w is in mm0, a is in mm4, e is in mm5 + AS2( paddq mm0, [edi+7*8]) // h + AS2( movq mm2, [edi+5*8]) // f + AS2( movq mm3, [edi+6*8]) // g + AS2( pxor mm2, mm3) + AS2( pand mm2, mm5) + SSE2_S0_S1(mm5,14,18,41) + AS2( pxor mm2, mm3) + AS2( paddq mm0, mm2) // h += Ch(e,f,g) + AS2( paddq mm5, mm0) // h += S1(e) + AS2( movq mm2, [edi+1*8]) // b + AS2( movq mm1, mm2) + AS2( por mm2, mm4) + AS2( pand mm2, [edi+2*8]) // c + AS2( pand mm1, mm4) + AS2( por mm1, mm2) + AS2( paddq mm1, mm5) // temp = h + Maj(a,b,c) + AS2( paddq mm5, [edi+3*8]) // e = d + h + AS2( movq [edi+3*8], mm5) + AS2( movq [edi+11*8], mm5) + SSE2_S0_S1(mm4,28,34,39) // S0(a) + AS2( paddq mm4, mm1) // a = temp + S0(a) + AS2( movq [edi-8], mm4) + AS2( movq [edi+7*8], mm4) + AS1( ret) + + // first 16 rounds + ASL(0) + AS2( movq mm0, [edx+eax*8]) + AS2( movq [esi+eax*8], mm0) + AS2( movq [esi+eax*8+16*8], mm0) + AS2( paddq mm0, [ebx+eax*8]) + ASC( call, SHA512_Round) + + AS1( inc eax) + AS2( sub edi, 8) + AS2( test eax, 7) + ASJ( jnz, 0, b) + AS2( add edi, 8*8) + AS2( cmp eax, 16) + ASJ( jne, 0, b) + + // rest of the rounds + AS2( movdqu xmm0, [esi+(16-2)*8]) + ASL(1) + // data expansion, W[i-2] already in xmm0 + AS2( movdqu xmm3, [esi]) + AS2( paddq xmm3, [esi+(16-7)*8]) + AS2( movdqu xmm2, [esi+(16-15)*8]) + SSE2_s1(xmm0, 6, 19, 61) + AS2( paddq xmm0, xmm3) + SSE2_s0(xmm2, 1, 7, 8) + AS2( paddq xmm0, xmm2) + AS2( movdq2q mm0, xmm0) + AS2( movhlps xmm1, xmm0) + AS2( paddq mm0, [ebx+eax*8]) + AS2( movlps [esi], xmm0) + AS2( movlps [esi+8], xmm1) + AS2( movlps [esi+8*16], xmm0) + AS2( movlps [esi+8*17], xmm1) + // 2 rounds + ASC( call, SHA512_Round) + AS2( sub edi, 8) + AS2( movdq2q mm0, xmm1) + AS2( paddq mm0, [ebx+eax*8+8]) + ASC( call, SHA512_Round) + // update indices and loop + AS2( add esi, 16) + AS2( add eax, 2) + AS2( sub edi, 8) + AS2( test eax, 7) + ASJ( jnz, 1, b) + // do housekeeping every 8 rounds + AS2( mov esi, 0xf) + AS2( and esi, eax) + AS2( lea esi, [esp+4+20*8+8+esi*8]) + AS2( add edi, 8*8) + AS2( cmp eax, 80) + ASJ( jne, 1, b) + +#define SSE2_CombineState(i) \ + AS2( movdqu xmm0, [edi+i*16])\ + AS2( paddq xmm0, [ecx+i*16])\ + AS2( movdqu [ecx+i*16], xmm0) + + SSE2_CombineState(0) + SSE2_CombineState(1) + SSE2_CombineState(2) + SSE2_CombineState(3) + + AS_POP_IF86( sp) + AS1( emms) + +#if defined(__GNUC__) + AS_POP_IF86( bx) + ATT_PREFIX + : + : "a" (SHA512_K), "c" (state), "d" (data) + : "%esi", "%edi", "memory", "cc" + ); +#else + AS1( pop edi) + AS1( pop esi) + AS1( pop ebx) + AS1( ret) +#endif +} + +ANONYMOUS_NAMESPACE_END + +#endif // CRYPTOPP_SSE2_ASM_AVAILABLE + +ANONYMOUS_NAMESPACE_BEGIN + +#define a(i) T[(0-i)&7] +#define b(i) T[(1-i)&7] +#define c(i) T[(2-i)&7] +#define d(i) T[(3-i)&7] +#define e(i) T[(4-i)&7] +#define f(i) T[(5-i)&7] +#define g(i) T[(6-i)&7] +#define h(i) T[(7-i)&7] + +#define blk0(i) (W[i]=data[i]) +#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) (y^((x^y)&(y^z))) + +#define s0(x) (rotrConstant<1>(x)^rotrConstant<8>(x)^(x>>7)) +#define s1(x) (rotrConstant<19>(x)^rotrConstant<61>(x)^(x>>6)) +#define S0(x) (rotrConstant<28>(x)^rotrConstant<34>(x)^rotrConstant<39>(x)) +#define S1(x) (rotrConstant<14>(x)^rotrConstant<18>(x)^rotrConstant<41>(x)) + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA512_K[i+j]+\ + (j?blk2(i):blk0(i));d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)); + +void SHA512_HashBlock_CXX(word64 *state, const word64 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + + word64 W[16]={0}, T[8]; + + /* Copy context->state[] to working vars */ + std::memcpy(T, state, sizeof(T)); + + /* 80 operations, partially loop unrolled */ + for (unsigned int j=0; j<80; j+=16) + { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + + state[0] += a(0); + state[1] += b(0); + state[2] += c(0); + state[3] += d(0); + state[4] += e(0); + state[5] += f(0); + state[6] += g(0); + state[7] += h(0); +} + +ANONYMOUS_NAMESPACE_END + +void SHA512::Transform(word64 *state, const word64 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + +#if CRYPTOPP_SSE2_ASM_AVAILABLE && (CRYPTOPP_BOOL_X86) + if (HasSSE2()) + { + SHA512_HashBlock_SSE2(state, data); + return; + } +#endif +#if CRYPTOGAMS_ARM_SHA512 + if (HasNEON()) + { +# if (CRYPTOPP_LITTLE_ENDIAN) + word64 dataBuf[16]; + ByteReverse(dataBuf, data, SHA512::BLOCKSIZE); + cryptogams_sha512_block_data_order_neon(state, dataBuf, 1); +# else + cryptogams_sha512_block_data_order_neon(state, data, 1); +# endif + return; + } + if (HasARMv7()) + { +# if (CRYPTOPP_LITTLE_ENDIAN) + word64 dataBuf[16]; + ByteReverse(dataBuf, data, SHA512::BLOCKSIZE); + cryptogams_sha512_block_data_order(state, dataBuf, 1); +# else + cryptogams_sha512_block_data_order(state, data, 1); +# endif + return; + } +#endif +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (HasSHA512()) + { + SHA512_HashMultipleBlocks_POWER8(state, data, SHA512::BLOCKSIZE, BIG_ENDIAN_ORDER); + return; + } +#endif + + SHA512_HashBlock_CXX(state, data); +} + +#undef Ch +#undef Maj + +#undef s0 +#undef s1 +#undef S0 +#undef S1 + +#undef blk0 +#undef blk1 +#undef blk2 + +#undef R + +#undef a +#undef b +#undef c +#undef d +#undef e +#undef f +#undef g +#undef h + +NAMESPACE_END + +#endif // Not CRYPTOPP_GENERATE_X64_MASM +#endif // Not CRYPTOPP_IMPORTS diff --git a/extension/third_party/cryptopp/sha.h b/extension/third_party/cryptopp/sha.h new file mode 100644 index 00000000..a819bd92 --- /dev/null +++ b/extension/third_party/cryptopp/sha.h @@ -0,0 +1,210 @@ +// sha.h - originally written and placed in the public domain by Wei Dai + +/// \file sha.h +/// \brief Classes for SHA-1 and SHA-2 family of message digests +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 + +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SHA_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA-1 message digest +/// \sa SHA-1 +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0 +class CRYPTOPP_DLL SHA1 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA1 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-1" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-1";} + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-256 message digest +/// \sa SHA-256 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA256 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA256 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-256" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-256";} + + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-224 message digest +/// \sa SHA-224 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA224 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA224 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA256::Transform(digest, data);} + /// \brief The algorithm name + /// \return C-style string "SHA-224" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-224";} + + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-512 message digest +/// \sa SHA-512 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA512 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA512 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-512" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-512";} + + // Algorithm class + std::string AlgorithmProvider() const; +}; + +/// \brief SHA-384 message digest +/// \sa SHA-384 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA384 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA384 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA512::Transform(digest, data);} + /// \brief The algorithm name + /// \return C-style string "SHA-384" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-384";} + + // Algorithm class + std::string AlgorithmProvider() const; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/sha1_armv4.S b/extension/third_party/cryptopp/sha1_armv4.S new file mode 100644 index 00000000..49a39f49 --- /dev/null +++ b/extension/third_party/cryptopp/sha1_armv4.S @@ -0,0 +1,1410 @@ +@ Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved. +@ +@ ==================================================================== +@ Written by Andy Polyakov for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ JW, MAY 2019: Begin defines from taken from arm_arch.h +@ The defines were included through the header. + +# if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +# endif + +# if !defined(__ARM_MAX_ARCH__) +# define __ARM_MAX_ARCH__ __ARM_ARCH__ +# endif + +# if __ARM_MAX_ARCH__<__ARM_ARCH__ +# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__" +# elif __ARM_MAX_ARCH__!=__ARM_ARCH__ +# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__) +# error "can't build universal big-endian binary" +# endif +# endif + +# define CRYPTOGAMS_ARMV7_NEON (1<<0) + +@ JW, MAY 2019: End defines from taken from arm_arch.h +@ Back to original Cryptogams code + +#if defined(__thumb2__) +.syntax unified +.thumb +#else +.code 32 +#endif + +.text + +.align 5 +.globl cryptogams_sha1_block_data_order +.type cryptogams_sha1_block_data_order,%function + +cryptogams_sha1_block_data_order: +.Lcryptogams_sha1_block_data_order: + +#if __ARM_ARCH__<7 && !defined(__thumb2__) + sub r3,pc,#8 @ cryptogams_sha1_block_data_order +#else + adr r3,.Lcryptogams_sha1_block_data_order +#endif + + stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + add r2,r1,r2,lsl#6 @ r2 to point at the end of r1 + ldmia r0,{r3,r4,r5,r6,r7} + +.Lloop: + ldr r8,.LK_00_19 + mov r14,sp + sub sp,sp,#15*4 + mov r5,r5,ror#30 + mov r6,r6,ror#30 + mov r7,r7,ror#30 @ [6] +.L_00_15: +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r7,r8,r7,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r5,r6 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r7,r8,r7,ror#2 @ E+=K_00_19 + eor r10,r5,r6 @ F_xx_xx + add r7,r7,r3,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r4,r10,ror#2 + add r7,r7,r9 @ E+=X[i] + eor r10,r10,r6,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r7,r7,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r6,r8,r6,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r4,r5 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r6,r8,r6,ror#2 @ E+=K_00_19 + eor r10,r4,r5 @ F_xx_xx + add r6,r6,r7,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r3,r10,ror#2 + add r6,r6,r9 @ E+=X[i] + eor r10,r10,r5,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r6,r6,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r5,r8,r5,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r3,r4 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r5,r8,r5,ror#2 @ E+=K_00_19 + eor r10,r3,r4 @ F_xx_xx + add r5,r5,r6,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r7,r10,ror#2 + add r5,r5,r9 @ E+=X[i] + eor r10,r10,r4,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r5,r5,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r4,r8,r4,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r7,r3 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r4,r8,r4,ror#2 @ E+=K_00_19 + eor r10,r7,r3 @ F_xx_xx + add r4,r4,r5,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r6,r10,ror#2 + add r4,r4,r9 @ E+=X[i] + eor r10,r10,r3,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r4,r4,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r3,r8,r3,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r6,r7 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r3,r8,r3,ror#2 @ E+=K_00_19 + eor r10,r6,r7 @ F_xx_xx + add r3,r3,r4,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r5,r10,ror#2 + add r3,r3,r9 @ E+=X[i] + eor r10,r10,r7,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r3,r3,r10 @ E+=F_00_19(B,C,D) +#if defined(__thumb2__) + mov r12,sp + teq r14,r12 +#else + teq r14,sp +#endif + bne .L_00_15 @ [((11+4)*5+2)*3] + sub sp,sp,#25*4 +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r7,r8,r7,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r5,r6 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r7,r8,r7,ror#2 @ E+=K_00_19 + eor r10,r5,r6 @ F_xx_xx + add r7,r7,r3,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r4,r10,ror#2 + add r7,r7,r9 @ E+=X[i] + eor r10,r10,r6,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r7,r7,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r3,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + eor r10,r10,r5,ror#2 @ F_00_19(B,C,D) + add r6,r6,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r7,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + eor r10,r10,r4,ror#2 @ F_00_19(B,C,D) + add r5,r5,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r6,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + eor r10,r10,r3,ror#2 @ F_00_19(B,C,D) + add r4,r4,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r5,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + eor r10,r10,r7,ror#2 @ F_00_19(B,C,D) + add r3,r3,r10 @ E+=F_00_19(B,C,D) + + ldr r8,.LK_20_39 @ [+15+16*4] + cmn sp,#0 @ [+3], clear carry to denote 20_39 +.L_20_39_or_60_79: + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r7,r8,r7,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r5,r6 @ F_xx_xx + mov r9,r9,ror#31 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r4,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r7,r7,r9 @ E+=X[i] + add r7,r7,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r3,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + add r6,r6,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r7,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + add r5,r5,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r6,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + add r4,r4,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r5,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + add r3,r3,r10 @ E+=F_20_39(B,C,D) +#if defined(__thumb2__) + mov r12,sp + teq r14,r12 +#else + teq r14,sp @ preserve carry +#endif + bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4] + bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes + + ldr r8,.LK_40_59 + sub sp,sp,#20*4 @ [+2] +.L_40_59: + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r7,r8,r7,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r5,r6 @ F_xx_xx + mov r9,r9,ror#31 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r4,r10,ror#2 @ F_xx_xx + and r11,r5,r6 @ F_xx_xx + add r7,r7,r9 @ E+=X[i] + add r7,r7,r10 @ E+=F_40_59(B,C,D) + add r7,r7,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r3,r10,ror#2 @ F_xx_xx + and r11,r4,r5 @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + add r6,r6,r10 @ E+=F_40_59(B,C,D) + add r6,r6,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r7,r10,ror#2 @ F_xx_xx + and r11,r3,r4 @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + add r5,r5,r10 @ E+=F_40_59(B,C,D) + add r5,r5,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r6,r10,ror#2 @ F_xx_xx + and r11,r7,r3 @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + add r4,r4,r10 @ E+=F_40_59(B,C,D) + add r4,r4,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r5,r10,ror#2 @ F_xx_xx + and r11,r6,r7 @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + add r3,r3,r10 @ E+=F_40_59(B,C,D) + add r3,r3,r11,ror#2 +#if defined(__thumb2__) + mov r12,sp + teq r14,r12 +#else + teq r14,sp +#endif + bne .L_40_59 @ [+((12+5)*5+2)*4] + + ldr r8,.LK_60_79 + sub sp,sp,#20*4 + cmp sp,#0 @ set carry to denote 60_79 + b .L_20_39_or_60_79 @ [+4], spare 300 bytes +.L_done: + add sp,sp,#80*4 @ "deallocate" stack frame + ldmia r0,{r8,r9,r10,r11,r12} + add r3,r8,r3 + add r4,r9,r4 + add r5,r10,r5,ror#2 + add r6,r11,r6,ror#2 + add r7,r12,r7,ror#2 + stmia r0,{r3,r4,r5,r6,r7} + teq r1,r2 + bne .Lloop @ [+18], total 1307 + +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_sha1_block_data_order,.-cryptogams_sha1_block_data_order + +.align 5 +.LK_00_19:.word 0x5a827999 +.LK_20_39:.word 0x6ed9eba1 +.LK_40_59:.word 0x8f1bbcdc +.LK_60_79:.word 0xca62c1d6 + +.align 5 +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.globl cryptogams_sha1_block_data_order_neon +.type cryptogams_sha1_block_data_order_neon,%function + +.align 4 +cryptogams_sha1_block_data_order_neon: + + stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + add r2,r1,r2,lsl#6 @ r2 to point at the end of r1 + @ dmb @ errata #451034 on early Cortex A8 + @ vstmdb sp!,{d8-d15} @ ABI specification says so + mov r14,sp + sub r12,sp,#64 + adr r8,.LK_00_19 + bic r12,r12,#15 @ align for 128-bit stores + + ldmia r0,{r3,r4,r5,r6,r7} @ load context + mov sp,r12 @ alloca + + vld1.8 {q0,q1},[r1]! @ handles unaligned + veor q15,q15,q15 + vld1.8 {q2,q3},[r1]! + vld1.32 {d28[],d29[]},[r8,:32]! @ load K_00_19 + vrev32.8 q0,q0 @ yes, even on + vrev32.8 q1,q1 @ big-endian... + vrev32.8 q2,q2 + vadd.i32 q8,q0,q14 + vrev32.8 q3,q3 + vadd.i32 q9,q1,q14 + vst1.32 {q8},[r12,:128]! + vadd.i32 q10,q2,q14 + vst1.32 {q9},[r12,:128]! + vst1.32 {q10},[r12,:128]! + ldr r9,[sp] @ big RAW stall + +.Loop_neon: + vext.8 q8,q0,q1,#8 + bic r10,r6,r4 + add r7,r7,r9 + and r11,r5,r4 + vadd.i32 q13,q3,q14 + ldr r9,[sp,#4] + add r7,r7,r3,ror#27 + vext.8 q12,q3,q15,#4 + eor r11,r11,r10 + mov r4,r4,ror#2 + add r7,r7,r11 + veor q8,q8,q0 + bic r10,r5,r3 + add r6,r6,r9 + veor q12,q12,q2 + and r11,r4,r3 + ldr r9,[sp,#8] + veor q12,q12,q8 + add r6,r6,r7,ror#27 + eor r11,r11,r10 + vst1.32 {q13},[r12,:128]! + sub r12,r12,#64 + mov r3,r3,ror#2 + add r6,r6,r11 + vext.8 q13,q15,q12,#4 + bic r10,r4,r7 + add r5,r5,r9 + vadd.i32 q8,q12,q12 + and r11,r3,r7 + ldr r9,[sp,#12] + vsri.32 q8,q12,#31 + add r5,r5,r6,ror#27 + eor r11,r11,r10 + mov r7,r7,ror#2 + vshr.u32 q12,q13,#30 + add r5,r5,r11 + bic r10,r3,r6 + vshl.u32 q13,q13,#2 + add r4,r4,r9 + and r11,r7,r6 + veor q8,q8,q12 + ldr r9,[sp,#16] + add r4,r4,r5,ror#27 + veor q8,q8,q13 + eor r11,r11,r10 + mov r6,r6,ror#2 + add r4,r4,r11 + vext.8 q9,q1,q2,#8 + bic r10,r7,r5 + add r3,r3,r9 + and r11,r6,r5 + vadd.i32 q13,q8,q14 + ldr r9,[sp,#20] + vld1.32 {d28[],d29[]},[r8,:32]! + add r3,r3,r4,ror#27 + vext.8 q12,q8,q15,#4 + eor r11,r11,r10 + mov r5,r5,ror#2 + add r3,r3,r11 + veor q9,q9,q1 + bic r10,r6,r4 + add r7,r7,r9 + veor q12,q12,q3 + and r11,r5,r4 + ldr r9,[sp,#24] + veor q12,q12,q9 + add r7,r7,r3,ror#27 + eor r11,r11,r10 + vst1.32 {q13},[r12,:128]! + mov r4,r4,ror#2 + add r7,r7,r11 + vext.8 q13,q15,q12,#4 + bic r10,r5,r3 + add r6,r6,r9 + vadd.i32 q9,q12,q12 + and r11,r4,r3 + ldr r9,[sp,#28] + vsri.32 q9,q12,#31 + add r6,r6,r7,ror#27 + eor r11,r11,r10 + mov r3,r3,ror#2 + vshr.u32 q12,q13,#30 + add r6,r6,r11 + bic r10,r4,r7 + vshl.u32 q13,q13,#2 + add r5,r5,r9 + and r11,r3,r7 + veor q9,q9,q12 + ldr r9,[sp,#32] + add r5,r5,r6,ror#27 + veor q9,q9,q13 + eor r11,r11,r10 + mov r7,r7,ror#2 + add r5,r5,r11 + vext.8 q10,q2,q3,#8 + bic r10,r3,r6 + add r4,r4,r9 + and r11,r7,r6 + vadd.i32 q13,q9,q14 + ldr r9,[sp,#36] + add r4,r4,r5,ror#27 + vext.8 q12,q9,q15,#4 + eor r11,r11,r10 + mov r6,r6,ror#2 + add r4,r4,r11 + veor q10,q10,q2 + bic r10,r7,r5 + add r3,r3,r9 + veor q12,q12,q8 + and r11,r6,r5 + ldr r9,[sp,#40] + veor q12,q12,q10 + add r3,r3,r4,ror#27 + eor r11,r11,r10 + vst1.32 {q13},[r12,:128]! + mov r5,r5,ror#2 + add r3,r3,r11 + vext.8 q13,q15,q12,#4 + bic r10,r6,r4 + add r7,r7,r9 + vadd.i32 q10,q12,q12 + and r11,r5,r4 + ldr r9,[sp,#44] + vsri.32 q10,q12,#31 + add r7,r7,r3,ror#27 + eor r11,r11,r10 + mov r4,r4,ror#2 + vshr.u32 q12,q13,#30 + add r7,r7,r11 + bic r10,r5,r3 + vshl.u32 q13,q13,#2 + add r6,r6,r9 + and r11,r4,r3 + veor q10,q10,q12 + ldr r9,[sp,#48] + add r6,r6,r7,ror#27 + veor q10,q10,q13 + eor r11,r11,r10 + mov r3,r3,ror#2 + add r6,r6,r11 + vext.8 q11,q3,q8,#8 + bic r10,r4,r7 + add r5,r5,r9 + and r11,r3,r7 + vadd.i32 q13,q10,q14 + ldr r9,[sp,#52] + add r5,r5,r6,ror#27 + vext.8 q12,q10,q15,#4 + eor r11,r11,r10 + mov r7,r7,ror#2 + add r5,r5,r11 + veor q11,q11,q3 + bic r10,r3,r6 + add r4,r4,r9 + veor q12,q12,q9 + and r11,r7,r6 + ldr r9,[sp,#56] + veor q12,q12,q11 + add r4,r4,r5,ror#27 + eor r11,r11,r10 + vst1.32 {q13},[r12,:128]! + mov r6,r6,ror#2 + add r4,r4,r11 + vext.8 q13,q15,q12,#4 + bic r10,r7,r5 + add r3,r3,r9 + vadd.i32 q11,q12,q12 + and r11,r6,r5 + ldr r9,[sp,#60] + vsri.32 q11,q12,#31 + add r3,r3,r4,ror#27 + eor r11,r11,r10 + mov r5,r5,ror#2 + vshr.u32 q12,q13,#30 + add r3,r3,r11 + bic r10,r6,r4 + vshl.u32 q13,q13,#2 + add r7,r7,r9 + and r11,r5,r4 + veor q11,q11,q12 + ldr r9,[sp,#0] + add r7,r7,r3,ror#27 + veor q11,q11,q13 + eor r11,r11,r10 + mov r4,r4,ror#2 + add r7,r7,r11 + vext.8 q12,q10,q11,#8 + bic r10,r5,r3 + add r6,r6,r9 + and r11,r4,r3 + veor q0,q0,q8 + ldr r9,[sp,#4] + add r6,r6,r7,ror#27 + veor q0,q0,q1 + eor r11,r11,r10 + mov r3,r3,ror#2 + vadd.i32 q13,q11,q14 + add r6,r6,r11 + bic r10,r4,r7 + veor q12,q12,q0 + add r5,r5,r9 + and r11,r3,r7 + vshr.u32 q0,q12,#30 + ldr r9,[sp,#8] + add r5,r5,r6,ror#27 + vst1.32 {q13},[r12,:128]! + sub r12,r12,#64 + eor r11,r11,r10 + mov r7,r7,ror#2 + vsli.32 q0,q12,#2 + add r5,r5,r11 + bic r10,r3,r6 + add r4,r4,r9 + and r11,r7,r6 + ldr r9,[sp,#12] + add r4,r4,r5,ror#27 + eor r11,r11,r10 + mov r6,r6,ror#2 + add r4,r4,r11 + bic r10,r7,r5 + add r3,r3,r9 + and r11,r6,r5 + ldr r9,[sp,#16] + add r3,r3,r4,ror#27 + eor r11,r11,r10 + mov r5,r5,ror#2 + add r3,r3,r11 + vext.8 q12,q11,q0,#8 + eor r10,r4,r6 + add r7,r7,r9 + ldr r9,[sp,#20] + veor q1,q1,q9 + eor r11,r10,r5 + add r7,r7,r3,ror#27 + veor q1,q1,q2 + mov r4,r4,ror#2 + add r7,r7,r11 + vadd.i32 q13,q0,q14 + eor r10,r3,r5 + add r6,r6,r9 + veor q12,q12,q1 + ldr r9,[sp,#24] + eor r11,r10,r4 + vshr.u32 q1,q12,#30 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + vst1.32 {q13},[r12,:128]! + add r6,r6,r11 + eor r10,r7,r4 + vsli.32 q1,q12,#2 + add r5,r5,r9 + ldr r9,[sp,#28] + eor r11,r10,r3 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + eor r10,r6,r3 + add r4,r4,r9 + ldr r9,[sp,#32] + eor r11,r10,r7 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + vext.8 q12,q0,q1,#8 + eor r10,r5,r7 + add r3,r3,r9 + ldr r9,[sp,#36] + veor q2,q2,q10 + eor r11,r10,r6 + add r3,r3,r4,ror#27 + veor q2,q2,q3 + mov r5,r5,ror#2 + add r3,r3,r11 + vadd.i32 q13,q1,q14 + eor r10,r4,r6 + vld1.32 {d28[],d29[]},[r8,:32]! + add r7,r7,r9 + veor q12,q12,q2 + ldr r9,[sp,#40] + eor r11,r10,r5 + vshr.u32 q2,q12,#30 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + vst1.32 {q13},[r12,:128]! + add r7,r7,r11 + eor r10,r3,r5 + vsli.32 q2,q12,#2 + add r6,r6,r9 + ldr r9,[sp,#44] + eor r11,r10,r4 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + add r6,r6,r11 + eor r10,r7,r4 + add r5,r5,r9 + ldr r9,[sp,#48] + eor r11,r10,r3 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + vext.8 q12,q1,q2,#8 + eor r10,r6,r3 + add r4,r4,r9 + ldr r9,[sp,#52] + veor q3,q3,q11 + eor r11,r10,r7 + add r4,r4,r5,ror#27 + veor q3,q3,q8 + mov r6,r6,ror#2 + add r4,r4,r11 + vadd.i32 q13,q2,q14 + eor r10,r5,r7 + add r3,r3,r9 + veor q12,q12,q3 + ldr r9,[sp,#56] + eor r11,r10,r6 + vshr.u32 q3,q12,#30 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + vst1.32 {q13},[r12,:128]! + add r3,r3,r11 + eor r10,r4,r6 + vsli.32 q3,q12,#2 + add r7,r7,r9 + ldr r9,[sp,#60] + eor r11,r10,r5 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + add r7,r7,r11 + eor r10,r3,r5 + add r6,r6,r9 + ldr r9,[sp,#0] + eor r11,r10,r4 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + add r6,r6,r11 + vext.8 q12,q2,q3,#8 + eor r10,r7,r4 + add r5,r5,r9 + ldr r9,[sp,#4] + veor q8,q8,q0 + eor r11,r10,r3 + add r5,r5,r6,ror#27 + veor q8,q8,q9 + mov r7,r7,ror#2 + add r5,r5,r11 + vadd.i32 q13,q3,q14 + eor r10,r6,r3 + add r4,r4,r9 + veor q12,q12,q8 + ldr r9,[sp,#8] + eor r11,r10,r7 + vshr.u32 q8,q12,#30 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + vst1.32 {q13},[r12,:128]! + sub r12,r12,#64 + add r4,r4,r11 + eor r10,r5,r7 + vsli.32 q8,q12,#2 + add r3,r3,r9 + ldr r9,[sp,#12] + eor r11,r10,r6 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + add r3,r3,r11 + eor r10,r4,r6 + add r7,r7,r9 + ldr r9,[sp,#16] + eor r11,r10,r5 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + add r7,r7,r11 + vext.8 q12,q3,q8,#8 + eor r10,r3,r5 + add r6,r6,r9 + ldr r9,[sp,#20] + veor q9,q9,q1 + eor r11,r10,r4 + add r6,r6,r7,ror#27 + veor q9,q9,q10 + mov r3,r3,ror#2 + add r6,r6,r11 + vadd.i32 q13,q8,q14 + eor r10,r7,r4 + add r5,r5,r9 + veor q12,q12,q9 + ldr r9,[sp,#24] + eor r11,r10,r3 + vshr.u32 q9,q12,#30 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + vst1.32 {q13},[r12,:128]! + add r5,r5,r11 + eor r10,r6,r3 + vsli.32 q9,q12,#2 + add r4,r4,r9 + ldr r9,[sp,#28] + eor r11,r10,r7 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + eor r10,r5,r7 + add r3,r3,r9 + ldr r9,[sp,#32] + eor r11,r10,r6 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + add r3,r3,r11 + vext.8 q12,q8,q9,#8 + add r7,r7,r9 + and r10,r5,r6 + ldr r9,[sp,#36] + veor q10,q10,q2 + add r7,r7,r3,ror#27 + eor r11,r5,r6 + veor q10,q10,q11 + add r7,r7,r10 + and r11,r11,r4 + vadd.i32 q13,q9,q14 + mov r4,r4,ror#2 + add r7,r7,r11 + veor q12,q12,q10 + add r6,r6,r9 + and r10,r4,r5 + vshr.u32 q10,q12,#30 + ldr r9,[sp,#40] + add r6,r6,r7,ror#27 + vst1.32 {q13},[r12,:128]! + eor r11,r4,r5 + add r6,r6,r10 + vsli.32 q10,q12,#2 + and r11,r11,r3 + mov r3,r3,ror#2 + add r6,r6,r11 + add r5,r5,r9 + and r10,r3,r4 + ldr r9,[sp,#44] + add r5,r5,r6,ror#27 + eor r11,r3,r4 + add r5,r5,r10 + and r11,r11,r7 + mov r7,r7,ror#2 + add r5,r5,r11 + add r4,r4,r9 + and r10,r7,r3 + ldr r9,[sp,#48] + add r4,r4,r5,ror#27 + eor r11,r7,r3 + add r4,r4,r10 + and r11,r11,r6 + mov r6,r6,ror#2 + add r4,r4,r11 + vext.8 q12,q9,q10,#8 + add r3,r3,r9 + and r10,r6,r7 + ldr r9,[sp,#52] + veor q11,q11,q3 + add r3,r3,r4,ror#27 + eor r11,r6,r7 + veor q11,q11,q0 + add r3,r3,r10 + and r11,r11,r5 + vadd.i32 q13,q10,q14 + mov r5,r5,ror#2 + vld1.32 {d28[],d29[]},[r8,:32]! + add r3,r3,r11 + veor q12,q12,q11 + add r7,r7,r9 + and r10,r5,r6 + vshr.u32 q11,q12,#30 + ldr r9,[sp,#56] + add r7,r7,r3,ror#27 + vst1.32 {q13},[r12,:128]! + eor r11,r5,r6 + add r7,r7,r10 + vsli.32 q11,q12,#2 + and r11,r11,r4 + mov r4,r4,ror#2 + add r7,r7,r11 + add r6,r6,r9 + and r10,r4,r5 + ldr r9,[sp,#60] + add r6,r6,r7,ror#27 + eor r11,r4,r5 + add r6,r6,r10 + and r11,r11,r3 + mov r3,r3,ror#2 + add r6,r6,r11 + add r5,r5,r9 + and r10,r3,r4 + ldr r9,[sp,#0] + add r5,r5,r6,ror#27 + eor r11,r3,r4 + add r5,r5,r10 + and r11,r11,r7 + mov r7,r7,ror#2 + add r5,r5,r11 + vext.8 q12,q10,q11,#8 + add r4,r4,r9 + and r10,r7,r3 + ldr r9,[sp,#4] + veor q0,q0,q8 + add r4,r4,r5,ror#27 + eor r11,r7,r3 + veor q0,q0,q1 + add r4,r4,r10 + and r11,r11,r6 + vadd.i32 q13,q11,q14 + mov r6,r6,ror#2 + add r4,r4,r11 + veor q12,q12,q0 + add r3,r3,r9 + and r10,r6,r7 + vshr.u32 q0,q12,#30 + ldr r9,[sp,#8] + add r3,r3,r4,ror#27 + vst1.32 {q13},[r12,:128]! + sub r12,r12,#64 + eor r11,r6,r7 + add r3,r3,r10 + vsli.32 q0,q12,#2 + and r11,r11,r5 + mov r5,r5,ror#2 + add r3,r3,r11 + add r7,r7,r9 + and r10,r5,r6 + ldr r9,[sp,#12] + add r7,r7,r3,ror#27 + eor r11,r5,r6 + add r7,r7,r10 + and r11,r11,r4 + mov r4,r4,ror#2 + add r7,r7,r11 + add r6,r6,r9 + and r10,r4,r5 + ldr r9,[sp,#16] + add r6,r6,r7,ror#27 + eor r11,r4,r5 + add r6,r6,r10 + and r11,r11,r3 + mov r3,r3,ror#2 + add r6,r6,r11 + vext.8 q12,q11,q0,#8 + add r5,r5,r9 + and r10,r3,r4 + ldr r9,[sp,#20] + veor q1,q1,q9 + add r5,r5,r6,ror#27 + eor r11,r3,r4 + veor q1,q1,q2 + add r5,r5,r10 + and r11,r11,r7 + vadd.i32 q13,q0,q14 + mov r7,r7,ror#2 + add r5,r5,r11 + veor q12,q12,q1 + add r4,r4,r9 + and r10,r7,r3 + vshr.u32 q1,q12,#30 + ldr r9,[sp,#24] + add r4,r4,r5,ror#27 + vst1.32 {q13},[r12,:128]! + eor r11,r7,r3 + add r4,r4,r10 + vsli.32 q1,q12,#2 + and r11,r11,r6 + mov r6,r6,ror#2 + add r4,r4,r11 + add r3,r3,r9 + and r10,r6,r7 + ldr r9,[sp,#28] + add r3,r3,r4,ror#27 + eor r11,r6,r7 + add r3,r3,r10 + and r11,r11,r5 + mov r5,r5,ror#2 + add r3,r3,r11 + add r7,r7,r9 + and r10,r5,r6 + ldr r9,[sp,#32] + add r7,r7,r3,ror#27 + eor r11,r5,r6 + add r7,r7,r10 + and r11,r11,r4 + mov r4,r4,ror#2 + add r7,r7,r11 + vext.8 q12,q0,q1,#8 + add r6,r6,r9 + and r10,r4,r5 + ldr r9,[sp,#36] + veor q2,q2,q10 + add r6,r6,r7,ror#27 + eor r11,r4,r5 + veor q2,q2,q3 + add r6,r6,r10 + and r11,r11,r3 + vadd.i32 q13,q1,q14 + mov r3,r3,ror#2 + add r6,r6,r11 + veor q12,q12,q2 + add r5,r5,r9 + and r10,r3,r4 + vshr.u32 q2,q12,#30 + ldr r9,[sp,#40] + add r5,r5,r6,ror#27 + vst1.32 {q13},[r12,:128]! + eor r11,r3,r4 + add r5,r5,r10 + vsli.32 q2,q12,#2 + and r11,r11,r7 + mov r7,r7,ror#2 + add r5,r5,r11 + add r4,r4,r9 + and r10,r7,r3 + ldr r9,[sp,#44] + add r4,r4,r5,ror#27 + eor r11,r7,r3 + add r4,r4,r10 + and r11,r11,r6 + mov r6,r6,ror#2 + add r4,r4,r11 + add r3,r3,r9 + and r10,r6,r7 + ldr r9,[sp,#48] + add r3,r3,r4,ror#27 + eor r11,r6,r7 + add r3,r3,r10 + and r11,r11,r5 + mov r5,r5,ror#2 + add r3,r3,r11 + vext.8 q12,q1,q2,#8 + eor r10,r4,r6 + add r7,r7,r9 + ldr r9,[sp,#52] + veor q3,q3,q11 + eor r11,r10,r5 + add r7,r7,r3,ror#27 + veor q3,q3,q8 + mov r4,r4,ror#2 + add r7,r7,r11 + vadd.i32 q13,q2,q14 + eor r10,r3,r5 + add r6,r6,r9 + veor q12,q12,q3 + ldr r9,[sp,#56] + eor r11,r10,r4 + vshr.u32 q3,q12,#30 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + vst1.32 {q13},[r12,:128]! + add r6,r6,r11 + eor r10,r7,r4 + vsli.32 q3,q12,#2 + add r5,r5,r9 + ldr r9,[sp,#60] + eor r11,r10,r3 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + eor r10,r6,r3 + add r4,r4,r9 + ldr r9,[sp,#0] + eor r11,r10,r7 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + vadd.i32 q13,q3,q14 + eor r10,r5,r7 + add r3,r3,r9 + vst1.32 {q13},[r12,:128]! + sub r12,r12,#64 + teq r1,r2 + sub r8,r8,#16 + it eq + subeq r1,r1,#64 + vld1.8 {q0,q1},[r1]! + ldr r9,[sp,#4] + eor r11,r10,r6 + vld1.8 {q2,q3},[r1]! + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + vld1.32 {d28[],d29[]},[r8,:32]! + add r3,r3,r11 + eor r10,r4,r6 + vrev32.8 q0,q0 + add r7,r7,r9 + ldr r9,[sp,#8] + eor r11,r10,r5 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + add r7,r7,r11 + eor r10,r3,r5 + add r6,r6,r9 + ldr r9,[sp,#12] + eor r11,r10,r4 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + add r6,r6,r11 + eor r10,r7,r4 + add r5,r5,r9 + ldr r9,[sp,#16] + eor r11,r10,r3 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + vrev32.8 q1,q1 + eor r10,r6,r3 + add r4,r4,r9 + vadd.i32 q8,q0,q14 + ldr r9,[sp,#20] + eor r11,r10,r7 + vst1.32 {q8},[r12,:128]! + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + eor r10,r5,r7 + add r3,r3,r9 + ldr r9,[sp,#24] + eor r11,r10,r6 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + add r3,r3,r11 + eor r10,r4,r6 + add r7,r7,r9 + ldr r9,[sp,#28] + eor r11,r10,r5 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + add r7,r7,r11 + eor r10,r3,r5 + add r6,r6,r9 + ldr r9,[sp,#32] + eor r11,r10,r4 + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + add r6,r6,r11 + vrev32.8 q2,q2 + eor r10,r7,r4 + add r5,r5,r9 + vadd.i32 q9,q1,q14 + ldr r9,[sp,#36] + eor r11,r10,r3 + vst1.32 {q9},[r12,:128]! + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + eor r10,r6,r3 + add r4,r4,r9 + ldr r9,[sp,#40] + eor r11,r10,r7 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + eor r10,r5,r7 + add r3,r3,r9 + ldr r9,[sp,#44] + eor r11,r10,r6 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + add r3,r3,r11 + eor r10,r4,r6 + add r7,r7,r9 + ldr r9,[sp,#48] + eor r11,r10,r5 + add r7,r7,r3,ror#27 + mov r4,r4,ror#2 + add r7,r7,r11 + vrev32.8 q3,q3 + eor r10,r3,r5 + add r6,r6,r9 + vadd.i32 q10,q2,q14 + ldr r9,[sp,#52] + eor r11,r10,r4 + vst1.32 {q10},[r12,:128]! + add r6,r6,r7,ror#27 + mov r3,r3,ror#2 + add r6,r6,r11 + eor r10,r7,r4 + add r5,r5,r9 + ldr r9,[sp,#56] + eor r11,r10,r3 + add r5,r5,r6,ror#27 + mov r7,r7,ror#2 + add r5,r5,r11 + eor r10,r6,r3 + add r4,r4,r9 + ldr r9,[sp,#60] + eor r11,r10,r7 + add r4,r4,r5,ror#27 + mov r6,r6,ror#2 + add r4,r4,r11 + eor r10,r5,r7 + add r3,r3,r9 + eor r11,r10,r6 + add r3,r3,r4,ror#27 + mov r5,r5,ror#2 + add r3,r3,r11 + ldmia r0,{r9,r10,r11,r12} @ accumulate context + add r3,r3,r9 + ldr r9,[r0,#16] + add r4,r4,r10 + add r5,r5,r11 + add r6,r6,r12 + it eq + moveq sp,r14 + add r7,r7,r9 + it ne + ldrne r9,[sp] + stmia r0,{r3,r4,r5,r6,r7} + itt ne + addne r12,sp,#3*16 + bne .Loop_neon + + @ vldmia sp!,{d8-d15} + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +.size cryptogams_sha1_block_data_order_neon,.-cryptogams_sha1_block_data_order_neon +#endif diff --git a/extension/third_party/cryptopp/sha1_armv4.h b/extension/third_party/cryptopp/sha1_armv4.h new file mode 100644 index 00000000..7cdb6dab --- /dev/null +++ b/extension/third_party/cryptopp/sha1_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA1. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA1_ARMV4_H +#define CRYPTOGAMS_SHA1_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified sha1_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha1_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA1_ARMV4_H */ diff --git a/extension/third_party/cryptopp/sha256_armv4.S b/extension/third_party/cryptopp/sha256_armv4.S new file mode 100644 index 00000000..e8c9d16d --- /dev/null +++ b/extension/third_party/cryptopp/sha256_armv4.S @@ -0,0 +1,2670 @@ +@ Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved. +@ +@ ==================================================================== +@ Written by Andy Polyakov for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ JW, MAY 2019: Begin defines from taken from arm_arch.h +@ The defines were included through the header. + +# if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +# endif + +# if !defined(__ARM_MAX_ARCH__) +# define __ARM_MAX_ARCH__ __ARM_ARCH__ +# endif + +# if __ARM_MAX_ARCH__<__ARM_ARCH__ +# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__" +# elif __ARM_MAX_ARCH__!=__ARM_ARCH__ +# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__) +# error "can't build universal big-endian binary" +# endif +# endif + +# define CRYPTOGAMS_ARMV7_NEON (1<<0) + +@ JW, MAY 2019: End defines from taken from arm_arch.h +@ Back to original Cryptogams code + +#if defined(__thumb2__) +.syntax unified +.thumb +#else +.code 32 +#endif + +.text + +.type K256,%object +.align 5 +K256: +.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 +.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 +.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 +.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 +.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc +.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da +.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 +.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 +.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 +.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 +.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 +.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 +.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 +.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 +.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 +.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +.size K256,.-K256 +.word 0 @ terminator + +.align 5 +.globl cryptogams_sha256_block_data_order +.type cryptogams_sha256_block_data_order,%function + +cryptogams_sha256_block_data_order: +.Lcryptogams_sha256_block_data_order: + +#if __ARM_ARCH__<7 && !defined(__thumb2__) + sub r3,pc,#8 @ cryptogams_sha256_block_data_order +#else + adr r3,.Lcryptogams_sha256_block_data_order +#endif + + add r2,r1,r2,lsl#6 @ len to point at the end of inp + stmdb sp!,{r0,r1,r2,r4-r11,lr} + ldmia r0,{r4,r5,r6,r7,r8,r9,r10,r11} + sub r14,r3,#256+32 @ K256 + sub sp,sp,#16*4 @ alloca(X[16]) + +.Loop: +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 +# else + ldrb r2,[r1,#3] +# endif + eor r3,r5,r6 @ magic + eor r12,r12,r12 +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 0 +# if 0==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r8,r8,ror#5 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r8,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 0 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 0==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r8,r8,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r8,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r11,r11,r2 @ h+=X[i] + str r2,[sp,#0*4] + eor r2,r9,r10 + add r11,r11,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r8 + add r11,r11,r12 @ h+=K256[i] + eor r2,r2,r10 @ Ch(e,f,g) + eor r0,r4,r4,ror#11 + add r11,r11,r2 @ h+=Ch(e,f,g) +#if 0==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 0<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r4,r5 @ a^b, b^c in next round +#else + ldr r2,[sp,#2*4] @ from future BODY_16_xx + eor r12,r4,r5 @ a^b, b^c in next round + ldr r1,[sp,#15*4] @ from future BODY_16_xx +#endif + eor r0,r0,r4,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r7,r7,r11 @ d+=h + eor r3,r3,r5 @ Maj(a,b,c) + add r11,r11,r0,ror#2 @ h+=Sigma0(a) + @ add r11,r11,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 1 +# if 1==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r7,r7,ror#5 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r7,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 1 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 1==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r7,r7,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r7,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r10,r10,r2 @ h+=X[i] + str r2,[sp,#1*4] + eor r2,r8,r9 + add r10,r10,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r7 + add r10,r10,r3 @ h+=K256[i] + eor r2,r2,r9 @ Ch(e,f,g) + eor r0,r11,r11,ror#11 + add r10,r10,r2 @ h+=Ch(e,f,g) +#if 1==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 1<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r11,r4 @ a^b, b^c in next round +#else + ldr r2,[sp,#3*4] @ from future BODY_16_xx + eor r3,r11,r4 @ a^b, b^c in next round + ldr r1,[sp,#0*4] @ from future BODY_16_xx +#endif + eor r0,r0,r11,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r6,r6,r10 @ d+=h + eor r12,r12,r4 @ Maj(a,b,c) + add r10,r10,r0,ror#2 @ h+=Sigma0(a) + @ add r10,r10,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 2 +# if 2==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r6,r6,ror#5 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r6,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 2 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 2==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r6,r6,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r6,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r9,r9,r2 @ h+=X[i] + str r2,[sp,#2*4] + eor r2,r7,r8 + add r9,r9,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r6 + add r9,r9,r12 @ h+=K256[i] + eor r2,r2,r8 @ Ch(e,f,g) + eor r0,r10,r10,ror#11 + add r9,r9,r2 @ h+=Ch(e,f,g) +#if 2==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 2<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r10,r11 @ a^b, b^c in next round +#else + ldr r2,[sp,#4*4] @ from future BODY_16_xx + eor r12,r10,r11 @ a^b, b^c in next round + ldr r1,[sp,#1*4] @ from future BODY_16_xx +#endif + eor r0,r0,r10,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r5,r5,r9 @ d+=h + eor r3,r3,r11 @ Maj(a,b,c) + add r9,r9,r0,ror#2 @ h+=Sigma0(a) + @ add r9,r9,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 3 +# if 3==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r5,r5,ror#5 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r5,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 3 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 3==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r5,r5,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r5,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r8,r8,r2 @ h+=X[i] + str r2,[sp,#3*4] + eor r2,r6,r7 + add r8,r8,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r5 + add r8,r8,r3 @ h+=K256[i] + eor r2,r2,r7 @ Ch(e,f,g) + eor r0,r9,r9,ror#11 + add r8,r8,r2 @ h+=Ch(e,f,g) +#if 3==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 3<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r9,r10 @ a^b, b^c in next round +#else + ldr r2,[sp,#5*4] @ from future BODY_16_xx + eor r3,r9,r10 @ a^b, b^c in next round + ldr r1,[sp,#2*4] @ from future BODY_16_xx +#endif + eor r0,r0,r9,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r4,r4,r8 @ d+=h + eor r12,r12,r10 @ Maj(a,b,c) + add r8,r8,r0,ror#2 @ h+=Sigma0(a) + @ add r8,r8,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 4 +# if 4==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r4,r4,ror#5 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r4,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 4 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 4==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r4,r4,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r4,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r7,r7,r2 @ h+=X[i] + str r2,[sp,#4*4] + eor r2,r5,r6 + add r7,r7,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r4 + add r7,r7,r12 @ h+=K256[i] + eor r2,r2,r6 @ Ch(e,f,g) + eor r0,r8,r8,ror#11 + add r7,r7,r2 @ h+=Ch(e,f,g) +#if 4==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 4<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r8,r9 @ a^b, b^c in next round +#else + ldr r2,[sp,#6*4] @ from future BODY_16_xx + eor r12,r8,r9 @ a^b, b^c in next round + ldr r1,[sp,#3*4] @ from future BODY_16_xx +#endif + eor r0,r0,r8,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r11,r11,r7 @ d+=h + eor r3,r3,r9 @ Maj(a,b,c) + add r7,r7,r0,ror#2 @ h+=Sigma0(a) + @ add r7,r7,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 5 +# if 5==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r11,r11,ror#5 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r11,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 5 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 5==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r11,r11,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r11,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r6,r6,r2 @ h+=X[i] + str r2,[sp,#5*4] + eor r2,r4,r5 + add r6,r6,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r11 + add r6,r6,r3 @ h+=K256[i] + eor r2,r2,r5 @ Ch(e,f,g) + eor r0,r7,r7,ror#11 + add r6,r6,r2 @ h+=Ch(e,f,g) +#if 5==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 5<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r7,r8 @ a^b, b^c in next round +#else + ldr r2,[sp,#7*4] @ from future BODY_16_xx + eor r3,r7,r8 @ a^b, b^c in next round + ldr r1,[sp,#4*4] @ from future BODY_16_xx +#endif + eor r0,r0,r7,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r10,r10,r6 @ d+=h + eor r12,r12,r8 @ Maj(a,b,c) + add r6,r6,r0,ror#2 @ h+=Sigma0(a) + @ add r6,r6,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 6 +# if 6==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r10,r10,ror#5 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r10,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 6 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 6==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r10,r10,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r10,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r5,r5,r2 @ h+=X[i] + str r2,[sp,#6*4] + eor r2,r11,r4 + add r5,r5,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r10 + add r5,r5,r12 @ h+=K256[i] + eor r2,r2,r4 @ Ch(e,f,g) + eor r0,r6,r6,ror#11 + add r5,r5,r2 @ h+=Ch(e,f,g) +#if 6==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 6<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r6,r7 @ a^b, b^c in next round +#else + ldr r2,[sp,#8*4] @ from future BODY_16_xx + eor r12,r6,r7 @ a^b, b^c in next round + ldr r1,[sp,#5*4] @ from future BODY_16_xx +#endif + eor r0,r0,r6,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r9,r9,r5 @ d+=h + eor r3,r3,r7 @ Maj(a,b,c) + add r5,r5,r0,ror#2 @ h+=Sigma0(a) + @ add r5,r5,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 7 +# if 7==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r9,r9,ror#5 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r9,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 7 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 7==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r9,r9,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r9,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r4,r4,r2 @ h+=X[i] + str r2,[sp,#7*4] + eor r2,r10,r11 + add r4,r4,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r9 + add r4,r4,r3 @ h+=K256[i] + eor r2,r2,r11 @ Ch(e,f,g) + eor r0,r5,r5,ror#11 + add r4,r4,r2 @ h+=Ch(e,f,g) +#if 7==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 7<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r5,r6 @ a^b, b^c in next round +#else + ldr r2,[sp,#9*4] @ from future BODY_16_xx + eor r3,r5,r6 @ a^b, b^c in next round + ldr r1,[sp,#6*4] @ from future BODY_16_xx +#endif + eor r0,r0,r5,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r8,r8,r4 @ d+=h + eor r12,r12,r6 @ Maj(a,b,c) + add r4,r4,r0,ror#2 @ h+=Sigma0(a) + @ add r4,r4,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 8 +# if 8==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r8,r8,ror#5 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r8,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 8 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 8==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r8,r8,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r8,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r11,r11,r2 @ h+=X[i] + str r2,[sp,#8*4] + eor r2,r9,r10 + add r11,r11,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r8 + add r11,r11,r12 @ h+=K256[i] + eor r2,r2,r10 @ Ch(e,f,g) + eor r0,r4,r4,ror#11 + add r11,r11,r2 @ h+=Ch(e,f,g) +#if 8==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 8<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r4,r5 @ a^b, b^c in next round +#else + ldr r2,[sp,#10*4] @ from future BODY_16_xx + eor r12,r4,r5 @ a^b, b^c in next round + ldr r1,[sp,#7*4] @ from future BODY_16_xx +#endif + eor r0,r0,r4,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r7,r7,r11 @ d+=h + eor r3,r3,r5 @ Maj(a,b,c) + add r11,r11,r0,ror#2 @ h+=Sigma0(a) + @ add r11,r11,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 9 +# if 9==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r7,r7,ror#5 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r7,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 9 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 9==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r7,r7,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r7,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r10,r10,r2 @ h+=X[i] + str r2,[sp,#9*4] + eor r2,r8,r9 + add r10,r10,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r7 + add r10,r10,r3 @ h+=K256[i] + eor r2,r2,r9 @ Ch(e,f,g) + eor r0,r11,r11,ror#11 + add r10,r10,r2 @ h+=Ch(e,f,g) +#if 9==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 9<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r11,r4 @ a^b, b^c in next round +#else + ldr r2,[sp,#11*4] @ from future BODY_16_xx + eor r3,r11,r4 @ a^b, b^c in next round + ldr r1,[sp,#8*4] @ from future BODY_16_xx +#endif + eor r0,r0,r11,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r6,r6,r10 @ d+=h + eor r12,r12,r4 @ Maj(a,b,c) + add r10,r10,r0,ror#2 @ h+=Sigma0(a) + @ add r10,r10,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 10 +# if 10==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r6,r6,ror#5 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r6,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 10 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 10==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r6,r6,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r6,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r9,r9,r2 @ h+=X[i] + str r2,[sp,#10*4] + eor r2,r7,r8 + add r9,r9,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r6 + add r9,r9,r12 @ h+=K256[i] + eor r2,r2,r8 @ Ch(e,f,g) + eor r0,r10,r10,ror#11 + add r9,r9,r2 @ h+=Ch(e,f,g) +#if 10==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 10<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r10,r11 @ a^b, b^c in next round +#else + ldr r2,[sp,#12*4] @ from future BODY_16_xx + eor r12,r10,r11 @ a^b, b^c in next round + ldr r1,[sp,#9*4] @ from future BODY_16_xx +#endif + eor r0,r0,r10,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r5,r5,r9 @ d+=h + eor r3,r3,r11 @ Maj(a,b,c) + add r9,r9,r0,ror#2 @ h+=Sigma0(a) + @ add r9,r9,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 11 +# if 11==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r5,r5,ror#5 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r5,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 11 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 11==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r5,r5,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r5,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r8,r8,r2 @ h+=X[i] + str r2,[sp,#11*4] + eor r2,r6,r7 + add r8,r8,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r5 + add r8,r8,r3 @ h+=K256[i] + eor r2,r2,r7 @ Ch(e,f,g) + eor r0,r9,r9,ror#11 + add r8,r8,r2 @ h+=Ch(e,f,g) +#if 11==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 11<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r9,r10 @ a^b, b^c in next round +#else + ldr r2,[sp,#13*4] @ from future BODY_16_xx + eor r3,r9,r10 @ a^b, b^c in next round + ldr r1,[sp,#10*4] @ from future BODY_16_xx +#endif + eor r0,r0,r9,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r4,r4,r8 @ d+=h + eor r12,r12,r10 @ Maj(a,b,c) + add r8,r8,r0,ror#2 @ h+=Sigma0(a) + @ add r8,r8,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 12 +# if 12==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r4,r4,ror#5 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r4,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 12 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 12==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r4,r4,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r4,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r7,r7,r2 @ h+=X[i] + str r2,[sp,#12*4] + eor r2,r5,r6 + add r7,r7,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r4 + add r7,r7,r12 @ h+=K256[i] + eor r2,r2,r6 @ Ch(e,f,g) + eor r0,r8,r8,ror#11 + add r7,r7,r2 @ h+=Ch(e,f,g) +#if 12==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 12<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r8,r9 @ a^b, b^c in next round +#else + ldr r2,[sp,#14*4] @ from future BODY_16_xx + eor r12,r8,r9 @ a^b, b^c in next round + ldr r1,[sp,#11*4] @ from future BODY_16_xx +#endif + eor r0,r0,r8,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r11,r11,r7 @ d+=h + eor r3,r3,r9 @ Maj(a,b,c) + add r7,r7,r0,ror#2 @ h+=Sigma0(a) + @ add r7,r7,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 13 +# if 13==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r11,r11,ror#5 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r11,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 13 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 13==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r11,r11,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r11,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r6,r6,r2 @ h+=X[i] + str r2,[sp,#13*4] + eor r2,r4,r5 + add r6,r6,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r11 + add r6,r6,r3 @ h+=K256[i] + eor r2,r2,r5 @ Ch(e,f,g) + eor r0,r7,r7,ror#11 + add r6,r6,r2 @ h+=Ch(e,f,g) +#if 13==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 13<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r7,r8 @ a^b, b^c in next round +#else + ldr r2,[sp,#15*4] @ from future BODY_16_xx + eor r3,r7,r8 @ a^b, b^c in next round + ldr r1,[sp,#12*4] @ from future BODY_16_xx +#endif + eor r0,r0,r7,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r10,r10,r6 @ d+=h + eor r12,r12,r8 @ Maj(a,b,c) + add r6,r6,r0,ror#2 @ h+=Sigma0(a) + @ add r6,r6,r12 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 14 +# if 14==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r10,r10,ror#5 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + eor r0,r0,r10,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 14 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + ldrb r12,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r12,lsl#8 + ldrb r12,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 14==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r10,r10,ror#5 + orr r2,r2,r12,lsl#24 + eor r0,r0,r10,ror#19 @ Sigma1(e) +#endif + ldr r12,[r14],#4 @ *K256++ + add r5,r5,r2 @ h+=X[i] + str r2,[sp,#14*4] + eor r2,r11,r4 + add r5,r5,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r10 + add r5,r5,r12 @ h+=K256[i] + eor r2,r2,r4 @ Ch(e,f,g) + eor r0,r6,r6,ror#11 + add r5,r5,r2 @ h+=Ch(e,f,g) +#if 14==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 14<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r6,r7 @ a^b, b^c in next round +#else + ldr r2,[sp,#0*4] @ from future BODY_16_xx + eor r12,r6,r7 @ a^b, b^c in next round + ldr r1,[sp,#13*4] @ from future BODY_16_xx +#endif + eor r0,r0,r6,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r9,r9,r5 @ d+=h + eor r3,r3,r7 @ Maj(a,b,c) + add r5,r5,r0,ror#2 @ h+=Sigma0(a) + @ add r5,r5,r3 @ h+=Maj(a,b,c) +#if __ARM_ARCH__>=7 + @ ldr r2,[r1],#4 @ 15 +# if 15==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r9,r9,ror#5 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + eor r0,r0,r9,ror#19 @ Sigma1(e) +# ifndef __ARMEB__ + rev r2,r2 +# endif +#else + @ ldrb r2,[r1,#3] @ 15 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + ldrb r3,[r1,#2] + ldrb r0,[r1,#1] + orr r2,r2,r3,lsl#8 + ldrb r3,[r1],#4 + orr r2,r2,r0,lsl#16 +# if 15==15 + str r1,[sp,#17*4] @ make room for r1 +# endif + eor r0,r9,r9,ror#5 + orr r2,r2,r3,lsl#24 + eor r0,r0,r9,ror#19 @ Sigma1(e) +#endif + ldr r3,[r14],#4 @ *K256++ + add r4,r4,r2 @ h+=X[i] + str r2,[sp,#15*4] + eor r2,r10,r11 + add r4,r4,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r9 + add r4,r4,r3 @ h+=K256[i] + eor r2,r2,r11 @ Ch(e,f,g) + eor r0,r5,r5,ror#11 + add r4,r4,r2 @ h+=Ch(e,f,g) +#if 15==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 15<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r5,r6 @ a^b, b^c in next round +#else + ldr r2,[sp,#1*4] @ from future BODY_16_xx + eor r3,r5,r6 @ a^b, b^c in next round + ldr r1,[sp,#14*4] @ from future BODY_16_xx +#endif + eor r0,r0,r5,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r8,r8,r4 @ d+=h + eor r12,r12,r6 @ Maj(a,b,c) + add r4,r4,r0,ror#2 @ h+=Sigma0(a) + @ add r4,r4,r12 @ h+=Maj(a,b,c) +.Lrounds_16_xx: + @ ldr r2,[sp,#1*4] @ 16 + @ ldr r1,[sp,#14*4] + mov r0,r2,ror#7 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#0*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#9*4] + + add r12,r12,r0 + eor r0,r8,r8,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r8,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r11,r11,r2 @ h+=X[i] + str r2,[sp,#0*4] + eor r2,r9,r10 + add r11,r11,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r8 + add r11,r11,r12 @ h+=K256[i] + eor r2,r2,r10 @ Ch(e,f,g) + eor r0,r4,r4,ror#11 + add r11,r11,r2 @ h+=Ch(e,f,g) +#if 16==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 16<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r4,r5 @ a^b, b^c in next round +#else + ldr r2,[sp,#2*4] @ from future BODY_16_xx + eor r12,r4,r5 @ a^b, b^c in next round + ldr r1,[sp,#15*4] @ from future BODY_16_xx +#endif + eor r0,r0,r4,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r7,r7,r11 @ d+=h + eor r3,r3,r5 @ Maj(a,b,c) + add r11,r11,r0,ror#2 @ h+=Sigma0(a) + @ add r11,r11,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#2*4] @ 17 + @ ldr r1,[sp,#15*4] + mov r0,r2,ror#7 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#1*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#10*4] + + add r3,r3,r0 + eor r0,r7,r7,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r7,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r10,r10,r2 @ h+=X[i] + str r2,[sp,#1*4] + eor r2,r8,r9 + add r10,r10,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r7 + add r10,r10,r3 @ h+=K256[i] + eor r2,r2,r9 @ Ch(e,f,g) + eor r0,r11,r11,ror#11 + add r10,r10,r2 @ h+=Ch(e,f,g) +#if 17==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 17<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r11,r4 @ a^b, b^c in next round +#else + ldr r2,[sp,#3*4] @ from future BODY_16_xx + eor r3,r11,r4 @ a^b, b^c in next round + ldr r1,[sp,#0*4] @ from future BODY_16_xx +#endif + eor r0,r0,r11,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r6,r6,r10 @ d+=h + eor r12,r12,r4 @ Maj(a,b,c) + add r10,r10,r0,ror#2 @ h+=Sigma0(a) + @ add r10,r10,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#3*4] @ 18 + @ ldr r1,[sp,#0*4] + mov r0,r2,ror#7 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#2*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#11*4] + + add r12,r12,r0 + eor r0,r6,r6,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r6,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r9,r9,r2 @ h+=X[i] + str r2,[sp,#2*4] + eor r2,r7,r8 + add r9,r9,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r6 + add r9,r9,r12 @ h+=K256[i] + eor r2,r2,r8 @ Ch(e,f,g) + eor r0,r10,r10,ror#11 + add r9,r9,r2 @ h+=Ch(e,f,g) +#if 18==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 18<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r10,r11 @ a^b, b^c in next round +#else + ldr r2,[sp,#4*4] @ from future BODY_16_xx + eor r12,r10,r11 @ a^b, b^c in next round + ldr r1,[sp,#1*4] @ from future BODY_16_xx +#endif + eor r0,r0,r10,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r5,r5,r9 @ d+=h + eor r3,r3,r11 @ Maj(a,b,c) + add r9,r9,r0,ror#2 @ h+=Sigma0(a) + @ add r9,r9,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#4*4] @ 19 + @ ldr r1,[sp,#1*4] + mov r0,r2,ror#7 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#3*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#12*4] + + add r3,r3,r0 + eor r0,r5,r5,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r5,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r8,r8,r2 @ h+=X[i] + str r2,[sp,#3*4] + eor r2,r6,r7 + add r8,r8,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r5 + add r8,r8,r3 @ h+=K256[i] + eor r2,r2,r7 @ Ch(e,f,g) + eor r0,r9,r9,ror#11 + add r8,r8,r2 @ h+=Ch(e,f,g) +#if 19==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 19<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r9,r10 @ a^b, b^c in next round +#else + ldr r2,[sp,#5*4] @ from future BODY_16_xx + eor r3,r9,r10 @ a^b, b^c in next round + ldr r1,[sp,#2*4] @ from future BODY_16_xx +#endif + eor r0,r0,r9,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r4,r4,r8 @ d+=h + eor r12,r12,r10 @ Maj(a,b,c) + add r8,r8,r0,ror#2 @ h+=Sigma0(a) + @ add r8,r8,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#5*4] @ 20 + @ ldr r1,[sp,#2*4] + mov r0,r2,ror#7 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#4*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#13*4] + + add r12,r12,r0 + eor r0,r4,r4,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r4,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r7,r7,r2 @ h+=X[i] + str r2,[sp,#4*4] + eor r2,r5,r6 + add r7,r7,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r4 + add r7,r7,r12 @ h+=K256[i] + eor r2,r2,r6 @ Ch(e,f,g) + eor r0,r8,r8,ror#11 + add r7,r7,r2 @ h+=Ch(e,f,g) +#if 20==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 20<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r8,r9 @ a^b, b^c in next round +#else + ldr r2,[sp,#6*4] @ from future BODY_16_xx + eor r12,r8,r9 @ a^b, b^c in next round + ldr r1,[sp,#3*4] @ from future BODY_16_xx +#endif + eor r0,r0,r8,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r11,r11,r7 @ d+=h + eor r3,r3,r9 @ Maj(a,b,c) + add r7,r7,r0,ror#2 @ h+=Sigma0(a) + @ add r7,r7,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#6*4] @ 21 + @ ldr r1,[sp,#3*4] + mov r0,r2,ror#7 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#5*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#14*4] + + add r3,r3,r0 + eor r0,r11,r11,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r11,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r6,r6,r2 @ h+=X[i] + str r2,[sp,#5*4] + eor r2,r4,r5 + add r6,r6,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r11 + add r6,r6,r3 @ h+=K256[i] + eor r2,r2,r5 @ Ch(e,f,g) + eor r0,r7,r7,ror#11 + add r6,r6,r2 @ h+=Ch(e,f,g) +#if 21==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 21<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r7,r8 @ a^b, b^c in next round +#else + ldr r2,[sp,#7*4] @ from future BODY_16_xx + eor r3,r7,r8 @ a^b, b^c in next round + ldr r1,[sp,#4*4] @ from future BODY_16_xx +#endif + eor r0,r0,r7,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r10,r10,r6 @ d+=h + eor r12,r12,r8 @ Maj(a,b,c) + add r6,r6,r0,ror#2 @ h+=Sigma0(a) + @ add r6,r6,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#7*4] @ 22 + @ ldr r1,[sp,#4*4] + mov r0,r2,ror#7 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#6*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#15*4] + + add r12,r12,r0 + eor r0,r10,r10,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r10,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r5,r5,r2 @ h+=X[i] + str r2,[sp,#6*4] + eor r2,r11,r4 + add r5,r5,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r10 + add r5,r5,r12 @ h+=K256[i] + eor r2,r2,r4 @ Ch(e,f,g) + eor r0,r6,r6,ror#11 + add r5,r5,r2 @ h+=Ch(e,f,g) +#if 22==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 22<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r6,r7 @ a^b, b^c in next round +#else + ldr r2,[sp,#8*4] @ from future BODY_16_xx + eor r12,r6,r7 @ a^b, b^c in next round + ldr r1,[sp,#5*4] @ from future BODY_16_xx +#endif + eor r0,r0,r6,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r9,r9,r5 @ d+=h + eor r3,r3,r7 @ Maj(a,b,c) + add r5,r5,r0,ror#2 @ h+=Sigma0(a) + @ add r5,r5,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#8*4] @ 23 + @ ldr r1,[sp,#5*4] + mov r0,r2,ror#7 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#7*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#0*4] + + add r3,r3,r0 + eor r0,r9,r9,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r9,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r4,r4,r2 @ h+=X[i] + str r2,[sp,#7*4] + eor r2,r10,r11 + add r4,r4,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r9 + add r4,r4,r3 @ h+=K256[i] + eor r2,r2,r11 @ Ch(e,f,g) + eor r0,r5,r5,ror#11 + add r4,r4,r2 @ h+=Ch(e,f,g) +#if 23==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 23<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r5,r6 @ a^b, b^c in next round +#else + ldr r2,[sp,#9*4] @ from future BODY_16_xx + eor r3,r5,r6 @ a^b, b^c in next round + ldr r1,[sp,#6*4] @ from future BODY_16_xx +#endif + eor r0,r0,r5,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r8,r8,r4 @ d+=h + eor r12,r12,r6 @ Maj(a,b,c) + add r4,r4,r0,ror#2 @ h+=Sigma0(a) + @ add r4,r4,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#9*4] @ 24 + @ ldr r1,[sp,#6*4] + mov r0,r2,ror#7 + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#8*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#1*4] + + add r12,r12,r0 + eor r0,r8,r8,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r8,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r11,r11,r2 @ h+=X[i] + str r2,[sp,#8*4] + eor r2,r9,r10 + add r11,r11,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r8 + add r11,r11,r12 @ h+=K256[i] + eor r2,r2,r10 @ Ch(e,f,g) + eor r0,r4,r4,ror#11 + add r11,r11,r2 @ h+=Ch(e,f,g) +#if 24==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 24<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r4,r5 @ a^b, b^c in next round +#else + ldr r2,[sp,#10*4] @ from future BODY_16_xx + eor r12,r4,r5 @ a^b, b^c in next round + ldr r1,[sp,#7*4] @ from future BODY_16_xx +#endif + eor r0,r0,r4,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r7,r7,r11 @ d+=h + eor r3,r3,r5 @ Maj(a,b,c) + add r11,r11,r0,ror#2 @ h+=Sigma0(a) + @ add r11,r11,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#10*4] @ 25 + @ ldr r1,[sp,#7*4] + mov r0,r2,ror#7 + add r11,r11,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#9*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#2*4] + + add r3,r3,r0 + eor r0,r7,r7,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r7,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r10,r10,r2 @ h+=X[i] + str r2,[sp,#9*4] + eor r2,r8,r9 + add r10,r10,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r7 + add r10,r10,r3 @ h+=K256[i] + eor r2,r2,r9 @ Ch(e,f,g) + eor r0,r11,r11,ror#11 + add r10,r10,r2 @ h+=Ch(e,f,g) +#if 25==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 25<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r11,r4 @ a^b, b^c in next round +#else + ldr r2,[sp,#11*4] @ from future BODY_16_xx + eor r3,r11,r4 @ a^b, b^c in next round + ldr r1,[sp,#8*4] @ from future BODY_16_xx +#endif + eor r0,r0,r11,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r6,r6,r10 @ d+=h + eor r12,r12,r4 @ Maj(a,b,c) + add r10,r10,r0,ror#2 @ h+=Sigma0(a) + @ add r10,r10,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#11*4] @ 26 + @ ldr r1,[sp,#8*4] + mov r0,r2,ror#7 + add r10,r10,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#10*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#3*4] + + add r12,r12,r0 + eor r0,r6,r6,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r6,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r9,r9,r2 @ h+=X[i] + str r2,[sp,#10*4] + eor r2,r7,r8 + add r9,r9,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r6 + add r9,r9,r12 @ h+=K256[i] + eor r2,r2,r8 @ Ch(e,f,g) + eor r0,r10,r10,ror#11 + add r9,r9,r2 @ h+=Ch(e,f,g) +#if 26==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 26<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r10,r11 @ a^b, b^c in next round +#else + ldr r2,[sp,#12*4] @ from future BODY_16_xx + eor r12,r10,r11 @ a^b, b^c in next round + ldr r1,[sp,#9*4] @ from future BODY_16_xx +#endif + eor r0,r0,r10,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r5,r5,r9 @ d+=h + eor r3,r3,r11 @ Maj(a,b,c) + add r9,r9,r0,ror#2 @ h+=Sigma0(a) + @ add r9,r9,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#12*4] @ 27 + @ ldr r1,[sp,#9*4] + mov r0,r2,ror#7 + add r9,r9,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#11*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#4*4] + + add r3,r3,r0 + eor r0,r5,r5,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r5,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r8,r8,r2 @ h+=X[i] + str r2,[sp,#11*4] + eor r2,r6,r7 + add r8,r8,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r5 + add r8,r8,r3 @ h+=K256[i] + eor r2,r2,r7 @ Ch(e,f,g) + eor r0,r9,r9,ror#11 + add r8,r8,r2 @ h+=Ch(e,f,g) +#if 27==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 27<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r9,r10 @ a^b, b^c in next round +#else + ldr r2,[sp,#13*4] @ from future BODY_16_xx + eor r3,r9,r10 @ a^b, b^c in next round + ldr r1,[sp,#10*4] @ from future BODY_16_xx +#endif + eor r0,r0,r9,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r4,r4,r8 @ d+=h + eor r12,r12,r10 @ Maj(a,b,c) + add r8,r8,r0,ror#2 @ h+=Sigma0(a) + @ add r8,r8,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#13*4] @ 28 + @ ldr r1,[sp,#10*4] + mov r0,r2,ror#7 + add r8,r8,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#12*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#5*4] + + add r12,r12,r0 + eor r0,r4,r4,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r4,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r7,r7,r2 @ h+=X[i] + str r2,[sp,#12*4] + eor r2,r5,r6 + add r7,r7,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r4 + add r7,r7,r12 @ h+=K256[i] + eor r2,r2,r6 @ Ch(e,f,g) + eor r0,r8,r8,ror#11 + add r7,r7,r2 @ h+=Ch(e,f,g) +#if 28==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 28<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r8,r9 @ a^b, b^c in next round +#else + ldr r2,[sp,#14*4] @ from future BODY_16_xx + eor r12,r8,r9 @ a^b, b^c in next round + ldr r1,[sp,#11*4] @ from future BODY_16_xx +#endif + eor r0,r0,r8,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r11,r11,r7 @ d+=h + eor r3,r3,r9 @ Maj(a,b,c) + add r7,r7,r0,ror#2 @ h+=Sigma0(a) + @ add r7,r7,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#14*4] @ 29 + @ ldr r1,[sp,#11*4] + mov r0,r2,ror#7 + add r7,r7,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#13*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#6*4] + + add r3,r3,r0 + eor r0,r11,r11,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r11,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r6,r6,r2 @ h+=X[i] + str r2,[sp,#13*4] + eor r2,r4,r5 + add r6,r6,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r11 + add r6,r6,r3 @ h+=K256[i] + eor r2,r2,r5 @ Ch(e,f,g) + eor r0,r7,r7,ror#11 + add r6,r6,r2 @ h+=Ch(e,f,g) +#if 29==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 29<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r7,r8 @ a^b, b^c in next round +#else + ldr r2,[sp,#15*4] @ from future BODY_16_xx + eor r3,r7,r8 @ a^b, b^c in next round + ldr r1,[sp,#12*4] @ from future BODY_16_xx +#endif + eor r0,r0,r7,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r10,r10,r6 @ d+=h + eor r12,r12,r8 @ Maj(a,b,c) + add r6,r6,r0,ror#2 @ h+=Sigma0(a) + @ add r6,r6,r12 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#15*4] @ 30 + @ ldr r1,[sp,#12*4] + mov r0,r2,ror#7 + add r6,r6,r12 @ h+=Maj(a,b,c) from the past + mov r12,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r12,r12,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#14*4] + eor r12,r12,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#7*4] + + add r12,r12,r0 + eor r0,r10,r10,ror#5 @ from BODY_00_15 + add r2,r2,r12 + eor r0,r0,r10,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r12,[r14],#4 @ *K256++ + add r5,r5,r2 @ h+=X[i] + str r2,[sp,#14*4] + eor r2,r11,r4 + add r5,r5,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r10 + add r5,r5,r12 @ h+=K256[i] + eor r2,r2,r4 @ Ch(e,f,g) + eor r0,r6,r6,ror#11 + add r5,r5,r2 @ h+=Ch(e,f,g) +#if 30==31 + and r12,r12,#0xff + cmp r12,#0xf2 @ done? +#endif +#if 30<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r12,r6,r7 @ a^b, b^c in next round +#else + ldr r2,[sp,#0*4] @ from future BODY_16_xx + eor r12,r6,r7 @ a^b, b^c in next round + ldr r1,[sp,#13*4] @ from future BODY_16_xx +#endif + eor r0,r0,r6,ror#20 @ Sigma0(a) + and r3,r3,r12 @ (b^c)&=(a^b) + add r9,r9,r5 @ d+=h + eor r3,r3,r7 @ Maj(a,b,c) + add r5,r5,r0,ror#2 @ h+=Sigma0(a) + @ add r5,r5,r3 @ h+=Maj(a,b,c) + @ ldr r2,[sp,#0*4] @ 31 + @ ldr r1,[sp,#13*4] + mov r0,r2,ror#7 + add r5,r5,r3 @ h+=Maj(a,b,c) from the past + mov r3,r1,ror#17 + eor r0,r0,r2,ror#18 + eor r3,r3,r1,ror#19 + eor r0,r0,r2,lsr#3 @ sigma0(X[i+1]) + ldr r2,[sp,#15*4] + eor r3,r3,r1,lsr#10 @ sigma1(X[i+14]) + ldr r1,[sp,#8*4] + + add r3,r3,r0 + eor r0,r9,r9,ror#5 @ from BODY_00_15 + add r2,r2,r3 + eor r0,r0,r9,ror#19 @ Sigma1(e) + add r2,r2,r1 @ X[i] + ldr r3,[r14],#4 @ *K256++ + add r4,r4,r2 @ h+=X[i] + str r2,[sp,#15*4] + eor r2,r10,r11 + add r4,r4,r0,ror#6 @ h+=Sigma1(e) + and r2,r2,r9 + add r4,r4,r3 @ h+=K256[i] + eor r2,r2,r11 @ Ch(e,f,g) + eor r0,r5,r5,ror#11 + add r4,r4,r2 @ h+=Ch(e,f,g) +#if 31==31 + and r3,r3,#0xff + cmp r3,#0xf2 @ done? +#endif +#if 31<15 +# if __ARM_ARCH__>=7 + ldr r2,[r1],#4 @ prefetch +# else + ldrb r2,[r1,#3] +# endif + eor r3,r5,r6 @ a^b, b^c in next round +#else + ldr r2,[sp,#1*4] @ from future BODY_16_xx + eor r3,r5,r6 @ a^b, b^c in next round + ldr r1,[sp,#14*4] @ from future BODY_16_xx +#endif + eor r0,r0,r5,ror#20 @ Sigma0(a) + and r12,r12,r3 @ (b^c)&=(a^b) + add r8,r8,r4 @ d+=h + eor r12,r12,r6 @ Maj(a,b,c) + add r4,r4,r0,ror#2 @ h+=Sigma0(a) + @ add r4,r4,r12 @ h+=Maj(a,b,c) +#ifdef __thumb2__ + ite eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq r3,[sp,#16*4] @ pull ctx + bne .Lrounds_16_xx + + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + ldr r0,[r3,#0] + ldr r2,[r3,#4] + ldr r12,[r3,#8] + add r4,r4,r0 + ldr r0,[r3,#12] + add r5,r5,r2 + ldr r2,[r3,#16] + add r6,r6,r12 + ldr r12,[r3,#20] + add r7,r7,r0 + ldr r0,[r3,#24] + add r8,r8,r2 + ldr r2,[r3,#28] + add r9,r9,r12 + ldr r1,[sp,#17*4] @ pull inp + ldr r12,[sp,#18*4] @ pull inp+len + add r10,r10,r0 + add r11,r11,r2 + stmia r3,{r4,r5,r6,r7,r8,r9,r10,r11} + cmp r1,r12 + sub r14,r14,#256 @ rewind Ktbl + bne .Loop + + add sp,sp,#19*4 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_sha256_block_data_order,.-cryptogams_sha256_block_data_order + +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.globl cryptogams_sha256_block_data_order_neon +.type cryptogams_sha256_block_data_order_neon,%function +.align 5 +.skip 16 +cryptogams_sha256_block_data_order_neon: + + stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + + sub r11,sp,#16*4+16 + adr r14,K256 + bic r11,r11,#15 @ align for 128-bit stores + mov r12,sp + mov sp,r11 @ alloca + add r2,r1,r2,lsl#6 @ len to point at the end of inp + + vld1.8 {q0},[r1]! + vld1.8 {q1},[r1]! + vld1.8 {q2},[r1]! + vld1.8 {q3},[r1]! + vld1.32 {q8},[r14,:128]! + vld1.32 {q9},[r14,:128]! + vld1.32 {q10},[r14,:128]! + vld1.32 {q11},[r14,:128]! + vrev32.8 q0,q0 @ yes, even on + str r0,[sp,#64] + vrev32.8 q1,q1 @ big-endian + str r1,[sp,#68] + mov r1,sp + vrev32.8 q2,q2 + str r2,[sp,#72] + vrev32.8 q3,q3 + str r12,[sp,#76] @ save original sp + vadd.i32 q8,q8,q0 + vadd.i32 q9,q9,q1 + vst1.32 {q8},[r1,:128]! + vadd.i32 q10,q10,q2 + vst1.32 {q9},[r1,:128]! + vadd.i32 q11,q11,q3 + vst1.32 {q10},[r1,:128]! + vst1.32 {q11},[r1,:128]! + + ldmia r0,{r4,r5,r6,r7,r8,r9,r10,r11} + sub r1,r1,#64 + ldr r2,[sp,#0] + eor r12,r12,r12 + eor r3,r5,r6 + b .L_00_48 + +.align 4 +.L_00_48: + vext.8 q8,q0,q1,#4 + add r11,r11,r2 + eor r2,r9,r10 + eor r0,r8,r8,ror#5 + vext.8 q9,q2,q3,#4 + add r4,r4,r12 + and r2,r2,r8 + eor r12,r0,r8,ror#19 + vshr.u32 q10,q8,#7 + eor r0,r4,r4,ror#11 + eor r2,r2,r10 + vadd.i32 q0,q0,q9 + add r11,r11,r12,ror#6 + eor r12,r4,r5 + vshr.u32 q9,q8,#3 + eor r0,r0,r4,ror#20 + add r11,r11,r2 + vsli.32 q10,q8,#25 + ldr r2,[sp,#4] + and r3,r3,r12 + vshr.u32 q11,q8,#18 + add r7,r7,r11 + add r11,r11,r0,ror#2 + eor r3,r3,r5 + veor q9,q9,q10 + add r10,r10,r2 + vsli.32 q11,q8,#14 + eor r2,r8,r9 + eor r0,r7,r7,ror#5 + vshr.u32 d24,d7,#17 + add r11,r11,r3 + and r2,r2,r7 + veor q9,q9,q11 + eor r3,r0,r7,ror#19 + eor r0,r11,r11,ror#11 + vsli.32 d24,d7,#15 + eor r2,r2,r9 + add r10,r10,r3,ror#6 + vshr.u32 d25,d7,#10 + eor r3,r11,r4 + eor r0,r0,r11,ror#20 + vadd.i32 q0,q0,q9 + add r10,r10,r2 + ldr r2,[sp,#8] + veor d25,d25,d24 + and r12,r12,r3 + add r6,r6,r10 + vshr.u32 d24,d7,#19 + add r10,r10,r0,ror#2 + eor r12,r12,r4 + vsli.32 d24,d7,#13 + add r9,r9,r2 + eor r2,r7,r8 + veor d25,d25,d24 + eor r0,r6,r6,ror#5 + add r10,r10,r12 + vadd.i32 d0,d0,d25 + and r2,r2,r6 + eor r12,r0,r6,ror#19 + vshr.u32 d24,d0,#17 + eor r0,r10,r10,ror#11 + eor r2,r2,r8 + vsli.32 d24,d0,#15 + add r9,r9,r12,ror#6 + eor r12,r10,r11 + vshr.u32 d25,d0,#10 + eor r0,r0,r10,ror#20 + add r9,r9,r2 + veor d25,d25,d24 + ldr r2,[sp,#12] + and r3,r3,r12 + vshr.u32 d24,d0,#19 + add r5,r5,r9 + add r9,r9,r0,ror#2 + eor r3,r3,r11 + vld1.32 {q8},[r14,:128]! + add r8,r8,r2 + vsli.32 d24,d0,#13 + eor r2,r6,r7 + eor r0,r5,r5,ror#5 + veor d25,d25,d24 + add r9,r9,r3 + and r2,r2,r5 + vadd.i32 d1,d1,d25 + eor r3,r0,r5,ror#19 + eor r0,r9,r9,ror#11 + vadd.i32 q8,q8,q0 + eor r2,r2,r7 + add r8,r8,r3,ror#6 + eor r3,r9,r10 + eor r0,r0,r9,ror#20 + add r8,r8,r2 + ldr r2,[sp,#16] + and r12,r12,r3 + add r4,r4,r8 + vst1.32 {q8},[r1,:128]! + add r8,r8,r0,ror#2 + eor r12,r12,r10 + vext.8 q8,q1,q2,#4 + add r7,r7,r2 + eor r2,r5,r6 + eor r0,r4,r4,ror#5 + vext.8 q9,q3,q0,#4 + add r8,r8,r12 + and r2,r2,r4 + eor r12,r0,r4,ror#19 + vshr.u32 q10,q8,#7 + eor r0,r8,r8,ror#11 + eor r2,r2,r6 + vadd.i32 q1,q1,q9 + add r7,r7,r12,ror#6 + eor r12,r8,r9 + vshr.u32 q9,q8,#3 + eor r0,r0,r8,ror#20 + add r7,r7,r2 + vsli.32 q10,q8,#25 + ldr r2,[sp,#20] + and r3,r3,r12 + vshr.u32 q11,q8,#18 + add r11,r11,r7 + add r7,r7,r0,ror#2 + eor r3,r3,r9 + veor q9,q9,q10 + add r6,r6,r2 + vsli.32 q11,q8,#14 + eor r2,r4,r5 + eor r0,r11,r11,ror#5 + vshr.u32 d24,d1,#17 + add r7,r7,r3 + and r2,r2,r11 + veor q9,q9,q11 + eor r3,r0,r11,ror#19 + eor r0,r7,r7,ror#11 + vsli.32 d24,d1,#15 + eor r2,r2,r5 + add r6,r6,r3,ror#6 + vshr.u32 d25,d1,#10 + eor r3,r7,r8 + eor r0,r0,r7,ror#20 + vadd.i32 q1,q1,q9 + add r6,r6,r2 + ldr r2,[sp,#24] + veor d25,d25,d24 + and r12,r12,r3 + add r10,r10,r6 + vshr.u32 d24,d1,#19 + add r6,r6,r0,ror#2 + eor r12,r12,r8 + vsli.32 d24,d1,#13 + add r5,r5,r2 + eor r2,r11,r4 + veor d25,d25,d24 + eor r0,r10,r10,ror#5 + add r6,r6,r12 + vadd.i32 d2,d2,d25 + and r2,r2,r10 + eor r12,r0,r10,ror#19 + vshr.u32 d24,d2,#17 + eor r0,r6,r6,ror#11 + eor r2,r2,r4 + vsli.32 d24,d2,#15 + add r5,r5,r12,ror#6 + eor r12,r6,r7 + vshr.u32 d25,d2,#10 + eor r0,r0,r6,ror#20 + add r5,r5,r2 + veor d25,d25,d24 + ldr r2,[sp,#28] + and r3,r3,r12 + vshr.u32 d24,d2,#19 + add r9,r9,r5 + add r5,r5,r0,ror#2 + eor r3,r3,r7 + vld1.32 {q8},[r14,:128]! + add r4,r4,r2 + vsli.32 d24,d2,#13 + eor r2,r10,r11 + eor r0,r9,r9,ror#5 + veor d25,d25,d24 + add r5,r5,r3 + and r2,r2,r9 + vadd.i32 d3,d3,d25 + eor r3,r0,r9,ror#19 + eor r0,r5,r5,ror#11 + vadd.i32 q8,q8,q1 + eor r2,r2,r11 + add r4,r4,r3,ror#6 + eor r3,r5,r6 + eor r0,r0,r5,ror#20 + add r4,r4,r2 + ldr r2,[sp,#32] + and r12,r12,r3 + add r8,r8,r4 + vst1.32 {q8},[r1,:128]! + add r4,r4,r0,ror#2 + eor r12,r12,r6 + vext.8 q8,q2,q3,#4 + add r11,r11,r2 + eor r2,r9,r10 + eor r0,r8,r8,ror#5 + vext.8 q9,q0,q1,#4 + add r4,r4,r12 + and r2,r2,r8 + eor r12,r0,r8,ror#19 + vshr.u32 q10,q8,#7 + eor r0,r4,r4,ror#11 + eor r2,r2,r10 + vadd.i32 q2,q2,q9 + add r11,r11,r12,ror#6 + eor r12,r4,r5 + vshr.u32 q9,q8,#3 + eor r0,r0,r4,ror#20 + add r11,r11,r2 + vsli.32 q10,q8,#25 + ldr r2,[sp,#36] + and r3,r3,r12 + vshr.u32 q11,q8,#18 + add r7,r7,r11 + add r11,r11,r0,ror#2 + eor r3,r3,r5 + veor q9,q9,q10 + add r10,r10,r2 + vsli.32 q11,q8,#14 + eor r2,r8,r9 + eor r0,r7,r7,ror#5 + vshr.u32 d24,d3,#17 + add r11,r11,r3 + and r2,r2,r7 + veor q9,q9,q11 + eor r3,r0,r7,ror#19 + eor r0,r11,r11,ror#11 + vsli.32 d24,d3,#15 + eor r2,r2,r9 + add r10,r10,r3,ror#6 + vshr.u32 d25,d3,#10 + eor r3,r11,r4 + eor r0,r0,r11,ror#20 + vadd.i32 q2,q2,q9 + add r10,r10,r2 + ldr r2,[sp,#40] + veor d25,d25,d24 + and r12,r12,r3 + add r6,r6,r10 + vshr.u32 d24,d3,#19 + add r10,r10,r0,ror#2 + eor r12,r12,r4 + vsli.32 d24,d3,#13 + add r9,r9,r2 + eor r2,r7,r8 + veor d25,d25,d24 + eor r0,r6,r6,ror#5 + add r10,r10,r12 + vadd.i32 d4,d4,d25 + and r2,r2,r6 + eor r12,r0,r6,ror#19 + vshr.u32 d24,d4,#17 + eor r0,r10,r10,ror#11 + eor r2,r2,r8 + vsli.32 d24,d4,#15 + add r9,r9,r12,ror#6 + eor r12,r10,r11 + vshr.u32 d25,d4,#10 + eor r0,r0,r10,ror#20 + add r9,r9,r2 + veor d25,d25,d24 + ldr r2,[sp,#44] + and r3,r3,r12 + vshr.u32 d24,d4,#19 + add r5,r5,r9 + add r9,r9,r0,ror#2 + eor r3,r3,r11 + vld1.32 {q8},[r14,:128]! + add r8,r8,r2 + vsli.32 d24,d4,#13 + eor r2,r6,r7 + eor r0,r5,r5,ror#5 + veor d25,d25,d24 + add r9,r9,r3 + and r2,r2,r5 + vadd.i32 d5,d5,d25 + eor r3,r0,r5,ror#19 + eor r0,r9,r9,ror#11 + vadd.i32 q8,q8,q2 + eor r2,r2,r7 + add r8,r8,r3,ror#6 + eor r3,r9,r10 + eor r0,r0,r9,ror#20 + add r8,r8,r2 + ldr r2,[sp,#48] + and r12,r12,r3 + add r4,r4,r8 + vst1.32 {q8},[r1,:128]! + add r8,r8,r0,ror#2 + eor r12,r12,r10 + vext.8 q8,q3,q0,#4 + add r7,r7,r2 + eor r2,r5,r6 + eor r0,r4,r4,ror#5 + vext.8 q9,q1,q2,#4 + add r8,r8,r12 + and r2,r2,r4 + eor r12,r0,r4,ror#19 + vshr.u32 q10,q8,#7 + eor r0,r8,r8,ror#11 + eor r2,r2,r6 + vadd.i32 q3,q3,q9 + add r7,r7,r12,ror#6 + eor r12,r8,r9 + vshr.u32 q9,q8,#3 + eor r0,r0,r8,ror#20 + add r7,r7,r2 + vsli.32 q10,q8,#25 + ldr r2,[sp,#52] + and r3,r3,r12 + vshr.u32 q11,q8,#18 + add r11,r11,r7 + add r7,r7,r0,ror#2 + eor r3,r3,r9 + veor q9,q9,q10 + add r6,r6,r2 + vsli.32 q11,q8,#14 + eor r2,r4,r5 + eor r0,r11,r11,ror#5 + vshr.u32 d24,d5,#17 + add r7,r7,r3 + and r2,r2,r11 + veor q9,q9,q11 + eor r3,r0,r11,ror#19 + eor r0,r7,r7,ror#11 + vsli.32 d24,d5,#15 + eor r2,r2,r5 + add r6,r6,r3,ror#6 + vshr.u32 d25,d5,#10 + eor r3,r7,r8 + eor r0,r0,r7,ror#20 + vadd.i32 q3,q3,q9 + add r6,r6,r2 + ldr r2,[sp,#56] + veor d25,d25,d24 + and r12,r12,r3 + add r10,r10,r6 + vshr.u32 d24,d5,#19 + add r6,r6,r0,ror#2 + eor r12,r12,r8 + vsli.32 d24,d5,#13 + add r5,r5,r2 + eor r2,r11,r4 + veor d25,d25,d24 + eor r0,r10,r10,ror#5 + add r6,r6,r12 + vadd.i32 d6,d6,d25 + and r2,r2,r10 + eor r12,r0,r10,ror#19 + vshr.u32 d24,d6,#17 + eor r0,r6,r6,ror#11 + eor r2,r2,r4 + vsli.32 d24,d6,#15 + add r5,r5,r12,ror#6 + eor r12,r6,r7 + vshr.u32 d25,d6,#10 + eor r0,r0,r6,ror#20 + add r5,r5,r2 + veor d25,d25,d24 + ldr r2,[sp,#60] + and r3,r3,r12 + vshr.u32 d24,d6,#19 + add r9,r9,r5 + add r5,r5,r0,ror#2 + eor r3,r3,r7 + vld1.32 {q8},[r14,:128]! + add r4,r4,r2 + vsli.32 d24,d6,#13 + eor r2,r10,r11 + eor r0,r9,r9,ror#5 + veor d25,d25,d24 + add r5,r5,r3 + and r2,r2,r9 + vadd.i32 d7,d7,d25 + eor r3,r0,r9,ror#19 + eor r0,r5,r5,ror#11 + vadd.i32 q8,q8,q3 + eor r2,r2,r11 + add r4,r4,r3,ror#6 + eor r3,r5,r6 + eor r0,r0,r5,ror#20 + add r4,r4,r2 + ldr r2,[r14] + and r12,r12,r3 + add r8,r8,r4 + vst1.32 {q8},[r1,:128]! + add r4,r4,r0,ror#2 + eor r12,r12,r6 + teq r2,#0 @ check for K256 terminator + ldr r2,[sp,#0] + sub r1,r1,#64 + bne .L_00_48 + + ldr r1,[sp,#68] + ldr r0,[sp,#72] + sub r14,r14,#256 @ rewind r14 + teq r1,r0 + it eq + subeq r1,r1,#64 @ avoid SEGV + vld1.8 {q0},[r1]! @ load next input block + vld1.8 {q1},[r1]! + vld1.8 {q2},[r1]! + vld1.8 {q3},[r1]! + it ne + strne r1,[sp,#68] + mov r1,sp + add r11,r11,r2 + eor r2,r9,r10 + eor r0,r8,r8,ror#5 + add r4,r4,r12 + vld1.32 {q8},[r14,:128]! + and r2,r2,r8 + eor r12,r0,r8,ror#19 + eor r0,r4,r4,ror#11 + eor r2,r2,r10 + vrev32.8 q0,q0 + add r11,r11,r12,ror#6 + eor r12,r4,r5 + eor r0,r0,r4,ror#20 + add r11,r11,r2 + vadd.i32 q8,q8,q0 + ldr r2,[sp,#4] + and r3,r3,r12 + add r7,r7,r11 + add r11,r11,r0,ror#2 + eor r3,r3,r5 + add r10,r10,r2 + eor r2,r8,r9 + eor r0,r7,r7,ror#5 + add r11,r11,r3 + and r2,r2,r7 + eor r3,r0,r7,ror#19 + eor r0,r11,r11,ror#11 + eor r2,r2,r9 + add r10,r10,r3,ror#6 + eor r3,r11,r4 + eor r0,r0,r11,ror#20 + add r10,r10,r2 + ldr r2,[sp,#8] + and r12,r12,r3 + add r6,r6,r10 + add r10,r10,r0,ror#2 + eor r12,r12,r4 + add r9,r9,r2 + eor r2,r7,r8 + eor r0,r6,r6,ror#5 + add r10,r10,r12 + and r2,r2,r6 + eor r12,r0,r6,ror#19 + eor r0,r10,r10,ror#11 + eor r2,r2,r8 + add r9,r9,r12,ror#6 + eor r12,r10,r11 + eor r0,r0,r10,ror#20 + add r9,r9,r2 + ldr r2,[sp,#12] + and r3,r3,r12 + add r5,r5,r9 + add r9,r9,r0,ror#2 + eor r3,r3,r11 + add r8,r8,r2 + eor r2,r6,r7 + eor r0,r5,r5,ror#5 + add r9,r9,r3 + and r2,r2,r5 + eor r3,r0,r5,ror#19 + eor r0,r9,r9,ror#11 + eor r2,r2,r7 + add r8,r8,r3,ror#6 + eor r3,r9,r10 + eor r0,r0,r9,ror#20 + add r8,r8,r2 + ldr r2,[sp,#16] + and r12,r12,r3 + add r4,r4,r8 + add r8,r8,r0,ror#2 + eor r12,r12,r10 + vst1.32 {q8},[r1,:128]! + add r7,r7,r2 + eor r2,r5,r6 + eor r0,r4,r4,ror#5 + add r8,r8,r12 + vld1.32 {q8},[r14,:128]! + and r2,r2,r4 + eor r12,r0,r4,ror#19 + eor r0,r8,r8,ror#11 + eor r2,r2,r6 + vrev32.8 q1,q1 + add r7,r7,r12,ror#6 + eor r12,r8,r9 + eor r0,r0,r8,ror#20 + add r7,r7,r2 + vadd.i32 q8,q8,q1 + ldr r2,[sp,#20] + and r3,r3,r12 + add r11,r11,r7 + add r7,r7,r0,ror#2 + eor r3,r3,r9 + add r6,r6,r2 + eor r2,r4,r5 + eor r0,r11,r11,ror#5 + add r7,r7,r3 + and r2,r2,r11 + eor r3,r0,r11,ror#19 + eor r0,r7,r7,ror#11 + eor r2,r2,r5 + add r6,r6,r3,ror#6 + eor r3,r7,r8 + eor r0,r0,r7,ror#20 + add r6,r6,r2 + ldr r2,[sp,#24] + and r12,r12,r3 + add r10,r10,r6 + add r6,r6,r0,ror#2 + eor r12,r12,r8 + add r5,r5,r2 + eor r2,r11,r4 + eor r0,r10,r10,ror#5 + add r6,r6,r12 + and r2,r2,r10 + eor r12,r0,r10,ror#19 + eor r0,r6,r6,ror#11 + eor r2,r2,r4 + add r5,r5,r12,ror#6 + eor r12,r6,r7 + eor r0,r0,r6,ror#20 + add r5,r5,r2 + ldr r2,[sp,#28] + and r3,r3,r12 + add r9,r9,r5 + add r5,r5,r0,ror#2 + eor r3,r3,r7 + add r4,r4,r2 + eor r2,r10,r11 + eor r0,r9,r9,ror#5 + add r5,r5,r3 + and r2,r2,r9 + eor r3,r0,r9,ror#19 + eor r0,r5,r5,ror#11 + eor r2,r2,r11 + add r4,r4,r3,ror#6 + eor r3,r5,r6 + eor r0,r0,r5,ror#20 + add r4,r4,r2 + ldr r2,[sp,#32] + and r12,r12,r3 + add r8,r8,r4 + add r4,r4,r0,ror#2 + eor r12,r12,r6 + vst1.32 {q8},[r1,:128]! + add r11,r11,r2 + eor r2,r9,r10 + eor r0,r8,r8,ror#5 + add r4,r4,r12 + vld1.32 {q8},[r14,:128]! + and r2,r2,r8 + eor r12,r0,r8,ror#19 + eor r0,r4,r4,ror#11 + eor r2,r2,r10 + vrev32.8 q2,q2 + add r11,r11,r12,ror#6 + eor r12,r4,r5 + eor r0,r0,r4,ror#20 + add r11,r11,r2 + vadd.i32 q8,q8,q2 + ldr r2,[sp,#36] + and r3,r3,r12 + add r7,r7,r11 + add r11,r11,r0,ror#2 + eor r3,r3,r5 + add r10,r10,r2 + eor r2,r8,r9 + eor r0,r7,r7,ror#5 + add r11,r11,r3 + and r2,r2,r7 + eor r3,r0,r7,ror#19 + eor r0,r11,r11,ror#11 + eor r2,r2,r9 + add r10,r10,r3,ror#6 + eor r3,r11,r4 + eor r0,r0,r11,ror#20 + add r10,r10,r2 + ldr r2,[sp,#40] + and r12,r12,r3 + add r6,r6,r10 + add r10,r10,r0,ror#2 + eor r12,r12,r4 + add r9,r9,r2 + eor r2,r7,r8 + eor r0,r6,r6,ror#5 + add r10,r10,r12 + and r2,r2,r6 + eor r12,r0,r6,ror#19 + eor r0,r10,r10,ror#11 + eor r2,r2,r8 + add r9,r9,r12,ror#6 + eor r12,r10,r11 + eor r0,r0,r10,ror#20 + add r9,r9,r2 + ldr r2,[sp,#44] + and r3,r3,r12 + add r5,r5,r9 + add r9,r9,r0,ror#2 + eor r3,r3,r11 + add r8,r8,r2 + eor r2,r6,r7 + eor r0,r5,r5,ror#5 + add r9,r9,r3 + and r2,r2,r5 + eor r3,r0,r5,ror#19 + eor r0,r9,r9,ror#11 + eor r2,r2,r7 + add r8,r8,r3,ror#6 + eor r3,r9,r10 + eor r0,r0,r9,ror#20 + add r8,r8,r2 + ldr r2,[sp,#48] + and r12,r12,r3 + add r4,r4,r8 + add r8,r8,r0,ror#2 + eor r12,r12,r10 + vst1.32 {q8},[r1,:128]! + add r7,r7,r2 + eor r2,r5,r6 + eor r0,r4,r4,ror#5 + add r8,r8,r12 + vld1.32 {q8},[r14,:128]! + and r2,r2,r4 + eor r12,r0,r4,ror#19 + eor r0,r8,r8,ror#11 + eor r2,r2,r6 + vrev32.8 q3,q3 + add r7,r7,r12,ror#6 + eor r12,r8,r9 + eor r0,r0,r8,ror#20 + add r7,r7,r2 + vadd.i32 q8,q8,q3 + ldr r2,[sp,#52] + and r3,r3,r12 + add r11,r11,r7 + add r7,r7,r0,ror#2 + eor r3,r3,r9 + add r6,r6,r2 + eor r2,r4,r5 + eor r0,r11,r11,ror#5 + add r7,r7,r3 + and r2,r2,r11 + eor r3,r0,r11,ror#19 + eor r0,r7,r7,ror#11 + eor r2,r2,r5 + add r6,r6,r3,ror#6 + eor r3,r7,r8 + eor r0,r0,r7,ror#20 + add r6,r6,r2 + ldr r2,[sp,#56] + and r12,r12,r3 + add r10,r10,r6 + add r6,r6,r0,ror#2 + eor r12,r12,r8 + add r5,r5,r2 + eor r2,r11,r4 + eor r0,r10,r10,ror#5 + add r6,r6,r12 + and r2,r2,r10 + eor r12,r0,r10,ror#19 + eor r0,r6,r6,ror#11 + eor r2,r2,r4 + add r5,r5,r12,ror#6 + eor r12,r6,r7 + eor r0,r0,r6,ror#20 + add r5,r5,r2 + ldr r2,[sp,#60] + and r3,r3,r12 + add r9,r9,r5 + add r5,r5,r0,ror#2 + eor r3,r3,r7 + add r4,r4,r2 + eor r2,r10,r11 + eor r0,r9,r9,ror#5 + add r5,r5,r3 + and r2,r2,r9 + eor r3,r0,r9,ror#19 + eor r0,r5,r5,ror#11 + eor r2,r2,r11 + add r4,r4,r3,ror#6 + eor r3,r5,r6 + eor r0,r0,r5,ror#20 + add r4,r4,r2 + ldr r2,[sp,#64] + and r12,r12,r3 + add r8,r8,r4 + add r4,r4,r0,ror#2 + eor r12,r12,r6 + vst1.32 {q8},[r1,:128]! + ldr r0,[r2,#0] + add r4,r4,r12 @ h+=Maj(a,b,c) from the past + ldr r12,[r2,#4] + ldr r3,[r2,#8] + ldr r1,[r2,#12] + add r4,r4,r0 @ accumulate + ldr r0,[r2,#16] + add r5,r5,r12 + ldr r12,[r2,#20] + add r6,r6,r3 + ldr r3,[r2,#24] + add r7,r7,r1 + ldr r1,[r2,#28] + add r8,r8,r0 + str r4,[r2],#4 + add r9,r9,r12 + str r5,[r2],#4 + add r10,r10,r3 + str r6,[r2],#4 + add r11,r11,r1 + str r7,[r2],#4 + stmia r2,{r8,r9,r10,r11} + + ittte ne + movne r1,sp + ldrne r2,[sp,#0] + eorne r12,r12,r12 + ldreq sp,[sp,#76] @ restore original sp + itt ne + eorne r3,r5,r6 + bne .L_00_48 + + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +.size cryptogams_sha256_block_data_order_neon,.-cryptogams_sha256_block_data_order_neon +#endif diff --git a/extension/third_party/cryptopp/sha256_armv4.h b/extension/third_party/cryptopp/sha256_armv4.h new file mode 100644 index 00000000..a577b5b0 --- /dev/null +++ b/extension/third_party/cryptopp/sha256_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA1. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA256_ARMV4_H +#define CRYPTOGAMS_SHA256_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified cryptogams_sha256_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha256_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA256_ARMV4_H */ diff --git a/extension/third_party/cryptopp/sha3.cpp b/extension/third_party/cryptopp/sha3.cpp new file mode 100644 index 00000000..35de1b13 --- /dev/null +++ b/extension/third_party/cryptopp/sha3.cpp @@ -0,0 +1,71 @@ +// sha3.cpp - modified by Wei Dai from Ronny Van Keer's public domain +// Keccak-simple.c. All modifications here are placed in the +// public domain by Wei Dai. +// Keccack core function moved to keccakc.cpp in AUG 2018 +// by Jeffrey Walton. Separating the core file allows both +// SHA3 and Keccack to share the core implementation. + +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michael Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "pch.h" +#include "sha3.h" + +NAMESPACE_BEGIN(CryptoPP) + +// The Keccak core function +extern void KeccakF1600(word64 *state); + +NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void SHA3::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0)); + if (length == 0) { return; } + + size_t spaceLeft; + while (length >= (spaceLeft = r() - m_counter)) + { + if (spaceLeft) + xorbuf(m_state.BytePtr() + m_counter, input, spaceLeft); + KeccakF1600(m_state); + input += spaceLeft; + length -= spaceLeft; + m_counter = 0; + } + + if (length) + xorbuf(m_state.BytePtr() + m_counter, input, length); + m_counter += (unsigned int)length; +} + +void SHA3::Restart() +{ + memset(m_state, 0, m_state.SizeInBytes()); + m_counter = 0; +} + +void SHA3::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + ThrowIfInvalidTruncatedSize(size); + + m_state.BytePtr()[m_counter] ^= 0x06; + m_state.BytePtr()[r()-1] ^= 0x80; + KeccakF1600(m_state); + std::memcpy(hash, m_state, size); + Restart(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/sha3.h b/extension/third_party/cryptopp/sha3.h new file mode 100644 index 00000000..f02b7d44 --- /dev/null +++ b/extension/third_party/cryptopp/sha3.h @@ -0,0 +1,106 @@ +// sha3.h - originally written and placed in the public domain by Wei Dai + +/// \file sha3.h +/// \brief Classes for SHA3 message digests +/// \details The Crypto++ implementation conforms to the FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \sa SHA-3, +/// SHA-3 STANDARD (FIPS 202). +/// \since Crypto++ 5.6.2 + +#ifndef CRYPTOPP_SHA3_H +#define CRYPTOPP_SHA3_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA3 message digest base class +/// \details The Crypto++ implementation conforms to FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// Library users should instantiate a derived class, and only use SHA3 +/// as a base class reference or pointer. +/// \sa Keccak, SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// \since Crypto++ 5.6.2 +class SHA3 : public HashTransformation +{ +protected: + /// \brief Construct a SHA3 + /// \param digestSize the digest size, in bytes + /// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. + /// Library users should instantiate a derived class, and only use SHA3 + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 5.6.2 + SHA3(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief SHA3 message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 5.6.2 +template +class SHA3_Final : public SHA3 +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize); + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE); + static std::string StaticAlgorithmName() + { return "SHA3-" + IntToString(DIGESTSIZE * 8); } + + /// \brief Construct a SHA3-X message digest + SHA3_Final() : SHA3(DIGESTSIZE) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief SHA3-224 message digest +/// \since Crypto++ 5.6.2 +class SHA3_224 : public SHA3_Final<28> {}; + +/// \brief SHA3-256 message digest +/// \since Crypto++ 5.6.2 +class SHA3_256 : public SHA3_Final<32> {}; + +/// \brief SHA3-384 message digest +/// \since Crypto++ 5.6.2 +class SHA3_384 : public SHA3_Final<48> {}; + +/// \brief SHA3-512 message digest +/// \since Crypto++ 5.6.2 +class SHA3_512 : public SHA3_Final<64> {}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/sha512_armv4.S b/extension/third_party/cryptopp/sha512_armv4.S new file mode 100644 index 00000000..c8dfb199 --- /dev/null +++ b/extension/third_party/cryptopp/sha512_armv4.S @@ -0,0 +1,1861 @@ +@ Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved. +@ +@ ==================================================================== +@ Written by Andy Polyakov for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ JW, MAY 2019: Begin defines from taken from arm_arch.h +@ The defines were included through the header. + +# if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +# endif + +# if !defined(__ARM_MAX_ARCH__) +# define __ARM_MAX_ARCH__ __ARM_ARCH__ +# endif + +# if __ARM_MAX_ARCH__<__ARM_ARCH__ +# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__" +# elif __ARM_MAX_ARCH__!=__ARM_ARCH__ +# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__) +# error "can't build universal big-endian binary" +# endif +# endif + +# define CRYPTOGAMS_ARMV7_NEON (1<<0) + +@ JW, MAY 2019: End defines from taken from arm_arch.h +@ Back to original Cryptogams code + +#ifdef __ARMEL__ +# define LO 0 +# define HI 4 +# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1 +#else +# define HI 0 +# define LO 4 +# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1 +#endif + +#if defined(__thumb2__) +.syntax unified +.thumb +# define adrl adr +#else +.code 32 +#endif + +.text + +.type K512,%object +.align 5 +K512: + WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd) + WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc) + WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019) + WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118) + WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe) + WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2) + WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1) + WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694) + WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3) + WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65) + WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483) + WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5) + WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210) + WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4) + WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725) + WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70) + WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926) + WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df) + WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8) + WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b) + WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001) + WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30) + WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910) + WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8) + WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53) + WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8) + WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb) + WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3) + WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60) + WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec) + WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9) + WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b) + WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207) + WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178) + WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6) + WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b) + WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493) + WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c) + WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a) + WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) +.size K512,.-K512 + +.skip 32 + +.align 5 +.globl cryptogams_sha512_block_data_order +.type cryptogams_sha512_block_data_order,%function + +cryptogams_sha512_block_data_order: +.Lcryptogams_sha512_block_data_order: + +#if __ARM_ARCH__<7 && !defined(__thumb2__) + sub r3,pc,#8 @ cryptogams_sha512_block_data_order +#else + adr r3,.Lcryptogams_sha512_block_data_order +#endif + + add r2,r1,r2,lsl#7 @ len to point at the end of inp + stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + sub r14,r3,#672 @ K512 + sub sp,sp,#9*8 + + ldr r7,[r0,#32+LO] + ldr r8,[r0,#32+HI] + ldr r9, [r0,#48+LO] + ldr r10, [r0,#48+HI] + ldr r11, [r0,#56+LO] + ldr r12, [r0,#56+HI] +.Loop: + str r9, [sp,#48+0] + str r10, [sp,#48+4] + str r11, [sp,#56+0] + str r12, [sp,#56+4] + ldr r5,[r0,#0+LO] + ldr r6,[r0,#0+HI] + ldr r3,[r0,#8+LO] + ldr r4,[r0,#8+HI] + ldr r9, [r0,#16+LO] + ldr r10, [r0,#16+HI] + ldr r11, [r0,#24+LO] + ldr r12, [r0,#24+HI] + str r3,[sp,#8+0] + str r4,[sp,#8+4] + str r9, [sp,#16+0] + str r10, [sp,#16+4] + str r11, [sp,#24+0] + str r12, [sp,#24+4] + ldr r3,[r0,#40+LO] + ldr r4,[r0,#40+HI] + str r3,[sp,#40+0] + str r4,[sp,#40+4] + +.L00_15: +#if __ARM_ARCH__<7 + ldrb r3,[r1,#7] + ldrb r9, [r1,#6] + ldrb r10, [r1,#5] + ldrb r11, [r1,#4] + ldrb r4,[r1,#3] + ldrb r12, [r1,#2] + orr r3,r3,r9,lsl#8 + ldrb r9, [r1,#1] + orr r3,r3,r10,lsl#16 + ldrb r10, [r1],#8 + orr r3,r3,r11,lsl#24 + orr r4,r4,r12,lsl#8 + orr r4,r4,r9,lsl#16 + orr r4,r4,r10,lsl#24 +#else + ldr r3,[r1,#4] + ldr r4,[r1],#8 +#ifdef __ARMEL__ + rev r3,r3 + rev r4,r4 +#endif +#endif + @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + mov r9,r7,lsr#14 + str r3,[sp,#64+0] + mov r10,r8,lsr#14 + str r4,[sp,#64+4] + eor r9,r9,r8,lsl#18 + ldr r11,[sp,#56+0] @ h.lo + eor r10,r10,r7,lsl#18 + ldr r12,[sp,#56+4] @ h.hi + eor r9,r9,r7,lsr#18 + eor r10,r10,r8,lsr#18 + eor r9,r9,r8,lsl#14 + eor r10,r10,r7,lsl#14 + eor r9,r9,r8,lsr#9 + eor r10,r10,r7,lsr#9 + eor r9,r9,r7,lsl#23 + eor r10,r10,r8,lsl#23 @ Sigma1(e) + adds r3,r3,r9 + ldr r9,[sp,#40+0] @ f.lo + adc r4,r4,r10 @ T += Sigma1(e) + ldr r10,[sp,#40+4] @ f.hi + adds r3,r3,r11 + ldr r11,[sp,#48+0] @ g.lo + adc r4,r4,r12 @ T += h + ldr r12,[sp,#48+4] @ g.hi + + eor r9,r9,r11 + str r7,[sp,#32+0] + eor r10,r10,r12 + str r8,[sp,#32+4] + and r9,r9,r7 + str r5,[sp,#0+0] + and r10,r10,r8 + str r6,[sp,#0+4] + eor r9,r9,r11 + ldr r11,[r14,#LO] @ K[i].lo + eor r10,r10,r12 @ Ch(e,f,g) + ldr r12,[r14,#HI] @ K[i].hi + + adds r3,r3,r9 + ldr r7,[sp,#24+0] @ d.lo + adc r4,r4,r10 @ T += Ch(e,f,g) + ldr r8,[sp,#24+4] @ d.hi + adds r3,r3,r11 + and r9,r11,#0xff + adc r4,r4,r12 @ T += K[i] + adds r7,r7,r3 + ldr r11,[sp,#8+0] @ b.lo + adc r8,r8,r4 @ d += T + teq r9,#148 + + ldr r12,[sp,#16+0] @ c.lo +#ifdef __thumb2__ + it eq @ Thumb2 thing, sanity check in ARM +#endif + orreq r14,r14,#1 + @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + mov r9,r5,lsr#28 + mov r10,r6,lsr#28 + eor r9,r9,r6,lsl#4 + eor r10,r10,r5,lsl#4 + eor r9,r9,r6,lsr#2 + eor r10,r10,r5,lsr#2 + eor r9,r9,r5,lsl#30 + eor r10,r10,r6,lsl#30 + eor r9,r9,r6,lsr#7 + eor r10,r10,r5,lsr#7 + eor r9,r9,r5,lsl#25 + eor r10,r10,r6,lsl#25 @ Sigma0(a) + adds r3,r3,r9 + and r9,r5,r11 + adc r4,r4,r10 @ T += Sigma0(a) + + ldr r10,[sp,#8+4] @ b.hi + orr r5,r5,r11 + ldr r11,[sp,#16+4] @ c.hi + and r5,r5,r12 + and r12,r6,r10 + orr r6,r6,r10 + orr r5,r5,r9 @ Maj(a,b,c).lo + and r6,r6,r11 + adds r5,r5,r3 + orr r6,r6,r12 @ Maj(a,b,c).hi + sub sp,sp,#8 + adc r6,r6,r4 @ h += T + tst r14,#1 + add r14,r14,#8 + tst r14,#1 + beq .L00_15 + ldr r9,[sp,#184+0] + ldr r10,[sp,#184+4] + bic r14,r14,#1 +.L16_79: + @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) + @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25 + @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7 + mov r3,r9,lsr#1 + ldr r11,[sp,#80+0] + mov r4,r10,lsr#1 + ldr r12,[sp,#80+4] + eor r3,r3,r10,lsl#31 + eor r4,r4,r9,lsl#31 + eor r3,r3,r9,lsr#8 + eor r4,r4,r10,lsr#8 + eor r3,r3,r10,lsl#24 + eor r4,r4,r9,lsl#24 + eor r3,r3,r9,lsr#7 + eor r4,r4,r10,lsr#7 + eor r3,r3,r10,lsl#25 + + @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26 + @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6 + mov r9,r11,lsr#19 + mov r10,r12,lsr#19 + eor r9,r9,r12,lsl#13 + eor r10,r10,r11,lsl#13 + eor r9,r9,r12,lsr#29 + eor r10,r10,r11,lsr#29 + eor r9,r9,r11,lsl#3 + eor r10,r10,r12,lsl#3 + eor r9,r9,r11,lsr#6 + eor r10,r10,r12,lsr#6 + ldr r11,[sp,#120+0] + eor r9,r9,r12,lsl#26 + + ldr r12,[sp,#120+4] + adds r3,r3,r9 + ldr r9,[sp,#192+0] + adc r4,r4,r10 + + ldr r10,[sp,#192+4] + adds r3,r3,r11 + adc r4,r4,r12 + adds r3,r3,r9 + adc r4,r4,r10 + @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + mov r9,r7,lsr#14 + str r3,[sp,#64+0] + mov r10,r8,lsr#14 + str r4,[sp,#64+4] + eor r9,r9,r8,lsl#18 + ldr r11,[sp,#56+0] @ h.lo + eor r10,r10,r7,lsl#18 + ldr r12,[sp,#56+4] @ h.hi + eor r9,r9,r7,lsr#18 + eor r10,r10,r8,lsr#18 + eor r9,r9,r8,lsl#14 + eor r10,r10,r7,lsl#14 + eor r9,r9,r8,lsr#9 + eor r10,r10,r7,lsr#9 + eor r9,r9,r7,lsl#23 + eor r10,r10,r8,lsl#23 @ Sigma1(e) + adds r3,r3,r9 + ldr r9,[sp,#40+0] @ f.lo + adc r4,r4,r10 @ T += Sigma1(e) + ldr r10,[sp,#40+4] @ f.hi + adds r3,r3,r11 + ldr r11,[sp,#48+0] @ g.lo + adc r4,r4,r12 @ T += h + ldr r12,[sp,#48+4] @ g.hi + + eor r9,r9,r11 + str r7,[sp,#32+0] + eor r10,r10,r12 + str r8,[sp,#32+4] + and r9,r9,r7 + str r5,[sp,#0+0] + and r10,r10,r8 + str r6,[sp,#0+4] + eor r9,r9,r11 + ldr r11,[r14,#LO] @ K[i].lo + eor r10,r10,r12 @ Ch(e,f,g) + ldr r12,[r14,#HI] @ K[i].hi + + adds r3,r3,r9 + ldr r7,[sp,#24+0] @ d.lo + adc r4,r4,r10 @ T += Ch(e,f,g) + ldr r8,[sp,#24+4] @ d.hi + adds r3,r3,r11 + and r9,r11,#0xff + adc r4,r4,r12 @ T += K[i] + adds r7,r7,r3 + ldr r11,[sp,#8+0] @ b.lo + adc r8,r8,r4 @ d += T + teq r9,#23 + + ldr r12,[sp,#16+0] @ c.lo +#ifdef __thumb2__ + it eq @ Thumb2 thing, sanity check in ARM +#endif + orreq r14,r14,#1 + @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + mov r9,r5,lsr#28 + mov r10,r6,lsr#28 + eor r9,r9,r6,lsl#4 + eor r10,r10,r5,lsl#4 + eor r9,r9,r6,lsr#2 + eor r10,r10,r5,lsr#2 + eor r9,r9,r5,lsl#30 + eor r10,r10,r6,lsl#30 + eor r9,r9,r6,lsr#7 + eor r10,r10,r5,lsr#7 + eor r9,r9,r5,lsl#25 + eor r10,r10,r6,lsl#25 @ Sigma0(a) + adds r3,r3,r9 + and r9,r5,r11 + adc r4,r4,r10 @ T += Sigma0(a) + + ldr r10,[sp,#8+4] @ b.hi + orr r5,r5,r11 + ldr r11,[sp,#16+4] @ c.hi + and r5,r5,r12 + and r12,r6,r10 + orr r6,r6,r10 + orr r5,r5,r9 @ Maj(a,b,c).lo + and r6,r6,r11 + adds r5,r5,r3 + orr r6,r6,r12 @ Maj(a,b,c).hi + sub sp,sp,#8 + adc r6,r6,r4 @ h += T + tst r14,#1 + add r14,r14,#8 +#ifdef __thumb2__ + ittt eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq r9,[sp,#184+0] + ldreq r10,[sp,#184+4] + beq .L16_79 + bic r14,r14,#1 + + ldr r3,[sp,#8+0] + ldr r4,[sp,#8+4] + ldr r9, [r0,#0+LO] + ldr r10, [r0,#0+HI] + ldr r11, [r0,#8+LO] + ldr r12, [r0,#8+HI] + adds r9,r5,r9 + str r9, [r0,#0+LO] + adc r10,r6,r10 + str r10, [r0,#0+HI] + adds r11,r3,r11 + str r11, [r0,#8+LO] + adc r12,r4,r12 + str r12, [r0,#8+HI] + + ldr r5,[sp,#16+0] + ldr r6,[sp,#16+4] + ldr r3,[sp,#24+0] + ldr r4,[sp,#24+4] + ldr r9, [r0,#16+LO] + ldr r10, [r0,#16+HI] + ldr r11, [r0,#24+LO] + ldr r12, [r0,#24+HI] + adds r9,r5,r9 + str r9, [r0,#16+LO] + adc r10,r6,r10 + str r10, [r0,#16+HI] + adds r11,r3,r11 + str r11, [r0,#24+LO] + adc r12,r4,r12 + str r12, [r0,#24+HI] + + ldr r3,[sp,#40+0] + ldr r4,[sp,#40+4] + ldr r9, [r0,#32+LO] + ldr r10, [r0,#32+HI] + ldr r11, [r0,#40+LO] + ldr r12, [r0,#40+HI] + adds r7,r7,r9 + str r7,[r0,#32+LO] + adc r8,r8,r10 + str r8,[r0,#32+HI] + adds r11,r3,r11 + str r11, [r0,#40+LO] + adc r12,r4,r12 + str r12, [r0,#40+HI] + + ldr r5,[sp,#48+0] + ldr r6,[sp,#48+4] + ldr r3,[sp,#56+0] + ldr r4,[sp,#56+4] + ldr r9, [r0,#48+LO] + ldr r10, [r0,#48+HI] + ldr r11, [r0,#56+LO] + ldr r12, [r0,#56+HI] + adds r9,r5,r9 + str r9, [r0,#48+LO] + adc r10,r6,r10 + str r10, [r0,#48+HI] + adds r11,r3,r11 + str r11, [r0,#56+LO] + adc r12,r4,r12 + str r12, [r0,#56+HI] + + add sp,sp,#640 + sub r14,r14,#640 + + teq r1,r2 + bne .Loop + + add sp,sp,#8*9 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc} +#else + ldmia sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet +.word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size cryptogams_sha512_block_data_order,.-cryptogams_sha512_block_data_order + +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.align 4 +.globl cryptogams_sha512_block_data_order_neon +.type cryptogams_sha512_block_data_order_neon,%function + +cryptogams_sha512_block_data_order_neon: + + dmb @ errata #451034 on early Cortex A8 + add r2,r1,r2,lsl#7 @ len to point at the end of inp + adr r3,K512 + vstmdb sp!,{d8-d15} + vldmia r0,{d16,d17,d18,d19,d20,d21,d22,d23} @ load context +.Loop_neon: + vshr.u64 d24,d20,#14 @ 0 +#if 0<16 + vld1.64 {d0},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d20,#18 +#if 0>0 + vadd.i64 d16,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d20,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d20,#50 + vsli.64 d25,d20,#46 + vmov d29,d20 + vsli.64 d26,d20,#23 +#if 0<16 && defined(__ARMEL__) + vrev64.8 d0,d0 +#endif + veor d25,d24 + vbsl d29,d21,d22 @ Ch(e,f,g) + vshr.u64 d24,d16,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d23 + vshr.u64 d25,d16,#34 + vsli.64 d24,d16,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d16,#39 + vadd.i64 d28,d0 + vsli.64 d25,d16,#30 + veor d30,d16,d17 + vsli.64 d26,d16,#25 + veor d23,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d18,d17 @ Maj(a,b,c) + veor d23,d26 @ Sigma0(a) + vadd.i64 d19,d27 + vadd.i64 d30,d27 + @ vadd.i64 d23,d30 + vshr.u64 d24,d19,#14 @ 1 +#if 1<16 + vld1.64 {d1},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d19,#18 +#if 1>0 + vadd.i64 d23,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d19,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d19,#50 + vsli.64 d25,d19,#46 + vmov d29,d19 + vsli.64 d26,d19,#23 +#if 1<16 && defined(__ARMEL__) + vrev64.8 d1,d1 +#endif + veor d25,d24 + vbsl d29,d20,d21 @ Ch(e,f,g) + vshr.u64 d24,d23,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d22 + vshr.u64 d25,d23,#34 + vsli.64 d24,d23,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d23,#39 + vadd.i64 d28,d1 + vsli.64 d25,d23,#30 + veor d30,d23,d16 + vsli.64 d26,d23,#25 + veor d22,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d17,d16 @ Maj(a,b,c) + veor d22,d26 @ Sigma0(a) + vadd.i64 d18,d27 + vadd.i64 d30,d27 + @ vadd.i64 d22,d30 + vshr.u64 d24,d18,#14 @ 2 +#if 2<16 + vld1.64 {d2},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d18,#18 +#if 2>0 + vadd.i64 d22,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d18,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d18,#50 + vsli.64 d25,d18,#46 + vmov d29,d18 + vsli.64 d26,d18,#23 +#if 2<16 && defined(__ARMEL__) + vrev64.8 d2,d2 +#endif + veor d25,d24 + vbsl d29,d19,d20 @ Ch(e,f,g) + vshr.u64 d24,d22,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d21 + vshr.u64 d25,d22,#34 + vsli.64 d24,d22,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d22,#39 + vadd.i64 d28,d2 + vsli.64 d25,d22,#30 + veor d30,d22,d23 + vsli.64 d26,d22,#25 + veor d21,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d16,d23 @ Maj(a,b,c) + veor d21,d26 @ Sigma0(a) + vadd.i64 d17,d27 + vadd.i64 d30,d27 + @ vadd.i64 d21,d30 + vshr.u64 d24,d17,#14 @ 3 +#if 3<16 + vld1.64 {d3},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d17,#18 +#if 3>0 + vadd.i64 d21,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d17,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d17,#50 + vsli.64 d25,d17,#46 + vmov d29,d17 + vsli.64 d26,d17,#23 +#if 3<16 && defined(__ARMEL__) + vrev64.8 d3,d3 +#endif + veor d25,d24 + vbsl d29,d18,d19 @ Ch(e,f,g) + vshr.u64 d24,d21,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d20 + vshr.u64 d25,d21,#34 + vsli.64 d24,d21,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d21,#39 + vadd.i64 d28,d3 + vsli.64 d25,d21,#30 + veor d30,d21,d22 + vsli.64 d26,d21,#25 + veor d20,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d23,d22 @ Maj(a,b,c) + veor d20,d26 @ Sigma0(a) + vadd.i64 d16,d27 + vadd.i64 d30,d27 + @ vadd.i64 d20,d30 + vshr.u64 d24,d16,#14 @ 4 +#if 4<16 + vld1.64 {d4},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d16,#18 +#if 4>0 + vadd.i64 d20,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d16,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d16,#50 + vsli.64 d25,d16,#46 + vmov d29,d16 + vsli.64 d26,d16,#23 +#if 4<16 && defined(__ARMEL__) + vrev64.8 d4,d4 +#endif + veor d25,d24 + vbsl d29,d17,d18 @ Ch(e,f,g) + vshr.u64 d24,d20,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d19 + vshr.u64 d25,d20,#34 + vsli.64 d24,d20,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d20,#39 + vadd.i64 d28,d4 + vsli.64 d25,d20,#30 + veor d30,d20,d21 + vsli.64 d26,d20,#25 + veor d19,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d22,d21 @ Maj(a,b,c) + veor d19,d26 @ Sigma0(a) + vadd.i64 d23,d27 + vadd.i64 d30,d27 + @ vadd.i64 d19,d30 + vshr.u64 d24,d23,#14 @ 5 +#if 5<16 + vld1.64 {d5},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d23,#18 +#if 5>0 + vadd.i64 d19,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d23,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d23,#50 + vsli.64 d25,d23,#46 + vmov d29,d23 + vsli.64 d26,d23,#23 +#if 5<16 && defined(__ARMEL__) + vrev64.8 d5,d5 +#endif + veor d25,d24 + vbsl d29,d16,d17 @ Ch(e,f,g) + vshr.u64 d24,d19,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d18 + vshr.u64 d25,d19,#34 + vsli.64 d24,d19,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d19,#39 + vadd.i64 d28,d5 + vsli.64 d25,d19,#30 + veor d30,d19,d20 + vsli.64 d26,d19,#25 + veor d18,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d21,d20 @ Maj(a,b,c) + veor d18,d26 @ Sigma0(a) + vadd.i64 d22,d27 + vadd.i64 d30,d27 + @ vadd.i64 d18,d30 + vshr.u64 d24,d22,#14 @ 6 +#if 6<16 + vld1.64 {d6},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d22,#18 +#if 6>0 + vadd.i64 d18,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d22,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d22,#50 + vsli.64 d25,d22,#46 + vmov d29,d22 + vsli.64 d26,d22,#23 +#if 6<16 && defined(__ARMEL__) + vrev64.8 d6,d6 +#endif + veor d25,d24 + vbsl d29,d23,d16 @ Ch(e,f,g) + vshr.u64 d24,d18,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d17 + vshr.u64 d25,d18,#34 + vsli.64 d24,d18,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d18,#39 + vadd.i64 d28,d6 + vsli.64 d25,d18,#30 + veor d30,d18,d19 + vsli.64 d26,d18,#25 + veor d17,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d20,d19 @ Maj(a,b,c) + veor d17,d26 @ Sigma0(a) + vadd.i64 d21,d27 + vadd.i64 d30,d27 + @ vadd.i64 d17,d30 + vshr.u64 d24,d21,#14 @ 7 +#if 7<16 + vld1.64 {d7},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d21,#18 +#if 7>0 + vadd.i64 d17,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d21,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d21,#50 + vsli.64 d25,d21,#46 + vmov d29,d21 + vsli.64 d26,d21,#23 +#if 7<16 && defined(__ARMEL__) + vrev64.8 d7,d7 +#endif + veor d25,d24 + vbsl d29,d22,d23 @ Ch(e,f,g) + vshr.u64 d24,d17,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d16 + vshr.u64 d25,d17,#34 + vsli.64 d24,d17,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d17,#39 + vadd.i64 d28,d7 + vsli.64 d25,d17,#30 + veor d30,d17,d18 + vsli.64 d26,d17,#25 + veor d16,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d19,d18 @ Maj(a,b,c) + veor d16,d26 @ Sigma0(a) + vadd.i64 d20,d27 + vadd.i64 d30,d27 + @ vadd.i64 d16,d30 + vshr.u64 d24,d20,#14 @ 8 +#if 8<16 + vld1.64 {d8},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d20,#18 +#if 8>0 + vadd.i64 d16,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d20,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d20,#50 + vsli.64 d25,d20,#46 + vmov d29,d20 + vsli.64 d26,d20,#23 +#if 8<16 && defined(__ARMEL__) + vrev64.8 d8,d8 +#endif + veor d25,d24 + vbsl d29,d21,d22 @ Ch(e,f,g) + vshr.u64 d24,d16,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d23 + vshr.u64 d25,d16,#34 + vsli.64 d24,d16,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d16,#39 + vadd.i64 d28,d8 + vsli.64 d25,d16,#30 + veor d30,d16,d17 + vsli.64 d26,d16,#25 + veor d23,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d18,d17 @ Maj(a,b,c) + veor d23,d26 @ Sigma0(a) + vadd.i64 d19,d27 + vadd.i64 d30,d27 + @ vadd.i64 d23,d30 + vshr.u64 d24,d19,#14 @ 9 +#if 9<16 + vld1.64 {d9},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d19,#18 +#if 9>0 + vadd.i64 d23,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d19,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d19,#50 + vsli.64 d25,d19,#46 + vmov d29,d19 + vsli.64 d26,d19,#23 +#if 9<16 && defined(__ARMEL__) + vrev64.8 d9,d9 +#endif + veor d25,d24 + vbsl d29,d20,d21 @ Ch(e,f,g) + vshr.u64 d24,d23,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d22 + vshr.u64 d25,d23,#34 + vsli.64 d24,d23,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d23,#39 + vadd.i64 d28,d9 + vsli.64 d25,d23,#30 + veor d30,d23,d16 + vsli.64 d26,d23,#25 + veor d22,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d17,d16 @ Maj(a,b,c) + veor d22,d26 @ Sigma0(a) + vadd.i64 d18,d27 + vadd.i64 d30,d27 + @ vadd.i64 d22,d30 + vshr.u64 d24,d18,#14 @ 10 +#if 10<16 + vld1.64 {d10},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d18,#18 +#if 10>0 + vadd.i64 d22,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d18,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d18,#50 + vsli.64 d25,d18,#46 + vmov d29,d18 + vsli.64 d26,d18,#23 +#if 10<16 && defined(__ARMEL__) + vrev64.8 d10,d10 +#endif + veor d25,d24 + vbsl d29,d19,d20 @ Ch(e,f,g) + vshr.u64 d24,d22,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d21 + vshr.u64 d25,d22,#34 + vsli.64 d24,d22,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d22,#39 + vadd.i64 d28,d10 + vsli.64 d25,d22,#30 + veor d30,d22,d23 + vsli.64 d26,d22,#25 + veor d21,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d16,d23 @ Maj(a,b,c) + veor d21,d26 @ Sigma0(a) + vadd.i64 d17,d27 + vadd.i64 d30,d27 + @ vadd.i64 d21,d30 + vshr.u64 d24,d17,#14 @ 11 +#if 11<16 + vld1.64 {d11},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d17,#18 +#if 11>0 + vadd.i64 d21,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d17,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d17,#50 + vsli.64 d25,d17,#46 + vmov d29,d17 + vsli.64 d26,d17,#23 +#if 11<16 && defined(__ARMEL__) + vrev64.8 d11,d11 +#endif + veor d25,d24 + vbsl d29,d18,d19 @ Ch(e,f,g) + vshr.u64 d24,d21,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d20 + vshr.u64 d25,d21,#34 + vsli.64 d24,d21,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d21,#39 + vadd.i64 d28,d11 + vsli.64 d25,d21,#30 + veor d30,d21,d22 + vsli.64 d26,d21,#25 + veor d20,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d23,d22 @ Maj(a,b,c) + veor d20,d26 @ Sigma0(a) + vadd.i64 d16,d27 + vadd.i64 d30,d27 + @ vadd.i64 d20,d30 + vshr.u64 d24,d16,#14 @ 12 +#if 12<16 + vld1.64 {d12},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d16,#18 +#if 12>0 + vadd.i64 d20,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d16,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d16,#50 + vsli.64 d25,d16,#46 + vmov d29,d16 + vsli.64 d26,d16,#23 +#if 12<16 && defined(__ARMEL__) + vrev64.8 d12,d12 +#endif + veor d25,d24 + vbsl d29,d17,d18 @ Ch(e,f,g) + vshr.u64 d24,d20,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d19 + vshr.u64 d25,d20,#34 + vsli.64 d24,d20,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d20,#39 + vadd.i64 d28,d12 + vsli.64 d25,d20,#30 + veor d30,d20,d21 + vsli.64 d26,d20,#25 + veor d19,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d22,d21 @ Maj(a,b,c) + veor d19,d26 @ Sigma0(a) + vadd.i64 d23,d27 + vadd.i64 d30,d27 + @ vadd.i64 d19,d30 + vshr.u64 d24,d23,#14 @ 13 +#if 13<16 + vld1.64 {d13},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d23,#18 +#if 13>0 + vadd.i64 d19,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d23,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d23,#50 + vsli.64 d25,d23,#46 + vmov d29,d23 + vsli.64 d26,d23,#23 +#if 13<16 && defined(__ARMEL__) + vrev64.8 d13,d13 +#endif + veor d25,d24 + vbsl d29,d16,d17 @ Ch(e,f,g) + vshr.u64 d24,d19,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d18 + vshr.u64 d25,d19,#34 + vsli.64 d24,d19,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d19,#39 + vadd.i64 d28,d13 + vsli.64 d25,d19,#30 + veor d30,d19,d20 + vsli.64 d26,d19,#25 + veor d18,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d21,d20 @ Maj(a,b,c) + veor d18,d26 @ Sigma0(a) + vadd.i64 d22,d27 + vadd.i64 d30,d27 + @ vadd.i64 d18,d30 + vshr.u64 d24,d22,#14 @ 14 +#if 14<16 + vld1.64 {d14},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d22,#18 +#if 14>0 + vadd.i64 d18,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d22,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d22,#50 + vsli.64 d25,d22,#46 + vmov d29,d22 + vsli.64 d26,d22,#23 +#if 14<16 && defined(__ARMEL__) + vrev64.8 d14,d14 +#endif + veor d25,d24 + vbsl d29,d23,d16 @ Ch(e,f,g) + vshr.u64 d24,d18,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d17 + vshr.u64 d25,d18,#34 + vsli.64 d24,d18,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d18,#39 + vadd.i64 d28,d14 + vsli.64 d25,d18,#30 + veor d30,d18,d19 + vsli.64 d26,d18,#25 + veor d17,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d20,d19 @ Maj(a,b,c) + veor d17,d26 @ Sigma0(a) + vadd.i64 d21,d27 + vadd.i64 d30,d27 + @ vadd.i64 d17,d30 + vshr.u64 d24,d21,#14 @ 15 +#if 15<16 + vld1.64 {d15},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d21,#18 +#if 15>0 + vadd.i64 d17,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d21,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d21,#50 + vsli.64 d25,d21,#46 + vmov d29,d21 + vsli.64 d26,d21,#23 +#if 15<16 && defined(__ARMEL__) + vrev64.8 d15,d15 +#endif + veor d25,d24 + vbsl d29,d22,d23 @ Ch(e,f,g) + vshr.u64 d24,d17,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d16 + vshr.u64 d25,d17,#34 + vsli.64 d24,d17,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d17,#39 + vadd.i64 d28,d15 + vsli.64 d25,d17,#30 + veor d30,d17,d18 + vsli.64 d26,d17,#25 + veor d16,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d19,d18 @ Maj(a,b,c) + veor d16,d26 @ Sigma0(a) + vadd.i64 d20,d27 + vadd.i64 d30,d27 + @ vadd.i64 d16,d30 + mov r12,#4 +.L16_79_neon: + subs r12,#1 + vshr.u64 q12,q7,#19 + vshr.u64 q13,q7,#61 + vadd.i64 d16,d30 @ h+=Maj from the past + vshr.u64 q15,q7,#6 + vsli.64 q12,q7,#45 + vext.8 q14,q0,q1,#8 @ X[i+1] + vsli.64 q13,q7,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q0,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q4,q5,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d20,#14 @ from NEON_00_15 + vadd.i64 q0,q14 + vshr.u64 d25,d20,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d20,#41 @ from NEON_00_15 + vadd.i64 q0,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d20,#50 + vsli.64 d25,d20,#46 + vmov d29,d20 + vsli.64 d26,d20,#23 +#if 16<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d21,d22 @ Ch(e,f,g) + vshr.u64 d24,d16,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d23 + vshr.u64 d25,d16,#34 + vsli.64 d24,d16,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d16,#39 + vadd.i64 d28,d0 + vsli.64 d25,d16,#30 + veor d30,d16,d17 + vsli.64 d26,d16,#25 + veor d23,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d18,d17 @ Maj(a,b,c) + veor d23,d26 @ Sigma0(a) + vadd.i64 d19,d27 + vadd.i64 d30,d27 + @ vadd.i64 d23,d30 + vshr.u64 d24,d19,#14 @ 17 +#if 17<16 + vld1.64 {d1},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d19,#18 +#if 17>0 + vadd.i64 d23,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d19,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d19,#50 + vsli.64 d25,d19,#46 + vmov d29,d19 + vsli.64 d26,d19,#23 +#if 17<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d20,d21 @ Ch(e,f,g) + vshr.u64 d24,d23,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d22 + vshr.u64 d25,d23,#34 + vsli.64 d24,d23,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d23,#39 + vadd.i64 d28,d1 + vsli.64 d25,d23,#30 + veor d30,d23,d16 + vsli.64 d26,d23,#25 + veor d22,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d17,d16 @ Maj(a,b,c) + veor d22,d26 @ Sigma0(a) + vadd.i64 d18,d27 + vadd.i64 d30,d27 + @ vadd.i64 d22,d30 + vshr.u64 q12,q0,#19 + vshr.u64 q13,q0,#61 + vadd.i64 d22,d30 @ h+=Maj from the past + vshr.u64 q15,q0,#6 + vsli.64 q12,q0,#45 + vext.8 q14,q1,q2,#8 @ X[i+1] + vsli.64 q13,q0,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q1,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q5,q6,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d18,#14 @ from NEON_00_15 + vadd.i64 q1,q14 + vshr.u64 d25,d18,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d18,#41 @ from NEON_00_15 + vadd.i64 q1,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d18,#50 + vsli.64 d25,d18,#46 + vmov d29,d18 + vsli.64 d26,d18,#23 +#if 18<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d19,d20 @ Ch(e,f,g) + vshr.u64 d24,d22,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d21 + vshr.u64 d25,d22,#34 + vsli.64 d24,d22,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d22,#39 + vadd.i64 d28,d2 + vsli.64 d25,d22,#30 + veor d30,d22,d23 + vsli.64 d26,d22,#25 + veor d21,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d16,d23 @ Maj(a,b,c) + veor d21,d26 @ Sigma0(a) + vadd.i64 d17,d27 + vadd.i64 d30,d27 + @ vadd.i64 d21,d30 + vshr.u64 d24,d17,#14 @ 19 +#if 19<16 + vld1.64 {d3},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d17,#18 +#if 19>0 + vadd.i64 d21,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d17,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d17,#50 + vsli.64 d25,d17,#46 + vmov d29,d17 + vsli.64 d26,d17,#23 +#if 19<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d18,d19 @ Ch(e,f,g) + vshr.u64 d24,d21,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d20 + vshr.u64 d25,d21,#34 + vsli.64 d24,d21,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d21,#39 + vadd.i64 d28,d3 + vsli.64 d25,d21,#30 + veor d30,d21,d22 + vsli.64 d26,d21,#25 + veor d20,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d23,d22 @ Maj(a,b,c) + veor d20,d26 @ Sigma0(a) + vadd.i64 d16,d27 + vadd.i64 d30,d27 + @ vadd.i64 d20,d30 + vshr.u64 q12,q1,#19 + vshr.u64 q13,q1,#61 + vadd.i64 d20,d30 @ h+=Maj from the past + vshr.u64 q15,q1,#6 + vsli.64 q12,q1,#45 + vext.8 q14,q2,q3,#8 @ X[i+1] + vsli.64 q13,q1,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q2,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q6,q7,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d16,#14 @ from NEON_00_15 + vadd.i64 q2,q14 + vshr.u64 d25,d16,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d16,#41 @ from NEON_00_15 + vadd.i64 q2,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d16,#50 + vsli.64 d25,d16,#46 + vmov d29,d16 + vsli.64 d26,d16,#23 +#if 20<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d17,d18 @ Ch(e,f,g) + vshr.u64 d24,d20,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d19 + vshr.u64 d25,d20,#34 + vsli.64 d24,d20,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d20,#39 + vadd.i64 d28,d4 + vsli.64 d25,d20,#30 + veor d30,d20,d21 + vsli.64 d26,d20,#25 + veor d19,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d22,d21 @ Maj(a,b,c) + veor d19,d26 @ Sigma0(a) + vadd.i64 d23,d27 + vadd.i64 d30,d27 + @ vadd.i64 d19,d30 + vshr.u64 d24,d23,#14 @ 21 +#if 21<16 + vld1.64 {d5},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d23,#18 +#if 21>0 + vadd.i64 d19,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d23,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d23,#50 + vsli.64 d25,d23,#46 + vmov d29,d23 + vsli.64 d26,d23,#23 +#if 21<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d16,d17 @ Ch(e,f,g) + vshr.u64 d24,d19,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d18 + vshr.u64 d25,d19,#34 + vsli.64 d24,d19,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d19,#39 + vadd.i64 d28,d5 + vsli.64 d25,d19,#30 + veor d30,d19,d20 + vsli.64 d26,d19,#25 + veor d18,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d21,d20 @ Maj(a,b,c) + veor d18,d26 @ Sigma0(a) + vadd.i64 d22,d27 + vadd.i64 d30,d27 + @ vadd.i64 d18,d30 + vshr.u64 q12,q2,#19 + vshr.u64 q13,q2,#61 + vadd.i64 d18,d30 @ h+=Maj from the past + vshr.u64 q15,q2,#6 + vsli.64 q12,q2,#45 + vext.8 q14,q3,q4,#8 @ X[i+1] + vsli.64 q13,q2,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q3,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q7,q0,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d22,#14 @ from NEON_00_15 + vadd.i64 q3,q14 + vshr.u64 d25,d22,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d22,#41 @ from NEON_00_15 + vadd.i64 q3,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d22,#50 + vsli.64 d25,d22,#46 + vmov d29,d22 + vsli.64 d26,d22,#23 +#if 22<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d23,d16 @ Ch(e,f,g) + vshr.u64 d24,d18,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d17 + vshr.u64 d25,d18,#34 + vsli.64 d24,d18,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d18,#39 + vadd.i64 d28,d6 + vsli.64 d25,d18,#30 + veor d30,d18,d19 + vsli.64 d26,d18,#25 + veor d17,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d20,d19 @ Maj(a,b,c) + veor d17,d26 @ Sigma0(a) + vadd.i64 d21,d27 + vadd.i64 d30,d27 + @ vadd.i64 d17,d30 + vshr.u64 d24,d21,#14 @ 23 +#if 23<16 + vld1.64 {d7},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d21,#18 +#if 23>0 + vadd.i64 d17,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d21,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d21,#50 + vsli.64 d25,d21,#46 + vmov d29,d21 + vsli.64 d26,d21,#23 +#if 23<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d22,d23 @ Ch(e,f,g) + vshr.u64 d24,d17,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d16 + vshr.u64 d25,d17,#34 + vsli.64 d24,d17,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d17,#39 + vadd.i64 d28,d7 + vsli.64 d25,d17,#30 + veor d30,d17,d18 + vsli.64 d26,d17,#25 + veor d16,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d19,d18 @ Maj(a,b,c) + veor d16,d26 @ Sigma0(a) + vadd.i64 d20,d27 + vadd.i64 d30,d27 + @ vadd.i64 d16,d30 + vshr.u64 q12,q3,#19 + vshr.u64 q13,q3,#61 + vadd.i64 d16,d30 @ h+=Maj from the past + vshr.u64 q15,q3,#6 + vsli.64 q12,q3,#45 + vext.8 q14,q4,q5,#8 @ X[i+1] + vsli.64 q13,q3,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q4,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q0,q1,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d20,#14 @ from NEON_00_15 + vadd.i64 q4,q14 + vshr.u64 d25,d20,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d20,#41 @ from NEON_00_15 + vadd.i64 q4,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d20,#50 + vsli.64 d25,d20,#46 + vmov d29,d20 + vsli.64 d26,d20,#23 +#if 24<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d21,d22 @ Ch(e,f,g) + vshr.u64 d24,d16,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d23 + vshr.u64 d25,d16,#34 + vsli.64 d24,d16,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d16,#39 + vadd.i64 d28,d8 + vsli.64 d25,d16,#30 + veor d30,d16,d17 + vsli.64 d26,d16,#25 + veor d23,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d18,d17 @ Maj(a,b,c) + veor d23,d26 @ Sigma0(a) + vadd.i64 d19,d27 + vadd.i64 d30,d27 + @ vadd.i64 d23,d30 + vshr.u64 d24,d19,#14 @ 25 +#if 25<16 + vld1.64 {d9},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d19,#18 +#if 25>0 + vadd.i64 d23,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d19,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d19,#50 + vsli.64 d25,d19,#46 + vmov d29,d19 + vsli.64 d26,d19,#23 +#if 25<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d20,d21 @ Ch(e,f,g) + vshr.u64 d24,d23,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d22 + vshr.u64 d25,d23,#34 + vsli.64 d24,d23,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d23,#39 + vadd.i64 d28,d9 + vsli.64 d25,d23,#30 + veor d30,d23,d16 + vsli.64 d26,d23,#25 + veor d22,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d17,d16 @ Maj(a,b,c) + veor d22,d26 @ Sigma0(a) + vadd.i64 d18,d27 + vadd.i64 d30,d27 + @ vadd.i64 d22,d30 + vshr.u64 q12,q4,#19 + vshr.u64 q13,q4,#61 + vadd.i64 d22,d30 @ h+=Maj from the past + vshr.u64 q15,q4,#6 + vsli.64 q12,q4,#45 + vext.8 q14,q5,q6,#8 @ X[i+1] + vsli.64 q13,q4,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q5,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q1,q2,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d18,#14 @ from NEON_00_15 + vadd.i64 q5,q14 + vshr.u64 d25,d18,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d18,#41 @ from NEON_00_15 + vadd.i64 q5,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d18,#50 + vsli.64 d25,d18,#46 + vmov d29,d18 + vsli.64 d26,d18,#23 +#if 26<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d19,d20 @ Ch(e,f,g) + vshr.u64 d24,d22,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d21 + vshr.u64 d25,d22,#34 + vsli.64 d24,d22,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d22,#39 + vadd.i64 d28,d10 + vsli.64 d25,d22,#30 + veor d30,d22,d23 + vsli.64 d26,d22,#25 + veor d21,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d16,d23 @ Maj(a,b,c) + veor d21,d26 @ Sigma0(a) + vadd.i64 d17,d27 + vadd.i64 d30,d27 + @ vadd.i64 d21,d30 + vshr.u64 d24,d17,#14 @ 27 +#if 27<16 + vld1.64 {d11},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d17,#18 +#if 27>0 + vadd.i64 d21,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d17,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d17,#50 + vsli.64 d25,d17,#46 + vmov d29,d17 + vsli.64 d26,d17,#23 +#if 27<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d18,d19 @ Ch(e,f,g) + vshr.u64 d24,d21,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d20 + vshr.u64 d25,d21,#34 + vsli.64 d24,d21,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d21,#39 + vadd.i64 d28,d11 + vsli.64 d25,d21,#30 + veor d30,d21,d22 + vsli.64 d26,d21,#25 + veor d20,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d23,d22 @ Maj(a,b,c) + veor d20,d26 @ Sigma0(a) + vadd.i64 d16,d27 + vadd.i64 d30,d27 + @ vadd.i64 d20,d30 + vshr.u64 q12,q5,#19 + vshr.u64 q13,q5,#61 + vadd.i64 d20,d30 @ h+=Maj from the past + vshr.u64 q15,q5,#6 + vsli.64 q12,q5,#45 + vext.8 q14,q6,q7,#8 @ X[i+1] + vsli.64 q13,q5,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q6,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q2,q3,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d16,#14 @ from NEON_00_15 + vadd.i64 q6,q14 + vshr.u64 d25,d16,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d16,#41 @ from NEON_00_15 + vadd.i64 q6,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d16,#50 + vsli.64 d25,d16,#46 + vmov d29,d16 + vsli.64 d26,d16,#23 +#if 28<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d17,d18 @ Ch(e,f,g) + vshr.u64 d24,d20,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d19 + vshr.u64 d25,d20,#34 + vsli.64 d24,d20,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d20,#39 + vadd.i64 d28,d12 + vsli.64 d25,d20,#30 + veor d30,d20,d21 + vsli.64 d26,d20,#25 + veor d19,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d22,d21 @ Maj(a,b,c) + veor d19,d26 @ Sigma0(a) + vadd.i64 d23,d27 + vadd.i64 d30,d27 + @ vadd.i64 d19,d30 + vshr.u64 d24,d23,#14 @ 29 +#if 29<16 + vld1.64 {d13},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d23,#18 +#if 29>0 + vadd.i64 d19,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d23,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d23,#50 + vsli.64 d25,d23,#46 + vmov d29,d23 + vsli.64 d26,d23,#23 +#if 29<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d16,d17 @ Ch(e,f,g) + vshr.u64 d24,d19,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d18 + vshr.u64 d25,d19,#34 + vsli.64 d24,d19,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d19,#39 + vadd.i64 d28,d13 + vsli.64 d25,d19,#30 + veor d30,d19,d20 + vsli.64 d26,d19,#25 + veor d18,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d21,d20 @ Maj(a,b,c) + veor d18,d26 @ Sigma0(a) + vadd.i64 d22,d27 + vadd.i64 d30,d27 + @ vadd.i64 d18,d30 + vshr.u64 q12,q6,#19 + vshr.u64 q13,q6,#61 + vadd.i64 d18,d30 @ h+=Maj from the past + vshr.u64 q15,q6,#6 + vsli.64 q12,q6,#45 + vext.8 q14,q7,q0,#8 @ X[i+1] + vsli.64 q13,q6,#3 + veor q15,q12 + vshr.u64 q12,q14,#1 + veor q15,q13 @ sigma1(X[i+14]) + vshr.u64 q13,q14,#8 + vadd.i64 q7,q15 + vshr.u64 q15,q14,#7 + vsli.64 q12,q14,#63 + vsli.64 q13,q14,#56 + vext.8 q14,q3,q4,#8 @ X[i+9] + veor q15,q12 + vshr.u64 d24,d22,#14 @ from NEON_00_15 + vadd.i64 q7,q14 + vshr.u64 d25,d22,#18 @ from NEON_00_15 + veor q15,q13 @ sigma0(X[i+1]) + vshr.u64 d26,d22,#41 @ from NEON_00_15 + vadd.i64 q7,q15 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d22,#50 + vsli.64 d25,d22,#46 + vmov d29,d22 + vsli.64 d26,d22,#23 +#if 30<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d23,d16 @ Ch(e,f,g) + vshr.u64 d24,d18,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d17 + vshr.u64 d25,d18,#34 + vsli.64 d24,d18,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d18,#39 + vadd.i64 d28,d14 + vsli.64 d25,d18,#30 + veor d30,d18,d19 + vsli.64 d26,d18,#25 + veor d17,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d20,d19 @ Maj(a,b,c) + veor d17,d26 @ Sigma0(a) + vadd.i64 d21,d27 + vadd.i64 d30,d27 + @ vadd.i64 d17,d30 + vshr.u64 d24,d21,#14 @ 31 +#if 31<16 + vld1.64 {d15},[r1]! @ handles unaligned +#endif + vshr.u64 d25,d21,#18 +#if 31>0 + vadd.i64 d17,d30 @ h+=Maj from the past +#endif + vshr.u64 d26,d21,#41 + vld1.64 {d28},[r3,:64]! @ K[i++] + vsli.64 d24,d21,#50 + vsli.64 d25,d21,#46 + vmov d29,d21 + vsli.64 d26,d21,#23 +#if 31<16 && defined(__ARMEL__) + vrev64.8 , +#endif + veor d25,d24 + vbsl d29,d22,d23 @ Ch(e,f,g) + vshr.u64 d24,d17,#28 + veor d26,d25 @ Sigma1(e) + vadd.i64 d27,d29,d16 + vshr.u64 d25,d17,#34 + vsli.64 d24,d17,#36 + vadd.i64 d27,d26 + vshr.u64 d26,d17,#39 + vadd.i64 d28,d15 + vsli.64 d25,d17,#30 + veor d30,d17,d18 + vsli.64 d26,d17,#25 + veor d16,d24,d25 + vadd.i64 d27,d28 + vbsl d30,d19,d18 @ Maj(a,b,c) + veor d16,d26 @ Sigma0(a) + vadd.i64 d20,d27 + vadd.i64 d30,d27 + @ vadd.i64 d16,d30 + bne .L16_79_neon + + vadd.i64 d16,d30 @ h+=Maj from the past + vldmia r0,{d24,d25,d26,d27,d28,d29,d30,d31} @ load context to temp + vadd.i64 q8,q12 @ vectorized accumulate + vadd.i64 q9,q13 + vadd.i64 q10,q14 + vadd.i64 q11,q15 + vstmia r0,{d16,d17,d18,d19,d20,d21,d22,d23} @ save context + teq r1,r2 + sub r3,#640 @ rewind K512 + bne .Loop_neon + vldmia sp!,{d8-d15} + bx lr @ .word 0xe12fff1e +.size cryptogams_sha512_block_data_order_neon,.-cryptogams_sha512_block_data_order_neon +#endif diff --git a/extension/third_party/cryptopp/sha512_armv4.h b/extension/third_party/cryptopp/sha512_armv4.h new file mode 100644 index 00000000..b914577f --- /dev/null +++ b/extension/third_party/cryptopp/sha512_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA512. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA512_ARMV4_H +#define CRYPTOGAMS_SHA512_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified cryptogams_sha512_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha512_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA512_ARMV4_H */ diff --git a/extension/third_party/cryptopp/sha_simd.cpp b/extension/third_party/cryptopp/sha_simd.cpp new file mode 100644 index 00000000..277c9362 --- /dev/null +++ b/extension/third_party/cryptopp/sha_simd.cpp @@ -0,0 +1,1508 @@ +// sha_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to SHA-NI and +// ARMv8a SHA instructions. A separate source file is needed +// because additional CXXFLAGS are required to enable the +// appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "sha.h" +#include "misc.h" + +#if defined(CRYPTOPP_DISABLE_SHA_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +#if (CRYPTOPP_SHANI_AVAILABLE) +# include +# include +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if CRYPTOPP_POWER8_SHA_AVAILABLE +# include "ppc_simd.h" +#endif + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Clang intrinsic casts +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char SHA_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +// ***************** SHA key tables ******************** + +extern const word32 SHA256_K[64]; +extern const word64 SHA512_K[80]; + +// ***************** SIGILL probes ******************** + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); + + static jmp_buf s_jmpSIGILL; + static void SigIllHandler(int) + { + longjmp(s_jmpSIGILL, 1); + } +} +#endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) +bool CPU_ProbeSHA1() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_ARM_SHA1_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + unsigned int w[] = {1,2,3,4, 5,6,7,8, 9,10,11,12}; + uint32x4_t data1 = vld1q_u32(w+0); + uint32x4_t data2 = vld1q_u32(w+4); + uint32x4_t data3 = vld1q_u32(w+8); + + uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2); + uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2); + uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2); + uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3); + uint32x4_t r5 = vsha1su1q_u32 (data1, data2); + + result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +# else + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + unsigned int w[] = {1,2,3,4, 5,6,7,8, 9,10,11,12}; + uint32x4_t data1 = vld1q_u32(w+0); + uint32x4_t data2 = vld1q_u32(w+4); + uint32x4_t data3 = vld1q_u32(w+8); + + uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2); + uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2); + uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2); + uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3); + uint32x4_t r5 = vsha1su1q_u32 (data1, data2); + + result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_SHA1_AVAILABLE +} + +bool CPU_ProbeSHA256() +{ +#if defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif (CRYPTOPP_ARM_SHA2_AVAILABLE) +# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + volatile bool result = true; + __try + { + unsigned int w[] = {1,2,3,4, 5,6,7,8, 9,10,11,12}; + uint32x4_t data1 = vld1q_u32(w+0); + uint32x4_t data2 = vld1q_u32(w+4); + uint32x4_t data3 = vld1q_u32(w+8); + + uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3); + uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3); + uint32x4_t r3 = vsha256su0q_u32 (data1, data2); + uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3); + + result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return result; +#else + + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } + + if (setjmp(s_jmpSIGILL)) + result = false; + else + { + unsigned int w[] = {1,2,3,4, 5,6,7,8, 9,10,11,12}; + uint32x4_t data1 = vld1q_u32(w+0); + uint32x4_t data2 = vld1q_u32(w+4); + uint32x4_t data3 = vld1q_u32(w+8); + + uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3); + uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3); + uint32x4_t r3 = vsha256su0q_u32 (data1, data2); + uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3); + + result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3)); + } + + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); + signal(SIGILL, oldHandler); + return result; +# endif +#else + return false; +#endif // CRYPTOPP_ARM_SHA2_AVAILABLE +} +#endif // ARM32 or ARM64 + +// ***************** Intel x86 SHA ******************** + +///////////////////////////////////// +// start of Walton and Gulley code // +///////////////////////////////////// + +#if CRYPTOPP_SHANI_AVAILABLE +// Based on http://software.intel.com/en-us/articles/intel-sha-extensions and code by Sean Gulley. +void SHA1_HashMultipleBlocks_SHANI(word32 *state, const word32 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA1::BLOCKSIZE); + + __m128i ABCD, ABCD_SAVE, E0, E0_SAVE, E1; + __m128i MASK, MSG0, MSG1, MSG2, MSG3; + + // Load initial values + ABCD = _mm_loadu_si128(CONST_M128_CAST(state)); + E0 = _mm_set_epi32(state[4], 0, 0, 0); + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + + // IA-32 SHA is little endian, SHA::Transform is big endian, + // and SHA::HashMultipleBlocks can be either. ByteOrder + // allows us to avoid extra endian reversals. It saves 1.0 cpb. + MASK = order == BIG_ENDIAN_ORDER ? // Data arrangement + _mm_set_epi8(0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15) : + _mm_set_epi8(3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12) ; + + while (length >= SHA1::BLOCKSIZE) + { + // Save current hash + ABCD_SAVE = ABCD; + E0_SAVE = E0; + + // Rounds 0-3 + MSG0 = _mm_loadu_si128(CONST_M128_CAST(data+0)); + MSG0 = _mm_shuffle_epi8(MSG0, MASK); + E0 = _mm_add_epi32(E0, MSG0); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + + // Rounds 4-7 + MSG1 = _mm_loadu_si128(CONST_M128_CAST(data+4)); + MSG1 = _mm_shuffle_epi8(MSG1, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + + // Rounds 8-11 + MSG2 = _mm_loadu_si128(CONST_M128_CAST(data+8)); + MSG2 = _mm_shuffle_epi8(MSG2, MASK); + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 12-15 + MSG3 = _mm_loadu_si128(CONST_M128_CAST(data+12)); + MSG3 = _mm_shuffle_epi8(MSG3, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 16-19 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 20-23 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 24-27 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 28-31 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 32-35 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 36-39 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 40-43 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 44-47 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 48-51 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 52-55 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 56-59 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 60-63 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 64-67 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 68-71 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 72-75 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + + // Rounds 76-79 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + + // Add values back to state + E0 = _mm_sha1nexte_epu32(E0, E0_SAVE); + ABCD = _mm_add_epi32(ABCD, ABCD_SAVE); + + data += SHA1::BLOCKSIZE/sizeof(word32); + length -= SHA1::BLOCKSIZE; + } + + // Save state + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + _mm_storeu_si128(M128_CAST(state), ABCD); + state[4] = _mm_extract_epi32(E0, 3); +} + +// Based on http://software.intel.com/en-us/articles/intel-sha-extensions and code by Sean Gulley. +void SHA256_HashMultipleBlocks_SHANI(word32 *state, const word32 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE); + + __m128i STATE0, STATE1; + __m128i MSG, TMP, MASK; + __m128i TMSG0, TMSG1, TMSG2, TMSG3; + __m128i ABEF_SAVE, CDGH_SAVE; + + // Load initial values + TMP = _mm_loadu_si128(M128_CAST(&state[0])); + STATE1 = _mm_loadu_si128(M128_CAST(&state[4])); + + // IA-32 SHA is little endian, SHA::Transform is big endian, + // and SHA::HashMultipleBlocks can be either. ByteOrder + // allows us to avoid extra endian reversals. It saves 1.0 cpb. + MASK = order == BIG_ENDIAN_ORDER ? // Data arrangement + _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3) : + _mm_set_epi8(15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0) ; + + TMP = _mm_shuffle_epi32(TMP, 0xB1); // CDAB + STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); // EFGH + STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); // ABEF + STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); // CDGH + + while (length >= SHA256::BLOCKSIZE) + { + // Save current hash + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + // Rounds 0-3 + MSG = _mm_loadu_si128(CONST_M128_CAST(data+0)); + TMSG0 = _mm_shuffle_epi8(MSG, MASK); + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(W64LIT(0xE9B5DBA5B5C0FBCF), W64LIT(0x71374491428A2F98))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 4-7 + TMSG1 = _mm_loadu_si128(CONST_M128_CAST(data+4)); + TMSG1 = _mm_shuffle_epi8(TMSG1, MASK); + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(W64LIT(0xAB1C5ED5923F82A4), W64LIT(0x59F111F13956C25B))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 8-11 + TMSG2 = _mm_loadu_si128(CONST_M128_CAST(data+8)); + TMSG2 = _mm_shuffle_epi8(TMSG2, MASK); + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(W64LIT(0x550C7DC3243185BE), W64LIT(0x12835B01D807AA98))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 12-15 + TMSG3 = _mm_loadu_si128(CONST_M128_CAST(data+12)); + TMSG3 = _mm_shuffle_epi8(TMSG3, MASK); + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(W64LIT(0xC19BF1749BDC06A7), W64LIT(0x80DEB1FE72BE5D74))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 16-19 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(W64LIT(0x240CA1CC0FC19DC6), W64LIT(0xEFBE4786E49B69C1))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 20-23 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(W64LIT(0x76F988DA5CB0A9DC), W64LIT(0x4A7484AA2DE92C6F))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 24-27 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(W64LIT(0xBF597FC7B00327C8), W64LIT(0xA831C66D983E5152))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 28-31 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(W64LIT(0x1429296706CA6351), W64LIT(0xD5A79147C6E00BF3))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 32-35 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(W64LIT(0x53380D134D2C6DFC), W64LIT(0x2E1B213827B70A85))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 36-39 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(W64LIT(0x92722C8581C2C92E), W64LIT(0x766A0ABB650A7354))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 40-43 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(W64LIT(0xC76C51A3C24B8B70), W64LIT(0xA81A664BA2BFE8A1))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 44-47 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(W64LIT(0x106AA070F40E3585), W64LIT(0xD6990624D192E819))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 48-51 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(W64LIT(0x34B0BCB52748774C), W64LIT(0x1E376C0819A4C116))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 52-55 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(W64LIT(0x682E6FF35B9CCA4F), W64LIT(0x4ED8AA4A391C0CB3))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 56-59 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(W64LIT(0x8CC7020884C87814), W64LIT(0x78A5636F748F82EE))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 60-63 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(W64LIT(0xC67178F2BEF9A3F7), W64LIT(0xA4506CEB90BEFFFA))); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Add values back to state + STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE); + STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE); + + data += SHA256::BLOCKSIZE/sizeof(word32); + length -= SHA256::BLOCKSIZE; + } + + TMP = _mm_shuffle_epi32(STATE0, 0x1B); // FEBA + STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); // DCHG + STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); // DCBA + STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); // ABEF + + // Save state + _mm_storeu_si128(M128_CAST(&state[0]), STATE0); + _mm_storeu_si128(M128_CAST(&state[4]), STATE1); +} +#endif // CRYPTOPP_SHANI_AVAILABLE + +/////////////////////////////////// +// end of Walton and Gulley code // +/////////////////////////////////// + +// ***************** ARMV8 SHA ******************** + +///////////////////////////////////////////////////////////// +// start of Walton, Schneiders, O'Rourke and Hovsmith code // +///////////////////////////////////////////////////////////// + +#if CRYPTOPP_ARM_SHA1_AVAILABLE +void SHA1_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA1::BLOCKSIZE); + + uint32x4_t C0, C1, C2, C3; + uint32x4_t ABCD, ABCD_SAVED; + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1; + uint32_t E0, E0_SAVED, E1; + + // Load initial values + C0 = vdupq_n_u32(0x5A827999); + C1 = vdupq_n_u32(0x6ED9EBA1); + C2 = vdupq_n_u32(0x8F1BBCDC); + C3 = vdupq_n_u32(0xCA62C1D6); + + ABCD = vld1q_u32(&state[0]); + E0 = state[4]; + + while (length >= SHA1::BLOCKSIZE) + { + // Save current hash + ABCD_SAVED = ABCD; + E0_SAVED = E0; + + MSG0 = vld1q_u32(data + 0); + MSG1 = vld1q_u32(data + 4); + MSG2 = vld1q_u32(data + 8); + MSG3 = vld1q_u32(data + 12); + + if (order == BIG_ENDIAN_ORDER) // Data arrangement + { + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + } + + TMP0 = vaddq_u32(MSG0, C0); + TMP1 = vaddq_u32(MSG1, C0); + + // Rounds 0-3 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C0); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 4-7 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C0); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 8-11 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C0); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 12-15 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 16-19 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C1); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 20-23 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C1); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 24-27 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C1); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 28-31 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 32-35 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 36-39 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C2); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 40-43 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C2); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 44-47 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C2); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 48-51 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 52-55 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 56-59 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C3); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 60-63 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C3); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 64-67 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C3); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 68-71 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + + // Rounds 72-75 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + + // Rounds 76-79 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + + E0 += E0_SAVED; + ABCD = vaddq_u32(ABCD_SAVED, ABCD); + + data += SHA1::BLOCKSIZE/sizeof(word32); + length -= SHA1::BLOCKSIZE; + } + + // Save state + vst1q_u32(&state[0], ABCD); + state[4] = E0; +} +#endif // CRYPTOPP_ARM_SHA1_AVAILABLE + +#if CRYPTOPP_ARM_SHA2_AVAILABLE +void SHA256_HashMultipleBlocks_ARMV8(word32 *state, const word32 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE); + + uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE; + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1, TMP2; + + // Load initial values + STATE0 = vld1q_u32(&state[0]); + STATE1 = vld1q_u32(&state[4]); + + while (length >= SHA256::BLOCKSIZE) + { + // Save current hash + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + // Load message + MSG0 = vld1q_u32(data + 0); + MSG1 = vld1q_u32(data + 4); + MSG2 = vld1q_u32(data + 8); + MSG3 = vld1q_u32(data + 12); + + if (order == BIG_ENDIAN_ORDER) // Data arrangement + { + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + } + + TMP0 = vaddq_u32(MSG0, vld1q_u32(&SHA256_K[0x00])); + + // Rounds 0-3 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&SHA256_K[0x04])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 4-7 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&SHA256_K[0x08])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 8-11 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&SHA256_K[0x0c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 12-15 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&SHA256_K[0x10])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 16-19 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&SHA256_K[0x14])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 20-23 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&SHA256_K[0x18])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 24-27 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&SHA256_K[0x1c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 28-31 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&SHA256_K[0x20])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 32-35 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&SHA256_K[0x24])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 36-39 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&SHA256_K[0x28])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 40-43 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&SHA256_K[0x2c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 44-47 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&SHA256_K[0x30])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 48-51 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&SHA256_K[0x34])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 52-55 + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&SHA256_K[0x38])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Rounds 56-59 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&SHA256_K[0x3c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 60-63 + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Add back to state + STATE0 = vaddq_u32(STATE0, ABEF_SAVE); + STATE1 = vaddq_u32(STATE1, CDGH_SAVE); + + data += SHA256::BLOCKSIZE/sizeof(word32); + length -= SHA256::BLOCKSIZE; + } + + // Save state + vst1q_u32(&state[0], STATE0); + vst1q_u32(&state[4], STATE1); +} +#endif // CRYPTOPP_ARM_SHA2_AVAILABLE + +/////////////////////////////////////////////////////////// +// end of Walton, Schneiders, O'Rourke and Hovsmith code // +/////////////////////////////////////////////////////////// + +// ***************** Power8 SHA ******************** + +////////////////////////////////////////////////// +// start Gustavo, Serra, Scalet and Walton code // +////////////////////////////////////////////////// + +#if CRYPTOPP_POWER8_SHA_AVAILABLE + +// Indexes into the S[] array +enum {A=0, B=1, C, D, E, F, G, H}; + +inline +uint32x4_p VecLoad32(const word32* data, int offset) +{ +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12}; + const uint32x4_p val = VecLoad(offset, data); + return (uint32x4_p)VecPermute(val, val, mask); +#else + return VecLoad(offset, data); +#endif +} + +template inline +void VecStore32(const T data, word32 dest[4]) +{ + VecStore(data, dest); +} + +inline +uint32x4_p VectorCh(const uint32x4_p x, const uint32x4_p y, const uint32x4_p z) +{ + // The trick below is due to Andy Polyakov and Jack Lloyd + return vec_sel(z,y,x); +} + +inline +uint32x4_p VectorMaj(const uint32x4_p x, const uint32x4_p y, const uint32x4_p z) +{ + // The trick below is due to Andy Polyakov and Jack Lloyd + return vec_sel(y, z, VecXor(x, y)); +} + +inline +uint32x4_p Vector_sigma0(const uint32x4_p val) +{ + return VecSHA256<0,0>(val); +} + +inline +uint32x4_p Vector_sigma1(const uint32x4_p val) +{ + return VecSHA256<0,0xf>(val); +} + +inline +uint32x4_p VectorSigma0(const uint32x4_p val) +{ + return VecSHA256<1,0>(val); +} + +inline +uint32x4_p VectorSigma1(const uint32x4_p val) +{ + return VecSHA256<1,0xf>(val); +} + +inline +uint32x4_p VectorPack(const uint32x4_p a, const uint32x4_p b, + const uint32x4_p c, const uint32x4_p d) +{ + const uint8x16_p m1 = {0,1,2,3, 16,17,18,19, 0,0,0,0, 0,0,0,0}; + const uint8x16_p m2 = {0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; + return VecPermute(VecPermute(a,b,m1), VecPermute(c,d,m1), m2); +} + +template inline +void SHA256_ROUND1(uint32x4_p W[16], uint32x4_p S[8], const uint32x4_p K, const uint32x4_p M) +{ + uint32x4_p T1, T2; + + W[R] = M; + T1 = S[H] + VectorSigma1(S[E]) + VectorCh(S[E],S[F],S[G]) + K + M; + T2 = VectorSigma0(S[A]) + VectorMaj(S[A],S[B],S[C]); + + S[H] = S[G]; S[G] = S[F]; S[F] = S[E]; + S[E] = S[D] + T1; + S[D] = S[C]; S[C] = S[B]; S[B] = S[A]; + S[A] = T1 + T2; +} + +template inline +void SHA256_ROUND2(uint32x4_p W[16], uint32x4_p S[8], const uint32x4_p K) +{ + // Indexes into the W[] array + enum {IDX0=(R+0)&0xf, IDX1=(R+1)&0xf, IDX9=(R+9)&0xf, IDX14=(R+14)&0xf}; + + const uint32x4_p s0 = Vector_sigma0(W[IDX1]); + const uint32x4_p s1 = Vector_sigma1(W[IDX14]); + + uint32x4_p T1 = (W[IDX0] += s0 + s1 + W[IDX9]); + T1 += S[H] + VectorSigma1(S[E]) + VectorCh(S[E],S[F],S[G]) + K; + uint32x4_p T2 = VectorSigma0(S[A]) + VectorMaj(S[A],S[B],S[C]); + + S[H] = S[G]; S[G] = S[F]; S[F] = S[E]; + S[E] = S[D] + T1; + S[D] = S[C]; S[C] = S[B]; S[B] = S[A]; + S[A] = T1 + T2; +} + +void SHA256_HashMultipleBlocks_POWER8(word32 *state, const word32 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA256::BLOCKSIZE); + CRYPTOPP_UNUSED(order); + + const uint32_t* k = reinterpret_cast(SHA256_K); + const uint32_t* m = reinterpret_cast(data); + + uint32x4_p abcd = VecLoad(state+0); + uint32x4_p efgh = VecLoad(state+4); + uint32x4_p W[16], S[8], vm, vk; + + size_t blocks = length / SHA256::BLOCKSIZE; + while (blocks--) + { + unsigned int offset=0; + + S[A] = abcd; S[E] = efgh; + S[B] = VecShiftLeftOctet<4>(S[A]); + S[F] = VecShiftLeftOctet<4>(S[E]); + S[C] = VecShiftLeftOctet<4>(S[B]); + S[G] = VecShiftLeftOctet<4>(S[F]); + S[D] = VecShiftLeftOctet<4>(S[C]); + S[H] = VecShiftLeftOctet<4>(S[G]); + + // Rounds 0-16 + vk = VecLoad(offset, k); + vm = VecLoad32(m, offset); + SHA256_ROUND1<0>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<1>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<2>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<3>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad32(m, offset); + SHA256_ROUND1<4>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<5>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<6>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<7>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad32(m, offset); + SHA256_ROUND1<8>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<9>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<10>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<11>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad32(m, offset); + SHA256_ROUND1<12>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<13>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<14>(W,S, vk,vm); + + vk = VecShiftLeftOctet<4>(vk); + vm = VecShiftLeftOctet<4>(vm); + SHA256_ROUND1<15>(W,S, vk,vm); + + m += 16; // 32-bit words, not bytes + + // Rounds 16-64 + for (unsigned int i=16; i<64; i+=16) + { + vk = VecLoad(offset, k); + SHA256_ROUND2<0>(W,S, vk); + SHA256_ROUND2<1>(W,S, VecShiftLeftOctet<4>(vk)); + SHA256_ROUND2<2>(W,S, VecShiftLeftOctet<8>(vk)); + SHA256_ROUND2<3>(W,S, VecShiftLeftOctet<12>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA256_ROUND2<4>(W,S, vk); + SHA256_ROUND2<5>(W,S, VecShiftLeftOctet<4>(vk)); + SHA256_ROUND2<6>(W,S, VecShiftLeftOctet<8>(vk)); + SHA256_ROUND2<7>(W,S, VecShiftLeftOctet<12>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA256_ROUND2<8>(W,S, vk); + SHA256_ROUND2<9>(W,S, VecShiftLeftOctet<4>(vk)); + SHA256_ROUND2<10>(W,S, VecShiftLeftOctet<8>(vk)); + SHA256_ROUND2<11>(W,S, VecShiftLeftOctet<12>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA256_ROUND2<12>(W,S, vk); + SHA256_ROUND2<13>(W,S, VecShiftLeftOctet<4>(vk)); + SHA256_ROUND2<14>(W,S, VecShiftLeftOctet<8>(vk)); + SHA256_ROUND2<15>(W,S, VecShiftLeftOctet<12>(vk)); + offset+=16; + } + + abcd += VectorPack(S[A],S[B],S[C],S[D]); + efgh += VectorPack(S[E],S[F],S[G],S[H]); + } + + VecStore32(abcd, state+0); + VecStore32(efgh, state+4); +} + +inline +void VecStore64(const uint64x2_p val, word64* data) +{ + VecStore(val, data); +} + +inline +uint64x2_p VecLoad64(const word64* data, int offset) +{ +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return VecPermute(VecLoad(offset, data), mask); +#else + return VecLoad(offset, data); +#endif +} + +inline +uint64x2_p VectorCh(const uint64x2_p x, const uint64x2_p y, const uint64x2_p z) +{ + // The trick below is due to Andy Polyakov and Jack Lloyd + return vec_sel(z,y,x); +} + +inline +uint64x2_p VectorMaj(const uint64x2_p x, const uint64x2_p y, const uint64x2_p z) +{ + // The trick below is due to Andy Polyakov and Jack Lloyd + return vec_sel(y, z, VecXor(x, y)); +} + +inline +uint64x2_p Vector_sigma0(const uint64x2_p val) +{ + return VecSHA512<0,0>(val); +} + +inline +uint64x2_p Vector_sigma1(const uint64x2_p val) +{ + return VecSHA512<0,0xf>(val); +} + +inline +uint64x2_p VectorSigma0(const uint64x2_p val) +{ + return VecSHA512<1,0>(val); +} + +inline +uint64x2_p VectorSigma1(const uint64x2_p val) +{ + return VecSHA512<1,0xf>(val); +} + +inline +uint64x2_p VectorPack(const uint64x2_p x, const uint64x2_p y) +{ + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 16,17,18,19, 20,21,22,23}; + return VecPermute(x,y,m); +} + +template inline +void SHA512_ROUND1(uint64x2_p W[16], uint64x2_p S[8], const uint64x2_p K, const uint64x2_p M) +{ + uint64x2_p T1, T2; + + W[R] = M; + T1 = S[H] + VectorSigma1(S[E]) + VectorCh(S[E],S[F],S[G]) + K + M; + T2 = VectorSigma0(S[A]) + VectorMaj(S[A],S[B],S[C]); + + S[H] = S[G]; S[G] = S[F]; S[F] = S[E]; + S[E] = S[D] + T1; + S[D] = S[C]; S[C] = S[B]; S[B] = S[A]; + S[A] = T1 + T2; +} + +template inline +void SHA512_ROUND2(uint64x2_p W[16], uint64x2_p S[8], const uint64x2_p K) +{ + // Indexes into the W[] array + enum {IDX0=(R+0)&0xf, IDX1=(R+1)&0xf, IDX9=(R+9)&0xf, IDX14=(R+14)&0xf}; + + const uint64x2_p s0 = Vector_sigma0(W[IDX1]); + const uint64x2_p s1 = Vector_sigma1(W[IDX14]); + + uint64x2_p T1 = (W[IDX0] += s0 + s1 + W[IDX9]); + T1 += S[H] + VectorSigma1(S[E]) + VectorCh(S[E],S[F],S[G]) + K; + uint64x2_p T2 = VectorSigma0(S[A]) + VectorMaj(S[A],S[B],S[C]); + + S[H] = S[G]; S[G] = S[F]; S[F] = S[E]; + S[E] = S[D] + T1; + S[D] = S[C]; S[C] = S[B]; S[B] = S[A]; + S[A] = T1 + T2; +} + +void SHA512_HashMultipleBlocks_POWER8(word64 *state, const word64 *data, size_t length, ByteOrder order) +{ + CRYPTOPP_ASSERT(state); CRYPTOPP_ASSERT(data); + CRYPTOPP_ASSERT(length >= SHA512::BLOCKSIZE); + CRYPTOPP_UNUSED(order); + + const uint64_t* k = reinterpret_cast(SHA512_K); + const uint64_t* m = reinterpret_cast(data); + + uint64x2_p ab = VecLoad(state+0); + uint64x2_p cd = VecLoad(state+2); + uint64x2_p ef = VecLoad(state+4); + uint64x2_p gh = VecLoad(state+6); + uint64x2_p W[16], S[8], vm, vk; + + size_t blocks = length / SHA512::BLOCKSIZE; + while (blocks--) + { + unsigned int offset=0; + + S[A] = ab; S[C] = cd; + S[E] = ef; S[G] = gh; + S[B] = VecShiftLeftOctet<8>(S[A]); + S[D] = VecShiftLeftOctet<8>(S[C]); + S[F] = VecShiftLeftOctet<8>(S[E]); + S[H] = VecShiftLeftOctet<8>(S[G]); + + // Rounds 0-16 + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<0>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<1>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<2>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<3>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<4>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<5>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<6>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<7>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<8>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<9>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<10>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<11>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<12>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<13>(W,S, vk,vm); + + vk = VecLoad(offset, k); + vm = VecLoad64(m, offset); + SHA512_ROUND1<14>(W,S, vk,vm); + offset+=16; + + vk = VecShiftLeftOctet<8>(vk); + vm = VecShiftLeftOctet<8>(vm); + SHA512_ROUND1<15>(W,S, vk,vm); + + m += 16; // 64-bit words, not bytes + + // Rounds 16-80 + for (unsigned int i=16; i<80; i+=16) + { + vk = VecLoad(offset, k); + SHA512_ROUND2<0>(W,S, vk); + SHA512_ROUND2<1>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<2>(W,S, vk); + SHA512_ROUND2<3>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<4>(W,S, vk); + SHA512_ROUND2<5>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<6>(W,S, vk); + SHA512_ROUND2<7>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<8>(W,S, vk); + SHA512_ROUND2<9>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<10>(W,S, vk); + SHA512_ROUND2<11>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<12>(W,S, vk); + SHA512_ROUND2<13>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + + vk = VecLoad(offset, k); + SHA512_ROUND2<14>(W,S, vk); + SHA512_ROUND2<15>(W,S, VecShiftLeftOctet<8>(vk)); + offset+=16; + } + + ab += VectorPack(S[A],S[B]); + cd += VectorPack(S[C],S[D]); + ef += VectorPack(S[E],S[F]); + gh += VectorPack(S[G],S[H]); + } + + VecStore64(ab, state+0); + VecStore64(cd, state+2); + VecStore64(ef, state+4); + VecStore64(gh, state+6); +} + +#endif // CRYPTOPP_POWER8_SHA_AVAILABLE + +//////////////////////////////////////////////// +// end Gustavo, Serra, Scalet and Walton code // +//////////////////////////////////////////////// + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/shacal2.cpp b/extension/third_party/cryptopp/shacal2.cpp new file mode 100644 index 00000000..37ba9899 --- /dev/null +++ b/extension/third_party/cryptopp/shacal2.cpp @@ -0,0 +1,172 @@ +// shacal2.cpp - written by Kevin Springle, 2003 +// +// Portions of this code were derived from +// Wei Dai's implementation of SHA-2 +// +// Jack Lloyd and the Botan team allowed Crypto++ to use parts of +// Botan's implementation under the same license as Crypto++ +// is released. The code for SHACAL2_Enc_ProcessAndXorBlock_SHANI +// below is Botan's x86_encrypt_blocks with minor tweaks. Many thanks +// to the Botan team. Also see http://github.com/randombit/botan/. +// +// The original code and all modifications are in the public domain. + +#include "pch.h" +#include "config.h" +#include "shacal2.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +// SHACAL-2 function and round definitions + +#define S0(x) (rotrConstant<2>(x)^rotrConstant<13>(x)^rotrConstant<22>(x)) +#define S1(x) (rotrConstant<6>(x)^rotrConstant<11>(x)^rotrConstant<25>(x)) +#define s0(x) (rotrConstant<7>(x)^rotrConstant<18>(x)^(x>>3)) +#define s1(x) (rotrConstant<17>(x)^rotrConstant<19>(x)^(x>>10)) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +/* R is the SHA-256 round function. */ +/* This macro increments the k argument as a side effect. */ +#define R(a,b,c,d,e,f,g,h,k) \ + h+=S1(e)+Ch(e,f,g)+*k++;d+=h;h+=S0(a)+Maj(a,b,c); + +/* P is the inverse of the SHA-256 round function. */ +/* This macro decrements the k argument as a side effect. */ +#define P(a,b,c,d,e,f,g,h,k) \ + h-=S0(a)+Maj(a,b,c);d-=h;h-=S1(e)+Ch(e,f,g)+*--k; + +#if CRYPTOPP_SHANI_AVAILABLE +extern void SHACAL2_Enc_ProcessAndXorBlock_SHANI(const word32* subKeys, + const byte *inBlock, const byte *xorBlock, byte *outBlock); +#endif + +std::string SHACAL2::Base::AlgorithmProvider() const +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + return "SHANI"; +#endif + return "C++"; +} + +void SHACAL2::Base::UncheckedSetKey(const byte *userKey, unsigned int keylen, const NameValuePairs &) +{ + AssertValidKeyLength(keylen); + + word32 *rk = m_key; + unsigned int i; + + // 32-bit GCC 5.4 hack... m_key.size() returns 0. Note: this surfaced after changing + // m_key to FixedSizeAlignedSecBlock at commit 1ab1e08ac5b5a0d63374de0c. + GetUserKey(BIG_ENDIAN_ORDER, rk, 64, userKey, keylen); + for (i = 0; i < 48; i++, rk++) + { + rk[16] = rk[0] + s0(rk[1]) + rk[9] + s1(rk[14]); + rk[0] += K[i]; + } + for (i = 48; i < 64; i++, rk++) + { + rk[0] += K[i]; + } +} + +typedef BlockGetAndPut Block; + +void SHACAL2::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (HasSHA()) + { + SHACAL2_Enc_ProcessAndXorBlock_SHANI(m_key, inBlock, xorBlock, outBlock); + return; + } +#endif + + word32 a, b, c, d, e, f, g, h; + const word32 *rk = m_key; + + /* + * map byte array block to cipher state: + */ + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + + // Perform SHA-256 transformation. + + /* 64 operations, partially loop unrolled */ + for (unsigned int j=0; j<64; j+=8) + { + R(a,b,c,d,e,f,g,h,rk); + R(h,a,b,c,d,e,f,g,rk); + R(g,h,a,b,c,d,e,f,rk); + R(f,g,h,a,b,c,d,e,rk); + R(e,f,g,h,a,b,c,d,rk); + R(d,e,f,g,h,a,b,c,rk); + R(c,d,e,f,g,h,a,b,rk); + R(b,c,d,e,f,g,h,a,rk); + } + + /* + * map cipher state to byte array block: + */ + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +void SHACAL2::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 a, b, c, d, e, f, g, h; + const word32 *rk = m_key + 64; + + /* + * map byte array block to cipher state: + */ + Block::Get(inBlock)(a)(b)(c)(d)(e)(f)(g)(h); + + // Perform inverse SHA-256 transformation. + + /* 64 operations, partially loop unrolled */ + for (unsigned int j=0; j<64; j+=8) + { + P(b,c,d,e,f,g,h,a,rk); + P(c,d,e,f,g,h,a,b,rk); + P(d,e,f,g,h,a,b,c,rk); + P(e,f,g,h,a,b,c,d,rk); + P(f,g,h,a,b,c,d,e,rk); + P(g,h,a,b,c,d,e,f,rk); + P(h,a,b,c,d,e,f,g,rk); + P(a,b,c,d,e,f,g,h,rk); + } + + /* + * map cipher state to byte array block: + */ + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d)(e)(f)(g)(h); +} + +// The SHACAL-2 round constants are identical to the SHA-256 round constants. +const word32 SHACAL2::Base::K[64] = +{ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/shacal2.h b/extension/third_party/cryptopp/shacal2.h new file mode 100644 index 00000000..ca0c482c --- /dev/null +++ b/extension/third_party/cryptopp/shacal2.h @@ -0,0 +1,66 @@ +// shacal.h - originally written and placed in the public domain by Wei Dai + +/// \file shacal2.h +/// \brief Classes for the SHACAL-2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 + +#ifndef CRYPTOPP_SHACAL2_H +#define CRYPTOPP_SHACAL2_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHACAL2 block cipher information +struct SHACAL2_Info : public FixedBlockSize<32>, public VariableKeyLength<16, 16, 64> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHACAL-2";} +}; + +/// \brief SHACAL2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 +/// \sa SHACAL-2 +class SHACAL2 : public SHACAL2_Info, public BlockCipherDocumentation +{ + /// \brief SHACAL2 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + std::string AlgorithmProvider() const; + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeAlignedSecBlock m_key; + + static const word32 K[64]; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Encryption transformation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Decryption transformation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHACAL2::Encryption SHACAL2Encryption; +typedef SHACAL2::Decryption SHACAL2Decryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/shacal2_simd.cpp b/extension/third_party/cryptopp/shacal2_simd.cpp new file mode 100644 index 00000000..45f38e48 --- /dev/null +++ b/extension/third_party/cryptopp/shacal2_simd.cpp @@ -0,0 +1,98 @@ +// shacla2_simd.cpp - written and placed in the public domain by +// Jeffrey Walton and Jack Lloyd +// +// Jack Lloyd and the Botan team allowed Crypto++ to use parts of +// Botan's implementation under the same license as Crypto++ +// is released. The code for SHACAL2_Enc_ProcessAndXorBlock_SHANI +// below is Botan's x86_encrypt_blocks with minor tweaks. Many thanks +// to the Botan team. Also see http://github.com/randombit/botan/. +// +// This source file uses intrinsics to gain access to SHA-NI and +// ARMv8a SHA instructions. A separate source file is needed because +// additional CXXFLAGS are required to enable the appropriate instruction +// sets in some build configurations. + +#include "pch.h" +#include "config.h" +#include "sha.h" +#include "misc.h" + +#if (CRYPTOPP_SHANI_AVAILABLE) +# include +# include +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) + +// Squash MS LNK4221 and libtool warnings +extern const char SHACAL2_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_SHANI_AVAILABLE +void SHACAL2_Enc_ProcessAndXorBlock_SHANI(const word32* subKeys, const byte *inBlock, const byte *xorBlock, byte *outBlock) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlock); + CRYPTOPP_ASSERT(outBlock); + + const __m128i MASK1 = _mm_set_epi8(8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7); + const __m128i MASK2 = _mm_set_epi8(0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15); + + __m128i B0 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(inBlock + 0)), MASK1); + __m128i B1 = _mm_shuffle_epi8(_mm_loadu_si128(CONST_M128_CAST(inBlock + 16)), MASK2); + + __m128i TMP = _mm_alignr_epi8(B0, B1, 8); + B1 = _mm_blend_epi16(B1, B0, 0xF0); + B0 = TMP; + +#if 0 + // SSE2 + SSSE3, but 0.2 cpb slower on a Celeraon J3455 + const __m128i MASK1 = _mm_set_epi8(8,9,10,11, 12,13,14,15, 0,1,2,3, 4,5,6,7); + const __m128i MASK2 = _mm_set_epi8(0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15); + + __m128i B0 = _mm_loadu_si128(CONST_M128_CAST(inBlock + 0)); + __m128i B1 = _mm_loadu_si128(CONST_M128_CAST(inBlock + 16)); + + __m128i TMP = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0, B1), MASK2); + B1 = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0, B1), MASK2); + B0 = TMP; +#endif + + const byte* keys = reinterpret_cast(subKeys); + for (size_t i = 0; i != 8; ++i) + { + const __m128i RK0 = _mm_load_si128(CONST_M128_CAST(keys + 32*i)); + const __m128i RK2 = _mm_load_si128(CONST_M128_CAST(keys + 32*i+16)); + const __m128i RK1 = _mm_srli_si128(RK0, 8); + const __m128i RK3 = _mm_srli_si128(RK2, 8); + + B1 = _mm_sha256rnds2_epu32(B1, B0, RK0); + B0 = _mm_sha256rnds2_epu32(B0, B1, RK1); + B1 = _mm_sha256rnds2_epu32(B1, B0, RK2); + B0 = _mm_sha256rnds2_epu32(B0, B1, RK3); + } + + TMP = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0, B1), MASK1); + B1 = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0, B1), MASK1); + B0 = TMP; + + if (xorBlock) + { + _mm_storeu_si128(M128_CAST(outBlock + 0), + _mm_xor_si128(B0, _mm_loadu_si128(CONST_M128_CAST(xorBlock + 0)))); + + _mm_storeu_si128(M128_CAST(outBlock + 16), + _mm_xor_si128(B1, _mm_loadu_si128(CONST_M128_CAST(xorBlock + 16)))); + } + else + { + _mm_storeu_si128(M128_CAST(outBlock + 0), B0); + _mm_storeu_si128(M128_CAST(outBlock + 16), B1); + } +} +#endif + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/shake.cpp b/extension/third_party/cryptopp/shake.cpp new file mode 100644 index 00000000..65e08235 --- /dev/null +++ b/extension/third_party/cryptopp/shake.cpp @@ -0,0 +1,85 @@ +// shake.cpp - modified by Wei Dai from Ronny Van Keer's public domain +// sha3-simple.c. All modifications here are placed in the +// public domain by Wei Dai. +// Keccack core function moved to keccakc.cpp in AUG 2018 +// by Jeffrey Walton. Separating the core file allows both +// SHA3 and Keccack to share the core implementation. + +/* +The SHAKE sponge function, designed by Guido Bertoni, Joan Daemen, +Michael Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "pch.h" +#include "shake.h" + +NAMESPACE_BEGIN(CryptoPP) + +// The Keccak core function +extern void KeccakF1600(word64 *state); + +void SHAKE::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0)); + if (length == 0) { return; } + + size_t spaceLeft; + while (length >= (spaceLeft = r() - m_counter)) + { + if (spaceLeft) + xorbuf(m_state.BytePtr() + m_counter, input, spaceLeft); + KeccakF1600(m_state); + input += spaceLeft; + length -= spaceLeft; + m_counter = 0; + } + + if (length) + xorbuf(m_state.BytePtr() + m_counter, input, length); + m_counter += (unsigned int)length; +} + +void SHAKE::Restart() +{ + memset(m_state, 0, m_state.SizeInBytes()); + m_counter = 0; +} + +void SHAKE::ThrowIfInvalidTruncatedSize(size_t size) const +{ + if (size > UINT_MAX) + throw InvalidArgument(std::string("HashTransformation: can't truncate a ") + + IntToString(UINT_MAX) + " byte digest to " + IntToString(size) + " bytes"); +} + +void SHAKE::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + ThrowIfInvalidTruncatedSize(size); + + m_state.BytePtr()[m_counter] ^= 0x1F; + m_state.BytePtr()[r()-1] ^= 0x80; + + // FIPS 202, Algorithm 8, pp 18-19. + while (size > 0) + { + KeccakF1600(m_state); + + const size_t segmentLen = STDMIN(size, (size_t)BlockSize()); + std::memcpy(hash, m_state, segmentLen); + + hash += segmentLen; + size -= segmentLen; + } + + Restart(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/shake.h b/extension/third_party/cryptopp/shake.h new file mode 100644 index 00000000..0eaab43b --- /dev/null +++ b/extension/third_party/cryptopp/shake.h @@ -0,0 +1,161 @@ +// shake.h - written and placed in the public domain by Jeffrey Walton + +/// \file shake.h +/// \brief Classes for SHAKE message digests +/// \details The library provides byte oriented SHAKE128 and SHAKE256 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits the output +/// size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE128, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 + +#ifndef CRYPTOPP_SHAKE_H +#define CRYPTOPP_SHAKE_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHAKE message digest base class +/// \details SHAKE is the base class for SHAKE128 and SHAKE258. +/// Library users should instantiate a derived class, and only use SHAKE +/// as a base class reference or pointer. +/// \sa Keccak, SHA3, SHAKE128, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE : public HashTransformation +{ +protected: + /// \brief Construct a SHAKE + /// \param digestSize the digest size, in bytes + /// \details SHAKE is the base class for SHAKE128 and SHAKE256. + /// Library users should instantiate a derived class, and only use SHAKE + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 8.1 + SHAKE(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + // SHAKE-128 and SHAKE-256 effectively allow unlimited + // output length. However, we use an unsigned int so + // we are limited in practice to UINT_MAX. + void ThrowIfInvalidTruncatedSize(size_t size) const; + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief SHAKE message digest template +/// \tparam T_Strength the strength of the digest +/// \since Crypto++ 8.1 +template +class SHAKE_Final : public SHAKE +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_Strength == 128 ? 32 : 64)); + CRYPTOPP_CONSTANT(BLOCKSIZE = (T_Strength == 128 ? 1344/8 : 1088/8)); + static std::string StaticAlgorithmName() + { return "SHAKE-" + IntToString(T_Strength); } + + /// \brief Construct a SHAKE-X message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algoirthm uses + /// output size as a parameter to the hash function. + SHAKE_Final(unsigned int outputSize=DIGESTSIZE) : SHAKE(outputSize) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// to block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief SHAKE128 message digest +/// \details The library provides byte oriented SHAKE128 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits +/// the output size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE128 : public SHAKE_Final<128> +{ +public: + /// \brief Construct a SHAKE128 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algoirthm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE128() {} + + /// \brief Construct a SHAKE128 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algoirthm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE128(unsigned int outputSize) : SHAKE_Final<128>(outputSize) {} +}; + +/// \brief SHAKE256 message digest +/// \details The library provides byte oriented SHAKE256 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits +/// the output size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE128, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE256 : public SHAKE_Final<256> +{ +public: + /// \brief Construct a SHAKE256 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algoirthm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE256() {} + + /// \brief Construct a SHAKE256 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algoirthm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE256(unsigned int outputSize) : SHAKE_Final<256>(outputSize) {} +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/shark.cpp b/extension/third_party/cryptopp/shark.cpp new file mode 100644 index 00000000..6e3b8da3 --- /dev/null +++ b/extension/third_party/cryptopp/shark.cpp @@ -0,0 +1,163 @@ +// shark.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "shark.h" +#include "misc.h" +#include "modes.h" +#include "gf256.h" + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +static word64 SHARKTransform(word64 a) +{ + static const byte iG[8][8] = { + 0xe7, 0x30, 0x90, 0x85, 0xd0, 0x4b, 0x91, 0x41, + 0x53, 0x95, 0x9b, 0xa5, 0x96, 0xbc, 0xa1, 0x68, + 0x02, 0x45, 0xf7, 0x65, 0x5c, 0x1f, 0xb6, 0x52, + 0xa2, 0xca, 0x22, 0x94, 0x44, 0x63, 0x2a, 0xa2, + 0xfc, 0x67, 0x8e, 0x10, 0x29, 0x75, 0x85, 0x71, + 0x24, 0x45, 0xa2, 0xcf, 0x2f, 0x22, 0xc1, 0x0e, + 0xa1, 0xf1, 0x71, 0x40, 0x91, 0x27, 0x18, 0xa5, + 0x56, 0xf4, 0xaf, 0x32, 0xd2, 0xa4, 0xdc, 0x71, + }; + + word64 result=0; + GF256 gf256(0xf5); + for (unsigned int i=0; i<8; i++) + for(unsigned int j=0; j<8; j++) + result ^= word64(gf256.Multiply(iG[i][j], GF256::Element(a>>(56-8*j)))) << (56-8*i); + return result; +} + +void SHARK::Base::UncheckedSetKey(const byte *key, unsigned int keyLen, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(keyLen); + + m_rounds = GetRoundsAndThrowIfInvalid(params, this); + m_roundKeys.New(m_rounds+1); + + // concatenate key enought times to fill a + for (unsigned int i=0; i<(m_rounds+1)*8; i++) + ((byte *)m_roundKeys.begin())[i] = key[i%keyLen]; + + SHARK::Encryption e; + e.InitForKeySetup(); + byte IV[8] = {0,0,0,0,0,0,0,0}; + CFB_Mode_ExternalCipher::Encryption cfb(e, IV); + + cfb.ProcessString((byte *)m_roundKeys.begin(), (m_rounds+1)*8); + + ConditionalByteReverse(BIG_ENDIAN_ORDER, m_roundKeys.begin(), m_roundKeys.begin(), (m_rounds+1)*8); + + m_roundKeys[m_rounds] = SHARKTransform(m_roundKeys[m_rounds]); + + if (!IsForwardTransformation()) + { + unsigned int i; + + // transform encryption round keys into decryption round keys + for (i=0; i())); + word64 tmp = *(word64 *)(void *)inBlock ^ m_roundKeys[0]; + + ByteOrder order = GetNativeByteOrder(); + tmp = cbox[0][GetByte(order, tmp, 0)] ^ cbox[1][GetByte(order, tmp, 1)] + ^ cbox[2][GetByte(order, tmp, 2)] ^ cbox[3][GetByte(order, tmp, 3)] + ^ cbox[4][GetByte(order, tmp, 4)] ^ cbox[5][GetByte(order, tmp, 5)] + ^ cbox[6][GetByte(order, tmp, 6)] ^ cbox[7][GetByte(order, tmp, 7)] + ^ m_roundKeys[1]; + + for(unsigned int i=2; i(xorBlock, outBlock) + (sbox[GETBYTE(tmp, 7)]) + (sbox[GETBYTE(tmp, 6)]) + (sbox[GETBYTE(tmp, 5)]) + (sbox[GETBYTE(tmp, 4)]) + (sbox[GETBYTE(tmp, 3)]) + (sbox[GETBYTE(tmp, 2)]) + (sbox[GETBYTE(tmp, 1)]) + (sbox[GETBYTE(tmp, 0)]); + + CRYPTOPP_ASSERT(IsAlignedOn(outBlock,GetAlignmentOf())); + *(word64 *)(void *)outBlock ^= m_roundKeys[m_rounds]; +} + +void SHARK::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + CRYPTOPP_ASSERT(IsAlignedOn(inBlock,GetAlignmentOf())); + word64 tmp = *(word64 *)(void *)inBlock ^ m_roundKeys[0]; + + ByteOrder order = GetNativeByteOrder(); + tmp = cbox[0][GetByte(order, tmp, 0)] ^ cbox[1][GetByte(order, tmp, 1)] + ^ cbox[2][GetByte(order, tmp, 2)] ^ cbox[3][GetByte(order, tmp, 3)] + ^ cbox[4][GetByte(order, tmp, 4)] ^ cbox[5][GetByte(order, tmp, 5)] + ^ cbox[6][GetByte(order, tmp, 6)] ^ cbox[7][GetByte(order, tmp, 7)] + ^ m_roundKeys[1]; + + for(unsigned int i=2; i(xorBlock, outBlock) + (sbox[GETBYTE(tmp, 7)]) + (sbox[GETBYTE(tmp, 6)]) + (sbox[GETBYTE(tmp, 5)]) + (sbox[GETBYTE(tmp, 4)]) + (sbox[GETBYTE(tmp, 3)]) + (sbox[GETBYTE(tmp, 2)]) + (sbox[GETBYTE(tmp, 1)]) + (sbox[GETBYTE(tmp, 0)]); + + CRYPTOPP_ASSERT(IsAlignedOn(outBlock,GetAlignmentOf())); + *(word64 *)(void *)outBlock ^= m_roundKeys[m_rounds]; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/shark.h b/extension/third_party/cryptopp/shark.h new file mode 100644 index 00000000..09459adc --- /dev/null +++ b/extension/third_party/cryptopp/shark.h @@ -0,0 +1,77 @@ +// shark.h - originally written and placed in the public domain by Wei Dai + +/// \file shark.h +/// \brief Classes for the SHARK block cipher +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_SHARK_H +#define CRYPTOPP_SHARK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHARK block cipher information +/// \since Crypto++ 2.1 +struct SHARK_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<6, 2> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHARK-E";} +}; + +/// \brief SHARK block cipher +/// SHARK-E +/// \since Crypto++ 2.1 +class SHARK : public SHARK_Info, public BlockCipherDocumentation +{ + /// \brief SHARK block cipher default operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶m); + + protected: + unsigned int m_rounds; + SecBlock m_roundKeys; + }; + + /// \brief SHARK block cipher encryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + // used by Base to do key setup + void InitForKeySetup(); + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + + /// \brief SHARK block cipher decryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHARK::Encryption SHARKEncryption; +typedef SHARK::Decryption SHARKDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/sharkbox.cpp b/extension/third_party/cryptopp/sharkbox.cpp new file mode 100644 index 00000000..1a50c171 --- /dev/null +++ b/extension/third_party/cryptopp/sharkbox.cpp @@ -0,0 +1,4166 @@ +#include "pch.h" +#include "shark.h" + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +const byte SHARK::Enc::sbox[256] = { +177, 206, 195, 149, 90, 173, 231, 2, 77, 68, 251, 145, 12, 135, 161, 80, +203, 103, 84, 221, 70, 143, 225, 78, 240, 253, 252, 235, 249, 196, 26, 110, + 94, 245, 204, 141, 28, 86, 67, 254, 7, 97, 248, 117, 89, 255, 3, 34, +138, 209, 19, 238, 136, 0, 14, 52, 21, 128, 148, 227, 237, 181, 83, 35, + 75, 71, 23, 167, 144, 53, 171, 216, 184, 223, 79, 87, 154, 146, 219, 27, + 60, 200, 153, 4, 142, 224, 215, 125, 133, 187, 64, 44, 58, 69, 241, 66, +101, 32, 65, 24, 114, 37, 147, 112, 54, 5, 242, 11, 163, 121, 236, 8, + 39, 49, 50, 182, 124, 176, 10, 115, 91, 123, 183, 129, 210, 13, 106, 38, +158, 88, 156, 131, 116, 179, 172, 48, 122, 105, 119, 15, 174, 33, 222, 208, + 46, 151, 16, 164, 152, 168, 212, 104, 45, 98, 41, 109, 22, 73, 118, 199, +232, 193, 150, 55, 229, 202, 244, 233, 99, 18, 194, 166, 20, 188, 211, 40, +175, 47, 230, 36, 82, 198, 160, 9, 189, 140, 207, 93, 17, 95, 1, 197, +159, 61, 162, 155, 201, 59, 190, 81, 25, 31, 63, 92, 178, 239, 74, 205, +191, 186, 111, 100, 217, 243, 62, 180, 170, 220, 213, 6, 192, 126, 246, 102, +108, 132, 113, 56, 185, 29, 127, 157, 72, 139, 42, 218, 165, 51, 130, 57, +214, 120, 134, 250, 228, 43, 169, 30, 137, 96, 107, 234, 85, 76, 247, 226, +}; + +const byte SHARK::Dec::sbox[256] = { + 53, 190, 7, 46, 83, 105, 219, 40, 111, 183, 118, 107, 12, 125, 54, 139, +146, 188, 169, 50, 172, 56, 156, 66, 99, 200, 30, 79, 36, 229, 247, 201, + 97, 141, 47, 63, 179, 101, 127, 112, 175, 154, 234, 245, 91, 152, 144, 177, +135, 113, 114, 237, 55, 69, 104, 163, 227, 239, 92, 197, 80, 193, 214, 202, + 90, 98, 95, 38, 9, 93, 20, 65, 232, 157, 206, 64, 253, 8, 23, 74, + 15, 199, 180, 62, 18, 252, 37, 75, 129, 44, 4, 120, 203, 187, 32, 189, +249, 41, 153, 168, 211, 96, 223, 17, 151, 137, 126, 250, 224, 155, 31, 210, +103, 226, 100, 119, 132, 43, 158, 138, 241, 109, 136, 121, 116, 87, 221, 230, + 57, 123, 238, 131, 225, 88, 242, 13, 52, 248, 48, 233, 185, 35, 84, 21, + 68, 11, 77, 102, 58, 3, 162, 145, 148, 82, 76, 195, 130, 231, 128, 192, +182, 14, 194, 108, 147, 236, 171, 67, 149, 246, 216, 70, 134, 5, 140, 176, +117, 0, 204, 133, 215, 61, 115, 122, 72, 228, 209, 89, 173, 184, 198, 208, +220, 161, 170, 2, 29, 191, 181, 159, 81, 196, 165, 16, 34, 207, 1, 186, +143, 49, 124, 174, 150, 218, 240, 86, 71, 212, 235, 78, 217, 19, 142, 73, + 85, 22, 255, 59, 244, 164, 178, 6, 160, 167, 251, 27, 110, 60, 51, 205, + 24, 94, 106, 213, 166, 33, 222, 254, 42, 28, 243, 10, 26, 25, 39, 45, +}; + +const word64 SHARK::Enc::cbox[8][256] = { +/* box 0 */ +W64LIT(0x060d838f16f3a365), +W64LIT(0xa68857ee5cae56f6), +W64LIT(0xebf516353c2c4d89), +W64LIT(0x652174be88e85bdc), +W64LIT(0x0d4e9a8086c17921), +W64LIT(0x27ba7d33cffa58a1), +W64LIT(0x88d9e104a237b530), +W64LIT(0x693b8755a4fbe816), +W64LIT(0xdac9591826b254a0), +W64LIT(0x45c2e369fb336af3), +W64LIT(0xa96e1fb87b3e4ef4), +W64LIT(0xb7578f1435eb7ef0), +W64LIT(0x839af80b32056f74), +W64LIT(0xae37f55cc71f277a), +W64LIT(0xa4208538fdff37d5), +W64LIT(0x35991e74ad3cdb6f), +W64LIT(0xba191594b32a07d1), +W64LIT(0x5344d1772e572b7b), +W64LIT(0xe7efe5de103ffe43), +W64LIT(0xa3796fdc41de5e5b), +W64LIT(0x2cf9643c5fc882e5), +W64LIT(0xffdbf6fd48196d22), +W64LIT(0x33949dfbbbcf780a), +W64LIT(0x7d15679dd0cec8bd), +W64LIT(0x5f5e229c024498b1), +W64LIT(0x1223634762c683ce), +W64LIT(0xdcc4da973041f7c5), +W64LIT(0x0b43190f9032da44), +W64LIT(0xc05598eddfc5a6e2), +W64LIT(0x9e5fd31a7753f4b8), +W64LIT(0x9afa8243c0f136fe), +W64LIT(0xcc4f6b06f3d61528), +W64LIT(0xdf38612a3bc25c0d), +W64LIT(0x43cf60e6edc0c996), +W64LIT(0xcfb3d0bbf855bee0), +W64LIT(0x96e071a8ece28534), +W64LIT(0x21b7febcd909fbc4), +W64LIT(0x8ed4628bb4c41655), +W64LIT(0x30682646b04cd3c2), +W64LIT(0xb5ff5dc294ba1fd3), +W64LIT(0x75aac52f4b7fb931), +W64LIT(0xe809ad8837afe641), +W64LIT(0x0eb2213d8d42d2e9), +W64LIT(0x9852509561a057dd), +W64LIT(0xaa92a40570bde53c), +W64LIT(0x7b18e412c63d6bd8), +W64LIT(0xa7dc3e85f67c9c1d), +W64LIT(0xd8618bce87e33583), +W64LIT(0xe34ab487a79d3c05), +W64LIT(0x20e397d773db312f), +W64LIT(0x05f138321d7008ad), +W64LIT(0x17d25b757fb68b63), +W64LIT(0x8a7133d20366d413), +W64LIT(0x0000000000000000), +W64LIT(0xeaa17f5e96fe8762), +W64LIT(0xc101f18675176c09), +W64LIT(0xbebc44cd0488c597), +W64LIT(0xdb9d30738c609e4b), +W64LIT(0xabc6cd6eda6f2fd7), +W64LIT(0x5aaf1aae1f34901c), +W64LIT(0xb00e65f089ca177e), +W64LIT(0xd47b7825abf08649), +W64LIT(0x924520f15b404772), +W64LIT(0x1686321ed5644188), +W64LIT(0x618425e73f4a999a), +W64LIT(0xe21eddec0d4ff6ee), +W64LIT(0xd787c398a0732d81), +W64LIT(0x1f6df9c7e407faef), +W64LIT(0x79b036c4676c0afb), +W64LIT(0x0fe6485627901802), +W64LIT(0x9cf701ccd602959b), +W64LIT(0xbfe82da6ae5a0f7c), +W64LIT(0x990639fecb729d36), +W64LIT(0xca42e889e525b64d), +W64LIT(0xb3f2de4d8249bcb6), +W64LIT(0x4033db5be643625e), +W64LIT(0x4167b2304c91a8b5), +W64LIT(0x108bb191c397e2ed), +W64LIT(0x1834132358269361), +W64LIT(0x541d3b93927642f5), +W64LIT(0x90edf227fa112651), +W64LIT(0x1dc52b1145569bcc), +W64LIT(0xe6bb8cb5baed34a8), +W64LIT(0xd276fbaabd03252c), +W64LIT(0x313c4f2d1a9e1929), +W64LIT(0xfd73242be9480c01), +W64LIT(0x9baeeb286a23fc15), +W64LIT(0xc9be5334eea61d85), +W64LIT(0xc70c720963e4cf6c), +W64LIT(0x3eda077b3d0e012b), +W64LIT(0x97b418c346304fdf), +W64LIT(0x32c0f490111db2e1), +W64LIT(0x2ba08ed8e3e9eb6b), +W64LIT(0x8b255ab9a9b41ef8), +W64LIT(0x91b99b4c50c3ecba), +W64LIT(0xfe8f9f96e2cba7c9), +W64LIT(0x3a7f56228aacc36d), +W64LIT(0xb15a0c9b2318dd95), +W64LIT(0x5953a11314b73bd4), +W64LIT(0xf3c10516640adee8), +W64LIT(0xedf895ba2adfeeec), +W64LIT(0xadcb4ee1cc9c8cb2), +W64LIT(0xde6c0841911096e6), +W64LIT(0x84c312ef8e2406fa), +W64LIT(0xa83a76d3d1ec841f), +W64LIT(0x1c91427aef845127), +W64LIT(0x3665a5c9a6bf70a7), +W64LIT(0xf6303d24797ad645), +W64LIT(0xcd1b026d5904dfc3), +W64LIT(0x1bc8a89e53a538a9), +W64LIT(0x7ee9dc20db4d6375), +W64LIT(0x51ec03a18f064a58), +W64LIT(0xc4f0c9b4686764a4), +W64LIT(0xdd90b3fc9a933d2e), +W64LIT(0x7a4c8d796cefa133), +W64LIT(0x73a746a05d8c1a54), +W64LIT(0x0759eae4bc21698e), +W64LIT(0xc8ea3a5f4474d76e), +W64LIT(0x38d784f42bfda24e), +W64LIT(0x231f2c6a78589ae7), +W64LIT(0xc3a92350d4460d2a), +W64LIT(0x72f32fcbf75ed0bf), +W64LIT(0xbd40ff700f0b6e5f), +W64LIT(0x157a89a3dee7ea40), +W64LIT(0x873fa95285a7ad32), +W64LIT(0x4d7d41db60821b7f), +W64LIT(0x1e3990ac4ed53004), +W64LIT(0x0a1770643ae010af), +W64LIT(0x9311499af1928d99), +W64LIT(0x64751dd5223a9137), +W64LIT(0xfa2acecf5569658f), +W64LIT(0x7c410ef67a1c0256), +W64LIT(0x56b5e945332723d6), +W64LIT(0x6f3604dab2084b73), +W64LIT(0xe95dc4e39d7d2caa), +W64LIT(0x13770a2cc8144925), +W64LIT(0xbc14961ba5d9a4b4), +W64LIT(0xb9e5ae29b8a9ac19), +W64LIT(0xf169d7c0c55bbfcb), +W64LIT(0x2446c68ec479f369), +W64LIT(0x806643b63986c4bc), +W64LIT(0x7fbdb54b719fa99e), +W64LIT(0x04a55159b7a2c246), +W64LIT(0xee042e07215c4524), +W64LIT(0x5bfb73c5b5e65af7), +W64LIT(0x0c1af3eb2c13b3ca), +W64LIT(0xa22d06b7eb0c94b0), +W64LIT(0xb8b1c742127b66f2), +W64LIT(0x285c3565e86a40a3), +W64LIT(0x3b2b3f49207e0986), +W64LIT(0x3c72d5ad9c5f6008), +W64LIT(0x770217f9ea2ed812), +W64LIT(0xfc274d40439ac6ea), +W64LIT(0x4fd5930dc1d37a5c), +W64LIT(0x2e51b6eafe99e3c6), +W64LIT(0x6b93558305aa8935), +W64LIT(0x19607a48f2f4598a), +W64LIT(0x08bfa2b29bb1718c), +W64LIT(0x3f8e6e1097dccbc0), +W64LIT(0x3983ed9f812f68a5), +W64LIT(0xac9f278a664e4659), +W64LIT(0x82ce916098d7a59f), +W64LIT(0xc2fd4a3b7e94c7c1), +W64LIT(0x66ddcf03836bf014), +W64LIT(0xe1e2665106cc5d26), +W64LIT(0x74feac44e1ad73da), +W64LIT(0x8d28d936bf47bd9d), +W64LIT(0x62789e5a34c93252), +W64LIT(0x81322add93540e57), +W64LIT(0xcb1681e24ff77ca6), +W64LIT(0x2512afe56eab3982), +W64LIT(0xd18a4017b6808ee4), +W64LIT(0x705bfd1d560fb19c), +W64LIT(0x4b70c2547671b81a), +W64LIT(0x49d81082d720d939), +W64LIT(0xe0b60f3aac1e97cd), +W64LIT(0x4e81fa666b01b0b7), +W64LIT(0x951cca15e7612efc), +W64LIT(0x463e58d4f0b0c13b), +W64LIT(0x632cf7319e1bf8b9), +W64LIT(0x5ca2992109c73379), +W64LIT(0xf764544fd3a81cae), +W64LIT(0x6ac73ce8af7843de), +W64LIT(0x9f0bba71dd813e53), +W64LIT(0x85977b8424f6cc11), +W64LIT(0x5807c878be65f13f), +W64LIT(0x686fee3e0e2922fd), +W64LIT(0x78e45fafcdbec010), +W64LIT(0x6ccabf67b98be0bb), +W64LIT(0x11dfd8fa69452806), +W64LIT(0xcee7b9d05287740b), +W64LIT(0x50b86aca25d480b3), +W64LIT(0x5df6f04aa315f992), +W64LIT(0x5e0a4bf7a896525a), +W64LIT(0x03fcbbbd0b83abc8), +W64LIT(0x8f800be01e16dcbe), +W64LIT(0xd32292c117d1efc7), +W64LIT(0xe5473708b16e9f60), +W64LIT(0x224b4501d28a500c), +W64LIT(0xfb7ea7a4ffbbaf64), +W64LIT(0x3d26bcc6368daae3), +W64LIT(0x866bc0392f7567d9), +W64LIT(0x3731cca20c6dba4c), +W64LIT(0xb603e67f9f39b41b), +W64LIT(0xa1d1bd0ae08f3f78), +W64LIT(0xd935e2a52d31ff68), +W64LIT(0xaf639c376dcded91), +W64LIT(0x0154696baad2caeb), +W64LIT(0xecacfcd1800d2407), +W64LIT(0xf03dbeab6f897520), +W64LIT(0x02a8d2d6a1516123), +W64LIT(0xf498eff2d82bb766), +W64LIT(0x710f9476fcdd7b77), +W64LIT(0xf8821c19f43804ac), +W64LIT(0xf9d675725eeace47), +W64LIT(0x1a9cc1f5f977f242), +W64LIT(0x5210b81c8485e190), +W64LIT(0x6d9ed60c13592a50), +W64LIT(0xf2956c7dced81403), +W64LIT(0xbb4d7cff19f8cd3a), +W64LIT(0x4c2928b0ca50d194), +W64LIT(0x6e626db118da8198), +W64LIT(0xe4135e631bbc558b), +W64LIT(0x9da368a77cd05f70), +W64LIT(0xa574ec53572dfd3e), +W64LIT(0x09ebcbd93163bb67), +W64LIT(0x4a24ab3fdca372f1), +W64LIT(0x429b098d4712037d), +W64LIT(0x57e1802e99f5e93d), +W64LIT(0xef50476c8b8e8fcf), +W64LIT(0xa085d4614a5df593), +W64LIT(0x34cd771f07ee1184), +W64LIT(0xc6581b62c9360587), +W64LIT(0x2dad0d57f51a480e), +W64LIT(0x898d886f08e57fdb), +W64LIT(0xd6d3aaf30aa1e76a), +W64LIT(0x76567e9240fc12f9), +W64LIT(0xb4ab34a93e68d538), +W64LIT(0xb2a6b726289b765d), +W64LIT(0x8c7cb05d15957776), +W64LIT(0x554952f838a4881e), +W64LIT(0xd52f114e01224ca2), +W64LIT(0x60d04c8c95985371), +W64LIT(0x6789a66829b93aff), +W64LIT(0x2f05df81544b292d), +W64LIT(0x476a31bf5a620bd0), +W64LIT(0xf5cc869972f97d8d), +W64LIT(0x488c79e97df213d2), +W64LIT(0x44968a0251e1a018), +W64LIT(0x26ee14586528924a), +W64LIT(0xd0de297c1c52440f), +W64LIT(0xc5a4a0dfc2b5ae4f), +W64LIT(0x29085c0e42b88a48), +W64LIT(0x142ee0c8743520ab), +W64LIT(0x2af4e7b3493b2180), +W64LIT(0x9448a37e4db3e417), +/* box 1 */ +W64LIT(0xe2795ba105ba30ce), +W64LIT(0x65b5d634f5e0fbdd), +W64LIT(0x2d7d7f1464dd8c55), +W64LIT(0xeefbf778add1c20b), +W64LIT(0x1eb0fbd1f11968e7), +W64LIT(0xe6073f45ce30cd8d), +W64LIT(0x21ffd3cdccb67e90), +W64LIT(0xdf0941cfa750a262), +W64LIT(0xc61df5b1b75ef18a), +W64LIT(0xc5c7defa9dc337c6), +W64LIT(0x2581b729073c83d3), +W64LIT(0xa5e97513167173cf), +W64LIT(0xdd3673bd381526b9), +W64LIT(0xe8baa1eef91ebb93), +W64LIT(0x3b314cf8f625eb34), +W64LIT(0x579d4bc8d5fc5df8), +W64LIT(0xbb598ec2e7681b28), +W64LIT(0xc8a06b1a80708794), +W64LIT(0x1c8fc9a36e5cec3c), +W64LIT(0xf60a5a3f0807d374), +W64LIT(0x1ace9f353a9395a4), +W64LIT(0x7e9e50387aab2cee), +W64LIT(0xb5e41069d0466d36), +W64LIT(0x8cea6ee3b92602d9), +W64LIT(0xf952ddad8af1e7fd), +W64LIT(0xb19a748d1bcc9075), +W64LIT(0x2464ae10b2e4c144), +W64LIT(0xfcc9a070f4a35829), +W64LIT(0xfa88f6e6a06c21b1), +W64LIT(0x2c98662dd105cec2), +W64LIT(0x9065a740d77aeee5), +W64LIT(0xcb7a4051aaed41d8), +W64LIT(0x55a279ba4ab9d923), +W64LIT(0x27be855b98790708), +W64LIT(0xbabc97fb52b059bf), +W64LIT(0xa19711f7ddfb8e8c), +W64LIT(0x047e64e4cb8afd43), +W64LIT(0xc386886cc90c4e5e), +W64LIT(0xc422c7c3281b7551), +W64LIT(0xfb6defdf15b46326), +W64LIT(0x01e51939b5d84297), +W64LIT(0x5cbba8be9c809432), +W64LIT(0x6f762c7b09447080), +W64LIT(0xcee13d8cd4bffe0c), +W64LIT(0x54476083ff619bb4), +W64LIT(0x6e933542bc9c3217), +W64LIT(0x4af79b520e78f353), +W64LIT(0x98996f7db49be163), +W64LIT(0xa07208ce6823cc1b), +W64LIT(0x2b3c29823012f5cd), +W64LIT(0x93bf8c0bfde728a9), +W64LIT(0x2225f886e62bb8dc), +W64LIT(0x7f7b4901cf736e79), +W64LIT(0x0000000000000000), +W64LIT(0x023f32729f4584db), +W64LIT(0xd5cabb805bf4293f), +W64LIT(0x07a44fafe1173b0f), +W64LIT(0xe95fb8d74cc6f904), +W64LIT(0x7b052de504f9933a), +W64LIT(0x6aed51a67716cf54), +W64LIT(0x68d263d4e8534b8f), +W64LIT(0xa96bd9cabe1a810a), +W64LIT(0x1d6ad09adb84aeab), +W64LIT(0x0d67b5e01db3b052), +W64LIT(0x52063615abaee22c), +W64LIT(0x8f3045a893bbc495), +W64LIT(0xd8ad0e604647996d), +W64LIT(0xaf2a8f5cead5f892), +W64LIT(0x3017af8ebf5922fe), +W64LIT(0x4034611df2dc780e), +W64LIT(0x721cfce1d2c0de2b), +W64LIT(0x28e602c91a8f3381), +W64LIT(0xe1a370ea2f27f682), +W64LIT(0x29031bf0af577116), +W64LIT(0x1914b47e100e53e8), +W64LIT(0x567852f160241f6f), +W64LIT(0x793a1f979bbc17e1), +W64LIT(0xef1eee411809809c), +W64LIT(0x6211999b14f7c0d2), +W64LIT(0x059b7ddd7e52bfd4), +W64LIT(0x43ee4a56d841be42), +W64LIT(0xf1ae1590e910e87b), +W64LIT(0x33cd84c595c4e4b2), +W64LIT(0x4b12826bbba0b1c4), +W64LIT(0xeb608aa5d3837ddf), +W64LIT(0x201acaf4796e3c07), +W64LIT(0xbf27ea262ce2e66b), +W64LIT(0x58c5cc5a570a6971), +W64LIT(0x37b3e0215e4e19f1), +W64LIT(0xab54ebb8215f05d1), +W64LIT(0x8ed55c9126638602), +W64LIT(0x9aa65d0f2bde65b8), +W64LIT(0xd7f589f2c4b1ade4), +W64LIT(0x5039046734eb66f7), +W64LIT(0x6cac073023d9b6cc), +W64LIT(0x51dc1d5e81332460), +W64LIT(0x17a92ad5272025f6), +W64LIT(0x47902eb213cb4301), +W64LIT(0x1b2b860c8f4bd733), +W64LIT(0x4f6ce68f702a4c87), +W64LIT(0xcf0424b56167bc9b), +W64LIT(0x997c76440143a3f4), +W64LIT(0x7ae034dcb121d1ad), +W64LIT(0x100d657ac6371ef9), +W64LIT(0x0ac3fa4ffca48b5d), +W64LIT(0xdeec58f61288e0f5), +W64LIT(0x265b9c622da1459f), +W64LIT(0xdcd36a848dcd642e), +W64LIT(0xe4380d3751754956), +W64LIT(0x13d74e31ecaad8b5), +W64LIT(0xfd2cb949417b1abe), +W64LIT(0x9624f1d683b5977d), +W64LIT(0x4675378ba6130196), +W64LIT(0x0b26e376497cc9ca), +W64LIT(0x41d1782447043a99), +W64LIT(0xe39c4298b0627259), +W64LIT(0xcd3b16c7fe223840), +W64LIT(0x7787813cac9261ff), +W64LIT(0x492db01924e5351f), +W64LIT(0x5afafe28c84fedaa), +W64LIT(0x8b4e214c583139d6), +W64LIT(0xccde0ffe4bfa7ad7), +W64LIT(0x76629805194a2368), +W64LIT(0x7ca1624ae5eea835), +W64LIT(0x61cbb2d03e6a069e), +W64LIT(0x48c8a920913d7788), +W64LIT(0x8068c23a114df01c), +W64LIT(0xd38bed160f3b50a7), +W64LIT(0x32289dfc201ca625), +W64LIT(0xc1b9ba1e5649ca85), +W64LIT(0xed21dc33874c0447), +W64LIT(0xa3a8238542be0a57), +W64LIT(0x5b1fe7117d97af3d), +W64LIT(0x3d701a6ea2ea92ac), +W64LIT(0x73f9e5d867189cbc), +W64LIT(0x9ed839ebe05498fb), +W64LIT(0x5920d563e2d22be6), +W64LIT(0xca9f59681f35034f), +W64LIT(0x11e87c4373ef5c6e), +W64LIT(0x97c1e8ef366dd5ea), +W64LIT(0xacf0a417c0483ede), +W64LIT(0xd26ef42fbae31230), +W64LIT(0xbcfdc16d067f2027), +W64LIT(0xbec2f31f993aa4fc), +W64LIT(0x45af1cc08c8ec7da), +W64LIT(0x31f2b6b70a816069), +W64LIT(0xd9481759f39fdbfa), +W64LIT(0xe5dd140ee4ad0bc1), +W64LIT(0xa6335e583cecb583), +W64LIT(0x38eb67b3dcb82d78), +W64LIT(0xf5d07174229a1538), +W64LIT(0x5f6183f5b61d527e), +W64LIT(0x0f58879282f63489), +W64LIT(0x164c33ec92f86761), +W64LIT(0x444a05f93956854d), +W64LIT(0x818ddb03a495b28b), +W64LIT(0x4d53d4fdef6fc85c), +W64LIT(0x8d0f77da0cfe404e), +W64LIT(0x8416a6dedac70d5f), +W64LIT(0x666ffd7fdf7d3d91), +W64LIT(0xb63e3b22fadbab7a), +W64LIT(0xf2743edbc38d2e37), +W64LIT(0xa40c6c2aa3a93158), +W64LIT(0x9f3d20d2558cda6c), +W64LIT(0xfef692026be6dcf2), +W64LIT(0x2ea7545f4e404a19), +W64LIT(0xb2405fc631515639), +W64LIT(0x23c0e1bf53f3fa4b), +W64LIT(0x83b2e9713bd03650), +W64LIT(0x0641569654cf7998), +W64LIT(0xb883a589cdf5dd64), +W64LIT(0x3ad455c143fda9a3), +W64LIT(0x925a9532483f6a3e), +W64LIT(0xaab1f28194874746), +W64LIT(0xf435684d974257af), +W64LIT(0xd1b4df64907ed47c), +W64LIT(0x390e7e8a69606fef), +W64LIT(0xd051c65d25a696eb), +W64LIT(0xb4010950659e2fa1), +W64LIT(0x0c82acd9a86bf2c5), +W64LIT(0x88940a0772acff9a), +W64LIT(0xf39127e276556ca0), +W64LIT(0xaecf96655f0dba05), +W64LIT(0x03da2b4b2a9dc64c), +W64LIT(0x3f4f281c3daf1677), +W64LIT(0x3469cb6a74d3dfbd), +W64LIT(0xf04b0ca95cc8aaec), +W64LIT(0x1f55e2e844c12a70), +W64LIT(0x4cb6cdc45ab78acb), +W64LIT(0xc05ca327e3918812), +W64LIT(0x95feda9da9285131), +W64LIT(0xb966bcb0782d9ff3), +W64LIT(0xa7d647618934f714), +W64LIT(0xd61090cb7169ef73), +W64LIT(0x71c6d7aaf85d1867), +W64LIT(0xecc4c50a329446d0), +W64LIT(0x6450cf0d4038b94a), +W64LIT(0x420b536f6d99fcd5), +W64LIT(0x75b8b34e33d7e524), +W64LIT(0xc26391557cd40cc9), +W64LIT(0xda923c12d9021db6), +W64LIT(0x4e89ffb6c5f20e10), +W64LIT(0x0919d104d6394d11), +W64LIT(0x8aab3875ede97b41), +W64LIT(0xa88ec0f30bc2c39d), +W64LIT(0xb7db221b4f03e9ed), +W64LIT(0xc7f8ec880286b31d), +W64LIT(0x2f424d66fb98088e), +W64LIT(0xe04669d39affb415), +W64LIT(0x3eaa3125887754e0), +W64LIT(0x5e849acc03c510e9), +W64LIT(0x8257f0488e0874c7), +W64LIT(0xbd18d854b3a762b0), +W64LIT(0xb3a546ff848914ae), +W64LIT(0x9ce70b997f111c20), +W64LIT(0x3c9503571732d03b), +W64LIT(0xe7e2267c7be88f1a), +W64LIT(0x63f480a2a12f8245), +W64LIT(0x602eabe98bb24409), +W64LIT(0x941bc3a41cf013a6), +W64LIT(0x678ae4466aa57f06), +W64LIT(0x1232570859729a22), +W64LIT(0x6d491e099601f45b), +W64LIT(0x5d5eb1872958d6a5), +W64LIT(0x1473019e0dbde3ba), +W64LIT(0xa24d3abcf76648c0), +W64LIT(0x85f3bfe76f1f4fc8), +W64LIT(0x08fcc83d63e10f86), +W64LIT(0x745daa77860fa7b3), +W64LIT(0x9180be7962a2ac72), +W64LIT(0x87cc8d95f05acb13), +W64LIT(0x78df06ae2e645576), +W64LIT(0x18f1ad47a5d6117f), +W64LIT(0x358cd253c10b9d2a), +W64LIT(0x0ebd9eab372e761e), +W64LIT(0xf7ef4306bddf91e3), +W64LIT(0x7023ce934d855af0), +W64LIT(0xd42fa2b9ee2c6ba8), +W64LIT(0x3656f918eb965b66), +W64LIT(0x9d0212a0cac95eb7), +W64LIT(0x2ad930bb85cab75a), +W64LIT(0x862994ac45828984), +W64LIT(0x7d447b735036eaa2), +W64LIT(0xb07f6db4ae14d2e2), +W64LIT(0x6b08489fc2ce8dc3), +W64LIT(0x9b4344369e06272f), +W64LIT(0xad15bd2e75907c49), +W64LIT(0xdb77252b6cda5f21), +W64LIT(0xea85939c665b3f48), +W64LIT(0xc945722335a8c503), +W64LIT(0x159618a7b865a12d), +W64LIT(0x69377aed5d8b0918), +W64LIT(0x8971133ec774bd0d), +W64LIT(0x53e32f2c1e76a0bb), +W64LIT(0xf8b7c4943f29a56a), +W64LIT(0xff138b3bde3e9e65), +/* box 2 */ +W64LIT(0x7c6a2eb5fdabecc6), +W64LIT(0x401cda0a752bbea0), +W64LIT(0x1925217156dc57c4), +W64LIT(0x56dec6d301d70787), +W64LIT(0x41c751ff73c6ac58), +W64LIT(0xc9067697a92cb5f9), +W64LIT(0x3391c917aaa0bc85), +W64LIT(0xae0a9a4c0e742afe), +W64LIT(0xaa8ca972162a62f4), +W64LIT(0x5aa193912935df99), +W64LIT(0x86fd9135fe27e5ba), +W64LIT(0xffca074b1d3f538e), +W64LIT(0x0e3cb65d24cdfc1b), +W64LIT(0x4384b2e07fe9885d), +W64LIT(0xc73ac0ca8de149e2), +W64LIT(0x48e5bc7645972eb4), +W64LIT(0xbe0d56b46ef9ffd6), +W64LIT(0x200e6d05c0ef5f50), +W64LIT(0xe1f17dee597f7abd), +W64LIT(0x0243e31f0c2f2405), +W64LIT(0xf4ab09dd2741f567), +W64LIT(0xe4acc52547cc204f), +W64LIT(0x348f92c3b83cc272), +W64LIT(0x53837e181f645d75), +W64LIT(0xd8da319acf4c7229), +W64LIT(0x81e3cae1ecbb9b4d), +W64LIT(0xd6e687c7eb818e32), +W64LIT(0x3dad7f4a8e6d409e), +W64LIT(0x28f70b79f053cf44), +W64LIT(0x493e3783437a3c4c), +W64LIT(0xb27203f6461b27c8), +W64LIT(0xd02357e6fff0e23d), +W64LIT(0xe8d390676f2ef851), +W64LIT(0x26cbbd24d49e335f), +W64LIT(0xee1640467b5f945e), +W64LIT(0x4aa65f6949b80ab1), +W64LIT(0xb56c58225487593f), +W64LIT(0x4ffbe7a2570b5043), +W64LIT(0x0aba85633c93b411), +W64LIT(0x78ec1d8be5f5a4cc), +W64LIT(0x501b16f215a66b88), +W64LIT(0x271036d1d27321a7), +W64LIT(0x7ff2465ff769da3b), +W64LIT(0x35541936bed1d08a), +W64LIT(0xb8c886957a8893d9), +W64LIT(0x2fe950ade2cfb1b3), +W64LIT(0xf90fd76a094e3f81), +W64LIT(0x2daab3b2eee095b6), +W64LIT(0x1abd499b5c1e6139), +W64LIT(0x0c7f554228e2d81e), +W64LIT(0x425f391579049aa5), +W64LIT(0xc3bcf3f495bf01e8), +W64LIT(0xb4b7d3d7526a4bc7), +W64LIT(0x0000000000000000), +W64LIT(0xa0362c112ab9d6e5), +W64LIT(0x91e406198c364e65), +W64LIT(0x454162c16b98e452), +W64LIT(0x139fa4126a4fe3d5), +W64LIT(0x01db8bf506ed12f8), +W64LIT(0x9a85088fb648e88c), +W64LIT(0x3ab3249e9cf13e69), +W64LIT(0xd57eef2de143b8cf), +W64LIT(0xb1ea6b1c4cd91135), +W64LIT(0x7aaffe94e9da80c9), +W64LIT(0xad92f2a604b61c03), +W64LIT(0xa3ae44fb207be018), +W64LIT(0xeb4bf88d65ecceac), +W64LIT(0xc0249b1e9f7d3715), +W64LIT(0xa8cf4a6d1a0546f1), +W64LIT(0xc6e14b3f8b0c5b1a), +W64LIT(0xce182d43bbb0cb0e), +W64LIT(0xfc526fa117fd6573), +W64LIT(0x8c471456c2b451ab), +W64LIT(0xac497953025b0efb), +W64LIT(0x0486333e185e480a), +W64LIT(0x18feaa845031453c), +W64LIT(0xa1eda7e42c54c41d), +W64LIT(0x06c5d02114716c0f), +W64LIT(0x055db8cb1eb35af2), +W64LIT(0xe5774ed0412132b7), +W64LIT(0x36cc71dcb413e677), +W64LIT(0x470281de67b7c057), +W64LIT(0x58e2708e251afb9c), +W64LIT(0xa914c1981ce85409), +W64LIT(0xb3a9880340f63530), +W64LIT(0x638adfe5bf06d70d), +W64LIT(0x0b610e963a7ea6e9), +W64LIT(0x927c6ef386f47898), +W64LIT(0xed8e28ac719da2a3), +W64LIT(0x7548c33ccbfa6e2a), +W64LIT(0xf3b5520935dd8b90), +W64LIT(0x8d9c9fa3c4594353), +W64LIT(0x31d22a08a68f9880), +W64LIT(0x0da4deb72e0fcae6), +W64LIT(0x8fdf7cbcc8766756), +W64LIT(0x5dbfc8453ba9a16e), +W64LIT(0x8e04f749ce9b75ae), +W64LIT(0x83a029fee094bf48), +W64LIT(0xa4b01f2f32e79eef), +W64LIT(0x1c7899ba486f0d36), +W64LIT(0x654f0fc4ab77bb02), +W64LIT(0x7db1a540fb46fe3e), +W64LIT(0x51c09d07134b7970), +W64LIT(0xcb459588a50391fc), +W64LIT(0x3fee9c558242649b), +W64LIT(0xfe118cbe1bd24176), +W64LIT(0x76d0abd6c13858d7), +W64LIT(0x5e27a0af316b9793), +W64LIT(0x69305a868395631c), +W64LIT(0x3b68af6b9a1c2c91), +W64LIT(0x6db669b89bcb2b16), +W64LIT(0xa72877c53825a812), +W64LIT(0xd3bb3f0cf532d4c0), +W64LIT(0x6ff58aa797e40f13), +W64LIT(0x96fa5dcd9eaa3092), +W64LIT(0x2c713847e80d874e), +W64LIT(0xc57923d581ce6de7), +W64LIT(0x2b6f6393fa91f9b9), +W64LIT(0x0922ed89365182ec), +W64LIT(0x324a42e2ac4dae7d), +W64LIT(0x16c21cd974fcb927), +W64LIT(0x956235279468066f), +W64LIT(0x7b747561ef379231), +W64LIT(0x449ae9346d75f6aa), +W64LIT(0xf570822821ace79f), +W64LIT(0x5939fb7b23f7e964), +W64LIT(0x7937967ee318b634), +W64LIT(0x84be722af208c1bf), +W64LIT(0x08f9667c30bc9014), +W64LIT(0xefcdcbb37db286a6), +W64LIT(0xa6f3fc303ec8baea), +W64LIT(0xea9073786301dc54), +W64LIT(0x62515410b9ebc5f5), +W64LIT(0xd260b4f9f3dfc638), +W64LIT(0x9e033bb1ae16a086), +W64LIT(0x38f0c78190de1a6c), +W64LIT(0xc267780193521310), +W64LIT(0x80384114ea5689b5), +W64LIT(0x9b5e837ab0a5fa74), +W64LIT(0xf73361372d83c39a), +W64LIT(0x3009a1fda0628a78), +W64LIT(0xd4a564d8e7aeaa37), +W64LIT(0xfb4c347505611b84), +W64LIT(0x5b7a18642fd8cd61), +W64LIT(0x239605efca2d69ad), +W64LIT(0xf8d45c9f0fa32d79), +W64LIT(0xbb50ee7f704aa524), +W64LIT(0x392b4c7496330894), +W64LIT(0x0fe73da82220eee3), +W64LIT(0x3717fa29b2fef48f), +W64LIT(0xf26ed9fc33309968), +W64LIT(0xd73d0c32ed6c9cca), +W64LIT(0xda99d285c363562c), +W64LIT(0xde1fe1bbdb3d1e26), +W64LIT(0x738d131ddf8b0225), +W64LIT(0x292c808cf6beddbc), +W64LIT(0xbc4eb5ab62d6dbd3), +W64LIT(0x039868ea0ac236fd), +W64LIT(0xcc5bce5cb79fef0b), +W64LIT(0xb031e0e94a3403cd), +W64LIT(0xc4a2a82087237f1f), +W64LIT(0xb72fbb3d58a87d3a), +W64LIT(0xafd111b908993806), +W64LIT(0x68ebd173857871e4), +W64LIT(0x9d9b535ba4d4967b), +W64LIT(0xe9081b9269c3eaa9), +W64LIT(0x71cef002d3a42620), +W64LIT(0x93a7e50680196a60), +W64LIT(0x891aac9ddc070b59), +W64LIT(0x155a74337e3e8fda), +W64LIT(0x4e206c5751e642bb), +W64LIT(0x9721d6389847226a), +W64LIT(0x12442fe76ca2f12d), +W64LIT(0x2553d5cede5c05a2), +W64LIT(0xa275cf0e2696f2e0), +W64LIT(0x24885e3bd8b1175a), +W64LIT(0x670cecdba7589f07), +W64LIT(0x749348c9cd177cd2), +W64LIT(0x64948431ad9aa9fa), +W64LIT(0x2ab4e866fc7ceb41), +W64LIT(0xe6ef263a4be3044a), +W64LIT(0xe734adcf4d0e16b2), +W64LIT(0x903f8dec8adb5c9d), +W64LIT(0xf02d3ae33f1fbd6d), +W64LIT(0x725698e8d96610dd), +W64LIT(0x1da3124f4e821fce), +W64LIT(0x1719972c7211abdf), +W64LIT(0x11dc470d6660c7d0), +W64LIT(0xec55a3597770b05b), +W64LIT(0xbfd6dd416814ed2e), +W64LIT(0x57054d26073a157f), +W64LIT(0x1e3b7aa544402933), +W64LIT(0x5ffc2b5a3786856b), +W64LIT(0x61c93cfab329f308), +W64LIT(0x3e3517a084af7663), +W64LIT(0xf6e8eac22b6ed162), +W64LIT(0x1007ccf8608dd528), +W64LIT(0x66d7672ea1b58dff), +W64LIT(0x8b594f82d0282f5c), +W64LIT(0x1fe0f15042ad3bcb), +W64LIT(0x4b7dd49c4f551849), +W64LIT(0x4c638f485dc966be), +W64LIT(0xcfc3a6b6bd5dd9f6), +W64LIT(0x46d90a2b615ad2af), +W64LIT(0x8565f9dff4e5d347), +W64LIT(0x94b9bed292851497), +W64LIT(0xfa97bf80038c097c), +W64LIT(0xb9130d607c658121), +W64LIT(0xdc5c02a4d7123a23), +W64LIT(0x224d8e1accc07b55), +W64LIT(0x87261ac0f8caf742), +W64LIT(0xd901ba6fc9a160d1), +W64LIT(0xab57228710c7700c), +W64LIT(0x21d5e6f0c6024da8), +W64LIT(0x98c6eb90ba67cc89), +W64LIT(0x827ba20be679adb0), +W64LIT(0x991d6065bc8ade71), +W64LIT(0x5546ae390b15317a), +W64LIT(0xa56b94da340a8c17), +W64LIT(0x071e5bd4129c7ef7), +W64LIT(0xe02af61b5f926845), +W64LIT(0x6b73b9998fba4719), +W64LIT(0xdfc46a4eddd00cde), +W64LIT(0x770b2023c7d54a2f), +W64LIT(0x7e29cdaaf184c8c3), +W64LIT(0xba8b658a76a7b7dc), +W64LIT(0x9c40d8aea2398483), +W64LIT(0x9fd8b044a8fbb27e), +W64LIT(0xdb425970c58e44d4), +W64LIT(0xe269150453bd4c40), +W64LIT(0x3c76f4bf88805266), +W64LIT(0xf1f6b11639f2af95), +W64LIT(0x549d25cc0df82382), +W64LIT(0x4db804bd5b247446), +W64LIT(0x8a82c477d6c53da4), +W64LIT(0x5258f5ed19894f8d), +W64LIT(0x6e2e015291091deb), +W64LIT(0xc1ff10eb999025ed), +W64LIT(0xbd953e5e643bc92b), +W64LIT(0xc8ddfd62afc1a701), +W64LIT(0x5c6443b03d44b396), +W64LIT(0x6c6de24d9d2639ee), +W64LIT(0x1481ffc678d39d22), +W64LIT(0xd1f8dc13f91df0c5), +W64LIT(0xca9e1e7da3ee8304), +W64LIT(0xdd878951d1ff28db), +W64LIT(0x6012b70fb5c4e1f0), +W64LIT(0x1b66c26e5af373c1), +W64LIT(0xe3b29ef155505eb8), +W64LIT(0x70157bf7d54934d8), +W64LIT(0x2e32db58e422a34b), +W64LIT(0x6aa8326c895755e1), +W64LIT(0xb6f430c85e456fc2), +W64LIT(0xfd89e4541110778b), +W64LIT(0x88c12768daea19a1), +W64LIT(0xcd8045a9b172fdf3), +/* box 3 */ +W64LIT(0x99183e616655b742), +W64LIT(0xb2872032a50d6860), +W64LIT(0x0946f63b060528ef), +W64LIT(0x36612b9a141ef07d), +W64LIT(0x0634da84dd49579b), +W64LIT(0xfc9c9e9b486c8a57), +W64LIT(0xa63fe3c0744e6fd0), +W64LIT(0xf1515758d8b46bf9), +W64LIT(0x3e82559fcd5197ff), +W64LIT(0x92e12d262bc40177), +W64LIT(0xc3bb433a5a7752c5), +W64LIT(0x21c3852a5183267a), +W64LIT(0x39130725cf528f09), +W64LIT(0x9ba7db1d2dc12998), +W64LIT(0xc58f99be873e055e), +W64LIT(0xd9d424498f32656c), +W64LIT(0x27f75fae8cca71e1), +W64LIT(0x59b91019a8fc3430), +W64LIT(0xce768af9caafb36b), +W64LIT(0x9d930199f0887e03), +W64LIT(0x63b07a7ef3706a8e), +W64LIT(0xb5167288a70e7096), +W64LIT(0x40cc1a28e967d22e), +W64LIT(0x4d01d3eb79bf3380), +W64LIT(0x9e896cdb6456afb4), +W64LIT(0x2548bad2c75eef3b), +W64LIT(0xa79a6bfeab0420bd), +W64LIT(0x9f2ce4e5bb1ce0d9), +W64LIT(0x32ea146282c3393c), +W64LIT(0x6d67defff7765a97), +W64LIT(0x83775912b31080eb), +W64LIT(0xf5da68a04e69a2b8), +W64LIT(0x1196743498d4819c), +W64LIT(0x0bf913474d91b635), +W64LIT(0x43d6776a7db90399), +W64LIT(0x444725d07fba1b6f), +W64LIT(0x6584a0fa2e393d15), +W64LIT(0x3f27dda1121bd892), +W64LIT(0xf6c005e2dab7730f), +W64LIT(0x56cb3ca673b04b44), +W64LIT(0x642128c4f1737278), +W64LIT(0xbf4ae9f135d589ce), +W64LIT(0xb038c54eee99f6ba), +W64LIT(0xf47fe09e9123edd5), +W64LIT(0x75b75cf069a7f3e4), +W64LIT(0xd419ed8a1fea84c2), +W64LIT(0x73838674b4eea47f), +W64LIT(0x498aec13ef62fac1), +W64LIT(0x20660d148ec96917), +W64LIT(0xa48006bc3fdaf10a), +W64LIT(0x2f1421ab55851663), +W64LIT(0x0a5c9b7992dbf958), +W64LIT(0xd1375a4c567d02ee), +W64LIT(0x0000000000000000), +W64LIT(0xc842507d17e6e4f0), +W64LIT(0xf3eeb2249320f523), +W64LIT(0xc9e7d843c8acab9d), +W64LIT(0xff86f3d9dcb25be0), +W64LIT(0xb4b3fab678443ffb), +W64LIT(0xb19d4d7031d3b9d7), +W64LIT(0x79df1d0d26355d27), +W64LIT(0x8eba90d123c86145), +W64LIT(0xaa57a23d3bdcc113), +W64LIT(0xcb583d3f83383547), +W64LIT(0xd871ac7750782a01), +W64LIT(0xe162ab529f2aa508), +W64LIT(0x38b68f1b1018c064), +W64LIT(0x237c60561a17b8a0), +W64LIT(0xa31154063dd9e9fc), +W64LIT(0x713c6308ff7a3aa5), +W64LIT(0x1a6f6773d54537a9), +W64LIT(0x08e37e05d94f6782), +W64LIT(0x357b46d880c021ca), +W64LIT(0x6cc256c1283c15fa), +W64LIT(0xcfd302c715e5fc06), +W64LIT(0xbdf50c8d7e411714), +W64LIT(0x7cf1aacb6fa2db0b), +W64LIT(0x5240035ee56d8205), +W64LIT(0x7b60f8716da1c3fd), +W64LIT(0x01a5883edf4a4f6d), +W64LIT(0xdd5f1bb119efac2d), +W64LIT(0x5474d9da3824d59e), +W64LIT(0x0f722cbfdb4c7f74), +W64LIT(0x17a2aeb0459dd607), +W64LIT(0x37c4a3a4cb54bf10), +W64LIT(0xc21ecb04853d1da8), +W64LIT(0x4273ff54a2f34cf4), +W64LIT(0xdace490b1becb4db), +W64LIT(0x6af68c45f5754261), +W64LIT(0x46f8c0ac342e85b5), +W64LIT(0x854383966e59d770), +W64LIT(0x81c8bc6ef8841e31), +W64LIT(0x3bace25984c611d3), +W64LIT(0x1033fc0a479ecef1), +W64LIT(0x1c5bbdf7080c6032), +W64LIT(0x7412d4ceb6edbc89), +W64LIT(0xa8e8474170485fc9), +W64LIT(0xb8dbbb4b37d69138), +W64LIT(0x079152ba020318f6), +W64LIT(0x72260e4a6ba4eb12), +W64LIT(0x905ec85a60509fad), +W64LIT(0x2dabc4d71e1188b9), +W64LIT(0xd092d27289374d83), +W64LIT(0x610f9f02b8e4f454), +W64LIT(0x02bfe57c4b949eda), +W64LIT(0x95707f9c29c71981), +W64LIT(0x6fd83b83bce2c44d), +W64LIT(0x5d322fe13e21fd71), +W64LIT(0x34decee65f8a6ea7), +W64LIT(0xcd6ce7bb5e7162dc), +W64LIT(0xfb0dcc214a6f92a1), +W64LIT(0x2eb1a9958acf590e), +W64LIT(0xdcfa938fc6a5e340), +W64LIT(0x669ecdb8bae7eca2), +W64LIT(0x151d4bcc0e0948dd), +W64LIT(0xfd3916a59726c53a), +W64LIT(0x581c982777b67b5d), +W64LIT(0x1bcaef4d0a0f78c4), +W64LIT(0xdfe0fecd527b32f7), +W64LIT(0x128c19760c0a502b), +W64LIT(0x84e60ba8b113981d), +W64LIT(0x3c3db0e386c50925), +W64LIT(0x7febc789fb7c0abc), +W64LIT(0x7d5422f5b0e89466), +W64LIT(0xd70380c88b345575), +W64LIT(0xbbc1d609a308408f), +W64LIT(0xe278c6100bf474bf), +W64LIT(0x5e2842a3aaff2cc6), +W64LIT(0x6b53047b2a3f0d0c), +W64LIT(0xf7658ddc05fd3c62), +W64LIT(0x9a025323f28b66f5), +W64LIT(0x8c0575ad685cff9f), +W64LIT(0x76ad31b2fd792253), +W64LIT(0x68496939bee1dcbb), +W64LIT(0x7e4e4fb7243645d1), +W64LIT(0xe44c1c94d6bd2324), +W64LIT(0xbeef61cfea9fc6a3), +W64LIT(0x91fb4064bf1ad0c0), +W64LIT(0x052eb7c64997862c), +W64LIT(0x4a9081517bbc2b76), +W64LIT(0x8f1f18effc822e28), +W64LIT(0x3a096a675b8c5ebe), +W64LIT(0xee1087ed4466da7c), +W64LIT(0x2652d79053803e8c), +W64LIT(0x7099eb36203075c8), +W64LIT(0xc7307cc2ccaa9b84), +W64LIT(0x5c97a7dfe16bb21c), +W64LIT(0x50ffe622aef91cdf), +W64LIT(0x8da0fd93b716b0f2), +W64LIT(0x69ece10761ab93d6), +W64LIT(0x31f07920161de88b), +W64LIT(0x13299148d3401f46), +W64LIT(0x031a6d4294ded1b7), +W64LIT(0xccc96f85813b2db1), +W64LIT(0x14b8c3f2d14307b0), +W64LIT(0x8659eed4fa8706c7), +W64LIT(0xba645e377c420fe2), +W64LIT(0x2920fb2f88cc41f8), +W64LIT(0x87fc66ea25cd49aa), +W64LIT(0x1ee4588b4398fee8), +W64LIT(0xecaf62910ff244a6), +W64LIT(0xf817a163deb14316), +W64LIT(0x45e2adeea0f05402), +W64LIT(0x806d345027ce515c), +W64LIT(0x576eb498acfa0429), +W64LIT(0xa5258e82e090be67), +W64LIT(0x892bc26b21cb79b3), +W64LIT(0x6e7db3bd63a88b20), +W64LIT(0x4e1bbea9ed61e237), +W64LIT(0xadc6f08739dfd9e5), +W64LIT(0x8b9427176a5fe769), +W64LIT(0xa1aeb17a764d7726), +W64LIT(0x4b35096fa4f6641b), +W64LIT(0x22d9e868c55df7cd), +W64LIT(0x55d151e4e76e9af3), +W64LIT(0x966a12debd19c836), +W64LIT(0x0dcdc9c390d8e1ae), +W64LIT(0xf24b3a1a4c6aba4e), +W64LIT(0x24ed32ec1814a056), +W64LIT(0xaf7915fb724b473f), +W64LIT(0x2885731157860e95), +W64LIT(0x9c3689a72fc2316e), +W64LIT(0x475d4892eb64cad8), +W64LIT(0xac6378b9e6959688), +W64LIT(0xa00b3944a907384b), +W64LIT(0xc695f4fc13e0d4e9), +W64LIT(0x3055f11ec957a7e6), +W64LIT(0x6215f2402c3a25e3), +W64LIT(0xde4576f38d317d9a), +W64LIT(0x9344a518f48e4e1a), +W64LIT(0x82d2d12c6c5acf86), +W64LIT(0xefb50fd39b2c9511), +W64LIT(0xe981d5574665c28a), +W64LIT(0x5f8dca9d75b563ab), +W64LIT(0xb60c1fca33d0a121), +W64LIT(0xfe237be703f8148d), +W64LIT(0xd6a608f6547e1a18), +W64LIT(0xb97e3375e89cde55), +W64LIT(0xd388bf301de99c34), +W64LIT(0x5b06f565e368aaea), +W64LIT(0xf0f4df6607fe2494), +W64LIT(0x1607268e9ad7996a), +W64LIT(0xaedc9dc5ad010852), +W64LIT(0xe0c7236c4060ea65), +W64LIT(0xea9bb815d2bb133d), +W64LIT(0x888e4a55fe8136de), +W64LIT(0x5aa37d5b3c22e587), +W64LIT(0xc104a64611e3cc1f), +W64LIT(0x515a6e1c71b353b2), +W64LIT(0xc42a118058744a33), +W64LIT(0x7708b98c22336d3e), +W64LIT(0x2a3a966d1c12904f), +W64LIT(0x8a31af29b515a804), +W64LIT(0xed0aeaafd0b80bcb), +W64LIT(0x2c0e4ce9c15bc7d4), +W64LIT(0x0c6841fd4f92aec3), +W64LIT(0x98bdb65fb91ff82f), +W64LIT(0x1f41d0b59cd2b185), +W64LIT(0xb322a80c7a47270d), +W64LIT(0xe6f3f9e89d29bdfe), +W64LIT(0x7ac5704fb2eb8c90), +W64LIT(0xa94dcf7faf0210a4), +W64LIT(0x787a9533f97f124a), +W64LIT(0xdb6bc135c4a6fbb6), +W64LIT(0x048b3ff896ddc941), +W64LIT(0xe8245d69992f8de7), +W64LIT(0xe3dd4e2ed4be3bd2), +W64LIT(0xcafdb5015c727a2a), +W64LIT(0xb7a997f4ec9aee4c), +W64LIT(0xe75671d64263f293), +W64LIT(0x2b9f1e53c358df22), +W64LIT(0x18d0820f9ed1a973), +W64LIT(0xabf22a03e4968e7e), +W64LIT(0xa2b4dc38e293a691), +W64LIT(0x673b458665ada3cf), +W64LIT(0xf9b2295d01fb0c7b), +W64LIT(0xd22d370ec2a3d359), +W64LIT(0x97cf9ae06253875b), +W64LIT(0x0ed7a48104063019), +W64LIT(0x482f642d3028b5ac), +W64LIT(0xc0a12e78cea98372), +W64LIT(0x4fbe3697322bad5a), +W64LIT(0x19750a31419be61e), +W64LIT(0x41699216362d9d43), +W64LIT(0xd5bc65b4c0a0cbaf), +W64LIT(0xe5e994aa09f76c49), +W64LIT(0xeb3e302b0df15c50), +W64LIT(0x94d5f7a2f68d56ec), +W64LIT(0x53e58b603a27cd68), +W64LIT(0x3d9838dd598f4648), +W64LIT(0x60aa173c67aebb39), +W64LIT(0x1dfe35c9d7462f5f), +W64LIT(0x4ca45bd5a6f57ced), +W64LIT(0xbc5084b3a10b5879), +W64LIT(0xfaa8441f9525ddcc), +W64LIT(0x334f9c5c5d897651), +/* box 4 */ +W64LIT(0xda1687a883adf27e), +W64LIT(0xe35c9378578d9f22), +W64LIT(0x303ca4531637fa40), +W64LIT(0xa088321f74b20375), +W64LIT(0xc9863f3a9acb95e9), +W64LIT(0x5fcf47c57d0b0ed4), +W64LIT(0x4aa211e4e1280b4b), +W64LIT(0xe1a4c9ba871d1289), +W64LIT(0x4926664759f03a4f), +W64LIT(0xadfb36ede3707bca), +W64LIT(0xcf7bd1891f8ef7e1), +W64LIT(0x9735559e8f882792), +W64LIT(0x5932a976f84e6cdc), +W64LIT(0x9dc792bef547818a), +W64LIT(0x06fdeeb385456208), +W64LIT(0x46ad38771ea2cf5b), +W64LIT(0x5eb36aa41543b27b), +W64LIT(0x8b2eb33cd1bcb511), +W64LIT(0x71105ff6e598ebbc), +W64LIT(0x5441ad846f8c1463), +W64LIT(0x4c5fff57646d6943), +W64LIT(0xf3485c49f633c9b1), +W64LIT(0x9cbbbfdf9d0f3d25), +W64LIT(0x22d031a067192178), +W64LIT(0xca0248992213a4ed), +W64LIT(0x19627fb263a9c18f), +W64LIT(0x9330e1efda5dc831), +W64LIT(0x1390b89219666797), +W64LIT(0x2edf18339893e568), +W64LIT(0x6c779435d3e4c590), +W64LIT(0x53c06e568281cac4), +W64LIT(0x6ff3e3966b3cf494), +W64LIT(0xfe3b58bb61f1b10e), +W64LIT(0x77edb14560dd89b4), +W64LIT(0x02f85ac2d0908dab), +W64LIT(0x12ec95f3712edb38), +W64LIT(0x85d9c06dfea6fcaa), +W64LIT(0x90b4964c6285f935), +W64LIT(0xf1b0068b26a3441a), +W64LIT(0x729428555d40dab8), +W64LIT(0x5c4b3066c5d33fd0), +W64LIT(0x5d371d07ad9b837f), +W64LIT(0xa48d866e2167ecd6), +W64LIT(0xb661139d504937ee), +W64LIT(0xa27068dda4228ede), +W64LIT(0xf8c6b608e4b4d306), +W64LIT(0x6bf657e73ee91b37), +W64LIT(0xac871b8c8b38c765), +W64LIT(0x4ea7a595b4fde4e8), +W64LIT(0x0d7304f297c278bf), +W64LIT(0xb71d3efc38018b41), +W64LIT(0xae7f414e5ba84ace), +W64LIT(0xaf036c2f33e0f661), +W64LIT(0x0000000000000000), +W64LIT(0xb89660cc7f537e55), +W64LIT(0xa675dcacf1f7617d), +W64LIT(0x610490c74426bd2f), +W64LIT(0xc18ca2d83094be5a), +W64LIT(0x2adaac42cd460acb), +W64LIT(0x7d1f76651a122fac), +W64LIT(0xc58916a9654151f9), +W64LIT(0xedabe0297897d699), +W64LIT(0x2d5b6f90204bd46c), +W64LIT(0x26d585d132cccedb), +W64LIT(0x9f3fc87c25d70c21), +W64LIT(0xc60d610add9960fd), +W64LIT(0x80a0597dc33bafa6), +W64LIT(0xd0e44088f9625466), +W64LIT(0x1d67cbc3367c2e2c), +W64LIT(0x2c2742f1480368c3), +W64LIT(0x89d6e9fe012c38ba), +W64LIT(0xe9ae54582d42393a), +W64LIT(0x3ecbd702392db3fb), +W64LIT(0xb5e5643ee89106ea), +W64LIT(0xa882affddeed28c6), +W64LIT(0x1ae60811db71f08b), +W64LIT(0x924ccc8eb215749e), +W64LIT(0xfcc30279b1613ca5), +W64LIT(0x825803bf13ab220d), +W64LIT(0xd992f00b3b75c37a), +W64LIT(0xc8fa125bf2832946), +W64LIT(0x35453d432baaa94c), +W64LIT(0xf9ba9b698cfc6fa9), +W64LIT(0x37bd6781fb3a24e7), +W64LIT(0x791ac2144fc7c00f), +W64LIT(0x16e9218224fb349b), +W64LIT(0xdb6aaac9ebe54ed1), +W64LIT(0xd8eedd6a533d7fd5), +W64LIT(0x7c635b04725a9303), +W64LIT(0x553d80e507c4a8cc), +W64LIT(0x9a46516c184a5f2d), +W64LIT(0x14117b40f46bb930), +W64LIT(0x1ee3bc608ea41f28), +W64LIT(0x27a9a8b05a847274), +W64LIT(0x4050d6c49be7ad53), +W64LIT(0x7be298d69f574da4), +W64LIT(0x6a8a7a8656a1a798), +W64LIT(0x4d23d2360c25d5ec), +W64LIT(0x1014cf31a1be5693), +W64LIT(0xb264a7ec059cd84d), +W64LIT(0xea2a23fb959a083e), +W64LIT(0xf0cc2bea4eebf8b5), +W64LIT(0x76919c240895351b), +W64LIT(0x0b8eea4112871ab7), +W64LIT(0x47d1151676ea73f4), +W64LIT(0xbdeff9dc42ce2d59), +W64LIT(0x2ba68123a50eb664), +W64LIT(0x057999103d9d530c), +W64LIT(0xe759270902587081), +W64LIT(0xef53baeba8075b32), +W64LIT(0x4fdb88f4dcb55847), +W64LIT(0x6e8fcef70374483b), +W64LIT(0x1168e250c9f6ea3c), +W64LIT(0x1b9a2570b3394c24), +W64LIT(0x706c72978dd05713), +W64LIT(0x865db7ce467ecdae), +W64LIT(0x52bc4337eac9766b), +W64LIT(0x504419f53a59fbc0), +W64LIT(0x8f2b074d84695ab2), +W64LIT(0x6078bda62c6e0180), +W64LIT(0x43d4a167233f9c57), +W64LIT(0x0ef773512f1a49bb), +W64LIT(0x0c0f2993ff8ac410), +W64LIT(0x4bde3c858960b7e4), +W64LIT(0x66855315a92b6388), +W64LIT(0xd360372b41ba6562), +W64LIT(0x584e84179006d073), +W64LIT(0x9b3a7c0d7002e382), +W64LIT(0xa5f1ab0f492f5079), +W64LIT(0x2822f6801dd68760), +W64LIT(0x445562b5ce3242f0), +W64LIT(0xaa7af53f0e7da56d), +W64LIT(0x3c338dc0e9bd3e50), +W64LIT(0x3bb24e1204b0e0f7), +W64LIT(0xd59dd998c4ff076a), +W64LIT(0x91c8bb2d0acd459a), +W64LIT(0x84a5ed0c96ee4005), +W64LIT(0x33b8d3f0aeefcb44), +W64LIT(0x57c5da27d7542567), +W64LIT(0x32c4fe91c6a777eb), +W64LIT(0x3439102243e215e3), +W64LIT(0xc7714c6bb5d1dc52), +W64LIT(0x3fb7fa6351650f54), +W64LIT(0x87219aaf2e367101), +W64LIT(0xf5b5b2fa7376abb9), +W64LIT(0x412cfba5f3af11fc), +W64LIT(0xdceb691b06e89076), +W64LIT(0xbb12176fc78b4f51), +W64LIT(0x73e8053435086617), +W64LIT(0xe220be193fc5238d), +W64LIT(0xb09cfd2ed50c55e6), +W64LIT(0xb9ea4dad171bc2fa), +W64LIT(0x9e43e51d4d9fb08e), +W64LIT(0x36c14ae093729848), +W64LIT(0xa9fe829cb6a59469), +W64LIT(0x0405b47155d5efa3), +W64LIT(0x0af2c7207acfa618), +W64LIT(0x7e9b01c6a2ca1ea8), +W64LIT(0xdd97447a6ea02cd9), +W64LIT(0x0781c3d2ed0ddea7), +W64LIT(0x7866ef75278f7ca0), +W64LIT(0xd1986de9912ae8c9), +W64LIT(0xcb7e65f84a5b1842), +W64LIT(0xcd838b4bcf1e7a4a), +W64LIT(0xab06d85e663519c2), +W64LIT(0xd4e1f4f9acb7bbc5), +W64LIT(0xfdbf2f18d929800a), +W64LIT(0xf23471289e7b751e), +W64LIT(0xbc93d4bd2a8691f6), +W64LIT(0x3d4fa0a181f582ff), +W64LIT(0xba6e3a0eafc3f3fe), +W64LIT(0x5ab6ded540965dd8), +W64LIT(0xeb560e9afdd2b491), +W64LIT(0x0976b083c217971c), +W64LIT(0xecd7cd4810df6a36), +W64LIT(0x23ac1cc10f519dd7), +W64LIT(0xbe6b8e7ffa161c5d), +W64LIT(0x7fe72ca7ca82a207), +W64LIT(0xc0f08fb958dc02f5), +W64LIT(0x7a9eb5b7f71ff10b), +W64LIT(0xa709f1cd99bfddd2), +W64LIT(0x8dd35d8f54f9d719), +W64LIT(0x8caf70ee3cb16bb6), +W64LIT(0xe4dd50aaba804185), +W64LIT(0x83242ede7be39ea2), +W64LIT(0x98be0baec8dad286), +W64LIT(0x690e0d25ee79969c), +W64LIT(0x95cd0f5c5f18aa39), +W64LIT(0x56b9f746bf1c99c8), +W64LIT(0x7469c6e6d805b8b0), +W64LIT(0x8a529e5db9f409be), +W64LIT(0xe6250a686a10cc2e), +W64LIT(0x2fa33552f0db59c7), +W64LIT(0x42a88c064b7720f8), +W64LIT(0x6d0bb954bbac793f), +W64LIT(0x181e52d30be17d20), +W64LIT(0xbf17a31e925ea0f2), +W64LIT(0x94b1223d37501696), +W64LIT(0xe8d27939450a8595), +W64LIT(0xccffa62aa756c6e5), +W64LIT(0x383639b1bc68d1f3), +W64LIT(0xee2f978ac04fe79d), +W64LIT(0xa30c45bccc6a3271), +W64LIT(0x1f9f9101e6eca387), +W64LIT(0xb1e0d04fbd44e949), +W64LIT(0x242ddf13e25c4370), +W64LIT(0x156d56219c23059f), +W64LIT(0x88aac49f69648415), +W64LIT(0x6280e764fcfe8c2b), +W64LIT(0xdf6f1eb8be30a172), +W64LIT(0xe5a17dcbd2c8fd2a), +W64LIT(0xe0d8e4dbef55ae26), +W64LIT(0x63fcca0594b63084), +W64LIT(0xa1f41f7e1cfabfda), +W64LIT(0x295edbe1759e3bcf), +W64LIT(0x67f97e74c163df27), +W64LIT(0x038477a3b8d83104), +W64LIT(0xde1333d9d6781ddd), +W64LIT(0x3ace63736cf85c58), +W64LIT(0xd619ae3b7c27366e), +W64LIT(0x5bcaf3b428dee177), +W64LIT(0xb3188a8d6dd464e2), +W64LIT(0x1c1be6a25e349283), +W64LIT(0x017c2d616848bcaf), +W64LIT(0x8e572a2cec21e61d), +W64LIT(0xf631c559cbae9abd), +W64LIT(0x81dc741cab731309), +W64LIT(0xff4775da09b90da1), +W64LIT(0xb499495f80d9ba45), +W64LIT(0x0f8b5e304752f514), +W64LIT(0x394a14d0d4206d5c), +W64LIT(0xce07fce877c64b4e), +W64LIT(0xf4c99f9b1b3e1716), +W64LIT(0xc4f53bc80d09ed56), +W64LIT(0xc208d57b884c8f5e), +W64LIT(0x080a9de2aa5f2bb3), +W64LIT(0x314089327e7f46ef), +W64LIT(0xfa3eecca34245ead), +W64LIT(0x20286b62b789acd3), +W64LIT(0x7515eb87b04d041f), +W64LIT(0x513834945211476f), +W64LIT(0x650124b611f3528c), +W64LIT(0x17950ce34cb38834), +W64LIT(0x45294fd4a67afe5f), +W64LIT(0x21544603dfc1107c), +W64LIT(0x485a4b2631b886e0), +W64LIT(0x6872204486312a33), +W64LIT(0x647d09d779bbee23), +W64LIT(0x2551f2728a14ffdf), +W64LIT(0xd765835a146f8ac1), +W64LIT(0xd21c1a4a29f2d9cd), +W64LIT(0x99c226cfa0926e29), +W64LIT(0xfb42c1ab5c6ce202), +W64LIT(0xc374f81ae00433f1), +W64LIT(0x964978ffe7c09b3d), +W64LIT(0xf74de838a3e62612), +/* box 5 */ +W64LIT(0x74b87b36b0592c6a), +W64LIT(0x3d82d75dffb4b81c), +W64LIT(0x8884246715267825), +W64LIT(0xdaf2d8a77ed4e5de), +W64LIT(0xfeb118650e53f9c7), +W64LIT(0xbd2d1aea59226b06), +W64LIT(0x26ce87f6dbabb191), +W64LIT(0x32772ecbeb66bd0a), +W64LIT(0xd4bbf82bc5104c8c), +W64LIT(0x055357720c4e03a1), +W64LIT(0xef5be62a32d0f6fd), +W64LIT(0xbe1c84c45d186aca), +W64LIT(0xacc7e4a565a1643c), +W64LIT(0x8dd7731519687b84), +W64LIT(0x11eafe4f3c830f3a), +W64LIT(0x04ef8e68a358afe5), +W64LIT(0x40ad9ca1534b930d), +W64LIT(0xe44191d4855a5c0e), +W64LIT(0x6001d20b809420f1), +W64LIT(0x73666b70173b8243), +W64LIT(0x372479b9e728beab), +W64LIT(0x45fecbd35f0590ac), +W64LIT(0x7057f55e1301838f), +W64LIT(0xff0dc17fa1455583), +W64LIT(0x0cc467b810e804da), +W64LIT(0xb9c29482fa7ac4e3), +W64LIT(0xa003831d754960e6), +W64LIT(0x8a096353be0ad5ad), +W64LIT(0xdd2cc8e1d9b64bf7), +W64LIT(0xc7dc415052bfee3e), +W64LIT(0x9f0c137421d17572), +W64LIT(0x35a93e8d4c041323), +W64LIT(0x9a5f44062d9f76d3), +W64LIT(0x71eb2c44bc172fcb), +W64LIT(0x0ff5f99614d20516), +W64LIT(0x7789e518b4632da6), +W64LIT(0xc99561dce97b476c), +W64LIT(0x5276fcc06bf29dfb), +W64LIT(0x4a0b32454bd795ba), +W64LIT(0x9274add69e2fddec), +W64LIT(0x4f5865374799961b), +W64LIT(0xb2d8e37c4df06e10), +W64LIT(0xc4eddf7e5685eff2), +W64LIT(0xb3643a66e2e6c254), +W64LIT(0xd50721316a06e0c8), +W64LIT(0x8bb5ba49111c79e9), +W64LIT(0x2bb639546455190f), +W64LIT(0xf8d3d1390627fbaa), +W64LIT(0x38d1802ff3fabbbd), +W64LIT(0xdfa18fd5729ae67f), +W64LIT(0x4ee4bc2de88f3a5f), +W64LIT(0xf72628af12f5febc), +W64LIT(0x0aa6aee4189c06b7), +W64LIT(0x0000000000000000), +W64LIT(0x9eb0ca6e8ec7d936), +W64LIT(0xcb1826e84257eae4), +W64LIT(0x187dce8520250841), +W64LIT(0xc28f16225ef1ed9f), +W64LIT(0xc333cf38f1e741db), +W64LIT(0x4220db95f8673e85), +W64LIT(0xdc9011fb76a0e7b3), +W64LIT(0x105627559395a37e), +W64LIT(0x2f59b73cc70db6ea), +W64LIT(0xe112c6a689145faf), +W64LIT(0x82228a830dba7e92), +W64LIT(0x2ee56e26681b1aae), +W64LIT(0x2a0ae04ecb43b54b), +W64LIT(0x47738ce7f4293d24), +W64LIT(0xa7dd935bd22bcecf), +W64LIT(0xd2d93177cd644ee1), +W64LIT(0xebb4684291885918), +W64LIT(0x0e49208cbbc4a952), +W64LIT(0xa550d46f79076347), +W64LIT(0x411145bbfc5d3f49), +W64LIT(0xe6ccd6e02e76f186), +W64LIT(0x4bb7eb5fe4c139fe), +W64LIT(0x5d8305567f2098ed), +W64LIT(0x95aabd90394d73c5), +W64LIT(0x25ff19d8df91b05d), +W64LIT(0x86cd04ebaee2d177), +W64LIT(0x03319e2e043a01cc), +W64LIT(0x6b1ba5f5371e8a02), +W64LIT(0x76353c021b7581e2), +W64LIT(0x64ee5c6323cc8f14), +W64LIT(0x5c3fdc4cd03634a9), +W64LIT(0x6996e2c19c32278a), +W64LIT(0x8938fd7dba30d461), +W64LIT(0x7b4d82a0a48b297c), +W64LIT(0xbfa05ddef20ec68e), +W64LIT(0x8ee6ed3b1d527a48), +W64LIT(0x61bd0b112f828cb5), +W64LIT(0x66631b5788e0229c), +W64LIT(0x55a8ec86cc9033d2), +W64LIT(0x1c9240ed837da7a4), +W64LIT(0x150570279fdba0df), +W64LIT(0x53ca25dac4e431bf), +W64LIT(0xd636bf1f6e3ce104), +W64LIT(0xcaa4fff2ed4146a0), +W64LIT(0x787c1c8ea0b128b0), +W64LIT(0xad7b3dbfcab7c878), +W64LIT(0xfc3c5f51a57f544f), +W64LIT(0xb78bb40e41be6db1), +W64LIT(0x8c6baa0fb67ed7c0), +W64LIT(0xce4b719a4e19e945), +W64LIT(0xf96f0823a93157ee), +W64LIT(0x7d2f4bfcacff2b11), +W64LIT(0x3eb34973fb8eb9d0), +W64LIT(0xe39f81922238f227), +W64LIT(0x239dd084d7e5b230), +W64LIT(0x1fa3dec38747a668), +W64LIT(0xc5510664f99343b6), +W64LIT(0xc829b8c6466deb28), +W64LIT(0x85fc9ac5aad8d0bb), +W64LIT(0xb6376d14eea8c1f5), +W64LIT(0x9d8154408afdd8fa), +W64LIT(0x3be01e01f7c0ba71), +W64LIT(0x628c953f2bb88d79), +W64LIT(0x6d796ca93f6a886f), +W64LIT(0xfa5e960dad0b5622), +W64LIT(0xe5fd48ce2a4cf04a), +W64LIT(0xe7700ffa81605dc2), +W64LIT(0x2dd4f0086c211b62), +W64LIT(0x2221099e78f31e74), +W64LIT(0xdb4e01bdd1c2499a), +W64LIT(0xf417b68116cfff70), +W64LIT(0xb506f33aea92c039), +W64LIT(0x514762ee6fc89c37), +W64LIT(0x9c3d8d5a25eb74be), +W64LIT(0x396d59355cec17f9), +W64LIT(0xccc636aee53544cd), +W64LIT(0x0b1a77feb78aaaf3), +W64LIT(0xe9392f763aa4f490), +W64LIT(0xaaa52df96dd56651), +W64LIT(0x46cf55fd5b3f9160), +W64LIT(0xa4ec0d75d611cf03), +W64LIT(0xaff67a8b619b65f0), +W64LIT(0x3415e797e312bf67), +W64LIT(0x7af15bba0b9d8538), +W64LIT(0x811314ad09807f5e), +W64LIT(0x8771ddf101f47d33), +W64LIT(0x969b23be3d777209), +W64LIT(0xd365e86d6272e2a5), +W64LIT(0x58d05224736e9b4c), +W64LIT(0xc660984afda9427a), +W64LIT(0x5414359c63869f96), +W64LIT(0xe885f66c95b258d4), +W64LIT(0x655285798cda2350), +W64LIT(0x6cc5b5b3907c242b), +W64LIT(0x6ff42b9d944625e7), +W64LIT(0xc0025116f5dd4017), +W64LIT(0xa28ec429de65cd6e), +W64LIT(0x63304c2584ae213d), +W64LIT(0x7fa20cc807d38699), +W64LIT(0x996eda2829a5771f), +W64LIT(0x1b4c50ab241f098d), +W64LIT(0x1e1f07d928510a2c), +W64LIT(0x33cbf7d14470114e), +W64LIT(0xb055a448e6dcc398), +W64LIT(0x98d2033286b3db5b), +W64LIT(0xec6a780436eaf731), +W64LIT(0xa1bf5a07da5fcca2), +W64LIT(0xbaf30aacfe40c52f), +W64LIT(0xf144e1f31a81fcd1), +W64LIT(0xe0ae1fbc2602f3eb), +W64LIT(0x14b9a93d30cd0c9b), +W64LIT(0x596c8b3edc783708), +W64LIT(0x682a3bdb33248bce), +W64LIT(0xb87e4d98556c68a7), +W64LIT(0x80afcdb7a696d31a), +W64LIT(0x5725abb267bc9e5a), +W64LIT(0x914533f89a15dc20), +W64LIT(0x5eb29b787b1a9921), +W64LIT(0x01bcd91aaf16ac44), +W64LIT(0xc1be880c5acbec53), +W64LIT(0xedd6a11e99fc5b75), +W64LIT(0x028d4734ab2cad88), +W64LIT(0x8f5a3421b244d60c), +W64LIT(0x4dd52203ecb53b93), +W64LIT(0x3f0f906954981594), +W64LIT(0xae4aa391ce8dc9b4), +W64LIT(0x3698a0a3483e12ef), +W64LIT(0xf5ab6f9bb9d95334), +W64LIT(0x082be9d0b3b0ab3f), +W64LIT(0xd1e8af59c95e4f2d), +W64LIT(0xd87f9f93d5f84856), +W64LIT(0x6e48f2873b5089a3), +W64LIT(0x2443c0c270871c19), +W64LIT(0xb1e97d5249ca6fdc), +W64LIT(0x7c9392e603e98755), +W64LIT(0x839e5399a2acd2d6), +W64LIT(0x19c1179f8f33a405), +W64LIT(0xde1d56cfdd8c4a3b), +W64LIT(0x20ac4eaad3dfb3fc), +W64LIT(0x1af089b18b09a5c9), +W64LIT(0x3a5cc71b58d61635), +W64LIT(0x444212c9f0133ce8), +W64LIT(0x72dab26ab82d2e07), +W64LIT(0x4c69fb1943a397d7), +W64LIT(0xf3c9a6c7b1ad5159), +W64LIT(0x1d2e99f72c6b0be0), +W64LIT(0xb4ba2a2045846c7d), +W64LIT(0xe22358888d2e5e63), +W64LIT(0x2887a77a606f18c3), +W64LIT(0xa8286acdc6f9cbd9), +W64LIT(0x5f0e4262d40c3565), +W64LIT(0xeee73f309dc65ab9), +W64LIT(0x9be39d1c8289da97), +W64LIT(0x1634ee099be1a113), +W64LIT(0xea08b1583e9ef55c), +W64LIT(0x9727faa49261de4d), +W64LIT(0x2c682912c337b726), +W64LIT(0xcff7a880e10f4501), +W64LIT(0x1788371334f70d57), +W64LIT(0x27725eec74bd1dd5), +W64LIT(0x3146b0e5ef5cbcc6), +W64LIT(0x099730ca1ca6077b), +W64LIT(0xf2757fdd1ebbfd1d), +W64LIT(0x6aa77cef98082646), +W64LIT(0xbb4fd3b65156696b), +W64LIT(0x569972a8c8aa321e), +W64LIT(0xa3321d337173612a), +W64LIT(0x50fbbbf4c0de3073), +W64LIT(0x5a5d1510d84236c4), +W64LIT(0xfd80864b0a69f80b), +W64LIT(0x07de1046a762ae29), +W64LIT(0xa6614a417d3d628b), +W64LIT(0xd78a6605c12a4d40), +W64LIT(0x67dfc24d27f68ed8), +W64LIT(0xbc91c3f0f634c742), +W64LIT(0xd05476436648e369), +W64LIT(0x493aac6b4fed9476), +W64LIT(0x12db606138b90ef6), +W64LIT(0xa994b3d769ef679d), +W64LIT(0x211097b07cc91fb8), +W64LIT(0x30fa69ff404a1082), +W64LIT(0x3c3e0e4750a21458), +W64LIT(0x7504a22c1f4f802e), +W64LIT(0x844043df05ce7cff), +W64LIT(0xf0f838e9b5975095), +W64LIT(0x7e1ed5d2a8c52add), +W64LIT(0x90f9eae235037064), +W64LIT(0x0662c95c0874026d), +W64LIT(0x9416648a965bdf81), +W64LIT(0xf69af1b5bde352f8), +W64LIT(0x0d78bea2bffea89e), +W64LIT(0x293b7e60cf79b487), +W64LIT(0xd9c346897aeee412), +W64LIT(0xfbe24f17021dfa66), +W64LIT(0x1367b97b97afa2b2), +W64LIT(0xab19f4e3c2c3ca15), +W64LIT(0x48867571e0fb3832), +W64LIT(0x93c874cc313971a8), +W64LIT(0x79c0c5940fa784f4), +W64LIT(0xcd7aefb44a23e889), +W64LIT(0x439c028f577192c1), +W64LIT(0x5be1cc0a77549a80), +/* box 6 */ +W64LIT(0x714d28d778656928), +W64LIT(0xc88a7c6b84f64f7c), +W64LIT(0xec43cac5ab89aaca), +W64LIT(0x777fa38110dc16a3), +W64LIT(0x0f7d5c87e4213b5c), +W64LIT(0x73f051e5f3a1ef51), +W64LIT(0xea714193c330d541), +W64LIT(0x95e5f3dae016c4f3), +W64LIT(0x63d3738095a0e173), +W64LIT(0x9825d66f8ff379d6), +W64LIT(0xe8cc38a148f45338), +W64LIT(0xa840b0c025f06bb0), +W64LIT(0x944135c35f748735), +W64LIT(0x74661caa247ad31c), +W64LIT(0xe7b16426acd56864), +W64LIT(0xd1e689df6e6f0589), +W64LIT(0xa73dec47c1d150ec), +W64LIT(0x64453ecf427bdd3e), +W64LIT(0x0ed99a9e5b43789a), +W64LIT(0x7b1b402dc05be840), +W64LIT(0x0dc025b56fe5bd25), +W64LIT(0x3f183a284e22293a), +W64LIT(0xa0aba108160a6ca1), +W64LIT(0x46be033705bd4703), +W64LIT(0x86df6e94b2b10f6e), +W64LIT(0xa216d83a9dceead8), +W64LIT(0x129e5b57edc5885b), +W64LIT(0x7e3074509c445274), +W64LIT(0x7d29cb7ba8e297cb), +W64LIT(0x1611a9330eb871a9), +W64LIT(0x486799a95efe3f99), +W64LIT(0x9fb39b205828459b), +W64LIT(0xd0424fc6d10d464f), +W64LIT(0xe968feb8f79610fe), +W64LIT(0x5d6f8fb164e08b8f), +W64LIT(0xaafdc9f2ae34edc9), +W64LIT(0x02bd79328bc48679), +W64LIT(0x9b3c6944bb55bc69), +W64LIT(0x6277b5992ac2a2b5), +W64LIT(0x877ba88d0dd34ca8), +W64LIT(0xfa5263f6a531db63), +W64LIT(0x2e9fde54974164de), +W64LIT(0xcda14816d8e9f548), +W64LIT(0x675c81e476dd1881), +W64LIT(0x2a102c30743c9d2c), +W64LIT(0x37f32be07dd82e2b), +W64LIT(0x256d70b7901da670), +W64LIT(0x4ce86bcdbd83c66b), +W64LIT(0x50afaa040b0536aa), +W64LIT(0xef5a75ee9f2f6f75), +W64LIT(0xb3913c4644ada73c), +W64LIT(0x1187e47cd9634de4), +W64LIT(0xc54a59deeb13f259), +W64LIT(0x0000000000000000), +W64LIT(0x01a4c619bf6243c6), +W64LIT(0x90cec7a7bc097ec7), +W64LIT(0xf94bdcdd91971edc), +W64LIT(0x8e347f5c814b087f), +W64LIT(0xc7f720ec60d77420), +W64LIT(0x354e52d2f61ca852), +W64LIT(0x34ea94cb497eeb94), +W64LIT(0xae723b964d49143b), +W64LIT(0xf48bf968fe72a3f9), +W64LIT(0xfc60e8a0cd88a4e8), +W64LIT(0x2909931b409a5893), +W64LIT(0xbd48a6d81feedfa6), +W64LIT(0x6cae2f077181da2f), +W64LIT(0xad6b84bd79efd184), +W64LIT(0x18c833ad55fb0933), +W64LIT(0x204644cacc021c44), +W64LIT(0x392ab17e269b56b1), +W64LIT(0x14acd001857cf7d0), +W64LIT(0x8abb8d386236f18d), +W64LIT(0xeefeb3f7204d2cb3), +W64LIT(0xf636805a75b62580), +W64LIT(0x2bb4ea29cb5edeea), +W64LIT(0xc653e6f5dfb537e6), +W64LIT(0x8d2dc077b5edcdc0), +W64LIT(0x31c1a0b6156151a0), +W64LIT(0xf8ef1ac42ef55d1a), +W64LIT(0xdbb0e125d65184e1), +W64LIT(0x82509cf051ccf69c), +W64LIT(0xe33e96424fa89196), +W64LIT(0xdf3f1341352c7d13), +W64LIT(0x8f90b9453e294bb9), +W64LIT(0x1023226566010e22), +W64LIT(0xa58095754a15d695), +W64LIT(0x2c22a7661c85e2a7), +W64LIT(0xe183ef70c46c17ef), +W64LIT(0xafd6fd8ff22b57fd), +W64LIT(0x471ac52ebadf04c5), +W64LIT(0x4d4cadd402e185ad), +W64LIT(0x916a01be036b3d01), +W64LIT(0x28ad5502fff81b55), +W64LIT(0x3657edf9c2ba6ded), +W64LIT(0xd2ff36f45ac9c036), +W64LIT(0xf1a0cd15a26d19cd), +W64LIT(0xd90d98175d950298), +W64LIT(0xf7924643cad46646), +W64LIT(0xdd826a73bee8fb6a), +W64LIT(0x9d0ee212d3ecc3e2), +W64LIT(0xb6ba083b18b21d08), +W64LIT(0x3da5431ac5e6af43), +W64LIT(0x08eb11c833fa0711), +W64LIT(0x052b347d5c1fba34), +W64LIT(0x6fb7902c45271f90), +W64LIT(0x133a9d4e52a7cb9d), +W64LIT(0x6e135635fa455c56), +W64LIT(0x725497fc4cc3ac97), +W64LIT(0xf31db42729a99fb4), +W64LIT(0x846217a639758917), +W64LIT(0x4b7e26826a58fa26), +W64LIT(0x235ffbe1f8a4d9fb), +W64LIT(0xff79578bf92e6157), +W64LIT(0xda14273c6933c727), +W64LIT(0x8b1f4b21dd54b24b), +W64LIT(0x9caa240b6c8e8024), +W64LIT(0xc1c5abba086e0bab), +W64LIT(0xde9bd5588a4e3ed5), +W64LIT(0x2d86617fa3e7a161), +W64LIT(0xbff5dfea942a59df), +W64LIT(0x66f847fdc9bf5b47), +W64LIT(0x3b97c84cad5fd0c8), +W64LIT(0x3ebcfc31f1406afc), +W64LIT(0xca3705590f32c905), +W64LIT(0x24c9b6ae2f7fe5b6), +W64LIT(0x408c88616d043888), +W64LIT(0x93d7788c88afbb78), +W64LIT(0x196cf5b4ea994af5), +W64LIT(0x9a98af5d0437ffaf), +W64LIT(0x8c89066e0a8f8e06), +W64LIT(0xab590feb1156ae0f), +W64LIT(0xd7d4028906d67a02), +W64LIT(0xe4a8db0d9873addb), +W64LIT(0xc378d28883aa8dd2), +W64LIT(0x4ff1d4e6892503d4), +W64LIT(0xd670c490b9b439c4), +W64LIT(0x65e1f8d6fd199ef8), +W64LIT(0xf2b9723e96cbdc72), +W64LIT(0xb12c4574cf692145), +W64LIT(0x569d215263bc4921), +W64LIT(0x69851b7a2d9e601b), +W64LIT(0x5e76309a50464e30), +W64LIT(0x5fd2f683ef240df6), +W64LIT(0xd8a95e0ee2f7415e), +W64LIT(0xe29a505bf0cad250), +W64LIT(0x96fc4cf1d4b0014c), +W64LIT(0x8806f40ae9f277f4), +W64LIT(0x53b6152f3fa3f315), +W64LIT(0x1c47c1c9b686f0c1), +W64LIT(0x80ede5c2da0870e5), +W64LIT(0xd5697bbb8d12fc7b), +W64LIT(0xfdc42eb972eae72e), +W64LIT(0x0bf2aee3075cc2ae), +W64LIT(0x22fb3df847c69a3d), +W64LIT(0xbadeeb97c835e3eb), +W64LIT(0xdc26ac6a018ab8ac), +W64LIT(0xbcec60c1a08c9c60), +W64LIT(0x4231f153e6c0bef1), +W64LIT(0x337cd9849ea5d7d9), +W64LIT(0x5b5d04e70c59f404), +W64LIT(0x79a6391f4b9f6e39), +W64LIT(0x5212d33680c1b0d3), +W64LIT(0xb5a3b7102c14d8b7), +W64LIT(0x7f94b249232611b2), +W64LIT(0x17b56f2ab1da326f), +W64LIT(0x59e07dd5879d727d), +W64LIT(0xebd5878a7c529687), +W64LIT(0xbb7a2d8e7757a02d), +W64LIT(0x0319bf2b34a6c5bf), +W64LIT(0x5ccb49a8db82c849), +W64LIT(0x1de307d009e4b307), +W64LIT(0x49c35fb0e19c7c5f), +W64LIT(0x55849e79571a8c9e), +W64LIT(0x7abf86347f39ab86), +W64LIT(0x9273be9537cdf8be), +W64LIT(0xe615a23f13b72ba2), +W64LIT(0x6821dd6392fc23dd), +W64LIT(0x5af9c2feb33bb7c2), +W64LIT(0x06328b5668b97f8b), +W64LIT(0x44037a058e79c17a), +W64LIT(0x83f45ae9eeaeb55a), +W64LIT(0x5739e74bdcde0ae7), +W64LIT(0xfbf6a5ef1a5398a5), +W64LIT(0xe50c1d142711ee1d), +W64LIT(0x1a754a9fde3f8f4a), +W64LIT(0x7802ff06f4fd2dff), +W64LIT(0xf52f3f714110e03f), +W64LIT(0x2674cf9ca4bb63cf), +W64LIT(0x60caccaba10624cc), +W64LIT(0xb088836d700b6283), +W64LIT(0xa6992a5e7eb3132a), +W64LIT(0xa9e476d99a922876), +W64LIT(0x6b386248a65ae662), +W64LIT(0xc2dc14913cc8ce14), +W64LIT(0x76db6598afbe5565), +W64LIT(0x32d81f9d21c7941f), +W64LIT(0x21e282d373605f82), +W64LIT(0xc0616da3b70c486d), +W64LIT(0x616e0ab21e64670a), +W64LIT(0x6d0ae91ecee399e9), +W64LIT(0x27d009851bd92009), +W64LIT(0xfedd9192464c2291), +W64LIT(0x45a7bc1c311b82bc), +W64LIT(0x54205860e878cf58), +W64LIT(0xa10f6711a9682f67), +W64LIT(0x9981107630913a10), +W64LIT(0xede70cdc14ebe90c), +W64LIT(0x70e9eecec7072aee), +W64LIT(0x1f5e7ee28220357e), +W64LIT(0x2f3b184d28232718), +W64LIT(0x41284e78d2667b4e), +W64LIT(0xa424536cf5779553), +W64LIT(0xa3b21e2322aca91e), +W64LIT(0x4e5512ff36474012), +W64LIT(0x1efab8fb3d4276b8), +W64LIT(0x89a2321356903432), +W64LIT(0xcb93c340b0508ac3), +W64LIT(0x306566afaa031266), +W64LIT(0x4adae09bd53ab9e0), +W64LIT(0xc92eba723b940cba), +W64LIT(0x094fd7d18c9844d7), +W64LIT(0xcc058e0f678bb68e), +W64LIT(0xd4cdbda23270bfbd), +W64LIT(0x0a5668fab83e8168), +W64LIT(0x510b6c1db467756c), +W64LIT(0xb86392a543f16592), +W64LIT(0x048ff264e37df9f2), +W64LIT(0x3a330e55123d930e), +W64LIT(0xb235fa5ffbcfe4fa), +W64LIT(0xb9c754bcfc932654), +W64LIT(0x3c0185037a84ec85), +W64LIT(0x0c64e3acd087fee3), +W64LIT(0xe02729697b0e5429), +W64LIT(0x07964d4fd7db3c4d), +W64LIT(0x814923db656a3323), +W64LIT(0x388e776799f91577), +W64LIT(0x6a9ca4511938a5a4), +W64LIT(0x1bd18c86615dcc8c), +W64LIT(0xb407710993769b71), +W64LIT(0x150816183a1eb416), +W64LIT(0x4395374a59a2fd37), +W64LIT(0xc4ee9fc75471b19f), +W64LIT(0x5844bbcc38ff31bb), +W64LIT(0xcf1c3124532d7331), +W64LIT(0xb71ece22a7d05ece), +W64LIT(0xaccf42a4c68d9242), +W64LIT(0x97588ae86bd2428a), +W64LIT(0x75c2dab39b1890da), +W64LIT(0x9e175d39e74a065d), +W64LIT(0xf0040b0c1d0f5a0b), +W64LIT(0xceb8f73dec4f30f7), +W64LIT(0xbe5119f32b481a19), +W64LIT(0xd35bf0ede5ab83f0), +W64LIT(0x7c8d0d621780d40d), +W64LIT(0x85c6d1bf8617cad1), +/* box 7 */ +W64LIT(0xb1c742127b66f2a4), +W64LIT(0xce916098d7a59fc1), +W64LIT(0xc312ef8e2406fa70), +W64LIT(0x956c7dced81403d5), +W64LIT(0x5a0c9b2318dd9520), +W64LIT(0xad0d57f51a480e8b), +W64LIT(0xe7b9d05287740b01), +W64LIT(0x0217f9ea2ed81268), +W64LIT(0x4d7cff19f8cd3a06), +W64LIT(0x44d1772e572b7b67), +W64LIT(0xfb73c5b5e65af72e), +W64LIT(0x91427aef84512705), +W64LIT(0x0c720963e4cf6c85), +W64LIT(0x87c398a0732d8117), +W64LIT(0xa17f5e96fe87620e), +W64LIT(0x50476c8b8e8fcf1d), +W64LIT(0xcb4ee1cc9c8cb225), +W64LIT(0x67b2304c91a8b59a), +W64LIT(0x54696baad2caebcd), +W64LIT(0xddcf03836bf01437), +W64LIT(0x46c68ec479f3690f), +W64LIT(0x8f9f96e2cba7c942), +W64LIT(0xe1802e99f5e93db9), +W64LIT(0x4e9a8086c179215a), +W64LIT(0xf0c9b4686764a427), +W64LIT(0xfd4a3b7e94c7c196), +W64LIT(0xfcbbbd0b83abc8a2), +W64LIT(0xebcbd93163bb6784), +W64LIT(0xf9643c5fc882e546), +W64LIT(0xc4da973041f7c5fc), +W64LIT(0x1af3eb2c13b3ca97), +W64LIT(0x6e1fb87b3e4ef4fb), +W64LIT(0x5e229c024498b1f0), +W64LIT(0xf516353c2c4d89c3), +W64LIT(0xcc869972f97d8da9), +W64LIT(0x8d886f08e57fdb2a), +W64LIT(0x1cca15e7612efc2f), +W64LIT(0x567e9240fc12f9a5), +W64LIT(0x43190f9032da44eb), +W64LIT(0xfeac44e1ad73daca), +W64LIT(0x07c878be65f13f8c), +W64LIT(0x618bce87e3358322), +W64LIT(0xf895ba2adfeeec72), +W64LIT(0x751dd5223a913758), +W64LIT(0x59eae4bc21698e7c), +W64LIT(0xff5dc294ba1fd3fe), +W64LIT(0x03e67f9f39b41b5c), +W64LIT(0x2292c117d1efc7c9), +W64LIT(0x8a4017b6808ee4a6), +W64LIT(0xd1bd0ae08f3f78b2), +W64LIT(0x135e631bbc558bf6), +W64LIT(0xee14586528924a60), +W64LIT(0x8857ee5cae56f6ce), +W64LIT(0x0000000000000000), +W64LIT(0x0e65f089ca177eed), +W64LIT(0x34132358269361db), +W64LIT(0x15679dd0cec8bd4e), +W64LIT(0x800be01e16dcbe9b), +W64LIT(0x949dfbbbcf780ae1), +W64LIT(0xe397d773db312fd1), +W64LIT(0xedf227fa1126513c), +W64LIT(0xb5e945332723d674), +W64LIT(0x53a11314b73bd441), +W64LIT(0x23634762c683cefd), +W64LIT(0x4b4501d28a500cbe), +W64LIT(0x473708b16e9f603b), +W64LIT(0x1770643ae010af26), +W64LIT(0xa746a05d8c1a54b6), +W64LIT(0x90b3fc9a933d2e31), +W64LIT(0x35e2a52d31ff68ef), +W64LIT(0xab34a93e68d53833), +W64LIT(0xd81082d720d939d3), +W64LIT(0xb86aca25d480b3c5), +W64LIT(0xdfd8fa694528065f), +W64LIT(0x4f6b06f3d615286e), +W64LIT(0x578f1435eb7ef091), +W64LIT(0x9af80b32056f740c), +W64LIT(0x92a40570bde53c59), +W64LIT(0xdbf6fd48196d228f), +W64LIT(0x1b026d5904dfc3a3), +W64LIT(0x3c4f2d1a9e19298e), +W64LIT(0xc8a89e53a538a979), +W64LIT(0x991e74ad3cdb6f50), +W64LIT(0x042e07215c4524d0), +W64LIT(0x8e6e1097dccbc076), +W64LIT(0xe071a8ece285348d), +W64LIT(0xd784f42bfda24e0a), +W64LIT(0x7d41db60821b7f0d), +W64LIT(0x85d4614a5df5937f), +W64LIT(0xbb8cb5baed34a899), +W64LIT(0x40ff700f0b6e5fb7), +W64LIT(0x2cf7319e1bf8b924), +W64LIT(0x3a76d3d1ec841f36), +W64LIT(0x4520f15b40477253), +W64LIT(0xf138321d7008ad13), +W64LIT(0x42e889e525b64ddf), +W64LIT(0x65a5c9a6bf70a7f2), +W64LIT(0x208538fdff37d5a1), +W64LIT(0x410ef67a1c025683), +W64LIT(0x18e412c63d6bd8ff), +W64LIT(0x72d5ad9c5f6008d4), +W64LIT(0x255ab9a9b41ef845), +W64LIT(0x93558305aa89356d), +W64LIT(0x70c2547671b81abc), +W64LIT(0x3604dab2084b73b3), +W64LIT(0x05df81544b292de4), +W64LIT(0xf2de4d8249bcb64f), +W64LIT(0x0bba71dd813e5309), +W64LIT(0xa368a77cd05f7066), +W64LIT(0x796fdc41de5e5bdd), +W64LIT(0xec03a18f064a5808), +W64LIT(0x085c0e42b88a4855), +W64LIT(0x274d40439ac6ea2d), +W64LIT(0x31cca20c6dba4c3f), +W64LIT(0x322add93540e5763), +W64LIT(0xb60f3aac1e97cd28), +W64LIT(0x7cb05d1595777639), +W64LIT(0xb036c4676c0afb90), +W64LIT(0x0a4bf7a896525a3d), +W64LIT(0x73242be9480c01e0), +W64LIT(0x5bfd1d560fb19c14), +W64LIT(0x7b7825abf08649b5), +W64LIT(0xb7febcd909fbc41c), +W64LIT(0x81fa666b01b0b7af), +W64LIT(0xd25b757fb68b63ee), +W64LIT(0x0d838f16f3a365b1), +W64LIT(0x6a31bf5a620bd02b), +W64LIT(0x26bcc6368daae319), +W64LIT(0x9ed60c13592a50dc), +W64LIT(0x581b62c936058748), +W64LIT(0x9cc1f5f977f242b4), +W64LIT(0x83ed9f812f68a5c7), +W64LIT(0x74ec53572dfd3e6c), +W64LIT(0xb3d0bbf855bee0cc), +W64LIT(0xacfcd1800d2407bf), +W64LIT(0x303d24797ad6450b), +W64LIT(0x7a89a3dee7ea4081), +W64LIT(0x69d7c0c55bbfcb77), +W64LIT(0x770a2cc814492530), +W64LIT(0x0f9476fcdd7b77d9), +W64LIT(0xaeeb286a23fc15d7), +W64LIT(0x2174be88e85bdc95), +W64LIT(0xde297c1c52440f6b), +W64LIT(0xd04c8c9598537186), +W64LIT(0x2ee0c8743520ab4c), +W64LIT(0x977b8424f6cc11bd), +W64LIT(0x10b81c8485e190aa), +W64LIT(0xa4a0dfc2b5ae4fea), +W64LIT(0x98eff2d82bb76664), +W64LIT(0xa8d2d6a15161236f), +W64LIT(0xd4628bb4c4165556), +W64LIT(0x682646b04cd3c243), +W64LIT(0x2d06b7eb0c94b010), +W64LIT(0x626db118da81987e), +W64LIT(0x2928b0ca50d194c0), +W64LIT(0x6df9c7e407faefa7), +W64LIT(0x1681e24ff77ca612), +W64LIT(0x4952f838a4881ed6), +W64LIT(0x76fbaabd03252c04), +W64LIT(0xc73ce8af7843dea0), +W64LIT(0xe82da6ae5a0f7cd8), +W64LIT(0xc10516640adee818), +W64LIT(0x968a0251e1a01889), +W64LIT(0x37f55cc71f277a87), +W64LIT(0xe5ae29b8a9ac1969), +W64LIT(0xcabf67b98be0bb11), +W64LIT(0xf4e7b3493b2180f7), +W64LIT(0xe9dc20db4d6375ec), +W64LIT(0x639c376dcded914a), +W64LIT(0x12afe56eab3982c2), +W64LIT(0xc2e369fb336af344), +W64LIT(0xa6b726289b765d82), +W64LIT(0x14961ba5d9a4b47a), +W64LIT(0xbc44cd0488c59715), +W64LIT(0xd3aaf30aa1e76ada), +W64LIT(0x28d936bf47bd9df4), +W64LIT(0xaf1aae1f34901ce3), +W64LIT(0x2f114e01224ca278), +W64LIT(0xe648562790180235), +W64LIT(0x24ab3fdca372f171), +W64LIT(0x52509561a057dd75), +W64LIT(0xc6cd6eda6f2fd794), +W64LIT(0xa08ed8e3e9eb6b3a), +W64LIT(0x09ad8837afe64161), +W64LIT(0xbdb54b719fa99e21), +W64LIT(0x8c79e97df213d21e), +W64LIT(0xcf60e6edc0c996f5), +W64LIT(0x5dc4e39d7d2caaac), +W64LIT(0x11499af1928d999e), +W64LIT(0x5fd31a7753f4b8c4), +W64LIT(0x01f18675176c0934), +W64LIT(0xc52b1145569bccc8), +W64LIT(0x9f278a664e4659e8), +W64LIT(0x3dbeab6f897520ba), +W64LIT(0xa2992109c7337952), +W64LIT(0x9b098d4712037d38), +W64LIT(0xc9591826b254a04d), +W64LIT(0x3b8755a4fbe81602), +W64LIT(0xbe5334eea61d857d), +W64LIT(0x51b6eafe99e3c629), +W64LIT(0x191594b32a07d1cb), +W64LIT(0x1f2c6a78589ae773), +W64LIT(0x3fa95285a7ad32d2), +W64LIT(0x5c3565e86a40a398), +W64LIT(0xb2213d8d42d2e9f8), +W64LIT(0xefe5de103ffe4354), +W64LIT(0x4ab487a79d3c058a), +W64LIT(0xcd771f07ee11849d), +W64LIT(0xbfa2b29bb1718c49), +W64LIT(0xba7d33cffa58a1ad), +W64LIT(0x6fee3e0e2922fdcf), +W64LIT(0x64544fd3a81caec6), +W64LIT(0xd9e104a237b530e7), +W64LIT(0xf32fcbf75ed0bf7b), +W64LIT(0x3e58d4f0b0c13be6), +W64LIT(0xb418c346304fdf40), +W64LIT(0xaac52f4b7fb93107), +W64LIT(0xdc3e85f67c9c1d03), +W64LIT(0xd5930dc1d37a5c62), +W64LIT(0x0639fecb729d36b8), +W64LIT(0xc0f490111db2e12c), +W64LIT(0x7ea7a4ffbbaf6451), +W64LIT(0xf6f04aa315f9929f), +W64LIT(0x6643b63986c4bcae), +W64LIT(0x6c0841911096e693), +W64LIT(0x8425e73f4a999a4b), +W64LIT(0x7133d20366d41388), +W64LIT(0x38612a3bc25c0d5e), +W64LIT(0xb99b4c50c3ecbaf1), +W64LIT(0x1d3b93927642f51b), +W64LIT(0x7f56228aacc36d65), +W64LIT(0x9d30738c609e4b80), +W64LIT(0x48a37e4db3e417e2), +W64LIT(0x8bb191c397e2ed92), +W64LIT(0x2acecf5569658f9c), +W64LIT(0xda077b3d0e012bbb), +W64LIT(0xa55159b7a2c246de), +W64LIT(0x33db5be643625e57), +W64LIT(0x821c19f43804acf3), +W64LIT(0x3990ac4ed530046a), +W64LIT(0xd675725eeace473e), +W64LIT(0x789e5a34c93252e9), +W64LIT(0x86321ed564418823), +W64LIT(0xfa8243c0f136fe1a), +W64LIT(0xe45fafcdbec0105d), +W64LIT(0x2b3f49207e0986a8), +W64LIT(0xa92350d4460d2a5b), +W64LIT(0x1eddec0d4ff6ee47), +W64LIT(0x89a66829b93afffa), +W64LIT(0x607a48f2f4598a16), +W64LIT(0x6bc0392f7567d91f), +W64LIT(0xea3a5f4474d76eb0), +W64LIT(0x5598eddfc5a6e2f9), +W64LIT(0x4c8d796cefa13332), +W64LIT(0xf701ccd602959bab), +W64LIT(0xe2665106cc5d26e5), +}; + +const word64 SHARK::Dec::cbox[8][256] = { +/* box 0 */ +W64LIT(0xe6126af05e55aff3), +W64LIT(0x4b6c893f310b0835), +W64LIT(0xaa4c0e84ebfc8d57), +W64LIT(0xfb9b5c7bf3b3090d), +W64LIT(0x4508a6a9ccba5ce2), +W64LIT(0xe5d1d2064dc6bde9), +W64LIT(0x348343755288edde), +W64LIT(0xb684505de46b250c), +W64LIT(0xa8cede205a1e91e8), +W64LIT(0x40b89b46f9fa6acc), +W64LIT(0x8ee1ec1afab080ba), +W64LIT(0xde77d6b7408e0a45), +W64LIT(0x9a3e184c2e455802), +W64LIT(0xbe93fad23f0955ef), +W64LIT(0x3ae76ce3af39b909), +W64LIT(0xad7ee3cf6f5ea7c6), +W64LIT(0x8b51d1f5cff0b694), +W64LIT(0x70ca8d8e3c43bf99), +W64LIT(0xccdba7f8b2a8f6c9), +W64LIT(0x4c5e6474b5a922a4), +W64LIT(0x5d31adcd541ccc32), +W64LIT(0x9b7f701e8c3456a7), +W64LIT(0x2ac9cd08ecfd593a), +W64LIT(0x8fa0844858c18e1f), +W64LIT(0x32f0c66c745bc9ea), +W64LIT(0xc58d6525cbbb888f), +W64LIT(0x8c633cbe4b529c05), +W64LIT(0xf2cd9ea68aa0774b), +W64LIT(0x2cba4811ca2e7d0e), +W64LIT(0xe2e33f4dc9649778), +W64LIT(0xf4be1bbfac73537f), +W64LIT(0x22de6787379f29d9), +W64LIT(0x0956c2dd79137e46), +W64LIT(0xe061efe978868bc7), +W64LIT(0x1cc85ed90f97a85b), +W64LIT(0x31337e9a67c8dbf0), +W64LIT(0x360193d1e36af161), +W64LIT(0x7fefca4a6383e5eb), +W64LIT(0x8535fe633241e243), +W64LIT(0xc3fee03ced68acbb), +W64LIT(0x81c4abdea570dac8), +W64LIT(0x67d6c12efb25753b), +W64LIT(0xa4282112164dd980), +W64LIT(0xcf181f0ea13be4d3), +W64LIT(0xa98fb672f86f9f4d), +W64LIT(0x5c70c59ff66dc297), +W64LIT(0xb0f7d544c2b80138), +W64LIT(0x0da79760ee2246cd), +W64LIT(0x3740fb83411bffc4), +W64LIT(0x24ade29e114c0ded), +W64LIT(0xf858e48de0201b17), +W64LIT(0x0e642f96fdb154d7), +W64LIT(0xddb46e41531d185f), +W64LIT(0x25ec8accb33d0348), +W64LIT(0x0282d0a4b1e21cbf), +W64LIT(0x1bfab3928b3582ca), +W64LIT(0xaffc336bdebcbb79), +W64LIT(0x35c22b27f0f9e37b), +W64LIT(0x03c3b8f61393121a), +W64LIT(0xb8e07fcb19da71db), +W64LIT(0x99fda0ba3dd64a18), +W64LIT(0xce59775c034aea76), +W64LIT(0x49ee599b80e9148a), +W64LIT(0xfe2b6194c6f33f23), +W64LIT(0x4edcb4d0044b3e1b), +W64LIT(0xd5a3c4ce887f68bc), +W64LIT(0xdf36bee5e2ff04e0), +W64LIT(0x171c4ca0c766caa2), +W64LIT(0x0bd41279c8f162f9), +W64LIT(0xe490ba54efb7b34c), +W64LIT(0x5b4228d472cfe806), +W64LIT(0x5355825ba9ad98e5), +W64LIT(0x9f8e25a31b056e2c), +W64LIT(0xcd9acfaa10d9f86c), +W64LIT(0x88926903dc63a48e), +W64LIT(0xb40680f9558939b3), +W64LIT(0x239f0fd595ee277c), +W64LIT(0xec8710db34d5c3af), +W64LIT(0x87b72ec783a3fefc), +W64LIT(0x632794936c144db0), +W64LIT(0x46cb1e5fdf294ef8), +W64LIT(0x83467b7a1492c677), +W64LIT(0x9c4d9d5508967c36), +W64LIT(0xd6607c389bec7aa6), +W64LIT(0x165d24f26517c407), +W64LIT(0xc4cc0d7769ca862a), +W64LIT(0xcbe94ab3360adc58), +W64LIT(0x847496319030ece6), +W64LIT(0x7a5ff7a556c3d3c5), +W64LIT(0xc03d58cafefbbea1), +W64LIT(0x76b908971a909bad), +W64LIT(0x2f79f0e7d9bd6f14), +W64LIT(0x197863363ad79e75), +W64LIT(0xda86830ad7bf32ce), +W64LIT(0x5a034086d0bee6a3), +W64LIT(0x97998f2cc0671ecf), +W64LIT(0x552607428f7ebcd1), +W64LIT(0x51d752ff184f845a), +W64LIT(0xbb23c73d0a4963c1), +W64LIT(0x2b88a55a4e8c579f), +W64LIT(0xd80453ae665d2e71), +W64LIT(0xee05c07f8537df10), +W64LIT(0x423a4be248187673), +W64LIT(0xcaa822e1947bd2fd), +W64LIT(0x1abbdbc029448c6f), +W64LIT(0x96d8e77e6216106a), +W64LIT(0x6266fcc1ce654315), +W64LIT(0x89d301517e12aa2b), +W64LIT(0x730935782fd0ad83), +W64LIT(0x8085c38c0701d46d), +W64LIT(0x6b303e1cb7763d53), +W64LIT(0x3f57510c9a798f27), +W64LIT(0x4449cefb6ecb5247), +W64LIT(0x48af31c922981a2f), +W64LIT(0x98bcc8e89fa744bd), +W64LIT(0x69b2eeb8069421ec), +W64LIT(0xebb5fd90b077e93e), +W64LIT(0x6a71564e150733f6), +W64LIT(0x116fc9b9e1b5ee96), +W64LIT(0x4a2de16d937a0690), +W64LIT(0xb9a11799bbab7f7e), +W64LIT(0x9368da9157562644), +W64LIT(0x718be5dc9e32b13c), +W64LIT(0xc82af2452599ce42), +W64LIT(0xb547e8abf7f83716), +W64LIT(0x33b1ae3ed62ac74f), +W64LIT(0x799c4f534550c1df), +W64LIT(0x3e16395e38088182), +W64LIT(0x7c2c72bc7010f7f1), +W64LIT(0xf38cf6f428d179ee), +W64LIT(0xd29129850cdd422d), +W64LIT(0x41f9f3145b8b6469), +W64LIT(0x945a37dad3f40cd5), +W64LIT(0x757ab061090389b7), +W64LIT(0x6554118a4ac76984), +W64LIT(0x7d6d1aeed261f954), +W64LIT(0x01416852a2710ea5), +W64LIT(0xb27505e0735a1d87), +W64LIT(0x77f860c5b8e19508), +W64LIT(0x78dd2701e721cf7a), +W64LIT(0xe12087bbdaf78562), +W64LIT(0x86f6469521d2f059), +W64LIT(0xef44a82d2746d1b5), +W64LIT(0xbc112a768eeb4950), +W64LIT(0xc2bf886e4f19a21e), +W64LIT(0x307216c8c5b9d555), +W64LIT(0xc96b9a1787e8c0e7), +W64LIT(0xa31acc5992eff311), +W64LIT(0xa0d974af817ce10b), +W64LIT(0xdcf50613f16c16fa), +W64LIT(0xfca9b1307711239c), +W64LIT(0x57a4d7e63e9ca06e), +W64LIT(0xc64eddd3d8289a95), +W64LIT(0xa25ba40b309efdb4), +W64LIT(0x2e3898b57bcc61b1), +W64LIT(0xf5ff73ed0e025dda), +W64LIT(0xa6aaf1b6a7afc53f), +W64LIT(0xd9453bfcc42c20d4), +W64LIT(0x9d0cf507aae77293), +W64LIT(0x290a75feff6e4b20), +W64LIT(0xa7eb99e405decb9a), +W64LIT(0xa1981cfd230defae), +W64LIT(0x12ac714ff226fc8c), +W64LIT(0x743bd833ab728712), +W64LIT(0x6c02d35733d417c2), +W64LIT(0xe9372d340195f581), +W64LIT(0xf77da349bfe04165), +W64LIT(0x68f386eaa4e52f49), +W64LIT(0x211ddf71240c3bc3), +W64LIT(0x13ed191d5057f229), +W64LIT(0xe8764566a3e4fb24), +W64LIT(0xf9198cdf425115b2), +W64LIT(0xd013f921bd3f5e92), +W64LIT(0x91ea0a35e6b43afb), +W64LIT(0x0732ed4b84a22a91), +W64LIT(0xeaf495c21206e79b), +W64LIT(0x5214ea090bdc9640), +W64LIT(0x0000000000000000), +W64LIT(0xb3346db2d12b1322), +W64LIT(0x0ce6ff324c534868), +W64LIT(0xaebd5b397ccdb5dc), +W64LIT(0x0a957a2b6a806c5c), +W64LIT(0x1f0be62f1c04ba41), +W64LIT(0x14dff456d4f5d8b8), +W64LIT(0x58819022615cfa1c), +W64LIT(0x05b03def3540362e), +W64LIT(0xe3a2571f6b1599dd), +W64LIT(0x9229b2c3f52728e1), +W64LIT(0xba62af6fa8386d64), +W64LIT(0x0673851926d32434), +W64LIT(0x641579d8e8b66721), +W64LIT(0x04f155bd9731388b), +W64LIT(0x9ecf4df1b9746089), +W64LIT(0x205cb723867d3566), +W64LIT(0x102ea1eb43c4e033), +W64LIT(0x3ba604b10d48b7ac), +W64LIT(0x50963aadba3e8aff), +W64LIT(0xac3f8b9dcd2fa963), +W64LIT(0x7b1e9ff7f4b2dd60), +W64LIT(0xf63ccb1b1d914fc0), +W64LIT(0x7eaea218c1f2eb4e), +W64LIT(0x5fb37d69e5fed08d), +W64LIT(0x56e5bfb49cedaecb), +W64LIT(0x2dfb2043685f73ab), +W64LIT(0x61a54437ddf6510f), +W64LIT(0x6fc16ba1204705d8), +W64LIT(0xe75302a2fc24a156), +W64LIT(0x3dd581a82b9b9398), +W64LIT(0xdbc7eb5875ce3c6b), +W64LIT(0x90ab626744c5345e), +W64LIT(0x59c0f870c32df4b9), +W64LIT(0x6697a97c59547b9e), +W64LIT(0xfde8d962d5602d39), +W64LIT(0xd3d041d7aeac4c88), +W64LIT(0x5ef2153b478fde28), +W64LIT(0xd4e2ac9c2a0e6619), +W64LIT(0x1e4a8e7dbe75b4e4), +W64LIT(0x72485d2a8da1a326), +W64LIT(0x437b23b0ea6978d6), +W64LIT(0x159e9c047684d61d), +W64LIT(0x0f2547c45fc05a72), +W64LIT(0xf10e265099336551), +W64LIT(0x3c94e9fa89ea9d3d), +W64LIT(0xbfd292809d785b4a), +W64LIT(0x0817aa8fdb6270e3), +W64LIT(0x60e42c657f875faa), +W64LIT(0x18390b6498a690d0), +W64LIT(0x478a760d7d58405d), +W64LIT(0x284b1dac5d1f4585), +W64LIT(0xb1b6bd1660c90f9d), +W64LIT(0xd15291731f4e5037), +W64LIT(0x4d1f0c2617d82c01), +W64LIT(0xc70fb5817a599430), +W64LIT(0x6d43bb0591a51967), +W64LIT(0x6e8003f382360b7d), +W64LIT(0x1d89368bade6a6fe), +W64LIT(0x4f9ddc82a63a30be), +W64LIT(0xedc6788996a4cd0a), +W64LIT(0xab0d66d6498d83f2), +W64LIT(0x54676f102d0fb274), +W64LIT(0xc17c30985c8ab004), +W64LIT(0x3865bc471edba5b6), +W64LIT(0x3924d415bcaaab13), +W64LIT(0x951b5f8871850270), +W64LIT(0x8a10b9a76d81b831), +W64LIT(0xbd5042242c9a47f5), +W64LIT(0xa5694940b43cd725), +W64LIT(0xff6a09c664823186), +W64LIT(0x8d2254ece92392a0), +W64LIT(0xb7c5380f461a2ba9), +W64LIT(0x82071328b6e3c8d2), +W64LIT(0xd721146a399d7403), +W64LIT(0xfada342951c207a8), +W64LIT(0x262f323aa0ae1152), +W64LIT(0xf04f4e023b426bf4), +W64LIT(0x276e5a6802df1ff7), +/* box 1 */ +W64LIT(0x3b4016dbfd16e203), +W64LIT(0x9a7574c51174530a), +W64LIT(0x90012e69c02ec8d3), +W64LIT(0xf44580e3d780e076), +W64LIT(0xf81dec2b49eca14b), +W64LIT(0x26cae3e8a6e3d7ef), +W64LIT(0x0962419e0c41f6ab), +W64LIT(0x54d1eb4070ebd951), +W64LIT(0x865e884b0188eec8), +W64LIT(0xdf76067ea406fe8a), +W64LIT(0x29849412e594fba0), +W64LIT(0x461569896869c0f2), +W64LIT(0xb5ddd6b3bbd6724e), +W64LIT(0x0c586cc89e6c413d), +W64LIT(0x6b0ad97054d904ea), +W64LIT(0xa135621eec62b109), +W64LIT(0x0eef7e47087ea461), +W64LIT(0xfaaafea4dffe4417), +W64LIT(0xe0ad344e80342331), +W64LIT(0xab4138b23d382ad0), +W64LIT(0x107390468e90fcff), +W64LIT(0xbe0885a2218561b9), +W64LIT(0xdbed22957d22c132), +W64LIT(0x2251c7037fc7e857), +W64LIT(0x33835ef8ba5e9c86), +W64LIT(0xb3f1e0d7f4e0a8aa), +W64LIT(0x3fdb32302432ddbb), +W64LIT(0xa719547aa3546bed), +W64LIT(0xe10c3df3cb3dab1f), +W64LIT(0x17feaf9f8aafae35), +W64LIT(0x9df84b1c154b01c0), +W64LIT(0x8364a51d93a5595e), +W64LIT(0x535cd49974d48b9b), +W64LIT(0x01a109bd4b09882e), +W64LIT(0xc4d0c529b0c51182), +W64LIT(0x2e09abcbe1aba96a), +W64LIT(0x1f3de7bccde7d0b0), +W64LIT(0x9317355b1d35a5a1), +W64LIT(0x6c87e6a950e65620), +W64LIT(0x8910ffb142ffc287), +W64LIT(0x40395fed275f1a16), +W64LIT(0x7b794936da49f815), +W64LIT(0xf269b68798b63a92), +W64LIT(0xfd27c17ddbc116dd), +W64LIT(0x8d8bdb5a9bdbfd3f), +W64LIT(0x1ba6c35714c3ef08), +W64LIT(0x6e30f426c6f4b37c), +W64LIT(0x7fe26ddd036dc7ad), +W64LIT(0x14e8b4ad57b4c347), +W64LIT(0xb985ba7b25ba3373), +W64LIT(0xe9cf75d08c75d59a), +W64LIT(0x626898ee5898f241), +W64LIT(0x5b9f9cba339cf51e), +W64LIT(0xb250e96abfe92084), +W64LIT(0x165fa622c1a6261b), +W64LIT(0xf5e4895e9c896858), +W64LIT(0xb76ac43c2dc49712), +W64LIT(0x02b7128f9612e55c), +W64LIT(0x1d8af5335bf535ec), +W64LIT(0x36b973ae28732b10), +W64LIT(0xa8572380e02347a2), +W64LIT(0xf6f2926c4192052a), +W64LIT(0x8c2ad2e7d0d27511), +W64LIT(0xd32e6ab63a6abfb7), +W64LIT(0xbd1e9e90fc9e0ccb), +W64LIT(0x03161b32dd1b6d72), +W64LIT(0x4dc03a98f23ad305), +W64LIT(0x81d3b79205b7bc02), +W64LIT(0x450372bbb572ad80), +W64LIT(0x2d1fb0f93cb0c418), +W64LIT(0x2a928f20388f96d2), +W64LIT(0x721b08a8d6080ebe), +W64LIT(0x92b63ce6563c2d8f), +W64LIT(0xeb78675f1a6730c6), +W64LIT(0x13658b74538b918d), +W64LIT(0x428e4d62b14dff4a), +W64LIT(0x88b1f60c09f64aa9), +W64LIT(0x75963771d2375c74), +W64LIT(0x7ad8408b9140703b), +W64LIT(0x57c7f072adf0b423), +W64LIT(0xe5971918121994a7), +W64LIT(0x5666f9cfe6f93c0d), +W64LIT(0x8f3cc9d50dc91863), +W64LIT(0x1e9cee0186ee589e), +W64LIT(0x8a06e4839fe4aff5), +W64LIT(0xb824b3c66eb3bb5d), +W64LIT(0xd1997839ac785aeb), +W64LIT(0x6752b5b8cab545d7), +W64LIT(0xb47cdf0ef0dffa60), +W64LIT(0x949a0a82190af76b), +W64LIT(0xc04be1c269e12e3a), +W64LIT(0xfc86c8c090c89ef3), +W64LIT(0xe3bb2f7c5d2f4e43), +W64LIT(0x6aabd0cd1fd08cc4), +W64LIT(0x2147dc31a2dc8525), +W64LIT(0xca3fbb6eb8bbb5e3), +W64LIT(0x48fa17ce60176493), +W64LIT(0x6444ae8a17ae28a5), +W64LIT(0x2b33869d73861efc), +W64LIT(0xd0387184e771d2c5), +W64LIT(0x7cf476efde76aadf), +W64LIT(0x63c9915313917a6f), +W64LIT(0xc929a05c65a0d891), +W64LIT(0xda4c2b28362b491c), +W64LIT(0xfe31da4f06da7baf), +W64LIT(0xc1eae87f22e8a614), +W64LIT(0x5c12a36337a3a7d4), +W64LIT(0x18b0d865c9d8827a), +W64LIT(0xe7200b97840b71fb), +W64LIT(0x4bec0cfcbd0c09e1), +W64LIT(0x0f4e77fa43772c4f), +W64LIT(0x4c613325b9335b2b), +W64LIT(0xf3c8bf3ad3bfb2bc), +W64LIT(0x87ff81f64a8166e6), +W64LIT(0xa38270917a705455), +W64LIT(0x1911d1d882d10a54), +W64LIT(0x44a27b06fe7b25ae), +W64LIT(0x049b24ebd9243fb8), +W64LIT(0xbb32a8f4b3a8d62f), +W64LIT(0x91a027d48b2740fd), +W64LIT(0x3d6c20bfb22038e7), +W64LIT(0xe681022acf02f9d5), +W64LIT(0xf17fadb545ad57e0), +W64LIT(0xcc138d0af78d6f07), +W64LIT(0x495b1e732b1eecbd), +W64LIT(0x38560de9200d8f71), +W64LIT(0xa9f62a3dab2acf8c), +W64LIT(0x47b46034236048dc), +W64LIT(0x8e9dc06846c0904d), +W64LIT(0xaccc076b3907781a), +W64LIT(0x32225745f15714a8), +W64LIT(0xd4a3556f3e55ed7d), +W64LIT(0xd7b54e5de34e800f), +W64LIT(0xddc114f132141bd6), +W64LIT(0x6d26ef141befde0e), +W64LIT(0x85489379dc9383ba), +W64LIT(0x0bd553119a5313f7), +W64LIT(0x786f520407529567), +W64LIT(0xcb9eb2d3f3b23dcd), +W64LIT(0xa223792c3179dc7b), +W64LIT(0x0a745aacd15a9bd9), +W64LIT(0x710d139a0b1363cc), +W64LIT(0x681cc24289c26998), +W64LIT(0x1a07caea5fca6726), +W64LIT(0x82c5aca0d8acd170), +W64LIT(0x25dcf8da7bf8ba9d), +W64LIT(0xc7c6de1b6dde7cf0), +W64LIT(0xc35dfaf0b4fa4348), +W64LIT(0xded70fc3ef0f76a4), +W64LIT(0x504acfaba9cfe6e9), +W64LIT(0xc571cc94fbcc99ac), +W64LIT(0x5ea5b1eca1b14288), +W64LIT(0xae7b15e4af159d46), +W64LIT(0xc888a9e12ea950bf), +W64LIT(0xf7539bd10a9b8d04), +W64LIT(0x962d180d8f181237), +W64LIT(0xe43610a559101c89), +W64LIT(0x772125fe4425b928), +W64LIT(0x84e99ac4979a0b94), +W64LIT(0xc667d7a626d7f4de), +W64LIT(0xefe343b4c3430f7e), +W64LIT(0xd5025cd2755c6553), +W64LIT(0xa6b85dc7e85de3c3), +W64LIT(0xd61447e0a8470821), +W64LIT(0x3e7a3b8d6f3b5595), +W64LIT(0x52fddd243fdd03b5), +W64LIT(0x8072be2f4ebe342c), +W64LIT(0x12c482c9188219a3), +W64LIT(0x9eee502ec8506cb2), +W64LIT(0xad6d0ed6720ef034), +W64LIT(0x59288e35a58e1042), +W64LIT(0xe21a26c11626c66d), +W64LIT(0x247df16730f132b3), +W64LIT(0xf0dea4080ea4dfce), +W64LIT(0x31344c772c4c79da), +W64LIT(0x4f77281764283659), +W64LIT(0x79ce5bb94c5b1d49), +W64LIT(0x0000000000000000), +W64LIT(0x73ba01159d018690), +W64LIT(0x74373ecc993ed45a), +W64LIT(0xbcbf972db79784e5), +W64LIT(0x4ed621aa2f21be77), +W64LIT(0xd95a301aeb30246e), +W64LIT(0x9c5942a15e4289ee), +W64LIT(0x37187a13637aa33e), +W64LIT(0x276bea55edea5fc1), +W64LIT(0x1c2bfc8e10fcbdc2), +W64LIT(0xed54513b5551ea22), +W64LIT(0x20e6d58ce9d50d0b), +W64LIT(0x3ae11f66b61f6a2d), +W64LIT(0x66f3bc0581bccdf9), +W64LIT(0x2cbeb94477b94c36), +W64LIT(0x99636ff7cc6f3e78), +W64LIT(0x953b033f52037f45), +W64LIT(0xb0e7fbe529fbc5d8), +W64LIT(0x60df8a61ce8a171d), +W64LIT(0x6f91fd9b8dfd3b52), +W64LIT(0xaae0310f7631a2fe), +W64LIT(0xbfa98c1f6a8ce997), +W64LIT(0x8ba7ed3ed4ed27db), +W64LIT(0x98c2664a8766b656), +W64LIT(0x062c36644f36dae4), +W64LIT(0x5570e2fd3be2517f), +W64LIT(0xead96ee2516eb8e8), +W64LIT(0x419856506c569238), +W64LIT(0x23f0cebe34ce6079), +W64LIT(0x309545ca6745f1f4), +W64LIT(0x5a3e950778957d30), +W64LIT(0x617e83dc85839f33), +W64LIT(0xfb0bf71994f7cc39), +W64LIT(0x3ccd2902f929b0c9), +W64LIT(0x70ac1a27401aebe2), +W64LIT(0xcea49f85619f8a5b), +W64LIT(0x39f704546b04075f), +W64LIT(0x0df96575d565c913), +W64LIT(0x08c3482347487e85), +W64LIT(0xd28f630b71633799), +W64LIT(0xecf558861e58620c), +W64LIT(0xc2fcf34dfff3cb66), +W64LIT(0x978c11b0c4119a19), +W64LIT(0x69bdcbffc2cbe1b6), +W64LIT(0xba93a149f8a15e01), +W64LIT(0x51ebc616e2c66ec7), +W64LIT(0x078d3fd9043f52ca), +W64LIT(0x58898788ee87986c), +W64LIT(0x4a4d0541f60581cf), +W64LIT(0xe86e7c6dc77c5db4), +W64LIT(0xee424a09884a8750), +W64LIT(0xcdb284b7bc84e729), +W64LIT(0x65e5a7375ca7a08b), +W64LIT(0x2fa8a276aaa22144), +W64LIT(0xa0946ba3a76b3927), +W64LIT(0xa5ae46f535468eb1), +W64LIT(0x35af689cf5684662), +W64LIT(0x28259dafae9d738e), +W64LIT(0xcf0596382a960275), +W64LIT(0xb6cbcd8166cd1f3c), +W64LIT(0x7e43646048644f83), +W64LIT(0x9bd47d785a7ddb24), +W64LIT(0x432f44dffa447764), +W64LIT(0x9f4f59938359e49c), +W64LIT(0x7d557f52957f22f1), +W64LIT(0x76802c430f2c3106), +W64LIT(0xdc601d4c791d93f8), +W64LIT(0x053a2d56922db796), +W64LIT(0x11d299fbc59974d1), +W64LIT(0xf9bce59602e52965), +W64LIT(0xd8fb39a7a039ac40), +W64LIT(0x340e6121be61ce4c), +W64LIT(0x5f04b851eab8caa6), +W64LIT(0x5db3aade7caa2ffa), +W64LIT(0x1549bd101cbd4b69), +W64LIT(0xff90d3f24dd3f381), +W64LIT(0xafda1c59e41c1568), +W64LIT(0xb146f25862f24df6), +W64LIT(0xa40f4f487e4f069f), +/* box 2 */ +W64LIT(0xa1a35cebf8f0f94c), +W64LIT(0x2c203d650f3f095d), +W64LIT(0x1a2bdaee4084a2a7), +W64LIT(0xd32404574d7bcc68), +W64LIT(0xf785bea594a9adc4), +W64LIT(0xf2eb54456206949c), +W64LIT(0x3f5e334d0475ced1), +W64LIT(0x5994299b835d1f60), +W64LIT(0x785b7989ac204794), +W64LIT(0x025da6a2cf461a41), +W64LIT(0xdf1f3a71f01a901b), +W64LIT(0x27284f018bb77637), +W64LIT(0xe1955a6d694c5310), +W64LIT(0x24a1baf2d9d261ac), +W64LIT(0xe4fbb08d9fe36a48), +W64LIT(0x8d83618ef7cff011), +W64LIT(0x2ac72276abf5279e), +W64LIT(0xf9e32621e68eebf6), +W64LIT(0xbf323fb4d3f86f69), +W64LIT(0xbb888605b8745beb), +W64LIT(0x70dafe1e7acd2f65), +W64LIT(0xd0adf1a41f1edbf3), +W64LIT(0x1e91635f2b089625), +W64LIT(0xee2791b8864818f8), +W64LIT(0x99ce23e4c56c1484), +W64LIT(0xf33f0714ff259946), +W64LIT(0xbd6f99161cbe7528), +W64LIT(0x9f293cf761a63a47), +W64LIT(0xb80173f6ea114c70), +W64LIT(0x6543ef25d54dc62a), +W64LIT(0x39b92c5ea0bfe012), +W64LIT(0x63a4f0367187e8e9), +W64LIT(0x4c0d38a02cddf62f), +W64LIT(0x07334c4239e92319), +W64LIT(0x43bff375c3d9bdc7), +W64LIT(0xca862b4a5f9a7954), +W64LIT(0x5d2e902ae8d12be2), +W64LIT(0x137e0e280b4ac78c), +W64LIT(0xf162a1b630638307), +W64LIT(0x55af17bd3e3c4313), +W64LIT(0x358212781ddebc61), +W64LIT(0x94214e93e52e452d), +W64LIT(0xc18e592edb12063e), +W64LIT(0xec7a371a490e02b9), +W64LIT(0x4963d240da72cf77), +W64LIT(0x41e255d70c9fa786), +W64LIT(0xff0439324244c535), +W64LIT(0x88ed8b6e0160c949), +W64LIT(0x6c163be39e83a301), +W64LIT(0xc534e09fb09e32bc), +W64LIT(0x806c0cf9d78da1b8), +W64LIT(0xdba583c09b96a499), +W64LIT(0x746047af11411be7), +W64LIT(0xf40c4b56c6ccba5f), +W64LIT(0x6270a367eca4e533), +W64LIT(0xd41748157492ef71), +W64LIT(0xeff3c2e91b6b1522), +W64LIT(0x0e66988472274632), +W64LIT(0x534808ae9af66dd0), +W64LIT(0x8231aa5b18cbbbf9), +W64LIT(0xb2dd52c3f3ba3ec0), +W64LIT(0xdd429cd33f5c8a5a), +W64LIT(0x4e509e02e39bec6e), +W64LIT(0x26fc1c5016947bed), +W64LIT(0xd9f8256254d0bed8), +W64LIT(0x0955d4c64bce652b), +W64LIT(0x1610e4c8fde5fed4), +W64LIT(0x6dc268b203a0aedb), +W64LIT(0x2e7d9bc7c079131c), +W64LIT(0xc3d3ff8c14541c7f), +W64LIT(0xd64aeeb7bbd4f530), +W64LIT(0xab7f7ddee15b8bfc), +W64LIT(0x144d426a32a3e495), +W64LIT(0x8e0a947da5aae78a), +W64LIT(0x798f2ad831034a4e), +W64LIT(0x3be48afc6ff9fa53), +W64LIT(0x529c5bff07d5600a), +W64LIT(0xbee66ce54edb62b3), +W64LIT(0x931202d1dcc76634), +W64LIT(0x50c1fd5dc8937a4b), +W64LIT(0xa4cdb60b0e5fc014), +W64LIT(0x57f2b11ff17a5952), +W64LIT(0x47054ac4a8558945), +W64LIT(0x5a1ddc68d13808fb), +W64LIT(0x5cfac37b75f22638), +W64LIT(0xc207acdd897711a5), +W64LIT(0x289a84d464b33ddf), +W64LIT(0xc05a0a7f46310be4), +W64LIT(0xe6a6162f50a57009), +W64LIT(0x06e71f13a4ca2ec3), +W64LIT(0x5f733688279731a3), +W64LIT(0xeb497b5870e721a0), +W64LIT(0xb667eb7298360a42), +W64LIT(0xe3c8fccfa60a4951), +W64LIT(0xe772457ecd867dd3), +W64LIT(0x6978d103682c9a59), +W64LIT(0x0def6d77204251a9), +W64LIT(0xc90fdeb90dff6ecf), +W64LIT(0xd179a2f5823dd629), +W64LIT(0x2fa9c8965d5a1ec6), +W64LIT(0x81b85fa84aaeac62), +W64LIT(0xdc96cf82a27f8780), +W64LIT(0x602d05c523e2ff72), +W64LIT(0x19a22f1d12e1b53c), +W64LIT(0xe52fe3dc02c06792), +W64LIT(0x58407aca1e7e12ba), +W64LIT(0x61f95694bec1f2a8), +W64LIT(0x48b781114751c2ad), +W64LIT(0xaaab2e8f7c788626), +W64LIT(0x04bab9b16b8c3482), +W64LIT(0x2df46e34921c0487), +W64LIT(0x1123a88ac40cddcd), +W64LIT(0xc6bd156ce2fb2527), +W64LIT(0x7f6835cb95c9648d), +W64LIT(0x83e5f90a85e8b623), +W64LIT(0x4f84cd537eb8e1b4), +W64LIT(0x294ed785f9903005), +W64LIT(0x1cccc5fde44e8c64), +W64LIT(0xcb52781bc2b9748e), +W64LIT(0x1d1896ac796d81be), +W64LIT(0xb30901926e99331a), +W64LIT(0xad9862cd4591a53f), +W64LIT(0xc8db8de890dc6315), +W64LIT(0x7bd28c7afe45500f), +W64LIT(0x0adc213519ab72b0), +W64LIT(0xa8f6882db33e9c67), +W64LIT(0xb5ee1e81ca531dd9), +W64LIT(0x201b0343b25e552e), +W64LIT(0x4036068691bcaa5c), +W64LIT(0xae11973e17f4b2a4), +W64LIT(0x9efd6fa6fc85379d), +W64LIT(0x33650d6bb91492a2), +W64LIT(0x3a30d9adf2daf789), +W64LIT(0x0c3b3e26bd615c73), +W64LIT(0xf651edf4098aa01e), +W64LIT(0x710ead4fe7ee22bf), +W64LIT(0x3138abc9765288e3), +W64LIT(0x9d749a55aee02006), +W64LIT(0x6e4b9d4151c5b940), +W64LIT(0x84d6b548bc01953a), +W64LIT(0x360be78b4fbbabfa), +W64LIT(0xa22aa918aa95eed7), +W64LIT(0xedae644bd42d0f63), +W64LIT(0x46d119953576849f), +W64LIT(0x6497bc74486ecbf0), +W64LIT(0xfbbe808329c8f1b7), +W64LIT(0x4aea27b38817d8ec), +W64LIT(0x5626e24e6c595488), +W64LIT(0x056eeae0f6af3958), +W64LIT(0x4558ec6667139304), +W64LIT(0x448cbf37fa309ede), +W64LIT(0x6f9fce10cce6b49a), +W64LIT(0xa0770fba65d3f496), +W64LIT(0x671e49871a0bdc6b), +W64LIT(0xda71d09106b5a943), +W64LIT(0x08818797d6ed68f1), +W64LIT(0xa3fefa4937b6e30d), +W64LIT(0xb080f4613cfc2481), +W64LIT(0x763de10dde0701a6), +W64LIT(0x4dd96bf1b1fefbf5), +W64LIT(0x92c6518041e46bee), +W64LIT(0x3456412980fdb1bb), +W64LIT(0x981a70b5584f195e), +W64LIT(0x3d0395efcb33d490), +W64LIT(0xba5cd55425575631), +W64LIT(0x4b3e74e21534d536), +W64LIT(0x6af124f03a498dc2), +W64LIT(0x7ebc669a08ea6957), +W64LIT(0x30ecf898eb718539), +W64LIT(0xa922db7c2e1d91bd), +W64LIT(0x7a06df2b63665dd5), +W64LIT(0xb154a730a1df295b), +W64LIT(0xfc8dccc11021d2ae), +W64LIT(0xcfe8c1aaa935400c), +W64LIT(0x97a8bb60b74b52b6), +W64LIT(0x18767c4c8fc2b8e6), +W64LIT(0x9a47d6179709031f), +W64LIT(0x0000000000000000), +W64LIT(0xac4c319cd8b2a8e5), +W64LIT(0xb9d520a7773241aa), +W64LIT(0xdecb69206d399dc1), +W64LIT(0x1f45300eb62b9bff), +W64LIT(0x10f7fbdb592fd017), +W64LIT(0x3e8a601c9956c30b), +W64LIT(0x8502e619212298e0), +W64LIT(0xf5d818075befb785), +W64LIT(0x547b44eca31f4ec9), +W64LIT(0x9ca0c90433c32ddc), +W64LIT(0xe041093cf46f5eca), +W64LIT(0xa69010a9c119da55), +W64LIT(0xc769463d7fd828fd), +W64LIT(0xc4e0b3ce2dbd3f66), +W64LIT(0x2575e9a344f16c76), +W64LIT(0x01d453519d230dda), +W64LIT(0xfa6ad3d2b4ebfc6d), +W64LIT(0xd5c31b44e9b1e2ab), +W64LIT(0xf83775707bade62c), +W64LIT(0xbcbbca47819d78f2), +W64LIT(0xd79ebde626f7f8ea), +W64LIT(0x5bc98f394c1b0521), +W64LIT(0x2246a5e17d184f6f), +W64LIT(0x12aa5d799669ca56), +W64LIT(0x5ea765d9bab43c79), +W64LIT(0x8939d83f9c43c493), +W64LIT(0x32b15e3a24379f78), +W64LIT(0xe914ddfabfa13be1), +W64LIT(0x909bf7228ea271af), +W64LIT(0x73530bed28a838fe), +W64LIT(0xd2f05706d058c1b2), +W64LIT(0xfed06a63df67c8ef), +W64LIT(0xb43a4dd057701003), +W64LIT(0xa519e55a937ccdce), +W64LIT(0x75b414fe8c62163d), +W64LIT(0xafc5c46f8ad7bf7e), +W64LIT(0x2392f6b0e03b42b5), +W64LIT(0x386d7f0f3d9cedc8), +W64LIT(0x21cf50122f7d58f4), +W64LIT(0x9b9385460a2a0ec5), +W64LIT(0x5115ae0c55b07791), +W64LIT(0x0fb2cbd5ef044be8), +W64LIT(0xea9d2809edc42c7a), +W64LIT(0xcc613459fb505797), +W64LIT(0x426ba0245efab01d), +W64LIT(0x1599113baf80e94f), +W64LIT(0x7d3593695a8f7ecc), +W64LIT(0x0389f5f35265179b), +W64LIT(0x875f40bbee6482a1), +W64LIT(0x95f51dc2780d48f7), +W64LIT(0x7ce1c038c7ac7316), +W64LIT(0xce3c92fb34164dd6), +W64LIT(0xcdb5670866735a4d), +W64LIT(0x8ab02dccce26d308), +W64LIT(0x914fa47313817c75), +W64LIT(0x8b647e9d5305ded2), +W64LIT(0xd82c7633c9f3b302), +W64LIT(0x728758bcb58b3524), +W64LIT(0xe8c08eab2282363b), +W64LIT(0x8fdec72c3889ea50), +W64LIT(0x2b13712736d62a44), +W64LIT(0x3cd7c6be5610d94a), +W64LIT(0x37dfb4dad298a620), +W64LIT(0x868b13ea73478f7b), +W64LIT(0xb7b3b82305150798), +W64LIT(0x0b08726484887f6a), +W64LIT(0x1bff89bfdda7af7d), +W64LIT(0x77e9b25c43240c7c), +W64LIT(0xf0b6f2e7ad408edd), +W64LIT(0x17c4b79960c6f30e), +W64LIT(0x8c5732df6aecfdcb), +W64LIT(0x68ac8252f50f9783), +W64LIT(0x66ca1ad68728d1b1), +W64LIT(0x6b2577a1a76a8018), +W64LIT(0xe21caf9e3b29448b), +W64LIT(0xa74443f85c3ad78f), +W64LIT(0xfd599f908d02df74), +W64LIT(0x967ce8312a685f6c), +/* box 3 */ +W64LIT(0xfa7b9775ba3af751), +W64LIT(0x03ef98cb769c2d13), +W64LIT(0x7191ce067072359e), +W64LIT(0xbab18b6bff7516a8), +W64LIT(0xe6e5ef4efbc1065e), +W64LIT(0x7bec74a3b1d0dbf4), +W64LIT(0x656b4fb907c31c4a), +W64LIT(0x4e8520f99fc86304), +W64LIT(0x8fd8df31d16dae58), +W64LIT(0x90a93fc1e60a7244), +W64LIT(0x30ad09f2b449cfc5), +W64LIT(0x8453be7e91bb5b90), +W64LIT(0x1d68a3d1c08feaad), +W64LIT(0x5c54642504b410f6), +W64LIT(0x8061383c8a9e3707), +W64LIT(0xf9940fbecca6da42), +W64LIT(0x46e1d97da982bbdf), +W64LIT(0xfc50521656f7ad77), +W64LIT(0x5e4d2704f35c2647), +W64LIT(0x8bea5973ca48c2cf), +W64LIT(0xd06323dfa34593bd), +W64LIT(0x62b651306a7a5dce), +W64LIT(0xa436b0714966d116), +W64LIT(0x4f73fb131ebc78a6), +W64LIT(0x92b07ce011e244f5), +W64LIT(0x33429139c2d5e2d6), +W64LIT(0xcee418c515565403), +W64LIT(0xd7be3d56cefcd239), +W64LIT(0x53ed83285f4789a9), +W64LIT(0xf3e9b51b0d043428), +W64LIT(0x20650e0fd8dd8a86), +W64LIT(0xb6e7f4add21aa2e4), +W64LIT(0x6d0fb63d3189c491), +W64LIT(0x0da0a42cac1bafee), +W64LIT(0x3f14eeffefba569a), +W64LIT(0x13279f361a086850), +W64LIT(0x9b225e8ea6dc878c), +W64LIT(0x6684d772715f3159), +W64LIT(0xa3ebaef824df9092), +W64LIT(0xc499a260d4f4ba69), +W64LIT(0xaa798c9693e153eb), +W64LIT(0x50021be329dba4ba), +W64LIT(0x949bb983fd2f1ed3), +W64LIT(0xdfdac4d2f8b60ae2), +W64LIT(0xf0062dd07b98193b), +W64LIT(0xafbdd13e09b024de), +W64LIT(0xb95e13a089e93bbb), +W64LIT(0x649d945386b707e8), +W64LIT(0xe4fcac6f0c2930ef), +W64LIT(0x413cc7f4c43bfa5b), +W64LIT(0x3b2668bdf49f3a0d), +W64LIT(0xe50a77858d5d2b4d), +W64LIT(0x05c45da89a517735), +W64LIT(0x3ee235156ece4d38), +W64LIT(0xfe491137a11f9bc6), +W64LIT(0xb7112f47536eb946), +W64LIT(0x07dd1e896db94184), +W64LIT(0x1ab5bd58ad36ab29), +W64LIT(0x8197e3d60bea2ca5), +W64LIT(0xab8f577c12954849), +W64LIT(0x9cff4007cb65c608), +W64LIT(0xa00436335243bd81), +W64LIT(0xfda689fcd783b6d5), +W64LIT(0xccfd5be4e2be62b2), +W64LIT(0x75a348446b575909), +W64LIT(0x17151974012d04c7), +W64LIT(0xfb8d4c9f3b4eecf3), +W64LIT(0xac5249f57f2c09cd), +W64LIT(0x9346a70a90965f57), +W64LIT(0x043286421b256c97), +W64LIT(0x27b81086b564cb02), +W64LIT(0x3569545a2e18b8f0), +W64LIT(0x6b24735edd449eb7), +W64LIT(0x2193d5e559a99124), +W64LIT(0xc7763aaba268977a), +W64LIT(0xb0cc31ce3ed7f8c2), +W64LIT(0xc939064c78ef1587), +W64LIT(0x16e3c29e80591f65), +W64LIT(0x5da2bfcf85c00b54), +W64LIT(0x5990398d9ee567c3), +W64LIT(0x67720c98f02b2afb), +W64LIT(0x54309da132fec82d), +W64LIT(0xeab39088d6aeb212), +W64LIT(0x9682faa20ac72862), +W64LIT(0xd38cbb14d5d9beae), +W64LIT(0x4c9c63d8682055b5), +W64LIT(0xd648e6bc4f88c99b), +W64LIT(0xdc355c198e2a27f1), +W64LIT(0x10c807fd6c944543), +W64LIT(0x450e41b6df1e96cc), +W64LIT(0x0b8b614f40d6f5c8), +W64LIT(0xd27a60fe54ada50c), +W64LIT(0x49583e70f2712280), +W64LIT(0x8dc19c10268598e9), +W64LIT(0x5866e2671f917c61), +W64LIT(0x79f537824638ed45), +W64LIT(0xc2b267033839e04f), +W64LIT(0xcb20456d8f072336), +W64LIT(0x2a18b4aa197f64ec), +W64LIT(0xdbe84290e3936675), +W64LIT(0x73888d27879a032f), +W64LIT(0xe8aad3a9214684a3), +W64LIT(0x6ee02ef64715e982), +W64LIT(0xa996145de57d7ef8), +W64LIT(0xc8cfdda6f99b0e25), +W64LIT(0x062bc563eccd5a26), +W64LIT(0x264ecb6c3410d0a0), +W64LIT(0xb8a8c84a089d2019), +W64LIT(0x7dc7b1c05d1d81d2), +W64LIT(0xd5a77e773914e488), +W64LIT(0x4b417d5105991431), +W64LIT(0xf62de8b39755431d), +W64LIT(0x993b1daf5134b13d), +W64LIT(0x82787b1d7d7601b6), +W64LIT(0xe321b2e66190716b), +W64LIT(0xb5086c66a4868ff7), +W64LIT(0x9ee603263c8df0b9), +W64LIT(0x349f8fb0af6ca352), +W64LIT(0x5b897aac690d5172), +W64LIT(0x7c316a2adc699a70), +W64LIT(0xd451a59db860ff2a), +W64LIT(0x706715ecf1062e3c), +W64LIT(0x838ea0f7fc021a14), +W64LIT(0x57df056a4462e53e), +W64LIT(0xcf12c32f94224fa1), +W64LIT(0xed6e8e01bb17f396), +W64LIT(0x915fe42b677e69e6), +W64LIT(0x89f31a523da0f47e), +W64LIT(0xe71334a47ab51dfc), +W64LIT(0xa860cfb76409655a), +W64LIT(0x9f10d8ccbdf9eb1b), +W64LIT(0xef77cd204cffc527), +W64LIT(0xf862d4544dd2c1e0), +W64LIT(0x8a1c82994b3cd96d), +W64LIT(0xae4b0ad488c43f7c), +W64LIT(0x98cdc645d040aa9f), +W64LIT(0x7fdef2e1aaf5b763), +W64LIT(0x4717029728f6a07d), +W64LIT(0x745593aeea2342ab), +W64LIT(0xee8116cacd8bde85), +W64LIT(0x727e56cd06ee188d), +W64LIT(0x227c4d2e2f35bc37), +W64LIT(0x977421488bb333c0), +W64LIT(0xa21d7512a5ab8b30), +W64LIT(0xbb4750817e010d0a), +W64LIT(0x6cf96dd7b0fddf33), +W64LIT(0x2801f78bee97525d), +W64LIT(0x1c9e783b41fbf10f), +W64LIT(0x9d099bed4a11ddaa), +W64LIT(0x7a1aaf4930a4c056), +W64LIT(0x32b44ad343a1f974), +W64LIT(0x3cfb763499267b89), +W64LIT(0xb2d572efc93fce73), +W64LIT(0x63408adaeb0e466c), +W64LIT(0xada4921ffe58126f), +W64LIT(0x5fbbfcee72283de5), +W64LIT(0x6ad2a8b45c308515), +W64LIT(0x0c567fc62d6fb44c), +W64LIT(0x956d62697c5b0571), +W64LIT(0x25a153a7428cfdb3), +W64LIT(0x150c5a55f6c53276), +W64LIT(0xe2d7690ce0e46ac9), +W64LIT(0xda1e997a62e77dd7), +W64LIT(0xf5c27078e1c96e0e), +W64LIT(0xc344bce9b94dfbed), +W64LIT(0x60af12119d926b7f), +W64LIT(0xa1f2edd9d337a623), +W64LIT(0xcad69e870e733894), +W64LIT(0x3770177bd9f08e41), +W64LIT(0xa5c06b9bc812cab4), +W64LIT(0x1f71e0f03767dc1c), +W64LIT(0x44f89a5c5e6a8d6e), +W64LIT(0x6159c9fb1ce670dd), +W64LIT(0x8e2e04db5019b5fa), +W64LIT(0x8805c1b8bcd4efdc), +W64LIT(0xe138f1c7967847da), +W64LIT(0x4ab7a6bb84ed0f93), +W64LIT(0x0000000000000000), +W64LIT(0x38c9f0768203171e), +W64LIT(0x1b4366b22c42b08b), +W64LIT(0x7803ec68c74cf6e7), +W64LIT(0xec9855eb3a63e834), +W64LIT(0xbe830d29e4507a3f), +W64LIT(0x2dc5aa2374c62568), +W64LIT(0xa62ff350be8ee7a7), +W64LIT(0x764cd08f1dcb741a), +W64LIT(0x8c3747faa7f1834b), +W64LIT(0x0fb9e70d5bf3995f), +W64LIT(0x55c6464bb38ad38f), +W64LIT(0xf7db3359162158bf), +W64LIT(0xd195f8352231881f), +W64LIT(0x0992226eb73ec379), +W64LIT(0x14fa81bf77b129d4), +W64LIT(0x48aee59a73053922), +W64LIT(0x2457884dc3f8e611), +W64LIT(0xffbfcadd206b8064), +W64LIT(0xb4feb78c25f29455), +W64LIT(0x864afd5f66536d21), +W64LIT(0x6f16f51cc661f220), +W64LIT(0xde2c1f3879c21140), +W64LIT(0x195a2593dbaa863a), +W64LIT(0x2e2a32e8025a087b), +W64LIT(0x432584d533d3ccea), +W64LIT(0x2c3371c9f5b23eca), +W64LIT(0xa7d928ba3ffafc05), +W64LIT(0x42d35f3fb2a7d748), +W64LIT(0x85a5659410cf4032), +W64LIT(0x0864f984364ad8db), +W64LIT(0xf21f6ef18c702f8a), +W64LIT(0xf1f0f63afaec0299), +W64LIT(0xd9f101b1147b50c4), +W64LIT(0x2fdce902832e13d9), +W64LIT(0x4d6ab832e9544e17), +W64LIT(0xe0ce2a2d170c5c78), +W64LIT(0x51f4c009a8afbf18), +W64LIT(0x68cbeb95abd8b3a4), +W64LIT(0xc15dffc84ea5cd5c), +W64LIT(0x02194321f7e836b1), +W64LIT(0x113edc17ede05ee1), +W64LIT(0x521b58c2de33920b), +W64LIT(0x9ad4856427a89c2e), +W64LIT(0x5629de80c516fe9c), +W64LIT(0x77ba0b659cbf6fb8), +W64LIT(0x238a96c4ae41a795), +W64LIT(0x12d144dc9b7c73f2), +W64LIT(0xd807da5b950f4b66), +W64LIT(0x3686cc91588495e3), +W64LIT(0x18acfe795ade9d98), +W64LIT(0x5a7fa146e8794ad0), +W64LIT(0xc680e141231c8cd8), +W64LIT(0x1e873b1ab613c7be), +W64LIT(0xf434ab9260bd75ac), +W64LIT(0xcd0b800e63ca7910), +W64LIT(0xbc9a4e0813b84c8e), +W64LIT(0x3d0dadde1852602b), +W64LIT(0x40ca1c1e454fe1f9), +W64LIT(0x0a7dbaa5c1a2ee6a), +W64LIT(0x693d307f2aaca806), +W64LIT(0x0e4f3ce7da8782fd), +W64LIT(0xbd6c95e292cc572c), +W64LIT(0x3ad0b35775eb21af), +W64LIT(0x7e28290b2b81acc1), +W64LIT(0x01f6dbea81741ba2), +W64LIT(0x87bc26b5e7277683), +W64LIT(0x393f2b9c03770cbc), +W64LIT(0xddc387f30f5e3c53), +W64LIT(0xeb454b6257daa9b0), +W64LIT(0xb323a905484bd5d1), +W64LIT(0xb13aea24bfa3e360), +W64LIT(0x315bd218353dd467), +W64LIT(0x2bee6f40980b7f4e), +W64LIT(0xe95c0843a0329f01), +W64LIT(0xc56f798a5580a1cb), +W64LIT(0xbf75d6c36524619d), +W64LIT(0x29f72c616fe349ff), +W64LIT(0xc0ab2422cfd1d6fe), +/* box 4 */ +W64LIT(0x561fc423e957943c), +W64LIT(0x014287ca69079288), +W64LIT(0x2f086129dfcd1d21), +W64LIT(0xc537d4aea044fd99), +W64LIT(0xf1e8c3bfd7c8a457), +W64LIT(0x2971998a5cdf9bfb), +W64LIT(0x23fa649a2ce9e460), +W64LIT(0x3aa9e9c356a6716a), +W64LIT(0xd6efa4e7aa3d1708), +W64LIT(0x705a24b1fda5b5eb), +W64LIT(0x101e0ce2b170a9fc), +W64LIT(0x7ca821020e814caa), +W64LIT(0x0bc97ada1931ed13), +W64LIT(0x34df1711778c59ce), +W64LIT(0xd35020ef9226d2bf), +W64LIT(0x575d43e9805006b4), +W64LIT(0x91acebec9b1db840), +W64LIT(0x549b3f423b5945d9), +W64LIT(0x99a3ed9d3925163e), +W64LIT(0x7917a50a369a891d), +W64LIT(0xe372343cb4b6dc4e), +W64LIT(0x8d40e2bdd949e8fd), +W64LIT(0xcfbc29bed0728202), +W64LIT(0x969794857108ac12), +W64LIT(0xdd26de3db30cfa1b), +W64LIT(0x115c8b28d8773b74), +W64LIT(0xe9f9c92cc480a3d5), +W64LIT(0x4dc8b21b4116d0d3), +W64LIT(0x316093194f979c79), +W64LIT(0x5124bb4a0342806e), +W64LIT(0xb31408bcdef3cea8), +W64LIT(0xc1cad76cf158aaa6), +W64LIT(0x88ff66b5e1522d4a), +W64LIT(0xa8c37e8476b28a47), +W64LIT(0x15a188ea896b6c4b), +W64LIT(0xa24883940684f5dc), +W64LIT(0xda1da1545919ee49), +W64LIT(0x22b8e35045ee76e8), +W64LIT(0x6106af9925d28e9f), +W64LIT(0xef80318f4792250f), +W64LIT(0x663dd0f0cfc79acd), +W64LIT(0x302214d326900ef1), +W64LIT(0xdfa2255c61022bfe), +W64LIT(0xe6cdb0348cad19f9), +W64LIT(0x50663c806a4512e6), +W64LIT(0x65fbac5b74ced9a0), +W64LIT(0xc4755364c9436f11), +W64LIT(0x8fc419dc0b473918), +W64LIT(0x5c9439339961eba7), +W64LIT(0x3f166dcb6ebdb4dd), +W64LIT(0xba59890715ccf25e), +W64LIT(0xf0aa4475becf36df), +W64LIT(0x03c67cabbb09436d), +W64LIT(0xb99ff5acaec5b133), +W64LIT(0xf9e7c5ce75f00a29), +W64LIT(0x6df4aa2ad6f677de), +W64LIT(0xaeba8627f5a00c9d), +W64LIT(0xa573fcfdec91e18e), +W64LIT(0x7f6e5da9b5880fc7), +W64LIT(0xca03adb6e86947b5), +W64LIT(0x74a72773acb9e2d4), +W64LIT(0x604428534cd51c17), +W64LIT(0xf8a542041cf798a1), +W64LIT(0x448533a08a29ec25), +W64LIT(0x80f060c4436a8334), +W64LIT(0x0db082799a236bc9), +W64LIT(0xfa21b965cef94944), +W64LIT(0x64b92b911dc94b28), +W64LIT(0x7118a37b94a22763), +W64LIT(0xaff801ed9ca79e15), +W64LIT(0x1dae8e9b2b53c235), +W64LIT(0x13d870490a79ea91), +W64LIT(0x8a7b9dd4335cfcaf), +W64LIT(0x1f2a75faf95d13d0), +W64LIT(0xeec2b6452e95b787), +W64LIT(0xc34e2c0d23567b43), +W64LIT(0x47434f0b3120af48), +W64LIT(0xa18eff3fbd8db6b1), +W64LIT(0x98e16a57502284b6), +W64LIT(0x37196bbacc851aa3), +W64LIT(0x8e869e166240ab90), +W64LIT(0x9fda153eba3790e4), +W64LIT(0xf515c07d86d4f368), +W64LIT(0x72dedfd02fab640e), +W64LIT(0xe230b3f6ddb14ec6), +W64LIT(0x97d5134f180f3e9a), +W64LIT(0xe1f6cf5d66b80dab), +W64LIT(0xe78f37fee5aa8b71), +W64LIT(0xa30a045e6f836754), +W64LIT(0x90ee6c26f21a2ac8), +W64LIT(0xaa4785e5a4bc5ba2), +W64LIT(0x4e0eceb0fa1f93be), +W64LIT(0x94136fe4a3067df7), +W64LIT(0x7b935e6be49458f8), +W64LIT(0x9b2716fceb2bc7db), +W64LIT(0x840d63061276d40b), +W64LIT(0xed04caee959cf4ea), +W64LIT(0xea3fb5877f89e0b8), +W64LIT(0xb56df01f5de14872), +W64LIT(0x4935b1d9100a87ec), +W64LIT(0x82749ba5916452d1), +W64LIT(0x58693af1c87dbc98), +W64LIT(0x89bde17f8855bfc2), +W64LIT(0x677f573aa6c00845), +W64LIT(0xeb7d324d168e7230), +W64LIT(0x0284fb61d20ed1e5), +W64LIT(0xb190f3dd0cfd1f4d), +W64LIT(0x684b2e22eeedb269), +W64LIT(0x2bf562eb8ed14a1e), +W64LIT(0xe0b448970fbf9f23), +W64LIT(0x396f9568edaf3207), +W64LIT(0x52e2c7e1b84bc303), +W64LIT(0x77615bd817b0a1b9), +W64LIT(0x7e2cda63dc8f9d4f), +W64LIT(0xf22ebf146cc1e73a), +W64LIT(0xc08850a6985f382e), +W64LIT(0xd9dbddffe210ad24), +W64LIT(0xbfe60d0f2dd737e9), +W64LIT(0x9a659136822c5553), +W64LIT(0x87cb1fada97f9766), +W64LIT(0x4c8a35d12811425b), +W64LIT(0x83361c6ff863c059), +W64LIT(0xd212a725fb214037), +W64LIT(0x9e9892f4d330026c), +W64LIT(0x45c7b46ae32e7ead), +W64LIT(0x5baf465a7374fff5), +W64LIT(0xdc6459f7da0b6893), +W64LIT(0xd46b5f867833c6ed), +W64LIT(0x5dd6bef9f066792f), +W64LIT(0xcb412a7c816ed53d), +W64LIT(0x75e5a0b9c5be705c), +W64LIT(0xf6d3bcd63dddb005), +W64LIT(0xfb633eafa7fedbcc), +W64LIT(0xd529d84c11345465), +W64LIT(0xc9c5d11d536004d8), +W64LIT(0xdb5f269e301e7cc1), +W64LIT(0x86899867c07805ee), +W64LIT(0x3d9296aabcb36538), +W64LIT(0x2cce1d8264c45e4c), +W64LIT(0x5aedc1901a736d7d), +W64LIT(0x2e4ae6e3b6ca8fa9), +W64LIT(0x1e68f230905a8158), +W64LIT(0xdee0a2960805b976), +W64LIT(0xcd38d2df027c53e7), +W64LIT(0x6909a9e887ea20e1), +W64LIT(0x24c11bf3c6fcf032), +W64LIT(0x18110a9313480782), +W64LIT(0xa7f7079c3e9f306b), +W64LIT(0xd8995a358b173fac), +W64LIT(0x854fe4cc7b714683), +W64LIT(0xbd62f66effd9e60c), +W64LIT(0x14e30f20e06cfec3), +W64LIT(0x6e32d6816dff34b3), +W64LIT(0x217e9ffbfee73585), +W64LIT(0xc88756d73a679650), +W64LIT(0x359d90db1e8bcb46), +W64LIT(0x2645e09214f221d7), +W64LIT(0x04fd03c2511c573f), +W64LIT(0x739c581a46acf686), +W64LIT(0xb0d2741765fa8dc5), +W64LIT(0xa0cc78f5d48a2439), +W64LIT(0x5e10c2524b6f3a42), +W64LIT(0xe50bcc9f37a45a94), +W64LIT(0x53a0402bd14c518b), +W64LIT(0x413ab7a8b2322992), +W64LIT(0x203c183197e0a70d), +W64LIT(0xcc7a55156b7bc16f), +W64LIT(0x4601c8c158273dc0), +W64LIT(0xbea48ac544d0a561), +W64LIT(0x638254f8f7dc5f7a), +W64LIT(0xa6b580565798a2e3), +W64LIT(0x3cd01160d5b4f7b0), +W64LIT(0x8c026577b04e7a75), +W64LIT(0x7ad1d9a18d93ca70), +W64LIT(0x785522c05f9d1b95), +W64LIT(0x5f5245982268a8ca), +W64LIT(0x9551e82eca01ef7f), +W64LIT(0x0000000000000000), +W64LIT(0xbb1b0ecd7ccb60d6), +W64LIT(0x094d81bbcb3f3cf6), +W64LIT(0x28331e4035d80973), +W64LIT(0xf7913b1c54da228d), +W64LIT(0x6acfd5433ce3638c), +W64LIT(0x1bd77638a84144ef), +W64LIT(0x62c0d3329edbcdf2), +W64LIT(0x81b2e70e2a6d11bc), +W64LIT(0xd7ad232dc33a8580), +W64LIT(0x05bf8408381bc5b7), +W64LIT(0x33e468789d994d9c), +W64LIT(0xfedcbaa79fe51e7b), +W64LIT(0x4f4c497a93180136), +W64LIT(0x073b7f69ea151452), +W64LIT(0x0cf205b3f324f941), +W64LIT(0x382d12a284a8a08f), +W64LIT(0x1cec0951425450bd), +W64LIT(0x55d9b888525ed751), +W64LIT(0x6cb62de0bff1e556), +W64LIT(0xd1d4db8e4028035a), +W64LIT(0x25839c39affb62ba), +W64LIT(0x4af3cd72ab03c481), +W64LIT(0xa4317b3785967306), +W64LIT(0x1a95f1f2c146d667), +W64LIT(0x926a97472014fb2d), +W64LIT(0xb7e90b7e8fef9997), +W64LIT(0xcefeae74b975108a), +W64LIT(0x3e54ea0107ba2655), +W64LIT(0xd0965c44292f91d2), +W64LIT(0xab05022fcdbbc92a), +W64LIT(0xfd1ac60c24ec5d16), +W64LIT(0xfc5841c64debcf9e), +W64LIT(0xe4494b555ea3c81c), +W64LIT(0xb6ab8cb4e6e80b1f), +W64LIT(0x3beb6e093fa1e3e2), +W64LIT(0xf36c38de05c675b2), +W64LIT(0x9c1c6995013ed389), +W64LIT(0x8b391a1e5a5b6e27), +W64LIT(0xec464d24fc9b6662), +W64LIT(0xad7cfa8c4ea94ff0), +W64LIT(0x0f347918482dba2c), +W64LIT(0x9d5eee5f68394101), +W64LIT(0x7623dc127eb73331), +W64LIT(0x32a6efb2f49edf14), +W64LIT(0x2d8c9a480dc3ccc4), +W64LIT(0xb2568f76b7f45c20), +W64LIT(0x0e76fed2212a28a4), +W64LIT(0x48773613790d1564), +W64LIT(0x129af783637e7819), +W64LIT(0x080f0671a238ae7e), +W64LIT(0x365bec70a582882b), +W64LIT(0x42fccb03093b6aff), +W64LIT(0x0a8bfd1070367f9b), +W64LIT(0xff9e3d6df6e28cf3), +W64LIT(0xe8bb4ee6ad87315d), +W64LIT(0xc7b32fcf724a2c7c), +W64LIT(0xb8dd7266c7c223bb), +W64LIT(0x9328108d491369a5), +W64LIT(0x0679f8a3831286da), +W64LIT(0x270767587df5b35f), +W64LIT(0xa981f94e1fb518cf), +W64LIT(0x6b8d528955e4f104), +W64LIT(0x1667f44132622f26), +W64LIT(0x2ab7e521e7d6d896), +W64LIT(0xac3e7d4627aedd78), +W64LIT(0x7deaa6c86786de22), +W64LIT(0x1725738b5b65bdae), +W64LIT(0x4bb14ab8c2045609), +W64LIT(0x592bbd3ba17a2e10), +W64LIT(0xc20cabc74a51e9cb), +W64LIT(0x6f70514b04f8a63b), +W64LIT(0xbc2071a496de7484), +W64LIT(0x19538d597a4f950a), +W64LIT(0xf45747b7efd361e0), +W64LIT(0x43be4cc9603cf877), +W64LIT(0xc6f1a8051b4dbef4), +W64LIT(0xb42f77d534e6dafa), +W64LIT(0x40783062db35bb1a), +/* box 5 */ +W64LIT(0xf5a96c292deb0a4e), +W64LIT(0x211c9df6ee653c51), +W64LIT(0x04de5ddcbeeef596), +W64LIT(0xe1e5b06f7457c19f), +W64LIT(0x74ca30f014a54fb6), +W64LIT(0xc296f9f7c5457d85), +W64LIT(0x7d4ee08a484d10b0), +W64LIT(0xae87f2d0bf9b13ad), +W64LIT(0x8df4bb480e89afb7), +W64LIT(0x2d8b7a67d9a2d61e), +W64LIT(0x0f3559c8bd712adb), +W64LIT(0x541bc7312f013338), +W64LIT(0x9ec4848b636d5164), +W64LIT(0x952f809f60f28e29), +W64LIT(0x28984d8cb28d6357), +W64LIT(0xd4b5f1dfc38e361f), +W64LIT(0x5674135f7076b373), +W64LIT(0xb791a330042172ec), +W64LIT(0xab94c53bd4b4a6e4), +W64LIT(0xf17731f59305ffd8), +W64LIT(0x39c7a621801e1dcf), +W64LIT(0x20d1f7c13ba47c8e), +W64LIT(0x5e3da912f95facaa), +W64LIT(0xb1202a82e5b80731), +W64LIT(0x13303fc36de4fed3), +W64LIT(0x2e29c43e5314168a), +W64LIT(0x861fbf5c0d1670fa), +W64LIT(0x6458b16af3f771f1), +W64LIT(0x3043765bdcf642c9), +W64LIT(0x12fd55f4b825be0c), +W64LIT(0x0a266e23d65e9f92), +W64LIT(0x6595db5d2636312e), +W64LIT(0x85bd010587a0b06e), +W64LIT(0x9bd7b3600842e42d), +W64LIT(0xaa59af0c0175e63b), +W64LIT(0x240faa1d854a8918), +W64LIT(0xf464061ef82a4a91), +W64LIT(0x5c527d7ca6282ce1), +W64LIT(0x03a2be598ab6c094), +W64LIT(0x40571b7776bdf8e9), +W64LIT(0xe4f687841f7874d6), +W64LIT(0x115febad32937e98), +W64LIT(0x5108f0da442e8671), +W64LIT(0x9cab50e53c1ad12f), +W64LIT(0x33e1c8025640825d), +W64LIT(0x87d2d56bd8d73025), +W64LIT(0xc0f92d999a32fdce), +W64LIT(0x62e938d8126e042c), +W64LIT(0x4a717554a0e3677b), +W64LIT(0x0beb0414039fdf4d), +W64LIT(0xd6da25b19cf9b654), +W64LIT(0x55d6ad06fac073e7), +W64LIT(0x632452efc7af44f3), +W64LIT(0xb5fe775e5b56f2a7), +W64LIT(0x892ae694b0675a21), +W64LIT(0x7a32030f7c1525b2), +W64LIT(0x5d9f174b73e96c3e), +W64LIT(0xc35b93c010843d5a), +W64LIT(0x373f95dee8ae77cb), +W64LIT(0xfb515fd6455b604a), +W64LIT(0xa9fb11558bc326af), +W64LIT(0x22be23af64d3fcc5), +W64LIT(0xa8367b625e026670), +W64LIT(0xb8a4faf8b9505837), +W64LIT(0x785dd7612362a5f9), +W64LIT(0x588c20a018c6d977), +W64LIT(0xea0eb47b77c81ed2), +W64LIT(0xa6ce489d36b20c74), +W64LIT(0x0c97e79137c7ea4f), +W64LIT(0x7c838abd9d8c506f), +W64LIT(0x57b97968a5b7f3ac), +W64LIT(0x6c110b277ade6e28), +W64LIT(0xc785ce1cae6ac8cc), +W64LIT(0x1581b6718c7d8b0e), +W64LIT(0x614b868198d8c4b8), +W64LIT(0x27ad14440ffc498c), +W64LIT(0xdb80a8177eff1cc4), +W64LIT(0x472bf8f242e5cdeb), +W64LIT(0x8a8858cd3ad19ab5), +W64LIT(0xf60bd270a75dcada), +W64LIT(0x43f5a52efc0b387d), +W64LIT(0x6ddc6110af1f2ef7), +W64LIT(0xf0ba5bc246c4bf07), +W64LIT(0x6fb3b57ef068aebc), +W64LIT(0x18db3bd76e7b219e), +W64LIT(0x903cb7740bdd3b60), +W64LIT(0x7bff6938a9d4656d), +W64LIT(0xbdb7cd13d27fed7e), +W64LIT(0x051337eb6b2fb549), +W64LIT(0x77688ea99e138f22), +W64LIT(0xd9ef7c7921889c8f), +W64LIT(0x077ce38534583502), +W64LIT(0xf318e59bcc727f93), +W64LIT(0xb34ffeecbacf877a), +W64LIT(0xe9ac0a22fd7ede46), +W64LIT(0xfc2dbc5371035548), +W64LIT(0x026fd46e5f77804b), +W64LIT(0xe53bedb3cab93409), +W64LIT(0xcc6eca08adf51781), +W64LIT(0xe028da58a1968140), +W64LIT(0x3a6518780aa8dd5b), +W64LIT(0xce011e66f28297ca), +W64LIT(0xa4a19cf369c58c3f), +W64LIT(0xc5ea1a72f11d4887), +W64LIT(0xc427704524dc0858), +W64LIT(0x4238cf1929ca78a2), +W64LIT(0x481ea13aff94e730), +W64LIT(0xdf5ef5cbc011e952), +W64LIT(0x80ae36eeec8f0527), +W64LIT(0x5ae3f4ce47b1593c), +W64LIT(0xcda3a03f7834575e), +W64LIT(0x71d9071b7f8afaff), +W64LIT(0xcadf43ba4c6c625c), +W64LIT(0x1623082806cb4b9a), +W64LIT(0x17ee621fd30a0b45), +W64LIT(0x448946abc8530d7f), +W64LIT(0x974054f13f850e62), +W64LIT(0x73b6d37520fd7ab4), +W64LIT(0xc8b097d4131be217), +W64LIT(0x9f09eebcb6ac11bb), +W64LIT(0x45442c9c1d924da0), +W64LIT(0x1b79858ee4cde10a), +W64LIT(0x0984d07a5ce85f06), +W64LIT(0x4cc0fce6417a12a6), +W64LIT(0x99b8670e57356466), +W64LIT(0xad254c89352dd339), +W64LIT(0x322ca2358381c282), +W64LIT(0xcfcc74512743d715), +W64LIT(0x6b6de8a24e865b2a), +W64LIT(0xda4dc220ab3e5c1b), +W64LIT(0x88e78ca365a61afe), +W64LIT(0x939e092d816bfbf4), +W64LIT(0xcb12298d99ad2283), +W64LIT(0xeed0e9a7c926eb44), +W64LIT(0x98750d3982f424b9), +W64LIT(0xd5789be8164f76c0), +W64LIT(0xbe15734a58c92dea), +W64LIT(0x49d3cb0d2a55a7ef), +W64LIT(0x67fa0f337941b165), +W64LIT(0x8c39d17fdb48ef68), +W64LIT(0x25c2c02a508bc9c7), +W64LIT(0x349d2b876218b75f), +W64LIT(0x70146d2caa4bba20), +W64LIT(0x1c05660bd095d408), +W64LIT(0xfe42683d2e74d503), +W64LIT(0x9a1ad957dd83a4f2), +W64LIT(0xf2d58fac19b33f4c), +W64LIT(0x81635cd9394e45f8), +W64LIT(0xb65cc907d1e03233), +W64LIT(0xdd3121a59f666919), +W64LIT(0x318e1c6c09370216), +W64LIT(0x8b4532faef10da6a), +W64LIT(0x191651e0bbba6141), +W64LIT(0x3f762f9361876812), +W64LIT(0xb96990cf6c9118e8), +W64LIT(0xb4331d698e97b278), +W64LIT(0xd822164ef449dc50), +W64LIT(0x84706b325261f0b1), +W64LIT(0x4eaf28881e0d92ed), +W64LIT(0x69023ccc11f1db61), +W64LIT(0x66376504ac80f1ba), +W64LIT(0x0849ba4d89291fd9), +W64LIT(0xff8f020afbb595dc), +W64LIT(0x50c59aed91efc6ae), +W64LIT(0x1dc80c3c055494d7), +W64LIT(0x1e6ab2658fe25443), +W64LIT(0x3d19fbfd3ef0e859), +W64LIT(0xfa9c35e1909a2095), +W64LIT(0x52aa4e83ce9846e5), +W64LIT(0x419a7140a37cb836), +W64LIT(0xa07fc12fd72b79a9), +W64LIT(0x68cf56fbc4309bbe), +W64LIT(0x01cd6a37d5c140df), +W64LIT(0x9253631a54aabb2b), +W64LIT(0xd06bac037d60c389), +W64LIT(0x295527bb674c2388), +W64LIT(0xd204786d221743c2), +W64LIT(0x0000000000000000), +W64LIT(0xf7c6b847729c8a05), +W64LIT(0xdcfc4b924aa729c6), +W64LIT(0xe38a64012b2041d4), +W64LIT(0xb28294db6f0ec7a5), +W64LIT(0x9d663ad2e9db91f0), +W64LIT(0x91f1dd43de1c7bbf), +W64LIT(0x6086ecb64d198467), +W64LIT(0x59414a97cd0799a8), +W64LIT(0xace826bee0ec93e6), +W64LIT(0xa56cf6c4bc04cce0), +W64LIT(0x727bb942f53c3a6b), +W64LIT(0x6e7edf4925a9ee63), +W64LIT(0x26607e73da3d0953), +W64LIT(0xe75439dd95ceb442), +W64LIT(0x7990bd56f6a3e526), +W64LIT(0xecbf3dc996516b0f), +W64LIT(0x76a5e49e4bd2cffd), +W64LIT(0x968d3ec6ea444ebd), +W64LIT(0x5b2e9ef9927019e3), +W64LIT(0x6aa082959b471bf5), +W64LIT(0xbb0644a133e698a3), +W64LIT(0x830c88b76639c5b3), +W64LIT(0xe2470e36fee1010b), +W64LIT(0xb0ed40b5307947ee), +W64LIT(0x355041b0b7d9f780), +W64LIT(0x8e560511843f6f23), +W64LIT(0x7f2134e4173a90fb), +W64LIT(0x2af799e2edfae31c), +W64LIT(0x4bbc1f63752227a4), +W64LIT(0xf8f3e18fcfeda0de), +W64LIT(0x0d5a8da6e206aa90), +W64LIT(0x2c4610500c6396c1), +W64LIT(0xde939ffc15d0a98d), +W64LIT(0xaf4a98e76a5a5372), +W64LIT(0x8f9b6f2651fe2ffc), +W64LIT(0x36f2ffe93d6f3714), +W64LIT(0x0ef833ff68b06a04), +W64LIT(0xe69953ea400ff49d), +W64LIT(0x23734998b112bc1a), +W64LIT(0x3ebb45a4b44628cd), +W64LIT(0x1ab4efb9310ca1d5), +W64LIT(0x2fe4ae0986d55655), +W64LIT(0xebc3de4ca2095e0d), +W64LIT(0x536724b41b59063a), +W64LIT(0x46e692c597248d34), +W64LIT(0x2b3af3d5383ba3c3), +W64LIT(0x3ba8724fdf699d84), +W64LIT(0xc13447ae4ff3bd11), +W64LIT(0x4d0d96d194bb5279), +W64LIT(0xfde0d664a4c21597), +W64LIT(0xd7174f864938f68b), +W64LIT(0x7eec5ed3c2fbd024), +W64LIT(0xbfd8197d8d086d35), +W64LIT(0x4f6242bfcbccd232), +W64LIT(0xa70322aae3734cab), +W64LIT(0xa3dd7f765d9db93d), +W64LIT(0x94e2eaa8b533cef6), +W64LIT(0x144cdc4659bccbd1), +W64LIT(0xc648a42b7bab8813), +W64LIT(0xf93e8bb81a2ce001), +W64LIT(0xbacb2e96e627d87c), +W64LIT(0xbc7aa72407beada1), +W64LIT(0xc97dfde3c6daa2c8), +W64LIT(0xa1b2ab1802ea3976), +W64LIT(0x1fa7d8525a23149c), +W64LIT(0x75075ac7c1640f69), +W64LIT(0xe861601528bf9e99), +W64LIT(0xa2101541885cf9e2), +W64LIT(0xef1d83901ce7ab9b), +W64LIT(0x06b189b2e19975dd), +W64LIT(0x380acc1655df5d10), +W64LIT(0x1092819ae7523e47), +W64LIT(0xd3c9125af7d6031d), +W64LIT(0xd1a6c634a8a18356), +W64LIT(0x5ff0c3252c9eec75), +W64LIT(0x82c1e280b3f8856c), +W64LIT(0xed7257fe43902bd0), +W64LIT(0x3cd491caeb31a886), +/* box 6 */ +W64LIT(0x94af9eb6fad9e7df), +W64LIT(0x9208ae5e03c94ddd), +W64LIT(0x1d8de8d67158480b), +W64LIT(0xfd093cd2ba147af8), +W64LIT(0xa45ceb22e6597ccf), +W64LIT(0x9bbde6e77bf113da), +W64LIT(0xe4edf4b465fffe5c), +W64LIT(0x7125622e4e8d2a2f), +W64LIT(0x1791b81b8f68430d), +W64LIT(0xb56a63d1902195c0), +W64LIT(0xa980832b30d2ee67), +W64LIT(0x4c0a7fb384862397), +W64LIT(0xed58bc0d1dc7a05b), +W64LIT(0x5955d7f05c4d0637), +W64LIT(0xd2b9b1c8806fcf4e), +W64LIT(0x06a730e8f910aa02), +W64LIT(0xb8b60bd846aa0768), +W64LIT(0x45bf370afcbe7d90), +W64LIT(0x16f6b0375ec370a1), +W64LIT(0x892276608b81afd4), +W64LIT(0xdcccc1b5d0ec08e7), +W64LIT(0xe856949162df5f58), +W64LIT(0x82592e81a41a977e), +W64LIT(0xac8eabb74fca1164), +W64LIT(0xfac9041692afe356), +W64LIT(0x3b882d75331ba3ba), +W64LIT(0xa39cd3e6cee2e561), +W64LIT(0xd077a190d7cca9e3), +W64LIT(0x9c7dde23534a8a74), +W64LIT(0x80973ed9f3b9f1d3), +W64LIT(0xce535132209cb4e9), +W64LIT(0xaa299b5fb6dabb66), +W64LIT(0x2d7e9d426dd8d31b), +W64LIT(0x8a8b6e140d89fad5), +W64LIT(0x6ca88af83fd56224), +W64LIT(0xf5db7c4713871753), +W64LIT(0xeef1a4799bcff55a), +W64LIT(0x76e55aea6636b381), +W64LIT(0x8ee24ea4a33a367a), +W64LIT(0x25acddd7c44bbeb0), +W64LIT(0x9adaeecbaa5a2076), +W64LIT(0x0e75707d5083c7a9), +W64LIT(0x2bd9adaa94c87919), +W64LIT(0x19e4c866dfeb84a4), +W64LIT(0x129f9087f070bc0e), +W64LIT(0xd9c2e929aff4f7e4), +W64LIT(0x6f01928cb9dd3725), +W64LIT(0x39463d2d64b8c517), +W64LIT(0xebff8ce5e4d70a59), +W64LIT(0xb40d6bfd418aa66c), +W64LIT(0xf21b44833b3c8efd), +W64LIT(0x3654457ce5903112), +W64LIT(0x431807e205aed792), +W64LIT(0xb10343613e92596f), +W64LIT(0x0a1c50cdfe300b06), +W64LIT(0x778252c6b79d802d), +W64LIT(0x0cbb60250720a104), +W64LIT(0xe1e3dc281ae7015f), +W64LIT(0x0f1278518128f405), +W64LIT(0x47712752ab1d1b3d), +W64LIT(0xe24ac45c9cef545e), +W64LIT(0x1ceae0faa0f37ba7), +W64LIT(0x9814fe93fdf946db), +W64LIT(0xec3fb421cc6c93f7), +W64LIT(0x833e26ad75b1a4d2), +W64LIT(0x6b68b23c176efb8a), +W64LIT(0x4904572ffb9edc94), +W64LIT(0x4bca4777ac3dba39), +W64LIT(0x2762cd8f93e8d81d), +W64LIT(0x9eb3ce7b04e9ecd9), +W64LIT(0xc2e8311727bc15ed), +W64LIT(0xea9884c9357c39f5), +W64LIT(0xfc6e34fe6bbf4954), +W64LIT(0x13f898ab21db8fa2), +W64LIT(0xb7a47389c782f36d), +W64LIT(0x7b3932e3b0bd2129), +W64LIT(0xaf27b3c3c9c24465), +W64LIT(0xb6c37ba51629c0c1), +W64LIT(0x84fe1e695d0a3d7c), +W64LIT(0x1a4dd01259e3d1a5), +W64LIT(0xab4e9373677188ca), +W64LIT(0x90c6be06546a2b70), +W64LIT(0xf37c4cafea97bd51), +W64LIT(0x647aca6d96460f8f), +W64LIT(0x4ec46febd325453a), +W64LIT(0x3e8605e94c035cb9), +W64LIT(0x0ddc6809d68b92a8), +W64LIT(0x8bec6638dc22c979), +W64LIT(0x67d3d219104e5a8e), +W64LIT(0x2abea58645634ab5), +W64LIT(0x5b9bc7a80bee609a), +W64LIT(0x936fa672d2627e71), +W64LIT(0x7d9e020b49ad8b2b), +W64LIT(0x5832dfdc8de6359b), +W64LIT(0xc7e6198b58a4eaee), +W64LIT(0xd41e8120797f654c), +W64LIT(0xf4bc746bc22c24ff), +W64LIT(0xe084d404cb4c32f3), +W64LIT(0x48635f032a35ef38), +W64LIT(0x8757061ddb02687d), +W64LIT(0x522e8f1173d63e9d), +W64LIT(0xbcdf2b68e819cbc7), +W64LIT(0xbf76331c6e119ec6), +W64LIT(0x08d24095a9936dab), +W64LIT(0x728c7a5ac8857f2e), +W64LIT(0xd110a9bc06679a4f), +W64LIT(0x1f43f88e26fb2ea6), +W64LIT(0xb2aa5b15b89a0c6e), +W64LIT(0x4aad4f5b7d968995), +W64LIT(0x9fd4c657d542df75), +W64LIT(0x323d65cc4b23fdbd), +W64LIT(0xc38f393bf6172641), +W64LIT(0xa152c3be994183cc), +W64LIT(0x9d1ad60f82e1b9d8), +W64LIT(0xe744ecc0e3f7ab5d), +W64LIT(0x38213501b513f6bb), +W64LIT(0xade9a39b9e6122c8), +W64LIT(0x37334d50343b02be), +W64LIT(0x55eeb7d55b6da733), +W64LIT(0x970686c27cd1b2de), +W64LIT(0x427f0fced405e43e), +W64LIT(0xc026214f701f7340), +W64LIT(0x40b11f9683a68293), +W64LIT(0x02ce105857a366ad), +W64LIT(0x7e371a7fcfa5de2a), +W64LIT(0xffc72c8aedb71c55), +W64LIT(0x68c1aa489166ae8b), +W64LIT(0xc68111a7890fd942), +W64LIT(0x79f722bbe71e4784), +W64LIT(0xd579890ca8d456e0), +W64LIT(0x70426a029f261983), +W64LIT(0xb0644b4def396ac3), +W64LIT(0xdb0cf971f8579149), +W64LIT(0x5489bff98ac6949f), +W64LIT(0x046920b0aeb3ccaf), +W64LIT(0x7cf90a279806b887), +W64LIT(0x050e289c7f18ff03), +W64LIT(0x651dc24147ed3c23), +W64LIT(0x5e95ef3474f69f99), +W64LIT(0x6dcf82d4ee7e5188), +W64LIT(0x8f854688729105d6), +W64LIT(0x81f036f52212c27f), +W64LIT(0xb9d103f4970134c4), +W64LIT(0x5349873da27d0d31), +W64LIT(0x20a2f54bbb5341b3), +W64LIT(0xf0d554db6c9fe850), +W64LIT(0x07c038c428bb99ae), +W64LIT(0x30f375941c809b10), +W64LIT(0x3fe10dc59da86f15), +W64LIT(0x46162f7e7ab62891), +W64LIT(0xe623e4ec325c98f1), +W64LIT(0xfea024a63c1c2ff9), +W64LIT(0x349a5524b23357bf), +W64LIT(0x35fd5d0863986413), +W64LIT(0x96618eeead7a8172), +W64LIT(0xcb5d79ae5f844bea), +W64LIT(0x21c5fd676af8721f), +W64LIT(0x5720a78d0ccec19e), +W64LIT(0xf6726433958f4252), +W64LIT(0x8d4b56d02532637b), +W64LIT(0x24cbd5fb15e08d1c), +W64LIT(0x3aef2559e2b09016), +W64LIT(0x5afccf84da455336), +W64LIT(0x51879765f5de6b9c), +W64LIT(0x2917bdf2c36b1fb4), +W64LIT(0xa7f5f356605129ce), +W64LIT(0xc1412963a1b440ec), +W64LIT(0x3d2f1d9dca0b09b8), +W64LIT(0xa53be30e37f24f63), +W64LIT(0x5ff2e718a55dac35), +W64LIT(0xa2fbdbca1f49d6cd), +W64LIT(0xf7156c1f442471fe), +W64LIT(0x7a5e3acf61161285), +W64LIT(0xca3a71828e2f7846), +W64LIT(0x1b2ad83e8848e209), +W64LIT(0xa8e78b07e179ddcb), +W64LIT(0xef96ac554a64c6f6), +W64LIT(0x0000000000000000), +W64LIT(0x6013eadd38f5c320), +W64LIT(0x3c4815b11ba03a14), +W64LIT(0x09b548b978385e07), +W64LIT(0x226ce513ecf0271e), +W64LIT(0x63baf2a9befd9621), +W64LIT(0x44d83f262d154e3c), +W64LIT(0xcdfa4946a694e1e8), +W64LIT(0x113688f37678e90f), +W64LIT(0x859916458ca10ed0), +W64LIT(0xc52809d30f078c43), +W64LIT(0x4d6d779f552d103b), +W64LIT(0x1e24f0a2f7501d0a), +W64LIT(0x0167082cd1ab33ac), +W64LIT(0x1438a06f0960160c), +W64LIT(0xf9601c6214a7b657), +W64LIT(0xa035cb9248eab060), +W64LIT(0x50e09f4924755830), +W64LIT(0xd7b79954ff77304d), +W64LIT(0xe58afc98b454cdf0), +W64LIT(0x03a9187486085501), +W64LIT(0x62ddfa856f56a58d), +W64LIT(0xc44f01ffdeacbfef), +W64LIT(0x73eb7276192e4c82), +W64LIT(0xd6d091782edc03e1), +W64LIT(0xfbae0c3a4304d0fa), +W64LIT(0x9973f6bf2c527577), +W64LIT(0x105180dfa7d3daa3), +W64LIT(0x2605c5a34243ebb1), +W64LIT(0x91a1b62a85c118dc), +W64LIT(0xc99369f608272d47), +W64LIT(0x5d3cf740f2feca98), +W64LIT(0xcf34591ef1378745), +W64LIT(0xc8f461dad98c1eeb), +W64LIT(0x0b7b58e12f9b38aa), +W64LIT(0xe32dcc704d4467f2), +W64LIT(0x754c429ee03ee680), +W64LIT(0xd3deb9e451c4fce2), +W64LIT(0x6e669aa068760489), +W64LIT(0x66b4da35c1e56922), +W64LIT(0x4fa367c7028e7696), +W64LIT(0xba781b80110961c5), +W64LIT(0x41d617ba520db13f), +W64LIT(0x335a6de09a88ce11), +W64LIT(0xdf65d9c156e45de6), +W64LIT(0xcc9d416a773fd244), +W64LIT(0x5c5bff6c2355f934), +W64LIT(0x2870b5de12c02c18), +W64LIT(0x155fa843d8cb25a0), +W64LIT(0x78902a9736b57428), +W64LIT(0xae40bbef186977c9), +W64LIT(0x88457e4c5a2a9c78), +W64LIT(0x6a0fba10c6c5c826), +W64LIT(0x7f5012531e0eed86), +W64LIT(0x8c2c5efcf49950d7), +W64LIT(0x31947db8cd2ba8bc), +W64LIT(0x2c19956ebc73e0b7), +W64LIT(0x230bed3f3d5b14b2), +W64LIT(0x69a6a26440cd9d27), +W64LIT(0x86300e310aa95bd1), +W64LIT(0xb3cd533969313fc2), +W64LIT(0x1883c04a0e40b708), +W64LIT(0xf1b25cf7bd34dbfc), +W64LIT(0x2fb08d1a3a7bb5b6), +W64LIT(0xd8a5e1057e5fc448), +W64LIT(0xddabc99901473b4b), +W64LIT(0xde02d1ed874f6e4a), +W64LIT(0xbdb8234439b2f86b), +W64LIT(0x5647afa1dd65f232), +W64LIT(0x2ed78536ebd0861a), +W64LIT(0xe9319cbdb3746cf4), +W64LIT(0xa692fb7ab1fa1a62), +W64LIT(0x742b4ab23195d52c), +W64LIT(0x95c8969a2b72d473), +W64LIT(0x6174e2f1e95ef08c), +W64LIT(0xf807144ec50c85fb), +W64LIT(0xbe113b30bfbaad6a), +W64LIT(0xda6bf15d29fca2e5), +W64LIT(0xbb1f13acc0a25269), +/* box 7 */ +W64LIT(0xc22b27f0f9e37bf9), +W64LIT(0x93fad23f0955ef09), +W64LIT(0x32ed4b84a22a91a2), +W64LIT(0x3898b57bcc61b1cc), +W64LIT(0x55825ba9ad98e5ad), +W64LIT(0xb2eeb8069421ec94), +W64LIT(0xc7eb5875ce3c6bce), +W64LIT(0x4b1dac5d1f45851f), +W64LIT(0xc16ba1204705d847), +W64LIT(0xc5380f461a2ba91a), +W64LIT(0xb908971a909bad90), +W64LIT(0x303e1cb7763d5376), +W64LIT(0xe6ff324c53486853), +W64LIT(0x6d1aeed261f95461), +W64LIT(0x0193d1e36af1616a), +W64LIT(0x51d1f5cff0b694f0), +W64LIT(0x29b2c3f52728e127), +W64LIT(0x112a768eeb4950eb), +W64LIT(0x8fb672f86f9f4d6f), +W64LIT(0xf0c66c745bc9ea5b), +W64LIT(0x3f8b9dcd2fa9632f), +W64LIT(0x65bc471edba5b6db), +W64LIT(0x4d9d5508967c3696), +W64LIT(0x3a4be24818767318), +W64LIT(0x2794936c144db014), +W64LIT(0x2af2452599ce4299), +W64LIT(0x4a8e7dbe75b4e475), +W64LIT(0x9ddc82a63a30be3a), +W64LIT(0xade29e114c0ded4c), +W64LIT(0xd1d2064dc6bde9c6), +W64LIT(0x7da349bfe04165e0), +W64LIT(0x6b9a1787e8c0e7e8), +W64LIT(0xa54437ddf6510ff6), +W64LIT(0x2254ece92392a023), +W64LIT(0x79f0e7d9bd6f14bd), +W64LIT(0x57510c9a798f2779), +W64LIT(0x346db2d12b13222b), +W64LIT(0x54118a4ac76984c7), +W64LIT(0xefca4a6383e5eb83), +W64LIT(0xca8d8e3c43bf9943), +W64LIT(0xfc336bdebcbb79bc), +W64LIT(0x3e184c2e45580245), +W64LIT(0xf495c21206e79b06), +W64LIT(0xff73ed0e025dda02), +W64LIT(0x4228d472cfe806cf), +W64LIT(0xbcc8e89fa744bda7), +W64LIT(0xab626744c5345ec5), +W64LIT(0xb6bd1660c90f9dc9), +W64LIT(0xb72ec783a3fefca3), +W64LIT(0x8be5dc9e32b13c32), +W64LIT(0x485d2a8da1a326a1), +W64LIT(0xc6788996a4cd0aa4), +W64LIT(0x40fb83411bffc41b), +W64LIT(0x08a6a9ccba5ce2ba), +W64LIT(0xf386eaa4e52f49e5), +W64LIT(0x1acc5992eff311ef), +W64LIT(0xa2571f6b1599dd15), +W64LIT(0x44a82d2746d1b546), +W64LIT(0x70c59ff66dc2976d), +W64LIT(0x8d6525cbbb888fbb), +W64LIT(0x963aadba3e8aff3e), +W64LIT(0x7c30985c8ab0048a), +W64LIT(0x607c389bec7aa6ec), +W64LIT(0xa822e1947bd2fd7b), +W64LIT(0x034086d0bee6a3be), +W64LIT(0x66fcc1ce65431565), +W64LIT(0xb37d69e5fed08dfe), +W64LIT(0x2f323aa0ae1152ae), +W64LIT(0x56c2dd79137e4613), +W64LIT(0x31adcd541ccc321c), +W64LIT(0xdff456d4f5d8b8f5), +W64LIT(0xf9f3145b8b64698b), +W64LIT(0x764566a3e4fb24e4), +W64LIT(0x0cf507aae77293e7), +W64LIT(0x59775c034aea764a), +W64LIT(0xb89b46f9fa6accfa), +W64LIT(0xe8d962d5602d3960), +W64LIT(0x17aa8fdb6270e362), +W64LIT(0x1c4ca0c766caa266), +W64LIT(0x2de16d937a06907a), +W64LIT(0x2547c45fc05a72c0), +W64LIT(0x0fb5817a59943059), +W64LIT(0x0680f9558939b389), +W64LIT(0x16395e3808818208), +W64LIT(0xac714ff226fc8c26), +W64LIT(0xa9b1307711239c11), +W64LIT(0xec8accb33d03483d), +W64LIT(0x6c893f310b08350b), +W64LIT(0xc4abdea570dac870), +W64LIT(0xba4811ca2e7d0e2e), +W64LIT(0xf155bd9731388b31), +W64LIT(0xdd2701e721cf7a21), +W64LIT(0xe94ab3360adc580a), +W64LIT(0x23c73d0a4963c149), +W64LIT(0x5cb723867d35667d), +W64LIT(0x5042242c9a47f59a), +W64LIT(0x198cdf425115b251), +W64LIT(0x0a75feff6e4b206e), +W64LIT(0xfda0ba3dd64a18d6), +W64LIT(0xcede205a1e91e81e), +W64LIT(0xd041d7aeac4c88ac), +W64LIT(0xe42c657f875faa87), +W64LIT(0x36bee5e2ff04e0ff), +W64LIT(0x6fc9b9e1b5ee96b5), +W64LIT(0x998f2cc0671ecf67), +W64LIT(0xd301517e12aa2b12), +W64LIT(0xaea218c1f2eb4ef2), +W64LIT(0xda342951c207a8c2), +W64LIT(0x61efe978868bc786), +W64LIT(0x7f701e8c3456a734), +W64LIT(0x0be62f1c04ba4104), +W64LIT(0x9129850cdd422ddd), +W64LIT(0xd6c12efb25753b25), +W64LIT(0xe33f4dc964977864), +W64LIT(0x1579d8e8b66721b6), +W64LIT(0xf860c5b8e19508e1), +W64LIT(0x7496319030ece630), +W64LIT(0x88a55a4e8c579f8c), +W64LIT(0xcf4df1b974608974), +W64LIT(0x10b9a76d81b83181), +W64LIT(0x0e26509933655133), +W64LIT(0x43bb0591a51967a5), +W64LIT(0x926903dc63a48e63), +W64LIT(0x9c4f534550c1df50), +W64LIT(0x3bd833ab72871272), +W64LIT(0xa4d7e63e9ca06e9c), +W64LIT(0xb46e41531d185f1d), +W64LIT(0x126af05e55aff355), +W64LIT(0x24d415bcaaab13aa), +W64LIT(0x1e9ff7f4b2dd60b2), +W64LIT(0x05c07f8537df1037), +W64LIT(0x467b7a1492c67792), +W64LIT(0x2087bbdaf78562f7), +W64LIT(0x819022615cfa1c5c), +W64LIT(0xcd9ea68aa0774ba0), +W64LIT(0xa79760ee2246cd22), +W64LIT(0x8343755288edde88), +W64LIT(0x58e48de0201b1720), +W64LIT(0x7216c8c5b9d555b9), +W64LIT(0x372d340195f58195), +W64LIT(0xa11799bbab7f7eab), +W64LIT(0x9f0fd595ee277cee), +W64LIT(0x676f102d0fb2740f), +W64LIT(0x9e9c047684d61d84), +W64LIT(0x49cefb6ecb5247cb), +W64LIT(0xd41279c8f162f9f1), +W64LIT(0x1f0c2617d82c01d8), +W64LIT(0x97a97c59547b9e54), +W64LIT(0xe76ce3af39b90939), +W64LIT(0xc3b8f61393121a93), +W64LIT(0x5ba40b309efdb49e), +W64LIT(0xea0a35e6b43afbb4), +W64LIT(0x5a37dad3f40cd5f4), +W64LIT(0x14ea090bdc9640dc), +W64LIT(0x5e6474b5a922a4a9), +W64LIT(0xfee03ced68acbb68), +W64LIT(0x071328b6e3c8d2e3), +W64LIT(0x5302a2fc24a15624), +W64LIT(0x85c38c0701d46d01), +W64LIT(0x3d58cafefbbea1fb), +W64LIT(0x84505de46b250c6b), +W64LIT(0x642f96fdb154d7b1), +W64LIT(0xbf886e4f19a21e19), +W64LIT(0x02d35733d417c2d4), +W64LIT(0x68da915756264456), +W64LIT(0x8710db34d5c3afd5), +W64LIT(0x0d66d6498d83f28d), +W64LIT(0x7b23b0ea6978d669), +W64LIT(0x1b5f887185027085), +W64LIT(0x3ccb1b1d914fc091), +W64LIT(0x0453ae665d2e715d), +W64LIT(0xcb1e5fdf294ef829), +W64LIT(0xf6469521d2f059d2), +W64LIT(0xb03def3540362e40), +W64LIT(0x633cbe4b529c0552), +W64LIT(0xf7d544c2b80138b8), +W64LIT(0x7ab061090389b703), +W64LIT(0x0000000000000000), +W64LIT(0xdba7f8b2a8f6c9a8), +W64LIT(0x35fe633241e24341), +W64LIT(0x21146a399d74039d), +W64LIT(0xd581a82b9b93989b), +W64LIT(0x0935782fd0ad83d0), +W64LIT(0x5ff7a556c3d3c5c3), +W64LIT(0xaf31c922981a2f98), +W64LIT(0x90ba54efb7b34cb7), +W64LIT(0x5291731f4e50374e), +W64LIT(0xc0f870c32df4b92d), +W64LIT(0x7ee3cf6f5ea7c65e), +W64LIT(0xe07fcb19da71dbda), +W64LIT(0x4eddd3d8289a9528), +W64LIT(0x13f921bd3f5e923f), +W64LIT(0xf50613f16c16fa6c), +W64LIT(0x981cfd230defae0d), +W64LIT(0x4c0e84ebfc8d57fc), +W64LIT(0x82d0a4b1e21cbfe2), +W64LIT(0x89368bade6a6fee6), +W64LIT(0xd292809d785b4a78), +W64LIT(0x47e8abf7f83716f8), +W64LIT(0x8e25a31b056e2c05), +W64LIT(0xd752ff184f845a4f), +W64LIT(0xcc0d7769ca862aca), +W64LIT(0x694940b43cd7253c), +W64LIT(0x2ea1eb43c4e033c4), +W64LIT(0xde6787379f29d99f), +W64LIT(0x181f0ea13be4d33b), +W64LIT(0x416852a2710ea571), +W64LIT(0x62af6fa8386d6438), +W64LIT(0xa0844858c18e1fc1), +W64LIT(0x337e9a67c8dbf0c8), +W64LIT(0x2c72bc7010f7f110), +W64LIT(0xbd5b397ccdb5dccd), +W64LIT(0xd8e77e6216106a16), +W64LIT(0x86830ad7bf32cebf), +W64LIT(0x4f4e023b426bf442), +W64LIT(0xe5bfb49cedaecbed), +W64LIT(0x8a760d7d58405d58), +W64LIT(0xe2ac9c2a0e66190e), +W64LIT(0xb5fd90b077e93e77), +W64LIT(0xdcb4d0044b3e1b4b), +W64LIT(0x453bfcc42c20d42c), +W64LIT(0xed191d5057f22957), +W64LIT(0xe1ec1afab080bab0), +W64LIT(0xee599b80e9148ae9), +W64LIT(0x2607428f7ebcd17e), +W64LIT(0x5d24f26517c40717), +W64LIT(0x6a09c66482318682), +W64LIT(0xa604b10d48b7ac48), +W64LIT(0xbe1bbfac73537f73), +W64LIT(0x282112164dd9804d), +W64LIT(0x7505e0735a1d875a), +W64LIT(0x73851926d32434d3), +W64LIT(0xd974af817ce10b7c), +W64LIT(0xeb99e405decb9ade), +W64LIT(0x9b5c7bf3b3090db3), +W64LIT(0xfab3928b3582ca35), +W64LIT(0x8003f382360b7d36), +W64LIT(0x94e9fa89ea9d3dea), +W64LIT(0xb1ae3ed62ac74f2a), +W64LIT(0x9acfaa10d9f86cd9), +W64LIT(0x390b6498a690d0a6), +W64LIT(0xf2153b478fde288f), +W64LIT(0x71564e150733f607), +W64LIT(0xa3c4ce887f68bc7f), +W64LIT(0xaaf1b6a7afc53faf), +W64LIT(0x1ddf71240c3bc30c), +W64LIT(0x77d6b7408e0a458e), +W64LIT(0x2b6194c6f33f23f3), +W64LIT(0xc9cd08ecfd593afd), +W64LIT(0xc85ed90f97a85b97), +W64LIT(0x8cf6f428d179eed1), +W64LIT(0x957a2b6a806c5c80), +W64LIT(0xbbdbc029448c6f44), +W64LIT(0x7863363ad79e75d7), +W64LIT(0x6e5a6802df1ff7df), +W64LIT(0xfb2043685f73ab5f), +}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/simeck.cpp b/extension/third_party/cryptopp/simeck.cpp new file mode 100644 index 00000000..a1a5316e --- /dev/null +++ b/extension/third_party/cryptopp/simeck.cpp @@ -0,0 +1,154 @@ +// simeck.cpp - written and placed in the public domain by Gangqiang Yang and Jeffrey Walton. +// Based on "The Simeck Family of Lightweight Block Ciphers" by Gangqiang Yang, +// Bo Zhu, Valentin Suder, Mark D. Aagaard, and Guang Gong + +#include "pch.h" +#include "config.h" + +#include "simeck.h" +#include "misc.h" +#include "cpu.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::rotlConstant; +using CryptoPP::rotrConstant; + +/// \brief SIMECK encryption round +/// \tparam T word type +/// \param key the key for the round or iteration +/// \param left the first value +/// \param right the second value +/// \details SIMECK_Encryption serves as the key schedule, encryption and +/// decryption functions. +template +inline void SIMECK_Encryption(const T key, T& left, T& right) +{ + const T temp = left; + left = (left & rotlConstant<5>(left)) ^ rotlConstant<1>(left) ^ right ^ key; + right = temp; +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +std::string SIMECK32::Base::AlgorithmProvider() const +{ + return "C++"; +} + +void SIMECK32::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + CRYPTOPP_UNUSED(keyLength); + + GetBlock kblock(userKey); + kblock(m_t[3])(m_t[2])(m_t[1])(m_t[0]); + + word16 constant = 0xFFFC; + word32 sequence = 0x9A42BB1F; + for (unsigned int i = 0; i < ROUNDS; ++i) + { + m_rk[i] = m_t[0]; + + constant &= 0xFFFC; + constant |= sequence & 1; + sequence >>= 1; + + SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); + + // rotate the LFSR of m_t + m_t[4] = m_t[1]; + m_t[1] = m_t[2]; + m_t[2] = m_t[3]; + m_t[3] = m_t[4]; + } +} + +void SIMECK32::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_t[1])(m_t[0]); + + for (int idx = 0; idx < ROUNDS; ++idx) + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); + + PutBlock oblock(xorBlock, outBlock); + oblock(m_t[1])(m_t[0]); +} + +void SIMECK32::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_t[0])(m_t[1]); + + for (int idx = ROUNDS - 1; idx >= 0; --idx) + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); + + PutBlock oblock(xorBlock, outBlock); + oblock(m_t[0])(m_t[1]); +} + +std::string SIMECK64::Base::AlgorithmProvider() const +{ + return "C++"; +} + +void SIMECK64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + CRYPTOPP_UNUSED(keyLength); + + GetBlock kblock(userKey); + kblock(m_t[3])(m_t[2])(m_t[1])(m_t[0]); + + word64 constant = W64LIT(0xFFFFFFFC); + word64 sequence = W64LIT(0x938BCA3083F); + for (unsigned int i = 0; i < ROUNDS; ++i) + { + m_rk[i] = m_t[0]; + + constant &= W64LIT(0xFFFFFFFC); + constant |= sequence & 1; + sequence >>= 1; + + SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); + + // rotate the LFSR of m_t + m_t[4] = m_t[1]; + m_t[1] = m_t[2]; + m_t[2] = m_t[3]; + m_t[3] = m_t[4]; + } +} + +void SIMECK64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_t[1])(m_t[0]); + + for (int idx = 0; idx < ROUNDS; ++idx) + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); + + PutBlock oblock(xorBlock, outBlock); + oblock(m_t[1])(m_t[0]); +} + +void SIMECK64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. + GetBlock iblock(inBlock); + iblock(m_t[0])(m_t[1]); + + for (int idx = ROUNDS - 1; idx >= 0; --idx) + SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); + + PutBlock oblock(xorBlock, outBlock); + oblock(m_t[0])(m_t[1]); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/simeck.h b/extension/third_party/cryptopp/simeck.h new file mode 100644 index 00000000..3449c7f8 --- /dev/null +++ b/extension/third_party/cryptopp/simeck.h @@ -0,0 +1,162 @@ +// simeck.h - written and placed in the public domain by Gangqiang Yang and Jeffrey Walton. +// Based on "The Simeck Family of Lightweight Block Ciphers" by Gangqiang Yang, +// Bo Zhu, Valentin Suder, Mark D. Aagaard, and Guang Gong + +/// \file simeck.h +/// \brief Classes for the SIMECK block cipher +/// \sa SIMECK, +/// The Simeck +/// Family of Lightweight Block Ciphers +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_SIMECK_H +#define CRYPTOPP_SIMECK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SIMECK block cipher information +/// \since Crypto++ 8.0 +struct SIMECK32_Info : public FixedBlockSize<4>, public FixedKeyLength<8>, public FixedRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "SIMECK-32"; + } +}; + +/// \brief SIMECK block cipher information +/// \since Crypto++ 8.0 +struct SIMECK64_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<44> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "SIMECK-64"; + } +}; + +/// \brief SIMECK 32-bit block cipher +/// \details SIMECK32 provides 32-bit block size. The valid key size is 64-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa SIMECK64, SIMECK, +/// The Simeck Family of +/// Lightweight Block Ciphers +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE SIMECK32 : public SIMECK32_Info, public BlockCipherDocumentation +{ +public: + /// \brief SIMECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + FixedSizeSecBlock m_rk; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SIMECK32::Encryption SIMECK32Encryption; +typedef SIMECK32::Decryption SIMECK32Decryption; + +/// \brief SIMECK 64-bit block cipher +/// \details SIMECK64 provides 64-bit block size. The valid key size is 128-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa SIMECK32, SIMECK, +/// The Simeck Family of +/// Lightweight Block Ciphers +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE SIMECK64 : public SIMECK64_Info, public BlockCipherDocumentation +{ +public: + /// \brief SIMECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + FixedSizeSecBlock m_rk; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SIMECK64::Encryption SIMECK64Encryption; +typedef SIMECK64::Decryption SIMECK64Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_SIMECK_H diff --git a/extension/third_party/cryptopp/simon.cpp b/extension/third_party/cryptopp/simon.cpp new file mode 100644 index 00000000..a0eacea4 --- /dev/null +++ b/extension/third_party/cryptopp/simon.cpp @@ -0,0 +1,505 @@ +// simon.h - written and placed in the public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" + +#include "simon.h" +#include "misc.h" +#include "cpu.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both simon.cpp and simon_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_SSE41_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::rotlConstant; +using CryptoPP::rotrConstant; + +/// \brief Round transformation helper +/// \tparam W word type +/// \param v value +template +inline W f(const W v) +{ + return (rotlConstant<1>(v) & rotlConstant<8>(v)) ^ rotlConstant<2>(v); +} + +/// \brief Round transformation +/// \tparam W word type +/// \param x value +/// \param y value +/// \param k value +/// \param l value +template +inline void R2(W& x, W& y, const W k, const W l) +{ + y ^= f(x); y ^= k; + x ^= f(y); x ^= l; +} + +/// \brief Forward transformation +/// \tparam W word type +/// \tparam R number of rounds +/// \param c output array +/// \param p input array +/// \param k subkey array +template +inline void SIMON_Encrypt(W c[2], const W p[2], const W k[R]) +{ + c[0]=p[0]; c[1]=p[1]; + + for (int i = 0; i < static_cast(R-1); i += 2) + R2(c[0], c[1], k[i], k[i + 1]); + + if (R & 1) + { + c[1] ^= f(c[0]); c[1] ^= k[R-1]; + W t = c[0]; c[0] = c[1]; c[1] = t; + } +} + +/// \brief Reverse transformation +/// \tparam W word type +/// \tparam R number of rounds +/// \param p output array +/// \param c input array +/// \param k subkey array +template +inline void SIMON_Decrypt(W p[2], const W c[2], const W k[R]) +{ + p[0]=c[0]; p[1]=c[1]; + unsigned int rounds = R; + + if (R & 1) + { + const W t = p[1]; p[1] = p[0]; p[0] = t; + p[1] ^= k[R - 1]; p[1] ^= f(p[0]); + rounds--; + } + + for (int i = static_cast(rounds - 2); i >= 0; i -= 2) + R2(p[1], p[0], k[i + 1], k[i]); +} + +/// \brief Subkey generation function +/// \details Used for SIMON-64 with 96-bit key and 42 rounds. A template was +/// not worthwhile because all instantiations would need specialization. +/// \param key empty subkey array +/// \param k user key array +inline void SIMON64_ExpandKey_3W(word32 key[42], const word32 k[3]) +{ + const word32 c = 0xfffffffc; + word64 z = W64LIT(0x7369f885192c0ef5); + + key[0] = k[2]; key[1] = k[1]; key[2] = k[0]; + for (size_t i = 3; i<42; ++i) + { + key[i] = static_cast(c ^ (z & 1) ^ key[i - 3] ^ + rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1])); + z >>= 1; + } +} + +/// \brief Subkey generation function +/// \details Used for SIMON-64 with 128-bit key and 44 rounds. A template was +/// not worthwhile because all instantiations would need specialization. +/// \param key empty subkey array +/// \param k user key array +inline void SIMON64_ExpandKey_4W(word32 key[44], const word32 k[4]) +{ + const word32 c = 0xfffffffc; + word64 z = W64LIT(0xfc2ce51207a635db); + + key[0] = k[3]; key[1] = k[2]; key[2] = k[1]; key[3] = k[0]; + for (size_t i = 4; i<44; ++i) + { + key[i] = static_cast(c ^ (z & 1) ^ key[i - 4] ^ + rotrConstant<3>(key[i - 1]) ^ key[i - 3] ^ rotrConstant<4>(key[i - 1]) ^ + rotrConstant<1>(key[i - 3])); + z >>= 1; + } +} + +/// \brief Subkey generation function +/// \details Used for SIMON-128 with 128-bit key and 68 rounds. A template was +/// not worthwhile because all instantiations would need specialization. +/// \param key empty subkey array +/// \param k user key array +inline void SIMON128_ExpandKey_2W(word64 key[68], const word64 k[2]) +{ + const word64 c = W64LIT(0xfffffffffffffffc); + word64 z = W64LIT(0x7369f885192c0ef5); + + key[0] = k[1]; key[1] = k[0]; + for (size_t i=2; i<66; ++i) + { + key[i] = c ^ (z & 1) ^ key[i - 2] ^ rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1]); + z>>=1; + } + + key[66] = c ^ 1 ^ key[64] ^ rotrConstant<3>(key[65]) ^ rotrConstant<4>(key[65]); + key[67] = c^key[65] ^ rotrConstant<3>(key[66]) ^ rotrConstant<4>(key[66]); +} + +/// \brief Subkey generation function +/// \details Used for SIMON-128 with 192-bit key and 69 rounds. A template was +/// not worthwhile because all instantiations would need specialization. +/// \param key empty subkey array +/// \param k user key array +inline void SIMON128_ExpandKey_3W(word64 key[69], const word64 k[3]) +{ + const word64 c = W64LIT(0xfffffffffffffffc); + word64 z = W64LIT(0xfc2ce51207a635db); + + key[0]=k[2]; key[1]=k[1]; key[2]=k[0]; + for (size_t i=3; i<67; ++i) + { + key[i] = c ^ (z & 1) ^ key[i - 3] ^ rotrConstant<3>(key[i - 1]) ^ rotrConstant<4>(key[i - 1]); + z>>=1; + } + + key[67] = c^key[64] ^ rotrConstant<3>(key[66]) ^ rotrConstant<4>(key[66]); + key[68] = c ^ 1 ^ key[65] ^ rotrConstant<3>(key[67]) ^ rotrConstant<4>(key[67]); +} + +/// \brief Subkey generation function +/// \details Used for SIMON-128 with 256-bit key and 72 rounds. A template was +/// not worthwhile because all instantiations would need specialization. +/// \param key empty subkey array +/// \param k user key array +inline void SIMON128_ExpandKey_4W(word64 key[72], const word64 k[4]) +{ + const word64 c = W64LIT(0xfffffffffffffffc); + word64 z = W64LIT(0xfdc94c3a046d678b); + + key[0]=k[3]; key[1]=k[2]; key[2]=k[1]; key[3]=k[0]; + for (size_t i=4; i<68; ++i) + { + key[i] = c ^ (z & 1) ^ key[i - 4] ^ rotrConstant<3>(key[i - 1]) ^ key[i - 3] ^ rotrConstant<4>(key[i - 1]) ^ rotrConstant<1>(key[i - 3]); + z>>=1; + } + + key[68] = c^key[64] ^ rotrConstant<3>(key[67]) ^ key[65] ^ rotrConstant<4>(key[67]) ^ rotrConstant<1>(key[65]); + key[69] = c ^ 1 ^ key[65] ^ rotrConstant<3>(key[68]) ^ key[66] ^ rotrConstant<4>(key[68]) ^ rotrConstant<1>(key[66]); + key[70] = c^key[66] ^ rotrConstant<3>(key[69]) ^ key[67] ^ rotrConstant<4>(key[69]) ^ rotrConstant<1>(key[67]); + key[71] = c^key[67] ^ rotrConstant<3>(key[70]) ^ key[68] ^ rotrConstant<4>(key[70]) ^ rotrConstant<1>(key[68]); +} + +ANONYMOUS_NAMESPACE_END + +/////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +extern size_t SIMON128_Enc_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SIMON128_Dec_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_SSSE3_AVAILABLE) +extern size_t SIMON128_Enc_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SIMON128_Dec_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +extern size_t SIMON128_Enc_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SIMON128_Dec_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +std::string SIMON64::Base::AlgorithmProvider() const +{ + return "C++"; +} + +unsigned int SIMON64::Base::OptimalDataAlignment() const +{ + return GetAlignmentOf(); +} + +void SIMON64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(keyLength == 12 || keyLength == 16); + CRYPTOPP_UNUSED(params); + + // Building the key schedule table requires {3,4} words workspace. + // Encrypting and decrypting requires 4 words workspace. + m_kwords = keyLength/sizeof(word32); + m_wspace.New(4U); + + // Do the endian gyrations from the paper and align pointers + typedef GetBlock KeyBlock; + KeyBlock kblk(userKey); + + switch (m_kwords) + { + case 3: + m_rkeys.New((m_rounds = 42)); + kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SIMON64_ExpandKey_3W(m_rkeys, m_wspace); + break; + case 4: + m_rkeys.New((m_rounds = 44)); + kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SIMON64_ExpandKey_4W(m_rkeys, m_wspace); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void SIMON64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 42: + SIMON_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 44: + SIMON_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +void SIMON64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 42: + SIMON_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 44: + SIMON_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +/////////////////////////////////////////////////////////// + +std::string SIMON128::Base::AlgorithmProvider() const +{ +#if (CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS) +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return "SSSE3"; +# endif +# if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; +# endif +# if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return "Altivec"; +# endif +#endif + return "C++"; +} + +unsigned int SIMON128::Base::OptimalDataAlignment() const +{ +#if (CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS) +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return 16; // load __m128i +# endif +# if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return 8; // load uint64x2_t +# endif +# if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return 16; // load uint64x2_p +# endif +#endif + return GetAlignmentOf(); +} + +void SIMON128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(keyLength == 16 || keyLength == 24 || keyLength == 32); + CRYPTOPP_UNUSED(params); + + // Building the key schedule table requires {2,3,4} words workspace. + // Encrypting and decrypting requires 4 words workspace. + m_kwords = keyLength/sizeof(word64); + m_wspace.New(4U); + + // Do the endian gyrations from the paper and align pointers + typedef GetBlock KeyBlock; + KeyBlock kblk(userKey); + + switch (m_kwords) + { + case 2: + m_rkeys.New((m_rounds = 68)); + kblk(m_wspace[1])(m_wspace[0]); + SIMON128_ExpandKey_2W(m_rkeys, m_wspace); + break; + case 3: + m_rkeys.New((m_rounds = 69)); + kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SIMON128_ExpandKey_3W(m_rkeys, m_wspace); + break; + case 4: + m_rkeys.New((m_rounds = 72)); + kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SIMON128_ExpandKey_4W(m_rkeys, m_wspace); + break; + default: + CRYPTOPP_ASSERT(0); + } + +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + + // Pre-splat the round keys for Altivec forward transformation +#if CRYPTOPP_ALTIVEC_AVAILABLE + if (IsForwardTransformation() && HasAltivec()) + { + AlignedSecBlock presplat(m_rkeys.size()*2); + for (size_t i=0, j=0; i InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 68: + SIMON_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 69: + SIMON_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 72: + SIMON_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +void SIMON128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 68: + SIMON_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 69: + SIMON_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 72: + SIMON_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +#if (CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS) +size_t SIMON128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return SIMON128_Enc_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return SIMON128_Enc_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return SIMON128_Enc_AdvancedProcessBlocks_ALTIVEC(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMON128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return SIMON128_Dec_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return SIMON128_Dec_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return SIMON128_Dec_AdvancedProcessBlocks_ALTIVEC(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/simon.h b/extension/third_party/cryptopp/simon.h new file mode 100644 index 00000000..107aae54 --- /dev/null +++ b/extension/third_party/cryptopp/simon.h @@ -0,0 +1,206 @@ +// simon.h - written and placed in the public domain by Jeffrey Walton + +/// \file simon.h +/// \brief Classes for the Simon block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SIMON on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIMON_H +#define CRYPTOPP_SIMON_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || \ + CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# ifndef CRYPTOPP_DISABLE_SIMON_SIMD +# define CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SIMON block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SIMON_Info : public FixedBlockSize, VariableKeyLength +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SIMON-" + IntToString(L*8); + } +}; + +/// \brief SIMON block cipher base class +/// \tparam W the word type +/// \details User code should use SIMON64 or SIMON128 +/// \sa SIMON64, SIMON128, SIMON on the Crypto++ wiki +/// \since Crypto++ 6.0 +template +struct SIMON_Base +{ + virtual ~SIMON_Base() {} + SIMON_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SIMON 64-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON64 : public SIMON_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON64 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SIMON64 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SIMON64 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SIMON 128-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON128 : public SIMON_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON128 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SIMON128 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief SIMON128 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SIMON_H diff --git a/extension/third_party/cryptopp/simon128_simd.cpp b/extension/third_party/cryptopp/simon128_simd.cpp new file mode 100644 index 00000000..758ee9cb --- /dev/null +++ b/extension/third_party/cryptopp/simon128_simd.cpp @@ -0,0 +1,870 @@ +// simon_simd.cpp - written and placed in the public domain by Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSSE3, ARM NEON and ARMv8a, and Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#include "simon.h" +#include "misc.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both simon.cpp and simon_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include "adv_simd.h" +# include +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include "adv_simd.h" +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if defined(_M_ARM64) +# include "adv_simd.h" +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +# include "adv_simd.h" +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char SIMON128_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::vec_swap; // SunCC + +// *************************** ARM NEON ************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +// Missing from Microsoft's ARM A-32 implementation +#if defined(_MSC_VER) && !defined(_M_ARM64) +inline uint64x2_t vld1q_dup_u64(const uint64_t* ptr) +{ + return vmovq_n_u64(*ptr); +} +#endif + +template +inline T UnpackHigh64(const T& a, const T& b) +{ + const uint64x1_t x(vget_high_u64((uint64x2_t)a)); + const uint64x1_t y(vget_high_u64((uint64x2_t)b)); + return (T)vcombine_u64(x, y); +} + +template +inline T UnpackLow64(const T& a, const T& b) +{ + const uint64x1_t x(vget_low_u64((uint64x2_t)a)); + const uint64x1_t y(vget_low_u64((uint64x2_t)b)); + return (T)vcombine_u64(x, y); +} + +template +inline uint64x2_t RotateLeft64(const uint64x2_t& val) +{ + const uint64x2_t a(vshlq_n_u64(val, R)); + const uint64x2_t b(vshrq_n_u64(val, 64 - R)); + return vorrq_u64(a, b); +} + +template +inline uint64x2_t RotateRight64(const uint64x2_t& val) +{ + const uint64x2_t a(vshlq_n_u64(val, 64 - R)); + const uint64x2_t b(vshrq_n_u64(val, R)); + return vorrq_u64(a, b); +} + +#if defined(__aarch32__) || defined(__aarch64__) +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline uint64x2_t RotateLeft64<8>(const uint64x2_t& val) +{ + const uint8_t maskb[16] = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u64_u8( + vqtbl1q_u8(vreinterpretq_u8_u64(val), mask)); +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline uint64x2_t RotateRight64<8>(const uint64x2_t& val) +{ + const uint8_t maskb[16] = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u64_u8( + vqtbl1q_u8(vreinterpretq_u8_u64(val), mask)); +} +#endif + +inline uint64x2_t SIMON128_f(const uint64x2_t& val) +{ + return veorq_u64(RotateLeft64<2>(val), + vandq_u64(RotateLeft64<1>(val), RotateLeft64<8>(val))); +} + +inline void SIMON128_Enc_Block(uint64x2_t &block0, uint64x2_t &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + + for (size_t i = 0; i < static_cast(rounds & ~1)-1; i += 2) + { + const uint64x2_t rk1 = vld1q_dup_u64(subkeys+i); + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk1); + + const uint64x2_t rk2 = vld1q_dup_u64(subkeys+i+1); + x1 = veorq_u64(veorq_u64(x1, SIMON128_f(y1)), rk2); + } + + if (rounds & 1) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys+rounds-1); + + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk); + std::swap(x1, y1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); +} + +inline void SIMON128_Enc_6_Blocks(uint64x2_t &block0, uint64x2_t &block1, + uint64x2_t &block2, uint64x2_t &block3, uint64x2_t &block4, uint64x2_t &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + uint64x2_t x2 = UnpackHigh64(block2, block3); + uint64x2_t y2 = UnpackLow64(block2, block3); + uint64x2_t x3 = UnpackHigh64(block4, block5); + uint64x2_t y3 = UnpackLow64(block4, block5); + + for (size_t i = 0; i < static_cast(rounds & ~1) - 1; i += 2) + { + const uint64x2_t rk1 = vld1q_dup_u64(subkeys+i); + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk1); + y2 = veorq_u64(veorq_u64(y2, SIMON128_f(x2)), rk1); + y3 = veorq_u64(veorq_u64(y3, SIMON128_f(x3)), rk1); + + const uint64x2_t rk2 = vld1q_dup_u64(subkeys+i+1); + x1 = veorq_u64(veorq_u64(x1, SIMON128_f(y1)), rk2); + x2 = veorq_u64(veorq_u64(x2, SIMON128_f(y2)), rk2); + x3 = veorq_u64(veorq_u64(x3, SIMON128_f(y3)), rk2); + } + + if (rounds & 1) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys + rounds - 1); + + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk); + y2 = veorq_u64(veorq_u64(y2, SIMON128_f(x2)), rk); + y3 = veorq_u64(veorq_u64(y3, SIMON128_f(x3)), rk); + std::swap(x1, y1); std::swap(x2, y2); std::swap(x3, y3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); + block2 = UnpackLow64(y2, x2); + block3 = UnpackHigh64(y2, x2); + block4 = UnpackLow64(y3, x3); + block5 = UnpackHigh64(y3, x3); +} + +inline void SIMON128_Dec_Block(uint64x2_t &block0, uint64x2_t &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + + if (rounds & 1) + { + std::swap(x1, y1); + const uint64x2_t rk = vld1q_dup_u64(subkeys + rounds - 1); + + y1 = veorq_u64(veorq_u64(y1, rk), SIMON128_f(x1)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const uint64x2_t rk1 = vld1q_dup_u64(subkeys+i+1); + x1 = veorq_u64(veorq_u64(x1, SIMON128_f(y1)), rk1); + + const uint64x2_t rk2 = vld1q_dup_u64(subkeys+i); + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk2); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); +} + +inline void SIMON128_Dec_6_Blocks(uint64x2_t &block0, uint64x2_t &block1, + uint64x2_t &block2, uint64x2_t &block3, uint64x2_t &block4, uint64x2_t &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + uint64x2_t x2 = UnpackHigh64(block2, block3); + uint64x2_t y2 = UnpackLow64(block2, block3); + uint64x2_t x3 = UnpackHigh64(block4, block5); + uint64x2_t y3 = UnpackLow64(block4, block5); + + if (rounds & 1) + { + std::swap(x1, y1); std::swap(x2, y2); std::swap(x3, y3); + const uint64x2_t rk = vld1q_dup_u64(subkeys + rounds - 1); + + y1 = veorq_u64(veorq_u64(y1, rk), SIMON128_f(x1)); + y2 = veorq_u64(veorq_u64(y2, rk), SIMON128_f(x2)); + y3 = veorq_u64(veorq_u64(y3, rk), SIMON128_f(x3)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const uint64x2_t rk1 = vld1q_dup_u64(subkeys + i + 1); + x1 = veorq_u64(veorq_u64(x1, SIMON128_f(y1)), rk1); + x2 = veorq_u64(veorq_u64(x2, SIMON128_f(y2)), rk1); + x3 = veorq_u64(veorq_u64(x3, SIMON128_f(y3)), rk1); + + const uint64x2_t rk2 = vld1q_dup_u64(subkeys + i); + y1 = veorq_u64(veorq_u64(y1, SIMON128_f(x1)), rk2); + y2 = veorq_u64(veorq_u64(y2, SIMON128_f(x2)), rk2); + y3 = veorq_u64(veorq_u64(y3, SIMON128_f(x3)), rk2); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); + block2 = UnpackLow64(y2, x2); + block3 = UnpackHigh64(y2, x2); + block4 = UnpackLow64(y3, x3); + block5 = UnpackHigh64(y3, x3); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** IA-32 ***************************** // + +#if (CRYPTOPP_SSSE3_AVAILABLE) + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#ifndef M128_CAST +# define M128_CAST(x) ((__m128i *)(void *)(x)) +#endif +#ifndef CONST_M128_CAST +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#endif + +// GCC double casts, https://www.spinics.net/lists/gcchelp/msg47735.html +#ifndef DOUBLE_CAST +# define DOUBLE_CAST(x) ((double *)(void *)(x)) +#endif +#ifndef CONST_DOUBLE_CAST +# define CONST_DOUBLE_CAST(x) ((const double *)(const void *)(x)) +#endif + +inline void Swap128(__m128i& a,__m128i& b) +{ +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) + // __m128i is an unsigned long long[2], and support for swapping it was not added until C++11. + // SunCC 12.1 - 12.3 fail to consume the swap; while SunCC 12.4 consumes it without -std=c++11. + vec_swap(a, b); +#else + std::swap(a, b); +#endif +} + +template +inline __m128i RotateLeft64(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, R); +#else + return _mm_or_si128( + _mm_slli_epi64(val, R), _mm_srli_epi64(val, 64-R)); +#endif +} + +template +inline __m128i RotateRight64(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 64-R); +#else + return _mm_or_si128( + _mm_slli_epi64(val, 64-R), _mm_srli_epi64(val, R)); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +__m128i RotateLeft64<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 8); +#else + const __m128i mask = _mm_set_epi8(14,13,12,11, 10,9,8,15, 6,5,4,3, 2,1,0,7); + return _mm_shuffle_epi8(val, mask); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +__m128i RotateRight64<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 64-8); +#else + const __m128i mask = _mm_set_epi8(8,15,14,13, 12,11,10,9, 0,7,6,5, 4,3,2,1); + return _mm_shuffle_epi8(val, mask); +#endif +} + +inline __m128i SIMON128_f(const __m128i& v) +{ + return _mm_xor_si128(RotateLeft64<2>(v), + _mm_and_si128(RotateLeft64<1>(v), RotateLeft64<8>(v))); +} + +inline void SIMON128_Enc_Block(__m128i &block0, __m128i &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + + for (size_t i = 0; i < static_cast(rounds & ~1)-1; i += 2) + { + // Round keys are pre-splated in forward direction + const __m128i rk1 = _mm_load_si128(CONST_M128_CAST(subkeys+i*2)); + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk1); + + const __m128i rk2 = _mm_load_si128(CONST_M128_CAST(subkeys+(i+1)*2)); + x1 = _mm_xor_si128(_mm_xor_si128(x1, SIMON128_f(y1)), rk2); + } + + if (rounds & 1) + { + // Round keys are pre-splated in forward direction + const __m128i rk = _mm_load_si128(CONST_M128_CAST(subkeys+(rounds-1)*2)); + + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk); + Swap128(x1, y1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); +} + +inline void SIMON128_Enc_6_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, __m128i &block4, __m128i &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + __m128i x2 = _mm_unpackhi_epi64(block2, block3); + __m128i y2 = _mm_unpacklo_epi64(block2, block3); + __m128i x3 = _mm_unpackhi_epi64(block4, block5); + __m128i y3 = _mm_unpacklo_epi64(block4, block5); + + for (size_t i = 0; i < static_cast(rounds & ~1) - 1; i += 2) + { + // Round keys are pre-splated in forward direction + const __m128i rk1 = _mm_load_si128(CONST_M128_CAST(subkeys+i*2)); + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk1); + y2 = _mm_xor_si128(_mm_xor_si128(y2, SIMON128_f(x2)), rk1); + y3 = _mm_xor_si128(_mm_xor_si128(y3, SIMON128_f(x3)), rk1); + + // Round keys are pre-splated in forward direction + const __m128i rk2 = _mm_load_si128(CONST_M128_CAST(subkeys+(i+1)*2)); + x1 = _mm_xor_si128(_mm_xor_si128(x1, SIMON128_f(y1)), rk2); + x2 = _mm_xor_si128(_mm_xor_si128(x2, SIMON128_f(y2)), rk2); + x3 = _mm_xor_si128(_mm_xor_si128(x3, SIMON128_f(y3)), rk2); + } + + if (rounds & 1) + { + // Round keys are pre-splated in forward direction + const __m128i rk = _mm_load_si128(CONST_M128_CAST(subkeys+(rounds-1)*2)); + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk); + y2 = _mm_xor_si128(_mm_xor_si128(y2, SIMON128_f(x2)), rk); + y3 = _mm_xor_si128(_mm_xor_si128(y3, SIMON128_f(x3)), rk); + Swap128(x1, y1); Swap128(x2, y2); Swap128(x3, y3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); + block2 = _mm_unpacklo_epi64(y2, x2); + block3 = _mm_unpackhi_epi64(y2, x2); + block4 = _mm_unpacklo_epi64(y3, x3); + block5 = _mm_unpackhi_epi64(y3, x3); +} + +inline void SIMON128_Dec_Block(__m128i &block0, __m128i &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + + if (rounds & 1) + { + const __m128i rk = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys + rounds - 1))); + + Swap128(x1, y1); + y1 = _mm_xor_si128(_mm_xor_si128(y1, rk), SIMON128_f(x1)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const __m128i rk1 = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys+i+1))); + x1 = _mm_xor_si128(_mm_xor_si128(x1, SIMON128_f(y1)), rk1); + + const __m128i rk2 = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys+i))); + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk2); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); +} + +inline void SIMON128_Dec_6_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, __m128i &block4, __m128i &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + __m128i x2 = _mm_unpackhi_epi64(block2, block3); + __m128i y2 = _mm_unpacklo_epi64(block2, block3); + __m128i x3 = _mm_unpackhi_epi64(block4, block5); + __m128i y3 = _mm_unpacklo_epi64(block4, block5); + + if (rounds & 1) + { + const __m128i rk = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys + rounds - 1))); + + Swap128(x1, y1); Swap128(x2, y2); Swap128(x3, y3); + y1 = _mm_xor_si128(_mm_xor_si128(y1, rk), SIMON128_f(x1)); + y2 = _mm_xor_si128(_mm_xor_si128(y2, rk), SIMON128_f(x2)); + y3 = _mm_xor_si128(_mm_xor_si128(y3, rk), SIMON128_f(x3)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const __m128i rk1 = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys + i + 1))); + x1 = _mm_xor_si128(_mm_xor_si128(x1, SIMON128_f(y1)), rk1); + x2 = _mm_xor_si128(_mm_xor_si128(x2, SIMON128_f(y2)), rk1); + x3 = _mm_xor_si128(_mm_xor_si128(x3, SIMON128_f(y3)), rk1); + + const __m128i rk2 = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys + i))); + y1 = _mm_xor_si128(_mm_xor_si128(y1, SIMON128_f(x1)), rk2); + y2 = _mm_xor_si128(_mm_xor_si128(y2, SIMON128_f(x2)), rk2); + y3 = _mm_xor_si128(_mm_xor_si128(y3, SIMON128_f(x3)), rk2); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); + block2 = _mm_unpacklo_epi64(y2, x2); + block3 = _mm_unpackhi_epi64(y2, x2); + block4 = _mm_unpacklo_epi64(y3, x3); + block5 = _mm_unpackhi_epi64(y3, x3); +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ***************************** Altivec ***************************** // + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + +// Altivec uses native 64-bit types on 64-bit environments, or 32-bit types +// in 32-bit environments. Speck128 will use the appropriate type for the +// environment. Functions like VecAdd64 have two overloads, one for each +// environment. The 32-bit overload treats uint32x4_p like a 64-bit type, +// and does things like perform a add with carry or subtract with borrow. + +// Speck128 on Power8 performed as expected because of 64-bit environment. +// Performance sucked on old PowerPC machines because of 32-bit environments. +// At Crypto++ 8.3 we added an implementation that operated on 32-bit words. +// Native 64-bit Speck128 performance dropped from about 4.1 to 6.3 cpb, but +// 32-bit Speck128 improved from 66.5 cpb to 10.4 cpb. Overall it was a +// good win even though we lost some performance in 64-bit environments. + +using CryptoPP::uint8x16_p; +using CryptoPP::uint32x4_p; +#if defined(_ARCH_PWR8) +using CryptoPP::uint64x2_p; +#endif + +using CryptoPP::VecAdd64; +using CryptoPP::VecSub64; +using CryptoPP::VecAnd64; +using CryptoPP::VecOr64; +using CryptoPP::VecXor64; +using CryptoPP::VecRotateLeft64; +using CryptoPP::VecRotateRight64; +using CryptoPP::VecSplatElement64; +using CryptoPP::VecLoad; +using CryptoPP::VecLoadAligned; +using CryptoPP::VecPermute; + +#if defined(_ARCH_PWR8) +#define simon128_t uint64x2_p +#else +#define simon128_t uint32x4_p +#endif + +inline simon128_t SIMON128_f(const simon128_t val) +{ + return (simon128_t)VecXor64(VecRotateLeft64<2>(val), + VecAnd64(VecRotateLeft64<1>(val), VecRotateLeft64<8>(val))); +} + +inline void SIMON128_Enc_Block(uint32x4_p &block, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + simon128_t x1 = (simon128_t)VecPermute(block, block, m1); + simon128_t y1 = (simon128_t)VecPermute(block, block, m2); + + for (size_t i = 0; i < static_cast(rounds & ~1)-1; i += 2) + { + // Round keys are pre-splated in forward direction + const word32* ptr1 = reinterpret_cast(subkeys+i*2); + const simon128_t rk1 = (simon128_t)VecLoadAligned(ptr1); + const word32* ptr2 = reinterpret_cast(subkeys+(i+1)*2); + const simon128_t rk2 = (simon128_t)VecLoadAligned(ptr2); + + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk1); + x1 = VecXor64(VecXor64(x1, SIMON128_f(y1)), rk2); + } + + if (rounds & 1) + { + // Round keys are pre-splated in forward direction + const word32* ptr = reinterpret_cast(subkeys+(rounds-1)*2); + const simon128_t rk = (simon128_t)VecLoadAligned(ptr); + + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk); + + std::swap(x1, y1); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + //const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + //const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block = (uint32x4_p)VecPermute(x1, y1, m3); +} + +inline void SIMON128_Dec_Block(uint32x4_p &block, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + simon128_t x1 = (simon128_t)VecPermute(block, block, m1); + simon128_t y1 = (simon128_t)VecPermute(block, block, m2); + + if (rounds & 1) + { + std::swap(x1, y1); + + const word32* ptr = reinterpret_cast(subkeys+rounds-1); + const simon128_t tk = (simon128_t)VecLoad(ptr); + const simon128_t rk = (simon128_t)VecSplatElement64<0>(tk); + + y1 = VecXor64(VecXor64(y1, rk), SIMON128_f(x1)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const word32* ptr = reinterpret_cast(subkeys+i); + const simon128_t tk = (simon128_t)VecLoad(ptr); + const simon128_t rk1 = (simon128_t)VecSplatElement64<1>(tk); + const simon128_t rk2 = (simon128_t)VecSplatElement64<0>(tk); + + x1 = VecXor64(VecXor64(x1, SIMON128_f(y1)), rk1); + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk2); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + //const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + //const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block = (uint32x4_p)VecPermute(x1, y1, m3); +} + +inline void SIMON128_Enc_6_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, uint32x4_p &block4, + uint32x4_p &block5, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + simon128_t x1 = (simon128_t)VecPermute(block0, block1, m1); + simon128_t y1 = (simon128_t)VecPermute(block0, block1, m2); + simon128_t x2 = (simon128_t)VecPermute(block2, block3, m1); + simon128_t y2 = (simon128_t)VecPermute(block2, block3, m2); + simon128_t x3 = (simon128_t)VecPermute(block4, block5, m1); + simon128_t y3 = (simon128_t)VecPermute(block4, block5, m2); + + for (size_t i = 0; i < static_cast(rounds & ~1)-1; i += 2) + { + // Round keys are pre-splated in forward direction + const word32* ptr1 = reinterpret_cast(subkeys+i*2); + const simon128_t rk1 = (simon128_t)VecLoadAligned(ptr1); + + const word32* ptr2 = reinterpret_cast(subkeys+(i+1)*2); + const simon128_t rk2 = (simon128_t)VecLoadAligned(ptr2); + + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk1); + y2 = VecXor64(VecXor64(y2, SIMON128_f(x2)), rk1); + y3 = VecXor64(VecXor64(y3, SIMON128_f(x3)), rk1); + + x1 = VecXor64(VecXor64(x1, SIMON128_f(y1)), rk2); + x2 = VecXor64(VecXor64(x2, SIMON128_f(y2)), rk2); + x3 = VecXor64(VecXor64(x3, SIMON128_f(y3)), rk2); + } + + if (rounds & 1) + { + // Round keys are pre-splated in forward direction + const word32* ptr = reinterpret_cast(subkeys+(rounds-1)*2); + const simon128_t rk = (simon128_t)VecLoadAligned(ptr); + + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk); + y2 = VecXor64(VecXor64(y2, SIMON128_f(x2)), rk); + y3 = VecXor64(VecXor64(y3, SIMON128_f(x3)), rk); + + std::swap(x1, y1); std::swap(x2, y2); std::swap(x3, y3); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = (uint32x4_p)VecPermute(x1, y1, m3); + block1 = (uint32x4_p)VecPermute(x1, y1, m4); + block2 = (uint32x4_p)VecPermute(x2, y2, m3); + block3 = (uint32x4_p)VecPermute(x2, y2, m4); + block4 = (uint32x4_p)VecPermute(x3, y3, m3); + block5 = (uint32x4_p)VecPermute(x3, y3, m4); +} + +inline void SIMON128_Dec_6_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, uint32x4_p &block4, + uint32x4_p &block5, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + simon128_t x1 = (simon128_t)VecPermute(block0, block1, m1); + simon128_t y1 = (simon128_t)VecPermute(block0, block1, m2); + simon128_t x2 = (simon128_t)VecPermute(block2, block3, m1); + simon128_t y2 = (simon128_t)VecPermute(block2, block3, m2); + simon128_t x3 = (simon128_t)VecPermute(block4, block5, m1); + simon128_t y3 = (simon128_t)VecPermute(block4, block5, m2); + + if (rounds & 1) + { + std::swap(x1, y1); std::swap(x2, y2); std::swap(x3, y3); + + const word32* ptr = reinterpret_cast(subkeys+rounds-1); + const simon128_t tk = (simon128_t)VecLoad(ptr); + const simon128_t rk = (simon128_t)VecSplatElement64<0>(tk); + + y1 = VecXor64(VecXor64(y1, rk), SIMON128_f(x1)); + y2 = VecXor64(VecXor64(y2, rk), SIMON128_f(x2)); + y3 = VecXor64(VecXor64(y3, rk), SIMON128_f(x3)); + rounds--; + } + + for (int i = static_cast(rounds-2); i >= 0; i -= 2) + { + const word32* ptr = reinterpret_cast(subkeys+i); + const simon128_t tk = (simon128_t)VecLoad(ptr); + const simon128_t rk1 = (simon128_t)VecSplatElement64<1>(tk); + const simon128_t rk2 = (simon128_t)VecSplatElement64<0>(tk); + + x1 = VecXor64(VecXor64(x1, SIMON128_f(y1)), rk1); + x2 = VecXor64(VecXor64(x2, SIMON128_f(y2)), rk1); + x3 = VecXor64(VecXor64(x3, SIMON128_f(y3)), rk1); + + y1 = VecXor64(VecXor64(y1, SIMON128_f(x1)), rk2); + y2 = VecXor64(VecXor64(y2, SIMON128_f(x2)), rk2); + y3 = VecXor64(VecXor64(y3, SIMON128_f(x3)), rk2); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = (uint32x4_p)VecPermute(x1, y1, m3); + block1 = (uint32x4_p)VecPermute(x1, y1, m4); + block2 = (uint32x4_p)VecPermute(x2, y2, m3); + block3 = (uint32x4_p)VecPermute(x2, y2, m4); + block4 = (uint32x4_p)VecPermute(x3, y3, m3); + block5 = (uint32x4_p)VecPermute(x3, y3, m4); +} + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +// *************************** ARM NEON **************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +size_t SIMON128_Enc_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_NEON(SIMON128_Enc_Block, SIMON128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMON128_Dec_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_NEON(SIMON128_Dec_Block, SIMON128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** IA-32 ***************************** // + +#if (CRYPTOPP_SSSE3_AVAILABLE) +size_t SIMON128_Enc_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_SSE(SIMON128_Enc_Block, SIMON128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMON128_Dec_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_SSE(SIMON128_Dec_Block, SIMON128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ***************************** Altivec ***************************** // + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +size_t SIMON128_Enc_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x1_ALTIVEC(SIMON128_Enc_Block, SIMON128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SIMON128_Dec_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x1_ALTIVEC(SIMON128_Dec_Block, SIMON128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/simple.cpp b/extension/third_party/cryptopp/simple.cpp new file mode 100644 index 00000000..b897cc12 --- /dev/null +++ b/extension/third_party/cryptopp/simple.cpp @@ -0,0 +1,13 @@ +// simple.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "simple.h" + +NAMESPACE_BEGIN(CryptoPP) + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/simple.h b/extension/third_party/cryptopp/simple.h new file mode 100644 index 00000000..f188aca6 --- /dev/null +++ b/extension/third_party/cryptopp/simple.h @@ -0,0 +1,506 @@ +// simple.h - originally written and placed in the public domain by Wei Dai + +/// \file simple.h +/// \brief Classes providing basic library services. + +#ifndef CRYPTOPP_SIMPLE_H +#define CRYPTOPP_SIMPLE_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for identifying alogorithm +/// \tparam BASE base class from which to derive +/// \tparam DERIVED class which to clone +template +class CRYPTOPP_NO_VTABLE ClonableImpl : public BASE +{ +public: + /// \brief Create a copy of this object + /// \return a copy of this object + /// \details The caller is responsible for freeing the object. + Clonable * Clone() const {return new DERIVED(*static_cast(this));} +}; + +/// \brief Base class information +/// \tparam BASE an Algorithm derived class +/// \tparam ALGORITHM_INFO an Algorithm derived class +/// \details AlgorithmImpl provides StaticAlgorithmName from the template parameter BASE +template +class CRYPTOPP_NO_VTABLE AlgorithmImpl : public BASE +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static member function. + /// The name is taken from information provided by BASE. + static std::string CRYPTOPP_API StaticAlgorithmName() {return ALGORITHM_INFO::StaticAlgorithmName();} + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a member function. + /// The name is is acquired by calling StaticAlgorithmName. + std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();} +}; + +/// \brief Exception thrown when an invalid key length is encountered +class CRYPTOPP_DLL InvalidKeyLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidKeyLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the key size associated with the exception + explicit InvalidKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {} +}; + +/// \brief Exception thrown when an invalid number of rounds is encountered +class CRYPTOPP_DLL InvalidRounds : public InvalidArgument +{ +public: + /// \brief Construct an InvalidRounds + /// \param algorithm the Algorithm associated with the exception + /// \param rounds the number of rounds associated with the exception + explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {} +}; + +/// \brief Exception thrown when an invalid block size is encountered +class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument +{ +public: + /// \brief Construct an InvalidBlockSize + /// \param algorithm the Algorithm associated with the exception + /// \param length the block size associated with the exception + explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {} +}; + +/// \brief Exception thrown when an invalid derived key length is encountered +class CRYPTOPP_DLL InvalidDerivedKeyLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidDerivedKeyLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the size associated with the exception + explicit InvalidDerivedKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid derived key length") {} +}; + +/// \brief Exception thrown when an invalid personalization string length is encountered +class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidPersonalizationLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the personalization size associated with the exception + explicit InvalidPersonalizationLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +/// \brief Exception thrown when an invalid salt length is encountered +class CRYPTOPP_DLL InvalidSaltLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidSaltLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the salt size associated with the exception + explicit InvalidSaltLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +// ***************************** + +/// \brief Base class for bufferless filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Bufferless : public T +{ +public: + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} +}; + +/// \brief Base class for unflushable filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Unflushable : public T +{ +public: + /// \brief Flush buffered input and/or output, with signal propagation + /// \param completeFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing + /// input + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 + /// means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and + /// output everything, even if there may not be enough data to complete the + /// action. For example, hard flushing a HexDecoder would cause an error if + /// you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can + /// only be done at "synchronization points". These synchronization points + /// are positions in the data stream that are created by hard flushes on the + /// corresponding reverse filters, in this example ZlibCompressor. This is + /// useful when zlib compressed data is moved across a network in packets + /// and compression state is preserved across packets, as in the SSH2 protocol. + bool Flush(bool completeFlush, int propagation=-1, bool blocking=true) + {return ChannelFlush(DEFAULT_CHANNEL, completeFlush, propagation, blocking);} + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 means + /// unlimited propagation. + bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) + { + if (hardFlush && !InputBufferIsEmpty()) + throw CannotFlush("Unflushable: this object has buffered input that cannot be flushed"); + else + { + BufferedTransformation *attached = this->AttachedTransformation(); + return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false; + } + } + +protected: + virtual bool InputBufferIsEmpty() const {return false;} +}; + +/// \brief Base class for input rejecting filters +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE InputRejecting : public T +{ +public: + struct InputRejected : public NotImplemented + {InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}}; + + /// \name INPUT + //@{ + + /// \brief Input a byte array for processing + /// \param inString the byte array to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \throw InputRejected + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Internally, the default implementation throws InputRejected. + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} + + /// \name SIGNALS + //@{ + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} + + /// \brief Marks the end of a series of messages, without signal propagation + /// \param blocking specifies whether the object should block when completing the processing on + /// the current series of messages + /// \return true if the message was successful, false otherwise + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); throw InputRejected();} + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + + /// \brief Marks the end of a series of messages on a channel + /// \param channel the channel to signal the end of a series of messages + /// \param messageEnd the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool ChannelMessageSeriesEnd(const std::string& channel, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} +}; + +/// \brief Interface for custom flush signals propagation +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomFlushPropagation : public T +{ +public: + /// \name SIGNALS + //@{ + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0; + + //@} + +private: + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} +}; + +/// \brief Interface for custom flush signals +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomSignalPropagation : public CustomFlushPropagation +{ +public: + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0; + +private: + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} +}; + +/// \brief Multiple channels support for custom signal processing +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE Multichannel : public CustomFlushPropagation +{ +public: + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return this->ChannelFlush(DEFAULT_CHANNEL, hardFlush, propagation, blocking);} + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return this->ChannelMessageSeriesEnd(DEFAULT_CHANNEL, propagation, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + byte * CreatePutSpace(size_t &size) + {return this->ChannelCreatePutSpace(DEFAULT_CHANNEL, size);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Derived classes must implement Put2(). + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPut2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Internally, PutModifiable2() calls Put2(). + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPutModifiable2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + + // void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1) + // {PropagateMessageSeriesEnd(propagation, channel);} + + /// \brief Request space which can be written into by the caller + /// \param channel the channel to process the data + /// \param size the requested size of the buffer + /// \return a pointer to a memory block with length size + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of + /// an ArraySink(), the pointer to the array is returned and the size is remaining size. + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {CRYPTOPP_UNUSED(channel); size = 0; return NULLPTR;} + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \return true if all bytes were processed, false otherwise. + bool ChannelPutModifiable(const std::string &channel, byte *inString, size_t length) + {this->ChannelPut(channel, inString, length); return false;} + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param begin the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) =0; + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data + /// \param begin the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return ChannelPut2(channel, begin, length, messageEnd, blocking);} + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0; +}; + +/// \brief Provides auto signaling support +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE AutoSignaling : public T +{ +public: + /// \brief Construct an AutoSignaling + /// \param propagation the propagation count + AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {} + + /// \brief Set propagation of automatically generated and transferred signals + /// \param propagation then new value + /// \details Setting propagation to 0 means do not automatically generate signals. Setting + /// propagation to -1 means unlimited propagation. + void SetAutoSignalPropagation(int propagation) + {m_autoSignalPropagation = propagation;} + + /// \brief Retrieve automatic signal propagation value + /// \return the number of attached transformations the signal is propagated to. 0 indicates + /// the signal is only witnessed by this object + int GetAutoSignalPropagation() const + {return m_autoSignalPropagation;} + +private: + int m_autoSignalPropagation; +}; + +/// \brief Acts as a Source for pre-existing, static data +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Store : public AutoSignaling > +{ +public: + /// \brief Construct a Store + Store() : m_messageEnd(false) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) + { + m_messageEnd = false; + StoreInitialize(parameters); + } + + unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;} + bool GetNextMessage(); + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + +protected: + virtual void StoreInitialize(const NameValuePairs ¶meters) =0; + + bool m_messageEnd; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Sink is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details A Sink doesnot produce any retrievable output. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Sink : public BufferedTransformation +{ +public: + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(transferBytes); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); transferBytes = 0; return 0;} + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +/// \brief Acts as an input discarding Filter or Sink +/// \details The BitBucket discards all input and returns 0 to the caller +/// to indicate all data was processed. +class CRYPTOPP_DLL BitBucket : public Bufferless +{ +public: + std::string AlgorithmName() const {return "BitBucket";} + void IsolatedInitialize(const NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(params);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/siphash.h b/extension/third_party/cryptopp/siphash.h new file mode 100644 index 00000000..4ffe1b50 --- /dev/null +++ b/extension/third_party/cryptopp/siphash.h @@ -0,0 +1,313 @@ +// siphash.h - written and placed in public domain by Jeffrey Walton. + +/// \file siphash.h +/// \brief Classes for SipHash message authentication code +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIPHASH_H +#define CRYPTOPP_SIPHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SipHash message authentication code information +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Info : public FixedKeyLength<16> +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";} + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8)); +}; + +/// \brief SipHash message authentication code base class +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info +{ +public: + static std::string StaticAlgorithmName() { + return std::string(SipHash_Info::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D); + } + + virtual ~SipHash_Base() {} + + SipHash_Base() : m_idx(0) {} + + virtual unsigned int DigestSize() const + {return SipHash_Info::DIGESTSIZE;} + virtual size_t MinKeyLength() const + {return SipHash_Info::MIN_KEYLENGTH;} + virtual size_t MaxKeyLength() const + {return SipHash_Info::MAX_KEYLENGTH;} + virtual size_t DefaultKeyLength() const + {return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual size_t GetValidKeyLength(size_t keylength) const + {CRYPTOPP_UNUSED(keylength); return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual IV_Requirement IVRequirement() const + {return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;} + virtual unsigned int IVSize() const + {return 0;} + virtual unsigned int OptimalBlockSize() const + {return sizeof(word64);} + virtual unsigned int OptimalDataAlignment () const + {return GetAlignmentOf();} + + virtual void Update(const byte *input, size_t length); + virtual void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual void Restart(); + + inline void SIPROUND() + { + m_v[0] += m_v[1]; + m_v[1] = rotlConstant<13>(m_v[1]); + m_v[1] ^= m_v[0]; + m_v[0] = rotlConstant<32>(m_v[0]); + m_v[2] += m_v[3]; + m_v[3] = rotlConstant<16>(m_v[3]); + m_v[3] ^= m_v[2]; + m_v[0] += m_v[3]; + m_v[3] = rotlConstant<21>(m_v[3]); + m_v[3] ^= m_v[0]; + m_v[2] += m_v[1]; + m_v[1] = rotlConstant<17>(m_v[1]); + m_v[1] ^= m_v[2]; + m_v[2] = rotlConstant<32>(m_v[2]); + } + +private: + FixedSizeSecBlock m_v; + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_b; + + // Tail bytes + FixedSizeSecBlock m_acc; + size_t m_idx; +}; + +/// \brief SipHash message authentication code +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 +template +class SipHash : public SipHash_Base +{ +public: + /// \brief Create a SipHash + SipHash() + {this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);} + /// \brief Create a SipHash + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + SipHash(const byte *key, unsigned int length) + {this->ThrowIfInvalidKeyLength(length); + this->UncheckedSetKey(key, length, g_nullNameValuePairs);} +}; + +template +void SipHash_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !length); + if (!length) return; + + if (m_idx) + { + size_t head = STDMIN(size_t(8U-m_idx), length); + memcpy(m_acc+m_idx, input, head); + m_idx += head; input += head; length -= head; + + if (m_idx == 8) + { + word64 m = GetWord(true, LITTLE_ENDIAN_ORDER, m_acc); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + m_idx = 0; + } + } + + while (length >= 8) + { + word64 m = GetWord(false, LITTLE_ENDIAN_ORDER, input); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + input += 8; + length -= 8; + } + + CRYPTOPP_ASSERT(length < 8); + size_t tail = length % 8; + if (tail) + { + memcpy(m_acc+m_idx, input, tail); + m_idx += tail; + } +} + +template +void SipHash_Base::TruncatedFinal(byte *digest, size_t digestSize) +{ + CRYPTOPP_ASSERT(digest); // Pointer is valid + + ThrowIfInvalidTruncatedSize(digestSize); + + // The high octet holds length and is digested mod 256 + m_b[0] += m_idx; m_b[0] <<= 56U; + switch (m_idx) + { + case 7: + m_b[0] |= ((word64)m_acc[6]) << 48; + // fall through + case 6: + m_b[0] |= ((word64)m_acc[5]) << 40; + // fall through + case 5: + m_b[0] |= ((word64)m_acc[4]) << 32; + // fall through + case 4: + m_b[0] |= ((word64)m_acc[3]) << 24; + // fall through + case 3: + m_b[0] |= ((word64)m_acc[2]) << 16; + // fall through + case 2: + m_b[0] |= ((word64)m_acc[1]) << 8; + // fall through + case 1: + m_b[0] |= ((word64)m_acc[0]); + // fall through + case 0: + break; + } + + m_v[3] ^= m_b[0]; + + for (unsigned int i=0; i::DIGESTSIZE)); + Restart(); +} + +template +void SipHash_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + if (key && length) + { + m_k[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key); + m_k[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key+8); + } + else + { + // Avoid Coverity finding + m_k[0] = m_k[1] = 0; + } + Restart(); +} + +template +void SipHash_Base::Restart () +{ + m_v[0] = W64LIT(0x736f6d6570736575); + m_v[1] = W64LIT(0x646f72616e646f6d); + m_v[2] = W64LIT(0x6c7967656e657261); + m_v[3] = W64LIT(0x7465646279746573); + + m_v[3] ^= m_k[1]; + m_v[2] ^= m_k[0]; + m_v[1] ^= m_k[1]; + m_v[0] ^= m_k[0]; + + if (T_128bit) + { + m_v[1] ^= 0xee; + } + + m_idx = 0; + m_b[0] = 0; +} + +NAMESPACE_END + +#endif // CRYPTOPP_SIPHASH_H diff --git a/extension/third_party/cryptopp/skipjack.cpp b/extension/third_party/cryptopp/skipjack.cpp new file mode 100644 index 00000000..d3f59ff7 --- /dev/null +++ b/extension/third_party/cryptopp/skipjack.cpp @@ -0,0 +1,202 @@ +// skipjack.cpp - modified by Wei Dai from Paulo Barreto's skipjack32.c, +// which is public domain according to his web site. + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "skipjack.h" + +/* + * Optimized implementation of SKIPJACK algorithm + * + * originally written by Panu Rissanen 1998.06.24 + * optimized by Mark Tillotson 1998.06.25 + * optimized by Paulo Barreto 1998.06.30 + */ + +NAMESPACE_BEGIN(CryptoPP) + +/** + * The F-table byte permutation (see description of the G-box permutation) + */ +const byte SKIPJACK::Base::fTable[256] = { + 0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9, + 0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28, + 0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53, + 0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2, + 0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8, + 0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90, + 0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76, + 0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d, + 0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18, + 0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4, + 0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40, + 0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5, + 0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2, + 0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8, + 0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac, + 0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46 +}; + +/** + * The key-dependent permutation G on V^16 is a four-round Feistel network. + * The round function is a fixed byte-substitution table (permutation on V^8), + * the F-table. Each round of G incorporates a single byte from the key. + */ +#define g(tab, w, i, j, k, l) \ +{ \ + w ^= (word)tab[i*256 + (w & 0xff)] << 8; \ + w ^= (word)tab[j*256 + (w >> 8)]; \ + w ^= (word)tab[k*256 + (w & 0xff)] << 8; \ + w ^= (word)tab[l*256 + (w >> 8)]; \ +} + +#define g0(tab, w) g(tab, w, 0, 1, 2, 3) +#define g1(tab, w) g(tab, w, 4, 5, 6, 7) +#define g2(tab, w) g(tab, w, 8, 9, 0, 1) +#define g3(tab, w) g(tab, w, 2, 3, 4, 5) +#define g4(tab, w) g(tab, w, 6, 7, 8, 9) + +/** + * The inverse of the G permutation. + */ +#define h(tab, w, i, j, k, l) \ +{ \ + w ^= (word)tab[l*256 + (w >> 8)]; \ + w ^= (word)tab[k*256 + (w & 0xff)] << 8; \ + w ^= (word)tab[j*256 + (w >> 8)]; \ + w ^= (word)tab[i*256 + (w & 0xff)] << 8; \ +} + +#define h0(tab, w) h(tab, w, 0, 1, 2, 3) +#define h1(tab, w) h(tab, w, 4, 5, 6, 7) +#define h2(tab, w) h(tab, w, 8, 9, 0, 1) +#define h3(tab, w) h(tab, w, 2, 3, 4, 5) +#define h4(tab, w) h(tab, w, 6, 7, 8, 9) + +/** + * Preprocess a user key into a table to save an XOR at each F-table access. + */ +void SKIPJACK::Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + /* tab[i][c] = fTable[c ^ key[i]] */ + int i; + for (i = 0; i < 10; i++) { + byte *t = tab+i*256, k = key[9-i]; + int c; + for (c = 0; c < 256; c++) { + t[c] = fTable[c ^ k]; + } + } +} + +typedef BlockGetAndPut Block; + +/** + * Encrypt a single block of data. + */ +void SKIPJACK::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 w1, w2, w3, w4; + Block::Get(inBlock)(w4)(w3)(w2)(w1); + + /* stepping rule A: */ + g0(tab, w1); w4 ^= w1 ^ 1; + g1(tab, w4); w3 ^= w4 ^ 2; + g2(tab, w3); w2 ^= w3 ^ 3; + g3(tab, w2); w1 ^= w2 ^ 4; + g4(tab, w1); w4 ^= w1 ^ 5; + g0(tab, w4); w3 ^= w4 ^ 6; + g1(tab, w3); w2 ^= w3 ^ 7; + g2(tab, w2); w1 ^= w2 ^ 8; + + /* stepping rule B: */ + w2 ^= w1 ^ 9; g3(tab, w1); + w1 ^= w4 ^ 10; g4(tab, w4); + w4 ^= w3 ^ 11; g0(tab, w3); + w3 ^= w2 ^ 12; g1(tab, w2); + w2 ^= w1 ^ 13; g2(tab, w1); + w1 ^= w4 ^ 14; g3(tab, w4); + w4 ^= w3 ^ 15; g4(tab, w3); + w3 ^= w2 ^ 16; g0(tab, w2); + + /* stepping rule A: */ + g1(tab, w1); w4 ^= w1 ^ 17; + g2(tab, w4); w3 ^= w4 ^ 18; + g3(tab, w3); w2 ^= w3 ^ 19; + g4(tab, w2); w1 ^= w2 ^ 20; + g0(tab, w1); w4 ^= w1 ^ 21; + g1(tab, w4); w3 ^= w4 ^ 22; + g2(tab, w3); w2 ^= w3 ^ 23; + g3(tab, w2); w1 ^= w2 ^ 24; + + /* stepping rule B: */ + w2 ^= w1 ^ 25; g4(tab, w1); + w1 ^= w4 ^ 26; g0(tab, w4); + w4 ^= w3 ^ 27; g1(tab, w3); + w3 ^= w2 ^ 28; g2(tab, w2); + w2 ^= w1 ^ 29; g3(tab, w1); + w1 ^= w4 ^ 30; g4(tab, w4); + w4 ^= w3 ^ 31; g0(tab, w3); + w3 ^= w2 ^ 32; g1(tab, w2); + + Block::Put(xorBlock, outBlock)(w4)(w3)(w2)(w1); +} + +/** + * Decrypt a single block of data. + */ +void SKIPJACK::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word16 w1, w2, w3, w4; + Block::Get(inBlock)(w4)(w3)(w2)(w1); + + /* stepping rule A: */ + h1(tab, w2); w3 ^= w2 ^ 32; + h0(tab, w3); w4 ^= w3 ^ 31; + h4(tab, w4); w1 ^= w4 ^ 30; + h3(tab, w1); w2 ^= w1 ^ 29; + h2(tab, w2); w3 ^= w2 ^ 28; + h1(tab, w3); w4 ^= w3 ^ 27; + h0(tab, w4); w1 ^= w4 ^ 26; + h4(tab, w1); w2 ^= w1 ^ 25; + + /* stepping rule B: */ + w1 ^= w2 ^ 24; h3(tab, w2); + w2 ^= w3 ^ 23; h2(tab, w3); + w3 ^= w4 ^ 22; h1(tab, w4); + w4 ^= w1 ^ 21; h0(tab, w1); + w1 ^= w2 ^ 20; h4(tab, w2); + w2 ^= w3 ^ 19; h3(tab, w3); + w3 ^= w4 ^ 18; h2(tab, w4); + w4 ^= w1 ^ 17; h1(tab, w1); + + /* stepping rule A: */ + h0(tab, w2); w3 ^= w2 ^ 16; + h4(tab, w3); w4 ^= w3 ^ 15; + h3(tab, w4); w1 ^= w4 ^ 14; + h2(tab, w1); w2 ^= w1 ^ 13; + h1(tab, w2); w3 ^= w2 ^ 12; + h0(tab, w3); w4 ^= w3 ^ 11; + h4(tab, w4); w1 ^= w4 ^ 10; + h3(tab, w1); w2 ^= w1 ^ 9; + + /* stepping rule B: */ + w1 ^= w2 ^ 8; h2(tab, w2); + w2 ^= w3 ^ 7; h1(tab, w3); + w3 ^= w4 ^ 6; h0(tab, w4); + w4 ^= w1 ^ 5; h4(tab, w1); + w1 ^= w2 ^ 4; h3(tab, w2); + w2 ^= w3 ^ 3; h2(tab, w3); + w3 ^= w4 ^ 2; h1(tab, w4); + w4 ^= w1 ^ 1; h0(tab, w1); + + Block::Put(xorBlock, outBlock)(w4)(w3)(w2)(w1); +} + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/skipjack.h b/extension/third_party/cryptopp/skipjack.h new file mode 100644 index 00000000..f158005a --- /dev/null +++ b/extension/third_party/cryptopp/skipjack.h @@ -0,0 +1,80 @@ +// skipjack.h - originally written and placed in the public domain by Wei Dai + +/// \file skipjack.h +/// \brief Classes for the SKIPJACK block cipher +/// \details The Crypto++ implementation conforms to SKIPJACK and KEA +/// Algorithm Specifications published by NIST in May 1998. The library passes +/// known answer tests available in NIST SP800-17, Table 6, pp. 140-42. +/// \sa SKIPJACK +/// and KEA Algorithm Specifications (May 1998), +/// SKIPJACK on the +// Crypto++ wiki + +#ifndef CRYPTOPP_SKIPJACK_H +#define CRYPTOPP_SKIPJACK_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SKIPJACK block cipher information +struct SKIPJACK_Info : public FixedBlockSize<8>, public FixedKeyLength<10> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "SKIPJACK";} +}; + +/// \brief SKIPJACK block cipher +/// \details The Crypto++ implementation conforms to SKIPJACK and KEA +/// Algorithm Specifications published by NIST in May 1998. The library passes +/// known answer tests available in NIST SP800-17, Table 6, pp. 140-42. +/// \sa SKIPJACK +/// and KEA Algorithm Specifications (May 1998), +/// SKIPJACK on the +/// Crypto++ wiki +class SKIPJACK : public SKIPJACK_Info, public BlockCipherDocumentation +{ + /// \brief SKIPJACK block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + static const byte fTable[256]; + + FixedSizeSecBlock tab; + }; + + /// \brief SKIPJACK block cipher encryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + /// \brief SKIPJACK block cipher decryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SKIPJACK::Encryption SKIPJACKEncryption; +typedef SKIPJACK::Decryption SKIPJACKDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/sm3.cpp b/extension/third_party/cryptopp/sm3.cpp new file mode 100644 index 00000000..bf01dd53 --- /dev/null +++ b/extension/third_party/cryptopp/sm3.cpp @@ -0,0 +1,255 @@ +// sm3.cpp - written and placed in the public domain by Jeffrey Walton and Han Lulu +// Based on the specification provided by Sean Shen and Xiaodong Lee. +// Based on code by Krzysztof Kwiatkowski and Jack Lloyd. +// Also see https://tools.ietf.org/html/draft-shen-sm3-hash. +// +// We understand future ARMv8 enhancements are supposed +// to include SM3 and SM4 related instructions so the function +// is stubbed for an eventual SM3_HashMultipleBlocks_ARMV8. + +#include "pch.h" +#include "config.h" + +#include "sm3.h" +#include "misc.h" +#include "cpu.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::rotlConstant; + +using CryptoPP::SM3; +using CryptoPP::GetBlock; +using CryptoPP::BigEndian; + +inline word32 P0(word32 X) +{ + return X ^ rotlConstant<9>(X) ^ rotlConstant<17>(X); +} + +inline word32 P1(word32 X) +{ + return X ^ rotlConstant<15>(X) ^ rotlConstant<23>(X); +} + +inline word32 EE(word32 W0, word32 W7, word32 W13, word32 W3, word32 W10) +{ + return P1(W0 ^ W7 ^ rotlConstant<15>(W13)) ^ rotlConstant<7>(W3) ^ W10; +} + +inline word32 FF(word32 X, word32 Y, word32 Z) +{ + return (X & Y) | ((X | Y) & Z); +} + +inline word32 GG(word32 X, word32 Y, word32 Z) +{ + return ((Z ^ (X & (Y ^ Z)))); +} + +inline void R1(word32 A, word32& B, word32 C, word32& D, word32 E, word32& F, + word32 G, word32& H, word32 TJ, word32 Wi, word32 Wj) +{ + const word32 A12 = rotlConstant<12>(A); + const word32 TT0 = rotlConstant<7>(A12 + E + TJ); + const word32 TT1 = (A ^ B ^ C) + D + (TT0 ^ A12) + Wj; + const word32 TT2 = (E ^ F ^ G) + H + TT0 + Wi; + + B = rotlConstant<9>(B); D = TT1; + F = rotlConstant<19>(F); H = P0(TT2); +} + +inline void R2(word32 A, word32& B, word32 C, word32& D, word32 E, word32& F, + word32 G, word32& H, word32 TJ, word32 Wi, word32 Wj) +{ + const word32 A12 = rotlConstant<12>(A); + const word32 TT0 = rotlConstant<7>(A12 + E + TJ); + const word32 TT1 = FF(A, B, C) + D + (TT0 ^ A12) + Wj; + const word32 TT2 = GG(E, F, G) + H + TT0 + Wi; + + B = rotlConstant<9>(B); D = TT1; + F = rotlConstant<19>(F); H = P0(TT2); +} + +// Krzysztof Kwiatkowski did a very nice job with this function. +size_t SM3_HashMultipleBlocks_CXX(word32 *state, const word32 *data, size_t length) +{ + CRYPTOPP_ASSERT(data); + + word32 A = state[0], B = state[1], C = state[2], D = state[3]; + word32 E = state[4], F = state[5], G = state[6], H = state[7]; + + while (length >= SM3::BLOCKSIZE) + { + // Reverse bytes on LittleEndian; align pointer on BigEndian + typedef GetBlock InBlock; + InBlock iblk(data); + + word32 W00, W01, W02, W03, W04, W05, W06, W07, W08, W09, W10, W11, W12, W13, W14, W15; + iblk(W00)(W01)(W02)(W03)(W04)(W05)(W06)(W07)(W08)(W09)(W10)(W11)(W12)(W13)(W14)(W15); + + R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04); + W00 = EE(W00, W07, W13, W03, W10); + R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05); + W01 = EE(W01, W08, W14, W04, W11); + R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06); + W02 = EE(W02, W09, W15, W05, W12); + R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07); + W03 = EE(W03, W10, W00, W06, W13); + R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08); + W04 = EE(W04, W11, W01, W07, W14); + R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09); + W05 = EE(W05, W12, W02, W08, W15); + R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10); + W06 = EE(W06, W13, W03, W09, W00); + R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11); + W07 = EE(W07, W14, W04, W10, W01); + R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12); + W08 = EE(W08, W15, W05, W11, W02); + R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13); + W09 = EE(W09, W00, W06, W12, W03); + R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14); + W10 = EE(W10, W01, W07, W13, W04); + R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15); + W11 = EE(W11, W02, W08, W14, W05); + R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00); + W12 = EE(W12, W03, W09, W15, W06); + R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01); + W13 = EE(W13, W04, W10, W00, W07); + R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02); + W14 = EE(W14, W05, W11, W01, W08); + R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03); + W15 = EE(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); + W00 = EE(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); + W01 = EE(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); + W02 = EE(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); + W03 = EE(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); + W04 = EE(W04, W11, W01, W07, W14); + R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); + W05 = EE(W05, W12, W02, W08, W15); + R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); + W06 = EE(W06, W13, W03, W09, W00); + R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); + W07 = EE(W07, W14, W04, W10, W01); + R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); + W08 = EE(W08, W15, W05, W11, W02); + R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); + W09 = EE(W09, W00, W06, W12, W03); + R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); + W10 = EE(W10, W01, W07, W13, W04); + R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); + W11 = EE(W11, W02, W08, W14, W05); + R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); + W12 = EE(W12, W03, W09, W15, W06); + R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); + W13 = EE(W13, W04, W10, W00, W07); + R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); + W14 = EE(W14, W05, W11, W01, W08); + R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); + W15 = EE(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04); + W00 = EE(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05); + W01 = EE(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06); + W02 = EE(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07); + W03 = EE(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08); + W04 = EE(W04, W11, W01, W07, W14); + R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09); + W05 = EE(W05, W12, W02, W08, W15); + R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10); + W06 = EE(W06, W13, W03, W09, W00); + R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11); + W07 = EE(W07, W14, W04, W10, W01); + R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12); + W08 = EE(W08, W15, W05, W11, W02); + R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13); + W09 = EE(W09, W00, W06, W12, W03); + R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14); + W10 = EE(W10, W01, W07, W13, W04); + R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15); + W11 = EE(W11, W02, W08, W14, W05); + R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00); + W12 = EE(W12, W03, W09, W15, W06); + R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01); + W13 = EE(W13, W04, W10, W00, W07); + R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02); + W14 = EE(W14, W05, W11, W01, W08); + R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03); + W15 = EE(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); + W00 = EE(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); + W01 = EE(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); + W02 = EE(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); + W03 = EE(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); + R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); + R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); + R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); + R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); + R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); + R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); + R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); + R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); + R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); + R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); + R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); + + A = (state[0] ^= A); + B = (state[1] ^= B); + C = (state[2] ^= C); + D = (state[3] ^= D); + E = (state[4] ^= E); + F = (state[5] ^= F); + G = (state[6] ^= G); + H = (state[7] ^= H); + + data += SM3::BLOCKSIZE/sizeof(word32); + length -= SM3::BLOCKSIZE; + } + + return length; +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void SM3::InitState(HashWordType *state) +{ + const word32 s[] = { + 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, + 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e + }; + + std::memcpy(state, s, sizeof(s)); +} + +void SM3::Transform(word32 *state, const word32 *data) +{ + CRYPTOPP_ASSERT(state); + CRYPTOPP_ASSERT(data); + + SM3_HashMultipleBlocks_CXX(state, data, SM3::BLOCKSIZE); +} + +size_t SM3::HashMultipleBlocks(const HashWordType *input, size_t length) +{ + const size_t res = length & (SM3::BLOCKSIZE - 1); + SM3_HashMultipleBlocks_CXX(m_state, input, length-res); + return res; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/sm3.h b/extension/third_party/cryptopp/sm3.h new file mode 100644 index 00000000..f163072a --- /dev/null +++ b/extension/third_party/cryptopp/sm3.h @@ -0,0 +1,61 @@ +// sm3.h - written and placed in the public domain by Jeffrey Walton and Han Lulu +// Based on the specification provided by Sean Shen and Xiaodong Lee. +// Based on code by Krzysztof Kwiatkowski and Jack Lloyd. +// Also see https://tools.ietf.org/html/draft-shen-sm3-hash. + +/// \file sm3.h +/// \brief Classes for the SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function and +/// Reference implementation using OpenSSL. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM3_H +#define CRYPTOPP_SM3_H + +#include "config.h" +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function +/// \since Crypto++ 6.0 +class SM3 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA256 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void InitState(HashWordType *state); + + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform() operates the hash on data. When the call is invoked + /// digest holds initial or current state. Upon return digest holds + /// the hash or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void Transform(HashWordType *digest, const HashWordType *data); + + /// \brief The algorithm name + /// \return C-style string "SM3" + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "SM3"; } + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM3_H diff --git a/extension/third_party/cryptopp/sm4.cpp b/extension/third_party/cryptopp/sm4.cpp new file mode 100644 index 00000000..ad7f3222 --- /dev/null +++ b/extension/third_party/cryptopp/sm4.cpp @@ -0,0 +1,212 @@ +// sm4.cpp - written and placed in the public domain by Jeffrey Walton and Han Lulu +// +// We understand future ARMv8 enhancements are supposed +// to include SM3 and SM4 related instructions so the function +// is stubbed for an eventual SM4_Round_ARMV8. + +#include "pch.h" +#include "config.h" + +#include "sm4.h" +#include "misc.h" +#include "cpu.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4307) +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::rotlConstant; + +CRYPTOPP_ALIGN_DATA(4) +const byte S[256] = +{ + 0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, + 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, + 0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, + 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, + 0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, + 0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, + 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, + 0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, + 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, + 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, + 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, + 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, + 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, + 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, + 0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48 +}; + +const word32 CK[32] = +{ + 0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, + 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9, + 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, + 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9, + 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, + 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299, + 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, + 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279 +}; + +inline word32 SM4_H(word32 x) +{ + return (S[GETBYTE(x, 3)] << 24) | (S[GETBYTE(x, 2)] << 16) | (S[GETBYTE(x, 1)] << 8) | (S[GETBYTE(x, 0)]); +} + +inline word32 SM4_G(word32 x) +{ + const word32 t = SM4_H(x); + return t ^ rotlConstant<13>(t) ^ rotlConstant<23>(t); +} + +inline word32 SM4_F(word32 x) +{ + const word32 t = SM4_H(x); + return t ^ rotlConstant<2>(t) ^ rotlConstant<10>(t) ^ rotlConstant<18>(t) ^ rotlConstant<24>(t); +} + +template +inline void SM4_Round(word32 wspace[4], const word32 rkeys[32]) +{ + if (FWD) + { + wspace[0] ^= SM4_F(wspace[1] ^ wspace[2] ^ wspace[3] ^ rkeys[R+0]); + wspace[1] ^= SM4_F(wspace[0] ^ wspace[2] ^ wspace[3] ^ rkeys[R+1]); + wspace[2] ^= SM4_F(wspace[0] ^ wspace[1] ^ wspace[3] ^ rkeys[R+2]); + wspace[3] ^= SM4_F(wspace[0] ^ wspace[1] ^ wspace[2] ^ rkeys[R+3]); + } + else + { + wspace[0] ^= SM4_F(wspace[1] ^ wspace[2] ^ wspace[3] ^ rkeys[R-0]); + wspace[1] ^= SM4_F(wspace[0] ^ wspace[2] ^ wspace[3] ^ rkeys[R-1]); + wspace[2] ^= SM4_F(wspace[0] ^ wspace[1] ^ wspace[3] ^ rkeys[R-2]); + wspace[3] ^= SM4_F(wspace[0] ^ wspace[1] ^ wspace[2] ^ rkeys[R-3]); + } +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS +# if defined(CRYPTOPP_AESNI_AVAILABLE) +extern size_t SM4_Enc_AdvancedProcessBlocks_AESNI(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +# endif +#endif + +std::string SM4::Enc::AlgorithmProvider() const +{ +#if defined(CRYPTOPP_AESNI_AVAILABLE) + if (HasAESNI()) + return "AESNI"; +#endif + return "C++"; +} + +void SM4::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(keyLength == 16); + CRYPTOPP_UNUSED(params); + + m_rkeys.New(32); + m_wspace.New(5); + + GetUserKey(BIG_ENDIAN_ORDER, m_wspace.begin(), 4, userKey, keyLength); + m_wspace[0] ^= 0xa3b1bac6; m_wspace[1] ^= 0x56aa3350; + m_wspace[2] ^= 0x677d9197; m_wspace[3] ^= 0xb27022dc; + + size_t i=0; + do + { + m_rkeys[i] = (m_wspace[0] ^= SM4_G(m_wspace[1] ^ m_wspace[2] ^ m_wspace[3] ^ CK[i])); i++; + m_rkeys[i] = (m_wspace[1] ^= SM4_G(m_wspace[2] ^ m_wspace[3] ^ m_wspace[0] ^ CK[i])); i++; + m_rkeys[i] = (m_wspace[2] ^= SM4_G(m_wspace[3] ^ m_wspace[0] ^ m_wspace[1] ^ CK[i])); i++; + m_rkeys[i] = (m_wspace[3] ^= SM4_G(m_wspace[0] ^ m_wspace[1] ^ m_wspace[2] ^ CK[i])); i++; + } + while (i < 32); +} + +void SM4::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Reverse bytes on LittleEndian; align pointer on BigEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[0])(m_wspace[1])(m_wspace[2])(m_wspace[3]); + + // Timing attack countermeasure, see comments in Rijndael for more details. + // The hardening does not materially affect benchmarks. SM4 runs at + // 30.5 cpb on a Core i5 Skylake with and without the code below. + const int cacheLineSize = GetCacheLineSize(); + volatile word32 _u = 0; + word32 u = _u; + + for (unsigned int i=0; i(m_wspace, m_rkeys); + SM4_Round< 4, true>(m_wspace, m_rkeys); + SM4_Round< 8, true>(m_wspace, m_rkeys); + SM4_Round<12, true>(m_wspace, m_rkeys); + SM4_Round<16, true>(m_wspace, m_rkeys); + SM4_Round<20, true>(m_wspace, m_rkeys); + SM4_Round<24, true>(m_wspace, m_rkeys); + SM4_Round<28, true>(m_wspace, m_rkeys); + + // Reverse bytes on LittleEndian; align pointer on BigEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); +} + +void SM4::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Reverse bytes on LittleEndian; align pointer on BigEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[0])(m_wspace[1])(m_wspace[2])(m_wspace[3]); + + // Timing attack countermeasure, see comments in Rijndael for more details. + // The hardening does not materially affect benchmarks. SM4 runs at + // 30.5 cpb on a Core i5 Skylake with and without the code below. + const int cacheLineSize = GetCacheLineSize(); + volatile word32 _u = 0; + word32 u = _u; + + for (unsigned int i=0; i(m_wspace, m_rkeys); + SM4_Round<27, false>(m_wspace, m_rkeys); + SM4_Round<23, false>(m_wspace, m_rkeys); + SM4_Round<19, false>(m_wspace, m_rkeys); + SM4_Round<15, false>(m_wspace, m_rkeys); + SM4_Round<11, false>(m_wspace, m_rkeys); + SM4_Round< 7, false>(m_wspace, m_rkeys); + SM4_Round< 3, false>(m_wspace, m_rkeys); + + // Reverse bytes on LittleEndian; align pointer on BigEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); +} + +#if CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS +size_t SM4::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if defined(CRYPTOPP_AESNI_AVAILABLE) + if (HasAESNI()) { + return SM4_Enc_AdvancedProcessBlocks_AESNI(m_rkeys, 32, + inBlocks, xorBlocks, outBlocks, length, flags); + } +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/sm4.h b/extension/third_party/cryptopp/sm4.h new file mode 100644 index 00000000..67f76052 --- /dev/null +++ b/extension/third_party/cryptopp/sm4.h @@ -0,0 +1,96 @@ +// sm4.h - written and placed in the public domain by Jeffrey Walton and Han Lulu + +/// \file sm4.h +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formely known as SMS4. +/// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is not acclerated because +/// it is not profitable. Thanks to Markku-Juhani Olavi Saarinen for help and the code. +/// \sa SMS4 Encryption Algorithm for Wireless Networks, +/// Reference implementation using OpenSSL and +/// Markku-Juhani Olavi Saarinen GitHub. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM4_H +#define CRYPTOPP_SM4_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) +# ifndef CRYPTOPP_DISABLE_SM4_SIMD +# define CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM4 block cipher information +/// \since Crypto++ 6.0 +struct SM4_Info : public FixedBlockSize<16>, FixedKeyLength<16> +{ + static const std::string StaticAlgorithmName() + { + return "SM4"; + } +}; + +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formely known as SMS4. +/// \sa SMS4 Encryption Algorithm for Wireless Networks +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SM4 : public SM4_Info, public BlockCipherDocumentation +{ +public: + /// \brief SM4 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + SecBlock > m_rkeys; + mutable SecBlock > m_wspace; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is + /// not acclerated because it is not profitable. Thanks to Markku-Juhani Olavi + /// Saarinen. + /// \since Crypto++ 6.0, AESNI encryption since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + std::string AlgorithmProvider() const; + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is + /// not acclerated because it is not profitable. Thanks to Markku-Juhani Olavi + /// Saarinen. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM4_H diff --git a/extension/third_party/cryptopp/sm4_simd.cpp b/extension/third_party/cryptopp/sm4_simd.cpp new file mode 100644 index 00000000..d19e0592 --- /dev/null +++ b/extension/third_party/cryptopp/sm4_simd.cpp @@ -0,0 +1,323 @@ +// sm4_simd.cpp - written and placed in the public domain by +// Markku-Juhani O. Saarinen and Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// AESNI, ARM NEON and ARMv8a, and Power7 Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. +// +// AES-NI based on Markku-Juhani O. Saarinen work at https://github.com/mjosaarinen/sm4ni. +// +// ARMv8 is upcoming. + +#include "pch.h" +#include "config.h" + +#include "sm4.h" +#include "misc.h" + +// Uncomment for benchmarking C++ against SSE. +// Do so in both simon.cpp and simon_simd.cpp. +// #undef CRYPTOPP_AESNI_AVAILABLE + +#if (CRYPTOPP_AESNI_AVAILABLE) +# include "adv_simd.h" +# include +# include +# include +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char SM4_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; + +#if (CRYPTOPP_AESNI_AVAILABLE) + +template +inline __m128i ShiftLeft(const __m128i& val) +{ + return _mm_slli_epi32(val, R); +} + +template +inline __m128i ShiftRight(const __m128i& val) +{ + return _mm_srli_epi32(val, R); +} + +template +inline __m128i ShiftLeft64(const __m128i& val) +{ + return _mm_slli_epi64(val, R); +} + +template +inline __m128i ShiftRight64(const __m128i& val) +{ + return _mm_srli_epi64(val, R); +} + +template +inline __m128i RotateLeft(const __m128i& val) +{ + return _mm_or_si128( + _mm_slli_epi32(val, R), _mm_srli_epi32(val, 32-R)); +} + +template +inline __m128i RotateRight(const __m128i& val) +{ + return _mm_or_si128( + _mm_slli_epi32(val, 32-R), _mm_srli_epi32(val, R)); +} + +template <> +inline __m128i RotateLeft<8>(const __m128i& val) +{ + const __m128i r08 = _mm_set_epi32(0x0E0D0C0F, 0x0A09080B, 0x06050407, 0x02010003); + return _mm_shuffle_epi8(val, r08); +} + +template <> +inline __m128i RotateLeft<16>(const __m128i& val) +{ + const __m128i mask = _mm_set_epi32(0x0D0C0F0E, 0x09080B0A, 0x05040706, 0x01000302); + return _mm_shuffle_epi8(val, mask); +} + +template <> +inline __m128i RotateLeft<24>(const __m128i& val) +{ + const __m128i mask = _mm_set_epi32(0x0C0F0E0D, 0x080B0A09, 0x04070605, 0x00030201); + return _mm_shuffle_epi8(val, mask); +} + +/// \brief Unpack XMM words +/// \tparam IDX the element from each XMM word +/// \param a the first XMM word +/// \param b the second XMM word +/// \param c the third XMM word +/// \param d the fourth XMM word +/// \details UnpackXMM selects the IDX element from a, b, c, d and returns a concatenation +/// equivalent to a[IDX] || b[IDX] || c[IDX] || d[IDX]. +template +inline __m128i UnpackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + CRYPTOPP_UNUSED(c); CRYPTOPP_UNUSED(d); + CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_unpacklo_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + const __m128i r1 = _mm_unpacklo_epi32(a, b); + const __m128i r2 = _mm_unpacklo_epi32(c, d); + return _mm_unpackhi_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_unpacklo_epi64(r1, r2); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + const __m128i r1 = _mm_unpackhi_epi32(a, b); + const __m128i r2 = _mm_unpackhi_epi32(c, d); + return _mm_unpackhi_epi64(r1, r2); +} + +/// \brief Unpack a XMM word +/// \tparam IDX the element from each XMM word +/// \param v the first XMM word +/// \details UnpackXMM selects the IDX element from v and returns a concatenation +/// equivalent to v[IDX] || v[IDX] || v[IDX] || v[IDX]. +template +inline __m128i UnpackXMM(const __m128i& v) +{ + // Should not be instantiated + CRYPTOPP_UNUSED(v); CRYPTOPP_ASSERT(0); + return _mm_setzero_si128(); +} + +template <> +inline __m128i UnpackXMM<0>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(3,2,1,0, 3,2,1,0, 3,2,1,0, 3,2,1,0)); +} + +template <> +inline __m128i UnpackXMM<1>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(7,6,5,4, 7,6,5,4, 7,6,5,4, 7,6,5,4)); +} + +template <> +inline __m128i UnpackXMM<2>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(11,10,9,8, 11,10,9,8, 11,10,9,8, 11,10,9,8)); +} + +template <> +inline __m128i UnpackXMM<3>(const __m128i& v) +{ + // Splat to all lanes + return _mm_shuffle_epi8(v, _mm_set_epi8(15,14,13,12, 15,14,13,12, 15,14,13,12, 15,14,13,12)); +} + +template +inline __m128i RepackXMM(const __m128i& a, const __m128i& b, const __m128i& c, const __m128i& d) +{ + return UnpackXMM(a, b, c, d); +} + +template +inline __m128i RepackXMM(const __m128i& v) +{ + return UnpackXMM(v); +} + +inline void SM4_Encrypt(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys) +{ + // nibble mask + const __m128i c0f = _mm_set_epi32(0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F); + + // flip all bytes in all 32-bit words + const __m128i flp = _mm_set_epi32(0x0C0D0E0F, 0x08090A0B, 0x04050607, 0x00010203); + + // inverse shift rows + const __m128i shr = _mm_set_epi32(0x0306090C, 0x0F020508, 0x0B0E0104, 0x070A0D00); + + // Affine transform 1 (low and high hibbles) + const __m128i m1l = _mm_set_epi32(0xC7C1B4B2, 0x22245157, 0x9197E2E4, 0x74720701); + const __m128i m1h = _mm_set_epi32(0xF052B91B, 0xF95BB012, 0xE240AB09, 0xEB49A200); + + // Affine transform 2 (low and high hibbles) + const __m128i m2l = _mm_set_epi32(0xEDD14478, 0x172BBE82, 0x5B67F2CE, 0xA19D0834); + const __m128i m2h = _mm_set_epi32(0x11CDBE62, 0xCC1063BF, 0xAE7201DD, 0x73AFDC00); + + __m128i t0 = UnpackXMM<0>(block0, block1, block2, block3); + __m128i t1 = UnpackXMM<1>(block0, block1, block2, block3); + __m128i t2 = UnpackXMM<2>(block0, block1, block2, block3); + __m128i t3 = UnpackXMM<3>(block0, block1, block2, block3); + + t0 = _mm_shuffle_epi8(t0, flp); + t1 = _mm_shuffle_epi8(t1, flp); + t2 = _mm_shuffle_epi8(t2, flp); + t3 = _mm_shuffle_epi8(t3, flp); + + const unsigned int ROUNDS = 32; + for (unsigned int i = 0; i < ROUNDS; i++) + { + const __m128i k = _mm_shuffle_epi32(_mm_castps_si128( + _mm_load_ss((const float*)(subkeys+i))), _MM_SHUFFLE(0,0,0,0)); + + __m128i x, y; + x = _mm_xor_si128(t1, _mm_xor_si128(t2, _mm_xor_si128(t3, k))); + + y = _mm_and_si128(x, c0f); // inner affine + y = _mm_shuffle_epi8(m1l, y); + x = _mm_and_si128(ShiftRight64<4>(x), c0f); + x = _mm_xor_si128(_mm_shuffle_epi8(m1h, x), y); + + x = _mm_shuffle_epi8(x, shr); // inverse MixColumns + x = _mm_aesenclast_si128(x, c0f); // AESNI instruction + + y = _mm_andnot_si128(x, c0f); // outer affine + y = _mm_shuffle_epi8(m2l, y); + x = _mm_and_si128(ShiftRight64<4>(x), c0f); + x = _mm_xor_si128(_mm_shuffle_epi8(m2h, x), y); + + // 4 parallel L1 linear transforms + y = _mm_xor_si128(x, RotateLeft<8>(x)); + y = _mm_xor_si128(y, RotateLeft<16>(x)); + y = _mm_xor_si128(ShiftLeft<2>(y), ShiftRight<30>(y)); + x = _mm_xor_si128(x, _mm_xor_si128(y, RotateLeft<24>(x))); + + // rotate registers + x = _mm_xor_si128(x, t0); + t0 = t1; t1 = t2; + t2 = t3; t3 = x; + } + + t0 = _mm_shuffle_epi8(t0, flp); + t1 = _mm_shuffle_epi8(t1, flp); + t2 = _mm_shuffle_epi8(t2, flp); + t3 = _mm_shuffle_epi8(t3, flp); + + block0 = RepackXMM<0>(t3,t2,t1,t0); + block1 = RepackXMM<1>(t3,t2,t1,t0); + block2 = RepackXMM<2>(t3,t2,t1,t0); + block3 = RepackXMM<3>(t3,t2,t1,t0); +} + +inline void SM4_Enc_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int /*rounds*/) +{ + SM4_Encrypt(block0, block1, block2, block3, subkeys); +} + +inline void SM4_Dec_4_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, const word32 *subkeys, unsigned int /*rounds*/) +{ + SM4_Encrypt(block0, block1, block2, block3, subkeys); +} + +inline void SM4_Enc_Block(__m128i &block0, + const word32 *subkeys, unsigned int /*rounds*/) +{ + __m128i t1 = _mm_setzero_si128(); + __m128i t2 = _mm_setzero_si128(); + __m128i t3 = _mm_setzero_si128(); + + SM4_Encrypt(block0, t1, t2, t3, subkeys); +} + +inline void SM4_Dec_Block(__m128i &block0, + const word32 *subkeys, unsigned int /*rounds*/) +{ + __m128i t1 = _mm_setzero_si128(); + __m128i t2 = _mm_setzero_si128(); + __m128i t3 = _mm_setzero_si128(); + + SM4_Encrypt(block0, t1, t2, t3, subkeys); +} + +#endif // CRYPTOPP_AESNI_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_AESNI_AVAILABLE) +size_t SM4_Enc_AdvancedProcessBlocks_AESNI(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_4x1_SSE(SM4_Enc_Block, SM4_Enc_4_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_AESNI_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/smartptr.h b/extension/third_party/cryptopp/smartptr.h new file mode 100644 index 00000000..04cb9a42 --- /dev/null +++ b/extension/third_party/cryptopp/smartptr.h @@ -0,0 +1,257 @@ +// smartptr.h - originally written and placed in the public domain by Wei Dai + +/// \file smartptr.h +/// \brief Classes for automatic resource management + +#ifndef CRYPTOPP_SMARTPTR_H +#define CRYPTOPP_SMARTPTR_H + +#include "config.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Manages resources for a single object +/// \tparam T class or type +/// \details \p simple_ptr is used frequently in the library to manage resources and +/// ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization). +template class simple_ptr +{ +public: + simple_ptr(T *p = NULLPTR) : m_p(p) {} + ~simple_ptr() + { + delete m_p; + m_p = NULLPTR; + } + + T *m_p; +}; + +/// \brief Pointer that overloads operator -> +/// \tparam T class or type +/// \details member_ptr is used frequently in the library to avoid the issues related to +/// std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent). +/// \bug Issue 48: "Use of auto_ptr +/// causes dirty compile under C++11" +template class member_ptr +{ +public: + explicit member_ptr(T *p = NULLPTR) : m_p(p) {} + + ~member_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return m_p; } + + const T* get() const { return m_p; } + T* get() { return m_p; } + + T* release() + { + T *old_p = m_p; + m_p = NULLPTR; + return old_p; + } + + void reset(T *p = NULLPTR); + +protected: + member_ptr(const member_ptr& rhs); // copy not allowed + void operator=(const member_ptr& rhs); // assignment not allowed + + T *m_p; +}; + +template member_ptr::~member_ptr() {delete m_p;} +template void member_ptr::reset(T *p) {delete m_p; m_p = p;} + +// ******************************************************** + +/// \brief Value pointer +/// \tparam T class or type +template class value_ptr : public member_ptr +{ +public: + value_ptr(const T &obj) : member_ptr(new T(obj)) {} + value_ptr(T *p = NULLPTR) : member_ptr(p) {} + value_ptr(const value_ptr& rhs) + : member_ptr(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {} + + value_ptr& operator=(const value_ptr& rhs); + bool operator==(const value_ptr& rhs) + { + return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p); + } +}; + +template value_ptr& value_ptr::operator=(const value_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief A pointer which can be copied and cloned +/// \tparam T class or type +/// \details \p T should adhere to the \p Clonable interface +template class clonable_ptr : public member_ptr +{ +public: + clonable_ptr(const T &obj) : member_ptr(obj.Clone()) {} + clonable_ptr(T *p = NULLPTR) : member_ptr(p) {} + clonable_ptr(const clonable_ptr& rhs) + : member_ptr(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {} + + clonable_ptr& operator=(const clonable_ptr& rhs); +}; + +template clonable_ptr& clonable_ptr::operator=(const clonable_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief Reference counted pointer +/// \tparam T class or type +/// \details users should declare \p m_referenceCount as std::atomic +/// (or similar) under C++ 11 +template class counted_ptr +{ +public: + explicit counted_ptr(T *p = NULLPTR); + counted_ptr(const T &r) : m_p(0) {attach(r);} + counted_ptr(const counted_ptr& rhs); + + ~counted_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return get(); } + + const T* get() const { return m_p; } + T* get(); + + void attach(const T &p); + + counted_ptr & operator=(const counted_ptr& rhs); + +private: + T *m_p; +}; + +template counted_ptr::counted_ptr(T *p) + : m_p(p) +{ + if (m_p) + m_p->m_referenceCount = 1; +} + +template counted_ptr::counted_ptr(const counted_ptr& rhs) + : m_p(rhs.m_p) +{ + if (m_p) + m_p->m_referenceCount++; +} + +template counted_ptr::~counted_ptr() +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; +} + +template void counted_ptr::attach(const T &r) +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + if (r.m_referenceCount == 0) + { + m_p = r.clone(); + m_p->m_referenceCount = 1; + } + else + { + m_p = const_cast(&r); + m_p->m_referenceCount++; + } +} + +template T* counted_ptr::get() +{ + if (m_p && m_p->m_referenceCount > 1) + { + T *temp = m_p->clone(); + m_p->m_referenceCount--; + m_p = temp; + m_p->m_referenceCount = 1; + } + return m_p; +} + +template counted_ptr & counted_ptr::operator=(const counted_ptr& rhs) +{ + if (m_p != rhs.m_p) + { + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + m_p = rhs.m_p; + if (m_p) + m_p->m_referenceCount++; + } + return *this; +} + +// ******************************************************** + +/// \brief Manages resources for an array of objects +/// \tparam T class or type +template class vector_member_ptrs +{ +public: + /// Construct an arry of \p T + /// \param size the size of the array, in elements + /// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized. + vector_member_ptrs(size_t size=0) + : m_size(size), m_ptr(new member_ptr[size]) {} + ~vector_member_ptrs() + {delete [] this->m_ptr;} + + member_ptr& operator[](size_t index) + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + const member_ptr& operator[](size_t index) const + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + + size_t size() const {return this->m_size;} + void resize(size_t newSize) + { + member_ptr *newPtr = new member_ptr[newSize]; + for (size_t i=0; im_size && im_ptr[i].release()); + delete [] this->m_ptr; + this->m_size = newSize; + this->m_ptr = newPtr; + } + +private: + vector_member_ptrs(const vector_member_ptrs &c); // copy not allowed + void operator=(const vector_member_ptrs &x); // assignment not allowed + + size_t m_size; + member_ptr *m_ptr; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/sosemanuk.cpp b/extension/third_party/cryptopp/sosemanuk.cpp new file mode 100644 index 00000000..82cf8c92 --- /dev/null +++ b/extension/third_party/cryptopp/sosemanuk.cpp @@ -0,0 +1,728 @@ +// sosemanuk.cpp - originally written and placed in the public domain by Wei Dai + +// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM sosemanuk.cpp" to generate MASM code + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702 4731) +#endif + +#ifndef CRYPTOPP_GENERATE_X64_MASM + +#include "sosemanuk.h" +#include "serpentp.h" +#include "secblock.h" +#include "misc.h" +#include "cpu.h" + +NAMESPACE_BEGIN(CryptoPP) + +std::string SosemanukPolicy::AlgorithmProvider() const +{ +#ifndef CRYPTOPP_DISABLE_SOSEMANUK_ASM +# if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +# endif +#endif + return "C++"; +} + +void SosemanukPolicy::CipherSetKey(const NameValuePairs ¶ms, const byte *userKey, size_t keylen) +{ + CRYPTOPP_UNUSED(params); + Serpent_KeySchedule(m_key, 24, userKey, keylen); +} + +void SosemanukPolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(iv), CRYPTOPP_UNUSED(length); + CRYPTOPP_ASSERT(length==16); + + word32 a, b, c, d, e; + + typedef BlockGetAndPut Block; + Block::Get(iv)(a)(b)(c)(d); + + const word32 *k = m_key; + unsigned int i=1; + + do + { + beforeS0(KX); beforeS0(S0); afterS0(LT); + afterS0(KX); afterS0(S1); afterS1(LT); + if (i == 3) // after 18th round + { + m_state[4] = b; + m_state[5] = e; + m_state[10] = c; + m_state[11] = a; + } + afterS1(KX); afterS1(S2); afterS2(LT); + afterS2(KX); afterS2(S3); afterS3(LT); + if (i == 2) // after 12th round + { + m_state[6] = c; + m_state[7] = d; + m_state[8] = b; + m_state[9] = e; + } + afterS3(KX); afterS3(S4); afterS4(LT); + afterS4(KX); afterS4(S5); afterS5(LT); + afterS5(KX); afterS5(S6); afterS6(LT); + afterS6(KX); afterS6(S7); afterS7(LT); + + if (i == 3) + break; + + ++i; + c = b; + b = e; + e = d; + d = a; + a = e; + k += 32; + } + while (true); + + afterS7(KX); + + m_state[0] = a; + m_state[1] = b; + m_state[2] = e; + m_state[3] = d; + +#define XMUX(c, x, y) (x ^ (y & (0 - (c & 1)))) + m_state[11] += XMUX(m_state[10], m_state[1], m_state[8]); + m_state[10] = rotlConstant<7>(m_state[10] * 0x54655307); +} + +extern "C" { +word32 s_sosemanukMulTables[512] = { +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) && !defined(CRYPTOPP_DISABLE_SOSEMANUK_ASM) + 0x00000000, 0xE19FCF12, 0x6B973724, 0x8A08F836, + 0xD6876E48, 0x3718A15A, 0xBD10596C, 0x5C8F967E, + 0x05A7DC90, 0xE4381382, 0x6E30EBB4, 0x8FAF24A6, + 0xD320B2D8, 0x32BF7DCA, 0xB8B785FC, 0x59284AEE, + 0x0AE71189, 0xEB78DE9B, 0x617026AD, 0x80EFE9BF, + 0xDC607FC1, 0x3DFFB0D3, 0xB7F748E5, 0x566887F7, + 0x0F40CD19, 0xEEDF020B, 0x64D7FA3D, 0x8548352F, + 0xD9C7A351, 0x38586C43, 0xB2509475, 0x53CF5B67, + 0x146722BB, 0xF5F8EDA9, 0x7FF0159F, 0x9E6FDA8D, + 0xC2E04CF3, 0x237F83E1, 0xA9777BD7, 0x48E8B4C5, + 0x11C0FE2B, 0xF05F3139, 0x7A57C90F, 0x9BC8061D, + 0xC7479063, 0x26D85F71, 0xACD0A747, 0x4D4F6855, + 0x1E803332, 0xFF1FFC20, 0x75170416, 0x9488CB04, + 0xC8075D7A, 0x29989268, 0xA3906A5E, 0x420FA54C, + 0x1B27EFA2, 0xFAB820B0, 0x70B0D886, 0x912F1794, + 0xCDA081EA, 0x2C3F4EF8, 0xA637B6CE, 0x47A879DC, + 0x28CE44DF, 0xC9518BCD, 0x435973FB, 0xA2C6BCE9, + 0xFE492A97, 0x1FD6E585, 0x95DE1DB3, 0x7441D2A1, + 0x2D69984F, 0xCCF6575D, 0x46FEAF6B, 0xA7616079, + 0xFBEEF607, 0x1A713915, 0x9079C123, 0x71E60E31, + 0x22295556, 0xC3B69A44, 0x49BE6272, 0xA821AD60, + 0xF4AE3B1E, 0x1531F40C, 0x9F390C3A, 0x7EA6C328, + 0x278E89C6, 0xC61146D4, 0x4C19BEE2, 0xAD8671F0, + 0xF109E78E, 0x1096289C, 0x9A9ED0AA, 0x7B011FB8, + 0x3CA96664, 0xDD36A976, 0x573E5140, 0xB6A19E52, + 0xEA2E082C, 0x0BB1C73E, 0x81B93F08, 0x6026F01A, + 0x390EBAF4, 0xD89175E6, 0x52998DD0, 0xB30642C2, + 0xEF89D4BC, 0x0E161BAE, 0x841EE398, 0x65812C8A, + 0x364E77ED, 0xD7D1B8FF, 0x5DD940C9, 0xBC468FDB, + 0xE0C919A5, 0x0156D6B7, 0x8B5E2E81, 0x6AC1E193, + 0x33E9AB7D, 0xD276646F, 0x587E9C59, 0xB9E1534B, + 0xE56EC535, 0x04F10A27, 0x8EF9F211, 0x6F663D03, + 0x50358817, 0xB1AA4705, 0x3BA2BF33, 0xDA3D7021, + 0x86B2E65F, 0x672D294D, 0xED25D17B, 0x0CBA1E69, + 0x55925487, 0xB40D9B95, 0x3E0563A3, 0xDF9AACB1, + 0x83153ACF, 0x628AF5DD, 0xE8820DEB, 0x091DC2F9, + 0x5AD2999E, 0xBB4D568C, 0x3145AEBA, 0xD0DA61A8, + 0x8C55F7D6, 0x6DCA38C4, 0xE7C2C0F2, 0x065D0FE0, + 0x5F75450E, 0xBEEA8A1C, 0x34E2722A, 0xD57DBD38, + 0x89F22B46, 0x686DE454, 0xE2651C62, 0x03FAD370, + 0x4452AAAC, 0xA5CD65BE, 0x2FC59D88, 0xCE5A529A, + 0x92D5C4E4, 0x734A0BF6, 0xF942F3C0, 0x18DD3CD2, + 0x41F5763C, 0xA06AB92E, 0x2A624118, 0xCBFD8E0A, + 0x97721874, 0x76EDD766, 0xFCE52F50, 0x1D7AE042, + 0x4EB5BB25, 0xAF2A7437, 0x25228C01, 0xC4BD4313, + 0x9832D56D, 0x79AD1A7F, 0xF3A5E249, 0x123A2D5B, + 0x4B1267B5, 0xAA8DA8A7, 0x20855091, 0xC11A9F83, + 0x9D9509FD, 0x7C0AC6EF, 0xF6023ED9, 0x179DF1CB, + 0x78FBCCC8, 0x996403DA, 0x136CFBEC, 0xF2F334FE, + 0xAE7CA280, 0x4FE36D92, 0xC5EB95A4, 0x24745AB6, + 0x7D5C1058, 0x9CC3DF4A, 0x16CB277C, 0xF754E86E, + 0xABDB7E10, 0x4A44B102, 0xC04C4934, 0x21D38626, + 0x721CDD41, 0x93831253, 0x198BEA65, 0xF8142577, + 0xA49BB309, 0x45047C1B, 0xCF0C842D, 0x2E934B3F, + 0x77BB01D1, 0x9624CEC3, 0x1C2C36F5, 0xFDB3F9E7, + 0xA13C6F99, 0x40A3A08B, 0xCAAB58BD, 0x2B3497AF, + 0x6C9CEE73, 0x8D032161, 0x070BD957, 0xE6941645, + 0xBA1B803B, 0x5B844F29, 0xD18CB71F, 0x3013780D, + 0x693B32E3, 0x88A4FDF1, 0x02AC05C7, 0xE333CAD5, + 0xBFBC5CAB, 0x5E2393B9, 0xD42B6B8F, 0x35B4A49D, + 0x667BFFFA, 0x87E430E8, 0x0DECC8DE, 0xEC7307CC, + 0xB0FC91B2, 0x51635EA0, 0xDB6BA696, 0x3AF46984, + 0x63DC236A, 0x8243EC78, 0x084B144E, 0xE9D4DB5C, + 0xB55B4D22, 0x54C48230, 0xDECC7A06, 0x3F53B514, +#else + 0x00000000, 0xE19FCF13, 0x6B973726, 0x8A08F835, + 0xD6876E4C, 0x3718A15F, 0xBD10596A, 0x5C8F9679, + 0x05A7DC98, 0xE438138B, 0x6E30EBBE, 0x8FAF24AD, + 0xD320B2D4, 0x32BF7DC7, 0xB8B785F2, 0x59284AE1, + 0x0AE71199, 0xEB78DE8A, 0x617026BF, 0x80EFE9AC, + 0xDC607FD5, 0x3DFFB0C6, 0xB7F748F3, 0x566887E0, + 0x0F40CD01, 0xEEDF0212, 0x64D7FA27, 0x85483534, + 0xD9C7A34D, 0x38586C5E, 0xB250946B, 0x53CF5B78, + 0x1467229B, 0xF5F8ED88, 0x7FF015BD, 0x9E6FDAAE, + 0xC2E04CD7, 0x237F83C4, 0xA9777BF1, 0x48E8B4E2, + 0x11C0FE03, 0xF05F3110, 0x7A57C925, 0x9BC80636, + 0xC747904F, 0x26D85F5C, 0xACD0A769, 0x4D4F687A, + 0x1E803302, 0xFF1FFC11, 0x75170424, 0x9488CB37, + 0xC8075D4E, 0x2998925D, 0xA3906A68, 0x420FA57B, + 0x1B27EF9A, 0xFAB82089, 0x70B0D8BC, 0x912F17AF, + 0xCDA081D6, 0x2C3F4EC5, 0xA637B6F0, 0x47A879E3, + 0x28CE449F, 0xC9518B8C, 0x435973B9, 0xA2C6BCAA, + 0xFE492AD3, 0x1FD6E5C0, 0x95DE1DF5, 0x7441D2E6, + 0x2D699807, 0xCCF65714, 0x46FEAF21, 0xA7616032, + 0xFBEEF64B, 0x1A713958, 0x9079C16D, 0x71E60E7E, + 0x22295506, 0xC3B69A15, 0x49BE6220, 0xA821AD33, + 0xF4AE3B4A, 0x1531F459, 0x9F390C6C, 0x7EA6C37F, + 0x278E899E, 0xC611468D, 0x4C19BEB8, 0xAD8671AB, + 0xF109E7D2, 0x109628C1, 0x9A9ED0F4, 0x7B011FE7, + 0x3CA96604, 0xDD36A917, 0x573E5122, 0xB6A19E31, + 0xEA2E0848, 0x0BB1C75B, 0x81B93F6E, 0x6026F07D, + 0x390EBA9C, 0xD891758F, 0x52998DBA, 0xB30642A9, + 0xEF89D4D0, 0x0E161BC3, 0x841EE3F6, 0x65812CE5, + 0x364E779D, 0xD7D1B88E, 0x5DD940BB, 0xBC468FA8, + 0xE0C919D1, 0x0156D6C2, 0x8B5E2EF7, 0x6AC1E1E4, + 0x33E9AB05, 0xD2766416, 0x587E9C23, 0xB9E15330, + 0xE56EC549, 0x04F10A5A, 0x8EF9F26F, 0x6F663D7C, + 0x50358897, 0xB1AA4784, 0x3BA2BFB1, 0xDA3D70A2, + 0x86B2E6DB, 0x672D29C8, 0xED25D1FD, 0x0CBA1EEE, + 0x5592540F, 0xB40D9B1C, 0x3E056329, 0xDF9AAC3A, + 0x83153A43, 0x628AF550, 0xE8820D65, 0x091DC276, + 0x5AD2990E, 0xBB4D561D, 0x3145AE28, 0xD0DA613B, + 0x8C55F742, 0x6DCA3851, 0xE7C2C064, 0x065D0F77, + 0x5F754596, 0xBEEA8A85, 0x34E272B0, 0xD57DBDA3, + 0x89F22BDA, 0x686DE4C9, 0xE2651CFC, 0x03FAD3EF, + 0x4452AA0C, 0xA5CD651F, 0x2FC59D2A, 0xCE5A5239, + 0x92D5C440, 0x734A0B53, 0xF942F366, 0x18DD3C75, + 0x41F57694, 0xA06AB987, 0x2A6241B2, 0xCBFD8EA1, + 0x977218D8, 0x76EDD7CB, 0xFCE52FFE, 0x1D7AE0ED, + 0x4EB5BB95, 0xAF2A7486, 0x25228CB3, 0xC4BD43A0, + 0x9832D5D9, 0x79AD1ACA, 0xF3A5E2FF, 0x123A2DEC, + 0x4B12670D, 0xAA8DA81E, 0x2085502B, 0xC11A9F38, + 0x9D950941, 0x7C0AC652, 0xF6023E67, 0x179DF174, + 0x78FBCC08, 0x9964031B, 0x136CFB2E, 0xF2F3343D, + 0xAE7CA244, 0x4FE36D57, 0xC5EB9562, 0x24745A71, + 0x7D5C1090, 0x9CC3DF83, 0x16CB27B6, 0xF754E8A5, + 0xABDB7EDC, 0x4A44B1CF, 0xC04C49FA, 0x21D386E9, + 0x721CDD91, 0x93831282, 0x198BEAB7, 0xF81425A4, + 0xA49BB3DD, 0x45047CCE, 0xCF0C84FB, 0x2E934BE8, + 0x77BB0109, 0x9624CE1A, 0x1C2C362F, 0xFDB3F93C, + 0xA13C6F45, 0x40A3A056, 0xCAAB5863, 0x2B349770, + 0x6C9CEE93, 0x8D032180, 0x070BD9B5, 0xE69416A6, + 0xBA1B80DF, 0x5B844FCC, 0xD18CB7F9, 0x301378EA, + 0x693B320B, 0x88A4FD18, 0x02AC052D, 0xE333CA3E, + 0xBFBC5C47, 0x5E239354, 0xD42B6B61, 0x35B4A472, + 0x667BFF0A, 0x87E43019, 0x0DECC82C, 0xEC73073F, + 0xB0FC9146, 0x51635E55, 0xDB6BA660, 0x3AF46973, + 0x63DC2392, 0x8243EC81, 0x084B14B4, 0xE9D4DBA7, + 0xB55B4DDE, 0x54C482CD, 0xDECC7AF8, 0x3F53B5EB, +#endif + 0x00000000, 0x180F40CD, 0x301E8033, 0x2811C0FE, + 0x603CA966, 0x7833E9AB, 0x50222955, 0x482D6998, + 0xC078FBCC, 0xD877BB01, 0xF0667BFF, 0xE8693B32, + 0xA04452AA, 0xB84B1267, 0x905AD299, 0x88559254, + 0x29F05F31, 0x31FF1FFC, 0x19EEDF02, 0x01E19FCF, + 0x49CCF657, 0x51C3B69A, 0x79D27664, 0x61DD36A9, + 0xE988A4FD, 0xF187E430, 0xD99624CE, 0xC1996403, + 0x89B40D9B, 0x91BB4D56, 0xB9AA8DA8, 0xA1A5CD65, + 0x5249BE62, 0x4A46FEAF, 0x62573E51, 0x7A587E9C, + 0x32751704, 0x2A7A57C9, 0x026B9737, 0x1A64D7FA, + 0x923145AE, 0x8A3E0563, 0xA22FC59D, 0xBA208550, + 0xF20DECC8, 0xEA02AC05, 0xC2136CFB, 0xDA1C2C36, + 0x7BB9E153, 0x63B6A19E, 0x4BA76160, 0x53A821AD, + 0x1B854835, 0x038A08F8, 0x2B9BC806, 0x339488CB, + 0xBBC11A9F, 0xA3CE5A52, 0x8BDF9AAC, 0x93D0DA61, + 0xDBFDB3F9, 0xC3F2F334, 0xEBE333CA, 0xF3EC7307, + 0xA492D5C4, 0xBC9D9509, 0x948C55F7, 0x8C83153A, + 0xC4AE7CA2, 0xDCA13C6F, 0xF4B0FC91, 0xECBFBC5C, + 0x64EA2E08, 0x7CE56EC5, 0x54F4AE3B, 0x4CFBEEF6, + 0x04D6876E, 0x1CD9C7A3, 0x34C8075D, 0x2CC74790, + 0x8D628AF5, 0x956DCA38, 0xBD7C0AC6, 0xA5734A0B, + 0xED5E2393, 0xF551635E, 0xDD40A3A0, 0xC54FE36D, + 0x4D1A7139, 0x551531F4, 0x7D04F10A, 0x650BB1C7, + 0x2D26D85F, 0x35299892, 0x1D38586C, 0x053718A1, + 0xF6DB6BA6, 0xEED42B6B, 0xC6C5EB95, 0xDECAAB58, + 0x96E7C2C0, 0x8EE8820D, 0xA6F942F3, 0xBEF6023E, + 0x36A3906A, 0x2EACD0A7, 0x06BD1059, 0x1EB25094, + 0x569F390C, 0x4E9079C1, 0x6681B93F, 0x7E8EF9F2, + 0xDF2B3497, 0xC724745A, 0xEF35B4A4, 0xF73AF469, + 0xBF179DF1, 0xA718DD3C, 0x8F091DC2, 0x97065D0F, + 0x1F53CF5B, 0x075C8F96, 0x2F4D4F68, 0x37420FA5, + 0x7F6F663D, 0x676026F0, 0x4F71E60E, 0x577EA6C3, + 0xE18D0321, 0xF98243EC, 0xD1938312, 0xC99CC3DF, + 0x81B1AA47, 0x99BEEA8A, 0xB1AF2A74, 0xA9A06AB9, + 0x21F5F8ED, 0x39FAB820, 0x11EB78DE, 0x09E43813, + 0x41C9518B, 0x59C61146, 0x71D7D1B8, 0x69D89175, + 0xC87D5C10, 0xD0721CDD, 0xF863DC23, 0xE06C9CEE, + 0xA841F576, 0xB04EB5BB, 0x985F7545, 0x80503588, + 0x0805A7DC, 0x100AE711, 0x381B27EF, 0x20146722, + 0x68390EBA, 0x70364E77, 0x58278E89, 0x4028CE44, + 0xB3C4BD43, 0xABCBFD8E, 0x83DA3D70, 0x9BD57DBD, + 0xD3F81425, 0xCBF754E8, 0xE3E69416, 0xFBE9D4DB, + 0x73BC468F, 0x6BB30642, 0x43A2C6BC, 0x5BAD8671, + 0x1380EFE9, 0x0B8FAF24, 0x239E6FDA, 0x3B912F17, + 0x9A34E272, 0x823BA2BF, 0xAA2A6241, 0xB225228C, + 0xFA084B14, 0xE2070BD9, 0xCA16CB27, 0xD2198BEA, + 0x5A4C19BE, 0x42435973, 0x6A52998D, 0x725DD940, + 0x3A70B0D8, 0x227FF015, 0x0A6E30EB, 0x12617026, + 0x451FD6E5, 0x5D109628, 0x750156D6, 0x6D0E161B, + 0x25237F83, 0x3D2C3F4E, 0x153DFFB0, 0x0D32BF7D, + 0x85672D29, 0x9D686DE4, 0xB579AD1A, 0xAD76EDD7, + 0xE55B844F, 0xFD54C482, 0xD545047C, 0xCD4A44B1, + 0x6CEF89D4, 0x74E0C919, 0x5CF109E7, 0x44FE492A, + 0x0CD320B2, 0x14DC607F, 0x3CCDA081, 0x24C2E04C, + 0xAC977218, 0xB49832D5, 0x9C89F22B, 0x8486B2E6, + 0xCCABDB7E, 0xD4A49BB3, 0xFCB55B4D, 0xE4BA1B80, + 0x17566887, 0x0F59284A, 0x2748E8B4, 0x3F47A879, + 0x776AC1E1, 0x6F65812C, 0x477441D2, 0x5F7B011F, + 0xD72E934B, 0xCF21D386, 0xE7301378, 0xFF3F53B5, + 0xB7123A2D, 0xAF1D7AE0, 0x870CBA1E, 0x9F03FAD3, + 0x3EA637B6, 0x26A9777B, 0x0EB8B785, 0x16B7F748, + 0x5E9A9ED0, 0x4695DE1D, 0x6E841EE3, 0x768B5E2E, + 0xFEDECC7A, 0xE6D18CB7, 0xCEC04C49, 0xD6CF0C84, + 0x9EE2651C, 0x86ED25D1, 0xAEFCE52F, 0xB6F3A5E2 +}; +} + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +unsigned int SosemanukPolicy::GetAlignment() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE +#ifdef __INTEL_COMPILER + if (HasSSE2() && !IsP4()) // Intel compiler produces faster code for this algorithm on the P4 +#else + if (HasSSE2()) +#endif + return 16; + else +#endif + return GetAlignmentOf(); +} + +unsigned int SosemanukPolicy::GetOptimalBlockSize() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE +#ifdef __INTEL_COMPILER + if (HasSSE2() && !IsP4()) // Intel compiler produces faster code for this algorithm on the P4 +#else + if (HasSSE2()) +#endif + return 4*BYTES_PER_ITERATION; + else +#endif + return BYTES_PER_ITERATION; +} +#endif + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE +extern "C" { +void Sosemanuk_OperateKeystream(size_t iterationCount, const byte *input, byte *output, word32 *state); +} +#endif + +void SosemanukPolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ +#endif // #ifdef CRYPTOPP_GENERATE_X64_MASM + +#ifdef CRYPTOPP_X64_MASM_AVAILABLE + Sosemanuk_OperateKeystream(iterationCount, input, output, m_state.data()); + return; +#endif + +#if CRYPTOPP_SSE2_ASM_AVAILABLE && !defined(CRYPTOPP_DISABLE_SOSEMANUK_ASM) +#ifdef CRYPTOPP_GENERATE_X64_MASM + ALIGN 8 + Sosemanuk_OperateKeystream PROC FRAME + rex_push_reg rsi + push_reg rdi + alloc_stack(80*4*2+12*4+8*WORD_SZ + 2*16+8) + save_xmm128 xmm6, 02f0h + save_xmm128 xmm7, 0300h + .endprolog + mov rdi, r8 + mov rax, r9 +#else +#ifdef __INTEL_COMPILER + if (HasSSE2() && !IsP4()) // Intel compiler produces faster code for this algorithm on the P4 +#else + if (HasSSE2()) +#endif + { +#ifdef __GNUC__ + #if CRYPTOPP_BOOL_X64 + FixedSizeAlignedSecBlock workspace; + #endif + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86( bx) +#else + word32 *state = m_state; + AS2( mov WORD_REG(ax), state) + AS2( mov WORD_REG(di), output) + AS2( mov WORD_REG(dx), input) + AS2( mov WORD_REG(cx), iterationCount) +#endif +#endif // #ifdef CRYPTOPP_GENERATE_X64_MASM + +#if defined(__GNUC__) && CRYPTOPP_BOOL_X64 + #define SSE2_workspace %5 +#else + #define SSE2_workspace WORD_REG(sp) +#endif + +#define SSE2_output WORD_PTR [SSE2_workspace+1*WORD_SZ] +#define SSE2_input WORD_PTR [SSE2_workspace+2*WORD_SZ] +#define SSE2_wordsLeft WORD_PTR [SSE2_workspace+3*WORD_SZ] +#define SSE2_diEnd WORD_PTR [SSE2_workspace+4*WORD_SZ] +#define SSE2_pMulTables WORD_PTR [SSE2_workspace+5*WORD_SZ] +#define SSE2_state WORD_PTR [SSE2_workspace+6*WORD_SZ] +#define SSE2_wordsLeft2 WORD_PTR [SSE2_workspace+7*WORD_SZ] +#define SSE2_stateCopy SSE2_workspace + 8*WORD_SZ +#define SSE2_uvStart SSE2_stateCopy + 12*4 + +#if (CRYPTOPP_BOOL_X86) && !defined(CRYPTOPP_DISABLE_SOSEMANUK_ASM) + AS_PUSH_IF86( bp) + AS2( mov AS_REG_6, esp) + AS2( and esp, -16) + AS2( sub esp, 80*4*2+12*4+8*WORD_SZ) // 80 v's, 80 u's, 12 state, 8 locals + AS2( mov [esp], AS_REG_6) +#endif + AS2( mov SSE2_output, WORD_REG(di)) + AS2( mov SSE2_input, WORD_REG(dx)) + AS2( mov SSE2_state, WORD_REG(ax)) +#ifndef _MSC_VER + AS2( mov SSE2_pMulTables, WORD_REG(si)) +#endif + AS2( lea WORD_REG(cx), [4*WORD_REG(cx)+WORD_REG(cx)]) + AS2( lea WORD_REG(si), [4*WORD_REG(cx)]) + AS2( mov SSE2_wordsLeft, WORD_REG(si)) + AS2( movdqa xmm0, [WORD_REG(ax)+0*16]) // copy state to stack to save a register + AS2( movdqa [SSE2_stateCopy+0*16], xmm0) + AS2( movdqa xmm0, [WORD_REG(ax)+1*16]) + AS2( movdqa [SSE2_stateCopy+1*16], xmm0) + AS2( movq xmm0, QWORD PTR [WORD_REG(ax)+2*16]) + AS2( movq QWORD PTR [SSE2_stateCopy+2*16], xmm0) + AS2( psrlq xmm0, 32) + AS2( movd AS_REG_6d, xmm0) // s(9) + AS2( mov ecx, [WORD_REG(ax)+10*4]) + AS2( mov edx, [WORD_REG(ax)+11*4]) + AS2( pcmpeqb xmm7, xmm7) // all ones + +#define s(i) SSE2_stateCopy + ASM_MOD(i,10)*4 +#define u(j) WORD_REG(di) + (ASM_MOD(j,4)*20 + (j/4)) * 4 +#define v(j) WORD_REG(di) + (ASM_MOD(j,4)*20 + (j/4)) * 4 + 80*4 + +#define R10 ecx +#define R11 edx +#define R20 edx +#define R21 ecx +// workaround bug in GAS 2.15 +#define R20r WORD_REG(dx) +#define R21r WORD_REG(cx) + +#define SSE2_STEP(i, j) \ + AS2( mov eax, [s(i+0)])\ + AS2( mov [v(i)], eax)\ + AS2( rol eax, 8)\ + AS2( lea AS_REG_7, [AS_REG_6 + R2##j##r])\ + AS2( xor AS_REG_7d, R1##j)\ + AS2( mov [u(i)], AS_REG_7d)\ + AS2( mov AS_REG_7d, 1)\ + AS2( and AS_REG_7d, R2##j)\ + AS1( neg AS_REG_7d)\ + AS2( and AS_REG_7d, AS_REG_6d)\ + AS2( xor AS_REG_6d, eax)\ + AS2( movzx eax, al)\ + AS2( xor AS_REG_6d, [WORD_REG(si)+WORD_REG(ax)*4])\ + AS2( mov eax, [s(i+3)])\ + AS2( xor AS_REG_7d, [s(i+2)])\ + AS2( add R1##j, AS_REG_7d)\ + AS2( movzx AS_REG_7d, al)\ + AS2( shr eax, 8)\ + AS2( xor AS_REG_6d, [WORD_REG(si)+1024+AS_REG_7*4])\ + AS2( xor AS_REG_6d, eax)\ + AS2( imul R2##j, AS_HEX(54655307))\ + AS2( rol R2##j, 7)\ + AS2( mov [s(i+0)], AS_REG_6d)\ + + ASL(2) // outer loop, each iteration of this processes 80 words + AS2( lea WORD_REG(di), [SSE2_uvStart]) // start of v and u + AS2( mov WORD_REG(ax), 80) + AS2( cmp WORD_REG(si), 80) + AS2( cmovg WORD_REG(si), WORD_REG(ax)) + AS2( mov SSE2_wordsLeft2, WORD_REG(si)) + AS2( lea WORD_REG(si), [WORD_REG(di)+WORD_REG(si)]) // use to end first inner loop + AS2( mov SSE2_diEnd, WORD_REG(si)) +#ifdef _MSC_VER + AS2( lea WORD_REG(si), s_sosemanukMulTables) +#else + AS2( mov WORD_REG(si), SSE2_pMulTables) +#endif + + ASL(0) // first inner loop, 20 words each, 4 iterations + SSE2_STEP(0, 0) + SSE2_STEP(1, 1) + SSE2_STEP(2, 0) + SSE2_STEP(3, 1) + SSE2_STEP(4, 0) + SSE2_STEP(5, 1) + SSE2_STEP(6, 0) + SSE2_STEP(7, 1) + SSE2_STEP(8, 0) + SSE2_STEP(9, 1) + SSE2_STEP(10, 0) + SSE2_STEP(11, 1) + SSE2_STEP(12, 0) + SSE2_STEP(13, 1) + SSE2_STEP(14, 0) + SSE2_STEP(15, 1) + SSE2_STEP(16, 0) + SSE2_STEP(17, 1) + SSE2_STEP(18, 0) + SSE2_STEP(19, 1) + // loop + AS2( add WORD_REG(di), 5*4) + AS2( cmp WORD_REG(di), SSE2_diEnd) + ASJ( jne, 0, b) + + AS2( mov WORD_REG(ax), SSE2_input) + AS2( mov AS_REG_7, SSE2_output) + AS2( lea WORD_REG(di), [SSE2_uvStart]) // start of v and u + AS2( mov WORD_REG(si), SSE2_wordsLeft2) + + ASL(1) // second inner loop, 16 words each, 5 iterations + AS2( movdqa xmm0, [WORD_REG(di)+0*20*4]) + AS2( movdqa xmm2, [WORD_REG(di)+2*20*4]) + AS2( movdqa xmm3, [WORD_REG(di)+3*20*4]) + AS2( movdqa xmm1, [WORD_REG(di)+1*20*4]) + // S2 + AS2( movdqa xmm4, xmm0) + AS2( pand xmm0, xmm2) + AS2( pxor xmm0, xmm3) + AS2( pxor xmm2, xmm1) + AS2( pxor xmm2, xmm0) + AS2( por xmm3, xmm4) + AS2( pxor xmm3, xmm1) + AS2( pxor xmm4, xmm2) + AS2( movdqa xmm1, xmm3) + AS2( por xmm3, xmm4) + AS2( pxor xmm3, xmm0) + AS2( pand xmm0, xmm1) + AS2( pxor xmm4, xmm0) + AS2( pxor xmm1, xmm3) + AS2( pxor xmm1, xmm4) + AS2( pxor xmm4, xmm7) + // xor with v + AS2( pxor xmm2, [WORD_REG(di)+80*4]) + AS2( pxor xmm3, [WORD_REG(di)+80*5]) + AS2( pxor xmm1, [WORD_REG(di)+80*6]) + AS2( pxor xmm4, [WORD_REG(di)+80*7]) + // exit loop early if less than 16 words left to output + // this is necessary because block size is 20 words, and we output 16 words in each iteration of this loop + AS2( cmp WORD_REG(si), 16) + ASJ( jl, 4, f) + // unpack + AS2( movdqa xmm6, xmm2) + AS2( punpckldq xmm2, xmm3) + AS2( movdqa xmm5, xmm1) + AS2( punpckldq xmm1, xmm4) + AS2( movdqa xmm0, xmm2) + AS2( punpcklqdq xmm2, xmm1) + AS2( punpckhqdq xmm0, xmm1) + AS2( punpckhdq xmm6, xmm3) + AS2( punpckhdq xmm5, xmm4) + AS2( movdqa xmm3, xmm6) + AS2( punpcklqdq xmm6, xmm5) + AS2( punpckhqdq xmm3, xmm5) + + // output keystream + AS_XMM_OUTPUT4(SSE2_Sosemanuk_Output, WORD_REG(ax), AS_REG_7, 2,0,6,3, 1, 0,1,2,3, 4) + + // loop + AS2( add WORD_REG(di), 4*4) + AS2( sub WORD_REG(si), 16) + ASJ( jnz, 1, b) + + // outer loop + AS2( mov WORD_REG(si), SSE2_wordsLeft) + AS2( sub WORD_REG(si), 80) + ASJ( jz, 6, f) + AS2( mov SSE2_wordsLeft, WORD_REG(si)) + AS2( mov SSE2_input, WORD_REG(ax)) + AS2( mov SSE2_output, AS_REG_7) + ASJ( jmp, 2, b) + + ASL(4) // final output of less than 16 words + AS2( test WORD_REG(ax), WORD_REG(ax)) + ASJ( jz, 5, f) + AS2( movd xmm0, dword ptr [WORD_REG(ax)+0*4]) + AS2( pxor xmm2, xmm0) + AS2( movd xmm0, dword ptr [WORD_REG(ax)+1*4]) + AS2( pxor xmm3, xmm0) + AS2( movd xmm0, dword ptr [WORD_REG(ax)+2*4]) + AS2( pxor xmm1, xmm0) + AS2( movd xmm0, dword ptr [WORD_REG(ax)+3*4]) + AS2( pxor xmm4, xmm0) + AS2( add WORD_REG(ax), 16) + ASL(5) + AS2( movd dword ptr [AS_REG_7+0*4], xmm2) + AS2( movd dword ptr [AS_REG_7+1*4], xmm3) + AS2( movd dword ptr [AS_REG_7+2*4], xmm1) + AS2( movd dword ptr [AS_REG_7+3*4], xmm4) + AS2( sub WORD_REG(si), 4) + ASJ( jz, 6, f) + AS2( add AS_REG_7, 16) + AS2( psrldq xmm2, 4) + AS2( psrldq xmm3, 4) + AS2( psrldq xmm1, 4) + AS2( psrldq xmm4, 4) + ASJ( jmp, 4, b) + + ASL(6) // save state + AS2( mov AS_REG_6, SSE2_state) + AS2( movdqa xmm0, [SSE2_stateCopy+0*16]) + AS2( movdqa [AS_REG_6+0*16], xmm0) + AS2( movdqa xmm0, [SSE2_stateCopy+1*16]) + AS2( movdqa [AS_REG_6+1*16], xmm0) + AS2( movq xmm0, QWORD PTR [SSE2_stateCopy+2*16]) + AS2( movq QWORD PTR [AS_REG_6+2*16], xmm0) + AS2( mov [AS_REG_6+10*4], ecx) + AS2( mov [AS_REG_6+11*4], edx) + + AS_POP_IF86( sp) + AS_POP_IF86( bp) + +#ifdef __GNUC__ + AS_POP_IF86( bx) + ATT_PREFIX + : + : "a" (m_state.data()), "c" (iterationCount), "S" (s_sosemanukMulTables), "D" (output), "d" (input) + #if CRYPTOPP_BOOL_X64 + , "r" (workspace.data()) + : "memory", "cc", "%r9", "%r10", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" + #else + : "memory", "cc" + #endif + ); +#endif +#ifdef CRYPTOPP_GENERATE_X64_MASM + movdqa xmm6, [rsp + 02f0h] + movdqa xmm7, [rsp + 0300h] + add rsp, 80*4*2+12*4+8*WORD_SZ + 2*16+8 + pop rdi + pop rsi + ret + Sosemanuk_OperateKeystream ENDP +#else + } + else +#endif +#endif +#ifndef CRYPTOPP_GENERATE_X64_MASM + { +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) && !defined(CRYPTOPP_DISABLE_SOSEMANUK_ASM) +#define MUL_A(x) (x = (rotlConstant<8>(x)), x ^ s_sosemanukMulTables[byte(x)]) +#else +#define MUL_A(x) (((x) << 8) ^ s_sosemanukMulTables[(x) >> 24]) +#endif + +#define DIV_A(x) (((x) >> 8) ^ s_sosemanukMulTables[256 + byte(x)]) + +#define r1(i) ((i%2) ? reg2 : reg1) +#define r2(i) ((i%2) ? reg1 : reg2) + +#define STEP(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, v, u) \ + u = (s##x9 + r2(x0)) ^ r1(x0);\ + t = v = s##x0;\ + s##x0 = MUL_A(t) ^ DIV_A(s##x3) ^ s##x9;\ + r1(x0) += XMUX(r2(x0), s##x2, s##x9);\ + r2(x0) = rotlFixed(r2(x0) * 0x54655307, 7);\ + +#define SOSEMANUK_OUTPUT(x) \ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, u2 ^ v0);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, u3 ^ v1);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, u1 ^ v2);\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, u4 ^ v3); + +#define OUTPUT4 \ + S2(0, u0, u1, u2, u3, u4);\ + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(SOSEMANUK_OUTPUT, 4*4); + + word32 s0 = m_state[0]; + word32 s1 = m_state[1]; + word32 s2 = m_state[2]; + word32 s3 = m_state[3]; + word32 s4 = m_state[4]; + word32 s5 = m_state[5]; + word32 s6 = m_state[6]; + word32 s7 = m_state[7]; + word32 s8 = m_state[8]; + word32 s9 = m_state[9]; + word32 reg1 = m_state[10]; + word32 reg2 = m_state[11]; + word32 t, u0, u1, u2, u3, u4, v0, v1, v2, v3; + + do + { + STEP(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, v0, u0) + STEP(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, v1, u1) + STEP(2, 3, 4, 5, 6, 7, 8, 9, 0, 1, v2, u2) + STEP(3, 4, 5, 6, 7, 8, 9, 0, 1, 2, v3, u3) + OUTPUT4 + STEP(4, 5, 6, 7, 8, 9, 0, 1, 2, 3, v0, u0) + STEP(5, 6, 7, 8, 9, 0, 1, 2, 3, 4, v1, u1) + STEP(6, 7, 8, 9, 0, 1, 2, 3, 4, 5, v2, u2) + STEP(7, 8, 9, 0, 1, 2, 3, 4, 5, 6, v3, u3) + OUTPUT4 + STEP(8, 9, 0, 1, 2, 3, 4, 5, 6, 7, v0, u0) + STEP(9, 0, 1, 2, 3, 4, 5, 6, 7, 8, v1, u1) + STEP(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, v2, u2) + STEP(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, v3, u3) + OUTPUT4 + STEP(2, 3, 4, 5, 6, 7, 8, 9, 0, 1, v0, u0) + STEP(3, 4, 5, 6, 7, 8, 9, 0, 1, 2, v1, u1) + STEP(4, 5, 6, 7, 8, 9, 0, 1, 2, 3, v2, u2) + STEP(5, 6, 7, 8, 9, 0, 1, 2, 3, 4, v3, u3) + OUTPUT4 + STEP(6, 7, 8, 9, 0, 1, 2, 3, 4, 5, v0, u0) + STEP(7, 8, 9, 0, 1, 2, 3, 4, 5, 6, v1, u1) + STEP(8, 9, 0, 1, 2, 3, 4, 5, 6, 7, v2, u2) + STEP(9, 0, 1, 2, 3, 4, 5, 6, 7, 8, v3, u3) + OUTPUT4 + } + while (--iterationCount); + + m_state[0] = s0; + m_state[1] = s1; + m_state[2] = s2; + m_state[3] = s3; + m_state[4] = s4; + m_state[5] = s5; + m_state[6] = s6; + m_state[7] = s7; + m_state[8] = s8; + m_state[9] = s9; + m_state[10] = reg1; + m_state[11] = reg2; + } +} + +NAMESPACE_END + +#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM diff --git a/extension/third_party/cryptopp/sosemanuk.h b/extension/third_party/cryptopp/sosemanuk.h new file mode 100644 index 00000000..94ebcfea --- /dev/null +++ b/extension/third_party/cryptopp/sosemanuk.h @@ -0,0 +1,62 @@ +// sosemanuk.h - originally written and placed in the public domain by Wei Dai + +/// \file sosemanuk.h +/// \brief Classes for Sosemanuk stream cipher +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_SOSEMANUK_H +#define CRYPTOPP_SOSEMANUK_H + +#include "strciphr.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SOSEMANUK_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Sosemanuk stream cipher information +/// \since Crypto++ 5.5 +struct SosemanukInfo : public VariableKeyLength<16, 1, 32, 1, SimpleKeyingInterface::UNIQUE_IV, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Sosemanuk";} +}; + +/// \brief Sosemanuk stream cipher implementation +/// \since Crypto++ 5.5 +class SosemanukPolicy : public AdditiveCipherConcretePolicy, public SosemanukInfo +{ +protected: + std::string AlgorithmProvider() const; + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CipherIsRandomAccess() const {return false;} +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + FixedSizeSecBlock m_key; + FixedSizeAlignedSecBlock m_state; +}; + +/// \brief Sosemanuk stream cipher +/// \details is a stream cipher developed by Come Berbain, Olivier Billet, Anne Canteaut, Nicolas Courtois, +/// Henri Gilbert, Louis Goubin, Aline Gouget, Louis Granboulan, Cédric Lauradoux, Marine Minier, Thomas +/// Pornin and Hervé Sibert. Sosemanuk is one of the final four Profile 1 (software) ciphers selected for +/// the eSTREAM Portfolio. +/// \sa Sosemanuk +/// \since Crypto++ 5.5 +struct Sosemanuk : public SosemanukInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, SosemanukInfo> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/speck.cpp b/extension/third_party/cryptopp/speck.cpp new file mode 100644 index 00000000..00b960d7 --- /dev/null +++ b/extension/third_party/cryptopp/speck.cpp @@ -0,0 +1,487 @@ +// speck.cpp - written and placed in the public domain by Jeffrey Walton + +#include "pch.h" +#include "config.h" + +#include "speck.h" +#include "misc.h" +#include "cpu.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both speck.cpp and speck_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_SSE41_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::rotlConstant; +using CryptoPP::rotrConstant; + +/// \brief Forward round transformation +/// \tparam W word type +/// \details TF83() is the forward round transformation using a=8 and b=3 rotations. +/// The initial test implementation provided template parameters, but they were +/// removed because SPECK32 using a=7 and b=2 was not on the road map. The +/// additional template parameters also made calling SPECK_Encrypt and SPECK_Decrypt +/// kind of messy. +template +inline void TF83(W& x, W& y, const W k) +{ + x = rotrConstant<8>(x); + x += y; x ^= k; + y = rotlConstant<3>(y); + y ^= x; +} + +/// \brief Reverse round transformation +/// \tparam W word type +/// \details TR83() is the reverse round transformation using a=8 and b=3 rotations. +/// The initial test implementation provided template parameters, but they were +/// removed because SPECK32 using a=7 and b=2 was not on the road map. The +/// additional template parameters also made calling SPECK_Encrypt and SPECK_Decrypt +/// kind of messy. +template +inline void TR83(W& x, W& y, const W k) +{ + y ^= x; + y = rotrConstant<3>(y); + x ^= k; x -= y; + x = rotlConstant<8>(x); +} + +/// \brief Forward transformation +/// \tparam W word type +/// \tparam R number of rounds +/// \param c output array +/// \param p input array +/// \param k subkey array +template +inline void SPECK_Encrypt(W c[2], const W p[2], const W k[R]) +{ + c[0]=p[0]; c[1]=p[1]; + + // Don't unroll this loop. Things slow down. + for (int i = 0; i < static_cast(R); ++i) + TF83(c[0], c[1], k[i]); +} + +/// \brief Reverse transformation +/// \tparam W word type +/// \tparam R number of rounds +/// \param p output array +/// \param c input array +/// \param k subkey array +template +inline void SPECK_Decrypt(W p[2], const W c[2], const W k[R]) +{ + p[0]=c[0]; p[1]=c[1]; + + // Don't unroll this loop. Things slow down. + for (int i = static_cast(R-1); i >= 0; --i) + TR83(p[0], p[1], k[i]); +} + +/// \brief Subkey generation function +/// \details Used when the user key consists of 2 words +/// \tparam W word type +/// \tparam R number of rounds +/// \param key empty subkey array +/// \param k user key array +template +inline void SPECK_ExpandKey_2W(W key[R], const W k[2]) +{ + CRYPTOPP_ASSERT(R==32); + W i=0, B=k[0], A=k[1]; + + while (i +inline void SPECK_ExpandKey_3W(W key[R], const W k[3]) +{ + CRYPTOPP_ASSERT(R==33 || R==26); + W i=0, C=k[0], B=k[1], A=k[2]; + + unsigned int blocks = R/2; + while (blocks--) + { + key[i+0]=A; TF83(B, A, i+0); + key[i+1]=A; TF83(C, A, i+1); + i+=2; + } + + // The constexpr residue should allow the optimizer to remove unneeded statements + if(R%2 == 1) + { + key[R-1]=A; + } +} + +/// \brief Subkey generation function +/// \details Used when the user key consists of 4 words +/// \tparam W word type +/// \tparam R number of rounds +/// \param key empty subkey array +/// \param k user key array +template +inline void SPECK_ExpandKey_4W(W key[R], const W k[4]) +{ + CRYPTOPP_ASSERT(R==34 || R==27); + W i=0, D=k[0], C=k[1], B=k[2], A=k[3]; + + unsigned int blocks = R/3; + while (blocks--) + { + key[i+0]=A; TF83(B, A, i+0); + key[i+1]=A; TF83(C, A, i+1); + key[i+2]=A; TF83(D, A, i+2); + i+=3; + } + + // The constexpr residue should allow the optimizer to remove unneeded statements + if(R%3 == 1) + { + key[R-1]=A; + } + else if(R%3 == 2) + { + key[R-2]=A; TF83(B, A, W(R-2)); + key[R-1]=A; + } +} + +ANONYMOUS_NAMESPACE_END + +/////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +extern size_t SPECK128_Enc_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SPECK128_Dec_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_SSE41_AVAILABLE) +extern size_t SPECK64_Enc_AdvancedProcessBlocks_SSE41(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SPECK64_Dec_AdvancedProcessBlocks_SSE41(const word32* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_SSSE3_AVAILABLE) +extern size_t SPECK128_Enc_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SPECK128_Dec_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +extern size_t SPECK128_Enc_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); + +extern size_t SPECK128_Dec_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags); +#endif + +std::string SPECK64::Base::AlgorithmProvider() const +{ + return "C++"; +} + +unsigned int SPECK64::Base::OptimalDataAlignment() const +{ + return GetAlignmentOf(); +} + +void SPECK64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(keyLength == 12 || keyLength == 16); + CRYPTOPP_UNUSED(params); + + // Building the key schedule table requires {3,4} words workspace. + // Encrypting and decrypting requires 4 words workspace. + m_kwords = keyLength/sizeof(word32); + m_wspace.New(4U); + + // Do the endian gyrations from the paper and align pointers + typedef GetBlock KeyBlock; + KeyBlock kblk(userKey); + + switch (m_kwords) + { + case 3: + m_rkeys.New((m_rounds = 26)); + kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SPECK_ExpandKey_3W(m_rkeys, m_wspace); + break; + case 4: + m_rkeys.New((m_rounds = 27)); + kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SPECK_ExpandKey_4W(m_rkeys, m_wspace); + break; + default: + CRYPTOPP_ASSERT(0); + } +} + +void SPECK64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 26: + SPECK_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 27: + SPECK_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +void SPECK64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 26: + SPECK_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 27: + SPECK_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +/////////////////////////////////////////////////////////// + +std::string SPECK128::Base::AlgorithmProvider() const +{ +#if (CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS) +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return "SSSE3"; +# endif +# if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return "NEON"; +# endif +# if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return "Altivec"; +# endif +#endif + return "C++"; +} + +unsigned int SPECK128::Base::OptimalDataAlignment() const +{ +#if (CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS) +# if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return 16; // load __m128i +# endif +# if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return 8; // load uint64x2_t +# endif +# if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return 16; // load uint64x2_p +# endif +#endif + return GetAlignmentOf(); +} + +void SPECK128::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + CRYPTOPP_ASSERT(keyLength == 16 || keyLength == 24 || keyLength == 32); + CRYPTOPP_UNUSED(params); + + // Building the key schedule table requires {2,3,4} words workspace. + // Encrypting and decrypting requires 4 words workspace. + m_kwords = keyLength/sizeof(word64); + m_wspace.New(4U); + + // Do the endian gyrations from the paper and align pointers + typedef GetBlock KeyBlock; + KeyBlock kblk(userKey); + + switch (m_kwords) + { + case 2: + m_rkeys.New((m_rounds = 32)); + kblk(m_wspace[1])(m_wspace[0]); + SPECK_ExpandKey_2W(m_rkeys, m_wspace); + break; + case 3: + m_rkeys.New((m_rounds = 33)); + kblk(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SPECK_ExpandKey_3W(m_rkeys, m_wspace); + break; + case 4: + m_rkeys.New((m_rounds = 34)); + kblk(m_wspace[3])(m_wspace[2])(m_wspace[1])(m_wspace[0]); + SPECK_ExpandKey_4W(m_rkeys, m_wspace); + break; + default: + CRYPTOPP_ASSERT(0); + } + +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + + // Pre-splat the round keys for Altivec forward transformation +#if CRYPTOPP_ALTIVEC_AVAILABLE + if (IsForwardTransformation() && HasAltivec()) + { + AlignedSecBlock presplat(m_rkeys.size()*2); + for (size_t i=0, j=0; i InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 32: + SPECK_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 33: + SPECK_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 34: + SPECK_Encrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +void SPECK128::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + // Do the endian gyrations from the paper and align pointers + typedef GetBlock InBlock; + InBlock iblk(inBlock); iblk(m_wspace[1])(m_wspace[0]); + + switch (m_rounds) + { + case 32: + SPECK_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 33: + SPECK_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + case 34: + SPECK_Decrypt(m_wspace+2, m_wspace+0, m_rkeys); + break; + default: + CRYPTOPP_ASSERT(0); + } + + // Do the endian gyrations from the paper and align pointers + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); oblk(m_wspace[3])(m_wspace[2]); +} + +#if (CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS) +size_t SPECK128::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return SPECK128_Enc_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return SPECK128_Enc_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return SPECK128_Enc_AdvancedProcessBlocks_ALTIVEC(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SPECK128::Dec::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, + byte *outBlocks, size_t length, word32 flags) const +{ +#if (CRYPTOPP_SSSE3_AVAILABLE) + if (HasSSSE3()) + return SPECK128_Dec_AdvancedProcessBlocks_SSSE3(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + if (HasNEON()) + return SPECK128_Dec_AdvancedProcessBlocks_NEON(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif +#if (CRYPTOPP_ALTIVEC_AVAILABLE) + if (HasAltivec()) + return SPECK128_Dec_AdvancedProcessBlocks_ALTIVEC(m_rkeys, (size_t)m_rounds, + inBlocks, xorBlocks, outBlocks, length, flags); +#endif + return BlockTransformation::AdvancedProcessBlocks(inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/speck.h b/extension/third_party/cryptopp/speck.h new file mode 100644 index 00000000..dbbdf2f6 --- /dev/null +++ b/extension/third_party/cryptopp/speck.h @@ -0,0 +1,206 @@ +// speck.h - written and placed in the public domain by Jeffrey Walton + +/// \file speck.h +/// \brief Classes for the Speck block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SPECK on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SPECK_H +#define CRYPTOPP_SPECK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || \ + CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# ifndef CRYPTOPP_DISABLE_SPECK_SIMD +# define CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SPECK block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SPECK_Info : public FixedBlockSize, VariableKeyLength +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SPECK-" + IntToString(L*8); + } +}; + +/// \brief SPECK block cipher base class +/// \tparam W the word type +/// \details User code should use SPECK64 or SPECK128 +/// \sa SPECK64, SPECK128, SPECK +/// \since Crypto++ 6.0 +template +struct SPECK_Base +{ + virtual ~SPECK_Base() {} + SPECK_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SPECK 64-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK64 : public SPECK_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK64 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SPECK64 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SPECK64 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SPECK 128-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK128 : public SPECK_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK128 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SPECK128 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief SPECK128 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SPECK_H diff --git a/extension/third_party/cryptopp/speck128_simd.cpp b/extension/third_party/cryptopp/speck128_simd.cpp new file mode 100644 index 00000000..1c61c9a1 --- /dev/null +++ b/extension/third_party/cryptopp/speck128_simd.cpp @@ -0,0 +1,762 @@ +// speck128_simd.cpp - written and placed in the public domain by Jeffrey Walton +// +// This source file uses intrinsics and built-ins to gain access to +// SSSE3, ARM NEON and ARMv8a, and Altivec instructions. A separate +// source file is needed because additional CXXFLAGS are required to enable +// the appropriate instructions sets in some build configurations. + +#include "pch.h" +#include "config.h" + +#include "speck.h" +#include "misc.h" + +// Uncomment for benchmarking C++ against SSE or NEON. +// Do so in both speck.cpp and speck_simd.cpp. +// #undef CRYPTOPP_SSSE3_AVAILABLE +// #undef CRYPTOPP_ARM_NEON_AVAILABLE + +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include "adv_simd.h" +# include +# include +#endif + +#if defined(__XOP__) +# include +# if defined(__GNUC__) +# include +# endif +#endif + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include "adv_simd.h" +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if defined(_M_ARM64) +# include "adv_simd.h" +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "adv_simd.h" +# include "ppc_simd.h" +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char SPECK128_SIMD_FNAME[] = __FILE__; + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; + +// *************************** ARM NEON ************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) + +// Missing from Microsoft's ARM A-32 implementation +#if defined(_MSC_VER) && !defined(_M_ARM64) +inline uint64x2_t vld1q_dup_u64(const uint64_t* ptr) +{ + return vmovq_n_u64(*ptr); +} +#endif + +template +inline T UnpackHigh64(const T& a, const T& b) +{ + const uint64x1_t x(vget_high_u64((uint64x2_t)a)); + const uint64x1_t y(vget_high_u64((uint64x2_t)b)); + return (T)vcombine_u64(x, y); +} + +template +inline T UnpackLow64(const T& a, const T& b) +{ + const uint64x1_t x(vget_low_u64((uint64x2_t)a)); + const uint64x1_t y(vget_low_u64((uint64x2_t)b)); + return (T)vcombine_u64(x, y); +} + +template +inline uint64x2_t RotateLeft64(const uint64x2_t& val) +{ + const uint64x2_t a(vshlq_n_u64(val, R)); + const uint64x2_t b(vshrq_n_u64(val, 64 - R)); + return vorrq_u64(a, b); +} + +template +inline uint64x2_t RotateRight64(const uint64x2_t& val) +{ + const uint64x2_t a(vshlq_n_u64(val, 64 - R)); + const uint64x2_t b(vshrq_n_u64(val, R)); + return vorrq_u64(a, b); +} + +#if defined(__aarch32__) || defined(__aarch64__) +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline uint64x2_t RotateLeft64<8>(const uint64x2_t& val) +{ + const uint8_t maskb[16] = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u64_u8( + vqtbl1q_u8(vreinterpretq_u8_u64(val), mask)); +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +inline uint64x2_t RotateRight64<8>(const uint64x2_t& val) +{ + const uint8_t maskb[16] = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + const uint8x16_t mask = vld1q_u8(maskb); + + return vreinterpretq_u64_u8( + vqtbl1q_u8(vreinterpretq_u8_u64(val), mask)); +} +#endif + +inline void SPECK128_Enc_Block(uint64x2_t &block0, uint64x2_t &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys+i); + + x1 = RotateRight64<8>(x1); + x1 = vaddq_u64(x1, y1); + x1 = veorq_u64(x1, rk); + y1 = RotateLeft64<3>(y1); + y1 = veorq_u64(y1, x1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); +} + +inline void SPECK128_Enc_6_Blocks(uint64x2_t &block0, uint64x2_t &block1, + uint64x2_t &block2, uint64x2_t &block3, uint64x2_t &block4, uint64x2_t &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + uint64x2_t x2 = UnpackHigh64(block2, block3); + uint64x2_t y2 = UnpackLow64(block2, block3); + uint64x2_t x3 = UnpackHigh64(block4, block5); + uint64x2_t y3 = UnpackLow64(block4, block5); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys+i); + + x1 = RotateRight64<8>(x1); + x2 = RotateRight64<8>(x2); + x3 = RotateRight64<8>(x3); + x1 = vaddq_u64(x1, y1); + x2 = vaddq_u64(x2, y2); + x3 = vaddq_u64(x3, y3); + x1 = veorq_u64(x1, rk); + x2 = veorq_u64(x2, rk); + x3 = veorq_u64(x3, rk); + y1 = RotateLeft64<3>(y1); + y2 = RotateLeft64<3>(y2); + y3 = RotateLeft64<3>(y3); + y1 = veorq_u64(y1, x1); + y2 = veorq_u64(y2, x2); + y3 = veorq_u64(y3, x3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); + block2 = UnpackLow64(y2, x2); + block3 = UnpackHigh64(y2, x2); + block4 = UnpackLow64(y3, x3); + block5 = UnpackHigh64(y3, x3); +} + +inline void SPECK128_Dec_Block(uint64x2_t &block0, uint64x2_t &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys+i); + + y1 = veorq_u64(y1, x1); + y1 = RotateRight64<3>(y1); + x1 = veorq_u64(x1, rk); + x1 = vsubq_u64(x1, y1); + x1 = RotateLeft64<8>(x1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); +} + +inline void SPECK128_Dec_6_Blocks(uint64x2_t &block0, uint64x2_t &block1, + uint64x2_t &block2, uint64x2_t &block3, uint64x2_t &block4, uint64x2_t &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + uint64x2_t x1 = UnpackHigh64(block0, block1); + uint64x2_t y1 = UnpackLow64(block0, block1); + uint64x2_t x2 = UnpackHigh64(block2, block3); + uint64x2_t y2 = UnpackLow64(block2, block3); + uint64x2_t x3 = UnpackHigh64(block4, block5); + uint64x2_t y3 = UnpackLow64(block4, block5); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const uint64x2_t rk = vld1q_dup_u64(subkeys+i); + + y1 = veorq_u64(y1, x1); + y2 = veorq_u64(y2, x2); + y3 = veorq_u64(y3, x3); + y1 = RotateRight64<3>(y1); + y2 = RotateRight64<3>(y2); + y3 = RotateRight64<3>(y3); + x1 = veorq_u64(x1, rk); + x2 = veorq_u64(x2, rk); + x3 = veorq_u64(x3, rk); + x1 = vsubq_u64(x1, y1); + x2 = vsubq_u64(x2, y2); + x3 = vsubq_u64(x3, y3); + x1 = RotateLeft64<8>(x1); + x2 = RotateLeft64<8>(x2); + x3 = RotateLeft64<8>(x3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = UnpackLow64(y1, x1); + block1 = UnpackHigh64(y1, x1); + block2 = UnpackLow64(y2, x2); + block3 = UnpackHigh64(y2, x2); + block4 = UnpackLow64(y3, x3); + block5 = UnpackHigh64(y3, x3); +} + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** IA-32 ***************************** // + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#ifndef M128_CAST +# define M128_CAST(x) ((__m128i *)(void *)(x)) +#endif +#ifndef CONST_M128_CAST +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#endif + +// GCC double casts, https://www.spinics.net/lists/gcchelp/msg47735.html +#ifndef DOUBLE_CAST +# define DOUBLE_CAST(x) ((double *)(void *)(x)) +#endif +#ifndef CONST_DOUBLE_CAST +# define CONST_DOUBLE_CAST(x) ((const double *)(const void *)(x)) +#endif + +template +inline __m128i RotateLeft64(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, R); +#else + return _mm_or_si128( + _mm_slli_epi64(val, R), _mm_srli_epi64(val, 64-R)); +#endif +} + +template +inline __m128i RotateRight64(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 64-R); +#else + return _mm_or_si128( + _mm_slli_epi64(val, 64-R), _mm_srli_epi64(val, R)); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +__m128i RotateLeft64<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 8); +#else + const __m128i mask = _mm_set_epi8(14,13,12,11, 10,9,8,15, 6,5,4,3, 2,1,0,7); + return _mm_shuffle_epi8(val, mask); +#endif +} + +// Faster than two Shifts and an Or. Thanks to Louis Wingers and Bryan Weeks. +template <> +__m128i RotateRight64<8>(const __m128i& val) +{ +#if defined(__XOP__) + return _mm_roti_epi64(val, 64-8); +#else + const __m128i mask = _mm_set_epi8(8,15,14,13, 12,11,10,9, 0,7,6,5, 4,3,2,1); + return _mm_shuffle_epi8(val, mask); +#endif +} + +inline void SPECK128_Enc_Block(__m128i &block0, __m128i &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + // Round keys are pre-splated in forward direction + const __m128i rk = _mm_load_si128(CONST_M128_CAST(subkeys+i*2)); + + x1 = RotateRight64<8>(x1); + x1 = _mm_add_epi64(x1, y1); + x1 = _mm_xor_si128(x1, rk); + y1 = RotateLeft64<3>(y1); + y1 = _mm_xor_si128(y1, x1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); +} + +inline void SPECK128_Enc_6_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, __m128i &block4, __m128i &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + __m128i x2 = _mm_unpackhi_epi64(block2, block3); + __m128i y2 = _mm_unpacklo_epi64(block2, block3); + __m128i x3 = _mm_unpackhi_epi64(block4, block5); + __m128i y3 = _mm_unpacklo_epi64(block4, block5); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + // Round keys are pre-splated in forward direction + const __m128i rk = _mm_load_si128(CONST_M128_CAST(subkeys+i*2)); + + x1 = RotateRight64<8>(x1); + x2 = RotateRight64<8>(x2); + x3 = RotateRight64<8>(x3); + x1 = _mm_add_epi64(x1, y1); + x2 = _mm_add_epi64(x2, y2); + x3 = _mm_add_epi64(x3, y3); + x1 = _mm_xor_si128(x1, rk); + x2 = _mm_xor_si128(x2, rk); + x3 = _mm_xor_si128(x3, rk); + y1 = RotateLeft64<3>(y1); + y2 = RotateLeft64<3>(y2); + y3 = RotateLeft64<3>(y3); + y1 = _mm_xor_si128(y1, x1); + y2 = _mm_xor_si128(y2, x2); + y3 = _mm_xor_si128(y3, x3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); + block2 = _mm_unpacklo_epi64(y2, x2); + block3 = _mm_unpackhi_epi64(y2, x2); + block4 = _mm_unpacklo_epi64(y3, x3); + block5 = _mm_unpackhi_epi64(y3, x3); +} + +inline void SPECK128_Dec_Block(__m128i &block0, __m128i &block1, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const __m128i rk = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys+i))); + + y1 = _mm_xor_si128(y1, x1); + y1 = RotateRight64<3>(y1); + x1 = _mm_xor_si128(x1, rk); + x1 = _mm_sub_epi64(x1, y1); + x1 = RotateLeft64<8>(x1); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); +} + +inline void SPECK128_Dec_6_Blocks(__m128i &block0, __m128i &block1, + __m128i &block2, __m128i &block3, __m128i &block4, __m128i &block5, + const word64 *subkeys, unsigned int rounds) +{ + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + __m128i x1 = _mm_unpackhi_epi64(block0, block1); + __m128i y1 = _mm_unpacklo_epi64(block0, block1); + __m128i x2 = _mm_unpackhi_epi64(block2, block3); + __m128i y2 = _mm_unpacklo_epi64(block2, block3); + __m128i x3 = _mm_unpackhi_epi64(block4, block5); + __m128i y3 = _mm_unpacklo_epi64(block4, block5); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const __m128i rk = _mm_castpd_si128( + _mm_loaddup_pd(CONST_DOUBLE_CAST(subkeys+i))); + + y1 = _mm_xor_si128(y1, x1); + y2 = _mm_xor_si128(y2, x2); + y3 = _mm_xor_si128(y3, x3); + y1 = RotateRight64<3>(y1); + y2 = RotateRight64<3>(y2); + y3 = RotateRight64<3>(y3); + x1 = _mm_xor_si128(x1, rk); + x2 = _mm_xor_si128(x2, rk); + x3 = _mm_xor_si128(x3, rk); + x1 = _mm_sub_epi64(x1, y1); + x2 = _mm_sub_epi64(x2, y2); + x3 = _mm_sub_epi64(x3, y3); + x1 = RotateLeft64<8>(x1); + x2 = RotateLeft64<8>(x2); + x3 = RotateLeft64<8>(x3); + } + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = _mm_unpacklo_epi64(y1, x1); + block1 = _mm_unpackhi_epi64(y1, x1); + block2 = _mm_unpacklo_epi64(y2, x2); + block3 = _mm_unpackhi_epi64(y2, x2); + block4 = _mm_unpacklo_epi64(y3, x3); + block5 = _mm_unpackhi_epi64(y3, x3); +} + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ***************************** Altivec ***************************** // + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + +// Altivec uses native 64-bit types on 64-bit environments, or 32-bit types +// in 32-bit environments. Speck128 will use the appropriate type for the +// environment. Functions like VecAdd64 have two overloads, one for each +// environment. The 32-bit overload treats uint32x4_p like a 64-bit type, +// and does things like perform a add with carry or subtract with borrow. + +// Speck128 on Power8 performed as expected because of 64-bit environment. +// Performance sucked on old PowerPC machines because of 32-bit environments. +// At Crypto++ 8.3 we added an implementation that operated on 32-bit words. +// Native 64-bit Speck128 performance dropped from about 4.1 to 6.3 cpb, but +// 32-bit Speck128 improved from 66.5 cpb to 10.4 cpb. Overall it was a +// good win even though we lost some performance in 64-bit environments. + +using CryptoPP::uint8x16_p; +using CryptoPP::uint32x4_p; +#if defined(_ARCH_PWR8) +using CryptoPP::uint64x2_p; +#endif + +using CryptoPP::VecAdd64; +using CryptoPP::VecSub64; +using CryptoPP::VecAnd64; +using CryptoPP::VecOr64; +using CryptoPP::VecXor64; +using CryptoPP::VecSplatWord64; +using CryptoPP::VecRotateLeft64; +using CryptoPP::VecRotateRight64; +using CryptoPP::VecLoad; +using CryptoPP::VecLoadAligned; +using CryptoPP::VecPermute; + +#if defined(_ARCH_PWR8) +#define speck128_t uint64x2_p +#else +#define speck128_t uint32x4_p +#endif + +void SPECK128_Enc_Block(uint32x4_p &block, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + speck128_t x1 = (speck128_t)VecPermute(block, block, m1); + speck128_t y1 = (speck128_t)VecPermute(block, block, m2); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + // Round keys are pre-splated in forward direction + const word32* ptr = reinterpret_cast(subkeys+i*2); + const speck128_t rk = (speck128_t)VecLoadAligned(ptr); + + x1 = (speck128_t)VecRotateRight64<8>(x1); + x1 = (speck128_t)VecAdd64(x1, y1); + x1 = (speck128_t)VecXor64(x1, rk); + + y1 = (speck128_t)VecRotateLeft64<3>(y1); + y1 = (speck128_t)VecXor64(y1, x1); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + //const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + //const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block = (uint32x4_p)VecPermute(x1, y1, m3); +} + +void SPECK128_Dec_Block(uint32x4_p &block, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + speck128_t x1 = (speck128_t)VecPermute(block, block, m1); + speck128_t y1 = (speck128_t)VecPermute(block, block, m2); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const speck128_t rk = (speck128_t)VecSplatWord64(subkeys[i]); + + y1 = (speck128_t)VecXor64(y1, x1); + y1 = (speck128_t)VecRotateRight64<3>(y1); + x1 = (speck128_t)VecXor64(x1, rk); + x1 = (speck128_t)VecSub64(x1, y1); + x1 = (speck128_t)VecRotateLeft64<8>(x1); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + //const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + //const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block = (uint32x4_p)VecPermute(x1, y1, m3); +} + +void SPECK128_Enc_6_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, uint32x4_p &block4, + uint32x4_p &block5, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + speck128_t x1 = (speck128_t)VecPermute(block0, block1, m1); + speck128_t y1 = (speck128_t)VecPermute(block0, block1, m2); + speck128_t x2 = (speck128_t)VecPermute(block2, block3, m1); + speck128_t y2 = (speck128_t)VecPermute(block2, block3, m2); + speck128_t x3 = (speck128_t)VecPermute(block4, block5, m1); + speck128_t y3 = (speck128_t)VecPermute(block4, block5, m2); + + for (size_t i=0; i < static_cast(rounds); ++i) + { + // Round keys are pre-splated in forward direction + const word32* ptr = reinterpret_cast(subkeys+i*2); + const speck128_t rk = (speck128_t)VecLoadAligned(ptr); + + x1 = (speck128_t)VecRotateRight64<8>(x1); + x2 = (speck128_t)VecRotateRight64<8>(x2); + x3 = (speck128_t)VecRotateRight64<8>(x3); + x1 = (speck128_t)VecAdd64(x1, y1); + x2 = (speck128_t)VecAdd64(x2, y2); + x3 = (speck128_t)VecAdd64(x3, y3); + x1 = (speck128_t)VecXor64(x1, rk); + x2 = (speck128_t)VecXor64(x2, rk); + x3 = (speck128_t)VecXor64(x3, rk); + + y1 = (speck128_t)VecRotateLeft64<3>(y1); + y2 = (speck128_t)VecRotateLeft64<3>(y2); + y3 = (speck128_t)VecRotateLeft64<3>(y3); + y1 = (speck128_t)VecXor64(y1, x1); + y2 = (speck128_t)VecXor64(y2, x2); + y3 = (speck128_t)VecXor64(y3, x3); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = (uint32x4_p)VecPermute(x1, y1, m3); + block1 = (uint32x4_p)VecPermute(x1, y1, m4); + block2 = (uint32x4_p)VecPermute(x2, y2, m3); + block3 = (uint32x4_p)VecPermute(x2, y2, m4); + block4 = (uint32x4_p)VecPermute(x3, y3, m3); + block5 = (uint32x4_p)VecPermute(x3, y3, m4); +} + +void SPECK128_Dec_6_Blocks(uint32x4_p &block0, uint32x4_p &block1, + uint32x4_p &block2, uint32x4_p &block3, uint32x4_p &block4, + uint32x4_p &block5, const word64 *subkeys, unsigned int rounds) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m1 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m2 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m1 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m2 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 A2][B1 B2] ... => [A1 B1][A2 B2] ... + speck128_t x1 = (speck128_t)VecPermute(block0, block1, m1); + speck128_t y1 = (speck128_t)VecPermute(block0, block1, m2); + speck128_t x2 = (speck128_t)VecPermute(block2, block3, m1); + speck128_t y2 = (speck128_t)VecPermute(block2, block3, m2); + speck128_t x3 = (speck128_t)VecPermute(block4, block5, m1); + speck128_t y3 = (speck128_t)VecPermute(block4, block5, m2); + + for (int i = static_cast(rounds-1); i >= 0; --i) + { + const speck128_t rk = (speck128_t)VecSplatWord64(subkeys[i]); + + y1 = (speck128_t)VecXor64(y1, x1); + y2 = (speck128_t)VecXor64(y2, x2); + y3 = (speck128_t)VecXor64(y3, x3); + y1 = (speck128_t)VecRotateRight64<3>(y1); + y2 = (speck128_t)VecRotateRight64<3>(y2); + y3 = (speck128_t)VecRotateRight64<3>(y3); + + x1 = (speck128_t)VecXor64(x1, rk); + x2 = (speck128_t)VecXor64(x2, rk); + x3 = (speck128_t)VecXor64(x3, rk); + x1 = (speck128_t)VecSub64(x1, y1); + x2 = (speck128_t)VecSub64(x2, y2); + x3 = (speck128_t)VecSub64(x3, y3); + x1 = (speck128_t)VecRotateLeft64<8>(x1); + x2 = (speck128_t)VecRotateLeft64<8>(x2); + x3 = (speck128_t)VecRotateLeft64<8>(x3); + } + +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m3 = {31,30,29,28,27,26,25,24, 15,14,13,12,11,10,9,8}; + const uint8x16_p m4 = {23,22,21,20,19,18,17,16, 7,6,5,4,3,2,1,0}; +#else + const uint8x16_p m3 = {7,6,5,4,3,2,1,0, 23,22,21,20,19,18,17,16}; + const uint8x16_p m4 = {15,14,13,12,11,10,9,8, 31,30,29,28,27,26,25,24}; +#endif + + // [A1 B1][A2 B2] ... => [A1 A2][B1 B2] ... + block0 = (uint32x4_p)VecPermute(x1, y1, m3); + block1 = (uint32x4_p)VecPermute(x1, y1, m4); + block2 = (uint32x4_p)VecPermute(x2, y2, m3); + block3 = (uint32x4_p)VecPermute(x2, y2, m4); + block4 = (uint32x4_p)VecPermute(x3, y3, m3); + block5 = (uint32x4_p)VecPermute(x3, y3, m4); +} + +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +ANONYMOUS_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +// *************************** ARM NEON **************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) +size_t SPECK128_Enc_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_NEON(SPECK128_Enc_Block, SPECK128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SPECK128_Dec_AdvancedProcessBlocks_NEON(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_NEON(SPECK128_Dec_Block, SPECK128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// ***************************** IA-32 ***************************** // + +#if (CRYPTOPP_SSSE3_AVAILABLE) +size_t SPECK128_Enc_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_SSE(SPECK128_Enc_Block, SPECK128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SPECK128_Dec_AdvancedProcessBlocks_SSSE3(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x2_SSE(SPECK128_Dec_Block, SPECK128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ***************************** Altivec ***************************** // + +#if (CRYPTOPP_ALTIVEC_AVAILABLE) +size_t SPECK128_Enc_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x1_ALTIVEC(SPECK128_Enc_Block, SPECK128_Enc_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} + +size_t SPECK128_Dec_AdvancedProcessBlocks_ALTIVEC(const word64* subKeys, size_t rounds, + const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + return AdvancedProcessBlocks128_6x1_ALTIVEC(SPECK128_Dec_Block, SPECK128_Dec_6_Blocks, + subKeys, rounds, inBlocks, xorBlocks, outBlocks, length, flags); +} +#endif // CRYPTOPP_ALTIVEC_AVAILABLE + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/square.cpp b/extension/third_party/cryptopp/square.cpp new file mode 100644 index 00000000..4065a7f3 --- /dev/null +++ b/extension/third_party/cryptopp/square.cpp @@ -0,0 +1,187 @@ +// square.cpp - originally written and placed in the public domain by Wei Dai +// Based on Paulo S.L.M. Barreto's public domain implementation + +#include "pch.h" +#include "config.h" + +#include "square.h" +#include "misc.h" +#include "gf256.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4244) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// apply theta to a roundkey +static void SquareTransform (word32 in[4], word32 out[4]) +{ + static const byte G[4][4] = + { + 0x02U, 0x01U, 0x01U, 0x03U, + 0x03U, 0x02U, 0x01U, 0x01U, + 0x01U, 0x03U, 0x02U, 0x01U, + 0x01U, 0x01U, 0x03U, 0x02U + }; + + GF256 gf256(0xf5); + + for (int i = 0; i < 4; i++) + { + word32 temp = 0; + for (unsigned int j = 0; j < 4; j++) + for (unsigned int k = 0; k < 4; k++) + temp ^= (word32)gf256.Multiply(GETBYTE(in[i], 3-k), G[k][j]) << ((3-j)*8); + out[i] = temp; + } +} + +#define roundkeys(i, j) m_roundkeys[(i)*4+(j)] +#define roundkeys4(i) (m_roundkeys+(i)*4) + +void Square::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) +{ + AssertValidKeyLength(length); + + static const word32 offset[ROUNDS] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + }; + + GetUserKey(BIG_ENDIAN_ORDER, m_roundkeys.data(), KEYLENGTH/4, userKey, KEYLENGTH); + + /* apply the key evolution function */ + for (int i = 1; i < ROUNDS+1; i++) + { + roundkeys(i, 0) = roundkeys(i-1, 0) ^ rotlConstant<8>(roundkeys(i-1, 3)) ^ offset[i-1]; + roundkeys(i, 1) = roundkeys(i-1, 1) ^ roundkeys(i, 0); + roundkeys(i, 2) = roundkeys(i-1, 2) ^ roundkeys(i, 1); + roundkeys(i, 3) = roundkeys(i-1, 3) ^ roundkeys(i, 2); + } + + /* produce the round keys */ + if (IsForwardTransformation()) + { + for (int i = 0; i < ROUNDS; i++) + SquareTransform (roundkeys4(i), roundkeys4(i)); + } + else + { + for (int i = 0; i < ROUNDS/2; i++) + for (int j = 0; j < 4; j++) + std::swap(roundkeys(i, j), roundkeys(ROUNDS-i, j)); + SquareTransform (roundkeys4(ROUNDS), roundkeys4(ROUNDS)); + } +} + +#define MSB(x) (((x) >> 24) & 0xffU) /* most significant byte */ +#define SSB(x) (((x) >> 16) & 0xffU) /* second in significance */ +#define TSB(x) (((x) >> 8) & 0xffU) /* third in significance */ +#define LSB(x) (((x) ) & 0xffU) /* least significant byte */ + +#define squareRound(text, temp, T0, T1, T2, T3, roundkey) \ +{ \ + temp[0] = T0[MSB (text[0])] \ + ^ T1[MSB (text[1])] \ + ^ T2[MSB (text[2])] \ + ^ T3[MSB (text[3])] \ + ^ roundkey[0]; \ + temp[1] = T0[SSB (text[0])] \ + ^ T1[SSB (text[1])] \ + ^ T2[SSB (text[2])] \ + ^ T3[SSB (text[3])] \ + ^ roundkey[1]; \ + temp[2] = T0[TSB (text[0])] \ + ^ T1[TSB (text[1])] \ + ^ T2[TSB (text[2])] \ + ^ T3[TSB (text[3])] \ + ^ roundkey[2]; \ + temp[3] = T0[LSB (text[0])] \ + ^ T1[LSB (text[1])] \ + ^ T2[LSB (text[2])] \ + ^ T3[LSB (text[3])] \ + ^ roundkey[3]; \ +} /* squareRound */ + +#define squareFinal(text, temp, S, roundkey) \ +{ \ + text[0] = ((word32) (S[MSB (temp[0])]) << 24) \ + ^ ((word32) (S[MSB (temp[1])]) << 16) \ + ^ ((word32) (S[MSB (temp[2])]) << 8) \ + ^ (word32) (S[MSB (temp[3])]) \ + ^ roundkey[0]; \ + text[1] = ((word32) (S[SSB (temp[0])]) << 24) \ + ^ ((word32) (S[SSB (temp[1])]) << 16) \ + ^ ((word32) (S[SSB (temp[2])]) << 8) \ + ^ (word32) (S[SSB (temp[3])]) \ + ^ roundkey[1]; \ + text[2] = ((word32) (S[TSB (temp[0])]) << 24) \ + ^ ((word32) (S[TSB (temp[1])]) << 16) \ + ^ ((word32) (S[TSB (temp[2])]) << 8) \ + ^ (word32) (S[TSB (temp[3])]) \ + ^ roundkey[2]; \ + text[3] = ((word32) (S[LSB (temp[0])]) << 24) \ + ^ ((word32) (S[LSB (temp[1])]) << 16) \ + ^ ((word32) (S[LSB (temp[2])]) << 8) \ + ^ (word32) (S[LSB (temp[3])]) \ + ^ roundkey[3]; \ +} /* squareFinal */ + +typedef BlockGetAndPut Block; + +void Square::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 text[4], temp[4]; + Block::Get(inBlock)(text[0])(text[1])(text[2])(text[3]); + + /* initial key addition */ + text[0] ^= roundkeys(0, 0); + text[1] ^= roundkeys(0, 1); + text[2] ^= roundkeys(0, 2); + text[3] ^= roundkeys(0, 3); + + /* ROUNDS - 1 full rounds */ + for (int i=1; i+1, public FixedKeyLength<16>, FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Square";} +}; + +/// \brief Square block cipher +/// \sa Square +/// \since Crypto++ 2.2 +class Square : public Square_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_roundkeys; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Square::Encryption SquareEncryption; +typedef Square::Decryption SquareDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/squaretb.cpp b/extension/third_party/cryptopp/squaretb.cpp new file mode 100644 index 00000000..e806f610 --- /dev/null +++ b/extension/third_party/cryptopp/squaretb.cpp @@ -0,0 +1,582 @@ +#include "pch.h" +#include "square.h" + +NAMESPACE_BEGIN(CryptoPP) + +const byte Square::Enc::Se[256] = { +177, 206, 195, 149, 90, 173, 231, 2, 77, 68, 251, 145, 12, 135, 161, 80, +203, 103, 84, 221, 70, 143, 225, 78, 240, 253, 252, 235, 249, 196, 26, 110, + 94, 245, 204, 141, 28, 86, 67, 254, 7, 97, 248, 117, 89, 255, 3, 34, +138, 209, 19, 238, 136, 0, 14, 52, 21, 128, 148, 227, 237, 181, 83, 35, + 75, 71, 23, 167, 144, 53, 171, 216, 184, 223, 79, 87, 154, 146, 219, 27, + 60, 200, 153, 4, 142, 224, 215, 125, 133, 187, 64, 44, 58, 69, 241, 66, +101, 32, 65, 24, 114, 37, 147, 112, 54, 5, 242, 11, 163, 121, 236, 8, + 39, 49, 50, 182, 124, 176, 10, 115, 91, 123, 183, 129, 210, 13, 106, 38, +158, 88, 156, 131, 116, 179, 172, 48, 122, 105, 119, 15, 174, 33, 222, 208, + 46, 151, 16, 164, 152, 168, 212, 104, 45, 98, 41, 109, 22, 73, 118, 199, +232, 193, 150, 55, 229, 202, 244, 233, 99, 18, 194, 166, 20, 188, 211, 40, +175, 47, 230, 36, 82, 198, 160, 9, 189, 140, 207, 93, 17, 95, 1, 197, +159, 61, 162, 155, 201, 59, 190, 81, 25, 31, 63, 92, 178, 239, 74, 205, +191, 186, 111, 100, 217, 243, 62, 180, 170, 220, 213, 6, 192, 126, 246, 102, +108, 132, 113, 56, 185, 29, 127, 157, 72, 139, 42, 218, 165, 51, 130, 57, +214, 120, 134, 250, 228, 43, 169, 30, 137, 96, 107, 234, 85, 76, 247, 226, +}; + +const byte Square::Dec::Sd[256] = { + 53, 190, 7, 46, 83, 105, 219, 40, 111, 183, 118, 107, 12, 125, 54, 139, +146, 188, 169, 50, 172, 56, 156, 66, 99, 200, 30, 79, 36, 229, 247, 201, + 97, 141, 47, 63, 179, 101, 127, 112, 175, 154, 234, 245, 91, 152, 144, 177, +135, 113, 114, 237, 55, 69, 104, 163, 227, 239, 92, 197, 80, 193, 214, 202, + 90, 98, 95, 38, 9, 93, 20, 65, 232, 157, 206, 64, 253, 8, 23, 74, + 15, 199, 180, 62, 18, 252, 37, 75, 129, 44, 4, 120, 203, 187, 32, 189, +249, 41, 153, 168, 211, 96, 223, 17, 151, 137, 126, 250, 224, 155, 31, 210, +103, 226, 100, 119, 132, 43, 158, 138, 241, 109, 136, 121, 116, 87, 221, 230, + 57, 123, 238, 131, 225, 88, 242, 13, 52, 248, 48, 233, 185, 35, 84, 21, + 68, 11, 77, 102, 58, 3, 162, 145, 148, 82, 76, 195, 130, 231, 128, 192, +182, 14, 194, 108, 147, 236, 171, 67, 149, 246, 216, 70, 134, 5, 140, 176, +117, 0, 204, 133, 215, 61, 115, 122, 72, 228, 209, 89, 173, 184, 198, 208, +220, 161, 170, 2, 29, 191, 181, 159, 81, 196, 165, 16, 34, 207, 1, 186, +143, 49, 124, 174, 150, 218, 240, 86, 71, 212, 235, 78, 217, 19, 142, 73, + 85, 22, 255, 59, 244, 164, 178, 6, 160, 167, 251, 27, 110, 60, 51, 205, + 24, 94, 106, 213, 166, 33, 222, 254, 42, 28, 243, 10, 26, 25, 39, 45, +}; + +const word32 Square::Enc::Te[4][256] = { +{ +0x97b1b126UL, 0x69cecea7UL, 0x73c3c3b0UL, 0xdf95954aUL, +0xb45a5aeeUL, 0xafadad02UL, 0x3be7e7dcUL, 0x04020206UL, +0x9a4d4dd7UL, 0x884444ccUL, 0x03fbfbf8UL, 0xd7919146UL, +0x180c0c14UL, 0xfb87877cUL, 0xb7a1a116UL, 0xa05050f0UL, +0x63cbcba8UL, 0xce6767a9UL, 0xa85454fcUL, 0x4fdddd92UL, +0x8c4646caUL, 0xeb8f8f64UL, 0x37e1e1d6UL, 0x9c4e4ed2UL, +0x15f0f0e5UL, 0x0ffdfdf2UL, 0x0dfcfcf1UL, 0x23ebebc8UL, +0x07f9f9feUL, 0x7dc4c4b9UL, 0x341a1a2eUL, 0xdc6e6eb2UL, +0xbc5e5ee2UL, 0x1ff5f5eaUL, 0x6dcccca1UL, 0xef8d8d62UL, +0x381c1c24UL, 0xac5656faUL, 0x864343c5UL, 0x09fefef7UL, +0x0e070709UL, 0xc26161a3UL, 0x05f8f8fdUL, 0xea75759fUL, +0xb25959ebUL, 0x0bfffff4UL, 0x06030305UL, 0x44222266UL, +0xe18a8a6bUL, 0x57d1d186UL, 0x26131335UL, 0x29eeeec7UL, +0xe588886dUL, 0x00000000UL, 0x1c0e0e12UL, 0x6834345cUL, +0x2a15153fUL, 0xf5808075UL, 0xdd949449UL, 0x33e3e3d0UL, +0x2fededc2UL, 0x9fb5b52aUL, 0xa65353f5UL, 0x46232365UL, +0x964b4bddUL, 0x8e4747c9UL, 0x2e171739UL, 0xbba7a71cUL, +0xd5909045UL, 0x6a35355fUL, 0xa3abab08UL, 0x45d8d89dUL, +0x85b8b83dUL, 0x4bdfdf94UL, 0x9e4f4fd1UL, 0xae5757f9UL, +0xc19a9a5bUL, 0xd1929243UL, 0x43dbdb98UL, 0x361b1b2dUL, +0x783c3c44UL, 0x65c8c8adUL, 0xc799995eUL, 0x0804040cUL, +0xe98e8e67UL, 0x35e0e0d5UL, 0x5bd7d78cUL, 0xfa7d7d87UL, +0xff85857aUL, 0x83bbbb38UL, 0x804040c0UL, 0x582c2c74UL, +0x743a3a4eUL, 0x8a4545cfUL, 0x17f1f1e6UL, 0x844242c6UL, +0xca6565afUL, 0x40202060UL, 0x824141c3UL, 0x30181828UL, +0xe4727296UL, 0x4a25256fUL, 0xd3939340UL, 0xe0707090UL, +0x6c36365aUL, 0x0a05050fUL, 0x11f2f2e3UL, 0x160b0b1dUL, +0xb3a3a310UL, 0xf279798bUL, 0x2dececc1UL, 0x10080818UL, +0x4e272769UL, 0x62313153UL, 0x64323256UL, 0x99b6b62fUL, +0xf87c7c84UL, 0x95b0b025UL, 0x140a0a1eUL, 0xe6737395UL, +0xb65b5bedUL, 0xf67b7b8dUL, 0x9bb7b72cUL, 0xf7818176UL, +0x51d2d283UL, 0x1a0d0d17UL, 0xd46a6abeUL, 0x4c26266aUL, +0xc99e9e57UL, 0xb05858e8UL, 0xcd9c9c51UL, 0xf3838370UL, +0xe874749cUL, 0x93b3b320UL, 0xadacac01UL, 0x60303050UL, +0xf47a7a8eUL, 0xd26969bbUL, 0xee777799UL, 0x1e0f0f11UL, +0xa9aeae07UL, 0x42212163UL, 0x49dede97UL, 0x55d0d085UL, +0x5c2e2e72UL, 0xdb97974cUL, 0x20101030UL, 0xbda4a419UL, +0xc598985dUL, 0xa5a8a80dUL, 0x5dd4d489UL, 0xd06868b8UL, +0x5a2d2d77UL, 0xc46262a6UL, 0x5229297bUL, 0xda6d6db7UL, +0x2c16163aUL, 0x924949dbUL, 0xec76769aUL, 0x7bc7c7bcUL, +0x25e8e8cdUL, 0x77c1c1b6UL, 0xd996964fUL, 0x6e373759UL, +0x3fe5e5daUL, 0x61cacaabUL, 0x1df4f4e9UL, 0x27e9e9ceUL, +0xc66363a5UL, 0x24121236UL, 0x71c2c2b3UL, 0xb9a6a61fUL, +0x2814143cUL, 0x8dbcbc31UL, 0x53d3d380UL, 0x50282878UL, +0xabafaf04UL, 0x5e2f2f71UL, 0x39e6e6dfUL, 0x4824246cUL, +0xa45252f6UL, 0x79c6c6bfUL, 0xb5a0a015UL, 0x1209091bUL, +0x8fbdbd32UL, 0xed8c8c61UL, 0x6bcfcfa4UL, 0xba5d5de7UL, +0x22111133UL, 0xbe5f5fe1UL, 0x02010103UL, 0x7fc5c5baUL, +0xcb9f9f54UL, 0x7a3d3d47UL, 0xb1a2a213UL, 0xc39b9b58UL, +0x67c9c9aeUL, 0x763b3b4dUL, 0x89bebe37UL, 0xa25151f3UL, +0x3219192bUL, 0x3e1f1f21UL, 0x7e3f3f41UL, 0xb85c5ce4UL, +0x91b2b223UL, 0x2befefc4UL, 0x944a4adeUL, 0x6fcdcda2UL, +0x8bbfbf34UL, 0x81baba3bUL, 0xde6f6fb1UL, 0xc86464acUL, +0x47d9d99eUL, 0x13f3f3e0UL, 0x7c3e3e42UL, 0x9db4b429UL, +0xa1aaaa0bUL, 0x4ddcdc91UL, 0x5fd5d58aUL, 0x0c06060aUL, +0x75c0c0b5UL, 0xfc7e7e82UL, 0x19f6f6efUL, 0xcc6666aaUL, +0xd86c6cb4UL, 0xfd848479UL, 0xe2717193UL, 0x70383848UL, +0x87b9b93eUL, 0x3a1d1d27UL, 0xfe7f7f81UL, 0xcf9d9d52UL, +0x904848d8UL, 0xe38b8b68UL, 0x542a2a7eUL, 0x41dada9bUL, +0xbfa5a51aUL, 0x66333355UL, 0xf1828273UL, 0x7239394bUL, +0x59d6d68fUL, 0xf0787888UL, 0xf986867fUL, 0x01fafafbUL, +0x3de4e4d9UL, 0x562b2b7dUL, 0xa7a9a90eUL, 0x3c1e1e22UL, +0xe789896eUL, 0xc06060a0UL, 0xd66b6bbdUL, 0x21eaeacbUL, +0xaa5555ffUL, 0x984c4cd4UL, 0x1bf7f7ecUL, 0x31e2e2d3UL, +}, + +{ +0x2697b1b1UL, 0xa769ceceUL, 0xb073c3c3UL, 0x4adf9595UL, +0xeeb45a5aUL, 0x02afadadUL, 0xdc3be7e7UL, 0x06040202UL, +0xd79a4d4dUL, 0xcc884444UL, 0xf803fbfbUL, 0x46d79191UL, +0x14180c0cUL, 0x7cfb8787UL, 0x16b7a1a1UL, 0xf0a05050UL, +0xa863cbcbUL, 0xa9ce6767UL, 0xfca85454UL, 0x924fddddUL, +0xca8c4646UL, 0x64eb8f8fUL, 0xd637e1e1UL, 0xd29c4e4eUL, +0xe515f0f0UL, 0xf20ffdfdUL, 0xf10dfcfcUL, 0xc823ebebUL, +0xfe07f9f9UL, 0xb97dc4c4UL, 0x2e341a1aUL, 0xb2dc6e6eUL, +0xe2bc5e5eUL, 0xea1ff5f5UL, 0xa16dccccUL, 0x62ef8d8dUL, +0x24381c1cUL, 0xfaac5656UL, 0xc5864343UL, 0xf709fefeUL, +0x090e0707UL, 0xa3c26161UL, 0xfd05f8f8UL, 0x9fea7575UL, +0xebb25959UL, 0xf40bffffUL, 0x05060303UL, 0x66442222UL, +0x6be18a8aUL, 0x8657d1d1UL, 0x35261313UL, 0xc729eeeeUL, +0x6de58888UL, 0x00000000UL, 0x121c0e0eUL, 0x5c683434UL, +0x3f2a1515UL, 0x75f58080UL, 0x49dd9494UL, 0xd033e3e3UL, +0xc22fededUL, 0x2a9fb5b5UL, 0xf5a65353UL, 0x65462323UL, +0xdd964b4bUL, 0xc98e4747UL, 0x392e1717UL, 0x1cbba7a7UL, +0x45d59090UL, 0x5f6a3535UL, 0x08a3ababUL, 0x9d45d8d8UL, +0x3d85b8b8UL, 0x944bdfdfUL, 0xd19e4f4fUL, 0xf9ae5757UL, +0x5bc19a9aUL, 0x43d19292UL, 0x9843dbdbUL, 0x2d361b1bUL, +0x44783c3cUL, 0xad65c8c8UL, 0x5ec79999UL, 0x0c080404UL, +0x67e98e8eUL, 0xd535e0e0UL, 0x8c5bd7d7UL, 0x87fa7d7dUL, +0x7aff8585UL, 0x3883bbbbUL, 0xc0804040UL, 0x74582c2cUL, +0x4e743a3aUL, 0xcf8a4545UL, 0xe617f1f1UL, 0xc6844242UL, +0xafca6565UL, 0x60402020UL, 0xc3824141UL, 0x28301818UL, +0x96e47272UL, 0x6f4a2525UL, 0x40d39393UL, 0x90e07070UL, +0x5a6c3636UL, 0x0f0a0505UL, 0xe311f2f2UL, 0x1d160b0bUL, +0x10b3a3a3UL, 0x8bf27979UL, 0xc12dececUL, 0x18100808UL, +0x694e2727UL, 0x53623131UL, 0x56643232UL, 0x2f99b6b6UL, +0x84f87c7cUL, 0x2595b0b0UL, 0x1e140a0aUL, 0x95e67373UL, +0xedb65b5bUL, 0x8df67b7bUL, 0x2c9bb7b7UL, 0x76f78181UL, +0x8351d2d2UL, 0x171a0d0dUL, 0xbed46a6aUL, 0x6a4c2626UL, +0x57c99e9eUL, 0xe8b05858UL, 0x51cd9c9cUL, 0x70f38383UL, +0x9ce87474UL, 0x2093b3b3UL, 0x01adacacUL, 0x50603030UL, +0x8ef47a7aUL, 0xbbd26969UL, 0x99ee7777UL, 0x111e0f0fUL, +0x07a9aeaeUL, 0x63422121UL, 0x9749dedeUL, 0x8555d0d0UL, +0x725c2e2eUL, 0x4cdb9797UL, 0x30201010UL, 0x19bda4a4UL, +0x5dc59898UL, 0x0da5a8a8UL, 0x895dd4d4UL, 0xb8d06868UL, +0x775a2d2dUL, 0xa6c46262UL, 0x7b522929UL, 0xb7da6d6dUL, +0x3a2c1616UL, 0xdb924949UL, 0x9aec7676UL, 0xbc7bc7c7UL, +0xcd25e8e8UL, 0xb677c1c1UL, 0x4fd99696UL, 0x596e3737UL, +0xda3fe5e5UL, 0xab61cacaUL, 0xe91df4f4UL, 0xce27e9e9UL, +0xa5c66363UL, 0x36241212UL, 0xb371c2c2UL, 0x1fb9a6a6UL, +0x3c281414UL, 0x318dbcbcUL, 0x8053d3d3UL, 0x78502828UL, +0x04abafafUL, 0x715e2f2fUL, 0xdf39e6e6UL, 0x6c482424UL, +0xf6a45252UL, 0xbf79c6c6UL, 0x15b5a0a0UL, 0x1b120909UL, +0x328fbdbdUL, 0x61ed8c8cUL, 0xa46bcfcfUL, 0xe7ba5d5dUL, +0x33221111UL, 0xe1be5f5fUL, 0x03020101UL, 0xba7fc5c5UL, +0x54cb9f9fUL, 0x477a3d3dUL, 0x13b1a2a2UL, 0x58c39b9bUL, +0xae67c9c9UL, 0x4d763b3bUL, 0x3789bebeUL, 0xf3a25151UL, +0x2b321919UL, 0x213e1f1fUL, 0x417e3f3fUL, 0xe4b85c5cUL, +0x2391b2b2UL, 0xc42befefUL, 0xde944a4aUL, 0xa26fcdcdUL, +0x348bbfbfUL, 0x3b81babaUL, 0xb1de6f6fUL, 0xacc86464UL, +0x9e47d9d9UL, 0xe013f3f3UL, 0x427c3e3eUL, 0x299db4b4UL, +0x0ba1aaaaUL, 0x914ddcdcUL, 0x8a5fd5d5UL, 0x0a0c0606UL, +0xb575c0c0UL, 0x82fc7e7eUL, 0xef19f6f6UL, 0xaacc6666UL, +0xb4d86c6cUL, 0x79fd8484UL, 0x93e27171UL, 0x48703838UL, +0x3e87b9b9UL, 0x273a1d1dUL, 0x81fe7f7fUL, 0x52cf9d9dUL, +0xd8904848UL, 0x68e38b8bUL, 0x7e542a2aUL, 0x9b41dadaUL, +0x1abfa5a5UL, 0x55663333UL, 0x73f18282UL, 0x4b723939UL, +0x8f59d6d6UL, 0x88f07878UL, 0x7ff98686UL, 0xfb01fafaUL, +0xd93de4e4UL, 0x7d562b2bUL, 0x0ea7a9a9UL, 0x223c1e1eUL, +0x6ee78989UL, 0xa0c06060UL, 0xbdd66b6bUL, 0xcb21eaeaUL, +0xffaa5555UL, 0xd4984c4cUL, 0xec1bf7f7UL, 0xd331e2e2UL, +}, + +{ +0xb12697b1UL, 0xcea769ceUL, 0xc3b073c3UL, 0x954adf95UL, +0x5aeeb45aUL, 0xad02afadUL, 0xe7dc3be7UL, 0x02060402UL, +0x4dd79a4dUL, 0x44cc8844UL, 0xfbf803fbUL, 0x9146d791UL, +0x0c14180cUL, 0x877cfb87UL, 0xa116b7a1UL, 0x50f0a050UL, +0xcba863cbUL, 0x67a9ce67UL, 0x54fca854UL, 0xdd924fddUL, +0x46ca8c46UL, 0x8f64eb8fUL, 0xe1d637e1UL, 0x4ed29c4eUL, +0xf0e515f0UL, 0xfdf20ffdUL, 0xfcf10dfcUL, 0xebc823ebUL, +0xf9fe07f9UL, 0xc4b97dc4UL, 0x1a2e341aUL, 0x6eb2dc6eUL, +0x5ee2bc5eUL, 0xf5ea1ff5UL, 0xcca16dccUL, 0x8d62ef8dUL, +0x1c24381cUL, 0x56faac56UL, 0x43c58643UL, 0xfef709feUL, +0x07090e07UL, 0x61a3c261UL, 0xf8fd05f8UL, 0x759fea75UL, +0x59ebb259UL, 0xfff40bffUL, 0x03050603UL, 0x22664422UL, +0x8a6be18aUL, 0xd18657d1UL, 0x13352613UL, 0xeec729eeUL, +0x886de588UL, 0x00000000UL, 0x0e121c0eUL, 0x345c6834UL, +0x153f2a15UL, 0x8075f580UL, 0x9449dd94UL, 0xe3d033e3UL, +0xedc22fedUL, 0xb52a9fb5UL, 0x53f5a653UL, 0x23654623UL, +0x4bdd964bUL, 0x47c98e47UL, 0x17392e17UL, 0xa71cbba7UL, +0x9045d590UL, 0x355f6a35UL, 0xab08a3abUL, 0xd89d45d8UL, +0xb83d85b8UL, 0xdf944bdfUL, 0x4fd19e4fUL, 0x57f9ae57UL, +0x9a5bc19aUL, 0x9243d192UL, 0xdb9843dbUL, 0x1b2d361bUL, +0x3c44783cUL, 0xc8ad65c8UL, 0x995ec799UL, 0x040c0804UL, +0x8e67e98eUL, 0xe0d535e0UL, 0xd78c5bd7UL, 0x7d87fa7dUL, +0x857aff85UL, 0xbb3883bbUL, 0x40c08040UL, 0x2c74582cUL, +0x3a4e743aUL, 0x45cf8a45UL, 0xf1e617f1UL, 0x42c68442UL, +0x65afca65UL, 0x20604020UL, 0x41c38241UL, 0x18283018UL, +0x7296e472UL, 0x256f4a25UL, 0x9340d393UL, 0x7090e070UL, +0x365a6c36UL, 0x050f0a05UL, 0xf2e311f2UL, 0x0b1d160bUL, +0xa310b3a3UL, 0x798bf279UL, 0xecc12decUL, 0x08181008UL, +0x27694e27UL, 0x31536231UL, 0x32566432UL, 0xb62f99b6UL, +0x7c84f87cUL, 0xb02595b0UL, 0x0a1e140aUL, 0x7395e673UL, +0x5bedb65bUL, 0x7b8df67bUL, 0xb72c9bb7UL, 0x8176f781UL, +0xd28351d2UL, 0x0d171a0dUL, 0x6abed46aUL, 0x266a4c26UL, +0x9e57c99eUL, 0x58e8b058UL, 0x9c51cd9cUL, 0x8370f383UL, +0x749ce874UL, 0xb32093b3UL, 0xac01adacUL, 0x30506030UL, +0x7a8ef47aUL, 0x69bbd269UL, 0x7799ee77UL, 0x0f111e0fUL, +0xae07a9aeUL, 0x21634221UL, 0xde9749deUL, 0xd08555d0UL, +0x2e725c2eUL, 0x974cdb97UL, 0x10302010UL, 0xa419bda4UL, +0x985dc598UL, 0xa80da5a8UL, 0xd4895dd4UL, 0x68b8d068UL, +0x2d775a2dUL, 0x62a6c462UL, 0x297b5229UL, 0x6db7da6dUL, +0x163a2c16UL, 0x49db9249UL, 0x769aec76UL, 0xc7bc7bc7UL, +0xe8cd25e8UL, 0xc1b677c1UL, 0x964fd996UL, 0x37596e37UL, +0xe5da3fe5UL, 0xcaab61caUL, 0xf4e91df4UL, 0xe9ce27e9UL, +0x63a5c663UL, 0x12362412UL, 0xc2b371c2UL, 0xa61fb9a6UL, +0x143c2814UL, 0xbc318dbcUL, 0xd38053d3UL, 0x28785028UL, +0xaf04abafUL, 0x2f715e2fUL, 0xe6df39e6UL, 0x246c4824UL, +0x52f6a452UL, 0xc6bf79c6UL, 0xa015b5a0UL, 0x091b1209UL, +0xbd328fbdUL, 0x8c61ed8cUL, 0xcfa46bcfUL, 0x5de7ba5dUL, +0x11332211UL, 0x5fe1be5fUL, 0x01030201UL, 0xc5ba7fc5UL, +0x9f54cb9fUL, 0x3d477a3dUL, 0xa213b1a2UL, 0x9b58c39bUL, +0xc9ae67c9UL, 0x3b4d763bUL, 0xbe3789beUL, 0x51f3a251UL, +0x192b3219UL, 0x1f213e1fUL, 0x3f417e3fUL, 0x5ce4b85cUL, +0xb22391b2UL, 0xefc42befUL, 0x4ade944aUL, 0xcda26fcdUL, +0xbf348bbfUL, 0xba3b81baUL, 0x6fb1de6fUL, 0x64acc864UL, +0xd99e47d9UL, 0xf3e013f3UL, 0x3e427c3eUL, 0xb4299db4UL, +0xaa0ba1aaUL, 0xdc914ddcUL, 0xd58a5fd5UL, 0x060a0c06UL, +0xc0b575c0UL, 0x7e82fc7eUL, 0xf6ef19f6UL, 0x66aacc66UL, +0x6cb4d86cUL, 0x8479fd84UL, 0x7193e271UL, 0x38487038UL, +0xb93e87b9UL, 0x1d273a1dUL, 0x7f81fe7fUL, 0x9d52cf9dUL, +0x48d89048UL, 0x8b68e38bUL, 0x2a7e542aUL, 0xda9b41daUL, +0xa51abfa5UL, 0x33556633UL, 0x8273f182UL, 0x394b7239UL, +0xd68f59d6UL, 0x7888f078UL, 0x867ff986UL, 0xfafb01faUL, +0xe4d93de4UL, 0x2b7d562bUL, 0xa90ea7a9UL, 0x1e223c1eUL, +0x896ee789UL, 0x60a0c060UL, 0x6bbdd66bUL, 0xeacb21eaUL, +0x55ffaa55UL, 0x4cd4984cUL, 0xf7ec1bf7UL, 0xe2d331e2UL, +}, + +{ +0xb1b12697UL, 0xcecea769UL, 0xc3c3b073UL, 0x95954adfUL, +0x5a5aeeb4UL, 0xadad02afUL, 0xe7e7dc3bUL, 0x02020604UL, +0x4d4dd79aUL, 0x4444cc88UL, 0xfbfbf803UL, 0x919146d7UL, +0x0c0c1418UL, 0x87877cfbUL, 0xa1a116b7UL, 0x5050f0a0UL, +0xcbcba863UL, 0x6767a9ceUL, 0x5454fca8UL, 0xdddd924fUL, +0x4646ca8cUL, 0x8f8f64ebUL, 0xe1e1d637UL, 0x4e4ed29cUL, +0xf0f0e515UL, 0xfdfdf20fUL, 0xfcfcf10dUL, 0xebebc823UL, +0xf9f9fe07UL, 0xc4c4b97dUL, 0x1a1a2e34UL, 0x6e6eb2dcUL, +0x5e5ee2bcUL, 0xf5f5ea1fUL, 0xcccca16dUL, 0x8d8d62efUL, +0x1c1c2438UL, 0x5656faacUL, 0x4343c586UL, 0xfefef709UL, +0x0707090eUL, 0x6161a3c2UL, 0xf8f8fd05UL, 0x75759feaUL, +0x5959ebb2UL, 0xfffff40bUL, 0x03030506UL, 0x22226644UL, +0x8a8a6be1UL, 0xd1d18657UL, 0x13133526UL, 0xeeeec729UL, +0x88886de5UL, 0x00000000UL, 0x0e0e121cUL, 0x34345c68UL, +0x15153f2aUL, 0x808075f5UL, 0x949449ddUL, 0xe3e3d033UL, +0xededc22fUL, 0xb5b52a9fUL, 0x5353f5a6UL, 0x23236546UL, +0x4b4bdd96UL, 0x4747c98eUL, 0x1717392eUL, 0xa7a71cbbUL, +0x909045d5UL, 0x35355f6aUL, 0xabab08a3UL, 0xd8d89d45UL, +0xb8b83d85UL, 0xdfdf944bUL, 0x4f4fd19eUL, 0x5757f9aeUL, +0x9a9a5bc1UL, 0x929243d1UL, 0xdbdb9843UL, 0x1b1b2d36UL, +0x3c3c4478UL, 0xc8c8ad65UL, 0x99995ec7UL, 0x04040c08UL, +0x8e8e67e9UL, 0xe0e0d535UL, 0xd7d78c5bUL, 0x7d7d87faUL, +0x85857affUL, 0xbbbb3883UL, 0x4040c080UL, 0x2c2c7458UL, +0x3a3a4e74UL, 0x4545cf8aUL, 0xf1f1e617UL, 0x4242c684UL, +0x6565afcaUL, 0x20206040UL, 0x4141c382UL, 0x18182830UL, +0x727296e4UL, 0x25256f4aUL, 0x939340d3UL, 0x707090e0UL, +0x36365a6cUL, 0x05050f0aUL, 0xf2f2e311UL, 0x0b0b1d16UL, +0xa3a310b3UL, 0x79798bf2UL, 0xececc12dUL, 0x08081810UL, +0x2727694eUL, 0x31315362UL, 0x32325664UL, 0xb6b62f99UL, +0x7c7c84f8UL, 0xb0b02595UL, 0x0a0a1e14UL, 0x737395e6UL, +0x5b5bedb6UL, 0x7b7b8df6UL, 0xb7b72c9bUL, 0x818176f7UL, +0xd2d28351UL, 0x0d0d171aUL, 0x6a6abed4UL, 0x26266a4cUL, +0x9e9e57c9UL, 0x5858e8b0UL, 0x9c9c51cdUL, 0x838370f3UL, +0x74749ce8UL, 0xb3b32093UL, 0xacac01adUL, 0x30305060UL, +0x7a7a8ef4UL, 0x6969bbd2UL, 0x777799eeUL, 0x0f0f111eUL, +0xaeae07a9UL, 0x21216342UL, 0xdede9749UL, 0xd0d08555UL, +0x2e2e725cUL, 0x97974cdbUL, 0x10103020UL, 0xa4a419bdUL, +0x98985dc5UL, 0xa8a80da5UL, 0xd4d4895dUL, 0x6868b8d0UL, +0x2d2d775aUL, 0x6262a6c4UL, 0x29297b52UL, 0x6d6db7daUL, +0x16163a2cUL, 0x4949db92UL, 0x76769aecUL, 0xc7c7bc7bUL, +0xe8e8cd25UL, 0xc1c1b677UL, 0x96964fd9UL, 0x3737596eUL, +0xe5e5da3fUL, 0xcacaab61UL, 0xf4f4e91dUL, 0xe9e9ce27UL, +0x6363a5c6UL, 0x12123624UL, 0xc2c2b371UL, 0xa6a61fb9UL, +0x14143c28UL, 0xbcbc318dUL, 0xd3d38053UL, 0x28287850UL, +0xafaf04abUL, 0x2f2f715eUL, 0xe6e6df39UL, 0x24246c48UL, +0x5252f6a4UL, 0xc6c6bf79UL, 0xa0a015b5UL, 0x09091b12UL, +0xbdbd328fUL, 0x8c8c61edUL, 0xcfcfa46bUL, 0x5d5de7baUL, +0x11113322UL, 0x5f5fe1beUL, 0x01010302UL, 0xc5c5ba7fUL, +0x9f9f54cbUL, 0x3d3d477aUL, 0xa2a213b1UL, 0x9b9b58c3UL, +0xc9c9ae67UL, 0x3b3b4d76UL, 0xbebe3789UL, 0x5151f3a2UL, +0x19192b32UL, 0x1f1f213eUL, 0x3f3f417eUL, 0x5c5ce4b8UL, +0xb2b22391UL, 0xefefc42bUL, 0x4a4ade94UL, 0xcdcda26fUL, +0xbfbf348bUL, 0xbaba3b81UL, 0x6f6fb1deUL, 0x6464acc8UL, +0xd9d99e47UL, 0xf3f3e013UL, 0x3e3e427cUL, 0xb4b4299dUL, +0xaaaa0ba1UL, 0xdcdc914dUL, 0xd5d58a5fUL, 0x06060a0cUL, +0xc0c0b575UL, 0x7e7e82fcUL, 0xf6f6ef19UL, 0x6666aaccUL, +0x6c6cb4d8UL, 0x848479fdUL, 0x717193e2UL, 0x38384870UL, +0xb9b93e87UL, 0x1d1d273aUL, 0x7f7f81feUL, 0x9d9d52cfUL, +0x4848d890UL, 0x8b8b68e3UL, 0x2a2a7e54UL, 0xdada9b41UL, +0xa5a51abfUL, 0x33335566UL, 0x828273f1UL, 0x39394b72UL, +0xd6d68f59UL, 0x787888f0UL, 0x86867ff9UL, 0xfafafb01UL, +0xe4e4d93dUL, 0x2b2b7d56UL, 0xa9a90ea7UL, 0x1e1e223cUL, +0x89896ee7UL, 0x6060a0c0UL, 0x6b6bbdd6UL, 0xeaeacb21UL, +0x5555ffaaUL, 0x4c4cd498UL, 0xf7f7ec1bUL, 0xe2e2d331UL, +}}; + +const word32 Square::Dec::Td[4][256] = { +{ +0xe368bc02UL, 0x5585620cUL, 0x2a3f2331UL, 0x61ab13f7UL, +0x98d46d72UL, 0x21cb9a19UL, 0x3c22a461UL, 0x459d3dcdUL, +0x05fdb423UL, 0x2bc4075fUL, 0x9b2c01c0UL, 0x3dd9800fUL, +0x486c5c74UL, 0xf97f7e85UL, 0xf173ab1fUL, 0xb6edde0eUL, +0x283c6bedUL, 0x4997781aUL, 0x9f2a918dUL, 0xc9579f33UL, +0xa907a8aaUL, 0xa50ded7dUL, 0x7c422d8fUL, 0x764db0c9UL, +0x4d91e857UL, 0xcea963ccUL, 0xb4ee96d2UL, 0x3028e1b6UL, +0x0df161b9UL, 0xbd196726UL, 0x419bad80UL, 0xc0a06ec7UL, +0x5183f241UL, 0x92dbf034UL, 0x6fa21efcUL, 0x8f32ce4cUL, +0x13e03373UL, 0x69a7c66dUL, 0xe56d6493UL, 0xbf1a2ffaUL, +0xbb1cbfb7UL, 0x587403b5UL, 0xe76e2c4fUL, 0x5d89b796UL, +0xe89c052aUL, 0x446619a3UL, 0x342e71fbUL, 0x0ff22965UL, +0xfe81827aUL, 0xb11322f1UL, 0xa30835ecUL, 0xcd510f7eUL, +0xff7aa614UL, 0x5c7293f8UL, 0x2fc29712UL, 0xf370e3c3UL, +0x992f491cUL, 0xd1431568UL, 0xc2a3261bUL, 0x88cc32b3UL, +0x8acf7a6fUL, 0xb0e8069fUL, 0x7a47f51eUL, 0xd2bb79daUL, +0xe6950821UL, 0x4398e55cUL, 0xd0b83106UL, 0x11e37bafUL, +0x7e416553UL, 0xccaa2b10UL, 0xd8b4e49cUL, 0x6456a7d4UL, +0xfb7c3659UL, 0x724b2084UL, 0xea9f4df6UL, 0x6a5faadfUL, +0x2dc1dfceUL, 0x70486858UL, 0xcaaff381UL, 0x0605d891UL, +0x5a774b69UL, 0x94de28a5UL, 0x39df1042UL, 0x813bc347UL, +0xfc82caa6UL, 0x23c8d2c5UL, 0x03f86cb2UL, 0x080cd59aUL, +0xdab7ac40UL, 0x7db909e1UL, 0x3824342cUL, 0xcf5247a2UL, +0xdcb274d1UL, 0x63a85b2bUL, 0x35d55595UL, 0x479e7511UL, +0x15e5ebe2UL, 0x4b9430c6UL, 0x4a6f14a8UL, 0x91239c86UL, +0x4c6acc39UL, 0x5f8aff4aUL, 0x0406904dUL, 0xee99ddbbUL, +0x1e1152caUL, 0xaaffc418UL, 0xeb646998UL, 0x07fefcffUL, +0x8b345e01UL, 0x567d0ebeUL, 0xbae79bd9UL, 0x4263c132UL, +0x75b5dc7bUL, 0x97264417UL, 0x67aecb66UL, 0x95250ccbUL, +0xec9a9567UL, 0x57862ad0UL, 0x60503799UL, 0xb8e4d305UL, +0x65ad83baUL, 0x19efae35UL, 0xa4f6c913UL, 0xc15b4aa9UL, +0x873e1bd6UL, 0xa0f0595eUL, 0x18148a5bUL, 0xaf02703bUL, +0xab04e076UL, 0xdd4950bfUL, 0xdf4a1863UL, 0xc6a5b656UL, +0x853d530aUL, 0xfa871237UL, 0x77b694a7UL, 0x4665517fUL, +0xed61b109UL, 0x1bece6e9UL, 0xd5458525UL, 0xf5753b52UL, +0x7fba413dUL, 0x27ce4288UL, 0xb2eb4e43UL, 0xd6bde997UL, +0x527b9ef3UL, 0x62537f45UL, 0x2c3afba0UL, 0x7bbcd170UL, +0xb91ff76bUL, 0x121b171dUL, 0xfd79eec8UL, 0x3a277cf0UL, +0x0c0a45d7UL, 0x96dd6079UL, 0x2233f6abUL, 0xacfa1c89UL, +0xc8acbb5dUL, 0xa10b7d30UL, 0xd4bea14bUL, 0xbee10b94UL, +0x25cd0a54UL, 0x547e4662UL, 0xa2f31182UL, 0x17e6a33eUL, +0x263566e6UL, 0xc3580275UL, 0x83388b9bUL, 0x7844bdc2UL, +0x020348dcUL, 0x4f92a08bUL, 0x2e39b37cUL, 0x4e6984e5UL, +0xf0888f71UL, 0x362d3927UL, 0x9cd2fd3fUL, 0x01fb246eUL, +0x893716ddUL, 0x00000000UL, 0xf68d57e0UL, 0xe293986cUL, +0x744ef815UL, 0x9320d45aUL, 0xad0138e7UL, 0xd3405db4UL, +0x1a17c287UL, 0xb3106a2dUL, 0x5078d62fUL, 0xf48e1f3cUL, +0xa70ea5a1UL, 0x71b34c36UL, 0x9ad725aeUL, 0x5e71db24UL, +0x161d8750UL, 0xef62f9d5UL, 0x8d318690UL, 0x1c121a16UL, +0xa6f581cfUL, 0x5b8c6f07UL, 0x37d61d49UL, 0x6e593a92UL, +0x84c67764UL, 0x86c53fb8UL, 0xd746cdf9UL, 0xe090d0b0UL, +0x29c74f83UL, 0xe49640fdUL, 0x0e090d0bUL, 0x6da15620UL, +0x8ec9ea22UL, 0xdb4c882eUL, 0xf776738eUL, 0xb515b2bcUL, +0x10185fc1UL, 0x322ba96aUL, 0x6ba48eb1UL, 0xaef95455UL, +0x406089eeUL, 0x6655ef08UL, 0xe9672144UL, 0x3e21ecbdUL, +0x2030be77UL, 0xf28bc7adUL, 0x80c0e729UL, 0x141ecf8cUL, +0xbce24348UL, 0xc4a6fe8aUL, 0x31d3c5d8UL, 0xb716fa60UL, +0x5380ba9dUL, 0xd94fc0f2UL, 0x1de93e78UL, 0x24362e3aUL, +0xe16bf4deUL, 0xcb54d7efUL, 0x09f7f1f4UL, 0x82c3aff5UL, +0x0bf4b928UL, 0x9d29d951UL, 0xc75e9238UL, 0xf8845aebUL, +0x90d8b8e8UL, 0xdeb13c0dUL, 0x33d08d04UL, 0x685ce203UL, +0xc55ddae4UL, 0x3bdc589eUL, 0x0a0f9d46UL, 0x3fdac8d3UL, +0x598f27dbUL, 0xa8fc8cc4UL, 0x79bf99acUL, 0x6c5a724eUL, +0x8ccaa2feUL, 0x9ed1b5e3UL, 0x1fea76a4UL, 0x73b004eaUL, +}, + +{ +0x02e368bcUL, 0x0c558562UL, 0x312a3f23UL, 0xf761ab13UL, +0x7298d46dUL, 0x1921cb9aUL, 0x613c22a4UL, 0xcd459d3dUL, +0x2305fdb4UL, 0x5f2bc407UL, 0xc09b2c01UL, 0x0f3dd980UL, +0x74486c5cUL, 0x85f97f7eUL, 0x1ff173abUL, 0x0eb6eddeUL, +0xed283c6bUL, 0x1a499778UL, 0x8d9f2a91UL, 0x33c9579fUL, +0xaaa907a8UL, 0x7da50dedUL, 0x8f7c422dUL, 0xc9764db0UL, +0x574d91e8UL, 0xcccea963UL, 0xd2b4ee96UL, 0xb63028e1UL, +0xb90df161UL, 0x26bd1967UL, 0x80419badUL, 0xc7c0a06eUL, +0x415183f2UL, 0x3492dbf0UL, 0xfc6fa21eUL, 0x4c8f32ceUL, +0x7313e033UL, 0x6d69a7c6UL, 0x93e56d64UL, 0xfabf1a2fUL, +0xb7bb1cbfUL, 0xb5587403UL, 0x4fe76e2cUL, 0x965d89b7UL, +0x2ae89c05UL, 0xa3446619UL, 0xfb342e71UL, 0x650ff229UL, +0x7afe8182UL, 0xf1b11322UL, 0xeca30835UL, 0x7ecd510fUL, +0x14ff7aa6UL, 0xf85c7293UL, 0x122fc297UL, 0xc3f370e3UL, +0x1c992f49UL, 0x68d14315UL, 0x1bc2a326UL, 0xb388cc32UL, +0x6f8acf7aUL, 0x9fb0e806UL, 0x1e7a47f5UL, 0xdad2bb79UL, +0x21e69508UL, 0x5c4398e5UL, 0x06d0b831UL, 0xaf11e37bUL, +0x537e4165UL, 0x10ccaa2bUL, 0x9cd8b4e4UL, 0xd46456a7UL, +0x59fb7c36UL, 0x84724b20UL, 0xf6ea9f4dUL, 0xdf6a5faaUL, +0xce2dc1dfUL, 0x58704868UL, 0x81caaff3UL, 0x910605d8UL, +0x695a774bUL, 0xa594de28UL, 0x4239df10UL, 0x47813bc3UL, +0xa6fc82caUL, 0xc523c8d2UL, 0xb203f86cUL, 0x9a080cd5UL, +0x40dab7acUL, 0xe17db909UL, 0x2c382434UL, 0xa2cf5247UL, +0xd1dcb274UL, 0x2b63a85bUL, 0x9535d555UL, 0x11479e75UL, +0xe215e5ebUL, 0xc64b9430UL, 0xa84a6f14UL, 0x8691239cUL, +0x394c6accUL, 0x4a5f8affUL, 0x4d040690UL, 0xbbee99ddUL, +0xca1e1152UL, 0x18aaffc4UL, 0x98eb6469UL, 0xff07fefcUL, +0x018b345eUL, 0xbe567d0eUL, 0xd9bae79bUL, 0x324263c1UL, +0x7b75b5dcUL, 0x17972644UL, 0x6667aecbUL, 0xcb95250cUL, +0x67ec9a95UL, 0xd057862aUL, 0x99605037UL, 0x05b8e4d3UL, +0xba65ad83UL, 0x3519efaeUL, 0x13a4f6c9UL, 0xa9c15b4aUL, +0xd6873e1bUL, 0x5ea0f059UL, 0x5b18148aUL, 0x3baf0270UL, +0x76ab04e0UL, 0xbfdd4950UL, 0x63df4a18UL, 0x56c6a5b6UL, +0x0a853d53UL, 0x37fa8712UL, 0xa777b694UL, 0x7f466551UL, +0x09ed61b1UL, 0xe91bece6UL, 0x25d54585UL, 0x52f5753bUL, +0x3d7fba41UL, 0x8827ce42UL, 0x43b2eb4eUL, 0x97d6bde9UL, +0xf3527b9eUL, 0x4562537fUL, 0xa02c3afbUL, 0x707bbcd1UL, +0x6bb91ff7UL, 0x1d121b17UL, 0xc8fd79eeUL, 0xf03a277cUL, +0xd70c0a45UL, 0x7996dd60UL, 0xab2233f6UL, 0x89acfa1cUL, +0x5dc8acbbUL, 0x30a10b7dUL, 0x4bd4bea1UL, 0x94bee10bUL, +0x5425cd0aUL, 0x62547e46UL, 0x82a2f311UL, 0x3e17e6a3UL, +0xe6263566UL, 0x75c35802UL, 0x9b83388bUL, 0xc27844bdUL, +0xdc020348UL, 0x8b4f92a0UL, 0x7c2e39b3UL, 0xe54e6984UL, +0x71f0888fUL, 0x27362d39UL, 0x3f9cd2fdUL, 0x6e01fb24UL, +0xdd893716UL, 0x00000000UL, 0xe0f68d57UL, 0x6ce29398UL, +0x15744ef8UL, 0x5a9320d4UL, 0xe7ad0138UL, 0xb4d3405dUL, +0x871a17c2UL, 0x2db3106aUL, 0x2f5078d6UL, 0x3cf48e1fUL, +0xa1a70ea5UL, 0x3671b34cUL, 0xae9ad725UL, 0x245e71dbUL, +0x50161d87UL, 0xd5ef62f9UL, 0x908d3186UL, 0x161c121aUL, +0xcfa6f581UL, 0x075b8c6fUL, 0x4937d61dUL, 0x926e593aUL, +0x6484c677UL, 0xb886c53fUL, 0xf9d746cdUL, 0xb0e090d0UL, +0x8329c74fUL, 0xfde49640UL, 0x0b0e090dUL, 0x206da156UL, +0x228ec9eaUL, 0x2edb4c88UL, 0x8ef77673UL, 0xbcb515b2UL, +0xc110185fUL, 0x6a322ba9UL, 0xb16ba48eUL, 0x55aef954UL, +0xee406089UL, 0x086655efUL, 0x44e96721UL, 0xbd3e21ecUL, +0x772030beUL, 0xadf28bc7UL, 0x2980c0e7UL, 0x8c141ecfUL, +0x48bce243UL, 0x8ac4a6feUL, 0xd831d3c5UL, 0x60b716faUL, +0x9d5380baUL, 0xf2d94fc0UL, 0x781de93eUL, 0x3a24362eUL, +0xdee16bf4UL, 0xefcb54d7UL, 0xf409f7f1UL, 0xf582c3afUL, +0x280bf4b9UL, 0x519d29d9UL, 0x38c75e92UL, 0xebf8845aUL, +0xe890d8b8UL, 0x0ddeb13cUL, 0x0433d08dUL, 0x03685ce2UL, +0xe4c55ddaUL, 0x9e3bdc58UL, 0x460a0f9dUL, 0xd33fdac8UL, +0xdb598f27UL, 0xc4a8fc8cUL, 0xac79bf99UL, 0x4e6c5a72UL, +0xfe8ccaa2UL, 0xe39ed1b5UL, 0xa41fea76UL, 0xea73b004UL, +}, + +{ +0xbc02e368UL, 0x620c5585UL, 0x23312a3fUL, 0x13f761abUL, +0x6d7298d4UL, 0x9a1921cbUL, 0xa4613c22UL, 0x3dcd459dUL, +0xb42305fdUL, 0x075f2bc4UL, 0x01c09b2cUL, 0x800f3dd9UL, +0x5c74486cUL, 0x7e85f97fUL, 0xab1ff173UL, 0xde0eb6edUL, +0x6bed283cUL, 0x781a4997UL, 0x918d9f2aUL, 0x9f33c957UL, +0xa8aaa907UL, 0xed7da50dUL, 0x2d8f7c42UL, 0xb0c9764dUL, +0xe8574d91UL, 0x63cccea9UL, 0x96d2b4eeUL, 0xe1b63028UL, +0x61b90df1UL, 0x6726bd19UL, 0xad80419bUL, 0x6ec7c0a0UL, +0xf2415183UL, 0xf03492dbUL, 0x1efc6fa2UL, 0xce4c8f32UL, +0x337313e0UL, 0xc66d69a7UL, 0x6493e56dUL, 0x2ffabf1aUL, +0xbfb7bb1cUL, 0x03b55874UL, 0x2c4fe76eUL, 0xb7965d89UL, +0x052ae89cUL, 0x19a34466UL, 0x71fb342eUL, 0x29650ff2UL, +0x827afe81UL, 0x22f1b113UL, 0x35eca308UL, 0x0f7ecd51UL, +0xa614ff7aUL, 0x93f85c72UL, 0x97122fc2UL, 0xe3c3f370UL, +0x491c992fUL, 0x1568d143UL, 0x261bc2a3UL, 0x32b388ccUL, +0x7a6f8acfUL, 0x069fb0e8UL, 0xf51e7a47UL, 0x79dad2bbUL, +0x0821e695UL, 0xe55c4398UL, 0x3106d0b8UL, 0x7baf11e3UL, +0x65537e41UL, 0x2b10ccaaUL, 0xe49cd8b4UL, 0xa7d46456UL, +0x3659fb7cUL, 0x2084724bUL, 0x4df6ea9fUL, 0xaadf6a5fUL, +0xdfce2dc1UL, 0x68587048UL, 0xf381caafUL, 0xd8910605UL, +0x4b695a77UL, 0x28a594deUL, 0x104239dfUL, 0xc347813bUL, +0xcaa6fc82UL, 0xd2c523c8UL, 0x6cb203f8UL, 0xd59a080cUL, +0xac40dab7UL, 0x09e17db9UL, 0x342c3824UL, 0x47a2cf52UL, +0x74d1dcb2UL, 0x5b2b63a8UL, 0x559535d5UL, 0x7511479eUL, +0xebe215e5UL, 0x30c64b94UL, 0x14a84a6fUL, 0x9c869123UL, +0xcc394c6aUL, 0xff4a5f8aUL, 0x904d0406UL, 0xddbbee99UL, +0x52ca1e11UL, 0xc418aaffUL, 0x6998eb64UL, 0xfcff07feUL, +0x5e018b34UL, 0x0ebe567dUL, 0x9bd9bae7UL, 0xc1324263UL, +0xdc7b75b5UL, 0x44179726UL, 0xcb6667aeUL, 0x0ccb9525UL, +0x9567ec9aUL, 0x2ad05786UL, 0x37996050UL, 0xd305b8e4UL, +0x83ba65adUL, 0xae3519efUL, 0xc913a4f6UL, 0x4aa9c15bUL, +0x1bd6873eUL, 0x595ea0f0UL, 0x8a5b1814UL, 0x703baf02UL, +0xe076ab04UL, 0x50bfdd49UL, 0x1863df4aUL, 0xb656c6a5UL, +0x530a853dUL, 0x1237fa87UL, 0x94a777b6UL, 0x517f4665UL, +0xb109ed61UL, 0xe6e91becUL, 0x8525d545UL, 0x3b52f575UL, +0x413d7fbaUL, 0x428827ceUL, 0x4e43b2ebUL, 0xe997d6bdUL, +0x9ef3527bUL, 0x7f456253UL, 0xfba02c3aUL, 0xd1707bbcUL, +0xf76bb91fUL, 0x171d121bUL, 0xeec8fd79UL, 0x7cf03a27UL, +0x45d70c0aUL, 0x607996ddUL, 0xf6ab2233UL, 0x1c89acfaUL, +0xbb5dc8acUL, 0x7d30a10bUL, 0xa14bd4beUL, 0x0b94bee1UL, +0x0a5425cdUL, 0x4662547eUL, 0x1182a2f3UL, 0xa33e17e6UL, +0x66e62635UL, 0x0275c358UL, 0x8b9b8338UL, 0xbdc27844UL, +0x48dc0203UL, 0xa08b4f92UL, 0xb37c2e39UL, 0x84e54e69UL, +0x8f71f088UL, 0x3927362dUL, 0xfd3f9cd2UL, 0x246e01fbUL, +0x16dd8937UL, 0x00000000UL, 0x57e0f68dUL, 0x986ce293UL, +0xf815744eUL, 0xd45a9320UL, 0x38e7ad01UL, 0x5db4d340UL, +0xc2871a17UL, 0x6a2db310UL, 0xd62f5078UL, 0x1f3cf48eUL, +0xa5a1a70eUL, 0x4c3671b3UL, 0x25ae9ad7UL, 0xdb245e71UL, +0x8750161dUL, 0xf9d5ef62UL, 0x86908d31UL, 0x1a161c12UL, +0x81cfa6f5UL, 0x6f075b8cUL, 0x1d4937d6UL, 0x3a926e59UL, +0x776484c6UL, 0x3fb886c5UL, 0xcdf9d746UL, 0xd0b0e090UL, +0x4f8329c7UL, 0x40fde496UL, 0x0d0b0e09UL, 0x56206da1UL, +0xea228ec9UL, 0x882edb4cUL, 0x738ef776UL, 0xb2bcb515UL, +0x5fc11018UL, 0xa96a322bUL, 0x8eb16ba4UL, 0x5455aef9UL, +0x89ee4060UL, 0xef086655UL, 0x2144e967UL, 0xecbd3e21UL, +0xbe772030UL, 0xc7adf28bUL, 0xe72980c0UL, 0xcf8c141eUL, +0x4348bce2UL, 0xfe8ac4a6UL, 0xc5d831d3UL, 0xfa60b716UL, +0xba9d5380UL, 0xc0f2d94fUL, 0x3e781de9UL, 0x2e3a2436UL, +0xf4dee16bUL, 0xd7efcb54UL, 0xf1f409f7UL, 0xaff582c3UL, +0xb9280bf4UL, 0xd9519d29UL, 0x9238c75eUL, 0x5aebf884UL, +0xb8e890d8UL, 0x3c0ddeb1UL, 0x8d0433d0UL, 0xe203685cUL, +0xdae4c55dUL, 0x589e3bdcUL, 0x9d460a0fUL, 0xc8d33fdaUL, +0x27db598fUL, 0x8cc4a8fcUL, 0x99ac79bfUL, 0x724e6c5aUL, +0xa2fe8ccaUL, 0xb5e39ed1UL, 0x76a41feaUL, 0x04ea73b0UL, +}, + +{ +0x68bc02e3UL, 0x85620c55UL, 0x3f23312aUL, 0xab13f761UL, +0xd46d7298UL, 0xcb9a1921UL, 0x22a4613cUL, 0x9d3dcd45UL, +0xfdb42305UL, 0xc4075f2bUL, 0x2c01c09bUL, 0xd9800f3dUL, +0x6c5c7448UL, 0x7f7e85f9UL, 0x73ab1ff1UL, 0xedde0eb6UL, +0x3c6bed28UL, 0x97781a49UL, 0x2a918d9fUL, 0x579f33c9UL, +0x07a8aaa9UL, 0x0ded7da5UL, 0x422d8f7cUL, 0x4db0c976UL, +0x91e8574dUL, 0xa963ccceUL, 0xee96d2b4UL, 0x28e1b630UL, +0xf161b90dUL, 0x196726bdUL, 0x9bad8041UL, 0xa06ec7c0UL, +0x83f24151UL, 0xdbf03492UL, 0xa21efc6fUL, 0x32ce4c8fUL, +0xe0337313UL, 0xa7c66d69UL, 0x6d6493e5UL, 0x1a2ffabfUL, +0x1cbfb7bbUL, 0x7403b558UL, 0x6e2c4fe7UL, 0x89b7965dUL, +0x9c052ae8UL, 0x6619a344UL, 0x2e71fb34UL, 0xf229650fUL, +0x81827afeUL, 0x1322f1b1UL, 0x0835eca3UL, 0x510f7ecdUL, +0x7aa614ffUL, 0x7293f85cUL, 0xc297122fUL, 0x70e3c3f3UL, +0x2f491c99UL, 0x431568d1UL, 0xa3261bc2UL, 0xcc32b388UL, +0xcf7a6f8aUL, 0xe8069fb0UL, 0x47f51e7aUL, 0xbb79dad2UL, +0x950821e6UL, 0x98e55c43UL, 0xb83106d0UL, 0xe37baf11UL, +0x4165537eUL, 0xaa2b10ccUL, 0xb4e49cd8UL, 0x56a7d464UL, +0x7c3659fbUL, 0x4b208472UL, 0x9f4df6eaUL, 0x5faadf6aUL, +0xc1dfce2dUL, 0x48685870UL, 0xaff381caUL, 0x05d89106UL, +0x774b695aUL, 0xde28a594UL, 0xdf104239UL, 0x3bc34781UL, +0x82caa6fcUL, 0xc8d2c523UL, 0xf86cb203UL, 0x0cd59a08UL, +0xb7ac40daUL, 0xb909e17dUL, 0x24342c38UL, 0x5247a2cfUL, +0xb274d1dcUL, 0xa85b2b63UL, 0xd5559535UL, 0x9e751147UL, +0xe5ebe215UL, 0x9430c64bUL, 0x6f14a84aUL, 0x239c8691UL, +0x6acc394cUL, 0x8aff4a5fUL, 0x06904d04UL, 0x99ddbbeeUL, +0x1152ca1eUL, 0xffc418aaUL, 0x646998ebUL, 0xfefcff07UL, +0x345e018bUL, 0x7d0ebe56UL, 0xe79bd9baUL, 0x63c13242UL, +0xb5dc7b75UL, 0x26441797UL, 0xaecb6667UL, 0x250ccb95UL, +0x9a9567ecUL, 0x862ad057UL, 0x50379960UL, 0xe4d305b8UL, +0xad83ba65UL, 0xefae3519UL, 0xf6c913a4UL, 0x5b4aa9c1UL, +0x3e1bd687UL, 0xf0595ea0UL, 0x148a5b18UL, 0x02703bafUL, +0x04e076abUL, 0x4950bfddUL, 0x4a1863dfUL, 0xa5b656c6UL, +0x3d530a85UL, 0x871237faUL, 0xb694a777UL, 0x65517f46UL, +0x61b109edUL, 0xece6e91bUL, 0x458525d5UL, 0x753b52f5UL, +0xba413d7fUL, 0xce428827UL, 0xeb4e43b2UL, 0xbde997d6UL, +0x7b9ef352UL, 0x537f4562UL, 0x3afba02cUL, 0xbcd1707bUL, +0x1ff76bb9UL, 0x1b171d12UL, 0x79eec8fdUL, 0x277cf03aUL, +0x0a45d70cUL, 0xdd607996UL, 0x33f6ab22UL, 0xfa1c89acUL, +0xacbb5dc8UL, 0x0b7d30a1UL, 0xbea14bd4UL, 0xe10b94beUL, +0xcd0a5425UL, 0x7e466254UL, 0xf31182a2UL, 0xe6a33e17UL, +0x3566e626UL, 0x580275c3UL, 0x388b9b83UL, 0x44bdc278UL, +0x0348dc02UL, 0x92a08b4fUL, 0x39b37c2eUL, 0x6984e54eUL, +0x888f71f0UL, 0x2d392736UL, 0xd2fd3f9cUL, 0xfb246e01UL, +0x3716dd89UL, 0x00000000UL, 0x8d57e0f6UL, 0x93986ce2UL, +0x4ef81574UL, 0x20d45a93UL, 0x0138e7adUL, 0x405db4d3UL, +0x17c2871aUL, 0x106a2db3UL, 0x78d62f50UL, 0x8e1f3cf4UL, +0x0ea5a1a7UL, 0xb34c3671UL, 0xd725ae9aUL, 0x71db245eUL, +0x1d875016UL, 0x62f9d5efUL, 0x3186908dUL, 0x121a161cUL, +0xf581cfa6UL, 0x8c6f075bUL, 0xd61d4937UL, 0x593a926eUL, +0xc6776484UL, 0xc53fb886UL, 0x46cdf9d7UL, 0x90d0b0e0UL, +0xc74f8329UL, 0x9640fde4UL, 0x090d0b0eUL, 0xa156206dUL, +0xc9ea228eUL, 0x4c882edbUL, 0x76738ef7UL, 0x15b2bcb5UL, +0x185fc110UL, 0x2ba96a32UL, 0xa48eb16bUL, 0xf95455aeUL, +0x6089ee40UL, 0x55ef0866UL, 0x672144e9UL, 0x21ecbd3eUL, +0x30be7720UL, 0x8bc7adf2UL, 0xc0e72980UL, 0x1ecf8c14UL, +0xe24348bcUL, 0xa6fe8ac4UL, 0xd3c5d831UL, 0x16fa60b7UL, +0x80ba9d53UL, 0x4fc0f2d9UL, 0xe93e781dUL, 0x362e3a24UL, +0x6bf4dee1UL, 0x54d7efcbUL, 0xf7f1f409UL, 0xc3aff582UL, +0xf4b9280bUL, 0x29d9519dUL, 0x5e9238c7UL, 0x845aebf8UL, +0xd8b8e890UL, 0xb13c0ddeUL, 0xd08d0433UL, 0x5ce20368UL, +0x5ddae4c5UL, 0xdc589e3bUL, 0x0f9d460aUL, 0xdac8d33fUL, +0x8f27db59UL, 0xfc8cc4a8UL, 0xbf99ac79UL, 0x5a724e6cUL, +0xcaa2fe8cUL, 0xd1b5e39eUL, 0xea76a41fUL, 0xb004ea73UL, +}}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/sse_simd.cpp b/extension/third_party/cryptopp/sse_simd.cpp new file mode 100644 index 00000000..96c80a27 --- /dev/null +++ b/extension/third_party/cryptopp/sse_simd.cpp @@ -0,0 +1,115 @@ +// sse_simd.cpp - written and placed in the public domain by +// Jeffrey Walton, Uri Blumenthal and Marcel Raad. +// +// This source file uses intrinsics to gain access to SSE for CPU +// feature testing. A separate source file is needed because additional +// CXXFLAGS are required to enable the appropriate instructions set in +// some build configurations. + +#include "pch.h" +#include "config.h" +#include "cpu.h" + +// Needed by MIPS for definition of NULL +#include "stdcpp.h" + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +# include +# include +#endif + +#ifndef EXCEPTION_EXECUTE_HANDLER +# define EXCEPTION_EXECUTE_HANDLER 1 +#endif + +// Needed by SunCC and MSVC +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# if !defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) && !CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_SSE2_INTRIN_AVAILABLE +# include +# endif +#endif + +// Squash MS LNK4221 and libtool warnings +extern const char SSE_SIMD_FNAME[] = __FILE__; + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY +extern "C" { + typedef void (*SigHandler)(int); +} + +extern "C" +{ + static jmp_buf s_jmpNoSSE2; + static void SigIllHandler(int) + { + longjmp(s_jmpNoSSE2, 1); + } +} +#endif // CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY + +bool CPU_ProbeSSE2() +{ + // Apple switched to Intel desktops in 2005/2006 using + // Core2 Duo's, which provides SSE2 and above. +#if CRYPTOPP_BOOL_X64 || defined(__APPLE__) + return true; +#elif defined(CRYPTOPP_NO_CPU_FEATURE_PROBES) + return false; +#elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) + __try + { +# if CRYPTOPP_SSE2_ASM_AVAILABLE + AS2(por xmm0, xmm0) // executing SSE2 instruction +# elif CRYPTOPP_SSE2_INTRIN_AVAILABLE + __m128i x = _mm_setzero_si128(); + return _mm_cvtsi128_si32(x) == 0; +# endif + } + // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + return true; +#else + // longjmp and clobber warnings. Volatile is required. + // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854 + volatile bool result = true; + + volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + +# ifndef __MINGW32__ + volatile sigset_t oldMask; + if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask)) + { + signal(SIGILL, oldHandler); + return false; + } +# endif + + if (setjmp(s_jmpNoSSE2)) + result = false; + else + { +# if CRYPTOPP_SSE2_ASM_AVAILABLE + __asm __volatile ("por %xmm0, %xmm0"); +# elif CRYPTOPP_SSE2_INTRIN_AVAILABLE + __m128i x = _mm_setzero_si128(); + result = _mm_cvtsi128_si32(x) == 0; +# endif + } + +# ifndef __MINGW32__ + sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR); +# endif + + signal(SIGILL, oldHandler); + return result; +#endif +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/stdcpp.h b/extension/third_party/cryptopp/stdcpp.h new file mode 100644 index 00000000..8bda2904 --- /dev/null +++ b/extension/third_party/cryptopp/stdcpp.h @@ -0,0 +1,101 @@ +// stdcpp.h - originally written and placed in the public domain by Wei Dai + +/// \file stdcpp.h +/// \brief Common C++ header files + +#ifndef CRYPTOPP_STDCPP_H +#define CRYPTOPP_STDCPP_H + +#if _MSC_VER >= 1500 +#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// http://connect.microsoft.com/VisualStudio/feedback/details/1600701/type-info-does-not-compile-with-has-exceptions-0 +#if defined(_MSC_VER) && (_MSC_VER < 1900) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 0) +namespace std { + using ::type_info; +} +#endif + +// workaround needed for IBM XLC and debug heaps on AIX +#if defined(_AIX) && (defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__)) +# if defined(__DEBUG_ALLOC__) +namespace std { + using ::_debug_memset; + using ::_debug_memcpy; +} +# endif +#endif + +// make_unchecked_array_iterator +#if _MSC_VER >= 1600 +#include +#endif + +#if defined(CRYPTOPP_CXX11_ATOMIC) +#include +#endif + +#if defined(CRYPTOPP_CXX11_SYNCHRONIZATION) +#include +#endif + +#if defined(CRYPTOPP_CXX11_RVALUES) +# include +#endif + +#include +#include +#include +#include + +// It is 2019 and VS2017/Win10 still can't compile a +// program that includes without making users +// do something special. "Epic fail" comes to mind. +// Also see https://github.com/weidai11/cryptopp/issues/781 +#ifndef _MSC_VER +# include +#endif + +// uintptr_t and ptrdiff_t +#if defined(__SUNPRO_CC) +# if (__SUNPRO_CC >= 0x5100) +# include +# endif +#elif defined(_MSC_VER) +# if (_MSC_VER >= 1700) +# include +# else +# include +# endif +#elif (__cplusplus < 201103L) +# include +#endif + +// workaround needed on Sun Studio 12u1 Sun C++ 5.10 SunOS_i386 128229-02 2009/09/21 +#ifdef CRYPTOPP_INCLUDE_VECTOR_CC +# include +#endif + +// C++Builder's standard library (Dinkumware) do not have C's global log() function +// https://github.com/weidai11/cryptopp/issues/520 +#ifdef __BORLANDC__ +using std::log; +#endif + +#endif // CRYPTOPP_STDCPP_H diff --git a/extension/third_party/cryptopp/strciphr.cpp b/extension/third_party/cryptopp/strciphr.cpp new file mode 100644 index 00000000..e5ca04fd --- /dev/null +++ b/extension/third_party/cryptopp/strciphr.cpp @@ -0,0 +1,286 @@ +// strciphr.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "strciphr.h" + +// Squash MS LNK4221 and libtool warnings +#ifndef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +extern const char STRCIPHER_FNAME[] = __FILE__; +#endif + +NAMESPACE_BEGIN(CryptoPP) + +template +void AdditiveCipherTemplate::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + PolicyInterface &policy = this->AccessPolicy(); + policy.CipherSetKey(params, key, length); + m_leftOver = 0; + unsigned int bufferByteSize = policy.CanOperateKeystream() ? GetBufferByteSize(policy) : RoundUpToMultipleOf(1024U, GetBufferByteSize(policy)); + m_buffer.New(bufferByteSize); + + if (this->IsResynchronizable()) + { + size_t ivLength; + const byte *iv = this->GetIVAndThrowIfInvalid(params, ivLength); + policy.CipherResynchronize(m_buffer, iv, ivLength); + } +} + +template +void AdditiveCipherTemplate::GenerateBlock(byte *outString, size_t length) +{ + if (m_leftOver > 0) + { + const size_t len = STDMIN(m_leftOver, length); + std::memcpy(outString, PtrSub(KeystreamBufferEnd(), m_leftOver), len); + + length -= len; m_leftOver -= len; + outString = PtrAdd(outString, len); + if (!length) {return;} + } + + PolicyInterface &policy = this->AccessPolicy(); + unsigned int bytesPerIteration = policy.GetBytesPerIteration(); + + if (length >= bytesPerIteration) + { + const size_t iterations = length / bytesPerIteration; + policy.WriteKeystream(outString, iterations); + length -= iterations * bytesPerIteration; + outString = PtrAdd(outString, iterations * bytesPerIteration); + } + + if (length > 0) + { + size_t bufferByteSize = RoundUpToMultipleOf(length, bytesPerIteration); + size_t bufferIterations = bufferByteSize / bytesPerIteration; + + policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bufferByteSize), bufferIterations); + std::memcpy(outString, PtrSub(KeystreamBufferEnd(), bufferByteSize), length); + m_leftOver = bufferByteSize - length; + } +} + +template +void AdditiveCipherTemplate::ProcessData(byte *outString, const byte *inString, size_t length) +{ + if (m_leftOver > 0) + { + const size_t len = STDMIN(m_leftOver, length); + xorbuf(outString, inString, PtrSub(KeystreamBufferEnd(), m_leftOver), len); + + length -= len; m_leftOver -= len; + inString = PtrAdd(inString, len); + outString = PtrAdd(outString, len); + + if (!length) {return;} + } + + PolicyInterface &policy = this->AccessPolicy(); + unsigned int bytesPerIteration = policy.GetBytesPerIteration(); + + if (policy.CanOperateKeystream() && length >= bytesPerIteration) + { + const size_t iterations = length / bytesPerIteration; + unsigned int alignment = policy.GetAlignment(); + volatile int inAligned = IsAlignedOn(inString, alignment) << 1; + volatile int outAligned = IsAlignedOn(outString, alignment) << 0; + + KeystreamOperation operation = KeystreamOperation(inAligned | outAligned); + policy.OperateKeystream(operation, outString, inString, iterations); + + inString = PtrAdd(inString, iterations * bytesPerIteration); + outString = PtrAdd(outString, iterations * bytesPerIteration); + length -= iterations * bytesPerIteration; + + if (!length) {return;} + } + + size_t bufferByteSize = m_buffer.size(); + size_t bufferIterations = bufferByteSize / bytesPerIteration; + + while (length >= bufferByteSize) + { + policy.WriteKeystream(m_buffer, bufferIterations); + xorbuf(outString, inString, KeystreamBufferBegin(), bufferByteSize); + + length -= bufferByteSize; + inString = PtrAdd(inString, bufferByteSize); + outString = PtrAdd(outString, bufferByteSize); + } + + if (length > 0) + { + bufferByteSize = RoundUpToMultipleOf(length, bytesPerIteration); + bufferIterations = bufferByteSize / bytesPerIteration; + + policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bufferByteSize), bufferIterations); + xorbuf(outString, inString, PtrSub(KeystreamBufferEnd(), bufferByteSize), length); + m_leftOver = bufferByteSize - length; + } +} + +template +void AdditiveCipherTemplate::Resynchronize(const byte *iv, int length) +{ + PolicyInterface &policy = this->AccessPolicy(); + m_leftOver = 0; + m_buffer.New(GetBufferByteSize(policy)); + policy.CipherResynchronize(m_buffer, iv, this->ThrowIfInvalidIVLength(length)); +} + +template +void AdditiveCipherTemplate::Seek(lword position) +{ + PolicyInterface &policy = this->AccessPolicy(); + word32 bytesPerIteration = policy.GetBytesPerIteration(); + + policy.SeekToIteration(position / bytesPerIteration); + position %= bytesPerIteration; + + if (position > 0) + { + policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bytesPerIteration), 1); + m_leftOver = bytesPerIteration - static_cast(position); + } + else + m_leftOver = 0; +} + +template +void CFB_CipherTemplate::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + PolicyInterface &policy = this->AccessPolicy(); + policy.CipherSetKey(params, key, length); + + if (this->IsResynchronizable()) + { + size_t ivLength; + const byte *iv = this->GetIVAndThrowIfInvalid(params, ivLength); + policy.CipherResynchronize(iv, ivLength); + } + + m_leftOver = policy.GetBytesPerIteration(); +} + +template +void CFB_CipherTemplate::Resynchronize(const byte *iv, int length) +{ + PolicyInterface &policy = this->AccessPolicy(); + policy.CipherResynchronize(iv, this->ThrowIfInvalidIVLength(length)); + m_leftOver = policy.GetBytesPerIteration(); +} + +template +void CFB_CipherTemplate::ProcessData(byte *outString, const byte *inString, size_t length) +{ + CRYPTOPP_ASSERT(outString); CRYPTOPP_ASSERT(inString); + CRYPTOPP_ASSERT(length % this->MandatoryBlockSize() == 0); + + PolicyInterface &policy = this->AccessPolicy(); + word32 bytesPerIteration = policy.GetBytesPerIteration(); + byte *reg = policy.GetRegisterBegin(); + + if (m_leftOver) + { + const size_t len = STDMIN(m_leftOver, length); + CombineMessageAndShiftRegister(outString, PtrAdd(reg, bytesPerIteration - m_leftOver), inString, len); + + m_leftOver -= len; length -= len; + inString = PtrAdd(inString, len); + outString = PtrAdd(outString, len); + } + + if (!length) {return;} + + // TODO: Figure out what is happening on ARM A-32. x86, Aarch64 and PowerPC are OK. + // The issue surfaced for CFB mode when we cut-in Cryptogams AES ARMv7 asm. + // Using 'outString' for both input and output leads to incorrect results. + // + // Benchmarking on Cortex-A7 and Cortex-A9 indicates removing the block + // below costs about 9 cpb for CFB mode on ARM. + // + // Also see https://github.com/weidai11/cryptopp/issues/683. + + const unsigned int alignment = policy.GetAlignment(); + volatile bool inAligned = IsAlignedOn(inString, alignment); + volatile bool outAligned = IsAlignedOn(outString, alignment); + + if (policy.CanIterate() && length >= bytesPerIteration && outAligned) + { + CipherDir cipherDir = GetCipherDir(*this); + if (inAligned) + policy.Iterate(outString, inString, cipherDir, length / bytesPerIteration); + else + { + // GCC and Clang do not like this on ARM. The incorrect result is a string + // of 0's instead of ciphertext (or plaintext if decrypting). The 0's trace + // back to the allocation for the std::string in datatest.cpp. Elements in the + // string are initialized to their default value, which is 0. + // + // It almost feels as if the compiler does not see the string is transformed + // in-place so it short-circuits the transform. However, if we use a stand-alone + // reproducer with the same data then the issue is _not_ present. + // + // When working on this issue we introduced PtrAdd and PtrSub to ensure we were + // not running afoul of pointer arithmetic rules of the language. Namely we need + // to use ptrdiff_t when subtracting pointers. We believe the relevant code paths + // are clean. + // + // One workaround is a distinct and aligned temporary buffer. It [mostly] works + // as expected but requires an extra allocation (casts not shown): + // + // std::string temp(inString, length); + // policy.Iterate(outString, &temp[0], cipherDir, length / bytesPerIteration); + + std::memcpy(outString, inString, length); + policy.Iterate(outString, outString, cipherDir, length / bytesPerIteration); + } + const size_t remainder = length % bytesPerIteration; + inString = PtrAdd(inString, length - remainder); + outString = PtrAdd(outString, length - remainder); + length = remainder; + } + + while (length >= bytesPerIteration) + { + policy.TransformRegister(); + CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration); + length -= bytesPerIteration; + inString = PtrAdd(inString, bytesPerIteration); + outString = PtrAdd(outString, bytesPerIteration); + } + + if (length > 0) + { + policy.TransformRegister(); + CombineMessageAndShiftRegister(outString, reg, inString, length); + m_leftOver = bytesPerIteration - length; + } +} + +template +void CFB_EncryptionTemplate::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) +{ + xorbuf(reg, message, length); + std::memcpy(output, reg, length); +} + +template +void CFB_DecryptionTemplate::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) +{ + for (size_t i=0; i +/// typedef SymmetricCipherFinal\, AdditiveCipherTemplate\<\> \> \> Encryption; +/// +/// \details AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't +/// need to take a policy class as a template parameter (although this is allowed), so +/// that their code is not duplicated for each new cipher. Instead they each get a +/// reference to an abstract policy interface by calling AccessPolicy() on itself, so +/// AccessPolicy() must be overridden to return the actual policy reference. This is done +/// by the ConceretePolicyHolder class. Finally, SymmetricCipherFinal implements the +/// constructors and other functions that must be implemented by the most derived class. + +#ifndef CRYPTOPP_STRCIPHR_H +#define CRYPTOPP_STRCIPHR_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275) +#endif + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Access a stream cipher policy object +/// \tparam POLICY_INTERFACE class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class CRYPTOPP_NO_VTABLE AbstractPolicyHolder : public BASE +{ +public: + typedef POLICY_INTERFACE PolicyInterface; + virtual ~AbstractPolicyHolder() {} + +protected: + virtual const POLICY_INTERFACE & GetPolicy() const =0; + virtual POLICY_INTERFACE & AccessPolicy() =0; +}; + +/// \brief Stream cipher policy object +/// \tparam POLICY class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class ConcretePolicyHolder : public BASE, protected POLICY +{ +public: + virtual ~ConcretePolicyHolder() {} +protected: + const POLICY_INTERFACE & GetPolicy() const {return *this;} + POLICY_INTERFACE & AccessPolicy() {return *this;} +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperationFlags { + /// \brief Output buffer is aligned + OUTPUT_ALIGNED=1, + /// \brief Input buffer is aligned + INPUT_ALIGNED=2, + /// \brief Input buffer is NULL + INPUT_NULL = 4 +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperation { + /// \brief Wirte the keystream to the output buffer, input is NULL + WRITE_KEYSTREAM = INPUT_NULL, + /// \brief Wirte the keystream to the aligned output buffer, input is NULL + WRITE_KEYSTREAM_ALIGNED = INPUT_NULL | OUTPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the output buffer + XOR_KEYSTREAM = 0, + /// \brief XOR the aligned input buffer and keystream, write to the output buffer + XOR_KEYSTREAM_INPUT_ALIGNED = INPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_OUTPUT_ALIGNED= OUTPUT_ALIGNED, + /// \brief XOR the aligned input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_BOTH_ALIGNED = OUTPUT_ALIGNED | INPUT_ALIGNED +}; + +/// \brief Policy object for additive stream ciphers +struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy +{ + virtual ~AdditiveCipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const {return 1;} + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() + virtual unsigned int GetOptimalBlockSize() const {return GetBytesPerIteration();} + + /// \brief Provides buffer size based on iterations + /// \return the buffer size based on iterations, in bytes + virtual unsigned int GetIterationsToBuffer() const =0; + + /// \brief Generate the keystream + /// \param keystream the key stream + /// \param iterationCount the number of iterations to generate the key stream + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual void WriteKeystream(byte *keystream, size_t iterationCount) + {OperateKeystream(KeystreamOperation(INPUT_NULL | static_cast(IsAlignedOn(keystream, GetAlignment()))), keystream, NULLPTR, iterationCount);} + + /// \brief Flag indicating + /// \return true if the stream can be generated independent of the transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual bool CanOperateKeystream() const {return false;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) + {CRYPTOPP_UNUSED(operation); CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); + CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false);} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param keystreamBuffer the keystream buffer + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) + {CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); + throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa SeekToIteration() + virtual bool CipherIsRandomAccess() const =0; + + /// \brief Seeks to a random position in the stream + /// \sa CipherIsRandomAccess() + virtual void SeekToIteration(lword iterationCount) + {CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(!CipherIsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access");} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } +}; + +/// \brief Base class for additive stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam X bytes per iteration count +/// \tparam BASE AdditiveCipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE AdditiveCipherConcretePolicy : public BASE +{ + /// \brief Word type for the cipher + typedef WT WordType; + + /// \brief Number of bytes for an iteration + /// \details BYTES_PER_ITERATION is the product sizeof(WordType) * W. + /// For example, ChaCha uses 16 each word32, and the value of + /// BYTES_PER_ITERATION is 64. Each invocation of the ChaCha block function + /// produces 64 bytes of keystream. + CRYPTOPP_CONSTANT(BYTES_PER_ITERATION = sizeof(WordType) * W); + + virtual ~AdditiveCipherConcretePolicy() {} + +#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X64) + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream + /// cipher is implemented using an SSE2 ASM or intrinsics, then the value + /// returned is usually 16. + unsigned int GetAlignment() const {return GetAlignmentOf();} +#endif + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return BYTES_PER_ITERATION;} + + /// \brief Provides buffer size based on iterations + /// \return the buffer size based on iterations, in bytes + unsigned int GetIterationsToBuffer() const {return X;} + + /// \brief Flag indicating + /// \return true if the stream can be generated independent of the + /// transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + bool CanOperateKeystream() const {return true;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) =0; +}; + +/// \brief Helper macro to implement OperateKeystream +/// \param x KeystreamOperation mask +/// \param b Endian order +/// \param i index in output buffer +/// \param a value to output +#define CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, b, i, a) \ + PutWord(bool(x & OUTPUT_ALIGNED), b, output+i*sizeof(WordType), (x & INPUT_NULL) ? (a) : (a) ^ GetWord(bool(x & INPUT_ALIGNED), b, input+i*sizeof(WordType))); + +/// \brief Helper macro to implement OperateKeystream +/// \param x KeystreamOperation mask +/// \param i index in output buffer +/// \param a value to output +#define CRYPTOPP_KEYSTREAM_OUTPUT_XMM(x, i, a) {\ + __m128i t = (x & INPUT_NULL) ? a : _mm_xor_si128(a, (x & INPUT_ALIGNED) ? _mm_load_si128((__m128i *)input+i) : _mm_loadu_si128((__m128i *)input+i));\ + if (x & OUTPUT_ALIGNED) _mm_store_si128((__m128i *)output+i, t);\ + else _mm_storeu_si128((__m128i *)output+i, t);} + +/// \brief Helper macro to implement OperateKeystream +#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y) \ + switch (operation) \ + { \ + case WRITE_KEYSTREAM: \ + x(WRITE_KEYSTREAM) \ + break; \ + case XOR_KEYSTREAM: \ + x(XOR_KEYSTREAM) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_INPUT_ALIGNED: \ + x(XOR_KEYSTREAM_INPUT_ALIGNED) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_OUTPUT_ALIGNED: \ + x(XOR_KEYSTREAM_OUTPUT_ALIGNED) \ + input += y; \ + break; \ + case WRITE_KEYSTREAM_ALIGNED: \ + x(WRITE_KEYSTREAM_ALIGNED) \ + break; \ + case XOR_KEYSTREAM_BOTH_ALIGNED: \ + x(XOR_KEYSTREAM_BOTH_ALIGNED) \ + input += y; \ + break; \ + } \ + output += y; + +/// \brief Base class for additive stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE, public RandomNumberGenerator +{ +public: + virtual ~AdditiveCipherTemplate() {} + AdditiveCipherTemplate() : m_leftOver(0) {} + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified + /// within the constraints of a particular generator. + void GenerateBlock(byte *output, size_t size); + + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size fo the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();} + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \return the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Determines if the cipher is self inverting + /// \return true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return true;} + + /// \brief Determines if the cipher is a forward transformation + /// \return true if the stream cipher is a forward transformation, false otherwise + bool IsForwardTransformation() const {return true;} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return this->GetPolicy().CipherIsRandomAccess();} + + /// \brief Seeks to a random position in the stream + /// \param position the absolute position in the stream + /// \sa IsRandomAccess() + void Seek(lword position); + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + std::string AlgorithmProvider() const { return this->GetPolicy().AlgorithmProvider(); } + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();} + + inline byte * KeystreamBufferBegin() {return this->m_buffer.data();} + inline byte * KeystreamBufferEnd() {return (PtrAdd(this->m_buffer.data(), this->m_buffer.size()));} + + AlignedSecByteBlock m_buffer; + size_t m_leftOver; +}; + +/// \brief Policy object for feeback based stream ciphers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_CipherAbstractPolicy +{ +public: + virtual ~CFB_CipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const =0; + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Access the feedback register + /// \return pointer to the first byte of the feedback register + virtual byte * GetRegisterBegin() =0; + + /// \brief TODO + virtual void TransformRegister() =0; + + /// \brief Flag indicating iteration support + /// \return true if the cipher supports iteration, false otherwise + virtual bool CanIterate() const {return false;} + + /// \brief Iterate the cipher + /// \param output the output buffer + /// \param input the input buffer + /// \param dir the direction of the cipher + /// \param iterationCount the number of iterations to perform on the input + /// \sa IsSelfInverting() and IsForwardTransformation() + virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) + {CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(dir); + CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false); + throw Exception(Exception::OTHER_ERROR, "SimpleKeyingInterface: unexpected error");} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(const byte *iv, size_t length) + {CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); + throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } +}; + +/// \brief Base class for feedback based stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam BASE CFB_CipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE CFB_CipherConcretePolicy : public BASE +{ + typedef WT WordType; + + virtual ~CFB_CipherConcretePolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + unsigned int GetAlignment() const {return sizeof(WordType);} + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} + + /// \brief Flag indicating iteration support + /// \return true if the cipher supports iteration, false otherwise + bool CanIterate() const {return true;} + + /// \brief Perform one iteration in the forward direction + void TransformRegister() {this->Iterate(NULLPTR, NULLPTR, ENCRYPTION, 1);} + + /// \brief Provides alternate access to a feedback register + /// \tparam B enumeration indicating endianness + /// \details RegisterOutput() provides alternate access to the feedback register. The + /// enumeration B is BigEndian or LittleEndian. Repeatedly applying operator() + /// results in advancing in the register. + template + struct RegisterOutput + { + RegisterOutput(byte *output, const byte *input, CipherDir dir) + : m_output(output), m_input(input), m_dir(dir) {} + + /// \brief XOR feedback register with data + /// \param registerWord data represented as a word type + /// \return reference to the next feedback register word + inline RegisterOutput& operator()(WordType ®isterWord) + { + //CRYPTOPP_ASSERT(IsAligned(m_output)); + //CRYPTOPP_ASSERT(IsAligned(m_input)); + + if (!NativeByteOrderIs(B::ToEnum())) + registerWord = ByteReverse(registerWord); + + if (m_dir == ENCRYPTION) + { + if (m_input == NULLPTR) + { + CRYPTOPP_ASSERT(m_output == NULLPTR); + } + else + { + // WordType ct = *(const WordType *)m_input ^ registerWord; + WordType ct = GetWord(false, NativeByteOrder::ToEnum(), m_input) ^ registerWord; + registerWord = ct; + + // *(WordType*)m_output = ct; + PutWord(false, NativeByteOrder::ToEnum(), m_output, ct); + + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + } + else + { + // WordType ct = *(const WordType *)m_input; + WordType ct = GetWord(false, NativeByteOrder::ToEnum(), m_input); + + // *(WordType*)m_output = registerWord ^ ct; + PutWord(false, NativeByteOrder::ToEnum(), m_output, registerWord ^ ct); + registerWord = ct; + + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + + // registerWord is left unreversed so it can be xor-ed with further input + + return *this; + } + + byte *m_output; + const byte *m_input; + CipherDir m_dir; + }; +}; + +/// \brief Base class for feedback based stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template +class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE +{ +public: + virtual ~CFB_CipherTemplate() {} + CFB_CipherTemplate() : m_leftOver(0) {} + + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size fo the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();} + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \return the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return false;} + + /// \brief Determines if the cipher is self inverting + /// \return true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return false;} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + std::string AlgorithmProvider() const { return this->GetPolicy().AlgorithmProvider(); } + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) =0; + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + size_t m_leftOver; +}; + +/// \brief Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_EncryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return true;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_DecryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return false;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers with a mandatory block size +/// \tparam BASE CFB_EncryptionTemplate or CFB_DecryptionTemplate base class +template +class CFB_RequireFullDataBlocks : public BASE +{ +public: + unsigned int MandatoryBlockSize() const {return this->OptimalBlockSize();} +}; + +/// \brief SymmetricCipher implementation +/// \tparam BASE AbstractPolicyHolder derived base class +/// \tparam INFO AbstractPolicyHolder derived information class +/// \sa Weak::ARC4, ChaCha8, ChaCha12, ChaCha20, Salsa20, SEAL, Sosemanuk, WAKE +template +class SymmetricCipherFinal : public AlgorithmImpl, INFO> +{ +public: + virtual ~SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \details This overload uses DEFAULT_KEYLENGTH + SymmetricCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + SymmetricCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + /// \param iv a byte array used as an initialization vector + SymmetricCipherFinal(const byte *key, size_t length, const byte *iv) + {this->SetKeyWithIV(key, length, iv);} + + /// \brief Clone a SymmetricCipher + /// \return a new SymmetricCipher based on this object + Clonable * Clone() const {return static_cast(new SymmetricCipherFinal(*this));} +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "strciphr.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractPolicyHolder; +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/extension/third_party/cryptopp/tea.cpp b/extension/third_party/cryptopp/tea.cpp new file mode 100644 index 00000000..32708c93 --- /dev/null +++ b/extension/third_party/cryptopp/tea.cpp @@ -0,0 +1,165 @@ +// tea.cpp - modified by Wei Dai from code in the original paper + +#include "pch.h" +#include "tea.h" +#include "misc.h" + +// http://github.com/weidai11/cryptopp/issues/503 +#if defined(__xlC__) || defined(__SUNPRO_CC) +# define MAYBE_VOLATILE(x) (*const_cast(&x)) +#else +# define MAYBE_VOLATILE(x) (x) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +static const word32 DELTA = 0x9e3779b9; +typedef BlockGetAndPut Block; + +#define UINT32_CAST(x) ((word32*)(void*)(x)) +#define CONST_UINT32_CAST(x) ((const word32*)(const void*)(x)) + +void TEA::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(length); + + GetUserKey(BIG_ENDIAN_ORDER, m_k.begin(), 4, userKey, KEYLENGTH); + m_limit = GetRoundsAndThrowIfInvalid(params, this) * DELTA; +} + +void TEA::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z, sum = 0; + Block::Get(inBlock)(y)(z); + + // http://github.com/weidai11/cryptopp/issues/503 + while (MAYBE_VOLATILE(sum) != m_limit) + { + sum += DELTA; + y += ((z << 4) + m_k[0]) ^ (z + sum) ^ ((z >> 5) + m_k[1]); + z += ((y << 4) + m_k[2]) ^ (y + sum) ^ ((y >> 5) + m_k[3]); + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +void TEA::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z, sum = m_limit; + Block::Get(inBlock)(y)(z); + + // http://github.com/weidai11/cryptopp/issues/503 + while (MAYBE_VOLATILE(sum) != 0) + { + z -= ((y << 4) + m_k[2]) ^ (y + sum) ^ ((y >> 5) + m_k[3]); + y -= ((z << 4) + m_k[0]) ^ (z + sum) ^ ((z >> 5) + m_k[1]); + sum -= DELTA; + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +void XTEA::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) +{ + AssertValidKeyLength(length); + + GetUserKey(BIG_ENDIAN_ORDER, m_k.begin(), 4, userKey, KEYLENGTH); + m_limit = GetRoundsAndThrowIfInvalid(params, this) * DELTA; +} + +void XTEA::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z, sum = 0; + Block::Get(inBlock)(y)(z); + + // http://github.com/weidai11/cryptopp/issues/503 + while (MAYBE_VOLATILE(sum) != m_limit) + { + y += ((z<<4 ^ z>>5) + z) ^ (sum + m_k[sum&3]); + sum += DELTA; + z += ((y<<4 ^ y>>5) + y) ^ (sum + m_k[sum>>11 & 3]); + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +void XTEA::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 y, z, sum = m_limit; + Block::Get(inBlock)(y)(z); + + // http://github.com/weidai11/cryptopp/issues/503 + while (MAYBE_VOLATILE(sum) != 0) + { + z -= ((y<<4 ^ y>>5) + y) ^ (sum + m_k[sum>>11 & 3]); + sum -= DELTA; + y -= ((z<<4 ^ z>>5) + z) ^ (sum + m_k[sum&3]); + } + + Block::Put(xorBlock, outBlock)(y)(z); +} + +#define MX ((z>>5^y<<2)+(y>>3^z<<4))^((sum^y)+(m_k[(p&3)^e]^z)) + +void BTEA::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + CRYPTOPP_UNUSED(xorBlock); + CRYPTOPP_ASSERT(IsAlignedOn(inBlock,GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(outBlock,GetAlignmentOf())); + + unsigned int n = m_blockSize / 4; + word32 *v = UINT32_CAST(outBlock); + ConditionalByteReverse(BIG_ENDIAN_ORDER, v, CONST_UINT32_CAST(inBlock), m_blockSize); + + word32 y, z = v[n-1], e; + word32 p, q = 6+52/n; + word32 sum = 0; + + while (q-- > 0) + { + sum += DELTA; + e = sum>>2 & 3; + for (p = 0; p < n-1; p++) + { + y = v[p+1]; + z = v[p] += MX; + } + y = v[0]; + z = v[n-1] += MX; + } + + ConditionalByteReverse(BIG_ENDIAN_ORDER, v, v, m_blockSize); +} + +void BTEA::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + CRYPTOPP_UNUSED(xorBlock); + CRYPTOPP_ASSERT(IsAlignedOn(inBlock,GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(outBlock,GetAlignmentOf())); + + unsigned int n = m_blockSize / 4; + word32 *v = UINT32_CAST(outBlock); + ConditionalByteReverse(BIG_ENDIAN_ORDER, v, CONST_UINT32_CAST(inBlock), m_blockSize); + + word32 y = v[0], z, e; + word32 p, q = 6+52/n; + word32 sum = q * DELTA; + + while (sum != 0) + { + e = sum>>2 & 3; + for (p = n-1; p > 0; p--) + { + z = v[p-1]; + y = v[p] -= MX; + } + + z = v[n-1]; + y = v[0] -= MX; + sum -= DELTA; + } + + ConditionalByteReverse(BIG_ENDIAN_ORDER, v, v, m_blockSize); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/tea.h b/extension/third_party/cryptopp/tea.h new file mode 100644 index 00000000..ef671dac --- /dev/null +++ b/extension/third_party/cryptopp/tea.h @@ -0,0 +1,161 @@ +// tea.h - originally written and placed in the public domain by Wei Dai + +/// \file tea.h +/// \brief Classes for the TEA, BTEA and XTEA block ciphers + +#ifndef CRYPTOPP_TEA_H +#define CRYPTOPP_TEA_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TEA block cipher information +struct TEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "TEA";} +}; + +/// \brief TEA block cipher +/// \sa TEA +class TEA : public TEA_Info, public BlockCipherDocumentation +{ + /// \brief TEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief TEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief TEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef TEA::Encryption TEAEncryption; +typedef TEA::Decryption TEADecryption; + +/// \brief XTEA block cipher information +struct XTEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "XTEA";} +}; + +/// \brief XTEA block cipher +/// \sa XTEA +class XTEA : public XTEA_Info, public BlockCipherDocumentation +{ + /// \brief XTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief XTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief XTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief BTEA block cipher information +struct BTEA_Info : public FixedKeyLength<16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BTEA";} +}; + +/// \brief BTEA block cipher +/// \details Corrected Block TEA as described in "xxtea". This class hasn't been tested yet. +/// \sa Correction to xtea and +/// Corrected Block TEA. +class BTEA : public BTEA_Info, public BlockCipherDocumentation +{ + /// \brief BTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public AlgorithmImpl, BTEA_Info> + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); + m_blockSize = params.GetIntValueWithDefault("BlockSize", 60*4); + GetUserKey(BIG_ENDIAN_ORDER, m_k.begin(), 4, key, KEYLENGTH); + } + + unsigned int BlockSize() const {return m_blockSize;} + + protected: + FixedSizeSecBlock m_k; + unsigned int m_blockSize; + }; + + /// \brief BTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief BTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/test.cpp b/extension/third_party/cryptopp/test.cpp new file mode 100644 index 00000000..5cac99ca --- /dev/null +++ b/extension/third_party/cryptopp/test.cpp @@ -0,0 +1,1093 @@ +// test.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 +// scoped_main added to CryptoPP::Test namespace by JW in July 2017 +// Also see http://github.com/weidai11/cryptopp/issues/447 + +#define CRYPTOPP_DEFAULT_NO_DLL +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "dll.h" +#include "cryptlib.h" +#include "aes.h" +#include "filters.h" +#include "md5.h" +#include "ripemd.h" +#include "rng.h" +#include "gzip.h" +#include "default.h" +#include "randpool.h" +#include "ida.h" +#include "base64.h" +#include "factory.h" +#include "whrlpool.h" +#include "tiger.h" +#include "smartptr.h" +#include "pkcspad.h" +#include "stdcpp.h" +#include "osrng.h" +#include "ossig.h" +#include "trap.h" + +#include "validate.h" +#include "bench.h" + +#include +#include +#include +#include +#include + +#ifdef CRYPTOPP_WIN32_AVAILABLE +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_BSD_AVAILABLE) +#include +#include +#include +#define UNIX_PATH_FAMILY 1 +#endif + +#if defined(CRYPTOPP_OSX_AVAILABLE) +#include +#include +#include +#include +#define UNIX_PATH_FAMILY 1 +#endif + +#if (_MSC_VER >= 1000) +#include // for the debug heap +#endif + +#if defined(__MWERKS__) && defined(macintosh) +#include +#endif + +#ifdef _OPENMP +# include +#endif + +#ifdef __BORLANDC__ +#pragma comment(lib, "cryptlib_bds.lib") +#endif + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +// If CRYPTOPP_USE_AES_GENERATOR is 1 then AES/OFB based is used. +// Otherwise the OS random number generator is used. +#define CRYPTOPP_USE_AES_GENERATOR 1 + +// Global namespace, provided by other source files +void FIPS140_SampleApplication(); +void RegisterFactories(CryptoPP::Test::TestClass suites); +int (*AdhocTest)(int argc, char *argv[]) = NULLPTR; + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +const int MAX_PHRASE_LENGTH = 250; +const int GLOBAL_SEED_LENGTH = 16; +std::string g_argvPathHint=""; + +void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed); +std::string RSAEncryptString(const char *pubFilename, const char *seed, const char *message); +std::string RSADecryptString(const char *privFilename, const char *ciphertext); +void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename); +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename); + +void DigestFile(const char *file); +void HmacFile(const char *hexKey, const char *file); + +void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile); + +std::string EncryptString(const char *plaintext, const char *passPhrase); +std::string DecryptString(const char *ciphertext, const char *passPhrase); + +void EncryptFile(const char *in, const char *out, const char *passPhrase); +void DecryptFile(const char *in, const char *out, const char *passPhrase); + +void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed); +void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames); + +void InformationDisperseFile(int threshold, int nShares, const char *filename); +void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames); + +void GzipFile(const char *in, const char *out, int deflate_level); +void GunzipFile(const char *in, const char *out); + +void Base64Encode(const char *infile, const char *outfile); +void Base64Decode(const char *infile, const char *outfile); +void HexEncode(const char *infile, const char *outfile); +void HexDecode(const char *infile, const char *outfile); + +void FIPS140_GenerateRandomFiles(); + +bool Validate(int, bool); +bool SetGlobalSeed(int argc, char* argv[], std::string& seed); +void SetArgvPathHint(const char* argv0, std::string& pathHint); + +ANONYMOUS_NAMESPACE_BEGIN +#if (CRYPTOPP_USE_AES_GENERATOR) +OFB_Mode::Encryption s_globalRNG; +#else +NonblockingRng s_globalRNG; +#endif +NAMESPACE_END + +RandomNumberGenerator & GlobalRNG() +{ + return dynamic_cast(s_globalRNG); +} + +// Global seed used for the self tests +std::string s_globalSeed; +void PrintSeedAndThreads(); + +// See misc.h and trap.h for comments and usage +#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE) +static const SignalHandler s_dummyHandler; +// static const DebugTrapHandler s_dummyHandler; +#endif + +int scoped_main(int argc, char *argv[]) +{ +#ifdef _CRTDBG_LEAK_CHECK_DF + // Turn on leak-checking + int tempflag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); + tempflag |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag( tempflag ); +#endif + +#ifdef _SUNPRO_CC + // No need for thread safety for the test program + cout.set_safe_flag(stream_MT::unsafe_object); + cin.set_safe_flag(stream_MT::unsafe_object); +#endif + + try + { + RegisterFactories(All); + + // A hint to help locate TestData/ and TestVectors/ after install. + SetArgvPathHint(argv[0], g_argvPathHint); + + // Set a seed for reproducible results. If the seed is too short then + // it is padded with spaces. If the seed is missing then time() is used. + // For example: + // ./cryptest.exe v seed=abcdefg + SetGlobalSeed(argc, argv, s_globalSeed); + +#if (CRYPTOPP_USE_AES_GENERATOR) + // Fetch the SymmetricCipher interface, not the RandomNumberGenerator + // interface, to key the underlying cipher. If CRYPTOPP_USE_AES_GENERATOR is 1 + // then AES/OFB based is used. Otherwise the OS random number generator is used. + SymmetricCipher& cipher = dynamic_cast(GlobalRNG()); + cipher.SetKeyWithIV((byte *)s_globalSeed.data(), s_globalSeed.size(), (byte *)s_globalSeed.data()); +#endif + + std::string command, executableName, macFilename; + + if (argc < 2) + command = 'h'; + else + command = argv[1]; + + if (command == "g") + { + char thisSeed[1024], privFilename[128], pubFilename[128]; + unsigned int keyLength; + + std::cout << "Key length in bits: "; + std::cin >> keyLength; + + std::cout << "\nSave private key to file: "; + std::cin >> privFilename; + + std::cout << "\nSave public key to file: "; + std::cin >> pubFilename; + + std::cout << "\nRandom Seed: "; + std::ws(std::cin); + std::cin.getline(thisSeed, 1024); + + GenerateRSAKey(keyLength, privFilename, pubFilename, thisSeed); + } + else if (command == "rs") + RSASignFile(argv[2], argv[3], argv[4]); + else if (command == "rv") + { + bool verified = RSAVerifyFile(argv[2], argv[3], argv[4]); + std::cout << (verified ? "valid signature" : "invalid signature") << std::endl; + } + else if (command == "r") + { + char privFilename[128], pubFilename[128]; + char thisSeed[1024], message[1024]; + + std::cout << "Private key file: "; + std::cin >> privFilename; + + std::cout << "\nPublic key file: "; + std::cin >> pubFilename; + + std::cout << "\nRandom Seed: "; + std::ws(std::cin); + std::cin.getline(thisSeed, 1024); + + std::cout << "\nMessage: "; + std::cin.getline(message, 1024); + + std::string ciphertext = RSAEncryptString(pubFilename, thisSeed, message); + std::cout << "\nCiphertext: " << ciphertext << std::endl; + + std::string decrypted = RSADecryptString(privFilename, ciphertext.c_str()); + std::cout << "\nDecrypted: " << decrypted << std::endl; + } + else if (command == "mt") + { + MaurerRandomnessTest mt; + FileStore fs(argv[2]); + fs.TransferAllTo(mt); + std::cout << "Maurer Test Value: " << mt.GetTestValue() << std::endl; + } + else if (command == "mac_dll") + { + std::string fname(argv[2] ? argv[2] : ""); + + // sanity check on file size + std::fstream dllFile(fname.c_str(), std::ios::in | std::ios::out | std::ios::binary); + if (!dllFile.good()) + { + std::cerr << "Failed to open file \"" << fname << "\"\n"; + return 1; + } + + std::ifstream::pos_type fileEnd = dllFile.seekg(0, std::ios_base::end).tellg(); + if (fileEnd > 20*1000*1000) + { + std::cerr << "Input file " << fname << " is too large"; + std::cerr << "(size is " << fileEnd << ").\n"; + return 1; + } + + // read file into memory + unsigned int fileSize = (unsigned int)fileEnd; + SecByteBlock buf(fileSize); + dllFile.seekg(0, std::ios_base::beg); + dllFile.read((char *)buf.begin(), fileSize); + + // find positions of relevant sections in the file, based on version 8 of documentation from http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx + word32 coffPos = *(word16 *)(void *)(buf+0x3c); + word32 optionalHeaderPos = coffPos + 24; + word16 optionalHeaderMagic = *(word16 *)(void *)(buf+optionalHeaderPos); + if (optionalHeaderMagic != 0x10b && optionalHeaderMagic != 0x20b) + { + std::cerr << "Target file is not a PE32 or PE32+ image.\n"; + return 3; + } + word32 checksumPos = optionalHeaderPos + 64; + word32 certificateTableDirectoryPos = optionalHeaderPos + (optionalHeaderMagic == 0x10b ? 128 : 144); + word32 certificateTablePos = *(word32 *)(void *)(buf+certificateTableDirectoryPos); + word32 certificateTableSize = *(word32 *)(void *)(buf+certificateTableDirectoryPos+4); + if (certificateTableSize != 0) + std::cerr << "Warning: certificate table (IMAGE_DIRECTORY_ENTRY_SECURITY) of target image is not empty.\n"; + + // find where to place computed MAC + byte mac[] = CRYPTOPP_DUMMY_DLL_MAC; + byte *found = std::search(buf.begin(), buf.end(), mac+0, mac+sizeof(mac)); + if (found == buf.end()) + { + std::cerr << "MAC placeholder not found. The MAC may already be placed.\n"; + return 2; + } + word32 macPos = (unsigned int)(found-buf.begin()); + + // compute MAC + member_ptr pMac(NewIntegrityCheckingMAC()); + CRYPTOPP_ASSERT(pMac->DigestSize() == sizeof(mac)); + MeterFilter f(new HashFilter(*pMac, new ArraySink(mac, sizeof(mac)))); + f.AddRangeToSkip(0, checksumPos, 4); + f.AddRangeToSkip(0, certificateTableDirectoryPos, 8); + f.AddRangeToSkip(0, macPos, sizeof(mac)); + f.AddRangeToSkip(0, certificateTablePos, certificateTableSize); + f.PutMessageEnd(buf.begin(), buf.size()); + + // Encode MAC + std::string hexMac; + HexEncoder encoder; + encoder.Put(mac, sizeof(mac)), encoder.MessageEnd(); + hexMac.resize(static_cast(encoder.MaxRetrievable())); + encoder.Get(reinterpret_cast(&hexMac[0]), hexMac.size()); + + // Report MAC and location + std::cout << "Placing MAC " << hexMac << " in " << fname << " at file offset " << macPos; + std::cout << " (0x" << std::hex << macPos << std::dec << ").\n"; + + // place MAC + dllFile.seekg(macPos, std::ios_base::beg); + dllFile.write((char *)mac, sizeof(mac)); + } + else if (command == "m") + DigestFile(argv[2]); + else if (command == "tv") + { + // TestDataFile() adds CRYPTOPP_DATA_DIR as required + std::string fname = (argv[2] ? argv[2] : "all"); + if (fname.find(".txt") == std::string::npos) + fname += ".txt"; + if (fname.find("TestVectors") == std::string::npos) + fname = "TestVectors/" + fname; + + PrintSeedAndThreads(); + return !RunTestDataFile(fname.c_str()); + } + else if (command == "t") + { + // VC60 workaround: use char array instead of std::string to workaround MSVC's getline bug + char passPhrase[MAX_PHRASE_LENGTH], plaintext[1024]; + + std::cout << "Passphrase: "; + std::cin.getline(passPhrase, MAX_PHRASE_LENGTH); + + std::cout << "\nPlaintext: "; + std::cin.getline(plaintext, sizeof(plaintext)); + + std::string ciphertext = EncryptString(plaintext, passPhrase); + std::cout << "\nCiphertext: " << ciphertext << std::endl; + + std::string decrypted = DecryptString(ciphertext.c_str(), passPhrase); + std::cout << "\nDecrypted: " << decrypted << std::endl; + + return 0; + } + else if (command == "e64") + Base64Encode(argv[2], argv[3]); + else if (command == "d64") + Base64Decode(argv[2], argv[3]); + else if (command == "e16") + HexEncode(argv[2], argv[3]); + else if (command == "d16") + HexDecode(argv[2], argv[3]); + else if (command == "e" || command == "d") + { + char passPhrase[MAX_PHRASE_LENGTH]; + std::cout << "Passphrase: "; + std::cin.getline(passPhrase, MAX_PHRASE_LENGTH); + if (command == "e") + EncryptFile(argv[2], argv[3], passPhrase); + else + DecryptFile(argv[2], argv[3], passPhrase); + } + else if (command == "ss") + { + char thisSeed[1024]; + std::cout << "\nRandom Seed: "; + std::ws(std::cin); + std::cin.getline(thisSeed, sizeof(thisSeed)); + SecretShareFile(StringToValue(argv[2]), StringToValue(argv[3]), argv[4], thisSeed); + } + else if (command == "sr") + SecretRecoverFile(argc-3, argv[2], argv+3); + else if (command == "id") + InformationDisperseFile(StringToValue(argv[2]), StringToValue(argv[3]), argv[4]); + else if (command == "ir") + InformationRecoverFile(argc-3, argv[2], argv+3); + else if (command == "v" || command == "vv") + return !Validate(argc>2 ? StringToValue(argv[2]) : 0, argv[1][1] == 'v'); + else if (command.substr(0,1) == "b") // "b", "b1", "b2", ... + BenchmarkWithCommand(argc, argv); + else if (command == "z") + GzipFile(argv[3], argv[4], argv[2][0]-'0'); + else if (command == "u") + GunzipFile(argv[2], argv[3]); + else if (command == "fips") + FIPS140_SampleApplication(); + else if (command == "fips-rand") + FIPS140_GenerateRandomFiles(); + else if (command == "a") + { + if (AdhocTest) + return (*AdhocTest)(argc, argv); + else + { + std::cerr << "AdhocTest not defined.\n"; + return 1; + } + } + else if (command == "hmac") + HmacFile(argv[2], argv[3]); + else if (command == "ae") + AES_CTR_Encrypt(argv[2], argv[3], argv[4], argv[5]); + else if (command == "h") + { + FileSource usage(DataDir("TestData/usage.dat").c_str(), true, new FileSink(std::cout)); + return 1; + } + else if (command == "V") + { + std::cout << CRYPTOPP_VERSION / 100 << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << std::endl; + } + else + { + std::cerr << "Unrecognized command. Run \"cryptest h\" to obtain usage information.\n"; + return 1; + } + return 0; + } + catch(const Exception &e) + { + std::cout << "\nException caught: " << e.what() << std::endl; + return -1; + } + catch(const std::exception &e) + { + std::cout << "\nstd::exception caught: " << e.what() << std::endl; + return -2; + } +} // main() + +bool SetGlobalSeed(int argc, char* argv[], std::string& seed) +{ + bool ret = false; + + for (int i=0; i::Signer priv(privFile); + FileSource f(messageFilename, true, new SignerFilter(GlobalRNG(), priv, new HexEncoder(new FileSink(signatureFilename)))); +} + +bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename) +{ + FileSource pubFile(pubFilename, true, new HexDecoder); + RSASS::Verifier pub(pubFile); + + FileSource signatureFile(signatureFilename, true, new HexDecoder); + if (signatureFile.MaxRetrievable() != pub.SignatureLength()) + return false; + SecByteBlock signature(pub.SignatureLength()); + signatureFile.Get(signature, signature.size()); + + SignatureVerificationFilter *verifierFilter = new SignatureVerificationFilter(pub); + verifierFilter->Put(signature, pub.SignatureLength()); + FileSource f(messageFilename, true, verifierFilter); + + return verifierFilter->GetLastResult(); +} + +void DigestFile(const char *filename) +{ + SHA1 sha; + RIPEMD160 ripemd; + SHA256 sha256; + Tiger tiger; + SHA512 sha512; + Whirlpool whirlpool; + + vector_member_ptrs filters(6); + filters[0].reset(new HashFilter(sha)); + filters[1].reset(new HashFilter(ripemd)); + filters[2].reset(new HashFilter(tiger)); + filters[3].reset(new HashFilter(sha256)); + filters[4].reset(new HashFilter(sha512)); + filters[5].reset(new HashFilter(whirlpool)); + + member_ptr channelSwitch(new ChannelSwitch); + size_t i; + for (i=0; iAddDefaultRoute(*filters[i]); + FileSource(filename, true, channelSwitch.release()); + + HexEncoder encoder(new FileSink(std::cout), false); + for (i=0; iAlgorithmName() << ": "; + filters[i]->TransferTo(encoder); + std::cout << "\n"; + } +} + +void HmacFile(const char *hexKey, const char *file) +{ + member_ptr mac; + if (strcmp(hexKey, "selftest") == 0) + { + std::cerr << "Computing HMAC/SHA1 value for self test.\n"; + mac.reset(NewIntegrityCheckingMAC()); + } + else + { + std::string decodedKey; + StringSource(hexKey, true, new HexDecoder(new StringSink(decodedKey))); + mac.reset(new HMAC((const byte *)decodedKey.data(), decodedKey.size())); + } + FileSource(file, true, new HashFilter(*mac, new HexEncoder(new FileSink(std::cout)))); +} + +void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile) +{ + SecByteBlock key = HexDecodeString(hexKey); + SecByteBlock iv = HexDecodeString(hexIV); + CTR_Mode::Encryption aes(key, key.size(), iv); + FileSource(infile, true, new StreamTransformationFilter(aes, new FileSink(outfile))); +} + +std::string EncryptString(const char *instr, const char *passPhrase) +{ + std::string outstr; + + DefaultEncryptorWithMAC encryptor(passPhrase, new HexEncoder(new StringSink(outstr))); + encryptor.Put((byte *)instr, strlen(instr)); + encryptor.MessageEnd(); + + return outstr; +} + +std::string DecryptString(const char *instr, const char *passPhrase) +{ + std::string outstr; + + HexDecoder decryptor(new DefaultDecryptorWithMAC(passPhrase, new StringSink(outstr))); + decryptor.Put((byte *)instr, strlen(instr)); + decryptor.MessageEnd(); + + return outstr; +} + +void EncryptFile(const char *in, const char *out, const char *passPhrase) +{ + FileSource f(in, true, new DefaultEncryptorWithMAC(passPhrase, new FileSink(out))); +} + +void DecryptFile(const char *in, const char *out, const char *passPhrase) +{ + FileSource f(in, true, new DefaultDecryptorWithMAC(passPhrase, new FileSink(out))); +} + +void SecretShareFile(int threshold, int nShares, const char *filename, const char *seed) +{ + CRYPTOPP_ASSERT(nShares >= 1 && nShares<=1000); + if (nShares < 1 || nShares > 1000) + throw InvalidArgument("SecretShareFile: " + IntToString(nShares) + " is not in range [1, 1000]"); + + RandomPool rng; + rng.IncorporateEntropy((byte *)seed, strlen(seed)); + + ChannelSwitch *channelSwitch = NULLPTR; + FileSource source(filename, false, new SecretSharing(rng, threshold, nShares, channelSwitch = new ChannelSwitch)); + + // Be careful of the type of Sink used. An ArraySink will stop writing data once the array + // is full. Also see http://groups.google.com/forum/#!topic/cryptopp-users/XEKKLCEFH3Y. + vector_member_ptrs fileSinks(nShares); + std::string channel; + for (int i=0; i(i); + fileSinks[i]->Put((const byte *)channel.data(), 4); + channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL); + } + + source.PumpAll(); +} + +void SecretRecoverFile(int threshold, const char *outFilename, char *const *inFilenames) +{ + CRYPTOPP_ASSERT(threshold >= 1 && threshold <=1000); + if (threshold < 1 || threshold > 1000) + throw InvalidArgument("SecretRecoverFile: " + IntToString(threshold) + " is not in range [1, 1000]"); + + SecretRecovery recovery(threshold, new FileSink(outFilename)); + + vector_member_ptrs fileSources(threshold); + SecByteBlock channel(4); + int i; + for (i=0; iPump(4); + fileSources[i]->Get(channel, 4); + fileSources[i]->Attach(new ChannelSwitch(recovery, std::string((char *)channel.begin(), 4))); + } + + while (fileSources[0]->Pump(256)) + for (i=1; iPump(256); + + for (i=0; iPumpAll(); +} + +void InformationDisperseFile(int threshold, int nShares, const char *filename) +{ + CRYPTOPP_ASSERT(threshold >= 1 && threshold <=1000); + if (threshold < 1 || threshold > 1000) + throw InvalidArgument("InformationDisperseFile: " + IntToString(nShares) + " is not in range [1, 1000]"); + + ChannelSwitch *channelSwitch = NULLPTR; + FileSource source(filename, false, new InformationDispersal(threshold, nShares, channelSwitch = new ChannelSwitch)); + + // Be careful of the type of Sink used. An ArraySink will stop writing data once the array + // is full. Also see http://groups.google.com/forum/#!topic/cryptopp-users/XEKKLCEFH3Y. + vector_member_ptrs fileSinks(nShares); + std::string channel; + for (int i=0; i(i); + fileSinks[i]->Put((const byte *)channel.data(), 4); + channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL); + } + + source.PumpAll(); +} + +void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames) +{ + CRYPTOPP_ASSERT(threshold<=1000); + if (threshold < 1 || threshold > 1000) + throw InvalidArgument("InformationRecoverFile: " + IntToString(threshold) + " is not in range [1, 1000]"); + + InformationRecovery recovery(threshold, new FileSink(outFilename)); + + vector_member_ptrs fileSources(threshold); + SecByteBlock channel(4); + int i; + for (i=0; iPump(4); + fileSources[i]->Get(channel, 4); + fileSources[i]->Attach(new ChannelSwitch(recovery, std::string((char *)channel.begin(), 4))); + } + + while (fileSources[0]->Pump(256)) + for (i=1; iPump(256); + + for (i=0; iPumpAll(); +} + +void GzipFile(const char *in, const char *out, int deflate_level) +{ +// FileSource(in, true, new Gzip(new FileSink(out), deflate_level)); + + // use a filter graph to compare decompressed data with original + // + // Source ----> Gzip ------> Sink + // \ | + // \ Gunzip + // \ | + // \ v + // > ComparisonFilter + + EqualityComparisonFilter comparison; + + Gunzip gunzip(new ChannelSwitch(comparison, "0")); + gunzip.SetAutoSignalPropagation(0); + + FileSink sink(out); + + ChannelSwitch *cs; + Gzip gzip(cs = new ChannelSwitch(sink), deflate_level); + cs->AddDefaultRoute(gunzip); + + cs = new ChannelSwitch(gzip); + cs->AddDefaultRoute(comparison, "1"); + FileSource source(in, true, cs); + + comparison.ChannelMessageSeriesEnd("0"); + comparison.ChannelMessageSeriesEnd("1"); +} + +void GunzipFile(const char *in, const char *out) +{ + FileSource(in, true, new Gunzip(new FileSink(out))); +} + +void Base64Encode(const char *in, const char *out) +{ + FileSource(in, true, new Base64Encoder(new FileSink(out))); +} + +void Base64Decode(const char *in, const char *out) +{ + FileSource(in, true, new Base64Decoder(new FileSink(out))); +} + +void HexEncode(const char *in, const char *out) +{ + FileSource(in, true, new HexEncoder(new FileSink(out))); +} + +void HexDecode(const char *in, const char *out) +{ + FileSource(in, true, new HexDecoder(new FileSink(out))); +} + +bool Validate(int alg, bool thorough) +{ + bool result; + + g_testBegin = ::time(NULLPTR); + PrintSeedAndThreads(); + + // TODO: we need to group these tests like benchmarks... + switch (alg) + { + case 0: result = ValidateAll(thorough); break; + case 1: result = TestSettings(); break; + case 2: result = TestOS_RNG(); break; +// case 3: result = TestSecRandom(); break; + case 4: result = ValidateMD5(); break; + case 5: result = ValidateSHA(); break; + case 6: result = ValidateDES(); break; + case 7: result = ValidateIDEA(); break; + case 8: result = ValidateARC4(); break; + case 9: result = ValidateRC5(); break; + case 10: result = ValidateBlowfish(); break; +// case 11: result = ValidateDiamond2(); break; + case 12: result = ValidateThreeWay(); break; + case 13: result = ValidateBBS(); break; + case 14: result = ValidateDH(); break; + case 15: result = ValidateX25519(); break; + case 16: result = ValidateRSA(); break; + case 17: result = ValidateElGamal(); break; + case 18: result = ValidateDSA(thorough); break; +// case 18: result = ValidateHAVAL(); break; + case 19: result = ValidateSAFER(); break; + case 20: result = ValidateLUC(); break; + case 21: result = ValidateRabin(); break; +// case 22: result = ValidateBlumGoldwasser(); break; + case 23: result = ValidateECP(); break; + case 24: result = ValidateEC2N(); break; +// case 25: result = ValidateMD5MAC(); break; + case 26: result = ValidateGOST(); break; + case 27: result = ValidateTiger(); break; + case 28: result = ValidateRIPEMD(); break; + case 29: result = ValidateHMAC(); break; +// case 30: result = ValidateXMACC(); break; + case 31: result = ValidateSHARK(); break; + case 32: result = ValidateLUC_DH(); break; + case 33: result = ValidateLUC_DL(); break; + case 34: result = ValidateSEAL(); break; + case 35: result = ValidateCAST(); break; + case 36: result = ValidateSquare(); break; + case 37: result = ValidateRC2(); break; + case 38: result = ValidateRC6(); break; + case 39: result = ValidateMARS(); break; + case 40: result = ValidateRW(); break; + case 41: result = ValidateMD2(); break; + case 42: result = ValidateNR(); break; + case 43: result = ValidateMQV(); break; + case 44: result = ValidateRijndael(); break; + case 45: result = ValidateTwofish(); break; + case 46: result = ValidateSerpent(); break; + case 47: result = ValidateCipherModes(); break; + case 48: result = ValidateCRC32(); break; + case 49: result = ValidateCRC32C(); break; + case 50: result = ValidateECDSA(); break; + case 51: result = ValidateECGDSA(thorough); break; + case 52: result = ValidateXTR_DH(); break; + case 53: result = ValidateSKIPJACK(); break; + case 54: result = ValidateSHA2(); break; + case 55: result = ValidatePanama(); break; + case 56: result = ValidateAdler32(); break; + case 57: result = ValidateMD4(); break; + case 58: result = ValidatePBKDF(); break; + case 59: result = ValidateHKDF(); break; + case 60: result = ValidateScrypt(); break; + case 61: result = ValidateESIGN(); break; + case 62: result = ValidateDLIES(); break; + case 63: result = ValidateBaseCode(); break; + case 64: result = ValidateSHACAL2(); break; + case 65: result = ValidateARIA(); break; + case 66: result = ValidateCamellia(); break; + case 67: result = ValidateWhirlpool(); break; + case 68: result = ValidateTTMAC(); break; + case 70: result = ValidateSalsa(); break; + case 71: result = ValidateChaCha(); break; + case 72: result = ValidateChaChaTLS(); break; + case 73: result = ValidateSosemanuk(); break; + case 74: result = ValidateRabbit(); break; + case 75: result = ValidateHC128(); break; + case 76: result = ValidateHC256(); break; + case 80: result = ValidateVMAC(); break; + case 81: result = ValidateCCM(); break; + case 82: result = ValidateGCM(); break; + case 83: result = ValidateXTS(); break; + case 84: result = ValidateCMAC(); break; + case 85: result = ValidateSM3(); break; + case 86: result = ValidateBLAKE2s(); break; + case 87: result = ValidateBLAKE2b(); break; + case 88: result = ValidatePoly1305(); break; + case 89: result = ValidateSipHash(); break; + case 90: result = ValidateHashDRBG(); break; + case 91: result = ValidateHmacDRBG(); break; + case 92: result = ValidateNaCl(); break; + + case 100: result = ValidateCHAM(); break; + case 101: result = ValidateSIMECK(); break; + case 102: result = ValidateSIMON(); break; + case 103: result = ValidateSPECK(); break; + + case 110: result = ValidateSHA3(); break; + case 111: result = ValidateSHAKE(); break; + case 112: result = ValidateSHAKE_XOF(); break; + + case 120: result = ValidateMQV(); break; + case 121: result = ValidateHMQV(); break; + case 122: result = ValidateFHMQV(); break; + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + // http://github.com/weidai11/cryptopp/issues/92 + case 9999: result = TestSecBlock(); break; + // http://github.com/weidai11/cryptopp/issues/64 + case 9998: result = TestPolynomialMod2(); break; + // http://github.com/weidai11/cryptopp/issues/336 + case 9997: result = TestIntegerBitops(); break; + // http://github.com/weidai11/cryptopp/issues/602 + case 9996: result = TestIntegerOps(); break; + // http://github.com/weidai11/cryptopp/issues/360 + case 9995: result = TestRounding(); break; + // http://github.com/weidai11/cryptopp/issues/242 + case 9994: result = TestHuffmanCodes(); break; + // http://github.com/weidai11/cryptopp/issues/346 + case 9993: result = TestASN1Parse(); break; + // http://github.com/weidai11/cryptopp/issues/242 + case 9992: result = TestX25519(); break; + // http://github.com/weidai11/cryptopp/issues/346 + case 9991: result = TestEd25519(); break; +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + case 9990: result = TestAltivecOps(); break; +# endif +#endif + + default: return false; + } + + g_testEnd = ::time(NULLPTR); + + std::cout << "\nSeed used was " << s_globalSeed; + std::cout << "\nTest started at " << TimeToString(g_testBegin); + std::cout << "\nTest ended at " << TimeToString(g_testEnd) << std::endl; + + return result; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +// Microsoft puts a byte in global namespace. Combined with +// a 'using namespace CryptoPP', it causes compile failures. +// Also see http://github.com/weidai11/cryptopp/issues/442 +// and http://github.com/weidai11/cryptopp/issues/447. +int CRYPTOPP_API main(int argc, char *argv[]) +{ + return CryptoPP::Test::scoped_main(argc, argv); +} diff --git a/extension/third_party/cryptopp/tftables.cpp b/extension/third_party/cryptopp/tftables.cpp new file mode 100644 index 00000000..00bb6bac --- /dev/null +++ b/extension/third_party/cryptopp/tftables.cpp @@ -0,0 +1,323 @@ +// Twofish tables + +#include "pch.h" +#include "config.h" + +#include "twofish.h" + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +const byte Twofish::Base::q[2][256] = { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0, + + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 +}; + +const word32 Twofish::Base::mds[4][256] = { + 0xbcbc3275, 0xecec21f3, 0x202043c6, 0xb3b3c9f4, + 0xdada03db, 0x02028b7b, 0xe2e22bfb, 0x9e9efac8, + 0xc9c9ec4a, 0xd4d409d3, 0x18186be6, 0x1e1e9f6b, + 0x98980e45, 0xb2b2387d, 0xa6a6d2e8, 0x2626b74b, + 0x3c3c57d6, 0x93938a32, 0x8282eed8, 0x525298fd, + 0x7b7bd437, 0xbbbb3771, 0x5b5b97f1, 0x474783e1, + 0x24243c30, 0x5151e20f, 0xbabac6f8, 0x4a4af31b, + 0xbfbf4887, 0x0d0d70fa, 0xb0b0b306, 0x7575de3f, + 0xd2d2fd5e, 0x7d7d20ba, 0x666631ae, 0x3a3aa35b, + 0x59591c8a, 0x00000000, 0xcdcd93bc, 0x1a1ae09d, + 0xaeae2c6d, 0x7f7fabc1, 0x2b2bc7b1, 0xbebeb90e, + 0xe0e0a080, 0x8a8a105d, 0x3b3b52d2, 0x6464bad5, + 0xd8d888a0, 0xe7e7a584, 0x5f5fe807, 0x1b1b1114, + 0x2c2cc2b5, 0xfcfcb490, 0x3131272c, 0x808065a3, + 0x73732ab2, 0x0c0c8173, 0x79795f4c, 0x6b6b4154, + 0x4b4b0292, 0x53536974, 0x94948f36, 0x83831f51, + 0x2a2a3638, 0xc4c49cb0, 0x2222c8bd, 0xd5d5f85a, + 0xbdbdc3fc, 0x48487860, 0xffffce62, 0x4c4c0796, + 0x4141776c, 0xc7c7e642, 0xebeb24f7, 0x1c1c1410, + 0x5d5d637c, 0x36362228, 0x6767c027, 0xe9e9af8c, + 0x4444f913, 0x1414ea95, 0xf5f5bb9c, 0xcfcf18c7, + 0x3f3f2d24, 0xc0c0e346, 0x7272db3b, 0x54546c70, + 0x29294cca, 0xf0f035e3, 0x0808fe85, 0xc6c617cb, + 0xf3f34f11, 0x8c8ce4d0, 0xa4a45993, 0xcaca96b8, + 0x68683ba6, 0xb8b84d83, 0x38382820, 0xe5e52eff, + 0xadad569f, 0x0b0b8477, 0xc8c81dc3, 0x9999ffcc, + 0x5858ed03, 0x19199a6f, 0x0e0e0a08, 0x95957ebf, + 0x70705040, 0xf7f730e7, 0x6e6ecf2b, 0x1f1f6ee2, + 0xb5b53d79, 0x09090f0c, 0x616134aa, 0x57571682, + 0x9f9f0b41, 0x9d9d803a, 0x111164ea, 0x2525cdb9, + 0xafafdde4, 0x4545089a, 0xdfdf8da4, 0xa3a35c97, + 0xeaead57e, 0x353558da, 0xededd07a, 0x4343fc17, + 0xf8f8cb66, 0xfbfbb194, 0x3737d3a1, 0xfafa401d, + 0xc2c2683d, 0xb4b4ccf0, 0x32325dde, 0x9c9c71b3, + 0x5656e70b, 0xe3e3da72, 0x878760a7, 0x15151b1c, + 0xf9f93aef, 0x6363bfd1, 0x3434a953, 0x9a9a853e, + 0xb1b1428f, 0x7c7cd133, 0x88889b26, 0x3d3da65f, + 0xa1a1d7ec, 0xe4e4df76, 0x8181942a, 0x91910149, + 0x0f0ffb81, 0xeeeeaa88, 0x161661ee, 0xd7d77321, + 0x9797f5c4, 0xa5a5a81a, 0xfefe3feb, 0x6d6db5d9, + 0x7878aec5, 0xc5c56d39, 0x1d1de599, 0x7676a4cd, + 0x3e3edcad, 0xcbcb6731, 0xb6b6478b, 0xefef5b01, + 0x12121e18, 0x6060c523, 0x6a6ab0dd, 0x4d4df61f, + 0xcecee94e, 0xdede7c2d, 0x55559df9, 0x7e7e5a48, + 0x2121b24f, 0x03037af2, 0xa0a02665, 0x5e5e198e, + 0x5a5a6678, 0x65654b5c, 0x62624e58, 0xfdfd4519, + 0x0606f48d, 0x404086e5, 0xf2f2be98, 0x3333ac57, + 0x17179067, 0x05058e7f, 0xe8e85e05, 0x4f4f7d64, + 0x89896aaf, 0x10109563, 0x74742fb6, 0x0a0a75fe, + 0x5c5c92f5, 0x9b9b74b7, 0x2d2d333c, 0x3030d6a5, + 0x2e2e49ce, 0x494989e9, 0x46467268, 0x77775544, + 0xa8a8d8e0, 0x9696044d, 0x2828bd43, 0xa9a92969, + 0xd9d97929, 0x8686912e, 0xd1d187ac, 0xf4f44a15, + 0x8d8d1559, 0xd6d682a8, 0xb9b9bc0a, 0x42420d9e, + 0xf6f6c16e, 0x2f2fb847, 0xdddd06df, 0x23233934, + 0xcccc6235, 0xf1f1c46a, 0xc1c112cf, 0x8585ebdc, + 0x8f8f9e22, 0x7171a1c9, 0x9090f0c0, 0xaaaa539b, + 0x0101f189, 0x8b8be1d4, 0x4e4e8ced, 0x8e8e6fab, + 0xababa212, 0x6f6f3ea2, 0xe6e6540d, 0xdbdbf252, + 0x92927bbb, 0xb7b7b602, 0x6969ca2f, 0x3939d9a9, + 0xd3d30cd7, 0xa7a72361, 0xa2a2ad1e, 0xc3c399b4, + 0x6c6c4450, 0x07070504, 0x04047ff6, 0x272746c2, + 0xacaca716, 0xd0d07625, 0x50501386, 0xdcdcf756, + 0x84841a55, 0xe1e15109, 0x7a7a25be, 0x1313ef91, + + 0xa9d93939, 0x67901717, 0xb3719c9c, 0xe8d2a6a6, + 0x04050707, 0xfd985252, 0xa3658080, 0x76dfe4e4, + 0x9a084545, 0x92024b4b, 0x80a0e0e0, 0x78665a5a, + 0xe4ddafaf, 0xddb06a6a, 0xd1bf6363, 0x38362a2a, + 0x0d54e6e6, 0xc6432020, 0x3562cccc, 0x98bef2f2, + 0x181e1212, 0xf724ebeb, 0xecd7a1a1, 0x6c774141, + 0x43bd2828, 0x7532bcbc, 0x37d47b7b, 0x269b8888, + 0xfa700d0d, 0x13f94444, 0x94b1fbfb, 0x485a7e7e, + 0xf27a0303, 0xd0e48c8c, 0x8b47b6b6, 0x303c2424, + 0x84a5e7e7, 0x54416b6b, 0xdf06dddd, 0x23c56060, + 0x1945fdfd, 0x5ba33a3a, 0x3d68c2c2, 0x59158d8d, + 0xf321ecec, 0xae316666, 0xa23e6f6f, 0x82165757, + 0x63951010, 0x015befef, 0x834db8b8, 0x2e918686, + 0xd9b56d6d, 0x511f8383, 0x9b53aaaa, 0x7c635d5d, + 0xa63b6868, 0xeb3ffefe, 0xa5d63030, 0xbe257a7a, + 0x16a7acac, 0x0c0f0909, 0xe335f0f0, 0x6123a7a7, + 0xc0f09090, 0x8cafe9e9, 0x3a809d9d, 0xf5925c5c, + 0x73810c0c, 0x2c273131, 0x2576d0d0, 0x0be75656, + 0xbb7b9292, 0x4ee9cece, 0x89f10101, 0x6b9f1e1e, + 0x53a93434, 0x6ac4f1f1, 0xb499c3c3, 0xf1975b5b, + 0xe1834747, 0xe66b1818, 0xbdc82222, 0x450e9898, + 0xe26e1f1f, 0xf4c9b3b3, 0xb62f7474, 0x66cbf8f8, + 0xccff9999, 0x95ea1414, 0x03ed5858, 0x56f7dcdc, + 0xd4e18b8b, 0x1c1b1515, 0x1eada2a2, 0xd70cd3d3, + 0xfb2be2e2, 0xc31dc8c8, 0x8e195e5e, 0xb5c22c2c, + 0xe9894949, 0xcf12c1c1, 0xbf7e9595, 0xba207d7d, + 0xea641111, 0x77840b0b, 0x396dc5c5, 0xaf6a8989, + 0x33d17c7c, 0xc9a17171, 0x62ceffff, 0x7137bbbb, + 0x81fb0f0f, 0x793db5b5, 0x0951e1e1, 0xaddc3e3e, + 0x242d3f3f, 0xcda47676, 0xf99d5555, 0xd8ee8282, + 0xe5864040, 0xc5ae7878, 0xb9cd2525, 0x4d049696, + 0x44557777, 0x080a0e0e, 0x86135050, 0xe730f7f7, + 0xa1d33737, 0x1d40fafa, 0xaa346161, 0xed8c4e4e, + 0x06b3b0b0, 0x706c5454, 0xb22a7373, 0xd2523b3b, + 0x410b9f9f, 0x7b8b0202, 0xa088d8d8, 0x114ff3f3, + 0x3167cbcb, 0xc2462727, 0x27c06767, 0x90b4fcfc, + 0x20283838, 0xf67f0404, 0x60784848, 0xff2ee5e5, + 0x96074c4c, 0x5c4b6565, 0xb1c72b2b, 0xab6f8e8e, + 0x9e0d4242, 0x9cbbf5f5, 0x52f2dbdb, 0x1bf34a4a, + 0x5fa63d3d, 0x9359a4a4, 0x0abcb9b9, 0xef3af9f9, + 0x91ef1313, 0x85fe0808, 0x49019191, 0xee611616, + 0x2d7cdede, 0x4fb22121, 0x8f42b1b1, 0x3bdb7272, + 0x47b82f2f, 0x8748bfbf, 0x6d2caeae, 0x46e3c0c0, + 0xd6573c3c, 0x3e859a9a, 0x6929a9a9, 0x647d4f4f, + 0x2a948181, 0xce492e2e, 0xcb17c6c6, 0x2fca6969, + 0xfcc3bdbd, 0x975ca3a3, 0x055ee8e8, 0x7ad0eded, + 0xac87d1d1, 0x7f8e0505, 0xd5ba6464, 0x1aa8a5a5, + 0x4bb72626, 0x0eb9bebe, 0xa7608787, 0x5af8d5d5, + 0x28223636, 0x14111b1b, 0x3fde7575, 0x2979d9d9, + 0x88aaeeee, 0x3c332d2d, 0x4c5f7979, 0x02b6b7b7, + 0xb896caca, 0xda583535, 0xb09cc4c4, 0x17fc4343, + 0x551a8484, 0x1ff64d4d, 0x8a1c5959, 0x7d38b2b2, + 0x57ac3333, 0xc718cfcf, 0x8df40606, 0x74695353, + 0xb7749b9b, 0xc4f59797, 0x9f56adad, 0x72dae3e3, + 0x7ed5eaea, 0x154af4f4, 0x229e8f8f, 0x12a2abab, + 0x584e6262, 0x07e85f5f, 0x99e51d1d, 0x34392323, + 0x6ec1f6f6, 0x50446c6c, 0xde5d3232, 0x68724646, + 0x6526a0a0, 0xbc93cdcd, 0xdb03dada, 0xf8c6baba, + 0xc8fa9e9e, 0xa882d6d6, 0x2bcf6e6e, 0x40507070, + 0xdceb8585, 0xfe750a0a, 0x328a9393, 0xa48ddfdf, + 0xca4c2929, 0x10141c1c, 0x2173d7d7, 0xf0ccb4b4, + 0xd309d4d4, 0x5d108a8a, 0x0fe25151, 0x00000000, + 0x6f9a1919, 0x9de01a1a, 0x368f9494, 0x42e6c7c7, + 0x4aecc9c9, 0x5efdd2d2, 0xc1ab7f7f, 0xe0d8a8a8, + + 0xbc75bc32, 0xecf3ec21, 0x20c62043, 0xb3f4b3c9, + 0xdadbda03, 0x027b028b, 0xe2fbe22b, 0x9ec89efa, + 0xc94ac9ec, 0xd4d3d409, 0x18e6186b, 0x1e6b1e9f, + 0x9845980e, 0xb27db238, 0xa6e8a6d2, 0x264b26b7, + 0x3cd63c57, 0x9332938a, 0x82d882ee, 0x52fd5298, + 0x7b377bd4, 0xbb71bb37, 0x5bf15b97, 0x47e14783, + 0x2430243c, 0x510f51e2, 0xbaf8bac6, 0x4a1b4af3, + 0xbf87bf48, 0x0dfa0d70, 0xb006b0b3, 0x753f75de, + 0xd25ed2fd, 0x7dba7d20, 0x66ae6631, 0x3a5b3aa3, + 0x598a591c, 0x00000000, 0xcdbccd93, 0x1a9d1ae0, + 0xae6dae2c, 0x7fc17fab, 0x2bb12bc7, 0xbe0ebeb9, + 0xe080e0a0, 0x8a5d8a10, 0x3bd23b52, 0x64d564ba, + 0xd8a0d888, 0xe784e7a5, 0x5f075fe8, 0x1b141b11, + 0x2cb52cc2, 0xfc90fcb4, 0x312c3127, 0x80a38065, + 0x73b2732a, 0x0c730c81, 0x794c795f, 0x6b546b41, + 0x4b924b02, 0x53745369, 0x9436948f, 0x8351831f, + 0x2a382a36, 0xc4b0c49c, 0x22bd22c8, 0xd55ad5f8, + 0xbdfcbdc3, 0x48604878, 0xff62ffce, 0x4c964c07, + 0x416c4177, 0xc742c7e6, 0xebf7eb24, 0x1c101c14, + 0x5d7c5d63, 0x36283622, 0x672767c0, 0xe98ce9af, + 0x441344f9, 0x149514ea, 0xf59cf5bb, 0xcfc7cf18, + 0x3f243f2d, 0xc046c0e3, 0x723b72db, 0x5470546c, + 0x29ca294c, 0xf0e3f035, 0x088508fe, 0xc6cbc617, + 0xf311f34f, 0x8cd08ce4, 0xa493a459, 0xcab8ca96, + 0x68a6683b, 0xb883b84d, 0x38203828, 0xe5ffe52e, + 0xad9fad56, 0x0b770b84, 0xc8c3c81d, 0x99cc99ff, + 0x580358ed, 0x196f199a, 0x0e080e0a, 0x95bf957e, + 0x70407050, 0xf7e7f730, 0x6e2b6ecf, 0x1fe21f6e, + 0xb579b53d, 0x090c090f, 0x61aa6134, 0x57825716, + 0x9f419f0b, 0x9d3a9d80, 0x11ea1164, 0x25b925cd, + 0xafe4afdd, 0x459a4508, 0xdfa4df8d, 0xa397a35c, + 0xea7eead5, 0x35da3558, 0xed7aedd0, 0x431743fc, + 0xf866f8cb, 0xfb94fbb1, 0x37a137d3, 0xfa1dfa40, + 0xc23dc268, 0xb4f0b4cc, 0x32de325d, 0x9cb39c71, + 0x560b56e7, 0xe372e3da, 0x87a78760, 0x151c151b, + 0xf9eff93a, 0x63d163bf, 0x345334a9, 0x9a3e9a85, + 0xb18fb142, 0x7c337cd1, 0x8826889b, 0x3d5f3da6, + 0xa1eca1d7, 0xe476e4df, 0x812a8194, 0x91499101, + 0x0f810ffb, 0xee88eeaa, 0x16ee1661, 0xd721d773, + 0x97c497f5, 0xa51aa5a8, 0xfeebfe3f, 0x6dd96db5, + 0x78c578ae, 0xc539c56d, 0x1d991de5, 0x76cd76a4, + 0x3ead3edc, 0xcb31cb67, 0xb68bb647, 0xef01ef5b, + 0x1218121e, 0x602360c5, 0x6add6ab0, 0x4d1f4df6, + 0xce4ecee9, 0xde2dde7c, 0x55f9559d, 0x7e487e5a, + 0x214f21b2, 0x03f2037a, 0xa065a026, 0x5e8e5e19, + 0x5a785a66, 0x655c654b, 0x6258624e, 0xfd19fd45, + 0x068d06f4, 0x40e54086, 0xf298f2be, 0x335733ac, + 0x17671790, 0x057f058e, 0xe805e85e, 0x4f644f7d, + 0x89af896a, 0x10631095, 0x74b6742f, 0x0afe0a75, + 0x5cf55c92, 0x9bb79b74, 0x2d3c2d33, 0x30a530d6, + 0x2ece2e49, 0x49e94989, 0x46684672, 0x77447755, + 0xa8e0a8d8, 0x964d9604, 0x284328bd, 0xa969a929, + 0xd929d979, 0x862e8691, 0xd1acd187, 0xf415f44a, + 0x8d598d15, 0xd6a8d682, 0xb90ab9bc, 0x429e420d, + 0xf66ef6c1, 0x2f472fb8, 0xdddfdd06, 0x23342339, + 0xcc35cc62, 0xf16af1c4, 0xc1cfc112, 0x85dc85eb, + 0x8f228f9e, 0x71c971a1, 0x90c090f0, 0xaa9baa53, + 0x018901f1, 0x8bd48be1, 0x4eed4e8c, 0x8eab8e6f, + 0xab12aba2, 0x6fa26f3e, 0xe60de654, 0xdb52dbf2, + 0x92bb927b, 0xb702b7b6, 0x692f69ca, 0x39a939d9, + 0xd3d7d30c, 0xa761a723, 0xa21ea2ad, 0xc3b4c399, + 0x6c506c44, 0x07040705, 0x04f6047f, 0x27c22746, + 0xac16aca7, 0xd025d076, 0x50865013, 0xdc56dcf7, + 0x8455841a, 0xe109e151, 0x7abe7a25, 0x139113ef, + + 0xd939a9d9, 0x90176790, 0x719cb371, 0xd2a6e8d2, + 0x05070405, 0x9852fd98, 0x6580a365, 0xdfe476df, + 0x08459a08, 0x024b9202, 0xa0e080a0, 0x665a7866, + 0xddafe4dd, 0xb06addb0, 0xbf63d1bf, 0x362a3836, + 0x54e60d54, 0x4320c643, 0x62cc3562, 0xbef298be, + 0x1e12181e, 0x24ebf724, 0xd7a1ecd7, 0x77416c77, + 0xbd2843bd, 0x32bc7532, 0xd47b37d4, 0x9b88269b, + 0x700dfa70, 0xf94413f9, 0xb1fb94b1, 0x5a7e485a, + 0x7a03f27a, 0xe48cd0e4, 0x47b68b47, 0x3c24303c, + 0xa5e784a5, 0x416b5441, 0x06dddf06, 0xc56023c5, + 0x45fd1945, 0xa33a5ba3, 0x68c23d68, 0x158d5915, + 0x21ecf321, 0x3166ae31, 0x3e6fa23e, 0x16578216, + 0x95106395, 0x5bef015b, 0x4db8834d, 0x91862e91, + 0xb56dd9b5, 0x1f83511f, 0x53aa9b53, 0x635d7c63, + 0x3b68a63b, 0x3ffeeb3f, 0xd630a5d6, 0x257abe25, + 0xa7ac16a7, 0x0f090c0f, 0x35f0e335, 0x23a76123, + 0xf090c0f0, 0xafe98caf, 0x809d3a80, 0x925cf592, + 0x810c7381, 0x27312c27, 0x76d02576, 0xe7560be7, + 0x7b92bb7b, 0xe9ce4ee9, 0xf10189f1, 0x9f1e6b9f, + 0xa93453a9, 0xc4f16ac4, 0x99c3b499, 0x975bf197, + 0x8347e183, 0x6b18e66b, 0xc822bdc8, 0x0e98450e, + 0x6e1fe26e, 0xc9b3f4c9, 0x2f74b62f, 0xcbf866cb, + 0xff99ccff, 0xea1495ea, 0xed5803ed, 0xf7dc56f7, + 0xe18bd4e1, 0x1b151c1b, 0xada21ead, 0x0cd3d70c, + 0x2be2fb2b, 0x1dc8c31d, 0x195e8e19, 0xc22cb5c2, + 0x8949e989, 0x12c1cf12, 0x7e95bf7e, 0x207dba20, + 0x6411ea64, 0x840b7784, 0x6dc5396d, 0x6a89af6a, + 0xd17c33d1, 0xa171c9a1, 0xceff62ce, 0x37bb7137, + 0xfb0f81fb, 0x3db5793d, 0x51e10951, 0xdc3eaddc, + 0x2d3f242d, 0xa476cda4, 0x9d55f99d, 0xee82d8ee, + 0x8640e586, 0xae78c5ae, 0xcd25b9cd, 0x04964d04, + 0x55774455, 0x0a0e080a, 0x13508613, 0x30f7e730, + 0xd337a1d3, 0x40fa1d40, 0x3461aa34, 0x8c4eed8c, + 0xb3b006b3, 0x6c54706c, 0x2a73b22a, 0x523bd252, + 0x0b9f410b, 0x8b027b8b, 0x88d8a088, 0x4ff3114f, + 0x67cb3167, 0x4627c246, 0xc06727c0, 0xb4fc90b4, + 0x28382028, 0x7f04f67f, 0x78486078, 0x2ee5ff2e, + 0x074c9607, 0x4b655c4b, 0xc72bb1c7, 0x6f8eab6f, + 0x0d429e0d, 0xbbf59cbb, 0xf2db52f2, 0xf34a1bf3, + 0xa63d5fa6, 0x59a49359, 0xbcb90abc, 0x3af9ef3a, + 0xef1391ef, 0xfe0885fe, 0x01914901, 0x6116ee61, + 0x7cde2d7c, 0xb2214fb2, 0x42b18f42, 0xdb723bdb, + 0xb82f47b8, 0x48bf8748, 0x2cae6d2c, 0xe3c046e3, + 0x573cd657, 0x859a3e85, 0x29a96929, 0x7d4f647d, + 0x94812a94, 0x492ece49, 0x17c6cb17, 0xca692fca, + 0xc3bdfcc3, 0x5ca3975c, 0x5ee8055e, 0xd0ed7ad0, + 0x87d1ac87, 0x8e057f8e, 0xba64d5ba, 0xa8a51aa8, + 0xb7264bb7, 0xb9be0eb9, 0x6087a760, 0xf8d55af8, + 0x22362822, 0x111b1411, 0xde753fde, 0x79d92979, + 0xaaee88aa, 0x332d3c33, 0x5f794c5f, 0xb6b702b6, + 0x96cab896, 0x5835da58, 0x9cc4b09c, 0xfc4317fc, + 0x1a84551a, 0xf64d1ff6, 0x1c598a1c, 0x38b27d38, + 0xac3357ac, 0x18cfc718, 0xf4068df4, 0x69537469, + 0x749bb774, 0xf597c4f5, 0x56ad9f56, 0xdae372da, + 0xd5ea7ed5, 0x4af4154a, 0x9e8f229e, 0xa2ab12a2, + 0x4e62584e, 0xe85f07e8, 0xe51d99e5, 0x39233439, + 0xc1f66ec1, 0x446c5044, 0x5d32de5d, 0x72466872, + 0x26a06526, 0x93cdbc93, 0x03dadb03, 0xc6baf8c6, + 0xfa9ec8fa, 0x82d6a882, 0xcf6e2bcf, 0x50704050, + 0xeb85dceb, 0x750afe75, 0x8a93328a, 0x8ddfa48d, + 0x4c29ca4c, 0x141c1014, 0x73d72173, 0xccb4f0cc, + 0x09d4d309, 0x108a5d10, 0xe2510fe2, 0x00000000, + 0x9a196f9a, 0xe01a9de0, 0x8f94368f, 0xe6c742e6, + 0xecc94aec, 0xfdd25efd, 0xab7fc1ab, 0xd8a8e0d8}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/threefish.cpp b/extension/third_party/cryptopp/threefish.cpp new file mode 100644 index 00000000..bf038ab8 --- /dev/null +++ b/extension/third_party/cryptopp/threefish.cpp @@ -0,0 +1,503 @@ +// threefish.cpp - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. Kuro's code is +// available at http://cppcrypto.sourceforge.net/. + +#include "pch.h" +#include "config.h" + +#include "threefish.h" +#include "misc.h" +#include "algparam.h" +#include "argnames.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::word64; +using CryptoPP::rotlConstant; +using CryptoPP::rotrConstant; +using CryptoPP::rotlVariable; +using CryptoPP::rotrVariable; + +template +inline void G256(word64& G0, word64& G1, word64& G2, word64& G3) +{ + G0 += G1; + G1 = rotlConstant(G1) ^ G0; + G2 += G3; + G3 = rotlConstant(G3) ^ G2; +} + +template +inline void IG256(word64& G0, word64& G1, word64& G2, word64& G3) +{ + G3 = rotrConstant(G3 ^ G2); + G2 -= G3; + G1 = rotrConstant(G1 ^ G0); + G0 -= G1; +} + +#define KS256(r) \ + G0 += m_rkey[(r + 1) % 5]; \ + G1 += m_rkey[(r + 2) % 5] + m_tweak[(r + 1) % 3]; \ + G2 += m_rkey[(r + 3) % 5] + m_tweak[(r + 2) % 3]; \ + G3 += m_rkey[(r + 4) % 5] + r + 1; + +#define IKS256(r) \ + G0 -= m_rkey[(r + 1) % 5]; \ + G1 -= (m_rkey[(r + 2) % 5] + m_tweak[(r + 1) % 3]); \ + G2 -= (m_rkey[(r + 3) % 5] + m_tweak[(r + 2) % 3]); \ + G3 -= (m_rkey[(r + 4) % 5] + r + 1); + +#define G256x8(r) \ + G256<14, 16>(G0, G1, G2, G3); \ + G256<52, 57>(G0, G3, G2, G1); \ + G256<23, 40>(G0, G1, G2, G3); \ + G256< 5, 37>(G0, G3, G2, G1); \ + KS256(r); \ + G256<25, 33>(G0, G1, G2, G3); \ + G256<46, 12>(G0, G3, G2, G1); \ + G256<58, 22>(G0, G1, G2, G3); \ + G256<32, 32>(G0, G3, G2, G1); \ + KS256(r + 1); + +#define IG256x8(r) \ + IG256<32, 32>(G0, G3, G2, G1); \ + IG256<58, 22>(G0, G1, G2, G3); \ + IG256<46, 12>(G0, G3, G2, G1); \ + IG256<25, 33>(G0, G1, G2, G3); \ + IKS256(r); \ + IG256< 5, 37>(G0, G3, G2, G1); \ + IG256<23, 40>(G0, G1, G2, G3); \ + IG256<52, 57>(G0, G3, G2, G1); \ + IG256<14, 16>(G0, G1, G2, G3); \ + IKS256(r - 1); + +/////////////////// + +template +inline void G512(word64& G0, word64& G1, word64& G2, word64& G3, word64& G4, word64& G5, word64& G6, word64& G7) +{ + G0 += G1; + G1 = rotlConstant(G1) ^ G0; + G2 += G3; + G3 = rotlConstant(G3) ^ G2; + G4 += G5; + G5 = rotlConstant(G5) ^ G4; + G6 += G7; + G7 = rotlConstant(G7) ^ G6; +} + +template +inline void IG512(word64& G0, word64& G1, word64& G2, word64& G3, word64& G4, word64& G5, word64& G6, word64& G7) +{ + G7 = rotrConstant(G7 ^ G6); + G6 -= G7; + G5 = rotrConstant(G5 ^ G4); + G4 -= G5; + G3 = rotrConstant(G3 ^ G2); + G2 -= G3; + G1 = rotrConstant(G1 ^ G0); + G0 -= G1; +} + +#define KS512(r) \ + G0 += m_rkey[(r + 1) % 9]; \ + G1 += m_rkey[(r + 2) % 9]; \ + G2 += m_rkey[(r + 3) % 9]; \ + G3 += m_rkey[(r + 4) % 9]; \ + G4 += m_rkey[(r + 5) % 9]; \ + G5 += m_rkey[(r + 6) % 9] + m_tweak[(r + 1) % 3]; \ + G6 += m_rkey[(r + 7) % 9] + m_tweak[(r + 2) % 3]; \ + G7 += m_rkey[(r + 8) % 9] + r + 1; + +#define IKS512(r) \ + G0 -= m_rkey[(r + 1) % 9]; \ + G1 -= m_rkey[(r + 2) % 9]; \ + G2 -= m_rkey[(r + 3) % 9]; \ + G3 -= m_rkey[(r + 4) % 9]; \ + G4 -= m_rkey[(r + 5) % 9]; \ + G5 -= (m_rkey[(r + 6) % 9] + m_tweak[(r + 1) % 3]); \ + G6 -= (m_rkey[(r + 7) % 9] + m_tweak[(r + 2) % 3]); \ + G7 -= (m_rkey[(r + 8) % 9] + r + 1); + +#define IG512x8(r) \ + IG512< 8, 35, 56, 22>(G6, G1, G0, G7, G2, G5, G4, G3); \ + IG512<25, 29, 39, 43>(G4, G1, G6, G3, G0, G5, G2, G7); \ + IG512<13, 50, 10, 17>(G2, G1, G4, G7, G6, G5, G0, G3); \ + IG512<39, 30, 34, 24>(G0, G1, G2, G3, G4, G5, G6, G7); \ + IKS512(r) \ + IG512<44, 9, 54, 56>(G6, G1, G0, G7, G2, G5, G4, G3); \ + IG512<17, 49, 36, 39>(G4, G1, G6, G3, G0, G5, G2, G7); \ + IG512<33, 27, 14, 42>(G2, G1, G4, G7, G6, G5, G0, G3); \ + IG512<46, 36, 19, 37>(G0, G1, G2, G3, G4, G5, G6, G7); \ + IKS512(r - 1) + +#define G512x8(r) \ + G512<46, 36, 19, 37>(G0, G1, G2, G3, G4, G5, G6, G7); \ + G512<33, 27, 14, 42>(G2, G1, G4, G7, G6, G5, G0, G3); \ + G512<17, 49, 36, 39>(G4, G1, G6, G3, G0, G5, G2, G7); \ + G512<44, 9, 54, 56>(G6, G1, G0, G7, G2, G5, G4, G3); \ + KS512(r) \ + G512<39, 30, 34, 24>(G0, G1, G2, G3, G4, G5, G6, G7); \ + G512<13, 50, 10, 17>(G2, G1, G4, G7, G6, G5, G0, G3); \ + G512<25, 29, 39, 43>(G4, G1, G6, G3, G0, G5, G2, G7); \ + G512< 8, 35, 56, 22>(G6, G1, G0, G7, G2, G5, G4, G3); \ + KS512(r + 1) + +/////////////////// + +template +inline void G1024A(word64& G0, word64& G1, word64& G2, word64& G3, + word64& G4, word64& G5, word64& G6, word64& G7) +{ + G0 += G1; + G1 = rotlConstant(G1) ^ G0; + G2 += G3; + G3 = rotlConstant(G3) ^ G2; + G4 += G5; + G5 = rotlConstant(G5) ^ G4; + G6 += G7; + G7 = rotlConstant(G7) ^ G6; +} + +template +inline void G1024B(word64& G8, word64& G9, word64& G10, word64& G11, + word64& G12, word64& G13, word64& G14, word64& G15) +{ + G8 += G9; + G9 = rotlConstant(G9) ^ G8; + G10 += G11; + G11 = rotlConstant(G11) ^ G10; + G12 += G13; + G13 = rotlConstant(G13) ^ G12; + G14 += G15; + G15 = rotlConstant(G15) ^ G14; +} + +template +inline void G1024(word64& G0, word64& G1, word64& G2, word64& G3, word64& G4, word64& G5, + word64& G6, word64& G7, word64& G8, word64& G9, word64& G10, word64& G11, word64& G12, + word64& G13, word64& G14, word64& G15) +{ + // The extra gyrations promote inlining. Without it Threefish1024 looses 10 cpb. + G1024A(G0, G1, G2, G3, G4, G5, G6, G7); + G1024B(G8, G9, G10, G11, G12, G13, G14, G15); +} + +template +inline void IG1024A(word64& G8, word64& G9, word64& G10, word64& G11, + word64& G12, word64& G13, word64& G14, word64& G15) +{ + G15 = rotrConstant(G15 ^ G14); + G14 -= G15; + G13 = rotrConstant(G13 ^ G12); + G12 -= G13; + G11 = rotrConstant(G11 ^ G10); + G10 -= G11; + G9 = rotrConstant(G9 ^ G8); + G8 -= G9; +} + +template +inline void IG1024B(word64& G0, word64& G1, word64& G2, word64& G3, + word64& G4, word64& G5, word64& G6, word64& G7) +{ + G7 = rotrConstant(G7 ^ G6); + G6 -= G7; + G5 = rotrConstant(G5 ^ G4); + G4 -= G5; + G3 = rotrConstant(G3 ^ G2); + G2 -= G3; + G1 = rotrConstant(G1 ^ G0); + G0 -= G1; +} + +template +inline void IG1024(word64& G0, word64& G1, word64& G2, word64& G3, word64& G4, word64& G5, + word64& G6, word64& G7, word64& G8, word64& G9, word64& G10, word64& G11, word64& G12, + word64& G13, word64& G14, word64& G15) +{ + // The extra gyrations promote inlining. Without it Threefish1024 looses 10 cpb. + IG1024A(G8, G9, G10, G11, G12, G13, G14, G15); + IG1024B(G0, G1, G2, G3, G4, G5, G6, G7); +} + +#define KS1024(r) \ + G0 += m_rkey[(r + 1) % 17]; \ + G1 += m_rkey[(r + 2) % 17]; \ + G2 += m_rkey[(r + 3) % 17]; \ + G3 += m_rkey[(r + 4) % 17]; \ + G4 += m_rkey[(r + 5) % 17]; \ + G5 += m_rkey[(r + 6) % 17]; \ + G6 += m_rkey[(r + 7) % 17]; \ + G7 += m_rkey[(r + 8) % 17]; \ + G8 += m_rkey[(r + 9) % 17]; \ + G9 += m_rkey[(r + 10) % 17]; \ + G10 += m_rkey[(r + 11) % 17]; \ + G11 += m_rkey[(r + 12) % 17]; \ + G12 += m_rkey[(r + 13) % 17]; \ + G13 += m_rkey[(r + 14) % 17] + m_tweak[(r + 1) % 3]; \ + G14 += m_rkey[(r + 15) % 17] + m_tweak[(r + 2) % 3]; \ + G15 += m_rkey[(r + 16) % 17] + r + 1; + +#define IKS1024(r) \ + G0 -= m_rkey[(r + 1) % 17]; \ + G1 -= m_rkey[(r + 2) % 17]; \ + G2 -= m_rkey[(r + 3) % 17]; \ + G3 -= m_rkey[(r + 4) % 17]; \ + G4 -= m_rkey[(r + 5) % 17]; \ + G5 -= m_rkey[(r + 6) % 17]; \ + G6 -= m_rkey[(r + 7) % 17]; \ + G7 -= m_rkey[(r + 8) % 17]; \ + G8 -= m_rkey[(r + 9) % 17]; \ + G9 -= m_rkey[(r + 10) % 17]; \ + G10 -= m_rkey[(r + 11) % 17]; \ + G11 -= m_rkey[(r + 12) % 17]; \ + G12 -= m_rkey[(r + 13) % 17]; \ + G13 -= (m_rkey[(r + 14) % 17] + m_tweak[(r + 1) % 3]); \ + G14 -= (m_rkey[(r + 15) % 17] + m_tweak[(r + 2) % 3]); \ + G15 -= (m_rkey[(r + 16) % 17] + r + 1); + +#define G1024x8(r) \ + G1024A<24, 13, 8, 47>(G0, G1, G2, G3, G4, G5, G6, G7); \ + G1024B< 8, 17, 22, 37>(G8, G9, G10, G11, G12, G13, G14, G15); \ + G1024A<38, 19, 10, 55>(G0, G9, G2, G13, G6, G11, G4, G15); \ + G1024B<49, 18, 23, 52>(G10, G7, G12, G3, G14, G5, G8, G1); \ + G1024A<33, 4, 51, 13>(G0, G7, G2, G5, G4, G3, G6, G1); \ + G1024B<34, 41, 59, 17>(G12, G15, G14, G13, G8, G11, G10, G9); \ + G1024A< 5, 20, 48, 41>(G0, G15, G2, G11, G6, G13, G4, G9); \ + G1024B<47, 28, 16, 25>(G14, G1, G8, G5, G10, G3, G12, G7); \ + KS1024(r); \ + G1024A<41, 9, 37, 31>(G0, G1, G2, G3, G4, G5, G6, G7); \ + G1024B<12, 47, 44, 30>(G8, G9, G10, G11, G12, G13, G14, G15); \ + G1024A<16, 34, 56, 51>(G0, G9, G2, G13, G6, G11, G4, G15); \ + G1024B< 4, 53, 42, 41>(G10, G7, G12, G3, G14, G5, G8, G1); \ + G1024A<31, 44, 47, 46>(G0, G7, G2, G5, G4, G3, G6, G1); \ + G1024B<19, 42, 44, 25>(G12, G15, G14, G13, G8, G11, G10, G9); \ + G1024A< 9, 48, 35, 52>(G0, G15, G2, G11, G6, G13, G4, G9); \ + G1024B<23, 31, 37, 20>(G14, G1, G8, G5, G10, G3, G12, G7); \ + KS1024(r + 1); + +#define IG1024x8(r) \ + IG1024A< 9, 48, 35, 52>(G0, G15, G2, G11, G6, G13, G4, G9); \ + IG1024B<23, 31, 37, 20>(G14, G1, G8, G5, G10, G3, G12, G7); \ + IG1024A<31, 44, 47, 46>(G0, G7, G2, G5, G4, G3, G6, G1); \ + IG1024B<19, 42, 44, 25>(G12, G15, G14, G13, G8, G11, G10, G9); \ + IG1024A<16, 34, 56, 51>(G0, G9, G2, G13, G6, G11, G4, G15); \ + IG1024B< 4, 53, 42, 41>(G10, G7, G12, G3, G14, G5, G8, G1); \ + IG1024A<41, 9, 37, 31>(G0, G1, G2, G3, G4, G5, G6, G7); \ + IG1024B<12, 47, 44, 30>(G8, G9, G10, G11, G12, G13, G14, G15); \ + IKS1024(r); \ + IG1024A< 5, 20, 48, 41>(G0, G15, G2, G11, G6, G13, G4, G9); \ + IG1024B<47, 28, 16, 25>(G14, G1, G8, G5, G10, G3, G12, G7); \ + IG1024A<33, 4, 51, 13>(G0, G7, G2, G5, G4, G3, G6, G1); \ + IG1024B<34, 41, 59, 17>(G12, G15, G14, G13, G8, G11, G10, G9); \ + IG1024A<38, 19, 10, 55>(G0, G9, G2, G13, G6, G11, G4, G15); \ + IG1024B<49, 18, 23, 52>(G10, G7, G12, G3, G14, G5, G8, G1); \ + IG1024A<24, 13, 8, 47>(G0, G1, G2, G3, G4, G5, G6, G7); \ + IG1024B< 8, 17, 22, 37>(G8, G9, G10, G11, G12, G13, G14, G15); \ + IKS1024(r - 1); + +ANONYMOUS_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +NAMESPACE_BEGIN(CryptoPP) + +void Threefish256::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + // Blocksize is Keylength for Threefish + CRYPTOPP_ASSERT(keyLength == KEYLENGTH); + + m_rkey.New(5); + m_wspace.New(4); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_rkey.begin(), 4, userKey, keyLength); + m_rkey[4] = W64LIT(0x1BD11BDAA9FC1A22) ^ m_rkey[0] ^ m_rkey[1] ^ m_rkey[2] ^ m_rkey[3]; + + SetTweak(params); +} + +void Threefish256::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3); + + G0 += m_rkey[0]; G1 += m_rkey[1]; G2 += m_rkey[2]; + G3 += m_rkey[3]; G1 += m_tweak[0]; G2 += m_tweak[1]; + + G256x8(0); G256x8(2); G256x8(4); G256x8(6); G256x8(8); + G256x8(10); G256x8(12); G256x8(14); G256x8(16); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3); +} + +void Threefish256::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3); + + G0 -= m_rkey[3]; G1 -= m_rkey[4]; G2 -= m_rkey[0]; G3 -= m_rkey[1]; + G1 -= m_tweak[0]; G2 -= m_tweak[1]; G3 -= 18; + + IG256x8(16); IG256x8(14); IG256x8(12); IG256x8(10); + IG256x8(8); IG256x8(6); IG256x8(4); IG256x8(2); IG256x8(0); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3); +} + +///////////////////////////////////////////////////////////////// + +void Threefish512::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + // Blocksize is Keylength for Threefish + CRYPTOPP_ASSERT(keyLength == KEYLENGTH); + + m_rkey.New(9); + m_wspace.New(8); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_rkey.begin(), 8, userKey, keyLength); + m_rkey[8] = W64LIT(0x1BD11BDAA9FC1A22) ^ m_rkey[0] ^ m_rkey[1] ^ m_rkey[2] ^ m_rkey[3] ^ + m_rkey[4] ^ m_rkey[5] ^ m_rkey[6] ^ m_rkey[7]; + + SetTweak(params); +} + +void Threefish512::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + word64 &G4=m_wspace[4], &G5=m_wspace[5], &G6=m_wspace[6], &G7=m_wspace[7]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7); + + // 34 integer instructions total + G0 += m_rkey[0]; G1 += m_rkey[1]; G2 += m_rkey[2]; G3 += m_rkey[3]; + G4 += m_rkey[4]; G5 += m_rkey[5]; G6 += m_rkey[6]; G7 += m_rkey[7]; + G5 += m_tweak[0]; G6 += m_tweak[1]; + + G512x8(0); G512x8(2); G512x8(4); G512x8(6); G512x8(8); + G512x8(10); G512x8(12); G512x8(14); G512x8(16); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7); +} + +void Threefish512::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + word64 &G4=m_wspace[4], &G5=m_wspace[5], &G6=m_wspace[6], &G7=m_wspace[7]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7); + + G0 -= m_rkey[0]; G1 -= m_rkey[1]; G2 -= m_rkey[2]; G3 -= m_rkey[3]; + G4 -= m_rkey[4]; G5 -= m_rkey[5]; G6 -= m_rkey[6]; G7 -= m_rkey[7]; + G5 -= m_tweak[0]; G6 -= m_tweak[1]; G7 -= 18; + + IG512x8(16); IG512x8(14); IG512x8(12); IG512x8(10); + IG512x8(8); IG512x8(6); IG512x8(4); IG512x8(2); IG512x8(0); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7); +} + +///////////////////////////////////////////////////////////////// + +void Threefish1024::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) +{ + // Blocksize is Keylength for Threefish + CRYPTOPP_ASSERT(keyLength == KEYLENGTH); + + m_rkey.New(17); + m_wspace.New(16); + + GetUserKey(LITTLE_ENDIAN_ORDER, m_rkey.begin(), 16, userKey, keyLength); + m_rkey[16] = W64LIT(0x1BD11BDAA9FC1A22) ^ m_rkey[0] ^ m_rkey[1] ^ m_rkey[2] ^ m_rkey[3] ^ m_rkey[4] ^ + m_rkey[5] ^ m_rkey[6] ^ m_rkey[7] ^ m_rkey[8] ^ m_rkey[9] ^ m_rkey[10] ^ m_rkey[11] ^ m_rkey[12] ^ + m_rkey[13] ^ m_rkey[14] ^ m_rkey[15]; + + SetTweak(params); +} + +void Threefish1024::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + word64 &G4=m_wspace[4], &G5=m_wspace[5], &G6=m_wspace[6], &G7=m_wspace[7]; + word64 &G8=m_wspace[8], &G9=m_wspace[9], &G10=m_wspace[10], &G11=m_wspace[11]; + word64 &G12=m_wspace[12], &G13=m_wspace[13], &G14=m_wspace[14], &G15=m_wspace[15]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7)(G8)(G9)(G10)(G11)(G12)(G13)(G14)(G15); + + G0 += m_rkey[0]; G1 += m_rkey[1]; G2 += m_rkey[2]; G3 += m_rkey[3]; + G4 += m_rkey[4]; G5 += m_rkey[5]; G6 += m_rkey[6]; G7 += m_rkey[7]; + G8 += m_rkey[8]; G9 += m_rkey[9]; G10 += m_rkey[10]; G11 += m_rkey[11]; + G12 += m_rkey[12]; G13 += m_rkey[13]; G14 += m_rkey[14]; G15 += m_rkey[15]; + G13 += m_tweak[0]; G14 += m_tweak[1]; + + G1024x8(0); G1024x8(2); G1024x8(4); G1024x8(6); G1024x8(8); + G1024x8(10); G1024x8(12); G1024x8(14); G1024x8(16); G1024x8(18); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7)(G8)(G9)(G10)(G11)(G12)(G13)(G14)(G15); +} + +void Threefish1024::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word64 &G0=m_wspace[0], &G1=m_wspace[1], &G2=m_wspace[2], &G3=m_wspace[3]; + word64 &G4=m_wspace[4], &G5=m_wspace[5], &G6=m_wspace[6], &G7=m_wspace[7]; + word64 &G8=m_wspace[8], &G9=m_wspace[9], &G10=m_wspace[10], &G11=m_wspace[11]; + word64 &G12=m_wspace[12], &G13=m_wspace[13], &G14=m_wspace[14], &G15=m_wspace[15]; + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef GetBlock InBlock; + InBlock iblk(inBlock); + iblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7)(G8)(G9)(G10)(G11)(G12)(G13)(G14)(G15); + + G0 -= m_rkey[3]; G1 -= m_rkey[4]; G2 -= m_rkey[5]; G3 -= m_rkey[6]; + G4 -= m_rkey[7]; G5 -= m_rkey[8]; G6 -= m_rkey[9]; G7 -= m_rkey[10]; + G8 -= m_rkey[11]; G9 -= m_rkey[12]; G10 -= m_rkey[13]; G11 -= m_rkey[14]; + G12 -= m_rkey[15]; G13 -= m_rkey[16]; G14 -= m_rkey[0]; G15 -= m_rkey[1]; + G13 -= m_tweak[2]; G14 -= m_tweak[0]; G15 -= 20; + + IG1024x8(18); IG1024x8(16); IG1024x8(14); IG1024x8(12); IG1024x8(10); + IG1024x8(8); IG1024x8(6); IG1024x8(4); IG1024x8(2); IG1024x8(0); + + // Reverse bytes on BigEndian; align pointer on LittleEndian + typedef PutBlock OutBlock; + OutBlock oblk(xorBlock, outBlock); + oblk(G0)(G1)(G2)(G3)(G4)(G5)(G6)(G7)(G8)(G9)(G10)(G11)(G12)(G13)(G14)(G15); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/threefish.h b/extension/third_party/cryptopp/threefish.h new file mode 100644 index 00000000..cb53d78a --- /dev/null +++ b/extension/third_party/cryptopp/threefish.h @@ -0,0 +1,201 @@ +// threefish.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. Kuro's code is +// available at http://cppcrypto.sourceforge.net/. + +/// \file Threefish.h +/// \brief Classes for the Threefish block cipher +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_THREEFISH_H +#define CRYPTOPP_THREEFISH_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" +#include "argnames.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Threefish block cipher information +/// \tparam BS block size of the cipher, in bytes +/// \since Crypto++ 6.0 +template +struct Threefish_Info : public FixedBlockSize, FixedKeyLength +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Threefish-" + IntToString(BS*8) + "(" + IntToString(BS*8) + ")"; + } +}; + +/// \brief Threefish block cipher base class +/// \tparam BS block size of the cipher, in bytes +/// \details User code should use Threefish256, Threefish512, Threefish1024 +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +template +struct CRYPTOPP_NO_VTABLE Threefish_Base +{ + virtual ~Threefish_Base() {} + + void SetTweak(const NameValuePairs ¶ms) + { + m_tweak.New(3); + ConstByteArrayParameter t; + if (params.GetValue(Name::Tweak(), t)) + { + // Tweak size is fixed at 16 for Threefish + CRYPTOPP_ASSERT(t.size() == 16); + GetUserKey(LITTLE_ENDIAN_ORDER, m_tweak.begin(), 2, t.begin(), 16); + m_tweak[2] = m_tweak[0] ^ m_tweak[1]; + } + else + { + std::memset(m_tweak.begin(), 0x00, 24); + } + } + + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // workspace + AlignedSecBlock64 m_rkey; // keys + AlignedSecBlock64 m_tweak; +}; + +/// \brief Threefish 256-bit block cipher +/// \details Threefish256 provides 256-bit block size. The valid key size is 256-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish256 : public Threefish_Info<32>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<32>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish256::Encryption Threefish256Encryption; +typedef Threefish256::Decryption Threefish256Decryption; + +/// \brief Threefish 512-bit block cipher +/// \details Threefish512 provides 512-bit block size. The valid key size is 512-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish512 : public Threefish_Info<64>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<64>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish512::Encryption Threefish512Encryption; +typedef Threefish512::Decryption Threefish512Decryption; + +/// \brief Threefish 1024-bit block cipher +/// \details Threefish1024 provides 1024-bit block size. The valid key size is 1024-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish512, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish1024 : public Threefish_Info<128>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<128>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Encryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish1024::Encryption Threefish1024Encryption; +typedef Threefish1024::Decryption Threefish1024Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_THREEFISH_H diff --git a/extension/third_party/cryptopp/tiger.cpp b/extension/third_party/cryptopp/tiger.cpp new file mode 100644 index 00000000..c71cdc2f --- /dev/null +++ b/extension/third_party/cryptopp/tiger.cpp @@ -0,0 +1,282 @@ +// tiger.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" +#include "config.h" + +#include "tiger.h" +#include "misc.h" +#include "cpu.h" + +#if defined(CRYPTOPP_DISABLE_TIGER_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +NAMESPACE_BEGIN(CryptoPP) + +std::string Tiger::AlgorithmProvider() const +{ +#ifndef CRYPTOPP_DISABLE_TIGER_ASM +# if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +# endif +#endif + return "C++"; +} + +void Tiger::InitState(HashWordType *state) +{ + state[0] = W64LIT(0x0123456789ABCDEF); + state[1] = W64LIT(0xFEDCBA9876543210); + state[2] = W64LIT(0xF096A5B4C3B2E187); +} + +void Tiger::TruncatedFinal(byte *digest, size_t digestSize) +{ + CRYPTOPP_ASSERT(digest != NULLPTR); + ThrowIfInvalidTruncatedSize(digestSize); + + PadLastBlock(56, 0x01); + CorrectEndianess(m_data, m_data, 56); + + m_data[7] = GetBitCountLo(); + + Transform(m_state, m_data); + CorrectEndianess(m_state, m_state, DigestSize()); + memcpy(digest, m_state, digestSize); + + Restart(); // reinit for next use +} + +void Tiger::Transform (word64 *state, const word64 *data) +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 + if (HasSSE2()) + { +#ifdef __GNUC__ + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86(bx) +#else + AS2( lea edx, [table]) + AS2( mov eax, state) + AS2( mov esi, data) +#endif + AS2( movq mm0, [eax]) + AS2( movq mm1, [eax+1*8]) + AS2( movq mm5, mm1) + AS2( movq mm2, [eax+2*8]) + AS2( movq mm7, [edx+4*2048+0*8]) + AS2( movq mm6, [edx+4*2048+1*8]) + AS2( mov ecx, esp) + AS2( and esp, 0xfffffff0) + AS2( sub esp, 8*8) + AS_PUSH_IF86(cx) + +#define SSE2_round(a,b,c,x,mul) \ + AS2( pxor c, [x])\ + AS2( movd ecx, c)\ + AS2( movzx edi, cl)\ + AS2( movq mm3, [edx+0*2048+edi*8])\ + AS2( movzx edi, ch)\ + AS2( movq mm4, [edx+3*2048+edi*8])\ + AS2( shr ecx, 16)\ + AS2( movzx edi, cl)\ + AS2( pxor mm3, [edx+1*2048+edi*8])\ + AS2( movzx edi, ch)\ + AS2( pxor mm4, [edx+2*2048+edi*8])\ + AS3( pextrw ecx, c, 2)\ + AS2( movzx edi, cl)\ + AS2( pxor mm3, [edx+2*2048+edi*8])\ + AS2( movzx edi, ch)\ + AS2( pxor mm4, [edx+1*2048+edi*8])\ + AS3( pextrw ecx, c, 3)\ + AS2( movzx edi, cl)\ + AS2( pxor mm3, [edx+3*2048+edi*8])\ + AS2( psubq a, mm3)\ + AS2( movzx edi, ch)\ + AS2( pxor mm4, [edx+0*2048+edi*8])\ + AS2( paddq b, mm4)\ + SSE2_mul_##mul(b) + +#define SSE2_mul_5(b) \ + AS2( movq mm3, b)\ + AS2( psllq b, 2)\ + AS2( paddq b, mm3) + +#define SSE2_mul_7(b) \ + AS2( movq mm3, b)\ + AS2( psllq b, 3)\ + AS2( psubq b, mm3) + +#define SSE2_mul_9(b) \ + AS2( movq mm3, b)\ + AS2( psllq b, 3)\ + AS2( paddq b, mm3) + +#define label2_5 1 +#define label2_7 2 +#define label2_9 3 + +#define SSE2_pass(A,B,C,mul,X) \ + AS2( xor ebx, ebx)\ + ASL(mul)\ + SSE2_round(A,B,C,X+0*8+ebx,mul)\ + SSE2_round(B,C,A,X+1*8+ebx,mul)\ + AS2( cmp ebx, 6*8)\ + ASJ( je, label2_##mul, f)\ + SSE2_round(C,A,B,X+2*8+ebx,mul)\ + AS2( add ebx, 3*8)\ + ASJ( jmp, mul, b)\ + ASL(label2_##mul) + +#define SSE2_key_schedule(Y,X) \ + AS2( movq mm3, [X+7*8])\ + AS2( pxor mm3, mm6)\ + AS2( movq mm4, [X+0*8])\ + AS2( psubq mm4, mm3)\ + AS2( movq [Y+0*8], mm4)\ + AS2( pxor mm4, [X+1*8])\ + AS2( movq mm3, mm4)\ + AS2( movq [Y+1*8], mm4)\ + AS2( paddq mm4, [X+2*8])\ + AS2( pxor mm3, mm7)\ + AS2( psllq mm3, 19)\ + AS2( movq [Y+2*8], mm4)\ + AS2( pxor mm3, mm4)\ + AS2( movq mm4, [X+3*8])\ + AS2( psubq mm4, mm3)\ + AS2( movq [Y+3*8], mm4)\ + AS2( pxor mm4, [X+4*8])\ + AS2( movq mm3, mm4)\ + AS2( movq [Y+4*8], mm4)\ + AS2( paddq mm4, [X+5*8])\ + AS2( pxor mm3, mm7)\ + AS2( psrlq mm3, 23)\ + AS2( movq [Y+5*8], mm4)\ + AS2( pxor mm3, mm4)\ + AS2( movq mm4, [X+6*8])\ + AS2( psubq mm4, mm3)\ + AS2( movq [Y+6*8], mm4)\ + AS2( pxor mm4, [X+7*8])\ + AS2( movq mm3, mm4)\ + AS2( movq [Y+7*8], mm4)\ + AS2( paddq mm4, [Y+0*8])\ + AS2( pxor mm3, mm7)\ + AS2( psllq mm3, 19)\ + AS2( movq [Y+0*8], mm4)\ + AS2( pxor mm3, mm4)\ + AS2( movq mm4, [Y+1*8])\ + AS2( psubq mm4, mm3)\ + AS2( movq [Y+1*8], mm4)\ + AS2( pxor mm4, [Y+2*8])\ + AS2( movq mm3, mm4)\ + AS2( movq [Y+2*8], mm4)\ + AS2( paddq mm4, [Y+3*8])\ + AS2( pxor mm3, mm7)\ + AS2( psrlq mm3, 23)\ + AS2( movq [Y+3*8], mm4)\ + AS2( pxor mm3, mm4)\ + AS2( movq mm4, [Y+4*8])\ + AS2( psubq mm4, mm3)\ + AS2( movq [Y+4*8], mm4)\ + AS2( pxor mm4, [Y+5*8])\ + AS2( movq [Y+5*8], mm4)\ + AS2( paddq mm4, [Y+6*8])\ + AS2( movq [Y+6*8], mm4)\ + AS2( pxor mm4, [edx+4*2048+2*8])\ + AS2( movq mm3, [Y+7*8])\ + AS2( psubq mm3, mm4)\ + AS2( movq [Y+7*8], mm3) + + SSE2_pass(mm0, mm1, mm2, 5, esi) + SSE2_key_schedule(esp+4, esi) + SSE2_pass(mm2, mm0, mm1, 7, esp+4) + SSE2_key_schedule(esp+4, esp+4) + SSE2_pass(mm1, mm2, mm0, 9, esp+4) + + AS2( pxor mm0, [eax+0*8]) + AS2( movq [eax+0*8], mm0) + AS2( psubq mm1, mm5) + AS2( movq [eax+1*8], mm1) + AS2( paddq mm2, [eax+2*8]) + AS2( movq [eax+2*8], mm2) + + AS_POP_IF86(sp) + AS1( emms) + +#ifdef __GNUC__ + AS_POP_IF86(bx) + ATT_PREFIX + : + : "a" (state), "S" (data), "d" (table) + : "%ecx", "%edi", "memory", "cc" + ); +#endif + } + else +#endif + { + word64 a = state[0]; + word64 b = state[1]; + word64 c = state[2]; + word64 Y[8]; + +#define t1 (table) +#define t2 (table+256) +#define t3 (table+256*2) +#define t4 (table+256*3) + +#define round(a,b,c,x,mul) \ + c ^= x; \ + a -= t1[GETBYTE(c,0)] ^ t2[GETBYTE(c,2)] ^ t3[GETBYTE(c,4)] ^ t4[GETBYTE(c,6)]; \ + b += t4[GETBYTE(c,1)] ^ t3[GETBYTE(c,3)] ^ t2[GETBYTE(c,5)] ^ t1[GETBYTE(c,7)]; \ + b *= mul + +#define pass(a,b,c,mul,X) {\ + int i=0;\ + while (true)\ + {\ + round(a,b,c,X[i+0],mul); \ + round(b,c,a,X[i+1],mul); \ + if (i==6)\ + break;\ + round(c,a,b,X[i+2],mul); \ + i+=3;\ + }} + +#define key_schedule(Y,X) \ + Y[0] = X[0] - (X[7]^W64LIT(0xA5A5A5A5A5A5A5A5)); \ + Y[1] = X[1] ^ Y[0]; \ + Y[2] = X[2] + Y[1]; \ + Y[3] = X[3] - (Y[2] ^ ((~Y[1])<<19)); \ + Y[4] = X[4] ^ Y[3]; \ + Y[5] = X[5] + Y[4]; \ + Y[6] = X[6] - (Y[5] ^ ((~Y[4])>>23)); \ + Y[7] = X[7] ^ Y[6]; \ + Y[0] += Y[7]; \ + Y[1] -= Y[0] ^ ((~Y[7])<<19); \ + Y[2] ^= Y[1]; \ + Y[3] += Y[2]; \ + Y[4] -= Y[3] ^ ((~Y[2])>>23); \ + Y[5] ^= Y[4]; \ + Y[6] += Y[5]; \ + Y[7] -= Y[6] ^ W64LIT(0x0123456789ABCDEF) + + pass(a,b,c,5,data); + key_schedule(Y,data); + pass(c,a,b,7,Y); + key_schedule(Y,Y); + pass(b,c,a,9,Y); + + state[0] = a ^ state[0]; + state[1] = b - state[1]; + state[2] = c + state[2]; + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/tiger.h b/extension/third_party/cryptopp/tiger.h new file mode 100644 index 00000000..580d6ed6 --- /dev/null +++ b/extension/third_party/cryptopp/tiger.h @@ -0,0 +1,61 @@ +// tiger.h - originally written and placed in the public domain by Wei Dai + +/// \file tiger.h +/// \brief Classes for the Tiger message digest +/// \details Crypto++ provides the original Tiger hash that was +/// submitted to the NESSIE project. The implementation is different +/// from the revised Tiger2 hash. +/// \sa Tiger and +/// Tiger: +/// A Fast New Cryptographic Hash Function +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_TIGER_H +#define CRYPTOPP_TIGER_H + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_TIGER_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Tiger message digest +/// \details Crypto++ provides the original Tiger hash that was +/// submitted to the NESSIE project. The implementation is different +/// from the revised Tiger2 hash. +/// \sa Tiger and +/// Tiger: +/// A Fast New Cryptographic Hash Function +/// \since Crypto++ 2.1 +class Tiger : public IteratedHashWithStaticTransform +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Tiger";} + std::string AlgorithmProvider() const; + + /// \brief Initialize state array + /// \param state the state of the hash + static void InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + static void Transform(word64 *digest, const word64 *data); + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() call Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + static const word64 table[4*256+3]; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/tigertab.cpp b/extension/third_party/cryptopp/tigertab.cpp new file mode 100644 index 00000000..5e219dcf --- /dev/null +++ b/extension/third_party/cryptopp/tigertab.cpp @@ -0,0 +1,525 @@ +#include "pch.h" +#include "tiger.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word64 Tiger::table[4*256+3] = +{ + W64LIT(0x02AAB17CF7E90C5E) /* 0 */, W64LIT(0xAC424B03E243A8EC) /* 1 */, + W64LIT(0x72CD5BE30DD5FCD3) /* 2 */, W64LIT(0x6D019B93F6F97F3A) /* 3 */, + W64LIT(0xCD9978FFD21F9193) /* 4 */, W64LIT(0x7573A1C9708029E2) /* 5 */, + W64LIT(0xB164326B922A83C3) /* 6 */, W64LIT(0x46883EEE04915870) /* 7 */, + W64LIT(0xEAACE3057103ECE6) /* 8 */, W64LIT(0xC54169B808A3535C) /* 9 */, + W64LIT(0x4CE754918DDEC47C) /* 10 */, W64LIT(0x0AA2F4DFDC0DF40C) /* 11 */, + W64LIT(0x10B76F18A74DBEFA) /* 12 */, W64LIT(0xC6CCB6235AD1AB6A) /* 13 */, + W64LIT(0x13726121572FE2FF) /* 14 */, W64LIT(0x1A488C6F199D921E) /* 15 */, + W64LIT(0x4BC9F9F4DA0007CA) /* 16 */, W64LIT(0x26F5E6F6E85241C7) /* 17 */, + W64LIT(0x859079DBEA5947B6) /* 18 */, W64LIT(0x4F1885C5C99E8C92) /* 19 */, + W64LIT(0xD78E761EA96F864B) /* 20 */, W64LIT(0x8E36428C52B5C17D) /* 21 */, + W64LIT(0x69CF6827373063C1) /* 22 */, W64LIT(0xB607C93D9BB4C56E) /* 23 */, + W64LIT(0x7D820E760E76B5EA) /* 24 */, W64LIT(0x645C9CC6F07FDC42) /* 25 */, + W64LIT(0xBF38A078243342E0) /* 26 */, W64LIT(0x5F6B343C9D2E7D04) /* 27 */, + W64LIT(0xF2C28AEB600B0EC6) /* 28 */, W64LIT(0x6C0ED85F7254BCAC) /* 29 */, + W64LIT(0x71592281A4DB4FE5) /* 30 */, W64LIT(0x1967FA69CE0FED9F) /* 31 */, + W64LIT(0xFD5293F8B96545DB) /* 32 */, W64LIT(0xC879E9D7F2A7600B) /* 33 */, + W64LIT(0x860248920193194E) /* 34 */, W64LIT(0xA4F9533B2D9CC0B3) /* 35 */, + W64LIT(0x9053836C15957613) /* 36 */, W64LIT(0xDB6DCF8AFC357BF1) /* 37 */, + W64LIT(0x18BEEA7A7A370F57) /* 38 */, W64LIT(0x037117CA50B99066) /* 39 */, + W64LIT(0x6AB30A9774424A35) /* 40 */, W64LIT(0xF4E92F02E325249B) /* 41 */, + W64LIT(0x7739DB07061CCAE1) /* 42 */, W64LIT(0xD8F3B49CECA42A05) /* 43 */, + W64LIT(0xBD56BE3F51382F73) /* 44 */, W64LIT(0x45FAED5843B0BB28) /* 45 */, + W64LIT(0x1C813D5C11BF1F83) /* 46 */, W64LIT(0x8AF0E4B6D75FA169) /* 47 */, + W64LIT(0x33EE18A487AD9999) /* 48 */, W64LIT(0x3C26E8EAB1C94410) /* 49 */, + W64LIT(0xB510102BC0A822F9) /* 50 */, W64LIT(0x141EEF310CE6123B) /* 51 */, + W64LIT(0xFC65B90059DDB154) /* 52 */, W64LIT(0xE0158640C5E0E607) /* 53 */, + W64LIT(0x884E079826C3A3CF) /* 54 */, W64LIT(0x930D0D9523C535FD) /* 55 */, + W64LIT(0x35638D754E9A2B00) /* 56 */, W64LIT(0x4085FCCF40469DD5) /* 57 */, + W64LIT(0xC4B17AD28BE23A4C) /* 58 */, W64LIT(0xCAB2F0FC6A3E6A2E) /* 59 */, + W64LIT(0x2860971A6B943FCD) /* 60 */, W64LIT(0x3DDE6EE212E30446) /* 61 */, + W64LIT(0x6222F32AE01765AE) /* 62 */, W64LIT(0x5D550BB5478308FE) /* 63 */, + W64LIT(0xA9EFA98DA0EDA22A) /* 64 */, W64LIT(0xC351A71686C40DA7) /* 65 */, + W64LIT(0x1105586D9C867C84) /* 66 */, W64LIT(0xDCFFEE85FDA22853) /* 67 */, + W64LIT(0xCCFBD0262C5EEF76) /* 68 */, W64LIT(0xBAF294CB8990D201) /* 69 */, + W64LIT(0xE69464F52AFAD975) /* 70 */, W64LIT(0x94B013AFDF133E14) /* 71 */, + W64LIT(0x06A7D1A32823C958) /* 72 */, W64LIT(0x6F95FE5130F61119) /* 73 */, + W64LIT(0xD92AB34E462C06C0) /* 74 */, W64LIT(0xED7BDE33887C71D2) /* 75 */, + W64LIT(0x79746D6E6518393E) /* 76 */, W64LIT(0x5BA419385D713329) /* 77 */, + W64LIT(0x7C1BA6B948A97564) /* 78 */, W64LIT(0x31987C197BFDAC67) /* 79 */, + W64LIT(0xDE6C23C44B053D02) /* 80 */, W64LIT(0x581C49FED002D64D) /* 81 */, + W64LIT(0xDD474D6338261571) /* 82 */, W64LIT(0xAA4546C3E473D062) /* 83 */, + W64LIT(0x928FCE349455F860) /* 84 */, W64LIT(0x48161BBACAAB94D9) /* 85 */, + W64LIT(0x63912430770E6F68) /* 86 */, W64LIT(0x6EC8A5E602C6641C) /* 87 */, + W64LIT(0x87282515337DDD2B) /* 88 */, W64LIT(0x2CDA6B42034B701B) /* 89 */, + W64LIT(0xB03D37C181CB096D) /* 90 */, W64LIT(0xE108438266C71C6F) /* 91 */, + W64LIT(0x2B3180C7EB51B255) /* 92 */, W64LIT(0xDF92B82F96C08BBC) /* 93 */, + W64LIT(0x5C68C8C0A632F3BA) /* 94 */, W64LIT(0x5504CC861C3D0556) /* 95 */, + W64LIT(0xABBFA4E55FB26B8F) /* 96 */, W64LIT(0x41848B0AB3BACEB4) /* 97 */, + W64LIT(0xB334A273AA445D32) /* 98 */, W64LIT(0xBCA696F0A85AD881) /* 99 */, + W64LIT(0x24F6EC65B528D56C) /* 100 */, W64LIT(0x0CE1512E90F4524A) /* 101 */, + W64LIT(0x4E9DD79D5506D35A) /* 102 */, W64LIT(0x258905FAC6CE9779) /* 103 */, + W64LIT(0x2019295B3E109B33) /* 104 */, W64LIT(0xF8A9478B73A054CC) /* 105 */, + W64LIT(0x2924F2F934417EB0) /* 106 */, W64LIT(0x3993357D536D1BC4) /* 107 */, + W64LIT(0x38A81AC21DB6FF8B) /* 108 */, W64LIT(0x47C4FBF17D6016BF) /* 109 */, + W64LIT(0x1E0FAADD7667E3F5) /* 110 */, W64LIT(0x7ABCFF62938BEB96) /* 111 */, + W64LIT(0xA78DAD948FC179C9) /* 112 */, W64LIT(0x8F1F98B72911E50D) /* 113 */, + W64LIT(0x61E48EAE27121A91) /* 114 */, W64LIT(0x4D62F7AD31859808) /* 115 */, + W64LIT(0xECEBA345EF5CEAEB) /* 116 */, W64LIT(0xF5CEB25EBC9684CE) /* 117 */, + W64LIT(0xF633E20CB7F76221) /* 118 */, W64LIT(0xA32CDF06AB8293E4) /* 119 */, + W64LIT(0x985A202CA5EE2CA4) /* 120 */, W64LIT(0xCF0B8447CC8A8FB1) /* 121 */, + W64LIT(0x9F765244979859A3) /* 122 */, W64LIT(0xA8D516B1A1240017) /* 123 */, + W64LIT(0x0BD7BA3EBB5DC726) /* 124 */, W64LIT(0xE54BCA55B86ADB39) /* 125 */, + W64LIT(0x1D7A3AFD6C478063) /* 126 */, W64LIT(0x519EC608E7669EDD) /* 127 */, + W64LIT(0x0E5715A2D149AA23) /* 128 */, W64LIT(0x177D4571848FF194) /* 129 */, + W64LIT(0xEEB55F3241014C22) /* 130 */, W64LIT(0x0F5E5CA13A6E2EC2) /* 131 */, + W64LIT(0x8029927B75F5C361) /* 132 */, W64LIT(0xAD139FABC3D6E436) /* 133 */, + W64LIT(0x0D5DF1A94CCF402F) /* 134 */, W64LIT(0x3E8BD948BEA5DFC8) /* 135 */, + W64LIT(0xA5A0D357BD3FF77E) /* 136 */, W64LIT(0xA2D12E251F74F645) /* 137 */, + W64LIT(0x66FD9E525E81A082) /* 138 */, W64LIT(0x2E0C90CE7F687A49) /* 139 */, + W64LIT(0xC2E8BCBEBA973BC5) /* 140 */, W64LIT(0x000001BCE509745F) /* 141 */, + W64LIT(0x423777BBE6DAB3D6) /* 142 */, W64LIT(0xD1661C7EAEF06EB5) /* 143 */, + W64LIT(0xA1781F354DAACFD8) /* 144 */, W64LIT(0x2D11284A2B16AFFC) /* 145 */, + W64LIT(0xF1FC4F67FA891D1F) /* 146 */, W64LIT(0x73ECC25DCB920ADA) /* 147 */, + W64LIT(0xAE610C22C2A12651) /* 148 */, W64LIT(0x96E0A810D356B78A) /* 149 */, + W64LIT(0x5A9A381F2FE7870F) /* 150 */, W64LIT(0xD5AD62EDE94E5530) /* 151 */, + W64LIT(0xD225E5E8368D1427) /* 152 */, W64LIT(0x65977B70C7AF4631) /* 153 */, + W64LIT(0x99F889B2DE39D74F) /* 154 */, W64LIT(0x233F30BF54E1D143) /* 155 */, + W64LIT(0x9A9675D3D9A63C97) /* 156 */, W64LIT(0x5470554FF334F9A8) /* 157 */, + W64LIT(0x166ACB744A4F5688) /* 158 */, W64LIT(0x70C74CAAB2E4AEAD) /* 159 */, + W64LIT(0xF0D091646F294D12) /* 160 */, W64LIT(0x57B82A89684031D1) /* 161 */, + W64LIT(0xEFD95A5A61BE0B6B) /* 162 */, W64LIT(0x2FBD12E969F2F29A) /* 163 */, + W64LIT(0x9BD37013FEFF9FE8) /* 164 */, W64LIT(0x3F9B0404D6085A06) /* 165 */, + W64LIT(0x4940C1F3166CFE15) /* 166 */, W64LIT(0x09542C4DCDF3DEFB) /* 167 */, + W64LIT(0xB4C5218385CD5CE3) /* 168 */, W64LIT(0xC935B7DC4462A641) /* 169 */, + W64LIT(0x3417F8A68ED3B63F) /* 170 */, W64LIT(0xB80959295B215B40) /* 171 */, + W64LIT(0xF99CDAEF3B8C8572) /* 172 */, W64LIT(0x018C0614F8FCB95D) /* 173 */, + W64LIT(0x1B14ACCD1A3ACDF3) /* 174 */, W64LIT(0x84D471F200BB732D) /* 175 */, + W64LIT(0xC1A3110E95E8DA16) /* 176 */, W64LIT(0x430A7220BF1A82B8) /* 177 */, + W64LIT(0xB77E090D39DF210E) /* 178 */, W64LIT(0x5EF4BD9F3CD05E9D) /* 179 */, + W64LIT(0x9D4FF6DA7E57A444) /* 180 */, W64LIT(0xDA1D60E183D4A5F8) /* 181 */, + W64LIT(0xB287C38417998E47) /* 182 */, W64LIT(0xFE3EDC121BB31886) /* 183 */, + W64LIT(0xC7FE3CCC980CCBEF) /* 184 */, W64LIT(0xE46FB590189BFD03) /* 185 */, + W64LIT(0x3732FD469A4C57DC) /* 186 */, W64LIT(0x7EF700A07CF1AD65) /* 187 */, + W64LIT(0x59C64468A31D8859) /* 188 */, W64LIT(0x762FB0B4D45B61F6) /* 189 */, + W64LIT(0x155BAED099047718) /* 190 */, W64LIT(0x68755E4C3D50BAA6) /* 191 */, + W64LIT(0xE9214E7F22D8B4DF) /* 192 */, W64LIT(0x2ADDBF532EAC95F4) /* 193 */, + W64LIT(0x32AE3909B4BD0109) /* 194 */, W64LIT(0x834DF537B08E3450) /* 195 */, + W64LIT(0xFA209DA84220728D) /* 196 */, W64LIT(0x9E691D9B9EFE23F7) /* 197 */, + W64LIT(0x0446D288C4AE8D7F) /* 198 */, W64LIT(0x7B4CC524E169785B) /* 199 */, + W64LIT(0x21D87F0135CA1385) /* 200 */, W64LIT(0xCEBB400F137B8AA5) /* 201 */, + W64LIT(0x272E2B66580796BE) /* 202 */, W64LIT(0x3612264125C2B0DE) /* 203 */, + W64LIT(0x057702BDAD1EFBB2) /* 204 */, W64LIT(0xD4BABB8EACF84BE9) /* 205 */, + W64LIT(0x91583139641BC67B) /* 206 */, W64LIT(0x8BDC2DE08036E024) /* 207 */, + W64LIT(0x603C8156F49F68ED) /* 208 */, W64LIT(0xF7D236F7DBEF5111) /* 209 */, + W64LIT(0x9727C4598AD21E80) /* 210 */, W64LIT(0xA08A0896670A5FD7) /* 211 */, + W64LIT(0xCB4A8F4309EBA9CB) /* 212 */, W64LIT(0x81AF564B0F7036A1) /* 213 */, + W64LIT(0xC0B99AA778199ABD) /* 214 */, W64LIT(0x959F1EC83FC8E952) /* 215 */, + W64LIT(0x8C505077794A81B9) /* 216 */, W64LIT(0x3ACAAF8F056338F0) /* 217 */, + W64LIT(0x07B43F50627A6778) /* 218 */, W64LIT(0x4A44AB49F5ECCC77) /* 219 */, + W64LIT(0x3BC3D6E4B679EE98) /* 220 */, W64LIT(0x9CC0D4D1CF14108C) /* 221 */, + W64LIT(0x4406C00B206BC8A0) /* 222 */, W64LIT(0x82A18854C8D72D89) /* 223 */, + W64LIT(0x67E366B35C3C432C) /* 224 */, W64LIT(0xB923DD61102B37F2) /* 225 */, + W64LIT(0x56AB2779D884271D) /* 226 */, W64LIT(0xBE83E1B0FF1525AF) /* 227 */, + W64LIT(0xFB7C65D4217E49A9) /* 228 */, W64LIT(0x6BDBE0E76D48E7D4) /* 229 */, + W64LIT(0x08DF828745D9179E) /* 230 */, W64LIT(0x22EA6A9ADD53BD34) /* 231 */, + W64LIT(0xE36E141C5622200A) /* 232 */, W64LIT(0x7F805D1B8CB750EE) /* 233 */, + W64LIT(0xAFE5C7A59F58E837) /* 234 */, W64LIT(0xE27F996A4FB1C23C) /* 235 */, + W64LIT(0xD3867DFB0775F0D0) /* 236 */, W64LIT(0xD0E673DE6E88891A) /* 237 */, + W64LIT(0x123AEB9EAFB86C25) /* 238 */, W64LIT(0x30F1D5D5C145B895) /* 239 */, + W64LIT(0xBB434A2DEE7269E7) /* 240 */, W64LIT(0x78CB67ECF931FA38) /* 241 */, + W64LIT(0xF33B0372323BBF9C) /* 242 */, W64LIT(0x52D66336FB279C74) /* 243 */, + W64LIT(0x505F33AC0AFB4EAA) /* 244 */, W64LIT(0xE8A5CD99A2CCE187) /* 245 */, + W64LIT(0x534974801E2D30BB) /* 246 */, W64LIT(0x8D2D5711D5876D90) /* 247 */, + W64LIT(0x1F1A412891BC038E) /* 248 */, W64LIT(0xD6E2E71D82E56648) /* 249 */, + W64LIT(0x74036C3A497732B7) /* 250 */, W64LIT(0x89B67ED96361F5AB) /* 251 */, + W64LIT(0xFFED95D8F1EA02A2) /* 252 */, W64LIT(0xE72B3BD61464D43D) /* 253 */, + W64LIT(0xA6300F170BDC4820) /* 254 */, W64LIT(0xEBC18760ED78A77A) /* 255 */, + W64LIT(0xE6A6BE5A05A12138) /* 256 */, W64LIT(0xB5A122A5B4F87C98) /* 257 */, + W64LIT(0x563C6089140B6990) /* 258 */, W64LIT(0x4C46CB2E391F5DD5) /* 259 */, + W64LIT(0xD932ADDBC9B79434) /* 260 */, W64LIT(0x08EA70E42015AFF5) /* 261 */, + W64LIT(0xD765A6673E478CF1) /* 262 */, W64LIT(0xC4FB757EAB278D99) /* 263 */, + W64LIT(0xDF11C6862D6E0692) /* 264 */, W64LIT(0xDDEB84F10D7F3B16) /* 265 */, + W64LIT(0x6F2EF604A665EA04) /* 266 */, W64LIT(0x4A8E0F0FF0E0DFB3) /* 267 */, + W64LIT(0xA5EDEEF83DBCBA51) /* 268 */, W64LIT(0xFC4F0A2A0EA4371E) /* 269 */, + W64LIT(0xE83E1DA85CB38429) /* 270 */, W64LIT(0xDC8FF882BA1B1CE2) /* 271 */, + W64LIT(0xCD45505E8353E80D) /* 272 */, W64LIT(0x18D19A00D4DB0717) /* 273 */, + W64LIT(0x34A0CFEDA5F38101) /* 274 */, W64LIT(0x0BE77E518887CAF2) /* 275 */, + W64LIT(0x1E341438B3C45136) /* 276 */, W64LIT(0xE05797F49089CCF9) /* 277 */, + W64LIT(0xFFD23F9DF2591D14) /* 278 */, W64LIT(0x543DDA228595C5CD) /* 279 */, + W64LIT(0x661F81FD99052A33) /* 280 */, W64LIT(0x8736E641DB0F7B76) /* 281 */, + W64LIT(0x15227725418E5307) /* 282 */, W64LIT(0xE25F7F46162EB2FA) /* 283 */, + W64LIT(0x48A8B2126C13D9FE) /* 284 */, W64LIT(0xAFDC541792E76EEA) /* 285 */, + W64LIT(0x03D912BFC6D1898F) /* 286 */, W64LIT(0x31B1AAFA1B83F51B) /* 287 */, + W64LIT(0xF1AC2796E42AB7D9) /* 288 */, W64LIT(0x40A3A7D7FCD2EBAC) /* 289 */, + W64LIT(0x1056136D0AFBBCC5) /* 290 */, W64LIT(0x7889E1DD9A6D0C85) /* 291 */, + W64LIT(0xD33525782A7974AA) /* 292 */, W64LIT(0xA7E25D09078AC09B) /* 293 */, + W64LIT(0xBD4138B3EAC6EDD0) /* 294 */, W64LIT(0x920ABFBE71EB9E70) /* 295 */, + W64LIT(0xA2A5D0F54FC2625C) /* 296 */, W64LIT(0xC054E36B0B1290A3) /* 297 */, + W64LIT(0xF6DD59FF62FE932B) /* 298 */, W64LIT(0x3537354511A8AC7D) /* 299 */, + W64LIT(0xCA845E9172FADCD4) /* 300 */, W64LIT(0x84F82B60329D20DC) /* 301 */, + W64LIT(0x79C62CE1CD672F18) /* 302 */, W64LIT(0x8B09A2ADD124642C) /* 303 */, + W64LIT(0xD0C1E96A19D9E726) /* 304 */, W64LIT(0x5A786A9B4BA9500C) /* 305 */, + W64LIT(0x0E020336634C43F3) /* 306 */, W64LIT(0xC17B474AEB66D822) /* 307 */, + W64LIT(0x6A731AE3EC9BAAC2) /* 308 */, W64LIT(0x8226667AE0840258) /* 309 */, + W64LIT(0x67D4567691CAECA5) /* 310 */, W64LIT(0x1D94155C4875ADB5) /* 311 */, + W64LIT(0x6D00FD985B813FDF) /* 312 */, W64LIT(0x51286EFCB774CD06) /* 313 */, + W64LIT(0x5E8834471FA744AF) /* 314 */, W64LIT(0xF72CA0AEE761AE2E) /* 315 */, + W64LIT(0xBE40E4CDAEE8E09A) /* 316 */, W64LIT(0xE9970BBB5118F665) /* 317 */, + W64LIT(0x726E4BEB33DF1964) /* 318 */, W64LIT(0x703B000729199762) /* 319 */, + W64LIT(0x4631D816F5EF30A7) /* 320 */, W64LIT(0xB880B5B51504A6BE) /* 321 */, + W64LIT(0x641793C37ED84B6C) /* 322 */, W64LIT(0x7B21ED77F6E97D96) /* 323 */, + W64LIT(0x776306312EF96B73) /* 324 */, W64LIT(0xAE528948E86FF3F4) /* 325 */, + W64LIT(0x53DBD7F286A3F8F8) /* 326 */, W64LIT(0x16CADCE74CFC1063) /* 327 */, + W64LIT(0x005C19BDFA52C6DD) /* 328 */, W64LIT(0x68868F5D64D46AD3) /* 329 */, + W64LIT(0x3A9D512CCF1E186A) /* 330 */, W64LIT(0x367E62C2385660AE) /* 331 */, + W64LIT(0xE359E7EA77DCB1D7) /* 332 */, W64LIT(0x526C0773749ABE6E) /* 333 */, + W64LIT(0x735AE5F9D09F734B) /* 334 */, W64LIT(0x493FC7CC8A558BA8) /* 335 */, + W64LIT(0xB0B9C1533041AB45) /* 336 */, W64LIT(0x321958BA470A59BD) /* 337 */, + W64LIT(0x852DB00B5F46C393) /* 338 */, W64LIT(0x91209B2BD336B0E5) /* 339 */, + W64LIT(0x6E604F7D659EF19F) /* 340 */, W64LIT(0xB99A8AE2782CCB24) /* 341 */, + W64LIT(0xCCF52AB6C814C4C7) /* 342 */, W64LIT(0x4727D9AFBE11727B) /* 343 */, + W64LIT(0x7E950D0C0121B34D) /* 344 */, W64LIT(0x756F435670AD471F) /* 345 */, + W64LIT(0xF5ADD442615A6849) /* 346 */, W64LIT(0x4E87E09980B9957A) /* 347 */, + W64LIT(0x2ACFA1DF50AEE355) /* 348 */, W64LIT(0xD898263AFD2FD556) /* 349 */, + W64LIT(0xC8F4924DD80C8FD6) /* 350 */, W64LIT(0xCF99CA3D754A173A) /* 351 */, + W64LIT(0xFE477BACAF91BF3C) /* 352 */, W64LIT(0xED5371F6D690C12D) /* 353 */, + W64LIT(0x831A5C285E687094) /* 354 */, W64LIT(0xC5D3C90A3708A0A4) /* 355 */, + W64LIT(0x0F7F903717D06580) /* 356 */, W64LIT(0x19F9BB13B8FDF27F) /* 357 */, + W64LIT(0xB1BD6F1B4D502843) /* 358 */, W64LIT(0x1C761BA38FFF4012) /* 359 */, + W64LIT(0x0D1530C4E2E21F3B) /* 360 */, W64LIT(0x8943CE69A7372C8A) /* 361 */, + W64LIT(0xE5184E11FEB5CE66) /* 362 */, W64LIT(0x618BDB80BD736621) /* 363 */, + W64LIT(0x7D29BAD68B574D0B) /* 364 */, W64LIT(0x81BB613E25E6FE5B) /* 365 */, + W64LIT(0x071C9C10BC07913F) /* 366 */, W64LIT(0xC7BEEB7909AC2D97) /* 367 */, + W64LIT(0xC3E58D353BC5D757) /* 368 */, W64LIT(0xEB017892F38F61E8) /* 369 */, + W64LIT(0xD4EFFB9C9B1CC21A) /* 370 */, W64LIT(0x99727D26F494F7AB) /* 371 */, + W64LIT(0xA3E063A2956B3E03) /* 372 */, W64LIT(0x9D4A8B9A4AA09C30) /* 373 */, + W64LIT(0x3F6AB7D500090FB4) /* 374 */, W64LIT(0x9CC0F2A057268AC0) /* 375 */, + W64LIT(0x3DEE9D2DEDBF42D1) /* 376 */, W64LIT(0x330F49C87960A972) /* 377 */, + W64LIT(0xC6B2720287421B41) /* 378 */, W64LIT(0x0AC59EC07C00369C) /* 379 */, + W64LIT(0xEF4EAC49CB353425) /* 380 */, W64LIT(0xF450244EEF0129D8) /* 381 */, + W64LIT(0x8ACC46E5CAF4DEB6) /* 382 */, W64LIT(0x2FFEAB63989263F7) /* 383 */, + W64LIT(0x8F7CB9FE5D7A4578) /* 384 */, W64LIT(0x5BD8F7644E634635) /* 385 */, + W64LIT(0x427A7315BF2DC900) /* 386 */, W64LIT(0x17D0C4AA2125261C) /* 387 */, + W64LIT(0x3992486C93518E50) /* 388 */, W64LIT(0xB4CBFEE0A2D7D4C3) /* 389 */, + W64LIT(0x7C75D6202C5DDD8D) /* 390 */, W64LIT(0xDBC295D8E35B6C61) /* 391 */, + W64LIT(0x60B369D302032B19) /* 392 */, W64LIT(0xCE42685FDCE44132) /* 393 */, + W64LIT(0x06F3DDB9DDF65610) /* 394 */, W64LIT(0x8EA4D21DB5E148F0) /* 395 */, + W64LIT(0x20B0FCE62FCD496F) /* 396 */, W64LIT(0x2C1B912358B0EE31) /* 397 */, + W64LIT(0xB28317B818F5A308) /* 398 */, W64LIT(0xA89C1E189CA6D2CF) /* 399 */, + W64LIT(0x0C6B18576AAADBC8) /* 400 */, W64LIT(0xB65DEAA91299FAE3) /* 401 */, + W64LIT(0xFB2B794B7F1027E7) /* 402 */, W64LIT(0x04E4317F443B5BEB) /* 403 */, + W64LIT(0x4B852D325939D0A6) /* 404 */, W64LIT(0xD5AE6BEEFB207FFC) /* 405 */, + W64LIT(0x309682B281C7D374) /* 406 */, W64LIT(0xBAE309A194C3B475) /* 407 */, + W64LIT(0x8CC3F97B13B49F05) /* 408 */, W64LIT(0x98A9422FF8293967) /* 409 */, + W64LIT(0x244B16B01076FF7C) /* 410 */, W64LIT(0xF8BF571C663D67EE) /* 411 */, + W64LIT(0x1F0D6758EEE30DA1) /* 412 */, W64LIT(0xC9B611D97ADEB9B7) /* 413 */, + W64LIT(0xB7AFD5887B6C57A2) /* 414 */, W64LIT(0x6290AE846B984FE1) /* 415 */, + W64LIT(0x94DF4CDEACC1A5FD) /* 416 */, W64LIT(0x058A5BD1C5483AFF) /* 417 */, + W64LIT(0x63166CC142BA3C37) /* 418 */, W64LIT(0x8DB8526EB2F76F40) /* 419 */, + W64LIT(0xE10880036F0D6D4E) /* 420 */, W64LIT(0x9E0523C9971D311D) /* 421 */, + W64LIT(0x45EC2824CC7CD691) /* 422 */, W64LIT(0x575B8359E62382C9) /* 423 */, + W64LIT(0xFA9E400DC4889995) /* 424 */, W64LIT(0xD1823ECB45721568) /* 425 */, + W64LIT(0xDAFD983B8206082F) /* 426 */, W64LIT(0xAA7D29082386A8CB) /* 427 */, + W64LIT(0x269FCD4403B87588) /* 428 */, W64LIT(0x1B91F5F728BDD1E0) /* 429 */, + W64LIT(0xE4669F39040201F6) /* 430 */, W64LIT(0x7A1D7C218CF04ADE) /* 431 */, + W64LIT(0x65623C29D79CE5CE) /* 432 */, W64LIT(0x2368449096C00BB1) /* 433 */, + W64LIT(0xAB9BF1879DA503BA) /* 434 */, W64LIT(0xBC23ECB1A458058E) /* 435 */, + W64LIT(0x9A58DF01BB401ECC) /* 436 */, W64LIT(0xA070E868A85F143D) /* 437 */, + W64LIT(0x4FF188307DF2239E) /* 438 */, W64LIT(0x14D565B41A641183) /* 439 */, + W64LIT(0xEE13337452701602) /* 440 */, W64LIT(0x950E3DCF3F285E09) /* 441 */, + W64LIT(0x59930254B9C80953) /* 442 */, W64LIT(0x3BF299408930DA6D) /* 443 */, + W64LIT(0xA955943F53691387) /* 444 */, W64LIT(0xA15EDECAA9CB8784) /* 445 */, + W64LIT(0x29142127352BE9A0) /* 446 */, W64LIT(0x76F0371FFF4E7AFB) /* 447 */, + W64LIT(0x0239F450274F2228) /* 448 */, W64LIT(0xBB073AF01D5E868B) /* 449 */, + W64LIT(0xBFC80571C10E96C1) /* 450 */, W64LIT(0xD267088568222E23) /* 451 */, + W64LIT(0x9671A3D48E80B5B0) /* 452 */, W64LIT(0x55B5D38AE193BB81) /* 453 */, + W64LIT(0x693AE2D0A18B04B8) /* 454 */, W64LIT(0x5C48B4ECADD5335F) /* 455 */, + W64LIT(0xFD743B194916A1CA) /* 456 */, W64LIT(0x2577018134BE98C4) /* 457 */, + W64LIT(0xE77987E83C54A4AD) /* 458 */, W64LIT(0x28E11014DA33E1B9) /* 459 */, + W64LIT(0x270CC59E226AA213) /* 460 */, W64LIT(0x71495F756D1A5F60) /* 461 */, + W64LIT(0x9BE853FB60AFEF77) /* 462 */, W64LIT(0xADC786A7F7443DBF) /* 463 */, + W64LIT(0x0904456173B29A82) /* 464 */, W64LIT(0x58BC7A66C232BD5E) /* 465 */, + W64LIT(0xF306558C673AC8B2) /* 466 */, W64LIT(0x41F639C6B6C9772A) /* 467 */, + W64LIT(0x216DEFE99FDA35DA) /* 468 */, W64LIT(0x11640CC71C7BE615) /* 469 */, + W64LIT(0x93C43694565C5527) /* 470 */, W64LIT(0xEA038E6246777839) /* 471 */, + W64LIT(0xF9ABF3CE5A3E2469) /* 472 */, W64LIT(0x741E768D0FD312D2) /* 473 */, + W64LIT(0x0144B883CED652C6) /* 474 */, W64LIT(0xC20B5A5BA33F8552) /* 475 */, + W64LIT(0x1AE69633C3435A9D) /* 476 */, W64LIT(0x97A28CA4088CFDEC) /* 477 */, + W64LIT(0x8824A43C1E96F420) /* 478 */, W64LIT(0x37612FA66EEEA746) /* 479 */, + W64LIT(0x6B4CB165F9CF0E5A) /* 480 */, W64LIT(0x43AA1C06A0ABFB4A) /* 481 */, + W64LIT(0x7F4DC26FF162796B) /* 482 */, W64LIT(0x6CBACC8E54ED9B0F) /* 483 */, + W64LIT(0xA6B7FFEFD2BB253E) /* 484 */, W64LIT(0x2E25BC95B0A29D4F) /* 485 */, + W64LIT(0x86D6A58BDEF1388C) /* 486 */, W64LIT(0xDED74AC576B6F054) /* 487 */, + W64LIT(0x8030BDBC2B45805D) /* 488 */, W64LIT(0x3C81AF70E94D9289) /* 489 */, + W64LIT(0x3EFF6DDA9E3100DB) /* 490 */, W64LIT(0xB38DC39FDFCC8847) /* 491 */, + W64LIT(0x123885528D17B87E) /* 492 */, W64LIT(0xF2DA0ED240B1B642) /* 493 */, + W64LIT(0x44CEFADCD54BF9A9) /* 494 */, W64LIT(0x1312200E433C7EE6) /* 495 */, + W64LIT(0x9FFCC84F3A78C748) /* 496 */, W64LIT(0xF0CD1F72248576BB) /* 497 */, + W64LIT(0xEC6974053638CFE4) /* 498 */, W64LIT(0x2BA7B67C0CEC4E4C) /* 499 */, + W64LIT(0xAC2F4DF3E5CE32ED) /* 500 */, W64LIT(0xCB33D14326EA4C11) /* 501 */, + W64LIT(0xA4E9044CC77E58BC) /* 502 */, W64LIT(0x5F513293D934FCEF) /* 503 */, + W64LIT(0x5DC9645506E55444) /* 504 */, W64LIT(0x50DE418F317DE40A) /* 505 */, + W64LIT(0x388CB31A69DDE259) /* 506 */, W64LIT(0x2DB4A83455820A86) /* 507 */, + W64LIT(0x9010A91E84711AE9) /* 508 */, W64LIT(0x4DF7F0B7B1498371) /* 509 */, + W64LIT(0xD62A2EABC0977179) /* 510 */, W64LIT(0x22FAC097AA8D5C0E) /* 511 */, + W64LIT(0xF49FCC2FF1DAF39B) /* 512 */, W64LIT(0x487FD5C66FF29281) /* 513 */, + W64LIT(0xE8A30667FCDCA83F) /* 514 */, W64LIT(0x2C9B4BE3D2FCCE63) /* 515 */, + W64LIT(0xDA3FF74B93FBBBC2) /* 516 */, W64LIT(0x2FA165D2FE70BA66) /* 517 */, + W64LIT(0xA103E279970E93D4) /* 518 */, W64LIT(0xBECDEC77B0E45E71) /* 519 */, + W64LIT(0xCFB41E723985E497) /* 520 */, W64LIT(0xB70AAA025EF75017) /* 521 */, + W64LIT(0xD42309F03840B8E0) /* 522 */, W64LIT(0x8EFC1AD035898579) /* 523 */, + W64LIT(0x96C6920BE2B2ABC5) /* 524 */, W64LIT(0x66AF4163375A9172) /* 525 */, + W64LIT(0x2174ABDCCA7127FB) /* 526 */, W64LIT(0xB33CCEA64A72FF41) /* 527 */, + W64LIT(0xF04A4933083066A5) /* 528 */, W64LIT(0x8D970ACDD7289AF5) /* 529 */, + W64LIT(0x8F96E8E031C8C25E) /* 530 */, W64LIT(0xF3FEC02276875D47) /* 531 */, + W64LIT(0xEC7BF310056190DD) /* 532 */, W64LIT(0xF5ADB0AEBB0F1491) /* 533 */, + W64LIT(0x9B50F8850FD58892) /* 534 */, W64LIT(0x4975488358B74DE8) /* 535 */, + W64LIT(0xA3354FF691531C61) /* 536 */, W64LIT(0x0702BBE481D2C6EE) /* 537 */, + W64LIT(0x89FB24057DEDED98) /* 538 */, W64LIT(0xAC3075138596E902) /* 539 */, + W64LIT(0x1D2D3580172772ED) /* 540 */, W64LIT(0xEB738FC28E6BC30D) /* 541 */, + W64LIT(0x5854EF8F63044326) /* 542 */, W64LIT(0x9E5C52325ADD3BBE) /* 543 */, + W64LIT(0x90AA53CF325C4623) /* 544 */, W64LIT(0xC1D24D51349DD067) /* 545 */, + W64LIT(0x2051CFEEA69EA624) /* 546 */, W64LIT(0x13220F0A862E7E4F) /* 547 */, + W64LIT(0xCE39399404E04864) /* 548 */, W64LIT(0xD9C42CA47086FCB7) /* 549 */, + W64LIT(0x685AD2238A03E7CC) /* 550 */, W64LIT(0x066484B2AB2FF1DB) /* 551 */, + W64LIT(0xFE9D5D70EFBF79EC) /* 552 */, W64LIT(0x5B13B9DD9C481854) /* 553 */, + W64LIT(0x15F0D475ED1509AD) /* 554 */, W64LIT(0x0BEBCD060EC79851) /* 555 */, + W64LIT(0xD58C6791183AB7F8) /* 556 */, W64LIT(0xD1187C5052F3EEE4) /* 557 */, + W64LIT(0xC95D1192E54E82FF) /* 558 */, W64LIT(0x86EEA14CB9AC6CA2) /* 559 */, + W64LIT(0x3485BEB153677D5D) /* 560 */, W64LIT(0xDD191D781F8C492A) /* 561 */, + W64LIT(0xF60866BAA784EBF9) /* 562 */, W64LIT(0x518F643BA2D08C74) /* 563 */, + W64LIT(0x8852E956E1087C22) /* 564 */, W64LIT(0xA768CB8DC410AE8D) /* 565 */, + W64LIT(0x38047726BFEC8E1A) /* 566 */, W64LIT(0xA67738B4CD3B45AA) /* 567 */, + W64LIT(0xAD16691CEC0DDE19) /* 568 */, W64LIT(0xC6D4319380462E07) /* 569 */, + W64LIT(0xC5A5876D0BA61938) /* 570 */, W64LIT(0x16B9FA1FA58FD840) /* 571 */, + W64LIT(0x188AB1173CA74F18) /* 572 */, W64LIT(0xABDA2F98C99C021F) /* 573 */, + W64LIT(0x3E0580AB134AE816) /* 574 */, W64LIT(0x5F3B05B773645ABB) /* 575 */, + W64LIT(0x2501A2BE5575F2F6) /* 576 */, W64LIT(0x1B2F74004E7E8BA9) /* 577 */, + W64LIT(0x1CD7580371E8D953) /* 578 */, W64LIT(0x7F6ED89562764E30) /* 579 */, + W64LIT(0xB15926FF596F003D) /* 580 */, W64LIT(0x9F65293DA8C5D6B9) /* 581 */, + W64LIT(0x6ECEF04DD690F84C) /* 582 */, W64LIT(0x4782275FFF33AF88) /* 583 */, + W64LIT(0xE41433083F820801) /* 584 */, W64LIT(0xFD0DFE409A1AF9B5) /* 585 */, + W64LIT(0x4325A3342CDB396B) /* 586 */, W64LIT(0x8AE77E62B301B252) /* 587 */, + W64LIT(0xC36F9E9F6655615A) /* 588 */, W64LIT(0x85455A2D92D32C09) /* 589 */, + W64LIT(0xF2C7DEA949477485) /* 590 */, W64LIT(0x63CFB4C133A39EBA) /* 591 */, + W64LIT(0x83B040CC6EBC5462) /* 592 */, W64LIT(0x3B9454C8FDB326B0) /* 593 */, + W64LIT(0x56F56A9E87FFD78C) /* 594 */, W64LIT(0x2DC2940D99F42BC6) /* 595 */, + W64LIT(0x98F7DF096B096E2D) /* 596 */, W64LIT(0x19A6E01E3AD852BF) /* 597 */, + W64LIT(0x42A99CCBDBD4B40B) /* 598 */, W64LIT(0xA59998AF45E9C559) /* 599 */, + W64LIT(0x366295E807D93186) /* 600 */, W64LIT(0x6B48181BFAA1F773) /* 601 */, + W64LIT(0x1FEC57E2157A0A1D) /* 602 */, W64LIT(0x4667446AF6201AD5) /* 603 */, + W64LIT(0xE615EBCACFB0F075) /* 604 */, W64LIT(0xB8F31F4F68290778) /* 605 */, + W64LIT(0x22713ED6CE22D11E) /* 606 */, W64LIT(0x3057C1A72EC3C93B) /* 607 */, + W64LIT(0xCB46ACC37C3F1F2F) /* 608 */, W64LIT(0xDBB893FD02AAF50E) /* 609 */, + W64LIT(0x331FD92E600B9FCF) /* 610 */, W64LIT(0xA498F96148EA3AD6) /* 611 */, + W64LIT(0xA8D8426E8B6A83EA) /* 612 */, W64LIT(0xA089B274B7735CDC) /* 613 */, + W64LIT(0x87F6B3731E524A11) /* 614 */, W64LIT(0x118808E5CBC96749) /* 615 */, + W64LIT(0x9906E4C7B19BD394) /* 616 */, W64LIT(0xAFED7F7E9B24A20C) /* 617 */, + W64LIT(0x6509EADEEB3644A7) /* 618 */, W64LIT(0x6C1EF1D3E8EF0EDE) /* 619 */, + W64LIT(0xB9C97D43E9798FB4) /* 620 */, W64LIT(0xA2F2D784740C28A3) /* 621 */, + W64LIT(0x7B8496476197566F) /* 622 */, W64LIT(0x7A5BE3E6B65F069D) /* 623 */, + W64LIT(0xF96330ED78BE6F10) /* 624 */, W64LIT(0xEEE60DE77A076A15) /* 625 */, + W64LIT(0x2B4BEE4AA08B9BD0) /* 626 */, W64LIT(0x6A56A63EC7B8894E) /* 627 */, + W64LIT(0x02121359BA34FEF4) /* 628 */, W64LIT(0x4CBF99F8283703FC) /* 629 */, + W64LIT(0x398071350CAF30C8) /* 630 */, W64LIT(0xD0A77A89F017687A) /* 631 */, + W64LIT(0xF1C1A9EB9E423569) /* 632 */, W64LIT(0x8C7976282DEE8199) /* 633 */, + W64LIT(0x5D1737A5DD1F7ABD) /* 634 */, W64LIT(0x4F53433C09A9FA80) /* 635 */, + W64LIT(0xFA8B0C53DF7CA1D9) /* 636 */, W64LIT(0x3FD9DCBC886CCB77) /* 637 */, + W64LIT(0xC040917CA91B4720) /* 638 */, W64LIT(0x7DD00142F9D1DCDF) /* 639 */, + W64LIT(0x8476FC1D4F387B58) /* 640 */, W64LIT(0x23F8E7C5F3316503) /* 641 */, + W64LIT(0x032A2244E7E37339) /* 642 */, W64LIT(0x5C87A5D750F5A74B) /* 643 */, + W64LIT(0x082B4CC43698992E) /* 644 */, W64LIT(0xDF917BECB858F63C) /* 645 */, + W64LIT(0x3270B8FC5BF86DDA) /* 646 */, W64LIT(0x10AE72BB29B5DD76) /* 647 */, + W64LIT(0x576AC94E7700362B) /* 648 */, W64LIT(0x1AD112DAC61EFB8F) /* 649 */, + W64LIT(0x691BC30EC5FAA427) /* 650 */, W64LIT(0xFF246311CC327143) /* 651 */, + W64LIT(0x3142368E30E53206) /* 652 */, W64LIT(0x71380E31E02CA396) /* 653 */, + W64LIT(0x958D5C960AAD76F1) /* 654 */, W64LIT(0xF8D6F430C16DA536) /* 655 */, + W64LIT(0xC8FFD13F1BE7E1D2) /* 656 */, W64LIT(0x7578AE66004DDBE1) /* 657 */, + W64LIT(0x05833F01067BE646) /* 658 */, W64LIT(0xBB34B5AD3BFE586D) /* 659 */, + W64LIT(0x095F34C9A12B97F0) /* 660 */, W64LIT(0x247AB64525D60CA8) /* 661 */, + W64LIT(0xDCDBC6F3017477D1) /* 662 */, W64LIT(0x4A2E14D4DECAD24D) /* 663 */, + W64LIT(0xBDB5E6D9BE0A1EEB) /* 664 */, W64LIT(0x2A7E70F7794301AB) /* 665 */, + W64LIT(0xDEF42D8A270540FD) /* 666 */, W64LIT(0x01078EC0A34C22C1) /* 667 */, + W64LIT(0xE5DE511AF4C16387) /* 668 */, W64LIT(0x7EBB3A52BD9A330A) /* 669 */, + W64LIT(0x77697857AA7D6435) /* 670 */, W64LIT(0x004E831603AE4C32) /* 671 */, + W64LIT(0xE7A21020AD78E312) /* 672 */, W64LIT(0x9D41A70C6AB420F2) /* 673 */, + W64LIT(0x28E06C18EA1141E6) /* 674 */, W64LIT(0xD2B28CBD984F6B28) /* 675 */, + W64LIT(0x26B75F6C446E9D83) /* 676 */, W64LIT(0xBA47568C4D418D7F) /* 677 */, + W64LIT(0xD80BADBFE6183D8E) /* 678 */, W64LIT(0x0E206D7F5F166044) /* 679 */, + W64LIT(0xE258A43911CBCA3E) /* 680 */, W64LIT(0x723A1746B21DC0BC) /* 681 */, + W64LIT(0xC7CAA854F5D7CDD3) /* 682 */, W64LIT(0x7CAC32883D261D9C) /* 683 */, + W64LIT(0x7690C26423BA942C) /* 684 */, W64LIT(0x17E55524478042B8) /* 685 */, + W64LIT(0xE0BE477656A2389F) /* 686 */, W64LIT(0x4D289B5E67AB2DA0) /* 687 */, + W64LIT(0x44862B9C8FBBFD31) /* 688 */, W64LIT(0xB47CC8049D141365) /* 689 */, + W64LIT(0x822C1B362B91C793) /* 690 */, W64LIT(0x4EB14655FB13DFD8) /* 691 */, + W64LIT(0x1ECBBA0714E2A97B) /* 692 */, W64LIT(0x6143459D5CDE5F14) /* 693 */, + W64LIT(0x53A8FBF1D5F0AC89) /* 694 */, W64LIT(0x97EA04D81C5E5B00) /* 695 */, + W64LIT(0x622181A8D4FDB3F3) /* 696 */, W64LIT(0xE9BCD341572A1208) /* 697 */, + W64LIT(0x1411258643CCE58A) /* 698 */, W64LIT(0x9144C5FEA4C6E0A4) /* 699 */, + W64LIT(0x0D33D06565CF620F) /* 700 */, W64LIT(0x54A48D489F219CA1) /* 701 */, + W64LIT(0xC43E5EAC6D63C821) /* 702 */, W64LIT(0xA9728B3A72770DAF) /* 703 */, + W64LIT(0xD7934E7B20DF87EF) /* 704 */, W64LIT(0xE35503B61A3E86E5) /* 705 */, + W64LIT(0xCAE321FBC819D504) /* 706 */, W64LIT(0x129A50B3AC60BFA6) /* 707 */, + W64LIT(0xCD5E68EA7E9FB6C3) /* 708 */, W64LIT(0xB01C90199483B1C7) /* 709 */, + W64LIT(0x3DE93CD5C295376C) /* 710 */, W64LIT(0xAED52EDF2AB9AD13) /* 711 */, + W64LIT(0x2E60F512C0A07884) /* 712 */, W64LIT(0xBC3D86A3E36210C9) /* 713 */, + W64LIT(0x35269D9B163951CE) /* 714 */, W64LIT(0x0C7D6E2AD0CDB5FA) /* 715 */, + W64LIT(0x59E86297D87F5733) /* 716 */, W64LIT(0x298EF221898DB0E7) /* 717 */, + W64LIT(0x55000029D1A5AA7E) /* 718 */, W64LIT(0x8BC08AE1B5061B45) /* 719 */, + W64LIT(0xC2C31C2B6C92703A) /* 720 */, W64LIT(0x94CC596BAF25EF42) /* 721 */, + W64LIT(0x0A1D73DB22540456) /* 722 */, W64LIT(0x04B6A0F9D9C4179A) /* 723 */, + W64LIT(0xEFFDAFA2AE3D3C60) /* 724 */, W64LIT(0xF7C8075BB49496C4) /* 725 */, + W64LIT(0x9CC5C7141D1CD4E3) /* 726 */, W64LIT(0x78BD1638218E5534) /* 727 */, + W64LIT(0xB2F11568F850246A) /* 728 */, W64LIT(0xEDFABCFA9502BC29) /* 729 */, + W64LIT(0x796CE5F2DA23051B) /* 730 */, W64LIT(0xAAE128B0DC93537C) /* 731 */, + W64LIT(0x3A493DA0EE4B29AE) /* 732 */, W64LIT(0xB5DF6B2C416895D7) /* 733 */, + W64LIT(0xFCABBD25122D7F37) /* 734 */, W64LIT(0x70810B58105DC4B1) /* 735 */, + W64LIT(0xE10FDD37F7882A90) /* 736 */, W64LIT(0x524DCAB5518A3F5C) /* 737 */, + W64LIT(0x3C9E85878451255B) /* 738 */, W64LIT(0x4029828119BD34E2) /* 739 */, + W64LIT(0x74A05B6F5D3CECCB) /* 740 */, W64LIT(0xB610021542E13ECA) /* 741 */, + W64LIT(0x0FF979D12F59E2AC) /* 742 */, W64LIT(0x6037DA27E4F9CC50) /* 743 */, + W64LIT(0x5E92975A0DF1847D) /* 744 */, W64LIT(0xD66DE190D3E623FE) /* 745 */, + W64LIT(0x5032D6B87B568048) /* 746 */, W64LIT(0x9A36B7CE8235216E) /* 747 */, + W64LIT(0x80272A7A24F64B4A) /* 748 */, W64LIT(0x93EFED8B8C6916F7) /* 749 */, + W64LIT(0x37DDBFF44CCE1555) /* 750 */, W64LIT(0x4B95DB5D4B99BD25) /* 751 */, + W64LIT(0x92D3FDA169812FC0) /* 752 */, W64LIT(0xFB1A4A9A90660BB6) /* 753 */, + W64LIT(0x730C196946A4B9B2) /* 754 */, W64LIT(0x81E289AA7F49DA68) /* 755 */, + W64LIT(0x64669A0F83B1A05F) /* 756 */, W64LIT(0x27B3FF7D9644F48B) /* 757 */, + W64LIT(0xCC6B615C8DB675B3) /* 758 */, W64LIT(0x674F20B9BCEBBE95) /* 759 */, + W64LIT(0x6F31238275655982) /* 760 */, W64LIT(0x5AE488713E45CF05) /* 761 */, + W64LIT(0xBF619F9954C21157) /* 762 */, W64LIT(0xEABAC46040A8EAE9) /* 763 */, + W64LIT(0x454C6FE9F2C0C1CD) /* 764 */, W64LIT(0x419CF6496412691C) /* 765 */, + W64LIT(0xD3DC3BEF265B0F70) /* 766 */, W64LIT(0x6D0E60F5C3578A9E) /* 767 */, + W64LIT(0x5B0E608526323C55) /* 768 */, W64LIT(0x1A46C1A9FA1B59F5) /* 769 */, + W64LIT(0xA9E245A17C4C8FFA) /* 770 */, W64LIT(0x65CA5159DB2955D7) /* 771 */, + W64LIT(0x05DB0A76CE35AFC2) /* 772 */, W64LIT(0x81EAC77EA9113D45) /* 773 */, + W64LIT(0x528EF88AB6AC0A0D) /* 774 */, W64LIT(0xA09EA253597BE3FF) /* 775 */, + W64LIT(0x430DDFB3AC48CD56) /* 776 */, W64LIT(0xC4B3A67AF45CE46F) /* 777 */, + W64LIT(0x4ECECFD8FBE2D05E) /* 778 */, W64LIT(0x3EF56F10B39935F0) /* 779 */, + W64LIT(0x0B22D6829CD619C6) /* 780 */, W64LIT(0x17FD460A74DF2069) /* 781 */, + W64LIT(0x6CF8CC8E8510ED40) /* 782 */, W64LIT(0xD6C824BF3A6ECAA7) /* 783 */, + W64LIT(0x61243D581A817049) /* 784 */, W64LIT(0x048BACB6BBC163A2) /* 785 */, + W64LIT(0xD9A38AC27D44CC32) /* 786 */, W64LIT(0x7FDDFF5BAAF410AB) /* 787 */, + W64LIT(0xAD6D495AA804824B) /* 788 */, W64LIT(0xE1A6A74F2D8C9F94) /* 789 */, + W64LIT(0xD4F7851235DEE8E3) /* 790 */, W64LIT(0xFD4B7F886540D893) /* 791 */, + W64LIT(0x247C20042AA4BFDA) /* 792 */, W64LIT(0x096EA1C517D1327C) /* 793 */, + W64LIT(0xD56966B4361A6685) /* 794 */, W64LIT(0x277DA5C31221057D) /* 795 */, + W64LIT(0x94D59893A43ACFF7) /* 796 */, W64LIT(0x64F0C51CCDC02281) /* 797 */, + W64LIT(0x3D33BCC4FF6189DB) /* 798 */, W64LIT(0xE005CB184CE66AF1) /* 799 */, + W64LIT(0xFF5CCD1D1DB99BEA) /* 800 */, W64LIT(0xB0B854A7FE42980F) /* 801 */, + W64LIT(0x7BD46A6A718D4B9F) /* 802 */, W64LIT(0xD10FA8CC22A5FD8C) /* 803 */, + W64LIT(0xD31484952BE4BD31) /* 804 */, W64LIT(0xC7FA975FCB243847) /* 805 */, + W64LIT(0x4886ED1E5846C407) /* 806 */, W64LIT(0x28CDDB791EB70B04) /* 807 */, + W64LIT(0xC2B00BE2F573417F) /* 808 */, W64LIT(0x5C9590452180F877) /* 809 */, + W64LIT(0x7A6BDDFFF370EB00) /* 810 */, W64LIT(0xCE509E38D6D9D6A4) /* 811 */, + W64LIT(0xEBEB0F00647FA702) /* 812 */, W64LIT(0x1DCC06CF76606F06) /* 813 */, + W64LIT(0xE4D9F28BA286FF0A) /* 814 */, W64LIT(0xD85A305DC918C262) /* 815 */, + W64LIT(0x475B1D8732225F54) /* 816 */, W64LIT(0x2D4FB51668CCB5FE) /* 817 */, + W64LIT(0xA679B9D9D72BBA20) /* 818 */, W64LIT(0x53841C0D912D43A5) /* 819 */, + W64LIT(0x3B7EAA48BF12A4E8) /* 820 */, W64LIT(0x781E0E47F22F1DDF) /* 821 */, + W64LIT(0xEFF20CE60AB50973) /* 822 */, W64LIT(0x20D261D19DFFB742) /* 823 */, + W64LIT(0x16A12B03062A2E39) /* 824 */, W64LIT(0x1960EB2239650495) /* 825 */, + W64LIT(0x251C16FED50EB8B8) /* 826 */, W64LIT(0x9AC0C330F826016E) /* 827 */, + W64LIT(0xED152665953E7671) /* 828 */, W64LIT(0x02D63194A6369570) /* 829 */, + W64LIT(0x5074F08394B1C987) /* 830 */, W64LIT(0x70BA598C90B25CE1) /* 831 */, + W64LIT(0x794A15810B9742F6) /* 832 */, W64LIT(0x0D5925E9FCAF8C6C) /* 833 */, + W64LIT(0x3067716CD868744E) /* 834 */, W64LIT(0x910AB077E8D7731B) /* 835 */, + W64LIT(0x6A61BBDB5AC42F61) /* 836 */, W64LIT(0x93513EFBF0851567) /* 837 */, + W64LIT(0xF494724B9E83E9D5) /* 838 */, W64LIT(0xE887E1985C09648D) /* 839 */, + W64LIT(0x34B1D3C675370CFD) /* 840 */, W64LIT(0xDC35E433BC0D255D) /* 841 */, + W64LIT(0xD0AAB84234131BE0) /* 842 */, W64LIT(0x08042A50B48B7EAF) /* 843 */, + W64LIT(0x9997C4EE44A3AB35) /* 844 */, W64LIT(0x829A7B49201799D0) /* 845 */, + W64LIT(0x263B8307B7C54441) /* 846 */, W64LIT(0x752F95F4FD6A6CA6) /* 847 */, + W64LIT(0x927217402C08C6E5) /* 848 */, W64LIT(0x2A8AB754A795D9EE) /* 849 */, + W64LIT(0xA442F7552F72943D) /* 850 */, W64LIT(0x2C31334E19781208) /* 851 */, + W64LIT(0x4FA98D7CEAEE6291) /* 852 */, W64LIT(0x55C3862F665DB309) /* 853 */, + W64LIT(0xBD0610175D53B1F3) /* 854 */, W64LIT(0x46FE6CB840413F27) /* 855 */, + W64LIT(0x3FE03792DF0CFA59) /* 856 */, W64LIT(0xCFE700372EB85E8F) /* 857 */, + W64LIT(0xA7BE29E7ADBCE118) /* 858 */, W64LIT(0xE544EE5CDE8431DD) /* 859 */, + W64LIT(0x8A781B1B41F1873E) /* 860 */, W64LIT(0xA5C94C78A0D2F0E7) /* 861 */, + W64LIT(0x39412E2877B60728) /* 862 */, W64LIT(0xA1265EF3AFC9A62C) /* 863 */, + W64LIT(0xBCC2770C6A2506C5) /* 864 */, W64LIT(0x3AB66DD5DCE1CE12) /* 865 */, + W64LIT(0xE65499D04A675B37) /* 866 */, W64LIT(0x7D8F523481BFD216) /* 867 */, + W64LIT(0x0F6F64FCEC15F389) /* 868 */, W64LIT(0x74EFBE618B5B13C8) /* 869 */, + W64LIT(0xACDC82B714273E1D) /* 870 */, W64LIT(0xDD40BFE003199D17) /* 871 */, + W64LIT(0x37E99257E7E061F8) /* 872 */, W64LIT(0xFA52626904775AAA) /* 873 */, + W64LIT(0x8BBBF63A463D56F9) /* 874 */, W64LIT(0xF0013F1543A26E64) /* 875 */, + W64LIT(0xA8307E9F879EC898) /* 876 */, W64LIT(0xCC4C27A4150177CC) /* 877 */, + W64LIT(0x1B432F2CCA1D3348) /* 878 */, W64LIT(0xDE1D1F8F9F6FA013) /* 879 */, + W64LIT(0x606602A047A7DDD6) /* 880 */, W64LIT(0xD237AB64CC1CB2C7) /* 881 */, + W64LIT(0x9B938E7225FCD1D3) /* 882 */, W64LIT(0xEC4E03708E0FF476) /* 883 */, + W64LIT(0xFEB2FBDA3D03C12D) /* 884 */, W64LIT(0xAE0BCED2EE43889A) /* 885 */, + W64LIT(0x22CB8923EBFB4F43) /* 886 */, W64LIT(0x69360D013CF7396D) /* 887 */, + W64LIT(0x855E3602D2D4E022) /* 888 */, W64LIT(0x073805BAD01F784C) /* 889 */, + W64LIT(0x33E17A133852F546) /* 890 */, W64LIT(0xDF4874058AC7B638) /* 891 */, + W64LIT(0xBA92B29C678AA14A) /* 892 */, W64LIT(0x0CE89FC76CFAADCD) /* 893 */, + W64LIT(0x5F9D4E0908339E34) /* 894 */, W64LIT(0xF1AFE9291F5923B9) /* 895 */, + W64LIT(0x6E3480F60F4A265F) /* 896 */, W64LIT(0xEEBF3A2AB29B841C) /* 897 */, + W64LIT(0xE21938A88F91B4AD) /* 898 */, W64LIT(0x57DFEFF845C6D3C3) /* 899 */, + W64LIT(0x2F006B0BF62CAAF2) /* 900 */, W64LIT(0x62F479EF6F75EE78) /* 901 */, + W64LIT(0x11A55AD41C8916A9) /* 902 */, W64LIT(0xF229D29084FED453) /* 903 */, + W64LIT(0x42F1C27B16B000E6) /* 904 */, W64LIT(0x2B1F76749823C074) /* 905 */, + W64LIT(0x4B76ECA3C2745360) /* 906 */, W64LIT(0x8C98F463B91691BD) /* 907 */, + W64LIT(0x14BCC93CF1ADE66A) /* 908 */, W64LIT(0x8885213E6D458397) /* 909 */, + W64LIT(0x8E177DF0274D4711) /* 910 */, W64LIT(0xB49B73B5503F2951) /* 911 */, + W64LIT(0x10168168C3F96B6B) /* 912 */, W64LIT(0x0E3D963B63CAB0AE) /* 913 */, + W64LIT(0x8DFC4B5655A1DB14) /* 914 */, W64LIT(0xF789F1356E14DE5C) /* 915 */, + W64LIT(0x683E68AF4E51DAC1) /* 916 */, W64LIT(0xC9A84F9D8D4B0FD9) /* 917 */, + W64LIT(0x3691E03F52A0F9D1) /* 918 */, W64LIT(0x5ED86E46E1878E80) /* 919 */, + W64LIT(0x3C711A0E99D07150) /* 920 */, W64LIT(0x5A0865B20C4E9310) /* 921 */, + W64LIT(0x56FBFC1FE4F0682E) /* 922 */, W64LIT(0xEA8D5DE3105EDF9B) /* 923 */, + W64LIT(0x71ABFDB12379187A) /* 924 */, W64LIT(0x2EB99DE1BEE77B9C) /* 925 */, + W64LIT(0x21ECC0EA33CF4523) /* 926 */, W64LIT(0x59A4D7521805C7A1) /* 927 */, + W64LIT(0x3896F5EB56AE7C72) /* 928 */, W64LIT(0xAA638F3DB18F75DC) /* 929 */, + W64LIT(0x9F39358DABE9808E) /* 930 */, W64LIT(0xB7DEFA91C00B72AC) /* 931 */, + W64LIT(0x6B5541FD62492D92) /* 932 */, W64LIT(0x6DC6DEE8F92E4D5B) /* 933 */, + W64LIT(0x353F57ABC4BEEA7E) /* 934 */, W64LIT(0x735769D6DA5690CE) /* 935 */, + W64LIT(0x0A234AA642391484) /* 936 */, W64LIT(0xF6F9508028F80D9D) /* 937 */, + W64LIT(0xB8E319A27AB3F215) /* 938 */, W64LIT(0x31AD9C1151341A4D) /* 939 */, + W64LIT(0x773C22A57BEF5805) /* 940 */, W64LIT(0x45C7561A07968633) /* 941 */, + W64LIT(0xF913DA9E249DBE36) /* 942 */, W64LIT(0xDA652D9B78A64C68) /* 943 */, + W64LIT(0x4C27A97F3BC334EF) /* 944 */, W64LIT(0x76621220E66B17F4) /* 945 */, + W64LIT(0x967743899ACD7D0B) /* 946 */, W64LIT(0xF3EE5BCAE0ED6782) /* 947 */, + W64LIT(0x409F753600C879FC) /* 948 */, W64LIT(0x06D09A39B5926DB6) /* 949 */, + W64LIT(0x6F83AEB0317AC588) /* 950 */, W64LIT(0x01E6CA4A86381F21) /* 951 */, + W64LIT(0x66FF3462D19F3025) /* 952 */, W64LIT(0x72207C24DDFD3BFB) /* 953 */, + W64LIT(0x4AF6B6D3E2ECE2EB) /* 954 */, W64LIT(0x9C994DBEC7EA08DE) /* 955 */, + W64LIT(0x49ACE597B09A8BC4) /* 956 */, W64LIT(0xB38C4766CF0797BA) /* 957 */, + W64LIT(0x131B9373C57C2A75) /* 958 */, W64LIT(0xB1822CCE61931E58) /* 959 */, + W64LIT(0x9D7555B909BA1C0C) /* 960 */, W64LIT(0x127FAFDD937D11D2) /* 961 */, + W64LIT(0x29DA3BADC66D92E4) /* 962 */, W64LIT(0xA2C1D57154C2ECBC) /* 963 */, + W64LIT(0x58C5134D82F6FE24) /* 964 */, W64LIT(0x1C3AE3515B62274F) /* 965 */, + W64LIT(0xE907C82E01CB8126) /* 966 */, W64LIT(0xF8ED091913E37FCB) /* 967 */, + W64LIT(0x3249D8F9C80046C9) /* 968 */, W64LIT(0x80CF9BEDE388FB63) /* 969 */, + W64LIT(0x1881539A116CF19E) /* 970 */, W64LIT(0x5103F3F76BD52457) /* 971 */, + W64LIT(0x15B7E6F5AE47F7A8) /* 972 */, W64LIT(0xDBD7C6DED47E9CCF) /* 973 */, + W64LIT(0x44E55C410228BB1A) /* 974 */, W64LIT(0xB647D4255EDB4E99) /* 975 */, + W64LIT(0x5D11882BB8AAFC30) /* 976 */, W64LIT(0xF5098BBB29D3212A) /* 977 */, + W64LIT(0x8FB5EA14E90296B3) /* 978 */, W64LIT(0x677B942157DD025A) /* 979 */, + W64LIT(0xFB58E7C0A390ACB5) /* 980 */, W64LIT(0x89D3674C83BD4A01) /* 981 */, + W64LIT(0x9E2DA4DF4BF3B93B) /* 982 */, W64LIT(0xFCC41E328CAB4829) /* 983 */, + W64LIT(0x03F38C96BA582C52) /* 984 */, W64LIT(0xCAD1BDBD7FD85DB2) /* 985 */, + W64LIT(0xBBB442C16082AE83) /* 986 */, W64LIT(0xB95FE86BA5DA9AB0) /* 987 */, + W64LIT(0xB22E04673771A93F) /* 988 */, W64LIT(0x845358C9493152D8) /* 989 */, + W64LIT(0xBE2A488697B4541E) /* 990 */, W64LIT(0x95A2DC2DD38E6966) /* 991 */, + W64LIT(0xC02C11AC923C852B) /* 992 */, W64LIT(0x2388B1990DF2A87B) /* 993 */, + W64LIT(0x7C8008FA1B4F37BE) /* 994 */, W64LIT(0x1F70D0C84D54E503) /* 995 */, + W64LIT(0x5490ADEC7ECE57D4) /* 996 */, W64LIT(0x002B3C27D9063A3A) /* 997 */, + W64LIT(0x7EAEA3848030A2BF) /* 998 */, W64LIT(0xC602326DED2003C0) /* 999 */, + W64LIT(0x83A7287D69A94086) /* 1000 */, W64LIT(0xC57A5FCB30F57A8A) /* 1001 */, + W64LIT(0xB56844E479EBE779) /* 1002 */, W64LIT(0xA373B40F05DCBCE9) /* 1003 */, + W64LIT(0xD71A786E88570EE2) /* 1004 */, W64LIT(0x879CBACDBDE8F6A0) /* 1005 */, + W64LIT(0x976AD1BCC164A32F) /* 1006 */, W64LIT(0xAB21E25E9666D78B) /* 1007 */, + W64LIT(0x901063AAE5E5C33C) /* 1008 */, W64LIT(0x9818B34448698D90) /* 1009 */, + W64LIT(0xE36487AE3E1E8ABB) /* 1010 */, W64LIT(0xAFBDF931893BDCB4) /* 1011 */, + W64LIT(0x6345A0DC5FBBD519) /* 1012 */, W64LIT(0x8628FE269B9465CA) /* 1013 */, + W64LIT(0x1E5D01603F9C51EC) /* 1014 */, W64LIT(0x4DE44006A15049B7) /* 1015 */, + W64LIT(0xBF6C70E5F776CBB1) /* 1016 */, W64LIT(0x411218F2EF552BED) /* 1017 */, + W64LIT(0xCB0C0708705A36A3) /* 1018 */, W64LIT(0xE74D14754F986044) /* 1019 */, + W64LIT(0xCD56D9430EA8280E) /* 1020 */, W64LIT(0xC12591D7535F5065) /* 1021 */, + W64LIT(0xC83223F1720AEF96) /* 1022 */, W64LIT(0xC3A0396F7363A51F) /* 1023 */, + W64LIT(0xffffffffffffffff), + W64LIT(0xA5A5A5A5A5A5A5A5), + W64LIT(0x0123456789ABCDEF), +}; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/trap.h b/extension/third_party/cryptopp/trap.h new file mode 100644 index 00000000..15360b56 --- /dev/null +++ b/extension/third_party/cryptopp/trap.h @@ -0,0 +1,163 @@ +// trap.h - written and placed in public domain by Jeffrey Walton. + +/// \file trap.h +/// \brief Debugging and diagnostic assertions +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic +/// assertion. CRYPTOPP_ASSERT is enabled by CRYPTOPP_DEBUG, +/// DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls +/// DebugBreak() (Windows). +/// \details CRYPTOPP_ASSERT is only in effect when the user requests a +/// debug configuration. NDEBUG (or failure to define it) does not +/// affect CRYPTOPP_ASSERT. +/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, Issue 277, +/// CVE-2016-7420 + +#ifndef CRYPTOPP_TRAP_H +#define CRYPTOPP_TRAP_H + +#include "config.h" + +#if defined(CRYPTOPP_DEBUG) +# include +# include +# if defined(UNIX_SIGNALS_AVAILABLE) +# include "ossig.h" +# elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +# endif +#endif // CRYPTOPP_DEBUG + +// ************** run-time assertion *************** + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Debugging and diagnostic assertion +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic +/// assertion. CRYPTOPP_ASSERT is enabled by the preprocessor macros +/// CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls +/// DebugBreak() (Windows). CRYPTOPP_ASSERT is only in effect +/// when the user explicitly requests a debug configuration. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then do +/// not define CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// Avoiding the defines means CRYPTOPP_ASSERT is preprocessed into an +/// empty string. +/// \details The traditional Posix define NDEBUG has no effect on +/// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. +/// \details An example of using CRYPTOPP_ASSERT and DebugTrapHandler is shown +/// below. The library's test program, cryptest.exe (from test.cpp), +/// exercises the structure: +///
+///   \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///   static const DebugTrapHandler g_dummyHandler;
+///   \#endif
+///
+///   int main(int argc, char* argv[])
+///   {
+///      CRYPTOPP_ASSERT(argv != nullptr);
+///      ...
+///   }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, SignalHandler, Issue 277, +/// CVE-2016-7420 +# define CRYPTOPP_ASSERT(exp) { ... } +#endif + +#if defined(CRYPTOPP_DEBUG) +# if defined(UNIX_SIGNALS_AVAILABLE) || defined(__CYGWIN__) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << __FILE__ << "(" \ + << __LINE__ << "): " << __func__ \ + << std::endl; \ + std::cout << std::flush; \ + std::cerr << oss.str(); \ + raise(SIGTRAP); \ + } \ + } +# elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << __FILE__ << "(" \ + << __LINE__ << "): " << __FUNCTION__ \ + << std::endl; \ + std::cout << std::flush; \ + std::cerr << oss.str(); \ + if (IsDebuggerPresent()) {DebugBreak();} \ + } \ + } +# endif // Unix or Windows +#endif // CRYPTOPP_DEBUG + +// Remove CRYPTOPP_ASSERT in non-debug builds. +#ifndef CRYPTOPP_ASSERT +# define CRYPTOPP_ASSERT(exp) (void)0 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** SIGTRAP handler *************** + +#if (CRYPTOPP_DEBUG && defined(UNIX_SIGNALS_AVAILABLE)) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Default SIGTRAP handler +/// \details DebugTrapHandler() can be used by a program to install an empty +/// SIGTRAP handler. If present, the handler ensures there is a signal +/// handler in place for SIGTRAP raised by +/// CRYPTOPP_ASSERT. If CRYPTOPP_ASSERT raises +/// SIGTRAP without a handler, then one of two things can +/// occur. First, the OS might allow the program to continue. Second, the OS +/// might terminate the program. OS X allows the program to continue, while +/// some Linuxes terminate the program. +/// \details If DebugTrapHandler detects another handler in place, then it will +/// not install a handler. This ensures a debugger can gain control of the +/// SIGTRAP signal without contention. It also allows multiple +/// DebugTrapHandler to be created without contentious or unusual behavior. +/// Though multiple DebugTrapHandler can be created, a program should only +/// create one, if needed. +/// \details A DebugTrapHandler is subject to C++ static initialization +/// [dis]order. If you need to install a handler and it must be installed +/// early, then reference the code associated with +/// CRYPTOPP_INIT_PRIORITY in cryptlib.cpp and cpu.cpp. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then +/// do not define CRYPTOPP_DEBUG, DEBUG or +/// _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT +/// is processed into ((void)0). +/// \details The traditional Posix define NDEBUG has no effect on +/// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. +/// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and +/// DebugTrapHandler is shown below. The library's test program, +/// cryptest.exe (from test.cpp), exercises the structure: +///
+///   \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///   const DebugTrapHandler g_dummyHandler;
+///   \#endif
+///
+///   int main(int argc, char* argv[])
+///   {
+///      CRYPTOPP_ASSERT(argv != nullptr);
+///      ...
+///   }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, Issue 277, +/// CVE-2016-7420 + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +class DebugTrapHandler : public SignalHandler { }; +#else +typedef SignalHandler DebugTrapHandler; +#endif + +#endif // Linux, Unix and Documentation + +NAMESPACE_END + +#endif // CRYPTOPP_TRAP_H diff --git a/extension/third_party/cryptopp/trunhash.h b/extension/third_party/cryptopp/trunhash.h new file mode 100644 index 00000000..36df5beb --- /dev/null +++ b/extension/third_party/cryptopp/trunhash.h @@ -0,0 +1,63 @@ +// trunhash.h - originally written and placed in the public domain by Wei Dai + +/// \file trunhash.h +/// \brief Classes for truncated hashes + +#ifndef CRYPTOPP_TRUNHASH_H +#define CRYPTOPP_TRUNHASH_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Null hash +/// \details A null hash that conforms to HashTransformation interface +class NullHash : public HashTransformation +{ +public: + void Update(const byte *input, size_t length) + {CRYPTOPP_UNUSED(input);CRYPTOPP_UNUSED(length);} + unsigned int DigestSize() const + {return 0;} + void TruncatedFinal(byte *digest, size_t digestSize) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestLength);return true;} +}; + +/// \brief Construct new HashModule with smaller digest size from an existing one +/// \tparam T HashTransformation derived class +template +class TruncatedHashTemplate : public HashTransformation +{ +public: + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(T hm, unsigned int digestSize) + : m_hm(hm), m_digestSize(digestSize) {} + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(const byte *key, size_t keyLength, unsigned int digestSize) + : m_hm(key, keyLength), m_digestSize(digestSize) {} + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(size_t digestSize) + : m_digestSize(digestSize) {} + + void Restart() + {m_hm.Restart();} + void Update(const byte *input, size_t length) + {m_hm.Update(input, length);} + unsigned int DigestSize() const {return m_digestSize;} + void TruncatedFinal(byte *digest, size_t digestSize) + {m_hm.TruncatedFinal(digest, digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {return m_hm.TruncatedVerify(digest, digestLength);} + +private: + T m_hm; + unsigned int m_digestSize; +}; + +typedef TruncatedHashTemplate TruncatedHashModule; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/ttmac.cpp b/extension/third_party/cryptopp/ttmac.cpp new file mode 100644 index 00000000..db7e3485 --- /dev/null +++ b/extension/third_party/cryptopp/ttmac.cpp @@ -0,0 +1,348 @@ +// ttmac.cpp - written and placed in the public domain by Kevin Springle + +#include "pch.h" +#include "ttmac.h" +#include "misc.h" + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::word32; +using CryptoPP::rotlVariable; +using CryptoPP::rotlConstant; + +// RIPEMD-160 definitions used by Two-Track-MAC +word32 F(word32 x, word32 y, word32 z) { return x ^ y ^ z; } +word32 G(word32 x, word32 y, word32 z) { return z ^ (x & (y^z)); } +word32 H(word32 x, word32 y, word32 z) { return z ^ (x | ~y); } +word32 I(word32 x, word32 y, word32 z) { return y ^ (z & (x^y)); } +word32 J(word32 x, word32 y, word32 z) { return x ^ (y | ~z); } + +template +void Subround(Fn fn, word32& a, word32 b, word32& c, word32 d, word32 e, word32 x, word32 k) +{ + a += fn(b, c, d) + x + k; + a = rotlVariable(a, S) + e; + c = rotlConstant<10>(c); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +const unsigned int k0 = 0; +const unsigned int k1 = 0x5a827999; +const unsigned int k2 = 0x6ed9eba1; +const unsigned int k3 = 0x8f1bbcdc; +const unsigned int k4 = 0xa953fd4e; +const unsigned int k5 = 0x50a28be6; +const unsigned int k6 = 0x5c4dd124; +const unsigned int k7 = 0x6d703ef3; +const unsigned int k8 = 0x7a6d76e9; +const unsigned int k9 = 0; + +void TTMAC_Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + memcpy(m_key, userKey, KEYLENGTH); + CorrectEndianess(m_key, m_key, KEYLENGTH); + + Init(); +} + +void TTMAC_Base::Init() +{ + m_digest[0] = m_digest[5] = m_key[0]; + m_digest[1] = m_digest[6] = m_key[1]; + m_digest[2] = m_digest[7] = m_key[2]; + m_digest[3] = m_digest[8] = m_key[3]; + m_digest[4] = m_digest[9] = m_key[4]; +} + +void TTMAC_Base::TruncatedFinal(byte *hash, size_t size) +{ + PadLastBlock(BlockSize() - 2*sizeof(HashWordType)); + CorrectEndianess(m_data, m_data, BlockSize() - 2*sizeof(HashWordType)); + + m_data[m_data.size()-2] = GetBitCountLo(); + m_data[m_data.size()-1] = GetBitCountHi(); + + Transform(m_digest, m_data, true); + + word32 t2 = m_digest[2]; + word32 t3 = m_digest[3]; + if (size != DIGESTSIZE) + { + switch (size) + { + case 16: + m_digest[3] += m_digest[1] + m_digest[4]; + // fall through + case 12: + m_digest[2] += m_digest[0] + t3; + // fall through + case 8: + m_digest[0] += m_digest[1] + t3; + m_digest[1] += m_digest[4] + t2; + break; + + case 4: + m_digest[0] += + m_digest[1] + + m_digest[2] + + m_digest[3] + + m_digest[4]; + break; + + case 0: + // Used by HashTransformation::Restart() + break; + + default: + throw InvalidArgument("TTMAC_Base: can't truncate a Two-Track-MAC 20 byte digest to " + IntToString(size) + " bytes"); + break; + } + } + + CorrectEndianess(m_digest, m_digest, size); + memcpy(hash, m_digest, size); + + Restart(); // reinit for next use +} + +void TTMAC_Base::Transform(word32 *digest, const word32 *X, bool last) +{ + word32 a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + word32 *trackA, *trackB; + + if (!last) + { + trackA = digest; + trackB = digest+5; + } + else + { + trackB = digest; + trackA = digest+5; + } + a1 = trackA[0]; + b1 = trackA[1]; + c1 = trackA[2]; + d1 = trackA[3]; + e1 = trackA[4]; + a2 = trackB[0]; + b2 = trackB[1]; + c2 = trackB[2]; + d2 = trackB[3]; + e2 = trackB[4]; + + Subround<11>(F, a1, b1, c1, d1, e1, X[ 0], k0); + Subround<14>(F, e1, a1, b1, c1, d1, X[ 1], k0); + Subround<15>(F, d1, e1, a1, b1, c1, X[ 2], k0); + Subround<12>(F, c1, d1, e1, a1, b1, X[ 3], k0); + Subround< 5>(F, b1, c1, d1, e1, a1, X[ 4], k0); + Subround< 8>(F, a1, b1, c1, d1, e1, X[ 5], k0); + Subround< 7>(F, e1, a1, b1, c1, d1, X[ 6], k0); + Subround< 9>(F, d1, e1, a1, b1, c1, X[ 7], k0); + Subround<11>(F, c1, d1, e1, a1, b1, X[ 8], k0); + Subround<13>(F, b1, c1, d1, e1, a1, X[ 9], k0); + Subround<14>(F, a1, b1, c1, d1, e1, X[10], k0); + Subround<15>(F, e1, a1, b1, c1, d1, X[11], k0); + Subround< 6>(F, d1, e1, a1, b1, c1, X[12], k0); + Subround< 7>(F, c1, d1, e1, a1, b1, X[13], k0); + Subround< 9>(F, b1, c1, d1, e1, a1, X[14], k0); + Subround< 8>(F, a1, b1, c1, d1, e1, X[15], k0); + + Subround< 7>(G, e1, a1, b1, c1, d1, X[ 7], k1); + Subround< 6>(G, d1, e1, a1, b1, c1, X[ 4], k1); + Subround< 8>(G, c1, d1, e1, a1, b1, X[13], k1); + Subround<13>(G, b1, c1, d1, e1, a1, X[ 1], k1); + Subround<11>(G, a1, b1, c1, d1, e1, X[10], k1); + Subround< 9>(G, e1, a1, b1, c1, d1, X[ 6], k1); + Subround< 7>(G, d1, e1, a1, b1, c1, X[15], k1); + Subround<15>(G, c1, d1, e1, a1, b1, X[ 3], k1); + Subround< 7>(G, b1, c1, d1, e1, a1, X[12], k1); + Subround<12>(G, a1, b1, c1, d1, e1, X[ 0], k1); + Subround<15>(G, e1, a1, b1, c1, d1, X[ 9], k1); + Subround< 9>(G, d1, e1, a1, b1, c1, X[ 5], k1); + Subround<11>(G, c1, d1, e1, a1, b1, X[ 2], k1); + Subround< 7>(G, b1, c1, d1, e1, a1, X[14], k1); + Subround<13>(G, a1, b1, c1, d1, e1, X[11], k1); + Subround<12>(G, e1, a1, b1, c1, d1, X[ 8], k1); + + Subround<11>(H, d1, e1, a1, b1, c1, X[ 3], k2); + Subround<13>(H, c1, d1, e1, a1, b1, X[10], k2); + Subround< 6>(H, b1, c1, d1, e1, a1, X[14], k2); + Subround< 7>(H, a1, b1, c1, d1, e1, X[ 4], k2); + Subround<14>(H, e1, a1, b1, c1, d1, X[ 9], k2); + Subround< 9>(H, d1, e1, a1, b1, c1, X[15], k2); + Subround<13>(H, c1, d1, e1, a1, b1, X[ 8], k2); + Subround<15>(H, b1, c1, d1, e1, a1, X[ 1], k2); + Subround<14>(H, a1, b1, c1, d1, e1, X[ 2], k2); + Subround< 8>(H, e1, a1, b1, c1, d1, X[ 7], k2); + Subround<13>(H, d1, e1, a1, b1, c1, X[ 0], k2); + Subround< 6>(H, c1, d1, e1, a1, b1, X[ 6], k2); + Subround< 5>(H, b1, c1, d1, e1, a1, X[13], k2); + Subround<12>(H, a1, b1, c1, d1, e1, X[11], k2); + Subround< 7>(H, e1, a1, b1, c1, d1, X[ 5], k2); + Subround< 5>(H, d1, e1, a1, b1, c1, X[12], k2); + + Subround<11>(I, c1, d1, e1, a1, b1, X[ 1], k3); + Subround<12>(I, b1, c1, d1, e1, a1, X[ 9], k3); + Subround<14>(I, a1, b1, c1, d1, e1, X[11], k3); + Subround<15>(I, e1, a1, b1, c1, d1, X[10], k3); + Subround<14>(I, d1, e1, a1, b1, c1, X[ 0], k3); + Subround<15>(I, c1, d1, e1, a1, b1, X[ 8], k3); + Subround< 9>(I, b1, c1, d1, e1, a1, X[12], k3); + Subround< 8>(I, a1, b1, c1, d1, e1, X[ 4], k3); + Subround< 9>(I, e1, a1, b1, c1, d1, X[13], k3); + Subround<14>(I, d1, e1, a1, b1, c1, X[ 3], k3); + Subround< 5>(I, c1, d1, e1, a1, b1, X[ 7], k3); + Subround< 6>(I, b1, c1, d1, e1, a1, X[15], k3); + Subround< 8>(I, a1, b1, c1, d1, e1, X[14], k3); + Subround< 6>(I, e1, a1, b1, c1, d1, X[ 5], k3); + Subround< 5>(I, d1, e1, a1, b1, c1, X[ 6], k3); + Subround<12>(I, c1, d1, e1, a1, b1, X[ 2], k3); + + Subround< 9>(J, b1, c1, d1, e1, a1, X[ 4], k4); + Subround<15>(J, a1, b1, c1, d1, e1, X[ 0], k4); + Subround< 5>(J, e1, a1, b1, c1, d1, X[ 5], k4); + Subround<11>(J, d1, e1, a1, b1, c1, X[ 9], k4); + Subround< 6>(J, c1, d1, e1, a1, b1, X[ 7], k4); + Subround< 8>(J, b1, c1, d1, e1, a1, X[12], k4); + Subround<13>(J, a1, b1, c1, d1, e1, X[ 2], k4); + Subround<12>(J, e1, a1, b1, c1, d1, X[10], k4); + Subround< 5>(J, d1, e1, a1, b1, c1, X[14], k4); + Subround<12>(J, c1, d1, e1, a1, b1, X[ 1], k4); + Subround<13>(J, b1, c1, d1, e1, a1, X[ 3], k4); + Subround<14>(J, a1, b1, c1, d1, e1, X[ 8], k4); + Subround<11>(J, e1, a1, b1, c1, d1, X[11], k4); + Subround< 8>(J, d1, e1, a1, b1, c1, X[ 6], k4); + Subround< 5>(J, c1, d1, e1, a1, b1, X[15], k4); + Subround< 6>(J, b1, c1, d1, e1, a1, X[13], k4); + + Subround< 8>(J, a2, b2, c2, d2, e2, X[ 5], k5); + Subround< 9>(J, e2, a2, b2, c2, d2, X[14], k5); + Subround< 9>(J, d2, e2, a2, b2, c2, X[ 7], k5); + Subround<11>(J, c2, d2, e2, a2, b2, X[ 0], k5); + Subround<13>(J, b2, c2, d2, e2, a2, X[ 9], k5); + Subround<15>(J, a2, b2, c2, d2, e2, X[ 2], k5); + Subround<15>(J, e2, a2, b2, c2, d2, X[11], k5); + Subround< 5>(J, d2, e2, a2, b2, c2, X[ 4], k5); + Subround< 7>(J, c2, d2, e2, a2, b2, X[13], k5); + Subround< 7>(J, b2, c2, d2, e2, a2, X[ 6], k5); + Subround< 8>(J, a2, b2, c2, d2, e2, X[15], k5); + Subround<11>(J, e2, a2, b2, c2, d2, X[ 8], k5); + Subround<14>(J, d2, e2, a2, b2, c2, X[ 1], k5); + Subround<14>(J, c2, d2, e2, a2, b2, X[10], k5); + Subround<12>(J, b2, c2, d2, e2, a2, X[ 3], k5); + Subround< 6>(J, a2, b2, c2, d2, e2, X[12], k5); + + Subround< 9>(I, e2, a2, b2, c2, d2, X[ 6], k6); + Subround<13>(I, d2, e2, a2, b2, c2, X[11], k6); + Subround<15>(I, c2, d2, e2, a2, b2, X[ 3], k6); + Subround< 7>(I, b2, c2, d2, e2, a2, X[ 7], k6); + Subround<12>(I, a2, b2, c2, d2, e2, X[ 0], k6); + Subround< 8>(I, e2, a2, b2, c2, d2, X[13], k6); + Subround< 9>(I, d2, e2, a2, b2, c2, X[ 5], k6); + Subround<11>(I, c2, d2, e2, a2, b2, X[10], k6); + Subround< 7>(I, b2, c2, d2, e2, a2, X[14], k6); + Subround< 7>(I, a2, b2, c2, d2, e2, X[15], k6); + Subround<12>(I, e2, a2, b2, c2, d2, X[ 8], k6); + Subround< 7>(I, d2, e2, a2, b2, c2, X[12], k6); + Subround< 6>(I, c2, d2, e2, a2, b2, X[ 4], k6); + Subround<15>(I, b2, c2, d2, e2, a2, X[ 9], k6); + Subround<13>(I, a2, b2, c2, d2, e2, X[ 1], k6); + Subround<11>(I, e2, a2, b2, c2, d2, X[ 2], k6); + + Subround< 9>(H, d2, e2, a2, b2, c2, X[15], k7); + Subround< 7>(H, c2, d2, e2, a2, b2, X[ 5], k7); + Subround<15>(H, b2, c2, d2, e2, a2, X[ 1], k7); + Subround<11>(H, a2, b2, c2, d2, e2, X[ 3], k7); + Subround< 8>(H, e2, a2, b2, c2, d2, X[ 7], k7); + Subround< 6>(H, d2, e2, a2, b2, c2, X[14], k7); + Subround< 6>(H, c2, d2, e2, a2, b2, X[ 6], k7); + Subround<14>(H, b2, c2, d2, e2, a2, X[ 9], k7); + Subround<12>(H, a2, b2, c2, d2, e2, X[11], k7); + Subround<13>(H, e2, a2, b2, c2, d2, X[ 8], k7); + Subround< 5>(H, d2, e2, a2, b2, c2, X[12], k7); + Subround<14>(H, c2, d2, e2, a2, b2, X[ 2], k7); + Subround<13>(H, b2, c2, d2, e2, a2, X[10], k7); + Subround<13>(H, a2, b2, c2, d2, e2, X[ 0], k7); + Subround< 7>(H, e2, a2, b2, c2, d2, X[ 4], k7); + Subround< 5>(H, d2, e2, a2, b2, c2, X[13], k7); + + Subround<15>(G, c2, d2, e2, a2, b2, X[ 8], k8); + Subround< 5>(G, b2, c2, d2, e2, a2, X[ 6], k8); + Subround< 8>(G, a2, b2, c2, d2, e2, X[ 4], k8); + Subround<11>(G, e2, a2, b2, c2, d2, X[ 1], k8); + Subround<14>(G, d2, e2, a2, b2, c2, X[ 3], k8); + Subround<14>(G, c2, d2, e2, a2, b2, X[11], k8); + Subround< 6>(G, b2, c2, d2, e2, a2, X[15], k8); + Subround<14>(G, a2, b2, c2, d2, e2, X[ 0], k8); + Subround< 6>(G, e2, a2, b2, c2, d2, X[ 5], k8); + Subround< 9>(G, d2, e2, a2, b2, c2, X[12], k8); + Subround<12>(G, c2, d2, e2, a2, b2, X[ 2], k8); + Subround< 9>(G, b2, c2, d2, e2, a2, X[13], k8); + Subround<12>(G, a2, b2, c2, d2, e2, X[ 9], k8); + Subround< 5>(G, e2, a2, b2, c2, d2, X[ 7], k8); + Subround<15>(G, d2, e2, a2, b2, c2, X[10], k8); + Subround< 8>(G, c2, d2, e2, a2, b2, X[14], k8); + + Subround< 8>(F, b2, c2, d2, e2, a2, X[12], k9); + Subround< 5>(F, a2, b2, c2, d2, e2, X[15], k9); + Subround<12>(F, e2, a2, b2, c2, d2, X[10], k9); + Subround< 9>(F, d2, e2, a2, b2, c2, X[ 4], k9); + Subround<12>(F, c2, d2, e2, a2, b2, X[ 1], k9); + Subround< 5>(F, b2, c2, d2, e2, a2, X[ 5], k9); + Subround<14>(F, a2, b2, c2, d2, e2, X[ 8], k9); + Subround< 6>(F, e2, a2, b2, c2, d2, X[ 7], k9); + Subround< 8>(F, d2, e2, a2, b2, c2, X[ 6], k9); + Subround<13>(F, c2, d2, e2, a2, b2, X[ 2], k9); + Subround< 6>(F, b2, c2, d2, e2, a2, X[13], k9); + Subround< 5>(F, a2, b2, c2, d2, e2, X[14], k9); + Subround<15>(F, e2, a2, b2, c2, d2, X[ 0], k9); + Subround<13>(F, d2, e2, a2, b2, c2, X[ 3], k9); + Subround<11>(F, c2, d2, e2, a2, b2, X[ 9], k9); + Subround<11>(F, b2, c2, d2, e2, a2, X[11], k9); + + a1 -= trackA[0]; + b1 -= trackA[1]; + c1 -= trackA[2]; + d1 -= trackA[3]; + e1 -= trackA[4]; + a2 -= trackB[0]; + b2 -= trackB[1]; + c2 -= trackB[2]; + d2 -= trackB[3]; + e2 -= trackB[4]; + + if (!last) + { + trackA[0] = (b1 + e1) - d2; + trackA[1] = c1 - e2; + trackA[2] = d1 - a2; + trackA[3] = e1 - b2; + trackA[4] = a1 - c2; + trackB[0] = d1 - e2; + trackB[1] = (e1 + c1) - a2; + trackB[2] = a1 - b2; + trackB[3] = b1 - c2; + trackB[4] = c1 - d2; + } + else + { + trackB[0] = a2 - a1; + trackB[1] = b2 - b1; + trackB[2] = c2 - c1; + trackB[3] = d2 - d1; + trackB[4] = e2 - e1; + trackA[0] = 0; + trackA[1] = 0; + trackA[2] = 0; + trackA[3] = 0; + trackA[4] = 0; + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/ttmac.h b/extension/third_party/cryptopp/ttmac.h new file mode 100644 index 00000000..d50b0038 --- /dev/null +++ b/extension/third_party/cryptopp/ttmac.h @@ -0,0 +1,44 @@ +// ttmac.h - written and placed in the public domain by Kevin Springle + +/// \file ttmac.h +/// \brief Classes for the TTMAC message authentication code + +#ifndef CRYPTOPP_TTMAC_H +#define CRYPTOPP_TTMAC_H + +#include "seckey.h" +#include "iterhash.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TTMAC message authentication code information +class CRYPTOPP_NO_VTABLE TTMAC_Base : public FixedKeyLength<20>, public IteratedHash +{ +public: + static std::string StaticAlgorithmName() {return std::string("Two-Track-MAC");} + CRYPTOPP_CONSTANT(DIGESTSIZE=20); + + unsigned int DigestSize() const {return DIGESTSIZE;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + +protected: + static void Transform (word32 *digest, const word32 *X, bool last); + void HashEndianCorrectedBlock(const word32 *data) {Transform(m_digest, data, false);} + void Init(); + word32* StateBuf() {return m_digest;} + + FixedSizeSecBlock m_digest; + FixedSizeSecBlock m_key; +}; + +/// \brief Two-Track-MAC message authentication code +/// \tparam T HashTransformation class +/// \details 160-bit MAC with 160-bit key +/// \sa MessageAuthenticationCode(), Two-Track-MAC +DOCUMENTED_TYPEDEF(MessageAuthenticationCodeFinal, TTMAC); + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/tweetnacl.cpp b/extension/third_party/cryptopp/tweetnacl.cpp new file mode 100644 index 00000000..71d80e70 --- /dev/null +++ b/extension/third_party/cryptopp/tweetnacl.cpp @@ -0,0 +1,924 @@ +// tweetnacl.cpp - modified tweetnacl.c placed in public domain by Jeffrey Walton. +// The NaCl library and tweetnacl.c is public domain source code +// written by Daniel J. Bernstein, Bernard van Gastel, Wesley +// Janssen, Tanja Lange, Peter Schwabe and Sjaak Smetsers. + +#include "pch.h" +#include "config.h" +#include "naclite.h" +#include "misc.h" +#include "osrng.h" +#include "stdcpp.h" + +// Don't destroy const time properties when squashing warnings. +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4146 4242 4244 4245) +#endif + +// Can't use GetAlignmentOf() because of C++11 and constexpr +// Can use 'const unsigned int' because of MSVC 2013 +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +# define ALIGN_SPEC 16 +#else +# define ALIGN_SPEC 4 +#endif + +#ifndef CRYPTOPP_DISABLE_NACL + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(NaCl) + +typedef sword64 gf[16]; + +static const byte + _0[32] = {0}, + _9[32] = {9}; + +static const gf + gf0 = {0}, + gf1 = {1}, + _121665 = {0xDB41,1}, + D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, + D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, + X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, + Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, + I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; + +// Added by Crypto++ for TweetNaCl +static void randombytes(byte * block, word64 size) +{ + DefaultAutoSeededRNG prng; + prng.GenerateBlock(block, (size_t)size); +} + +static word32 L32(word32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); } + +static word32 ld32(const byte *x) +{ + word32 u = x[3]; + u = (u<<8)|x[2]; + u = (u<<8)|x[1]; + return (u<<8)|x[0]; +} + +static word64 dl64(const byte *x) +{ + word64 i,u=0; + for(i=0; i<8; ++i) u=(u<<8)|x[i]; + return u; +} + +static void st32(byte *x,word32 u) +{ + int i; + for(i=0; i<4; ++i) { x[i] = u; u >>= 8; } +} + +static void ts64(byte *x,word64 u) +{ + int i; + for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } +} + +// Extra cast due to Coverity CID 186949 +static int verify_n(const byte *x,const byte *y,word32 n) +{ + word32 i,d = 0; + for(i=0; i> 8)) - 1; +} + +int crypto_verify_16(const byte *x,const byte *y) +{ + return verify_n(x,y,16); +} + +int crypto_verify_32(const byte *x,const byte *y) +{ + return verify_n(x,y,32); +} + +static void core(byte *out,const byte *in,const byte *k,const byte *c,int h) +{ + word32 w[16],x[16],y[16],t[4]; + int i,j,m; + + for(i=0; i<4; ++i) { + x[5*i] = ld32(c+4*i); + x[1+i] = ld32(k+4*i); + x[6+i] = ld32(in+4*i); + x[11+i] = ld32(k+16+4*i); + } + + for(i=0; i<16; ++i) y[i] = x[i]; + + for(i=0; i<20; ++i) { + for(j=0; j<4; ++j) { + for(m=0; m<4; ++m) t[m] = x[(5*j+4*m)%16]; + t[1] ^= L32(t[0]+t[3], 7); + t[2] ^= L32(t[1]+t[0], 9); + t[3] ^= L32(t[2]+t[1],13); + t[0] ^= L32(t[3]+t[2],18); + for(m=0; m<4; ++m) w[4*j+(j+m)%4] = t[m]; + } + for(m=0; m<16; ++m) x[m] = w[m]; + } + + if (h) { + for(i=0; i<16; ++i) x[i] += y[i]; + for(i=0; i<4; ++i) { + x[5*i] -= ld32(c+4*i); + x[6+i] -= ld32(in+4*i); + } + for(i=0; i<4; ++i) { + st32(out+4*i,x[5*i]); + st32(out+16+4*i,x[6+i]); + } + } else + for(i=0; i<16; ++i) st32(out + 4 * i,x[i] + y[i]); +} + +int crypto_core_salsa20(byte *out,const byte *in,const byte *k,const byte *c) +{ + core(out,in,k,c,0); + return 0; +} + +int crypto_core_hsalsa20(byte *out,const byte *in,const byte *k,const byte *c) +{ + core(out,in,k,c,1); + return 0; +} + +static const byte sigma[16] = {0x65,0x78,0x70,0x61,0x6E,0x64,0x20,0x33,0x32,0x2D,0x62,0x79,0x74,0x65,0x20,0x6B}; + +int crypto_stream_salsa20_xor(byte *c,const byte *m,word64 b,const byte *n,const byte *k) +{ + byte z[16],x[64]; + word32 u,i; + if (!b) return 0; + for(i=0; i<16; ++i) z[i] = 0; + for(i=0; i<8; ++i) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for(i=0; i<64; ++i) c[i] = (m?m[i]:0) ^ x[i]; + u = 1; + for (i = 8;i < 16;++i) { + u += (word32) z[i]; + z[i] = u; + u >>= 8; + } + b -= 64; + c += 64; + if (m) m += 64; + } + if (b) { + crypto_core_salsa20(x,z,k,sigma); + for(i=0; i>= 8; + } +} + +static const word32 minusp[17] = { + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 +} ; + +int crypto_onetimeauth(byte *out,const byte *m,word64 n,const byte *k) +{ + word32 s,i,j,u,x[17],r[17],h[17],c[17],g[17]; + + for(j=0; j<17; ++j) r[j]=h[j]=0; + for(j=0; j<16; ++j) r[j]=k[j]; + r[3]&=15; + r[4]&=252; + r[7]&=15; + r[8]&=252; + r[11]&=15; + r[12]&=252; + r[15]&=15; + + while (n > 0) { + for(j=0; j<17; ++j) c[j] = 0; + for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j]; + c[j] = 1; + m += j; n -= j; + add1305(h,c); + for(i=0; i<17; ++i) { + x[i] = 0; + for(j=0; j<17; ++j) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); + } + for(i=0; i<17; ++i) h[i] = x[i]; + u = 0; + for(j=0; j<16; ++j) { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; h[16] = u & 3; + u = 5 * (u >> 2); + for(j=0; j<16; ++j) { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; h[16] = u; + } + + for(j=0; j<17; ++j) g[j] = h[j]; + add1305(h,minusp); + s = -(h[16] >> 7); + for(j=0; j<17; ++j) h[j] ^= s & (g[j] ^ h[j]); + + for(j=0; j<16; ++j) c[j] = k[j + 16]; + c[16] = 0; + add1305(h,c); + for(j=0; j<16; ++j) out[j] = h[j]; + return 0; +} + +int crypto_onetimeauth_verify(const byte *h,const byte *m,word64 n,const byte *k) +{ + byte x[16]; + crypto_onetimeauth(x,m,n,k); + return crypto_verify_16(h,x); +} + +int crypto_secretbox(byte *c,const byte *m,word64 d,const byte *n,const byte *k) +{ + int i; + if (d < 32) return -1; + crypto_stream_xor(c,m,d,n,k); + crypto_onetimeauth(c + 16,c + 32,d - 32,c); + for(i=0; i<16; ++i) c[i] = 0; + return 0; +} + +int crypto_secretbox_open(byte *m,const byte *c,word64 d,const byte *n,const byte *k) +{ + int i; + byte x[32]; + if (d < 32) return -1; + crypto_stream(x,32,n,k); + if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1; + crypto_stream_xor(m,c,d,n,k); + for(i=0; i<32; ++i) m[i] = 0; + return 0; +} + +static void set25519(gf r, const gf a) +{ + int i; + for(i=0; i<16; ++i) r[i]=a[i]; +} + +static void car25519(gf o) +{ + int i; + sword64 c; + for(i=0; i<16; ++i) { + o[i]+=(1LL<<16); + c=o[i]>>16; + o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); + o[i]-=((word64)c)<<16; + } +} + +static void sel25519(gf p,gf q,int b) +{ + sword64 t,i,c=~(b-1); + for(i=0; i<16; ++i) { + t= c&(p[i]^q[i]); + p[i]^=t; + q[i]^=t; + } +} + +static void pack25519(byte *o,const gf n) +{ + int i,j,b; + gf m,t; + for(i=0; i<16; ++i) t[i]=n[i]; + car25519(t); + car25519(t); + car25519(t); + for(j=0; j<2; ++j) { + m[0]=t[0]-0xffed; + for(i=1;i<15;i++) { + m[i]=t[i]-0xffff-((m[i-1]>>16)&1); + m[i-1]&=0xffff; + } + m[15]=t[15]-0x7fff-((m[14]>>16)&1); + b=(m[15]>>16)&1; + m[14]&=0xffff; + sel25519(t,m,1-b); + } + for(i=0; i<16; ++i) { + o[2*i]=t[i]&0xff; + o[2*i+1]=t[i]>>8; + } +} + +static int neq25519(const gf a, const gf b) +{ + byte c[32],d[32]; + pack25519(c,a); + pack25519(d,b); + return crypto_verify_32(c,d); +} + +static byte par25519(const gf a) +{ + byte d[32]; + pack25519(d,a); + return d[0]&1; +} + +static void unpack25519(gf o, const byte *n) +{ + int i; + for(i=0; i<16; ++i) o[i]=n[2*i]+((sword64)n[2*i+1]<<8); + o[15]&=0x7fff; +} + +static void A(gf o,const gf a,const gf b) +{ + int i; + for(i=0; i<16; ++i) o[i]=a[i]+b[i]; +} + +static void Z(gf o,const gf a,const gf b) +{ + int i; + for(i=0; i<16; ++i) o[i]=a[i]-b[i]; +} + +static void M(gf o,const gf a,const gf b) +{ + sword64 i,j,t[31]; + for(i=0; i<31; ++i) t[i]=0; + for(i=0; i<16; ++i) for(j=0; j<16; ++j) t[i+j]+=a[i]*b[j]; + for(i=0; i<15; ++i) t[i]+=38*t[i+16]; + for(i=0; i<16; ++i) o[i]=t[i]; + car25519(o); + car25519(o); +} + +static void S(gf o,const gf a) +{ + M(o,a,a); +} + +static void inv25519(gf o,const gf i) +{ + gf c; + int a; + for(a=0; a<16; ++a) c[a]=i[a]; + for(a=253;a>=0;a--) { + S(c,c); + if(a!=2&&a!=4) M(c,c,i); + } + for(a=0; a<16; ++a) o[a]=c[a]; +} + +static void pow2523(gf o,const gf i) +{ + gf c; + int a; + for(a=0; a<16; ++a) c[a]=i[a]; + for(a=250;a>=0;a--) { + S(c,c); + if(a!=1) M(c,c,i); + } + for(a=0; a<16; ++a) o[a]=c[a]; +} + +// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c +static int has_small_order(const byte s[32]) +{ + CRYPTOPP_ALIGN_DATA(ALIGN_SPEC) + const byte blacklist[][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 }, + { 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 }, + { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 }, + { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 }, + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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 }, + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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 }, + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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 }, + { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 }, + { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 }, + { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + CRYPTOPP_COMPILE_ASSERT(12 == COUNTOF(blacklist)); + + byte c[12] = { 0 }; + for (size_t j = 0; j < 32; j++) { + for (size_t i = 0; i < COUNTOF(blacklist); i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + + unsigned int k = 0; + for (size_t i = 0; i < COUNTOF(blacklist); i++) { + k |= (c[i] - 1); + } + + return (int) ((k >> 8) & 1); +} + +int crypto_scalarmult(byte *q,const byte *n,const byte *p) +{ + byte z[32]; + sword64 x[80],r,i; + gf a,b,c,d,e,f; + for(i=0; i<31; ++i) z[i]=n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for(i=0; i<16; ++i) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for(i=254;i>=0;--i) { + r=(z[i>>3]>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for(i=0; i<16; ++i) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + inv25519(x+32,x+32); + M(x+16,x+16,x+32); + pack25519(q,x+16); + return 0; +} + +int crypto_scalarmult_base(byte *q,const byte *n) +{ + return crypto_scalarmult(q,n,_9); +} + +int crypto_box_keypair(byte *y,byte *x) +{ + randombytes(x,32); + return crypto_scalarmult_base(y,x); +} + +// Avoid small order elements. Also see https://eprint.iacr.org/2017/806.pdf +// and https://github.com/jedisct1/libsodium/commit/675149b9b8b66ff4. +int crypto_box_beforenm(byte *k,const byte *y,const byte *x) +{ + byte s[32]; + if(crypto_scalarmult(s,x,y) != 0) return -1; + if(has_small_order(s) != 0) return -1; + return crypto_core_hsalsa20(k,_0,s,sigma); +} + +// Allow small order elements. Also see https://eprint.iacr.org/2017/806.pdf +int crypto_box_beforenm_unchecked(byte *k,const byte *y,const byte *x) +{ + byte s[32]; + if(crypto_scalarmult(s,x,y) != 0) return -1; + return crypto_core_hsalsa20(k,_0,s,sigma); +} + +int crypto_box_afternm(byte *c,const byte *m,word64 d,const byte *n,const byte *k) +{ + return crypto_secretbox(c,m,d,n,k); +} + +int crypto_box_open_afternm(byte *m,const byte *c,word64 d,const byte *n,const byte *k) +{ + return crypto_secretbox_open(m,c,d,n,k); +} + +int crypto_box(byte *c, const byte *m, word64 d, const byte *n, const byte *y, const byte *x) +{ + byte k[32]; + if (crypto_box_beforenm(k, y, x) != 0) return -1; + return crypto_box_afternm(c, m, d, n, k); +} + +int crypto_box_unchecked(byte *c, const byte *m, word64 d, const byte *n, const byte *y, const byte *x) +{ + byte k[32]; + crypto_box_beforenm_unchecked(k, y, x); + return crypto_box_afternm(c, m, d, n, k); +} + +int crypto_box_open(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x) +{ + byte k[32]; + if(crypto_box_beforenm(k,y,x) != 0) return -1; + return crypto_box_open_afternm(m,c,d,n,k); +} + +int crypto_box_open_unchecked(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x) +{ + byte k[32]; + crypto_box_beforenm_unchecked(k,y,x); + return crypto_box_open_afternm(m,c,d,n,k); +} + +static word64 R(word64 x,int c) { return (x >> c) | (x << (64 - c)); } +static word64 Ch(word64 x,word64 y,word64 z) { return (x & y) ^ (~x & z); } +static word64 Maj(word64 x,word64 y,word64 z) { return (x & y) ^ (x & z) ^ (y & z); } +static word64 Sigma0(word64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); } +static word64 Sigma1(word64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); } +static word64 sigma0(word64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); } +static word64 sigma1(word64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); } + +static const word64 K[80] = +{ + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) +}; + +int crypto_hashblocks(byte *x,const byte *m,word64 n) +{ + word64 z[8],b[8],a[8],w[16],t; + int i,j; + + for(i=0; i<8; ++i) z[i] = a[i] = dl64(x + 8 * i); + + while (n >= 128) { + for(i=0; i<16; ++i) w[i] = dl64(m + 8 * i); + + for(i=0; i<80; ++i) { + for(j=0; j<8; ++j) b[j] = a[j]; + t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; + b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); + b[3] += t; + for(j=0; j<8; ++j) a[(j+1)%8] = b[j]; + if (i%16 == 15) + for(j=0; j<16; ++j) + w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); + } + + for(i=0; i<8; ++i) { a[i] += z[i]; z[i] = a[i]; } + + m += 128; + n -= 128; + } + + for(i=0; i<8; ++i) ts64(x+8*i,z[i]); + + return n; +} + +static const byte iv[64] = { + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +} ; + +int crypto_hash(byte *out,const byte *m,word64 n) +{ + byte h[64],x[256]; + word64 i,b = n; + + for(i=0; i<64; ++i) h[i] = iv[i]; + + crypto_hashblocks(h,m,n); + m += n; + n &= 127; + m -= n; + + for(i=0; i<256; ++i) x[i] = 0; + for(i=0; i> 61; + ts64(x+n-8,b<<3); + crypto_hashblocks(h,x,n); + + for(i=0; i<64; ++i) out[i] = h[i]; + + return 0; +} + +static void add(gf p[4],gf q[4]) +{ + gf a,b,c,d,t,e,f,g,h; + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +static void cswap(gf p[4],gf q[4],byte b) +{ + int i; + for(i=0; i<4; ++i) + sel25519(p[i],q[i],b); +} + +static void pack(byte *r,gf p[4]) +{ + gf tx, ty, zi; + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +static void scalarmult(gf p[4],gf q[4],const byte *s) +{ + int i; + set25519(p[0],gf0); + set25519(p[1],gf1); + set25519(p[2],gf1); + set25519(p[3],gf0); + for (i = 255;i >= 0;--i) { + byte b = (s[i/8]>>(i&7))&1; + cswap(p,q,b); + add(q,p); + add(p,p); + cswap(p,q,b); + } +} + +static void scalarbase(gf p[4],const byte *s) +{ + gf q[4]; + set25519(q[0],X); + set25519(q[1],Y); + set25519(q[2],gf1); + M(q[3],X,Y); + scalarmult(p,q,s); +} + +int crypto_sign_keypair(byte *pk, byte *sk) +{ + byte d[64]; + gf p[4]; + int i; + + randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p,d); + pack(pk,p); + + for(i=0; i<32; ++i) sk[32 + i] = pk[i]; + return 0; +} + +int crypto_sign_sk2pk(byte *pk, const byte *sk) +{ + byte d[64]; + gf p[4]; + // int i; + + // randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p,d); + pack(pk,p); + + // for(i=0; i<32; ++i) sk[32 + i] = pk[i]; + return 0; +} + +static const word64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; + +static void modL(byte *r,sword64 x[64]) +{ + sword64 carry,i,j; + for (i = 63;i >= 32;--i) { + carry = 0; + for (j = i - 32;j < i - 12;++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= ((word64)carry) << 8; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for(j=0; j<32; ++j) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for(j=0; j<32; ++j) x[j] -= carry * L[j]; + for(i=0; i<32; ++i) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +static void reduce(byte *r) +{ + sword64 x[64],i; + for(i=0; i<64; ++i) x[i] = (word64) r[i]; + for(i=0; i<64; ++i) r[i] = 0; + modL(r,x); +} + +int crypto_sign(byte *sm,word64 *smlen,const byte *m,word64 n,const byte *sk) +{ + byte d[64],h[64],r[64]; + word64 i; sword64 j,x[64]; + gf p[4]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + *smlen = n+64; + for(i=0; i>7)) Z(r[0],gf0,r[0]); + + M(r[3],r[0],r[1]); + return 0; +} + +int crypto_sign_open(byte *m,word64 *mlen,const byte *sm,word64 n,const byte *pk) +{ + word32 i; + byte t[32],h[64]; + gf p[4],q[4]; + + *mlen = ~W64LIT(0); + if (n < 64) return -1; + + if (unpackneg(q,pk)) return -1; + + for(i=0; i>1) ^ ((c & 1) ? (modulus>>1) : 0); + return c | (c1 << 8) | (c2 << 16) | (c1 << 24); +} + +// compute RS(12,8) code with the above polynomial as generator +// this is equivalent to multiplying by the RS matrix +static word32 ReedSolomon(word32 high, word32 low) +{ + for (unsigned int i=0; i<8; i++) + { + high = Mod(high>>24) ^ (high<<8) ^ (low>>24); + low <<= 8; + } + return high; +} + +inline word32 Twofish::Base::h0(word32 x, const word32 *key, unsigned int kLen) +{ + x = x | (x<<8) | (x<<16) | (x<<24); + switch(kLen) + { +#define Q(a, b, c, d, t) q[a][GETBYTE(t,0)] ^ (q[b][GETBYTE(t,1)] << 8) ^ (q[c][GETBYTE(t,2)] << 16) ^ (q[d][GETBYTE(t,3)] << 24) + case 4: x = Q(1, 0, 0, 1, x) ^ key[6]; + // fall through + case 3: x = Q(1, 1, 0, 0, x) ^ key[4]; + // fall through + case 2: x = Q(0, 1, 0, 1, x) ^ key[2]; + x = Q(0, 0, 1, 1, x) ^ key[0]; + } + return x; +} + +inline word32 Twofish::Base::h(word32 x, const word32 *key, unsigned int kLen) +{ + x = h0(x, key, kLen); + return mds[0][GETBYTE(x,0)] ^ mds[1][GETBYTE(x,1)] ^ mds[2][GETBYTE(x,2)] ^ mds[3][GETBYTE(x,3)]; +} + +void Twofish::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &) +{ + AssertValidKeyLength(keylength); + + unsigned int len = (keylength <= 16 ? 2 : (keylength <= 24 ? 3 : 4)); + SecBlock key(len*2); + GetUserKey(LITTLE_ENDIAN_ORDER, key.begin(), len*2, userKey, keylength); + + unsigned int i; + for (i=0; i<40; i+=2) + { + word32 a = h(i, key, len); + word32 b = rotlConstant<8>(h(i + 1, key + 1, len)); + m_k[i] = a+b; + m_k[i + 1] = rotlConstant<9>(a + 2 * b); + } + + SecBlock svec(2*len); + for (i=0; i(c); \ + (d) = rotlConstant<1>(d) ^ y + +#define ENCCYCLE(n) \ + ENCROUND (2 * (n), a, b, c, d); \ + ENCROUND (2 * (n) + 1, c, d, a, b) + +#define DECROUND(n, a, b, c, d) \ + x = G1 (a); y = G2 (b); \ + x += y; y += x; \ + (d) ^= y + k[2 * (n) + 1]; \ + (d) = rotrConstant<1>(d); \ + (c) = rotlConstant<1>(c); \ + (c) ^= (x + k[2 * (n)]) + +#define DECCYCLE(n) \ + DECROUND (2 * (n) + 1, c, d, a, b); \ + DECROUND (2 * (n), a, b, c, d) + +typedef BlockGetAndPut Block; + +void Twofish::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 x, y, a, b, c, d; + + Block::Get(inBlock)(a)(b)(c)(d); + + a ^= m_k[0]; + b ^= m_k[1]; + c ^= m_k[2]; + d ^= m_k[3]; + + const word32 *k = m_k+8; + ENCCYCLE (0); + ENCCYCLE (1); + ENCCYCLE (2); + ENCCYCLE (3); + ENCCYCLE (4); + ENCCYCLE (5); + ENCCYCLE (6); + ENCCYCLE (7); + + c ^= m_k[4]; + d ^= m_k[5]; + a ^= m_k[6]; + b ^= m_k[7]; + + Block::Put(xorBlock, outBlock)(c)(d)(a)(b); +} + +void Twofish::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const +{ + word32 x, y, a, b, c, d; + + Block::Get(inBlock)(c)(d)(a)(b); + + c ^= m_k[4]; + d ^= m_k[5]; + a ^= m_k[6]; + b ^= m_k[7]; + + const word32 *k = m_k+8; + DECCYCLE (7); + DECCYCLE (6); + DECCYCLE (5); + DECCYCLE (4); + DECCYCLE (3); + DECCYCLE (2); + DECCYCLE (1); + DECCYCLE (0); + + a ^= m_k[0]; + b ^= m_k[1]; + c ^= m_k[2]; + d ^= m_k[3]; + + Block::Put(xorBlock, outBlock)(a)(b)(c)(d); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/twofish.h b/extension/third_party/cryptopp/twofish.h new file mode 100644 index 00000000..16284b48 --- /dev/null +++ b/extension/third_party/cryptopp/twofish.h @@ -0,0 +1,64 @@ +// twofish.h - originally written and placed in the public domain by Wei Dai + +/// \file twofish.h +/// \brief Classes for the Twofish block cipher + +#ifndef CRYPTOPP_TWOFISH_H +#define CRYPTOPP_TWOFISH_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Twofish block cipher information +/// \since Crypto++ 3.1 +struct Twofish_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Twofish";} +}; + +/// \brief Twofish block cipher +/// \sa Twofish +/// \since Crypto++ 3.1 +class Twofish : public Twofish_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static word32 h0(word32 x, const word32 *key, unsigned int kLen); + static word32 h(word32 x, const word32 *key, unsigned int kLen); + + static const byte q[2][256]; + static const word32 mds[4][256]; + + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_s; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Twofish::Encryption TwofishEncryption; +typedef Twofish::Decryption TwofishDecryption; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/validat0.cpp b/extension/third_party/cryptopp/validat0.cpp new file mode 100644 index 00000000..54dac5f9 --- /dev/null +++ b/extension/third_party/cryptopp/validat0.cpp @@ -0,0 +1,1576 @@ +// validat0.cpp - originally written and placed in the public domain by Wei Dai and Jeffrey Walton +// Routines in this source file are only tested in Debug builds. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "asn.h" +#include "gf2n.h" +#include "default.h" +#include "integer.h" +#include "polynomi.h" +#include "channels.h" + +#include "ida.h" +#include "gzip.h" +#include "zlib.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +// Issue 64: "PolynomialMod2::operator<<=", http://github.com/weidai11/cryptopp/issues/64 +bool TestPolynomialMod2() +{ + std::cout << "\nTesting PolynomialMod2 bit operations...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + const unsigned int start = 0; + const unsigned int stop = 4 * WORD_BITS + 1; + + for (unsigned int i = start; i < stop; i++) + { + PolynomialMod2 p(1); + p <<= i; + + Integer n(Integer::One()); + n <<= i; + + std::ostringstream oss1; + oss1 << p; + + std::string str1, str2; + + // str1 needs the commas removed used for grouping + str1 = oss1.str(); + str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end()); + + // str1 needs the trailing 'b' removed + str1.erase(str1.end() - 1); + + // str2 is fine as-is + str2 = IntToString(n, 2); + + pass1 &= (str1 == str2); + } + + for (unsigned int i = start; i < stop; i++) + { + const word w((word)SIZE_MAX); + + PolynomialMod2 p(w); + p <<= i; + + Integer n(Integer::POSITIVE, static_cast(w)); + n <<= i; + + std::ostringstream oss1; + oss1 << p; + + std::string str1, str2; + + // str1 needs the commas removed used for grouping + str1 = oss1.str(); + str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end()); + + // str1 needs the trailing 'b' removed + str1.erase(str1.end() - 1); + + // str2 is fine as-is + str2 = IntToString(n, 2); + + pass2 &= (str1 == str2); + } + + RandomNumberGenerator& prng = GlobalRNG(); + for (unsigned int i = start; i < stop; i++) + { + word w; // Cast to lword due to Visual Studio + prng.GenerateBlock((byte*)&w, sizeof(w)); + + PolynomialMod2 p(w); + p <<= i; + + Integer n(Integer::POSITIVE, static_cast(w)); + n <<= i; + + std::ostringstream oss1; + oss1 << p; + + std::string str1, str2; + + // str1 needs the commas removed used for grouping + str1 = oss1.str(); + str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end()); + + // str1 needs the trailing 'b' removed + str1.erase(str1.end() - 1); + + // str2 is fine as-is + str2 = IntToString(n, 2); + + if (str1 != str2) + { + std::cout << " Oops..." << "\n"; + std::cout << " random: " << std::hex << n << std::dec << "\n"; + std::cout << " str1: " << str1 << "\n"; + std::cout << " str2: " << str2 << "\n"; + } + + pass3 &= (str1 == str2); + } + + std::cout << (!pass1 ? "FAILED" : "passed") << ": " << "1 shifted over range [" << std::dec << start << "," << stop << "]" << "\n"; + std::cout << (!pass2 ? "FAILED" : "passed") << ": " << "0x" << std::hex << word(SIZE_MAX) << std::dec << " shifted over range [" << start << "," << stop << "]" << "\n"; + std::cout << (!pass3 ? "FAILED" : "passed") << ": " << "random values shifted over range [" << std::dec << start << "," << stop << "]" << "\n"; + + return pass1 && pass2 && pass3; +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestCompressors() +{ + std::cout << "\nTesting Compressors and Decompressors...\n\n"; + bool fail1 = false, fail2 = false, fail3 = false; + const unsigned int COMP_COUNT = 64; + + try + { + // Gzip uses Adler32 checksums. We expect a failure to happen on occasion. + // If we see more than 2 failures in a run of 128, then we need to investigate. + unsigned int truncatedCount=0; + for (unsigned int i = 0; i= 2) + { + std::cout << "FAILED: Gzip failed to detect a truncated stream\n"; + fail1 = true; + } + } + catch (const Exception&) {} + } + } + catch (const Exception& ex) + { + std::cout << "FAILED: " << ex.what() << "\n"; + fail1 = true; + } + + // ************************************************************** + + // Gzip Filename, Filetime and Comment + try + { + std::string filename = "test.txt"; + std::string comment = "This is a test"; + word32 filetime = GlobalRNG().GenerateWord32(4, 0xffffff); + + AlgorithmParameters params = MakeParameters(Name::FileTime(), (int)filetime) + (Name::FileName(), ConstByteArrayParameter(filename.c_str(), false)) + (Name::Comment(), ConstByteArrayParameter(comment.c_str(), false)); + + std::string src, dest; + unsigned int len = GlobalRNG().GenerateWord32(4, 0xfff); + + RandomNumberSource(GlobalRNG(), len, true, new StringSink(src)); + Gunzip unzip(new StringSink(dest)); + StringSource(src, true, new Gzip(params, new Redirector(unzip))); + + if (filename != unzip.GetFilename()) + throw Exception(Exception::OTHER_ERROR, "Failed to retrieve filename"); + + if (filetime != unzip.GetFiletime()) + throw Exception(Exception::OTHER_ERROR, "Failed to retrieve filetime"); + + if (comment != unzip.GetComment()) + throw Exception(Exception::OTHER_ERROR, "Failed to retrieve comment"); + + std::cout << "passed: filenames, filetimes and comments\n"; + } + catch (const Exception& ex) + { + std::cout << "FAILED: " << ex.what() << "\n"; + } + + // Unzip random data. See if we can induce a crash + for (unsigned int i = 0; i strShares(shares); + vector_member_ptrs strSinks(shares); + std::string channel; + + // ********** Create Shares + for (unsigned int i=0; i(i); + strSinks[i]->Put((const byte *)channel.data(), CHID_LENGTH); + channelSwitch->AddRoute(channel, *strSinks[i], DEFAULT_CHANNEL); + } + source.PumpAll(); + + // ********** Randomize shares + + GlobalRNG().Shuffle(strShares.begin(), strShares.end()); + + // ********** Recover secret + try + { + std::string recovered; + InformationRecovery recovery(threshold, new StringSink(recovered)); + + vector_member_ptrs strSources(threshold); + channel.resize(CHID_LENGTH); + + for (unsigned int i=0; iPump(CHID_LENGTH); + strSources[i]->Get((byte*)&channel[0], CHID_LENGTH); + strSources[i]->Attach(new ChannelSwitch(recovery, channel)); + } + + while (strSources[0]->Pump(256)) + { + for (unsigned int i=1; iPump(256); + } + + for (unsigned int i=0; iPumpAll(); + + fail = (message != recovered); + } + catch (const Exception&) + { + fail = true; + } + + pass &= !fail; + } + + std::cout << (fail ? "FAILED:" : "passed:") << " " << INFORMATION_SHARES << " information dispersals\n"; + + // ********** Secret Sharing **********// + + for (unsigned int shares=3; shares strShares(shares); + vector_member_ptrs strSinks(shares); + std::string channel; + + // ********** Create Shares + for (unsigned int i=0; i(i); + strSinks[i]->Put((const byte *)channel.data(), CHID_LENGTH); + channelSwitch->AddRoute(channel, *strSinks[i], DEFAULT_CHANNEL); + } + source.PumpAll(); + + // ********** Randomize shares + + GlobalRNG().Shuffle(strShares.begin(), strShares.end()); + + // ********** Recover secret + try + { + std::string recovered; + SecretRecovery recovery(threshold, new StringSink(recovered)); + + vector_member_ptrs strSources(threshold); + channel.resize(CHID_LENGTH); + for (unsigned int i=0; iPump(CHID_LENGTH); + strSources[i]->Get((byte*)&channel[0], CHID_LENGTH); + strSources[i]->Attach(new ChannelSwitch(recovery, channel)); + } + + while (strSources[0]->Pump(256)) + { + for (unsigned int i=1; iPump(256); + } + + for (unsigned int i=0; iPumpAll(); + + fail = (message != recovered); + } + catch (const Exception&) + { + fail = true; + } + + pass &= !fail; + } + + std::cout << (fail ? "FAILED:" : "passed:") << " " << SECRET_SHARES << " secret sharings\n"; + + return pass; +} + +bool TestRounding() +{ + std::cout << "\nTesting RoundUpToMultipleOf/RoundDownToMultipleOf...\n\n"; + bool pass=true, fail; + + // ********** byte **********// + try + { + const byte v=0, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n"; + + try + { + const byte v=1, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + fail = (r != b); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n"; + + try + { + const byte v=0x08, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n"; + + try + { + const byte v=0xf7, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + fail = (r != 0xf8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n"; + + try + { + const byte v=0xf8, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + fail = (r != 0xf8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, no overflow\n"; + + try + { + const byte v=0xf9, b=0x08; + byte r=RoundUpToMultipleOf(v, b); + CRYPTOPP_UNUSED(r); + fail = true; + } + catch(const Exception&) + { + fail = false; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, byte, overflow\n"; + + // ********** word16 **********// + try + { + const word16 v=0, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n"; + + try + { + const word16 v=1, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + fail = (r != b); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n"; + + try + { + const word16 v=0x08, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n"; + + try + { + const word16 v=0xfff7, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + fail = (r != 0xfff8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n"; + + try + { + const word16 v=0xfff8, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + fail = (r != 0xfff8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, no overflow\n"; + + try + { + const word16 v=0xfff9, b=0x08; + word16 r=RoundUpToMultipleOf(v, b); + CRYPTOPP_UNUSED(r); + fail = true; + } + catch(const Exception&) + { + fail = false; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word16, overflow\n"; + + // ********** word32 **********// + try + { + const word32 v=0, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n"; + + try + { + const word32 v=1, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + fail = (r != b); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n"; + + try + { + const word32 v=0x08, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n"; + + try + { + const word32 v=0xfffffff7, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + fail = (r != 0xfffffff8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n"; + + try + { + const word32 v=0xfffffff8, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + fail = (r != 0xfffffff8); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, no overflow\n"; + + try + { + const word32 v=0xfffffff9, b=0x08; + word32 r=RoundUpToMultipleOf(v, b); + CRYPTOPP_UNUSED(r); + fail = true; + } + catch(const Exception&) + { + fail = false; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word32, overflow\n"; + + // ********** word64 **********// + try + { + const word64 v=0, b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n"; + + try + { + const word64 v=1, b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + fail = (r != b); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n"; + + try + { + const word64 v=0x08, b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n"; + + try + { + const word64 v=W64LIT(0xffffffffffffff7), b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + fail = (r != W64LIT(0xffffffffffffff8)); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n"; + + try + { + const word64 v=W64LIT(0xffffffffffffff8), b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + fail = (r != W64LIT(0xffffffffffffff8)); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, no overflow\n"; + + try + { + const word64 v=W64LIT(0xfffffffffffffff9), b=0x08; + word64 r=RoundUpToMultipleOf(v, b); + CRYPTOPP_UNUSED(r); + fail = true; + } + catch(const Exception&) + { + fail = false; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word64, overflow\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + // ********** word128 **********// + try + { + const word128 v=0, b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n"; + + try + { + const word128 v=1, b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + fail = (r != b); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n"; + + try + { + const word128 v=0x08, b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + fail = (r != v); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n"; + + try + { + // http://stackoverflow.com/q/31461318/608639 + const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U; + const word128 v = h | (word128)W64LIT(0xfffffffffffffff7), b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + fail = (r != (h | (word128)W64LIT(0xfffffffffffffff8))); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n"; + + try + { + const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U; + const word128 v = h | (word128)W64LIT(0xfffffffffffffff8), b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + fail = (r != (h | (word128)W64LIT(0xfffffffffffffff8))); + } + catch(const Exception&) + { + fail = true; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, no overflow\n"; + + try + { + const word128 h = ((word128)W64LIT(0xffffffffffffffff)) << 64U; + const word128 v = h | (word128)W64LIT(0xfffffffffffffff9), b=0x08; + word128 r=RoundUpToMultipleOf(v, b); + CRYPTOPP_UNUSED(r); + fail = true; + } + catch(const Exception&) + { + fail = false; + } + + pass = !fail && pass; + std::cout << (fail ? "FAILED:" : "passed:") << " RoundUpToMultipleOf, word128, overflow\n"; +#endif + + return pass; +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +struct ASN1_TestTuple +{ + ASN1_TestTuple(int tag, int result, const char* data, size_t len) { + m_result = result; + m_tag = tag; + m_data = std::string(data, len); + } + + std::string Name() const { + return Id2String(); + } + + const byte* Data() const { + return ConstBytePtr(m_data); + } + + size_t Size() const { + return BytePtrSize(m_data); + } + + int Tag() const { + return m_tag; + } + + int Result() const { + return m_result; + } + + std::string Id2String() const + { + switch(m_tag) + { + case BIT_STRING: + return "BIT_STRING"; + case OCTET_STRING: + return "OCTET_STRING"; + case INTEGER: + return "INTEGER"; + case UTF8_STRING: + return "UTF8_STRING"; + case PRINTABLE_STRING: + return "PRINTABLE_STRING"; + case IA5_STRING: + return "IA5_STRING"; + default: + return "Unknown"; + } + } + +protected: + std::string m_data; + int m_tag, m_result; +}; + +bool RunASN1TestSet(const ASN1_TestTuple asnTuples[], size_t count) +{ + bool pass=true, fail; + + // Disposition + enum {REJECT=3, ACCEPT=4}; + + for(size_t i=0; i(as2, unused5, byte(INTEGER), 0, W64LIT(0xffffffffffffffff)); + break; + + case UTF8_STRING: case PRINTABLE_STRING: case IA5_STRING: + BERDecodeTextString(as1, unused2, tag); + break; + + default: + BERGeneralDecoder(as1, tag); + break; + } + + fail = thisTest.Result() != ACCEPT; + } + catch(const Exception&) + { + fail = thisTest.Result() != REJECT; + } + + std::cout << (fail ? "FAILED:" : "passed:") << (thisTest.Result() == ACCEPT ? " accept " : " reject "); + std::cout << asnTuples[i].Name() << " " << val << "\n"; + pass = !fail && pass; + } + + return pass; +} + +bool TestASN1Parse() +{ + std::cout << "\nTesting ASN.1 parser...\n\n"; + + bool pass = true; + + // Disposition + enum {REJECT=3, ACCEPT=4}; + + // All the types Crypto++ recognizes. + // "C" is one content octet with value 0x43. + const ASN1_TestTuple bitStrings[] = + { + // The first "\x00" content octet is the "initial octet" representing unused bits. In the + // primitive encoding form, there may be zero, one or more contents after the initial octet. + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x01" "\x00", 3), // definite length, short form, initial octet, zero subsequent octets + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x01" "\x08", 3), // definite length, short form, initial octet, zero subsequent octets + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x02" "\x00" "C", 4), // definite length, short form, expected subsequent octets + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x02" "\x08" "C", 4), // too many unused bits + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x7F" "\x00" "C", 4), // runt or underrun + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x81\x01" "\x00", 4), // definite length, long form, initial octet, zero subsequent octets + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\x01" "\x08", 4), // definite length, long form, initial octet, zero subsequent octets + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x81\x02" "\x00" "C", 5), // definite length, long form + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\x02" "\x08" "C", 5), // too many unused bits + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x81\xff" "\x00" "C", 5), // runt or underrun + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x82\x00\x02" "\x00" "C", 6), // definite length, long form + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x82\x00\x02" "\x08" "C", 6), // too many unused bits + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x82\xff\xff" "\x00" "C", 6), // runt or underrun + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x83\x00\x00\x02" "\x00" "C", 7), // definite length, long form + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x83\x00\x00\x02" "\x08" "C", 7), // too many unused bits + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x83\xff\xff\xff" "\x00" "C", 7), // runt or underrun + ASN1_TestTuple(BIT_STRING, ACCEPT, "\x03\x84\x00\x00\x00\x02" "\x00" "C", 8), // definite length, long form + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x84\x00\x00\x00\x02" "\x08" "C", 8), // too many unused bits + ASN1_TestTuple(BIT_STRING, REJECT, "\x03\x84\xff\xff\xff\xff" "\x00" "C", 8), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(bitStrings, COUNTOF(bitStrings)) && pass; + + const ASN1_TestTuple octetStrings[] = + { + // In the primitive encoding form, there may be zero, one or more contents. + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x00", 2), // definite length, short form, zero content octets + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x01" "C", 3), // definite length, short form, expected content octets + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x02" "C", 3), // runt or underrun + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x7F" "C", 3), // runt or underrun + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x81\x00", 3), // definite length, long form, zero content octets + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x81\x01" "C", 4), // definite length, long form, expected content octets + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x81\x02" "C", 4), // runt or underrun + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x81\xff" "C", 4), // runt or underrun + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x82\x00\x00", 4), // definite length, long form, zero content octets + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x82\x00\x01" "C", 5), // definite length, long form, expected content octets + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x82\x00\x02" "C", 5), // runt or underrun + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x82\xff\xff" "C", 5), // runt or underrun + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x83\x00\x00\x00", 5), // definite length, long form, zero content octets + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x83\x00\x00\x02" "C", 6), // runt or underrun + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x83\xff\xff\xff" "C", 6), // runt or underrun + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets + ASN1_TestTuple(OCTET_STRING, ACCEPT, "\x04\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x84\x00\x00\x00\x02" "C", 7), // runt or underrun + ASN1_TestTuple(OCTET_STRING, REJECT, "\x04\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(octetStrings, COUNTOF(octetStrings)) && pass; + + const ASN1_TestTuple utf8Strings[] = + { + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x00", 2), // definite length, short form, zero content octets + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x01" "C", 3), // definite length, short form, expected content octets + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x02" "C", 3), // runt or underrun + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x7F" "C", 3), // runt or underrun + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x81\x00", 3), // definite length, long form, zero content octets + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x81\x01" "C", 4), // definite length, long form, expected content octets + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x81\x02" "C", 4), // runt or underrun + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x81\xff" "C", 4), // runt or underrun + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x82\x00\x00", 4), // definite length, long form, zero content octets + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x82\x00\x01" "C", 5), // definite length, long form, expected content octets + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x82\x00\x02" "C", 5), // runt or underrun + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x82\xff\xff" "C", 5), // runt or underrun + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x83\x00\x00\x00", 5), // definite length, long form, zero content octets + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x83\x00\x00\x02" "C", 6), // runt or underrun + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x83\xff\xff\xff" "C", 6), // runt or underrun + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets + ASN1_TestTuple(UTF8_STRING, ACCEPT, "\x0c\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x84\x00\x00\x00\x02" "C", 7), // runt or underrun + ASN1_TestTuple(UTF8_STRING, REJECT, "\x0c\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(utf8Strings, COUNTOF(utf8Strings)) && pass; + + const ASN1_TestTuple printableStrings[] = + { + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x00", 2), // definite length, short form, zero content octets + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x01" "C", 3), // definite length, short form, expected content octets + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x02" "C", 3), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x7F" "C", 3), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x81\x00", 3), // definite length, long form, zero content octets + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x81\x01" "C", 4), // definite length, long form, expected content octets + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x81\x02" "C", 4), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x81\xff" "C", 4), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x82\x00\x00", 4), // definite length, long form, zero content octets + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x82\x00\x01" "C", 5), // definite length, long form, expected content octets + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x82\x00\x02" "C", 5), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x82\xff\xff" "C", 5), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x83\x00\x00\x00", 5), // definite length, long form, zero content octets + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x83\x00\x00\x02" "C", 6), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x83\xff\xff\xff" "C", 6), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets + ASN1_TestTuple(PRINTABLE_STRING, ACCEPT, "\x13\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x84\x00\x00\x00\x02" "C", 7), // runt or underrun + ASN1_TestTuple(PRINTABLE_STRING, REJECT, "\x13\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(printableStrings, COUNTOF(printableStrings)) && pass; + + const ASN1_TestTuple ia5Strings[] = + { + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x00", 2), // definite length, short form, zero content octets + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x01" "C", 3), // definite length, short form, expected content octets + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x02" "C", 3), // runt or underrun + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x7F" "C", 3), // runt or underrun + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x81\x00", 3), // definite length, long form, zero content octets + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x81\x01" "C", 4), // definite length, long form, expected content octets + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x81\x02" "C", 4), // runt or underrun + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x81\xff" "C", 4), // runt or underrun + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x82\x00\x00", 4), // definite length, long form, zero content octets + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x82\x00\x01" "C", 5), // definite length, long form, expected content octets + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x82\x00\x02" "C", 5), // runt or underrun + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x82\xff\xff" "C", 5), // runt or underrun + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x83\x00\x00\x00", 5), // definite length, long form, zero content octets + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x83\x00\x00\x02" "C", 6), // runt or underrun + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x83\xff\xff\xff" "C", 6), // runt or underrun + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets + ASN1_TestTuple(IA5_STRING, ACCEPT, "\x16\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x84\x00\x00\x00\x02" "C", 7), // runt or underrun + ASN1_TestTuple(IA5_STRING, REJECT, "\x16\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(ia5Strings, COUNTOF(ia5Strings)) && pass; + + const ASN1_TestTuple integerValues[] = + { + // 8.3.1 The encoding of an integer value shall be primitive. The contents octets shall consist of one or more octets. + ASN1_TestTuple(INTEGER, REJECT, "\x02\x00", 2), // definite length, short form, zero content octets + ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x01" "C", 3), // definite length, short form, expected content octets + ASN1_TestTuple(INTEGER, REJECT, "\x02\x02" "C", 3), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x7F" "C", 3), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\x00", 3), // definite length, long form, zero content octets + ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x81\x01" "C", 4), // definite length, long form, expected content octets + ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\x02" "C", 4), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x81\xff" "C", 4), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\x00\x00", 4), // definite length, long form, zero content octets + ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x82\x00\x01" "C", 5), // definite length, long form, expected content octets + ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\x00\x02" "C", 5), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x82\xff\xff" "C", 5), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\x00\x00\x00", 5), // definite length, long form, zero content octets + ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x83\x00\x00\x01" "C", 6), // definite length, long form, expected content octets + ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\x00\x00\x02" "C", 6), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x83\xff\xff\xff" "C", 6), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\x00\x00\x00\x00", 6), // definite length, long form, zero content octets + ASN1_TestTuple(INTEGER, ACCEPT, "\x02\x84\x00\x00\x00\x01" "C", 7), // definite length, long form, expected content octets + ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\x00\x00\x00\x02" "C", 7), // runt or underrun + ASN1_TestTuple(INTEGER, REJECT, "\x02\x84\xff\xff\xff\xff" "C", 7), // <== Issue 346; requires large allocation + }; + + pass = RunASN1TestSet(integerValues, COUNTOF(integerValues)) && pass; + + return pass; +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestStringSink() +{ + try + { + std::string in = "The quick brown fox jumps over the lazy dog"; + + std::string str; + StringSource s1(in, true, new StringSink(str)); + + std::vector vec; + StringSource s2(in, true, new VectorSink(vec)); + + std::vector vec2; + VectorSource s3(vec, true, new VectorSink(vec2)); + + return str.size() == vec.size() && + std::equal(str.begin(), str.end(), vec.begin()) && + vec.size() == vec2.size() && + std::equal(vec.begin(), vec.end(), vec2.begin()); + } + catch(const std::exception&) + { + } + return false; +} +#endif + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat1.cpp b/extension/third_party/cryptopp/validat1.cpp new file mode 100644 index 00000000..db523880 --- /dev/null +++ b/extension/third_party/cryptopp/validat1.cpp @@ -0,0 +1,1225 @@ +// validat1.cpp - originally written and placed in the public domain by Wei Dai and Jeffrey Walton +// Routines in this source file are only tested in Debug builds. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "secblock.h" +#include "gzip.h" +#include "zlib.h" + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# include "ppc_simd.h" +#endif + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestSecBlock() +{ + std::cout << "\nTesting SecBlock...\n\n"; + + bool pass1=true, pass2=true, pass3=true, pass4=true, pass5=true, pass6=true, pass7=true, temp=false; + + //************ Allocators ************// + + { + std::basic_string, AllocatorWithCleanup > s1; + std::basic_string, AllocatorWithCleanup > s2; + s1.resize(1024); s2.resize(1024); + + std::vector > v1; + std::vector > v2; + v1.resize(1024); v2.resize(1024); + } + + //********** Zeroized block **********// + + { + // NULL ptr with a size means to create a new SecBlock with all elements zero'd + SecByteBlock z1(NULLPTR, 256); + temp = true; + + for (size_t i = 0; i < z1.size(); i++) + temp &= (z1[i] == 0); + + pass1 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Zeroized byte array\n"; + + SecBlock z2(NULLPTR, 256); + temp = true; + + for (size_t i = 0; i < z2.size(); i++) + temp &= (z2[i] == 0); + + pass1 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Zeroized word32 array\n"; + + SecBlock z3(NULLPTR, 256); + temp = true; + + for (size_t i = 0; i < z3.size(); i++) + temp &= (z3[i] == 0); + + pass1 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Zeroized word64 array\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + SecBlock z4(NULLPTR, 256); + temp = true; + + for (size_t i = 0; i < z4.size(); i++) + temp &= (z4[i] == 0); + + pass1 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Zeroized word128 array\n"; +#endif + } + + //********** Non-zero'd block **********// + + { + SecByteBlock z1(NULLPTR, 256); + z1.SetMark(0); + + SecBlock z2(NULLPTR, 256); + z2.SetMark(0); + + SecBlock z3(NULLPTR, 256); + z3.SetMark(0); + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + SecBlock z4(NULLPTR, 256); + z4.SetMark(0); +#endif + } + + //********** Assign **********// + + try + { + SecByteBlock a, b; + temp = true; + + a.Assign((const byte*)"a", 1); + b.Assign((const byte*)"b", 1); + + temp &= (a.SizeInBytes() == 1); + temp &= (b.SizeInBytes() == 1); + temp &= (a[0] == 'a'); + temp &= (b[0] == 'b'); + + a.Assign((const byte*)"ab", 2); + b.Assign((const byte*)"cd", 2); + + temp &= (a.SizeInBytes() == 2); + temp &= (b.SizeInBytes() == 2); + temp &= (a[0] == 'a' && a[1] == 'b'); + temp &= (b[0] == 'c' && b[1] == 'd'); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass2 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Assign byte\n"; + + try + { + SecBlock a, b; + temp = true; + + word32 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + temp &= (a.SizeInBytes() == 4); + temp &= (b.SizeInBytes() == 4); + temp &= (a[0] == 1); + temp &= (b[0] == 2); + + word32 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + temp &= (a.SizeInBytes() == 8); + temp &= (b.SizeInBytes() == 8); + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass2 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Assign word32\n"; + + try + { + SecBlock a, b; + temp = true; + + word64 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + temp &= (a.SizeInBytes() == 8); + temp &= (b.SizeInBytes() == 8); + temp &= (a[0] == 1); + temp &= (b[0] == 2); + + word64 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + temp &= (a.SizeInBytes() == 16); + temp &= (b.SizeInBytes() == 16); + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass2 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Assign word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + try + { + SecBlock a, b; + temp = true; + + word128 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + temp &= (a.SizeInBytes() == 16); + temp &= (b.SizeInBytes() == 16); + temp &= (a[0] == 1); + temp &= (b[0] == 2); + + word128 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + temp &= (a.SizeInBytes() == 32); + temp &= (b.SizeInBytes() == 32); + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass2 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Assign word128\n"; +#endif + + //********** Append **********// + + try + { + SecByteBlock a, b; + temp = true; + + a.Assign((const byte*)"a", 1); + b.Assign((const byte*)"b", 1); + + a += b; + temp &= (a.SizeInBytes() == 2); + temp &= (a[0] == 'a' && a[1] == 'b'); + + a.Assign((const byte*)"ab", 2); + b.Assign((const byte*)"cd", 2); + + a += b; + temp &= (a.SizeInBytes() == 4); + temp &= (a[0] == 'a' && a[1] == 'b' && a[2] == 'c' && a[3] == 'd'); + + a.Assign((const byte*)"a", 1); + + a += a; + temp &= (a.SizeInBytes() == 2); + temp &= (a[0] == 'a' && a[1] == 'a'); + + a.Assign((const byte*)"ab", 2); + + a += a; + temp &= (a.SizeInBytes() == 4); + temp &= (a[0] == 'a' && a[1] == 'b' && a[2] == 'a' && a[3] == 'b'); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass3 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Append byte\n"; + + try + { + SecBlock a, b; + temp = true; + + const word32 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + a += b; + temp &= (a.SizeInBytes() == 8); + temp &= (a[0] == 1 && a[1] == 2); + + const word32 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + a += b; + temp &= (a.SizeInBytes() == 16); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 3 && a[3] == 4); + + a.Assign(one, 1); + + a += a; + temp &= (a.SizeInBytes() == 8); + temp &= (a[0] == 1 && a[1] == 1); + + a.Assign(three, 2); + + a += a; + temp &= (a.SizeInBytes() == 16); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 1 && a[3] == 2); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass3 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Append word32\n"; + + try + { + SecBlock a, b; + temp = true; + + const word64 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + a += b; + temp &= (a.SizeInBytes() == 16); + temp &= (a[0] == 1 && a[1] == 2); + + const word64 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + a += b; + temp &= (a.SizeInBytes() == 32); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 3 && a[3] == 4); + + a.Assign(one, 1); + + a += a; + temp &= (a.SizeInBytes() == 16); + temp &= (a[0] == 1 && a[1] == 1); + + a.Assign(three, 2); + + a += a; + temp &= (a.SizeInBytes() == 32); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 1 && a[3] == 2); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass3 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Append word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + try + { + SecBlock a, b; + temp = true; + + const word128 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + a += b; + temp &= (a.SizeInBytes() == 32); + temp &= (a[0] == 1 && a[1] == 2); + + const word128 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + a += b; + temp &= (a.SizeInBytes() == 64); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 3 && a[3] == 4); + + a.Assign(one, 1); + + a += a; + temp &= (a.SizeInBytes() == 32); + temp &= (a[0] == 1 && a[1] == 1); + + a.Assign(three, 2); + + a += a; + temp &= (a.SizeInBytes() == 64); + temp &= (a[0] == 1 && a[1] == 2 && a[2] == 1 && a[3] == 2); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass3 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Append word128\n"; +#endif + + //********** Concatenate **********// + + // byte + try + { + SecByteBlock a, b, c; + temp = true; + + a.Assign((const byte*)"a", 1); + b.Assign((const byte*)"b", 1); + + c = a + b; + temp &= (a[0] == 'a'); + temp &= (b[0] == 'b'); + temp &= (c.SizeInBytes() == 2); + temp &= (c[0] == 'a' && c[1] == 'b'); + + a.Assign((const byte*)"ab", 2); + b.Assign((const byte*)"cd", 2); + + c = a + b; + temp &= (a[0] == 'a' && a[1] == 'b'); + temp &= (b[0] == 'c' && b[1] == 'd'); + temp &= (c.SizeInBytes() == 4); + temp &= (c[0] == 'a' && c[1] == 'b' && c[2] == 'c' && c[3] == 'd'); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass4 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Concatenate byte\n"; + + // word32 + try + { + SecBlock a, b, c; + temp = true; + + const word32 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + c = a + b; + temp &= (a[0] == 1); + temp &= (b[0] == 2); + temp &= (c.SizeInBytes() == 8); + temp &= (c[0] == 1 && c[1] == 2); + + const word32 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + c = a + b; + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + temp &= (c.SizeInBytes() == 16); + temp &= (c[0] == 1 && c[1] == 2 && c[2] == 3 && c[3] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass4 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Concatenate word32\n"; + + // word64 + try + { + SecBlock a, b, c; + temp = true; + + const word64 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + c = a + b; + temp &= (a[0] == 1); + temp &= (b[0] == 2); + temp &= (c.SizeInBytes() == 16); + temp &= (c[0] == 1 && c[1] == 2); + + const word64 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + c = a + b; + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + temp &= (c.SizeInBytes() == 32); + temp &= (c[0] == 1 && c[1] == 2 && c[2] == 3 && c[3] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass4 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Concatenate word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + try + { + SecBlock a, b, c; + temp = true; + + const word128 one[1] = {1}, two[1] = {2}; + a.Assign(one, 1); + b.Assign(two, 1); + + c = a + b; + temp &= (a[0] == 1); + temp &= (b[0] == 2); + temp &= (c.SizeInBytes() == 32); + temp &= (c[0] == 1 && c[1] == 2); + + const word128 three[2] = {1,2}, four[2] = {3,4}; + a.Assign(three, 2); + b.Assign(four, 2); + + c = a + b; + temp &= (a[0] == 1 && a[1] == 2); + temp &= (b[0] == 3 && b[1] == 4); + temp &= (c.SizeInBytes() == 64); + temp &= (c[0] == 1 && c[1] == 2 && c[2] == 3 && c[3] == 4); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass4 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Concatenate word128\n"; +#endif + + //********** Equality **********// + + // byte + try + { + static const byte str1[] = "abcdefghijklmnopqrstuvwxyz"; + static const byte str2[] = "zyxwvutsrqponmlkjihgfedcba"; + static const byte str3[] = "0123456789"; + + temp = true; + SecByteBlock a,b; + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str1, COUNTOF(str1)); + temp &= (a.operator==(b)); + + a.Assign(str3, COUNTOF(str3)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a == b); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str2, COUNTOF(str2)); + temp &= (a.operator!=(b)); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a != b); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass5 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Equality byte\n"; + + // word32 + try + { + static const word32 str1[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97}; + static const word32 str2[] = {97,89,83,79,73,71,67,61,59,53,47,43,41,37,31,29,23,19,17,13,11,7,5,3,2}; + static const word32 str3[] = {0,1,2,3,4,5,6,7,8,9}; + + temp = true; + SecBlock a,b; + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str1, COUNTOF(str1)); + temp &= (a.operator==(b)); + + a.Assign(str3, COUNTOF(str3)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a == b); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str2, COUNTOF(str2)); + temp &= (a.operator!=(b)); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a != b); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass5 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Equality word32\n"; + + // word64 + try + { + static const word64 str1[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97}; + static const word64 str2[] = {97,89,83,79,73,71,67,61,59,53,47,43,41,37,31,29,23,19,17,13,11,7,5,3,2}; + static const word64 str3[] = {0,1,2,3,4,5,6,7,8,9}; + + temp = true; + SecBlock a,b; + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str1, COUNTOF(str1)); + temp &= (a.operator==(b)); + + a.Assign(str3, COUNTOF(str3)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a == b); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str2, COUNTOF(str2)); + temp &= (a.operator!=(b)); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a != b); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass5 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Equality word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + // word128 + try + { + static const word128 str1[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97}; + static const word128 str2[] = {97,89,83,79,73,71,67,61,59,53,47,43,41,37,31,29,23,19,17,13,11,7,5,3,2}; + static const word128 str3[] = {0,1,2,3,4,5,6,7,8,9}; + + temp = true; + SecBlock a,b; + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str1, COUNTOF(str1)); + temp &= (a.operator==(b)); + + a.Assign(str3, COUNTOF(str3)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a == b); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str2, COUNTOF(str2)); + temp &= (a.operator!=(b)); + + a.Assign(str1, COUNTOF(str1)); + b.Assign(str3, COUNTOF(str3)); + temp &= (a != b); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + + pass5 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Equality word128\n"; +#endif + + //********** Allocator Size/Overflow **********// + + try + { + temp = false; + + AllocatorBase A; + const size_t max = A.max_size(); + SecBlock t(max+1); + } + catch(const Exception& /*ex*/) + { + temp = true; + } + catch(const std::exception& /*ex*/) + { + temp = true; + } + + pass6 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Overflow word32\n"; + + try + { + temp = false; + + AllocatorBase A; + const size_t max = A.max_size(); + SecBlock t(max+1); + } + catch(const Exception& /*ex*/) + { + temp = true; + } + catch(const std::exception& /*ex*/) + { + temp = true; + } + + pass6 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Overflow word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + try + { + temp = false; + + AllocatorBase A; + const size_t max = A.max_size(); + SecBlock t(max+1); + } + catch(const Exception& /*ex*/) + { + temp = true; + } + catch(const std::exception& /*ex*/) + { + temp = true; + } + + pass6 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Overflow word128\n"; +#endif + + //********** FixedSizeAllocatorWithCleanup and Grow **********// + + // byte + try + { + static const unsigned int SIZE = 8; + SecBlockWithHint block(SIZE); + memset(block, 0xaa, block.SizeInBytes()); + + temp = true; + block.CleanGrow(SIZE*2); + temp &= (block.size() == SIZE*2); + + for (size_t i = 0; i < block.size()/2; i++) + temp &= (block[i] == 0xaa); + for (size_t i = block.size()/2; i < block.size(); i++) + temp &= (block[i] == 0); + + block.CleanNew(SIZE*4); + temp &= (block.size() == SIZE*4); + for (size_t i = 0; i < block.size(); i++) + temp &= (block[i] == 0); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + catch(const std::exception& /*ex*/) + { + temp = false; + } + + pass7 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " FixedSizeAllocator Grow with byte\n"; + + // word32 + try + { + static const unsigned int SIZE = 8; + SecBlockWithHint block(SIZE); + memset(block, 0xaa, block.SizeInBytes()); + + temp = true; + block.CleanGrow(SIZE*2); + temp &= (block.size() == SIZE*2); + + for (size_t i = 0; i < block.size()/2; i++) + temp &= (block[i] == 0xaaaaaaaa); + + for (size_t i = block.size()/2; i < block.size(); i++) + temp &= (block[i] == 0); + + block.CleanNew(SIZE*4); + temp &= (block.size() == SIZE*4); + for (size_t i = 0; i < block.size(); i++) + temp &= (block[i] == 0); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + catch(const std::exception& /*ex*/) + { + temp = false; + } + + pass7 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " FixedSizeAllocator Grow with word32\n"; + + // word64 + try + { + static const unsigned int SIZE = 8; + SecBlockWithHint block(SIZE); + memset(block, 0xaa, block.SizeInBytes()); + + temp = true; + block.CleanGrow(SIZE*2); + temp &= (block.size() == SIZE*2); + + for (size_t i = 0; i < block.size()/2; i++) + temp &= (block[i] == W64LIT(0xaaaaaaaaaaaaaaaa)); + + for (size_t i = block.size()/2; i < block.size(); i++) + temp &= (block[i] == 0); + + block.CleanNew(SIZE*4); + temp &= (block.size() == SIZE*4); + for (size_t i = 0; i < block.size(); i++) + temp &= (block[i] == 0); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + catch(const std::exception& /*ex*/) + { + temp = false; + } + + pass7 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " FixedSizeAllocator Grow with word64\n"; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) + // word128 + try + { + static const unsigned int SIZE = 8; + SecBlock > block(SIZE); + memset(block, 0xaa, block.SizeInBytes()); + + temp = true; + block.CleanGrow(SIZE*2); + temp &= (block.size() == SIZE*2); + + for (size_t i = 0; i < block.size()/2; i++) + temp &= (block[i] == (((word128)W64LIT(0xaaaaaaaaaaaaaaaa) << 64U) | W64LIT(0xaaaaaaaaaaaaaaaa))); + + for (size_t i = block.size()/2; i < block.size(); i++) + temp &= (block[i] == 0); + + block.CleanNew(SIZE*4); + temp &= (block.size() == SIZE*4); + for (size_t i = 0; i < block.size(); i++) + temp &= (block[i] == 0); + } + catch(const Exception& /*ex*/) + { + temp = false; + } + catch(const std::exception& /*ex*/) + { + temp = false; + } + + pass7 &= temp; + if (!temp) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " FixedSizeAllocator Grow with word128\n"; +#endif + + return pass1 && pass2 && pass3 && pass4 && pass5 && pass6 && pass7; +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestHuffmanCodes() +{ + std::cout << "\nTesting Huffman codes...\n\n"; + bool pass=true; + + static const size_t nCodes = 30; + const unsigned int codeCounts[nCodes] = { + 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, 0}; + + static const unsigned int maxCodeBits = nCodes >> 1; + unsigned int codeBits[nCodes] = { + ~0u, ~0u, ~0u, ~0u, ~0u, + ~0u, ~0u, ~0u, ~0u, ~0u, + ~0u, ~0u, ~0u, ~0u, ~0u, + }; + + try + { + HuffmanEncoder::GenerateCodeLengths(codeBits, maxCodeBits, codeCounts, nCodes); + } + catch(const Exception& /*ex*/) + { + pass=false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " GenerateCodeLengths" << std::endl; + + // Try to crash the HuffmanDecoder + for (unsigned int i=0; i<128; ++i) + { + try + { + byte data1[0xfff]; // Place on stack, avoid new + unsigned int data2[0xff]; + + unsigned int len1 = GlobalRNG().GenerateWord32(4, 0xfff); + GlobalRNG().GenerateBlock(data1, len1); + unsigned int len2 = GlobalRNG().GenerateWord32(4, 0xff); + GlobalRNG().GenerateBlock((byte*)data2, len2*sizeof(unsigned int)); + + ArraySource source(data1, len1, false); + HuffmanDecoder decoder(data2, len2); + + LowFirstBitReader reader(source); + unsigned int val; + for (unsigned int j=0; !source.AnyRetrievable(); ++j) + decoder.Decode(reader, val); + } + catch (const Exception&) {} + } + + std::cout << "passed: HuffmanDecoder decode" << std::endl; + + return pass; +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +bool TestAltivecOps() +{ + std::cout << "\nTesting Altivec operations...\n\n"; + + if (HasAltivec() == false) + { + std::cout << "\nAltivec not available, skipping test." << std::endl; + return true; + } + + // These tests may seem superflous, but we really want to test the + // Altivec/POWER4 implementation. That does not happen when POWER7 + // or POWER8 is available because we use POWER7's unaligned loads + // and stores with POWER8's AES, SHA, etc. These tests enage + // Altivec/POWER4 without POWER7, like on an old PowerMac. + + //********** Unaligned loads and stores **********// + bool pass1=true; + + CRYPTOPP_ALIGN_DATA(16) + byte dest[20], src[20] = {23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4}; + const byte st1[16] = {22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7}; + const byte st2[16] = {21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6}; + const byte st3[16] = {20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5}; + + VecStore(VecLoad(src), dest); + pass1 = (0 == std::memcmp(src, dest, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStore(VecLoad(src+1), dest+1); + pass1 = (0 == std::memcmp(st1, dest+1, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStore(VecLoad(src+2), dest+2); + pass1 = (0 == std::memcmp(st2, dest+2, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStore(VecLoad(src+3), dest+3); + pass1 = (0 == std::memcmp(st3, dest+3, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStoreBE(VecLoadBE(src), dest); + pass1 = (0 == std::memcmp(src, dest, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStoreBE(VecLoadBE(src+1), dest+1); + pass1 = (0 == std::memcmp(st1, dest+1, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStoreBE(VecLoadBE(src+2), dest+2); + pass1 = (0 == std::memcmp(st2, dest+2, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStoreBE(VecLoadBE(src+3), dest+3); + pass1 = (0 == std::memcmp(st3, dest+3, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + +#if (CRYPTOPP_LITTLE_ENDIAN) + VecStore(VecLoadBE(src), dest); + pass1 = (0 != std::memcmp(src, dest, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); + + VecStoreBE(VecLoad(src), dest); + pass1 = (0 != std::memcmp(src, dest, 16)) && pass1; + CRYPTOPP_ASSERT(pass1); +#endif + + if (!pass1) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Altivec loads and stores" << std::endl; + + //********** Shifts **********// + bool pass2=true; + + uint8x16_p val = {0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; + + pass2 = (VecEqual(val, VecShiftLeftOctet<0>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + pass2 = (VecEqual(val, VecShiftRightOctet<0>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + + uint8x16_p lsh1 = {0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00}; + uint8x16_p rsh1 = {0x00,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff}; + + pass2 = (VecEqual(lsh1, VecShiftLeftOctet<1>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + pass2 = (VecEqual(rsh1, VecShiftRightOctet<1>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + + uint8x16_p lsh15 = {0xff,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; + uint8x16_p rsh15 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xff}; + + pass2 = (VecEqual(lsh15, VecShiftLeftOctet<15>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + pass2 = (VecEqual(rsh15, VecShiftRightOctet<15>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + + uint8x16_p lsh16 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; + uint8x16_p rsh16 = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; + + pass2 = (VecEqual(lsh16, VecShiftLeftOctet<16>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + pass2 = (VecEqual(rsh16, VecShiftRightOctet<16>(val))) && pass2; + CRYPTOPP_ASSERT(pass2); + + if (!pass2) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Altivec left and right shifts" << std::endl; + + //********** Extraction **********// + bool pass3=true; + + const byte bex1[] = {0x1f,0x1e,0x1d,0x1c, 0x1b,0x1a,0x19,0x18, + 0x17,0x16,0x15,0x14, 0x13,0x12,0x11,0x10}; + const byte bex2[] = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x17,0x16,0x15,0x14, 0x13,0x12,0x11,0x10}; + const byte bex3[] = {0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, + 0x1f,0x1e,0x1d,0x1c, 0x1b,0x1a,0x19,0x18}; + + const uint8x16_p ex1 = (uint8x16_p)VecLoad(bex1); + const uint8x16_p ex2 = (uint8x16_p)VecLoad(bex2); + const uint8x16_p ex3 = (uint8x16_p)VecLoad(bex3); + + pass3 = VecEqual(ex2, VecGetLow(ex1)) && pass3; + CRYPTOPP_ASSERT(pass3); + pass3 = VecEqual(ex3, VecGetHigh(ex1)) && pass3; + CRYPTOPP_ASSERT(pass3); + + uint8x16_p ex4 = VecShiftRightOctet<8>(VecShiftLeftOctet<8>(ex1)); + pass3 = VecEqual(ex4, VecGetLow(ex1)) && pass3; + CRYPTOPP_ASSERT(pass3); + uint8x16_p ex5 = VecShiftRightOctet<8>(ex1); + pass3 = VecEqual(ex5, VecGetHigh(ex1)) && pass3; + CRYPTOPP_ASSERT(pass3); + + if (!pass3) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Altivec vector extraction" << std::endl; + + return pass1 && pass2 && pass3; +} +#endif +#endif + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat10.cpp b/extension/third_party/cryptopp/validat10.cpp new file mode 100644 index 00000000..4e7bf9f8 --- /dev/null +++ b/extension/third_party/cryptopp/validat10.cpp @@ -0,0 +1,535 @@ +// validat10.cpp - written and placed in the public domain by Jeffrey Walton +// Routines in this source file test NaCl library routines. +// Source files split in July 2018 to expedite compiles. +// +// There are two types or sets of self tests. First is a known answer test, +// and second are pairwise consitency checks. The known answer tests are test +// vectors lifted from libsodium. The pairwise consitency checks are randomized +// and confirm the library can arrive at the same result or round trip data +// using it's own transformations. +// +// A link like https://github.com/jedisct1/libsodium/blob/master/test/default/box.c +// references the libsodium test data for a test. For example, box.c is one of the +// test runners for crypto_box, and there is a box.exp with the known answer. The +// glue code for box.c and box.exp is in "cmptest.h". box.c runs the test and +// generates output, while cmptest.h gathers the output and compares them. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "secblock.h" +#include "integer.h" +#include "naclite.h" +#include "validate.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4610 4510 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +#ifndef CRYPTOPP_DISABLE_NACL + +USING_NAMESPACE(NaCl) + +bool TestCryptoBox() +{ + // https://github.com/jedisct1/libsodium/blob/master/test/default/box.c + const byte alicesk[32] = { + 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, + 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, + 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a + }; + + const byte bobpk[32] = { + 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, + 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, + 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f + }; + + const byte small_order_p[crypto_box_PUBLICKEYBYTES] = { + 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, + 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, + 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 + }; + + const byte nonce[24] = { + 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, + 0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37 + }; + + /* API requires first 32 bytes to be 0 */ + const byte m[163] = { + 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, 0xbe, 0x07, 0x5f, 0xc5, + 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16, 0xeb, 0xeb, 0x0c, 0x7b, + 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4, 0x4b, 0x66, 0x84, 0x9b, + 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf, 0x33, 0xbd, 0x75, 0x1a, + 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29, 0x6c, 0xdc, 0x3c, 0x01, + 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce, 0x31, 0x4a, 0xdb, 0x31, + 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d, 0xce, 0xea, 0x3a, 0x7f, + 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a, 0xd6, 0xb1, 0x31, 0x8a, + 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde, 0x04, 0x89, 0x77, 0xeb, + 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c, 0x60, 0x90, 0x2e, 0x52, + 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40, 0xe0, 0x82, 0xf9, 0x37, + 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05 + }; + + const byte exp1[] = { + 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9, + 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, + 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, + 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, + 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, + 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, + 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, + 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, + 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, + 0xe3,0x55,0xa5 + }; + + const byte exp2[] = { + 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5 ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9, + 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73 ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, + 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4 ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, + 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, + 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2 ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, + 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, + 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, + 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, + 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6 ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, + 0xe3,0x55,0xa5 + }; + + byte c[163]; + byte k[crypto_box_BEFORENMBYTES]; + + bool pass = true; int rc; + + // Reject small order elements + + rc = crypto_box(c, m, 163, nonce, bobpk, alicesk); + pass = (rc == 0) && pass; + pass = (std::memcmp(c+16, exp1, 163-16) == 0) && pass; + + rc = crypto_box(c, m, 163, nonce, small_order_p, alicesk); + pass = (rc != 0) && pass; + std::memset(c, 0, sizeof(c)); + + rc = crypto_box_beforenm(k, bobpk, alicesk); + pass = (rc == 0) && pass; + rc = crypto_box_afternm(c, m, 163, nonce, k); + pass = (rc == 0) && pass; + pass = (std::memcmp(c+16, exp2, 163-16) == 0) && pass; + + rc = crypto_box_beforenm(k, small_order_p, alicesk); + pass = (rc != 0) && pass; + + // Allow small order elements + + rc = crypto_box_unchecked(c, m, 163, nonce, bobpk, alicesk); + pass = (rc == 0) && pass; + pass = (std::memcmp(c+16, exp1, 163-16) == 0) && pass; + + rc = crypto_box_unchecked(c, m, 163, nonce, small_order_p, alicesk); + pass = (rc == 0) && pass; + std::memset(c, 0, sizeof(c)); + + rc = crypto_box_beforenm_unchecked(k, bobpk, alicesk); + pass = (rc == 0) && pass; + rc = crypto_box_afternm(c, m, 163, nonce, k); + pass = (rc == 0) && pass; + pass = (std::memcmp(c+16, exp2, 163-16) == 0) && pass; + + rc = crypto_box_beforenm_unchecked(k, small_order_p, alicesk); + pass = (rc == 0) && pass; + + return pass; +} + +bool TestCryptoBoxOpen() +{ + // https://github.com/jedisct1/libsodium/blob/master/test/default/box2.c + const byte bobsk[32] = { + 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, + 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, + 0xff, 0x88, 0xe0, 0xeb + }; + + const byte alicepk[32] = { + 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, + 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, + 0xaa, 0x9b, 0x4e, 0x6a + }; + + static const byte small_order_p[crypto_box_PUBLICKEYBYTES] = { + 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, + 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, + 0x5f, 0x49, 0xb8, 0x00 + }; + + const byte nonce[24] = { + 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, + 0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37 + }; + + /* API requires first 16 bytes to be 0 */ + const byte c[163] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, + 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9, 0x8e, 0x99, 0x3b, 0x9f, + 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, + 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5, + 0x31, 0xa1, 0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, + 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, + 0x9b, 0x92, 0x8f, 0xe2, 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, + 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, 0xb9, 0x32, 0x16, 0x45, + 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, + 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83, 0x2b, 0x61, + 0xca, 0x01, 0xb6, 0xde, 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, + 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, 0x59, 0x9b, 0x1f, 0x65, + 0x4c, 0xb4, 0x5a, 0x74, 0xe3, 0x55, 0xa5 + }; + + const byte exp1[] = { + 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5, 0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b, + 0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4, 0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc, + 0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a, 0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29, + 0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4, 0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31, + 0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d, 0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57, + 0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a, 0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde, + 0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd, 0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52, + 0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40, 0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64, + 0x5e,0x07,0x05 + }; + + const byte exp2[] = { + 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5, 0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b, + 0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4, 0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc, + 0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a, 0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29, + 0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4, 0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31, + 0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d, 0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57, + 0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a, 0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde, + 0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd, 0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52, + 0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40, 0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64, + 0x5e,0x07,0x05 + }; + + byte m[163]; + byte k[crypto_box_BEFORENMBYTES]; + + bool pass = true; int rc; + + // Reject small order elements + + rc = crypto_box_open(m, c, 163, nonce, alicepk, bobsk); + pass = (rc == 0) && pass; + pass = (std::memcmp(m+32, exp1, 163-32) == 0) && pass; + + rc = crypto_box_open(m, c, 163, nonce, small_order_p, bobsk); + pass = (rc != 0) && pass; + + rc = crypto_box_beforenm(k, small_order_p, bobsk); + pass = (rc != 0) && pass; + rc = crypto_box_beforenm(k, alicepk, bobsk); + pass = (rc == 0) && pass; + + rc = crypto_box_open_afternm(m, c, 163, nonce, k); + pass = (rc == 0) && pass; + pass = (std::memcmp(m+32, exp2, 163-32) == 0) && pass; + + // Allow small order elements + + rc = crypto_box_open_unchecked(m, c, 163, nonce, alicepk, bobsk); + pass = (rc == 0) && pass; + pass = (std::memcmp(m+32, exp1, 163-32) == 0) && pass; + + rc = crypto_box_beforenm_unchecked(k, small_order_p, bobsk); + pass = (rc == 0) && pass; + rc = crypto_box_beforenm_unchecked(k, alicepk, bobsk); + pass = (rc == 0) && pass; + + rc = crypto_box_open_afternm(m, c, 163, nonce, k); + pass = (rc == 0) && pass; + pass = (std::memcmp(m+32, exp2, 163-32) == 0) && pass; + + return pass; +} + +bool TestCryptoBoxKeys() +{ + // https://github.com/jedisct1/libsodium/blob/master/test/default/box7.c + const unsigned int MAX_TEST = 64; + const unsigned int MAX_MESSAGE = 4096; + + byte alicesk[crypto_box_SECRETKEYBYTES]; + byte alicepk[crypto_box_PUBLICKEYBYTES]; + byte bobsk[crypto_box_SECRETKEYBYTES]; + byte bobpk[crypto_box_PUBLICKEYBYTES]; + + // byte m[MAX_MESSAGE+32]; + // byte c[MAX_MESSAGE+32]; + // byte r[MAX_MESSAGE+32]; + + bool pass = true, fail; int rc; + for (unsigned int i=0; i < MAX_TEST; ++i) + { + fail = (crypto_box_keypair(alicepk, alicesk) != 0); + pass = !fail && pass; + fail = (crypto_box_keypair(bobpk, bobsk) != 0); + pass = !fail && pass; + + SecByteBlock m, c, r, n; + const word32 len = (i == 0 ? 0 : GlobalRNG().GenerateWord32(1, MAX_MESSAGE)); + + m.New(len+crypto_box_ZEROBYTES); + c.New(len+crypto_box_BOXZEROBYTES+crypto_box_MACBYTES); + r.New(len+crypto_box_ZEROBYTES); + n.New(crypto_box_NONCEBYTES); + + GlobalRNG().GenerateBlock(m+crypto_box_ZEROBYTES, len); + GlobalRNG().GenerateBlock(n, crypto_box_NONCEBYTES); + + std::memset(m, 0x00, crypto_box_ZEROBYTES); + rc = crypto_box(c, m, len + crypto_box_ZEROBYTES, n, bobpk, alicesk); + fail = (rc != 0); pass = !fail && pass; + + std::memset(c, 0x00, crypto_box_BOXZEROBYTES); + rc = crypto_box_open(r, c, len + crypto_box_BOXZEROBYTES + crypto_box_MACBYTES, n, alicepk, bobsk); + fail = (rc != 0); pass = !fail && pass; + + fail = std::memcmp(m+crypto_box_ZEROBYTES, r+crypto_box_ZEROBYTES, len) != 0; + pass = !fail && pass; + + m.SetMark(16); c.SetMark(16); r.SetMark(16); + } + + return pass; +} + +struct TestData { + const byte sk[crypto_sign_SEEDBYTES]; + const byte pk[crypto_sign_PUBLICKEYBYTES]; + const byte sig[crypto_sign_BYTES]; + const word32 len; + const char* msg; +}; + +// https://github.com/jedisct1/libsodium/blob/master/test/default/sign.c +const TestData test_data[] = { + {{0x9d,0x61,0xb1,0x9d,0xef,0xfd,0x5a,0x60,0xba,0x84,0x4a,0xf4,0x92,0xec,0x2c,0xc4,0x44,0x49,0xc5,0x69,0x7b,0x32,0x69,0x19,0x70,0x3b,0xac,0x03,0x1c,0xae,0x7f,0x60,},{0xd7,0x5a,0x98,0x01,0x82,0xb1,0x0a,0xb7,0xd5,0x4b,0xfe,0xd3,0xc9,0x64,0x07,0x3a,0x0e,0xe1,0x72,0xf3,0xda,0xa6,0x23,0x25,0xaf,0x02,0x1a,0x68,0xf7,0x07,0x51,0x1a,},{0xe5,0x56,0x43,0x00,0xc3,0x60,0xac,0x72,0x90,0x86,0xe2,0xcc,0x80,0x6e,0x82,0x8a,0x84,0x87,0x7f,0x1e,0xb8,0xe5,0xd9,0x74,0xd8,0x73,0xe0,0x65,0x22,0x49,0x01,0x55,0x5f,0xb8,0x82,0x15,0x90,0xa3,0x3b,0xac,0xc6,0x1e,0x39,0x70,0x1c,0xf9,0xb4,0x6b,0xd2,0x5b,0xf5,0xf0,0x59,0x5b,0xbe,0x24,0x65,0x51,0x41,0x43,0x8e,0x7a,0x10,0x0b,},0,""}, + {{0x4c,0xcd,0x08,0x9b,0x28,0xff,0x96,0xda,0x9d,0xb6,0xc3,0x46,0xec,0x11,0x4e,0x0f,0x5b,0x8a,0x31,0x9f,0x35,0xab,0xa6,0x24,0xda,0x8c,0xf6,0xed,0x4f,0xb8,0xa6,0xfb,},{0x3d,0x40,0x17,0xc3,0xe8,0x43,0x89,0x5a,0x92,0xb7,0x0a,0xa7,0x4d,0x1b,0x7e,0xbc,0x9c,0x98,0x2c,0xcf,0x2e,0xc4,0x96,0x8c,0xc0,0xcd,0x55,0xf1,0x2a,0xf4,0x66,0x0c,},{0x92,0xa0,0x09,0xa9,0xf0,0xd4,0xca,0xb8,0x72,0x0e,0x82,0x0b,0x5f,0x64,0x25,0x40,0xa2,0xb2,0x7b,0x54,0x16,0x50,0x3f,0x8f,0xb3,0x76,0x22,0x23,0xeb,0xdb,0x69,0xda,0x08,0x5a,0xc1,0xe4,0x3e,0x15,0x99,0x6e,0x45,0x8f,0x36,0x13,0xd0,0xf1,0x1d,0x8c,0x38,0x7b,0x2e,0xae,0xb4,0x30,0x2a,0xee,0xb0,0x0d,0x29,0x16,0x12,0xbb,0x0c,0x00,},1,"\x72"}, + {{0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b,0xed,0xb7,0x44,0x2f,0x31,0xdc,0xb7,0xb1,0x66,0xd3,0x85,0x35,0x07,0x6f,0x09,0x4b,0x85,0xce,0x3a,0x2e,0x0b,0x44,0x58,0xf7,},{0xfc,0x51,0xcd,0x8e,0x62,0x18,0xa1,0xa3,0x8d,0xa4,0x7e,0xd0,0x02,0x30,0xf0,0x58,0x08,0x16,0xed,0x13,0xba,0x33,0x03,0xac,0x5d,0xeb,0x91,0x15,0x48,0x90,0x80,0x25,},{0x62,0x91,0xd6,0x57,0xde,0xec,0x24,0x02,0x48,0x27,0xe6,0x9c,0x3a,0xbe,0x01,0xa3,0x0c,0xe5,0x48,0xa2,0x84,0x74,0x3a,0x44,0x5e,0x36,0x80,0xd7,0xdb,0x5a,0xc3,0xac,0x18,0xff,0x9b,0x53,0x8d,0x16,0xf2,0x90,0xae,0x67,0xf7,0x60,0x98,0x4d,0xc6,0x59,0x4a,0x7c,0x15,0xe9,0x71,0x6e,0xd2,0x8d,0xc0,0x27,0xbe,0xce,0xea,0x1e,0xc4,0x0a,},2,"\xaf\x82"}, + {{0x0d,0x4a,0x05,0xb0,0x73,0x52,0xa5,0x43,0x6e,0x18,0x03,0x56,0xda,0x0a,0xe6,0xef,0xa0,0x34,0x5f,0xf7,0xfb,0x15,0x72,0x57,0x57,0x72,0xe8,0x00,0x5e,0xd9,0x78,0xe9,},{0xe6,0x1a,0x18,0x5b,0xce,0xf2,0x61,0x3a,0x6c,0x7c,0xb7,0x97,0x63,0xce,0x94,0x5d,0x3b,0x24,0x5d,0x76,0x11,0x4d,0xd4,0x40,0xbc,0xf5,0xf2,0xdc,0x1a,0xa5,0x70,0x57,},{0xd9,0x86,0x8d,0x52,0xc2,0xbe,0xbc,0xe5,0xf3,0xfa,0x5a,0x79,0x89,0x19,0x70,0xf3,0x09,0xcb,0x65,0x91,0xe3,0xe1,0x70,0x2a,0x70,0x27,0x6f,0xa9,0x7c,0x24,0xb3,0xa8,0xe5,0x86,0x06,0xc3,0x8c,0x97,0x58,0x52,0x9d,0xa5,0x0e,0xe3,0x1b,0x82,0x19,0xcb,0xa4,0x52,0x71,0xc6,0x89,0xaf,0xa6,0x0b,0x0e,0xa2,0x6c,0x99,0xdb,0x19,0xb0,0x0c,},3,"\xcb\xc7\x7b"}, + {{0x6d,0xf9,0x34,0x0c,0x13,0x8c,0xc1,0x88,0xb5,0xfe,0x44,0x64,0xeb,0xaa,0x3f,0x7f,0xc2,0x06,0xa2,0xd5,0x5c,0x34,0x34,0x70,0x7e,0x74,0xc9,0xfc,0x04,0xe2,0x0e,0xbb,},{0xc0,0xda,0xc1,0x02,0xc4,0x53,0x31,0x86,0xe2,0x5d,0xc4,0x31,0x28,0x47,0x23,0x53,0xea,0xab,0xdb,0x87,0x8b,0x15,0x2a,0xeb,0x8e,0x00,0x1f,0x92,0xd9,0x02,0x33,0xa7,},{0x12,0x4f,0x6f,0xc6,0xb0,0xd1,0x00,0x84,0x27,0x69,0xe7,0x1b,0xd5,0x30,0x66,0x4d,0x88,0x8d,0xf8,0x50,0x7d,0xf6,0xc5,0x6d,0xed,0xfd,0xb5,0x09,0xae,0xb9,0x34,0x16,0xe2,0x6b,0x91,0x8d,0x38,0xaa,0x06,0x30,0x5d,0xf3,0x09,0x56,0x97,0xc1,0x8b,0x2a,0xa8,0x32,0xea,0xa5,0x2e,0xdc,0x0a,0xe4,0x9f,0xba,0xe5,0xa8,0x5e,0x15,0x0c,0x07,},4,"\x5f\x4c\x89\x89"}, + {{0xb7,0x80,0x38,0x1a,0x65,0xed,0xf8,0xb7,0x8f,0x69,0x45,0xe8,0xdb,0xec,0x79,0x41,0xac,0x04,0x9f,0xd4,0xc6,0x10,0x40,0xcf,0x0c,0x32,0x43,0x57,0x97,0x5a,0x29,0x3c,},{0xe2,0x53,0xaf,0x07,0x66,0x80,0x4b,0x86,0x9b,0xb1,0x59,0x5b,0xe9,0x76,0x5b,0x53,0x48,0x86,0xbb,0xaa,0xb8,0x30,0x5b,0xf5,0x0d,0xbc,0x7f,0x89,0x9b,0xfb,0x5f,0x01,},{0xb2,0xfc,0x46,0xad,0x47,0xaf,0x46,0x44,0x78,0xc1,0x99,0xe1,0xf8,0xbe,0x16,0x9f,0x1b,0xe6,0x32,0x7c,0x7f,0x9a,0x0a,0x66,0x89,0x37,0x1c,0xa9,0x4c,0xaf,0x04,0x06,0x4a,0x01,0xb2,0x2a,0xff,0x15,0x20,0xab,0xd5,0x89,0x51,0x34,0x16,0x03,0xfa,0xed,0x76,0x8c,0xf7,0x8c,0xe9,0x7a,0xe7,0xb0,0x38,0xab,0xfe,0x45,0x6a,0xa1,0x7c,0x09,},5,"\x18\xb6\xbe\xc0\x97"}, + {{0x78,0xae,0x9e,0xff,0xe6,0xf2,0x45,0xe9,0x24,0xa7,0xbe,0x63,0x04,0x11,0x46,0xeb,0xc6,0x70,0xdb,0xd3,0x06,0x0c,0xba,0x67,0xfb,0xc6,0x21,0x6f,0xeb,0xc4,0x45,0x46,},{0xfb,0xcf,0xbf,0xa4,0x05,0x05,0xd7,0xf2,0xbe,0x44,0x4a,0x33,0xd1,0x85,0xcc,0x54,0xe1,0x6d,0x61,0x52,0x60,0xe1,0x64,0x0b,0x2b,0x50,0x87,0xb8,0x3e,0xe3,0x64,0x3d,},{0x6e,0xd6,0x29,0xfc,0x1d,0x9c,0xe9,0xe1,0x46,0x87,0x55,0xff,0x63,0x6d,0x5a,0x3f,0x40,0xa5,0xd9,0xc9,0x1a,0xfd,0x93,0xb7,0x9d,0x24,0x18,0x30,0xf7,0xe5,0xfa,0x29,0x85,0x4b,0x8f,0x20,0xcc,0x6e,0xec,0xbb,0x24,0x8d,0xbd,0x8d,0x16,0xd1,0x4e,0x99,0x75,0x21,0x94,0xe4,0x90,0x4d,0x09,0xc7,0x4d,0x63,0x95,0x18,0x83,0x9d,0x23,0x00,},6,"\x89\x01\x0d\x85\x59\x72"}, + {{0x69,0x18,0x65,0xbf,0xc8,0x2a,0x1e,0x4b,0x57,0x4e,0xec,0xde,0x4c,0x75,0x19,0x09,0x3f,0xaf,0x0c,0xf8,0x67,0x38,0x02,0x34,0xe3,0x66,0x46,0x45,0xc6,0x1c,0x5f,0x79,},{0x98,0xa5,0xe3,0xa3,0x6e,0x67,0xaa,0xba,0x89,0x88,0x8b,0xf0,0x93,0xde,0x1a,0xd9,0x63,0xe7,0x74,0x01,0x3b,0x39,0x02,0xbf,0xab,0x35,0x6d,0x8b,0x90,0x17,0x8a,0x63,},{0x6e,0x0a,0xf2,0xfe,0x55,0xae,0x37,0x7a,0x6b,0x7a,0x72,0x78,0xed,0xfb,0x41,0x9b,0xd3,0x21,0xe0,0x6d,0x0d,0xf5,0xe2,0x70,0x37,0xdb,0x88,0x12,0xe7,0xe3,0x52,0x98,0x10,0xfa,0x55,0x52,0xf6,0xc0,0x02,0x09,0x85,0xca,0x17,0xa0,0xe0,0x2e,0x03,0x6d,0x7b,0x22,0x2a,0x24,0xf9,0x9b,0x77,0xb7,0x5f,0xdd,0x16,0xcb,0x05,0x56,0x81,0x07,},7,"\xb4\xa8\xf3\x81\xe7\x0e\x7a"}, + {{0x3b,0x26,0x51,0x6f,0xb3,0xdc,0x88,0xeb,0x18,0x1b,0x9e,0xd7,0x3f,0x0b,0xcd,0x52,0xbc,0xd6,0xb4,0xc7,0x88,0xe4,0xbc,0xaf,0x46,0x05,0x7f,0xd0,0x78,0xbe,0xe0,0x73,},{0xf8,0x1f,0xb5,0x4a,0x82,0x5f,0xce,0xd9,0x5e,0xb0,0x33,0xaf,0xcd,0x64,0x31,0x40,0x75,0xab,0xfb,0x0a,0xbd,0x20,0xa9,0x70,0x89,0x25,0x03,0x43,0x6f,0x34,0xb8,0x63,},{0xd6,0xad,0xde,0xc5,0xaf,0xb0,0x52,0x8a,0xc1,0x7b,0xb1,0x78,0xd3,0xe7,0xf2,0x88,0x7f,0x9a,0xdb,0xb1,0xad,0x16,0xe1,0x10,0x54,0x5e,0xf3,0xbc,0x57,0xf9,0xde,0x23,0x14,0xa5,0xc8,0x38,0x8f,0x72,0x3b,0x89,0x07,0xbe,0x0f,0x3a,0xc9,0x0c,0x62,0x59,0xbb,0xe8,0x85,0xec,0xc1,0x76,0x45,0xdf,0x3d,0xb7,0xd4,0x88,0xf8,0x05,0xfa,0x08,},8,"\x42\x84\xab\xc5\x1b\xb6\x72\x35"}, + {{0xed,0xc6,0xf5,0xfb,0xdd,0x1c,0xee,0x4d,0x10,0x1c,0x06,0x35,0x30,0xa3,0x04,0x90,0xb2,0x21,0xbe,0x68,0xc0,0x36,0xf5,0xb0,0x7d,0x0f,0x95,0x3b,0x74,0x5d,0xf1,0x92,},{0xc1,0xa4,0x9c,0x66,0xe6,0x17,0xf9,0xef,0x5e,0xc6,0x6b,0xc4,0xc6,0x56,0x4c,0xa3,0x3d,0xe2,0xa5,0xfb,0x5e,0x14,0x64,0x06,0x2e,0x6d,0x6c,0x62,0x19,0x15,0x5e,0xfd,},{0x2c,0x76,0xa0,0x4a,0xf2,0x39,0x1c,0x14,0x70,0x82,0xe3,0x3f,0xaa,0xcd,0xbe,0x56,0x64,0x2a,0x1e,0x13,0x4b,0xd3,0x88,0x62,0x0b,0x85,0x2b,0x90,0x1a,0x6b,0xc1,0x6f,0xf6,0xc9,0xcc,0x94,0x04,0xc4,0x1d,0xea,0x12,0xed,0x28,0x1d,0xa0,0x67,0xa1,0x51,0x38,0x66,0xf9,0xd9,0x64,0xf8,0xbd,0xd2,0x49,0x53,0x85,0x6c,0x50,0x04,0x29,0x01,},9,"\x67\x2b\xf8\x96\x5d\x04\xbc\x51\x46"}, + {{0x4e,0x7d,0x21,0xfb,0x3b,0x18,0x97,0x57,0x1a,0x44,0x58,0x33,0xbe,0x0f,0x9f,0xd4,0x1c,0xd6,0x2b,0xe3,0xaa,0x04,0x04,0x0f,0x89,0x34,0xe1,0xfc,0xbd,0xca,0xcd,0x45,},{0x31,0xb2,0x52,0x4b,0x83,0x48,0xf7,0xab,0x1d,0xfa,0xfa,0x67,0x5c,0xc5,0x38,0xe9,0xa8,0x4e,0x3f,0xe5,0x81,0x9e,0x27,0xc1,0x2a,0xd8,0xbb,0xc1,0xa3,0x6e,0x4d,0xff,},{0x28,0xe4,0x59,0x8c,0x41,0x5a,0xe9,0xde,0x01,0xf0,0x3f,0x9f,0x3f,0xab,0x4e,0x91,0x9e,0x8b,0xf5,0x37,0xdd,0x2b,0x0c,0xdf,0x6e,0x79,0xb9,0xe6,0x55,0x9c,0x94,0x09,0xd9,0x15,0x1a,0x4c,0x40,0xf0,0x83,0x19,0x39,0x37,0x62,0x7c,0x36,0x94,0x88,0x25,0x9e,0x99,0xda,0x5a,0x9f,0x0a,0x87,0x49,0x7f,0xa6,0x69,0x6a,0x5d,0xd6,0xce,0x08,},10,"\x33\xd7\xa7\x86\xad\xed\x8c\x1b\xf6\x91"}, + {{0xa9,0x80,0xf8,0x92,0xdb,0x13,0xc9,0x9a,0x3e,0x89,0x71,0xe9,0x65,0xb2,0xff,0x3d,0x41,0xea,0xfd,0x54,0x09,0x3b,0xc9,0xf3,0x4d,0x1f,0xd2,0x2d,0x84,0x11,0x5b,0xb6,},{0x44,0xb5,0x7e,0xe3,0x0c,0xdb,0x55,0x82,0x9d,0x0a,0x5d,0x4f,0x04,0x6b,0xae,0xf0,0x78,0xf1,0xe9,0x7a,0x7f,0x21,0xb6,0x2d,0x75,0xf8,0xe9,0x6e,0xa1,0x39,0xc3,0x5f,},{0x77,0xd3,0x89,0xe5,0x99,0x63,0x0d,0x93,0x40,0x76,0x32,0x95,0x83,0xcd,0x41,0x05,0xa6,0x49,0xa9,0x29,0x2a,0xbc,0x44,0xcd,0x28,0xc4,0x00,0x00,0xc8,0xe2,0xf5,0xac,0x76,0x60,0xa8,0x1c,0x85,0xb7,0x2a,0xf8,0x45,0x2d,0x7d,0x25,0xc0,0x70,0x86,0x1d,0xae,0x91,0x60,0x1c,0x78,0x03,0xd6,0x56,0x53,0x16,0x50,0xdd,0x4e,0x5c,0x41,0x00,},11,"\x34\x86\xf6\x88\x48\xa6\x5a\x0e\xb5\x50\x7d"}, + {{0x5b,0x5a,0x61,0x9f,0x8c,0xe1,0xc6,0x6d,0x7c,0xe2,0x6e,0x5a,0x2a,0xe7,0xb0,0xc0,0x4f,0xeb,0xcd,0x34,0x6d,0x28,0x6c,0x92,0x9e,0x19,0xd0,0xd5,0x97,0x3b,0xfe,0xf9,},{0x6f,0xe8,0x36,0x93,0xd0,0x11,0xd1,0x11,0x13,0x1c,0x4f,0x3f,0xba,0xaa,0x40,0xa9,0xd3,0xd7,0x6b,0x30,0x01,0x2f,0xf7,0x3b,0xb0,0xe3,0x9e,0xc2,0x7a,0xb1,0x82,0x57,},{0x0f,0x9a,0xd9,0x79,0x30,0x33,0xa2,0xfa,0x06,0x61,0x4b,0x27,0x7d,0x37,0x38,0x1e,0x6d,0x94,0xf6,0x5a,0xc2,0xa5,0xa9,0x45,0x58,0xd0,0x9e,0xd6,0xce,0x92,0x22,0x58,0xc1,0xa5,0x67,0x95,0x2e,0x86,0x3a,0xc9,0x42,0x97,0xae,0xc3,0xc0,0xd0,0xc8,0xdd,0xf7,0x10,0x84,0xe5,0x04,0x86,0x0b,0xb6,0xba,0x27,0x44,0x9b,0x55,0xad,0xc4,0x0e,},12,"\x5a\x8d\x9d\x0a\x22\x35\x7e\x66\x55\xf9\xc7\x85"}, + {{0x94,0x0c,0x89,0xfe,0x40,0xa8,0x1d,0xaf,0xbd,0xb2,0x41,0x6d,0x14,0xae,0x46,0x91,0x19,0x86,0x97,0x44,0x41,0x0c,0x33,0x03,0xbf,0xaa,0x02,0x41,0xda,0xc5,0x78,0x00,},{0xa2,0xeb,0x8c,0x05,0x01,0xe3,0x0b,0xae,0x0c,0xf8,0x42,0xd2,0xbd,0xe8,0xde,0xc7,0x38,0x6f,0x6b,0x7f,0xc3,0x98,0x1b,0x8c,0x57,0xc9,0x79,0x2b,0xb9,0x4c,0xf2,0xdd,},{0xd8,0xbb,0x64,0xaa,0xd8,0xc9,0x95,0x5a,0x11,0x5a,0x79,0x3a,0xdd,0xd2,0x4f,0x7f,0x2b,0x07,0x76,0x48,0x71,0x4f,0x49,0xc4,0x69,0x4e,0xc9,0x95,0xb3,0x30,0xd0,0x9d,0x64,0x0d,0xf3,0x10,0xf4,0x47,0xfd,0x7b,0x6c,0xb5,0xc1,0x4f,0x9f,0xe9,0xf4,0x90,0xbc,0xf8,0xcf,0xad,0xbf,0xd2,0x16,0x9c,0x8a,0xc2,0x0d,0x3b,0x8a,0xf4,0x9a,0x0c,},13,"\xb8\x7d\x38\x13\xe0\x3f\x58\xcf\x19\xfd\x0b\x63\x95"}, + {{0x9a,0xca,0xd9,0x59,0xd2,0x16,0x21,0x2d,0x78,0x9a,0x11,0x92,0x52,0xeb,0xfe,0x0c,0x96,0x51,0x2a,0x23,0xc7,0x3b,0xd9,0xf3,0xb2,0x02,0x29,0x2d,0x69,0x16,0xa7,0x38,},{0xcf,0x3a,0xf8,0x98,0x46,0x7a,0x5b,0x7a,0x52,0xd3,0x3d,0x53,0xbc,0x03,0x7e,0x26,0x42,0xa8,0xda,0x99,0x69,0x03,0xfc,0x25,0x22,0x17,0xe9,0xc0,0x33,0xe2,0xf2,0x91,},{0x6e,0xe3,0xfe,0x81,0xe2,0x3c,0x60,0xeb,0x23,0x12,0xb2,0x00,0x6b,0x3b,0x25,0xe6,0x83,0x8e,0x02,0x10,0x66,0x23,0xf8,0x44,0xc4,0x4e,0xdb,0x8d,0xaf,0xd6,0x6a,0xb0,0x67,0x10,0x87,0xfd,0x19,0x5d,0xf5,0xb8,0xf5,0x8a,0x1d,0x6e,0x52,0xaf,0x42,0x90,0x80,0x53,0xd5,0x5c,0x73,0x21,0x01,0x00,0x92,0x74,0x87,0x95,0xef,0x94,0xcf,0x06,},14,"\x55\xc7\xfa\x43\x4f\x5e\xd8\xcd\xec\x2b\x7a\xea\xc1\x73"}, + {{0xd5,0xae,0xee,0x41,0xee,0xb0,0xe9,0xd1,0xbf,0x83,0x37,0xf9,0x39,0x58,0x7e,0xbe,0x29,0x61,0x61,0xe6,0xbf,0x52,0x09,0xf5,0x91,0xec,0x93,0x9e,0x14,0x40,0xc3,0x00,},{0xfd,0x2a,0x56,0x57,0x23,0x16,0x3e,0x29,0xf5,0x3c,0x9d,0xe3,0xd5,0xe8,0xfb,0xe3,0x6a,0x7a,0xb6,0x6e,0x14,0x39,0xec,0x4e,0xae,0x9c,0x0a,0x60,0x4a,0xf2,0x91,0xa5,},{0xf6,0x8d,0x04,0x84,0x7e,0x5b,0x24,0x97,0x37,0x89,0x9c,0x01,0x4d,0x31,0xc8,0x05,0xc5,0x00,0x7a,0x62,0xc0,0xa1,0x0d,0x50,0xbb,0x15,0x38,0xc5,0xf3,0x55,0x03,0x95,0x1f,0xbc,0x1e,0x08,0x68,0x2f,0x2c,0xc0,0xc9,0x2e,0xfe,0x8f,0x49,0x85,0xde,0xc6,0x1d,0xcb,0xd5,0x4d,0x4b,0x94,0xa2,0x25,0x47,0xd2,0x44,0x51,0x27,0x1c,0x8b,0x00,},15,"\x0a\x68\x8e\x79\xbe\x24\xf8\x66\x28\x6d\x46\x46\xb5\xd8\x1c"}, + {{0x0a,0x47,0xd1,0x04,0x52,0xae,0x2f,0xeb,0xec,0x51,0x8a,0x1c,0x7c,0x36,0x28,0x90,0xc3,0xfc,0x1a,0x49,0xd3,0x4b,0x03,0xb6,0x46,0x7d,0x35,0xc9,0x04,0xa8,0x36,0x2d,},{0x34,0xe5,0xa8,0x50,0x8c,0x47,0x43,0x74,0x69,0x62,0xc0,0x66,0xe4,0xba,0xde,0xa2,0x20,0x1b,0x8a,0xb4,0x84,0xde,0x5c,0x4f,0x94,0x47,0x6c,0xcd,0x21,0x43,0x95,0x5b,},{0x2a,0x3d,0x27,0xdc,0x40,0xd0,0xa8,0x12,0x79,0x49,0xa3,0xb7,0xf9,0x08,0xb3,0x68,0x8f,0x63,0xb7,0xf1,0x4f,0x65,0x1a,0xac,0xd7,0x15,0x94,0x0b,0xdb,0xe2,0x7a,0x08,0x09,0xaa,0xc1,0x42,0xf4,0x7a,0xb0,0xe1,0xe4,0x4f,0xa4,0x90,0xba,0x87,0xce,0x53,0x92,0xf3,0x3a,0x89,0x15,0x39,0xca,0xf1,0xef,0x4c,0x36,0x7c,0xae,0x54,0x50,0x0c,},16,"\xc9\x42\xfa\x7a\xc6\xb2\x3a\xb7\xff\x61\x2f\xdc\x8e\x68\xef\x39"}, + {{0xf8,0x14,0x8f,0x75,0x06,0xb7,0x75,0xef,0x46,0xfd,0xc8,0xe8,0xc7,0x56,0x51,0x68,0x12,0xd4,0x7d,0x6c,0xfb,0xfa,0x31,0x8c,0x27,0xc9,0xa2,0x26,0x41,0xe5,0x6f,0x17,},{0x04,0x45,0xe4,0x56,0xda,0xcc,0x7d,0x5b,0x0b,0xbe,0xd2,0x3c,0x82,0x00,0xcd,0xb7,0x4b,0xdc,0xb0,0x3e,0x4c,0x7b,0x73,0xf0,0xa2,0xb9,0xb4,0x6e,0xac,0x5d,0x43,0x72,},{0x36,0x53,0xcc,0xb2,0x12,0x19,0x20,0x2b,0x84,0x36,0xfb,0x41,0xa3,0x2b,0xa2,0x61,0x8c,0x4a,0x13,0x34,0x31,0xe6,0xe6,0x34,0x63,0xce,0xb3,0xb6,0x10,0x6c,0x4d,0x56,0xe1,0xd2,0xba,0x16,0x5b,0xa7,0x6e,0xaa,0xd3,0xdc,0x39,0xbf,0xfb,0x13,0x0f,0x1d,0xe3,0xd8,0xe6,0x42,0x7d,0xb5,0xb7,0x19,0x38,0xdb,0x4e,0x27,0x2b,0xc3,0xe2,0x0b,},17,"\x73\x68\x72\x4a\x5b\x0e\xfb\x57\xd2\x8d\x97\x62\x2d\xbd\xe7\x25\xaf"}, + {{0x77,0xf8,0x86,0x91,0xc4,0xef,0xf2,0x3e,0xbb,0x73,0x64,0x94,0x70,0x92,0x95,0x1a,0x5f,0xf3,0xf1,0x07,0x85,0xb4,0x17,0xe9,0x18,0x82,0x3a,0x55,0x2d,0xab,0x7c,0x75,},{0x74,0xd2,0x91,0x27,0xf1,0x99,0xd8,0x6a,0x86,0x76,0xae,0xc3,0x3b,0x4c,0xe3,0xf2,0x25,0xcc,0xb1,0x91,0xf5,0x2c,0x19,0x1c,0xcd,0x1e,0x8c,0xca,0x65,0x21,0x3a,0x6b,},{0xfb,0xe9,0x29,0xd7,0x43,0xa0,0x3c,0x17,0x91,0x05,0x75,0x49,0x2f,0x30,0x92,0xee,0x2a,0x2b,0xf1,0x4a,0x60,0xa3,0xfc,0xac,0xec,0x74,0xa5,0x8c,0x73,0x34,0x51,0x0f,0xc2,0x62,0xdb,0x58,0x27,0x91,0x32,0x2d,0x6c,0x8c,0x41,0xf1,0x70,0x0a,0xdb,0x80,0x02,0x7e,0xca,0xbc,0x14,0x27,0x0b,0x70,0x34,0x44,0xae,0x3e,0xe7,0x62,0x3e,0x0a,},18,"\xbd\x8e\x05\x03\x3f\x3a\x8b\xcd\xcb\xf4\xbe\xce\xb7\x09\x01\xc8\x2e\x31"}, + {{0xab,0x6f,0x7a,0xee,0x6a,0x08,0x37,0xb3,0x34,0xba,0x5e,0xb1,0xb2,0xad,0x7f,0xce,0xcf,0xab,0x7e,0x32,0x3c,0xab,0x18,0x7f,0xe2,0xe0,0xa9,0x5d,0x80,0xef,0xf1,0x32,},{0x5b,0x96,0xdc,0xa4,0x97,0x87,0x5b,0xf9,0x66,0x4c,0x5e,0x75,0xfa,0xcf,0x3f,0x9b,0xc5,0x4b,0xae,0x91,0x3d,0x66,0xca,0x15,0xee,0x85,0xf1,0x49,0x1c,0xa2,0x4d,0x2c,},{0x73,0xbc,0xa6,0x4e,0x9d,0xd0,0xdb,0x88,0x13,0x8e,0xed,0xfa,0xfc,0xea,0x8f,0x54,0x36,0xcf,0xb7,0x4b,0xfb,0x0e,0x77,0x33,0xcf,0x34,0x9b,0xaa,0x0c,0x49,0x77,0x5c,0x56,0xd5,0x93,0x4e,0x1d,0x38,0xe3,0x6f,0x39,0xb7,0xc5,0xbe,0xb0,0xa8,0x36,0x51,0x0c,0x45,0x12,0x6f,0x8e,0xc4,0xb6,0x81,0x05,0x19,0x90,0x5b,0x0c,0xa0,0x7c,0x09,},19,"\x81\x71\x45\x6f\x8b\x90\x71\x89\xb1\xd7\x79\xe2\x6b\xc5\xaf\xbb\x08\xc6\x7a"}, + {{0x8d,0x13,0x5d,0xe7,0xc8,0x41,0x1b,0xbd,0xbd,0x1b,0x31,0xe5,0xdc,0x67,0x8f,0x2a,0xc7,0x10,0x9e,0x79,0x2b,0x60,0xf3,0x8c,0xd2,0x49,0x36,0xe8,0xa8,0x98,0xc3,0x2d,},{0x1c,0xa2,0x81,0x93,0x85,0x29,0x89,0x65,0x35,0xa7,0x71,0x4e,0x35,0x84,0x08,0x5b,0x86,0xef,0x9f,0xec,0x72,0x3f,0x42,0x81,0x9f,0xc8,0xdd,0x5d,0x8c,0x00,0x81,0x7f,},{0xa1,0xad,0xc2,0xbc,0x6a,0x2d,0x98,0x06,0x62,0x67,0x7e,0x7f,0xdf,0xf6,0x42,0x4d,0xe7,0xdb,0xa5,0x0f,0x57,0x95,0xca,0x90,0xfd,0xf3,0xe9,0x6e,0x25,0x6f,0x32,0x85,0xca,0xc7,0x1d,0x33,0x60,0x48,0x2e,0x99,0x3d,0x02,0x94,0xba,0x4e,0xc7,0x44,0x0c,0x61,0xaf,0xfd,0xf3,0x5f,0xe8,0x3e,0x6e,0x04,0x26,0x39,0x37,0xdb,0x93,0xf1,0x05,},20,"\x8b\xa6\xa4\xc9\xa1\x5a\x24\x4a\x9c\x26\xbb\x2a\x59\xb1\x02\x6f\x21\x34\x8b\x49"}, + {{0x0e,0x76,0x5d,0x72,0x0e,0x70,0x5f,0x93,0x66,0xc1,0xab,0x8c,0x3f,0xa8,0x4c,0x9a,0x44,0x37,0x0c,0x06,0x96,0x9f,0x80,0x32,0x96,0x88,0x4b,0x28,0x46,0xa6,0x52,0xa4,},{0x7f,0xae,0x45,0xdd,0x0a,0x05,0x97,0x10,0x26,0xd4,0x10,0xbc,0x49,0x7a,0xf5,0xbe,0x7d,0x08,0x27,0xa8,0x2a,0x14,0x5c,0x20,0x3f,0x62,0x5d,0xfc,0xb8,0xb0,0x3b,0xa8,},{0xbb,0x61,0xcf,0x84,0xde,0x61,0x86,0x22,0x07,0xc6,0xa4,0x55,0x25,0x8b,0xc4,0xdb,0x4e,0x15,0xee,0xa0,0x31,0x7f,0xf8,0x87,0x18,0xb8,0x82,0xa0,0x6b,0x5c,0xf6,0xec,0x6f,0xd2,0x0c,0x5a,0x26,0x9e,0x5d,0x5c,0x80,0x5b,0xaf,0xbc,0xc5,0x79,0xe2,0x59,0x0a,0xf4,0x14,0xc7,0xc2,0x27,0x27,0x3c,0x10,0x2a,0x10,0x07,0x0c,0xdf,0xe8,0x0f,},21,"\x1d\x56\x6a\x62\x32\xbb\xaa\xb3\xe6\xd8\x80\x4b\xb5\x18\xa4\x98\xed\x0f\x90\x49\x86"}, + {{0xdb,0x36,0xe3,0x26,0xd6,0x76,0xc2,0xd1,0x9c,0xc8,0xfe,0x0c,0x14,0xb7,0x09,0x20,0x2e,0xcf,0xc7,0x61,0xd2,0x70,0x89,0xeb,0x6e,0xa4,0xb1,0xbb,0x02,0x1e,0xcf,0xa7,},{0x48,0x35,0x9b,0x85,0x0d,0x23,0xf0,0x71,0x5d,0x94,0xbb,0x8b,0xb7,0x5e,0x7e,0x14,0x32,0x2e,0xaf,0x14,0xf0,0x6f,0x28,0xa8,0x05,0x40,0x3f,0xbd,0xa0,0x02,0xfc,0x85,},{0xb6,0xdc,0xd0,0x99,0x89,0xdf,0xba,0xc5,0x43,0x22,0xa3,0xce,0x87,0x87,0x6e,0x1d,0x62,0x13,0x4d,0xa9,0x98,0xc7,0x9d,0x24,0xb5,0x0b,0xd7,0xa6,0xa7,0x97,0xd8,0x6a,0x0e,0x14,0xdc,0x9d,0x74,0x91,0xd6,0xc1,0x4a,0x67,0x3c,0x65,0x2c,0xfb,0xec,0x9f,0x96,0x2a,0x38,0xc9,0x45,0xda,0x3b,0x2f,0x08,0x79,0xd0,0xb6,0x8a,0x92,0x13,0x00,},22,"\x1b\x0a\xfb\x0a\xc4\xba\x9a\xb7\xb7\x17\x2c\xdd\xc9\xeb\x42\xbb\xa1\xa6\x4b\xce\x47\xd4"}, + {{0xc8,0x99,0x55,0xe0,0xf7,0x74,0x1d,0x90,0x5d,0xf0,0x73,0x0b,0x3d,0xc2,0xb0,0xce,0x1a,0x13,0x13,0x4e,0x44,0xfe,0xf3,0xd4,0x0d,0x60,0xc0,0x20,0xef,0x19,0xdf,0x77,},{0xfd,0xb3,0x06,0x73,0x40,0x2f,0xaf,0x1c,0x80,0x33,0x71,0x4f,0x35,0x17,0xe4,0x7c,0xc0,0xf9,0x1f,0xe7,0x0c,0xf3,0x83,0x6d,0x6c,0x23,0x63,0x6e,0x3f,0xd2,0x28,0x7c,},{0x7e,0xf6,0x6e,0x5e,0x86,0xf2,0x36,0x08,0x48,0xe0,0x01,0x4e,0x94,0x88,0x0a,0xe2,0x92,0x0a,0xd8,0xa3,0x18,0x5a,0x46,0xb3,0x5d,0x1e,0x07,0xde,0xa8,0xfa,0x8a,0xe4,0xf6,0xb8,0x43,0xba,0x17,0x4d,0x99,0xfa,0x79,0x86,0x65,0x4a,0x08,0x91,0xc1,0x2a,0x79,0x44,0x55,0x66,0x93,0x75,0xbf,0x92,0xaf,0x4c,0xc2,0x77,0x0b,0x57,0x9e,0x0c,},23,"\x50\x7c\x94\xc8\x82\x0d\x2a\x57\x93\xcb\xf3\x44\x2b\x3d\x71\x93\x6f\x35\xfe\x3a\xfe\xf3\x16"}, + {{0x4e,0x62,0x62,0x7f,0xc2,0x21,0x14,0x24,0x78,0xae,0xe7,0xf0,0x07,0x81,0xf8,0x17,0xf6,0x62,0xe3,0xb7,0x5d,0xb2,0x9b,0xb1,0x4a,0xb4,0x7c,0xf8,0xe8,0x41,0x04,0xd6,},{0xb1,0xd3,0x98,0x01,0x89,0x20,0x27,0xd5,0x8a,0x8c,0x64,0x33,0x51,0x63,0x19,0x58,0x93,0xbf,0xc1,0xb6,0x1d,0xbe,0xca,0x32,0x60,0x49,0x7e,0x1f,0x30,0x37,0x11,0x07,},{0x83,0x6a,0xfa,0x76,0x4d,0x9c,0x48,0xaa,0x47,0x70,0xa4,0x38,0x8b,0x65,0x4e,0x97,0xb3,0xc1,0x6f,0x08,0x29,0x67,0xfe,0xbc,0xa2,0x7f,0x2f,0xc4,0x7d,0xdf,0xd9,0x24,0x4b,0x03,0xcf,0xc7,0x29,0x69,0x8a,0xcf,0x51,0x09,0x70,0x43,0x46,0xb6,0x0b,0x23,0x0f,0x25,0x54,0x30,0x08,0x9d,0xdc,0x56,0x91,0x23,0x99,0xd1,0x12,0x2d,0xe7,0x0a,},24,"\xd3\xd6\x15\xa8\x47\x2d\x99\x62\xbb\x70\xc5\xb5\x46\x6a\x3d\x98\x3a\x48\x11\x04\x6e\x2a\x0e\xf5"}, + {{0x6b,0x83,0xd7,0xda,0x89,0x08,0xc3,0xe7,0x20,0x5b,0x39,0x86,0x4b,0x56,0xe5,0xf3,0xe1,0x71,0x96,0xa3,0xfc,0x9c,0x2f,0x58,0x05,0xaa,0xd0,0xf5,0x55,0x4c,0x14,0x2d,},{0xd0,0xc8,0x46,0xf9,0x7f,0xe2,0x85,0x85,0xc0,0xee,0x15,0x90,0x15,0xd6,0x4c,0x56,0x31,0x1c,0x88,0x6e,0xdd,0xcc,0x18,0x5d,0x29,0x6d,0xbb,0x16,0x5d,0x26,0x25,0xd6,},{0x16,0xe4,0x62,0xa2,0x9a,0x6d,0xd4,0x98,0x68,0x5a,0x37,0x18,0xb3,0xee,0xd0,0x0c,0xc1,0x59,0x86,0x01,0xee,0x47,0x82,0x04,0x86,0x03,0x2d,0x6b,0x9a,0xcc,0x9b,0xf8,0x9f,0x57,0x68,0x4e,0x08,0xd8,0xc0,0xf0,0x55,0x89,0xcd,0xa2,0x88,0x2a,0x05,0xdc,0x4c,0x63,0xf9,0xd0,0x43,0x1d,0x65,0x52,0x71,0x08,0x12,0x43,0x30,0x03,0xbc,0x08,},25,"\x6a\xda\x80\xb6\xfa\x84\xf7\x03\x49\x20\x78\x9e\x85\x36\xb8\x2d\x5e\x46\x78\x05\x9a\xed\x27\xf7\x1c"}, + {{0x19,0xa9,0x1f,0xe2,0x3a,0x4e,0x9e,0x33,0xec,0xc4,0x74,0x87,0x8f,0x57,0xc6,0x4c,0xf1,0x54,0xb3,0x94,0x20,0x34,0x87,0xa7,0x03,0x5e,0x1a,0xd9,0xcd,0x69,0x7b,0x0d,},{0x2b,0xf3,0x2b,0xa1,0x42,0xba,0x46,0x22,0xd8,0xf3,0xe2,0x9e,0xcd,0x85,0xee,0xa0,0x7b,0x9c,0x47,0xbe,0x9d,0x64,0x41,0x2c,0x9b,0x51,0x0b,0x27,0xdd,0x21,0x8b,0x23,},{0x88,0x1f,0x5b,0x8c,0x5a,0x03,0x0d,0xf0,0xf7,0x5b,0x66,0x34,0xb0,0x70,0xdd,0x27,0xbd,0x1e,0xe3,0xc0,0x87,0x38,0xae,0x34,0x93,0x38,0xb3,0xee,0x64,0x69,0xbb,0xf9,0x76,0x0b,0x13,0x57,0x8a,0x23,0x7d,0x51,0x82,0x53,0x5e,0xde,0x12,0x12,0x83,0x02,0x7a,0x90,0xb5,0xf8,0x65,0xd6,0x3a,0x65,0x37,0xdc,0xa0,0x7b,0x44,0x04,0x9a,0x0f,},26,"\x82\xcb\x53\xc4\xd5\xa0\x13\xba\xe5\x07\x07\x59\xec\x06\xc3\xc6\x95\x5a\xb7\xa4\x05\x09\x58\xec\x32\x8c"}, + {{0x1d,0x5b,0x8c,0xb6,0x21,0x5c,0x18,0x14,0x16,0x66,0xba,0xee,0xfc,0xf5,0xd6,0x9d,0xad,0x5b,0xea,0x9a,0x34,0x93,0xdd,0xda,0xa3,0x57,0xa4,0x39,0x7a,0x13,0xd4,0xde,},{0x94,0xd2,0x3d,0x97,0x7c,0x33,0xe4,0x9e,0x5e,0x49,0x92,0xc6,0x8f,0x25,0xec,0x99,0xa2,0x7c,0x41,0xce,0x6b,0x91,0xf2,0xbf,0xa0,0xcd,0x82,0x92,0xfe,0x96,0x28,0x35,},{0x3a,0xcd,0x39,0xbe,0xc8,0xc3,0xcd,0x2b,0x44,0x29,0x97,0x22,0xb5,0x85,0x0a,0x04,0x00,0xc1,0x44,0x35,0x90,0xfd,0x48,0x61,0xd5,0x9a,0xae,0x74,0x96,0xac,0xb3,0xdf,0x73,0xfc,0x3f,0xdf,0x79,0x69,0xae,0x5f,0x50,0xba,0x47,0xdd,0xdc,0x43,0x52,0x46,0xe5,0xfd,0x37,0x6f,0x6b,0x89,0x1c,0xd4,0xc2,0xca,0xf5,0xd6,0x14,0xb6,0x17,0x0c,},27,"\xa9\xa8\xcb\xb0\xad\x58\x51\x24\xe5\x22\xab\xbf\xb4\x05\x33\xbd\xd6\xf4\x93\x47\xb5\x5b\x18\xe8\x55\x8c\xb0"}, + {{0x6a,0x91,0xb3,0x22,0x7c,0x47,0x22,0x99,0x08,0x9b,0xdc,0xe9,0x35,0x6e,0x72,0x6a,0x40,0xef,0xd8,0x40,0xf1,0x10,0x02,0x70,0x8b,0x7e,0xe5,0x5b,0x64,0x10,0x5a,0xc2,},{0x9d,0x08,0x4a,0xa8,0xb9,0x7a,0x6b,0x9b,0xaf,0xa4,0x96,0xdb,0xc6,0xf7,0x6f,0x33,0x06,0xa1,0x16,0xc9,0xd9,0x17,0xe6,0x81,0x52,0x0a,0x0f,0x91,0x43,0x69,0x42,0x7e,},{0xf5,0x87,0x54,0x23,0x78,0x1b,0x66,0x21,0x6c,0xb5,0xe8,0x99,0x8d,0xe5,0xd9,0xff,0xc2,0x9d,0x1d,0x67,0x10,0x70,0x54,0xac,0xe3,0x37,0x45,0x03,0xa9,0xc3,0xef,0x81,0x15,0x77,0xf2,0x69,0xde,0x81,0x29,0x67,0x44,0xbd,0x70,0x6f,0x1a,0xc4,0x78,0xca,0xf0,0x9b,0x54,0xcd,0xf8,0x71,0xb3,0xf8,0x02,0xbd,0x57,0xf9,0xa6,0xcb,0x91,0x01,},28,"\x5c\xb6\xf9\xaa\x59\xb8\x0e\xca\x14\xf6\xa6\x8f\xb4\x0c\xf0\x7b\x79\x4e\x75\x17\x1f\xba\x96\x26\x2c\x1c\x6a\xdc"}, + {{0x93,0xea,0xa8,0x54,0xd7,0x91,0xf0,0x53,0x72,0xce,0x72,0xb9,0x4f,0xc6,0x50,0x3b,0x2f,0xf8,0xae,0x68,0x19,0xe6,0xa2,0x1a,0xfe,0x82,0x5e,0x27,0xad,0xa9,0xe4,0xfb,},{0x16,0xce,0xe8,0xa3,0xf2,0x63,0x18,0x34,0xc8,0x8b,0x67,0x08,0x97,0xff,0x0b,0x08,0xce,0x90,0xcc,0x14,0x7b,0x45,0x93,0xb3,0xf1,0xf4,0x03,0x72,0x7f,0x7e,0x7a,0xd5,},{0xd8,0x34,0x19,0x7c,0x1a,0x30,0x80,0x61,0x4e,0x0a,0x5f,0xa0,0xaa,0xaa,0x80,0x88,0x24,0xf2,0x1c,0x38,0xd6,0x92,0xe6,0xff,0xbd,0x20,0x0f,0x7d,0xfb,0x3c,0x8f,0x44,0x40,0x2a,0x73,0x82,0x18,0x0b,0x98,0xad,0x0a,0xfc,0x8e,0xec,0x1a,0x02,0xac,0xec,0xf3,0xcb,0x7f,0xde,0x62,0x7b,0x9f,0x18,0x11,0x1f,0x26,0x0a,0xb1,0xdb,0x9a,0x07,},29,"\x32\xfe\x27\x99\x41\x24\x20\x21\x53\xb5\xc7\x0d\x38\x13\xfd\xee\x9c\x2a\xa6\xe7\xdc\x74\x3d\x4d\x53\x5f\x18\x40\xa5"}, + {{0x94,0x1c,0xac,0x69,0xfb,0x7b,0x18,0x15,0xc5,0x7b,0xb9,0x87,0xc4,0xd6,0xc2,0xad,0x2c,0x35,0xd5,0xf9,0xa3,0x18,0x2a,0x79,0xd4,0xba,0x13,0xea,0xb2,0x53,0xa8,0xad,},{0x23,0xbe,0x32,0x3c,0x56,0x2d,0xfd,0x71,0xce,0x65,0xf5,0xbb,0xa5,0x6a,0x74,0xa3,0xa6,0xdf,0xc3,0x6b,0x57,0x3d,0x2f,0x94,0xf6,0x35,0xc7,0xf9,0xb4,0xfd,0x5a,0x5b,},{0x0f,0x8f,0xad,0x1e,0x6b,0xde,0x77,0x1b,0x4f,0x54,0x20,0xea,0xc7,0x5c,0x37,0x8b,0xae,0x6d,0xb5,0xac,0x66,0x50,0xcd,0x2b,0xc2,0x10,0xc1,0x82,0x3b,0x43,0x2b,0x48,0xe0,0x16,0xb1,0x05,0x95,0x45,0x8f,0xfa,0xb9,0x2f,0x7a,0x89,0x89,0xb2,0x93,0xce,0xb8,0xdf,0xed,0x6c,0x24,0x3a,0x20,0x38,0xfc,0x06,0x65,0x2a,0xaa,0xf1,0x6f,0x02,},30,"\xbb\x31\x72\x79\x57\x10\xfe\x00\x05\x4d\x3b\x5d\xfe\xf8\xa1\x16\x23\x58\x2d\xa6\x8b\xf8\xe4\x6d\x72\xd2\x7c\xec\xe2\xaa"}, + {{0x1a,0xcd,0xbb,0x79,0x3b,0x03,0x84,0x93,0x46,0x27,0x47,0x0d,0x79,0x5c,0x3d,0x1d,0xd4,0xd7,0x9c,0xea,0x59,0xef,0x98,0x3f,0x29,0x5b,0x9b,0x59,0x17,0x9c,0xbb,0x28,},{0x3f,0x60,0xc7,0x54,0x1a,0xfa,0x76,0xc0,0x19,0xcf,0x5a,0xa8,0x2d,0xcd,0xb0,0x88,0xed,0x9e,0x4e,0xd9,0x78,0x05,0x14,0xae,0xfb,0x37,0x9d,0xab,0xc8,0x44,0xf3,0x1a,},{0xbe,0x71,0xef,0x48,0x06,0xcb,0x04,0x1d,0x88,0x5e,0xff,0xd9,0xe6,0xb0,0xfb,0xb7,0x3d,0x65,0xd7,0xcd,0xec,0x47,0xa8,0x9c,0x8a,0x99,0x48,0x92,0xf4,0xe5,0x5a,0x56,0x8c,0x4c,0xc7,0x8d,0x61,0xf9,0x01,0xe8,0x0d,0xbb,0x62,0x8b,0x86,0xa2,0x3c,0xcd,0x59,0x4e,0x71,0x2b,0x57,0xfa,0x94,0xc2,0xd6,0x7e,0xc2,0x66,0x34,0x87,0x85,0x07,},31,"\x7c\xf3\x4f\x75\xc3\xda\xc9\xa8\x04\xd0\xfc\xd0\x9e\xba\x9b\x29\xc9\x48\x4e\x8a\x01\x8f\xa9\xe0\x73\x04\x2d\xf8\x8e\x3c\x56"}, + {{0x8e,0xd7,0xa7,0x97,0xb9,0xce,0xa8,0xa8,0x37,0x0d,0x41,0x91,0x36,0xbc,0xdf,0x68,0x3b,0x75,0x9d,0x2e,0x3c,0x69,0x47,0xf1,0x7e,0x13,0xe2,0x48,0x5a,0xa9,0xd4,0x20,},{0xb4,0x9f,0x3a,0x78,0xb1,0xc6,0xa7,0xfc,0xa8,0xf3,0x46,0x6f,0x33,0xbc,0x0e,0x92,0x9f,0x01,0xfb,0xa0,0x43,0x06,0xc2,0xa7,0x46,0x5f,0x46,0xc3,0x75,0x93,0x16,0xd9,},{0x04,0x26,0x6c,0x03,0x3b,0x91,0xc1,0x32,0x2c,0xeb,0x34,0x46,0xc9,0x01,0xff,0xcf,0x3c,0xc4,0x0c,0x40,0x34,0xe8,0x87,0xc9,0x59,0x7c,0xa1,0x89,0x3b,0xa7,0x33,0x0b,0xec,0xbb,0xd8,0xb4,0x81,0x42,0xef,0x35,0xc0,0x12,0xc6,0xba,0x51,0xa6,0x6d,0xf9,0x30,0x8c,0xb6,0x26,0x8a,0xd6,0xb1,0xe4,0xb0,0x3e,0x70,0x10,0x24,0x95,0x79,0x0b,},32,"\xa7\x50\xc2\x32\x93\x3d\xc1\x4b\x11\x84\xd8\x6d\x8b\x4c\xe7\x2e\x16\xd6\x97\x44\xba\x69\x81\x8b\x6a\xc3\x3b\x1d\x82\x3b\xb2\xc3"}, + {{0xf2,0xab,0x39,0x6f,0xe8,0x90,0x6e,0x3e,0x56,0x33,0xe9,0x9c,0xab,0xcd,0x5b,0x09,0xdf,0x08,0x59,0xb5,0x16,0x23,0x0b,0x1e,0x04,0x50,0xb5,0x80,0xb6,0x5f,0x61,0x6c,},{0x8e,0xa0,0x74,0x24,0x51,0x59,0xa1,0x16,0xaa,0x71,0x22,0xa2,0x5e,0xc1,0x6b,0x89,0x1d,0x62,0x5a,0x68,0xf3,0x36,0x60,0x42,0x39,0x08,0xf6,0xbd,0xc4,0x4f,0x8c,0x1b,},{0xa0,0x6a,0x23,0xd9,0x82,0xd8,0x1a,0xb8,0x83,0xaa,0xe2,0x30,0xad,0xbc,0x36,0x8a,0x6a,0x99,0x77,0xf0,0x03,0xce,0xbb,0x00,0xd4,0xc2,0xe4,0x01,0x84,0x90,0x19,0x1a,0x84,0xd3,0xa2,0x82,0xfd,0xbf,0xb2,0xfc,0x88,0x04,0x6e,0x62,0xde,0x43,0xe1,0x5f,0xb5,0x75,0x33,0x6b,0x3c,0x8b,0x77,0xd1,0x9c,0xe6,0xa0,0x09,0xce,0x51,0xf5,0x0c,},33,"\x5a\x44\xe3\x4b\x74\x6c\x5f\xd1\x89\x8d\x55\x2a\xb3\x54\xd2\x8f\xb4\x71\x38\x56\xd7\x69\x7d\xd6\x3e\xb9\xbd\x6b\x99\xc2\x80\xe1\x87"}, + {{0x55,0x0a,0x41,0xc0,0x13,0xf7,0x9b,0xab,0x8f,0x06,0xe4,0x3a,0xd1,0x83,0x6d,0x51,0x31,0x27,0x36,0xa9,0x71,0x38,0x06,0xfa,0xfe,0x66,0x45,0x21,0x9e,0xaa,0x1f,0x9d,},{0xaf,0x6b,0x71,0x45,0x47,0x4d,0xc9,0x95,0x4b,0x9a,0xf9,0x3a,0x9c,0xdb,0x34,0x44,0x9d,0x5b,0x7c,0x65,0x1c,0x82,0x4d,0x24,0xe2,0x30,0xb9,0x00,0x33,0xce,0x59,0xc0,},{0x16,0xdc,0x1e,0x2b,0x9f,0xa9,0x09,0xee,0xfd,0xc2,0x77,0xba,0x16,0xeb,0xe2,0x07,0xb8,0xda,0x5e,0x91,0x14,0x3c,0xde,0x78,0xc5,0x04,0x7a,0x89,0xf6,0x81,0xc3,0x3c,0x4e,0x4e,0x34,0x28,0xd5,0xc9,0x28,0x09,0x59,0x03,0xa8,0x11,0xec,0x00,0x2d,0x52,0xa3,0x9e,0xd7,0xf8,0xb3,0xfe,0x19,0x27,0x20,0x0c,0x6d,0xd0,0xb9,0xab,0x3e,0x04,},34,"\x8b\xc4\x18\x5e\x50\xe5\x7d\x5f\x87\xf4\x75\x15\xfe\x2b\x18\x37\xd5\x85\xf0\xaa\xe9\xe1\xca\x38\x3b\x3e\xc9\x08\x88\x4b\xb9\x00\xff\x27"}, + {{0x19,0xac,0x3e,0x27,0x24,0x38,0xc7,0x2d,0xdf,0x7b,0x88,0x19,0x64,0x86,0x7c,0xb3,0xb3,0x1f,0xf4,0xc7,0x93,0xbb,0x7e,0xa1,0x54,0x61,0x3c,0x1d,0xb0,0x68,0xcb,0x7e,},{0xf8,0x5b,0x80,0xe0,0x50,0xa1,0xb9,0x62,0x0d,0xb1,0x38,0xbf,0xc9,0xe1,0x00,0x32,0x7e,0x25,0xc2,0x57,0xc5,0x92,0x17,0xb6,0x01,0xf1,0xf6,0xac,0x9a,0x41,0x3d,0x3f,},{0xea,0x85,0x5d,0x78,0x1c,0xbe,0xa4,0x68,0x2e,0x35,0x01,0x73,0xcb,0x89,0xe8,0x61,0x9c,0xcf,0xdd,0xb9,0x7c,0xdc,0xe1,0x6f,0x9a,0x2f,0x6f,0x68,0x92,0xf4,0x6d,0xbe,0x68,0xe0,0x4b,0x12,0xb8,0xd8,0x86,0x89,0xa7,0xa3,0x16,0x70,0xcd,0xff,0x40,0x9a,0xf9,0x8a,0x93,0xb4,0x9a,0x34,0x53,0x7b,0x6a,0xa0,0x09,0xd2,0xeb,0x8b,0x47,0x01,},35,"\x95\x87\x2d\x5f\x78\x9f\x95\x48\x4e\x30\xcb\xb0\xe1\x14\x02\x89\x53\xb1\x6f\x5c\x6a\x8d\x9f\x65\xc0\x03\xa8\x35\x43\xbe\xaa\x46\xb3\x86\x45"}, + {{0xca,0x26,0x7d,0xe9,0x6c,0x93,0xc2,0x38,0xfa,0xfb,0x12,0x79,0x81,0x20,0x59,0xab,0x93,0xac,0x03,0x05,0x96,0x57,0xfd,0x99,0x4f,0x8f,0xa5,0xa0,0x92,0x39,0xc8,0x21,},{0x01,0x73,0x70,0xc8,0x79,0x09,0x0a,0x81,0xc7,0xf2,0x72,0xc2,0xfc,0x80,0xe3,0xaa,0xc2,0xbc,0x60,0x3f,0xcb,0x37,0x9a,0xfc,0x98,0x69,0x11,0x60,0xab,0x74,0x5b,0x26,},{0xac,0x95,0x7f,0x82,0x33,0x5a,0xa7,0x14,0x1e,0x96,0xb5,0x9d,0x63,0xe3,0xcc,0xee,0x95,0xc3,0xa2,0xc4,0x7d,0x02,0x65,0x40,0xc2,0xaf,0x42,0xdc,0x95,0x33,0xd5,0xfd,0x81,0x82,0x7d,0x16,0x79,0xad,0x18,0x7a,0xea,0xf3,0x78,0x34,0x91,0x5e,0x75,0xb1,0x47,0xa9,0x28,0x68,0x06,0xc8,0x01,0x75,0x16,0xba,0x43,0xdd,0x05,0x1a,0x5e,0x0c,},36,"\xe0\x5f\x71\xe4\xe4\x9a\x72\xec\x55\x0c\x44\xa3\xb8\x5a\xca\x8f\x20\xff\x26\xc3\xee\x94\xa8\x0f\x1b\x43\x1c\x7d\x15\x4e\xc9\x60\x3e\xe0\x25\x31"}, + {{0x3d,0xff,0x5e,0x89,0x94,0x75,0xe7,0xe9,0x1d,0xd2,0x61,0x32,0x2f,0xab,0x09,0x98,0x0c,0x52,0x97,0x0d,0xe1,0xda,0x6e,0x2e,0x20,0x16,0x60,0xcc,0x4f,0xce,0x70,0x32,},{0xf3,0x01,0x62,0xba,0xc9,0x84,0x47,0xc4,0x04,0x2f,0xac,0x05,0xda,0x44,0x80,0x34,0x62,0x9b,0xe2,0xc6,0xa5,0x8d,0x30,0xdf,0xd5,0x78,0xba,0x9f,0xb5,0xe3,0x93,0x0b,},{0x5e,0xfe,0x7a,0x92,0xff,0x96,0x23,0x08,0x9b,0x3e,0x3b,0x78,0xf3,0x52,0x11,0x53,0x66,0xe2,0x6b,0xa3,0xfb,0x1a,0x41,0x62,0x09,0xbc,0x02,0x9e,0x9c,0xad,0xcc,0xd9,0xf4,0xaf,0xfa,0x33,0x35,0x55,0xa8,0xf3,0xa3,0x5a,0x9d,0x0f,0x7c,0x34,0xb2,0x92,0xca,0xe7,0x7e,0xc9,0x6f,0xa3,0xad,0xfc,0xaa,0xde,0xe2,0xd9,0xce,0xd8,0xf8,0x05,},37,"\x93\x8f\x0e\x77\x62\x1b\xf3\xea\x52\xc7\xc4\x91\x1c\x51\x57\xc2\xd8\xa2\xa8\x58\x09\x3e\xf1\x6a\xa9\xb1\x07\xe6\x9d\x98\x03\x7b\xa1\x39\xa3\xc3\x82"}, + {{0x9a,0x6b,0x84,0x78,0x64,0xe7,0x0c,0xfe,0x8b,0xa6,0xab,0x22,0xfa,0x0c,0xa3,0x08,0xc0,0xcc,0x8b,0xec,0x71,0x41,0xfb,0xca,0xa3,0xb8,0x1f,0x5d,0x1e,0x1c,0xfc,0xfc,},{0x34,0xad,0x0f,0xbd,0xb2,0x56,0x65,0x07,0xa8,0x1c,0x2b,0x1f,0x8a,0xa8,0xf5,0x3d,0xcc,0xaa,0x64,0xcc,0x87,0xad,0xa9,0x1b,0x90,0x3e,0x90,0x0d,0x07,0xee,0xe9,0x30,},{0x2a,0xb2,0x55,0x16,0x9c,0x48,0x9c,0x54,0xc7,0x32,0x23,0x2e,0x37,0xc8,0x73,0x49,0xd4,0x86,0xb1,0xeb,0xa2,0x05,0x09,0xdb,0xab,0xe7,0xfe,0xd3,0x29,0xef,0x08,0xfd,0x75,0xba,0x1c,0xd1,0x45,0xe6,0x7b,0x2e,0xa2,0x6c,0xb5,0xcc,0x51,0xca,0xb3,0x43,0xee,0xb0,0x85,0xfe,0x1f,0xd7,0xb0,0xec,0x4c,0x6a,0xfc,0xd9,0xb9,0x79,0xf9,0x05,},38,"\x83\x83\x67\x47\x11\x83\xc7\x1f\x7e\x71\x77\x24\xf8\x9d\x40\x1c\x3a\xd9\x86\x3f\xd9\xcc\x7a\xa3\xcf\x33\xd3\xc5\x29\x86\x0c\xb5\x81\xf3\x09\x3d\x87\xda"}, + {{0x57,0x5b,0xe0,0x7a,0xfc,0xa5,0xd0,0x63,0xc2,0x38,0xcd,0x9b,0x80,0x28,0x77,0x2c,0xc4,0x9c,0xda,0x34,0x47,0x14,0x32,0xa2,0xe1,0x66,0xe0,0x96,0xe2,0x21,0x9e,0xfc,},{0x94,0xe5,0xeb,0x4d,0x50,0x24,0xf4,0x9d,0x7e,0xbf,0x79,0x81,0x7c,0x8d,0xe1,0x14,0x97,0xdc,0x2b,0x55,0x62,0x2a,0x51,0xae,0x12,0x3f,0xfc,0x74,0x9d,0xbb,0x16,0xe0,},{0x58,0x27,0x1d,0x44,0x23,0x6f,0x3b,0x98,0xc5,0x8f,0xd7,0xae,0x0d,0x2f,0x49,0xef,0x2b,0x6e,0x3a,0xff,0xdb,0x22,0x5a,0xa3,0xba,0x55,0x5f,0x0e,0x11,0xcc,0x53,0xc2,0x3a,0xd1,0x9b,0xaf,0x24,0x34,0x65,0x90,0xd0,0x5d,0x7d,0x53,0x90,0x58,0x20,0x82,0xcf,0x94,0xd3,0x9c,0xad,0x65,0x30,0xab,0x93,0xd1,0x3e,0xfb,0x39,0x27,0x95,0x06,},39,"\x33\xe5\x91\x8b\x66\xd3\x3d\x55\xfe\x71\x7c\xa3\x43\x83\xea\xe7\x8f\x0a\xf8\x28\x89\xca\xf6\x69\x6e\x1a\xc9\xd9\x5d\x1f\xfb\x32\xcb\xa7\x55\xf9\xe3\x50\x3e"}, + {{0x15,0xff,0xb4,0x55,0x14,0xd4,0x34,0x44,0xd6,0x1f,0xcb,0x10,0x5e,0x30,0xe1,0x35,0xfd,0x26,0x85,0x23,0xdd,0xa2,0x0b,0x82,0x75,0x8b,0x17,0x94,0x23,0x11,0x04,0x41,},{0x17,0x72,0xc5,0xab,0xc2,0xd2,0x3f,0xd2,0xf9,0xd1,0xc3,0x25,0x7b,0xe7,0xbc,0x3c,0x1c,0xd7,0x9c,0xee,0x40,0x84,0x4b,0x74,0x9b,0x3a,0x77,0x43,0xd2,0xf9,0x64,0xb8,},{0x68,0x28,0xcd,0x76,0x24,0xe7,0x93,0xb8,0xa4,0xce,0xb9,0x6d,0x3c,0x2a,0x97,0x5b,0xf7,0x73,0xe5,0xff,0x66,0x45,0xf3,0x53,0x61,0x40,0x58,0x62,0x1e,0x58,0x83,0x52,0x89,0xe7,0xf3,0x1f,0x42,0xdf,0xe6,0xaf,0x6d,0x73,0x6f,0x26,0x44,0x51,0x1e,0x32,0x0c,0x0f,0xa6,0x98,0x58,0x2a,0x79,0x77,0x8d,0x18,0x73,0x0e,0xd3,0xe8,0xcb,0x08,},40,"\xda\x9c\x55\x59\xd0\xea\x51\xd2\x55\xb6\xbd\x9d\x76\x38\xb8\x76\x47\x2f\x94\x2b\x33\x0f\xc0\xe2\xb3\x0a\xea\x68\xd7\x73\x68\xfc\xe4\x94\x82\x72\x99\x1d\x25\x7e"}, + {{0xfe,0x05,0x68,0x64,0x29,0x43,0xb2,0xe1,0xaf,0xbf,0xd1,0xf1,0x0f,0xe8,0xdf,0x87,0xa4,0x23,0x6b,0xea,0x40,0xdc,0xe7,0x42,0x07,0x2c,0xb2,0x18,0x86,0xee,0xc1,0xfa,},{0x29,0x9e,0xbd,0x1f,0x13,0x17,0x7d,0xbd,0xb6,0x6a,0x91,0x2b,0xbf,0x71,0x20,0x38,0xfd,0xf7,0x3b,0x06,0xc3,0xac,0x02,0x0c,0x7b,0x19,0x12,0x67,0x55,0xd4,0x7f,0x61,},{0xd5,0x9e,0x6d,0xfc,0xc6,0xd7,0xe3,0xe2,0xc5,0x8d,0xec,0x81,0xe9,0x85,0xd2,0x45,0xe6,0x81,0xac,0xf6,0x59,0x4a,0x23,0xc5,0x92,0x14,0xf7,0xbe,0xd8,0x01,0x5d,0x81,0x3c,0x76,0x82,0xb6,0x0b,0x35,0x83,0x44,0x03,0x11,0xe7,0x2a,0x86,0x65,0xba,0x2c,0x96,0xde,0xc2,0x3c,0xe8,0x26,0xe1,0x60,0x12,0x7e,0x18,0x13,0x2b,0x03,0x04,0x04,},41,"\xc5\x9d\x08\x62\xec\x1c\x97\x46\xab\xcc\x3c\xf8\x3c\x9e\xeb\xa2\xc7\x08\x2a\x03\x6a\x8c\xb5\x7c\xe4\x87\xe7\x63\x49\x27\x96\xd4\x7e\x6e\x06\x3a\x0c\x1f\xec\xcc\x2d"}, + {{0x5e,0xcb,0x16,0xc2,0xdf,0x27,0xc8,0xcf,0x58,0xe4,0x36,0xa9,0xd3,0xaf,0xfb,0xd5,0x8e,0x95,0x38,0xa9,0x26,0x59,0xa0,0xf9,0x7c,0x4c,0x4f,0x99,0x46,0x35,0xa8,0xca,},{0xda,0x76,0x8b,0x20,0xc4,0x37,0xdd,0x3a,0xa5,0xf8,0x4b,0xb6,0xa0,0x77,0xff,0xa3,0x4a,0xb6,0x85,0x01,0xc5,0x35,0x2b,0x5c,0xc3,0xfd,0xce,0x7f,0xe6,0xc2,0x39,0x8d,},{0x1c,0x72,0x3a,0x20,0xc6,0x77,0x24,0x26,0xa6,0x70,0xe4,0xd5,0xc4,0xa9,0x7c,0x6e,0xbe,0x91,0x47,0xf7,0x1b,0xb0,0xa4,0x15,0x63,0x1e,0x44,0x40,0x6e,0x29,0x03,0x22,0xe4,0xca,0x97,0x7d,0x34,0x8f,0xe7,0x85,0x6a,0x8e,0xdc,0x23,0x5d,0x0f,0xe9,0x5f,0x7e,0xd9,0x1a,0xef,0xdd,0xf2,0x8a,0x77,0xe2,0xc7,0xdb,0xfd,0x8f,0x55,0x2f,0x0a,},42,"\x56\xf1\x32\x9d\x9a\x6b\xe2\x5a\x61\x59\xc7\x2f\x12\x68\x8d\xc8\x31\x4e\x85\xdd\x9e\x7e\x4d\xc0\x5b\xbe\xcb\x77\x29\xe0\x23\xc8\x6f\x8e\x09\x37\x35\x3f\x27\xc7\xed\xe9"}, + {{0xd5,0x99,0xd6,0x37,0xb3,0xc3,0x0a,0x82,0xa9,0x98,0x4e,0x2f,0x75,0x84,0x97,0xd1,0x44,0xde,0x6f,0x06,0xb9,0xfb,0xa0,0x4d,0xd4,0x0f,0xd9,0x49,0x03,0x9d,0x7c,0x84,},{0x67,0x91,0xd8,0xce,0x50,0xa4,0x46,0x89,0xfc,0x17,0x87,0x27,0xc5,0xc3,0xa1,0xc9,0x59,0xfb,0xee,0xd7,0x4e,0xf7,0xd8,0xe7,0xbd,0x3c,0x1a,0xb4,0xda,0x31,0xc5,0x1f,},{0xeb,0xf1,0x0d,0x9a,0xc7,0xc9,0x61,0x08,0x14,0x0e,0x7d,0xef,0x6f,0xe9,0x53,0x3d,0x72,0x76,0x46,0xff,0x5b,0x3a,0xf2,0x73,0xc1,0xdf,0x95,0x76,0x2a,0x66,0xf3,0x2b,0x65,0xa0,0x96,0x34,0xd0,0x13,0xf5,0x4b,0x5d,0xd6,0x01,0x1f,0x91,0xbc,0x33,0x6c,0xa8,0xb3,0x55,0xce,0x33,0xf8,0xcf,0xbe,0xc2,0x53,0x5a,0x4c,0x42,0x7f,0x82,0x05,},43,"\xa7\xc0\x4e\x8b\xa7\x5d\x0a\x03\xd8\xb1\x66\xad\x7a\x1d\x77\xe1\xb9\x1c\x7a\xaf\x7b\xef\xdd\x99\x31\x1f\xc3\xc5\x4a\x68\x4d\xdd\x97\x1d\x5b\x32\x11\xc3\xee\xaf\xf1\xe5\x4e"}, + {{0x30,0xab,0x82,0x32,0xfa,0x70,0x18,0xf0,0xce,0x6c,0x39,0xbd,0x8f,0x78,0x2f,0xe2,0xe1,0x59,0x75,0x8b,0xb0,0xf2,0xf4,0x38,0x6c,0x7f,0x28,0xcf,0xd2,0xc8,0x58,0x98,},{0xec,0xfb,0x6a,0x2b,0xd4,0x2f,0x31,0xb6,0x12,0x50,0xba,0x5d,0xe7,0xe4,0x6b,0x47,0x19,0xaf,0xdf,0xbc,0x66,0x0d,0xb7,0x1a,0x7b,0xd1,0xdf,0x7b,0x0a,0x3a,0xbe,0x37,},{0x9a,0xf8,0x85,0x34,0x4c,0xc7,0x23,0x94,0x98,0xf7,0x12,0xdf,0x80,0xbc,0x01,0xb8,0x06,0x38,0x29,0x1e,0xd4,0xa1,0xd2,0x8b,0xaa,0x55,0x45,0x01,0x7a,0x72,0xe2,0xf6,0x56,0x49,0xcc,0xf9,0x60,0x3d,0xa6,0xeb,0x5b,0xfa,0xb9,0xf5,0x54,0x3a,0x6c,0xa4,0xa7,0xaf,0x38,0x66,0x15,0x3c,0x76,0xbf,0x66,0xbf,0x95,0xde,0xf6,0x15,0xb0,0x0c,},44,"\x63\xb8\x0b\x79\x56\xac\xbe\xcf\x0c\x35\xe9\xab\x06\xb9\x14\xb0\xc7\x01\x4f\xe1\xa4\xbb\xc0\x21\x72\x40\xc1\xa3\x30\x95\xd7\x07\x95\x3e\xd7\x7b\x15\xd2\x11\xad\xaf\x9b\x97\xdc"}, + {{0x0d,0xdc,0xdc,0x87,0x2c,0x7b,0x74,0x8d,0x40,0xef,0xe9,0x6c,0x28,0x81,0xae,0x18,0x9d,0x87,0xf5,0x61,0x48,0xed,0x8a,0xf3,0xeb,0xbb,0xc8,0x03,0x24,0xe3,0x8b,0xdd,},{0x58,0x8d,0xda,0xdc,0xbc,0xed,0xf4,0x0d,0xf0,0xe9,0x69,0x7d,0x8b,0xb2,0x77,0xc7,0xbb,0x14,0x98,0xfa,0x1d,0x26,0xce,0x0a,0x83,0x5a,0x76,0x0b,0x92,0xca,0x7c,0x85,},{0xc1,0x79,0xc0,0x94,0x56,0xe2,0x35,0xfe,0x24,0x10,0x5a,0xfa,0x6e,0x8e,0xc0,0x46,0x37,0xf8,0xf9,0x43,0x81,0x7c,0xd0,0x98,0xba,0x95,0x38,0x7f,0x96,0x53,0xb2,0xad,0xd1,0x81,0xa3,0x14,0x47,0xd9,0x2d,0x1a,0x1d,0xdf,0x1c,0xeb,0x0d,0xb6,0x21,0x18,0xde,0x9d,0xff,0xb7,0xdc,0xd2,0x42,0x40,0x57,0xcb,0xdf,0xf5,0xd4,0x1d,0x04,0x03,},45,"\x65\x64\x1c\xd4\x02\xad\xd8\xbf\x3d\x1d\x67\xdb\xeb\x6d\x41\xde\xbf\xbe\xf6\x7e\x43\x17\xc3\x5b\x0a\x6d\x5b\xbb\xae\x0e\x03\x4d\xe7\xd6\x70\xba\x14\x13\xd0\x56\xf2\xd6\xf1\xde\x12"}, + {{0x89,0xf0,0xd6,0x82,0x99,0xba,0x0a,0x5a,0x83,0xf2,0x48,0xae,0x0c,0x16,0x9f,0x8e,0x38,0x49,0xa9,0xb4,0x7b,0xd4,0x54,0x98,0x84,0x30,0x5c,0x99,0x12,0xb4,0x66,0x03,},{0xab,0xa3,0xe7,0x95,0xaa,0xb2,0x01,0x2a,0xcc,0xea,0xdd,0x7b,0x3b,0xd9,0xda,0xee,0xed,0x6f,0xf5,0x25,0x8b,0xdc,0xd7,0xc9,0x36,0x99,0xc2,0xa3,0x83,0x6e,0x38,0x32,},{0x2c,0x69,0x1f,0xa8,0xd4,0x87,0xce,0x20,0xd5,0xd2,0xfa,0x41,0x55,0x91,0x16,0xe0,0xbb,0xf4,0x39,0x7c,0xf5,0x24,0x0e,0x15,0x25,0x56,0x18,0x35,0x41,0xd6,0x6c,0xf7,0x53,0x58,0x24,0x01,0xa4,0x38,0x8d,0x39,0x03,0x39,0xdb,0xef,0x4d,0x38,0x47,0x43,0xca,0xa3,0x46,0xf5,0x5f,0x8d,0xab,0xa6,0x8b,0xa7,0xb9,0x13,0x1a,0x8a,0x6e,0x0b,},46,"\x4f\x18\x46\xdd\x7a\xd5\x0e\x54\x5d\x4c\xfb\xff\xbb\x1d\xc2\xff\x14\x5d\xc1\x23\x75\x4d\x08\xaf\x4e\x44\xec\xc0\xbc\x8c\x91\x41\x13\x88\xbc\x76\x53\xe2\xd8\x93\xd1\xea\xc2\x10\x7d\x05"}, + {{0x0a,0x3c,0x18,0x44,0xe2,0xdb,0x07,0x0f,0xb2,0x4e,0x3c,0x95,0xcb,0x1c,0xc6,0x71,0x4e,0xf8,0x4e,0x2c,0xcd,0x2b,0x9d,0xd2,0xf1,0x46,0x0e,0xbf,0x7e,0xcf,0x13,0xb1,},{0x72,0xe4,0x09,0x93,0x7e,0x06,0x10,0xeb,0x5c,0x20,0xb3,0x26,0xdc,0x6e,0xa1,0xbb,0xbc,0x04,0x06,0x70,0x1c,0x5c,0xd6,0x7d,0x1f,0xbd,0xe0,0x91,0x92,0xb0,0x7c,0x01,},{0x87,0xf7,0xfd,0xf4,0x60,0x95,0x20,0x1e,0x87,0x7a,0x58,0x8f,0xe3,0xe5,0xaa,0xf4,0x76,0xbd,0x63,0x13,0x8d,0x8a,0x87,0x8b,0x89,0xd6,0xac,0x60,0x63,0x1b,0x34,0x58,0xb9,0xd4,0x1a,0x3c,0x61,0xa5,0x88,0xe1,0xdb,0x8d,0x29,0xa5,0x96,0x89,0x81,0xb0,0x18,0x77,0x6c,0x58,0x87,0x80,0x92,0x2f,0x5a,0xa7,0x32,0xba,0x63,0x79,0xdd,0x05,},47,"\x4c\x82\x74\xd0\xed\x1f\x74\xe2\xc8\x6c\x08\xd9\x55\xbd\xe5\x5b\x2d\x54\x32\x7e\x82\x06\x2a\x1f\x71\xf7\x0d\x53\x6f\xdc\x87\x22\xcd\xea\xd7\xd2\x2a\xae\xad\x2b\xfa\xa1\xad\x00\xb8\x29\x57"}, + {{0xc8,0xd7,0xa8,0x81,0x8b,0x98,0xdf,0xdb,0x20,0x83,0x9c,0x87,0x1c,0xb5,0xc4,0x8e,0x9e,0x94,0x70,0xca,0x3a,0xd3,0x5b,0xa2,0x61,0x3a,0x5d,0x31,0x99,0xc8,0xab,0x23,},{0x90,0xd2,0xef,0xbb,0xa4,0xd4,0x3e,0x6b,0x2b,0x99,0x2c,0xa1,0x60,0x83,0xdb,0xcf,0xa2,0xb3,0x22,0x38,0x39,0x07,0xb0,0xee,0x75,0xf3,0xe9,0x58,0x45,0xd3,0xc4,0x7f,},{0xfa,0x2e,0x99,0x44,0x21,0xae,0xf1,0xd5,0x85,0x66,0x74,0x81,0x3d,0x05,0xcb,0xd2,0xcf,0x84,0xef,0x5e,0xb4,0x24,0xaf,0x6e,0xcd,0x0d,0xc6,0xfd,0xbd,0xc2,0xfe,0x60,0x5f,0xe9,0x85,0x88,0x33,0x12,0xec,0xf3,0x4f,0x59,0xbf,0xb2,0xf1,0xc9,0x14,0x9e,0x5b,0x9c,0xc9,0xec,0xda,0x05,0xb2,0x73,0x11,0x30,0xf3,0xed,0x28,0xdd,0xae,0x0b,},48,"\x78\x3e\x33\xc3\xac\xbd\xbb\x36\xe8\x19\xf5\x44\xa7\x78\x1d\x83\xfc\x28\x3d\x33\x09\xf5\xd3\xd1\x2c\x8d\xcd\x6b\x0b\x3d\x0e\x89\xe3\x8c\xfd\x3b\x4d\x08\x85\x66\x1c\xa5\x47\xfb\x97\x64\xab\xff"}, + {{0xb4,0x82,0x70,0x36,0x12,0xd0,0xc5,0x86,0xf7,0x6c,0xfc,0xb2,0x1c,0xfd,0x21,0x03,0xc9,0x57,0x25,0x15,0x04,0xa8,0xc0,0xac,0x4c,0x86,0xc9,0xc6,0xf3,0xe4,0x29,0xff,},{0xfd,0x71,0x1d,0xc7,0xdd,0x3b,0x1d,0xfb,0x9d,0xf9,0x70,0x4b,0xe3,0xe6,0xb2,0x6f,0x58,0x7f,0xe7,0xdd,0x7b,0xa4,0x56,0xa9,0x1b,0xa4,0x3f,0xe5,0x1a,0xec,0x09,0xad,},{0x58,0x83,0x2b,0xde,0xb2,0x6f,0xea,0xfc,0x31,0xb4,0x62,0x77,0xcf,0x3f,0xb5,0xd7,0xa1,0x7d,0xfb,0x7c,0xcd,0x9b,0x1f,0x58,0xec,0xbe,0x6f,0xeb,0x97,0x96,0x66,0x82,0x8f,0x23,0x9b,0xa4,0xd7,0x52,0x19,0x26,0x0e,0xca,0xc0,0xac,0xf4,0x0f,0x0e,0x5e,0x25,0x90,0xf4,0xca,0xa1,0x6b,0xbb,0xcd,0x8a,0x15,0x5d,0x34,0x79,0x67,0xa6,0x07,},49,"\x29\xd7\x7a\xcf\xd9\x9c\x7a\x00\x70\xa8\x8f\xeb\x62\x47\xa2\xbc\xe9\x98\x4f\xe3\xe6\xfb\xf1\x9d\x40\x45\x04\x2a\x21\xab\x26\xcb\xd7\x71\xe1\x84\xa9\xa7\x5f\x31\x6b\x64\x8c\x69\x20\xdb\x92\xb8\x7b"}, + {{0x84,0xe5,0x0d,0xd9,0xa0,0xf1,0x97,0xe3,0x89,0x3c,0x38,0xdb,0xd9,0x1f,0xaf,0xc3,0x44,0xc1,0x77,0x6d,0x3a,0x40,0x0e,0x2f,0x0f,0x0e,0xe7,0xaa,0x82,0x9e,0xb8,0xa2,},{0x2c,0x50,0xf8,0x70,0xee,0x48,0xb3,0x6b,0x0a,0xc2,0xf8,0xa5,0xf3,0x36,0xfb,0x09,0x0b,0x11,0x30,0x50,0xdb,0xcc,0x25,0xe0,0x78,0x20,0x0a,0x6e,0x16,0x15,0x3e,0xea,},{0x69,0xe6,0xa4,0x49,0x1a,0x63,0x83,0x73,0x16,0xe8,0x6a,0x5f,0x4b,0xa7,0xcd,0x0d,0x73,0x1e,0xcc,0x58,0xf1,0xd0,0xa2,0x64,0xc6,0x7c,0x89,0xbe,0xfd,0xd8,0xd3,0x82,0x9d,0x8d,0xe1,0x3b,0x33,0xcc,0x0b,0xf5,0x13,0x93,0x17,0x15,0xc7,0x80,0x96,0x57,0xe2,0xbf,0xb9,0x60,0xe5,0xc7,0x64,0xc9,0x71,0xd7,0x33,0x74,0x60,0x93,0xe5,0x00,},50,"\xf3\x99\x2c\xde\x64\x93\xe6\x71\xf1\xe1\x29\xdd\xca\x80\x38\xb0\xab\xdb\x77\xbb\x90\x35\xf9\xf8\xbe\x54\xbd\x5d\x68\xc1\xae\xff\x72\x4f\xf4\x7d\x29\x34\x43\x91\xdc\x53\x61\x66\xb8\x67\x1c\xbb\xf1\x23"}, + {{0xb3,0x22,0xd4,0x65,0x77,0xa2,0xa9,0x91,0xa4,0xd1,0x69,0x82,0x87,0x83,0x2a,0x39,0xc4,0x87,0xef,0x77,0x6b,0x4b,0xff,0x03,0x7a,0x05,0xc7,0xf1,0x81,0x2b,0xde,0xec,},{0xeb,0x2b,0xca,0xdf,0xd3,0xee,0xc2,0x98,0x6b,0xaf,0xf3,0x2b,0x98,0xe7,0xc4,0xdb,0xf0,0x3f,0xf9,0x5d,0x8a,0xd5,0xff,0x9a,0xa9,0x50,0x6e,0x54,0x72,0xff,0x84,0x5f,},{0xc7,0xb5,0x51,0x37,0x31,0x7c,0xa2,0x1e,0x33,0x48,0x9f,0xf6,0xa9,0xbf,0xab,0x97,0xc8,0x55,0xdc,0x6f,0x85,0x68,0x4a,0x70,0xa9,0x12,0x5a,0x26,0x1b,0x56,0xd5,0xe6,0xf1,0x49,0xc5,0x77,0x4d,0x73,0x4f,0x2d,0x8d,0xeb,0xfc,0x77,0xb7,0x21,0x89,0x6a,0x82,0x67,0xc2,0x37,0x68,0xe9,0xba,0xdb,0x91,0x0e,0xef,0x83,0xec,0x25,0x88,0x02,},51,"\x19\xf1\xbf\x5d\xcf\x17\x50\xc6\x11\xf1\xc4\xa2\x86\x52\x00\x50\x4d\x82\x29\x8e\xdd\x72\x67\x1f\x62\xa7\xb1\x47\x1a\xc3\xd4\xa3\x0f\x7d\xe9\xe5\xda\x41\x08\xc5\x2a\x4c\xe7\x0a\x3e\x11\x4a\x52\xa3\xb3\xc5"}, + {{0x96,0x0c,0xab,0x50,0x34,0xb9,0x83,0x8d,0x09,0x8d,0x2d,0xcb,0xf4,0x36,0x4b,0xec,0x16,0xd3,0x88,0xf6,0x37,0x6d,0x73,0xa6,0x27,0x3b,0x70,0xf8,0x2b,0xbc,0x98,0xc0,},{0x5e,0x3c,0x19,0xf2,0x41,0x5a,0xcf,0x72,0x9f,0x82,0x9a,0x4e,0xbd,0x5c,0x40,0xe1,0xa6,0xbc,0x9f,0xbc,0xa9,0x57,0x03,0xa9,0x37,0x60,0x87,0xed,0x09,0x37,0xe5,0x1a,},{0x27,0xd4,0xc3,0xa1,0x81,0x1e,0xf9,0xd4,0x36,0x0b,0x3b,0xdd,0x13,0x3c,0x2c,0xcc,0x30,0xd0,0x2c,0x2f,0x24,0x82,0x15,0x77,0x6c,0xb0,0x7e,0xe4,0x17,0x7f,0x9b,0x13,0xfc,0x42,0xdd,0x70,0xa6,0xc2,0xfe,0xd8,0xf2,0x25,0xc7,0x66,0x3c,0x7f,0x18,0x2e,0x7e,0xe8,0xec,0xcf,0xf2,0x0d,0xc7,0xb0,0xe1,0xd5,0x83,0x4e,0xc5,0xb1,0xea,0x01,},52,"\xf8\xb2\x19\x62\x44\x7b\x0a\x8f\x2e\x42\x79\xde\x41\x1b\xea\x12\x8e\x0b\xe4\x4b\x69\x15\xe6\xcd\xa8\x83\x41\xa6\x8a\x0d\x81\x83\x57\xdb\x93\x8e\xac\x73\xe0\xaf\x6d\x31\x20\x6b\x39\x48\xf8\xc4\x8a\x44\x73\x08"}, + {{0xeb,0x77,0xb2,0x63,0x8f,0x23,0xee,0xbc,0x82,0xef,0xe4,0x5e,0xe9,0xe5,0xa0,0x32,0x66,0x37,0x40,0x1e,0x66,0x3e,0xd0,0x29,0x69,0x9b,0x21,0xe6,0x44,0x3f,0xb4,0x8e,},{0x9e,0xf2,0x76,0x08,0x96,0x1a,0xc7,0x11,0xde,0x71,0xa6,0xe2,0xd4,0xd4,0x66,0x3e,0xa3,0xec,0xd4,0x2f,0xb7,0xe4,0xe8,0x62,0x7c,0x39,0x62,0x2d,0xf4,0xaf,0x0b,0xbc,},{0x18,0xdc,0x56,0xd7,0xbd,0x9a,0xcd,0x4f,0x4d,0xaa,0x78,0x54,0x0b,0x4a,0xc8,0xff,0x7a,0xa9,0x81,0x5f,0x45,0xa0,0xbb,0xa3,0x70,0x73,0x1a,0x14,0xea,0xab,0xe9,0x6d,0xf8,0xb5,0xf3,0x7d,0xbf,0x8e,0xae,0x4c,0xb1,0x5a,0x64,0xb2,0x44,0x65,0x1e,0x59,0xd6,0xa3,0xd6,0x76,0x1d,0x9e,0x3c,0x50,0xf2,0xd0,0xcb,0xb0,0x9c,0x05,0xec,0x06,},53,"\x99\xe3\xd0\x09\x34\x00\x3e\xba\xfc\x3e\x9f\xdb\x68\x7b\x0f\x5f\xf9\xd5\x78\x2a\x4b\x1f\x56\xb9\x70\x00\x46\xc0\x77\x91\x56\x02\xc3\x13\x4e\x22\xfc\x90\xed\x7e\x69\x0f\xdd\xd4\x43\x3e\x20\x34\xdc\xb2\xdc\x99\xab"}, + {{0xb6,0x25,0xaa,0x89,0xd3,0xf7,0x30,0x87,0x15,0x42,0x7b,0x6c,0x39,0xbb,0xac,0x58,0xef,0xfd,0x3a,0x0f,0xb7,0x31,0x6f,0x7a,0x22,0xb9,0x9e,0xe5,0x92,0x2f,0x2d,0xc9,},{0x65,0xa9,0x9c,0x3e,0x16,0xfe,0xa8,0x94,0xec,0x33,0xc6,0xb2,0x0d,0x91,0x05,0xe2,0xa0,0x4e,0x27,0x64,0xa4,0x76,0x9d,0x9b,0xbd,0x4d,0x8b,0xac,0xfe,0xab,0x4a,0x2e,},{0x01,0xbb,0x90,0x1d,0x83,0xb8,0xb6,0x82,0xd3,0x61,0x4a,0xf4,0x6a,0x80,0x7b,0xa2,0x69,0x13,0x58,0xfe,0xb7,0x75,0x32,0x5d,0x34,0x23,0xf5,0x49,0xff,0x0a,0xa5,0x75,0x7e,0x4e,0x1a,0x74,0xe9,0xc7,0x0f,0x97,0x21,0xd8,0xf3,0x54,0xb3,0x19,0xd4,0xf4,0xa1,0xd9,0x14,0x45,0xc8,0x70,0xfd,0x0f,0xfb,0x94,0xfe,0xd6,0x46,0x64,0x73,0x0d,},54,"\xe0\x72\x41\xdb\xd3\xad\xbe\x61\x0b\xbe\x4d\x00\x5d\xd4\x67\x32\xa4\xc2\x50\x86\xec\xb8\xec\x29\xcd\x7b\xca\x11\x6e\x1b\xf9\xf5\x3b\xfb\xf3\xe1\x1f\xa4\x90\x18\xd3\x9f\xf1\x15\x4a\x06\x66\x8e\xf7\xdf\x5c\x67\x8e\x6a"}, + {{0xb1,0xc9,0xf8,0xbd,0x03,0xfe,0x82,0xe7,0x8f,0x5c,0x0f,0xb0,0x64,0x50,0xf2,0x7d,0xac,0xdf,0x71,0x64,0x34,0xdb,0x26,0x82,0x75,0xdf,0x3e,0x1d,0xc1,0x77,0xaf,0x42,},{0x7f,0xc8,0x8b,0x1f,0x7b,0x3f,0x11,0xc6,0x29,0xbe,0x67,0x1c,0x21,0x62,0x1f,0x5c,0x10,0x67,0x2f,0xaf,0xc8,0x49,0x2d,0xa8,0x85,0x74,0x20,0x59,0xee,0x67,0x74,0xcf,},{0x4b,0x22,0x99,0x51,0xef,0x26,0x2f,0x16,0x97,0x8f,0x79,0x14,0xbc,0x67,0x2e,0x72,0x26,0xc5,0xf8,0x37,0x9d,0x27,0x78,0xc5,0xa2,0xdc,0x0a,0x26,0x50,0x86,0x9f,0x7a,0xcf,0xbd,0x0b,0xcd,0x30,0xfd,0xb0,0x61,0x9b,0xb4,0x4f,0xc1,0xae,0x59,0x39,0xb8,0x7c,0xc3,0x18,0x13,0x30,0x09,0xc2,0x03,0x95,0xb6,0xc7,0xeb,0x98,0x10,0x77,0x01,},55,"\x33\x1d\xa7\xa9\xc1\xf8\x7b\x2a\xc9\x1e\xe3\xb8\x6d\x06\xc2\x91\x63\xc0\x5e\xd6\xf8\xd8\xa9\x72\x5b\x47\x1b\x7d\xb0\xd6\xac\xec\x7f\x0f\x70\x24\x87\x16\x3f\x5e\xda\x02\x0c\xa5\xb4\x93\xf3\x99\xe1\xc8\xd3\x08\xc3\xc0\xc2"}, + {{0x6d,0x8c,0xdb,0x2e,0x07,0x5f,0x3a,0x2f,0x86,0x13,0x72,0x14,0xcb,0x23,0x6c,0xeb,0x89,0xa6,0x72,0x8b,0xb4,0xa2,0x00,0x80,0x6b,0xf3,0x55,0x7f,0xb7,0x8f,0xac,0x69,},{0x57,0xa0,0x4c,0x7a,0x51,0x13,0xcd,0xdf,0xe4,0x9a,0x4c,0x12,0x46,0x91,0xd4,0x6c,0x1f,0x9c,0xdc,0x8f,0x34,0x3f,0x9d,0xcb,0x72,0xa1,0x33,0x0a,0xec,0xa7,0x1f,0xda,},{0xa6,0xcb,0xc9,0x47,0xf9,0xc8,0x7d,0x14,0x55,0xcf,0x1a,0x70,0x85,0x28,0xc0,0x90,0xf1,0x1e,0xce,0xe4,0x85,0x5d,0x1d,0xba,0xad,0xf4,0x74,0x54,0xa4,0xde,0x55,0xfa,0x4c,0xe8,0x4b,0x36,0xd7,0x3a,0x5b,0x5f,0x8f,0x59,0x29,0x8c,0xcf,0x21,0x99,0x2d,0xf4,0x92,0xef,0x34,0x16,0x3d,0x87,0x75,0x3b,0x7e,0x9d,0x32,0xf2,0xc3,0x66,0x0b,},56,"\x7f\x31\x8d\xbd\x12\x1c\x08\xbf\xdd\xfe\xff\x4f\x6a\xff\x4e\x45\x79\x32\x51\xf8\xab\xf6\x58\x40\x33\x58\x23\x89\x84\x36\x00\x54\xf2\xa8\x62\xc5\xbb\x83\xed\x89\x02\x5d\x20\x14\xa7\xa0\xce\xe5\x0d\xa3\xcb\x0e\x76\xbb\xb6\xbf"}, + {{0x47,0xad,0xc6,0xd6,0xbf,0x57,0x1e,0xe9,0x57,0x0c,0xa0,0xf7,0x5b,0x60,0x4a,0xc4,0x3e,0x30,0x3e,0x4a,0xb3,0x39,0xca,0x9b,0x53,0xca,0xcc,0x5b,0xe4,0x5b,0x2c,0xcb,},{0xa3,0xf5,0x27,0xa1,0xc1,0xf1,0x7d,0xfe,0xed,0x92,0x27,0x73,0x47,0xc9,0xf9,0x8a,0xb4,0x75,0xde,0x17,0x55,0xb0,0xab,0x54,0x6b,0x8a,0x15,0xd0,0x1b,0x9b,0xd0,0xbe,},{0x4e,0x8c,0x31,0x83,0x43,0xc3,0x06,0xad,0xbb,0xa6,0x0c,0x92,0xb7,0x5c,0xb0,0x56,0x9b,0x92,0x19,0xd8,0xa8,0x6e,0x5d,0x57,0x75,0x2e,0xd2,0x35,0xfc,0x10,0x9a,0x43,0xc2,0xcf,0x4e,0x94,0x2c,0xac,0xf2,0x97,0x27,0x9f,0xbb,0x28,0x67,0x53,0x47,0xe0,0x80,0x27,0x72,0x2a,0x4e,0xb7,0x39,0x5e,0x00,0xa1,0x74,0x95,0xd3,0x2e,0xdf,0x0b,},57,"\xce\x49\x7c\x5f\xf5\xa7\x79\x90\xb7\xd8\xf8\x69\x9e\xb1\xf5\xd8\xc0\x58\x2f\x70\xcb\x7a\xc5\xc5\x4d\x9d\x92\x49\x13\x27\x8b\xc6\x54\xd3\x7e\xa2\x27\x59\x0e\x15\x20\x22\x17\xfc\x98\xda\xc4\xc0\xf3\xbe\x21\x83\xd1\x33\x31\x57\x39"}, + {{0x3c,0x19,0xb5,0x0b,0x0f,0xe4,0x79,0x61,0x71,0x9c,0x38,0x1d,0x0d,0x8d,0xa9,0xb9,0x86,0x9d,0x31,0x2f,0x13,0xe3,0x29,0x8b,0x97,0xfb,0x22,0xf0,0xaf,0x29,0xcb,0xbe,},{0x0f,0x7e,0xda,0x09,0x14,0x99,0x62,0x5e,0x2b,0xae,0x85,0x36,0xea,0x35,0xcd,0xa5,0x48,0x3b,0xd1,0x6a,0x9c,0x7e,0x41,0x6b,0x34,0x1d,0x6f,0x2c,0x83,0x34,0x36,0x12,},{0xef,0xbd,0x41,0xf2,0x6a,0x5d,0x62,0x68,0x55,0x16,0xf8,0x82,0xb6,0xec,0x74,0xe0,0xd5,0xa7,0x18,0x30,0xd2,0x03,0xc2,0x31,0x24,0x8f,0x26,0xe9,0x9a,0x9c,0x65,0x78,0xec,0x90,0x0d,0x68,0xcd,0xb8,0xfa,0x72,0x16,0xad,0x0d,0x24,0xf9,0xec,0xbc,0x9f,0xfa,0x65,0x53,0x51,0x66,0x65,0x82,0xf6,0x26,0x64,0x53,0x95,0xa3,0x1f,0xa7,0x04,},58,"\x8d\xdc\xd6\x30\x43\xf5\x5e\xc3\xbf\xc8\x3d\xce\xae\x69\xd8\xf8\xb3\x2f\x4c\xdb\x6e\x2a\xeb\xd9\x4b\x43\x14\xf8\xfe\x72\x87\xdc\xb6\x27\x32\xc9\x05\x2e\x75\x57\xfe\x63\x53\x43\x38\xef\xb5\xb6\x25\x4c\x5d\x41\xd2\x69\x0c\xf5\x14\x4f"}, + {{0x34,0xe1,0xe9,0xd5,0x39,0x10,0x7e,0xb8,0x6b,0x39,0x3a,0x5c,0xce,0xa1,0x49,0x6d,0x35,0xbc,0x7d,0x5e,0x9a,0x8c,0x51,0x59,0xd9,0x57,0xe4,0xe5,0x85,0x2b,0x3e,0xb0,},{0x0e,0xcb,0x26,0x01,0xd5,0xf7,0x04,0x74,0x28,0xe9,0xf9,0x09,0x88,0x3a,0x12,0x42,0x00,0x85,0xf0,0x4e,0xe2,0xa8,0x8b,0x6d,0x95,0xd3,0xd7,0xf2,0xc9,0x32,0xbd,0x76,},{0x32,0xd2,0x29,0x04,0xd3,0xe7,0x01,0x2d,0x6f,0x5a,0x44,0x1b,0x0b,0x42,0x28,0x06,0x4a,0x5c,0xf9,0x5b,0x72,0x3a,0x66,0xb0,0x48,0xa0,0x87,0xec,0xd5,0x59,0x20,0xc3,0x1c,0x20,0x4c,0x3f,0x20,0x06,0x89,0x1a,0x85,0xdd,0x19,0x32,0xe3,0xf1,0xd6,0x14,0xcf,0xd6,0x33,0xb5,0xe6,0x32,0x91,0xc6,0xd8,0x16,0x6f,0x30,0x11,0x43,0x1e,0x09,},59,"\xa6\xd4\xd0\x54\x2c\xfe\x0d\x24\x0a\x90\x50\x7d\xeb\xac\xab\xce\x7c\xbb\xd4\x87\x32\x35\x3f\x4f\xad\x82\xc7\xbb\x7d\xbd\x9d\xf8\xe7\xd9\xa1\x69\x80\xa4\x51\x86\xd8\x78\x6c\x5e\xf6\x54\x45\xbc\xc5\xb2\xad\x5f\x66\x0f\xfc\x7c\x8e\xaa\xc0"}, + {{0x49,0xdd,0x47,0x3e,0xde,0x6a,0xa3,0xc8,0x66,0x82,0x4a,0x40,0xad,0xa4,0x99,0x6c,0x23,0x9a,0x20,0xd8,0x4c,0x93,0x65,0xe4,0xf0,0xa4,0x55,0x4f,0x80,0x31,0xb9,0xcf,},{0x78,0x8d,0xe5,0x40,0x54,0x4d,0x3f,0xeb,0x0c,0x91,0x92,0x40,0xb3,0x90,0x72,0x9b,0xe4,0x87,0xe9,0x4b,0x64,0xad,0x97,0x3e,0xb6,0x5b,0x46,0x69,0xec,0xf2,0x35,0x01,},{0xd2,0xfd,0xe0,0x27,0x91,0xe7,0x20,0x85,0x25,0x07,0xfa,0xa7,0xc3,0x78,0x90,0x40,0xd9,0xef,0x86,0x64,0x63,0x21,0xf3,0x13,0xac,0x55,0x7f,0x40,0x02,0x49,0x15,0x42,0xdd,0x67,0xd0,0x5c,0x69,0x90,0xcd,0xb0,0xd4,0x95,0x50,0x1f,0xbc,0x5d,0x51,0x88,0xbf,0xbb,0x84,0xdc,0x1b,0xf6,0x09,0x8b,0xee,0x06,0x03,0xa4,0x7f,0xc2,0x69,0x0f,},60,"\x3a\x53\x59\x4f\x3f\xba\x03\x02\x93\x18\xf5\x12\xb0\x84\xa0\x71\xeb\xd6\x0b\xae\xc7\xf5\x5b\x02\x8d\xc7\x3b\xfc\x9c\x74\xe0\xca\x49\x6b\xf8\x19\xdd\x92\xab\x61\xcd\x8b\x74\xbe\x3c\x0d\x6d\xcd\x12\x8e\xfc\x5e\xd3\x34\x2c\xba\x12\x4f\x72\x6c"}, + {{0x33,0x1c,0x64,0xda,0x48,0x2b,0x6b,0x55,0x13,0x73,0xc3,0x64,0x81,0xa0,0x2d,0x81,0x36,0xec,0xad,0xbb,0x01,0xab,0x11,0x4b,0x44,0x70,0xbf,0x41,0x60,0x7a,0xc5,0x71,},{0x52,0xa0,0x0d,0x96,0xa3,0x14,0x8b,0x47,0x26,0x69,0x2d,0x9e,0xff,0x89,0x16,0x0e,0xa9,0xf9,0x9a,0x5c,0xc4,0x38,0x9f,0x36,0x1f,0xed,0x0b,0xb1,0x6a,0x42,0xd5,0x21,},{0x22,0xc9,0x9a,0xa9,0x46,0xea,0xd3,0x9a,0xc7,0x99,0x75,0x62,0x81,0x0c,0x01,0xc2,0x0b,0x46,0xbd,0x61,0x06,0x45,0xbd,0x2d,0x56,0xdc,0xdc,0xba,0xac,0xc5,0x45,0x2c,0x74,0xfb,0xf4,0xb8,0xb1,0x81,0x3b,0x0e,0x94,0xc3,0x0d,0x80,0x8c,0xe5,0x49,0x8e,0x61,0xd4,0xf7,0xcc,0xbb,0x4c,0xc5,0xf0,0x4d,0xfc,0x61,0x40,0x82,0x5a,0x96,0x00,},61,"\x20\xe1\xd0\x5a\x0d\x5b\x32\xcc\x81\x50\xb8\x11\x6c\xef\x39\x65\x9d\xd5\xfb\x44\x3a\xb1\x56\x00\xf7\x8e\x5b\x49\xc4\x53\x26\xd9\x32\x3f\x28\x50\xa6\x3c\x38\x08\x85\x94\x95\xae\x27\x3f\x58\xa5\x1e\x9d\xe9\xa1\x45\xd7\x74\xb4\x0b\xa9\xd7\x53\xd3"}, + {{0x5c,0x0b,0x96,0xf2,0xaf,0x87,0x12,0x12,0x2c,0xf7,0x43,0xc8,0xf8,0xdc,0x77,0xb6,0xcd,0x55,0x70,0xa7,0xde,0x13,0x29,0x7b,0xb3,0xdd,0xe1,0x88,0x62,0x13,0xcc,0xe2,},{0x05,0x10,0xea,0xf5,0x7d,0x73,0x01,0xb0,0xe1,0xd5,0x27,0x03,0x9b,0xf4,0xc6,0xe2,0x92,0x30,0x0a,0x3a,0x61,0xb4,0x76,0x54,0x34,0xf3,0x20,0x3c,0x10,0x03,0x51,0xb1,},{0x06,0xe5,0xd8,0x43,0x6a,0xc7,0x70,0x5b,0x3a,0x90,0xf1,0x63,0x1c,0xdd,0x38,0xec,0x1a,0x3f,0xa4,0x97,0x78,0xa9,0xb9,0xf2,0xfa,0x5e,0xbe,0xa4,0xe7,0xd5,0x60,0xad,0xa7,0xdd,0x26,0xff,0x42,0xfa,0xfa,0x8b,0xa4,0x20,0x32,0x37,0x42,0x76,0x1a,0xca,0x69,0x04,0x94,0x0d,0xc2,0x1b,0xbe,0xf6,0x3f,0xf7,0x2d,0xaa,0xb4,0x5d,0x43,0x0b,},62,"\x54\xe0\xca\xa8\xe6\x39\x19\xca\x61\x4b\x2b\xfd\x30\x8c\xcf\xe5\x0c\x9e\xa8\x88\xe1\xee\x44\x46\xd6\x82\xcb\x50\x34\x62\x7f\x97\xb0\x53\x92\xc0\x4e\x83\x55\x56\xc3\x1c\x52\x81\x6a\x48\xe4\xfb\x19\x66\x93\x20\x6b\x8a\xfb\x44\x08\x66\x2b\x3c\xb5\x75"}, + {{0xde,0x84,0xf2,0x43,0x5f,0x78,0xde,0xdb,0x87,0xda,0x18,0x19,0x4f,0xf6,0xa3,0x36,0xf0,0x81,0x11,0x15,0x0d,0xef,0x90,0x1c,0x1a,0xc4,0x18,0x14,0x6e,0xb7,0xb5,0x4a,},{0xd3,0xa9,0x2b,0xba,0xa4,0xd6,0x3a,0xf7,0x9c,0x22,0x26,0xa7,0x23,0x6e,0x64,0x27,0x42,0x8d,0xf8,0xb3,0x62,0x42,0x7f,0x87,0x30,0x23,0xb2,0x2d,0x2f,0x5e,0x03,0xf2,},{0x47,0x1e,0xbc,0x97,0x3c,0xfd,0xac,0xee,0xc0,0x72,0x79,0x30,0x73,0x68,0xb7,0x3b,0xe3,0x5b,0xc6,0xf8,0xd8,0x31,0x2b,0x70,0x15,0x05,0x67,0x36,0x90,0x96,0x70,0x6d,0xc4,0x71,0x12,0x6c,0x35,0x76,0xf9,0xf0,0xeb,0x55,0x0d,0xf5,0xac,0x6a,0x52,0x51,0x81,0x11,0x00,0x29,0xdd,0x1f,0xc1,0x11,0x74,0xd1,0xaa,0xce,0xd4,0x8d,0x63,0x0f,},63,"\x20\x51\x35\xec\x7f\x41\x7c\x85\x80\x72\xd5\x23\x3f\xb3\x64\x82\xd4\x90\x6a\xbd\x60\xa7\x4a\x49\x8c\x34\x7f\xf2\x48\xdf\xa2\x72\x2c\xa7\x4e\x87\x9d\xe3\x31\x69\xfa\xdc\x7c\xd4\x4d\x6c\x94\xa1\x7d\x16\xe1\xe6\x30\x82\x4b\xa3\xe0\xdf\x22\xed\x68\xea\xab"}, + {{0xba,0x4d,0x6e,0x67,0xb2,0xce,0x67,0xa1,0xe4,0x43,0x26,0x49,0x40,0x44,0xf3,0x7a,0x44,0x2f,0x3b,0x81,0x72,0x5b,0xc1,0xf9,0x34,0x14,0x62,0x71,0x8b,0x55,0xee,0x20,},{0xf7,0x3f,0xa0,0x76,0xf8,0x4b,0x6d,0xb6,0x75,0xa5,0xfd,0xa5,0xad,0x67,0xe3,0x51,0xa4,0x1e,0x8e,0x7f,0x29,0xad,0xd1,0x68,0x09,0xca,0x01,0x03,0x87,0xe9,0xc6,0xcc,},{0x57,0xb9,0xd2,0xa7,0x11,0x20,0x7f,0x83,0x74,0x21,0xba,0xe7,0xdd,0x48,0xea,0xa1,0x8e,0xab,0x1a,0x9a,0x70,0xa0,0xf1,0x30,0x58,0x06,0xfe,0xe1,0x7b,0x45,0x8f,0x3a,0x09,0x64,0xb3,0x02,0xd1,0x83,0x4d,0x3e,0x0a,0xc9,0xe8,0x49,0x6f,0x00,0x0b,0x77,0xf0,0x08,0x3b,0x41,0xf8,0xa9,0x57,0xe6,0x32,0xfb,0xc7,0x84,0x0e,0xee,0x6a,0x06,},64,"\x4b\xaf\xda\xc9\x09\x9d\x40\x57\xed\x6d\xd0\x8b\xca\xee\x87\x56\xe9\xa4\x0f\x2c\xb9\x59\x80\x20\xeb\x95\x01\x95\x28\x40\x9b\xbe\xa3\x8b\x38\x4a\x59\xf1\x19\xf5\x72\x97\xbf\xb2\xfa\x14\x2f\xc7\xbb\x1d\x90\xdb\xdd\xde\x77\x2b\xcd\xe4\x8c\x56\x70\xd5\xfa\x13"}, + {{0x0d,0x13,0x1c,0x45,0xae,0xa6,0xf3,0xa4,0xe1,0xb9,0xa2,0xcf,0x60,0xc5,0x51,0x04,0x58,0x7e,0xfa,0xa8,0x46,0xb2,0x22,0xbf,0x0a,0x7b,0x74,0xce,0x7a,0x3f,0x63,0xb6,},{0x3c,0x67,0x29,0xdb,0xe9,0x3b,0x49,0x9c,0x4e,0x61,0x4a,0x2f,0x21,0xbe,0xb7,0x29,0x43,0x8d,0x49,0x8e,0x1a,0xc8,0xd1,0x4c,0xba,0xd9,0x71,0x7a,0x5d,0xbd,0x97,0xcd,},{0xa9,0xc5,0xee,0x86,0xfb,0x06,0xd9,0xe4,0x6b,0x37,0x9c,0x32,0xdd,0xa7,0xc9,0x2c,0x9c,0x13,0xdb,0x27,0x4d,0xc2,0x41,0x16,0xfb,0xdd,0x87,0x86,0x96,0x04,0x54,0x88,0xcc,0x75,0xa5,0x2f,0xff,0x67,0xd1,0xa5,0x11,0x3d,0x06,0xe3,0x33,0xac,0x67,0xff,0x66,0x4b,0x3f,0x2a,0x40,0x5f,0xa1,0xd1,0x4d,0xd5,0xbb,0xb9,0x74,0x09,0xb6,0x06,},65,"\xb4\x29\x1d\x08\xb8\x8f\xb2\xf7\xb8\xf9\x9d\x0d\xce\x40\x07\x9f\xcb\xab\x71\x8b\xbd\x8f\x4e\x8e\xab\xc3\xc1\x42\x8b\x6a\x07\x1f\xb2\xa3\xc8\xeb\xa1\xca\xcc\xcf\xa8\x71\xb3\x65\xc7\x08\xbe\xf2\x68\x5b\xc1\x3e\x6b\x80\xbc\x14\xa5\xf2\x49\x17\x0f\xfc\x56\xd0\x14"}, +}; + +bool TestCryptoSign() +{ + // https://github.com/jedisct1/libsodium/blob/master/test/default/sign.c + const unsigned int MAX_MESSAGE = 65; // Sync with test data + + byte pk[crypto_sign_PUBLICKEYBYTES]; + byte sk[crypto_sign_SECRETKEYBYTES]; + SecByteBlock sm(MAX_MESSAGE+crypto_sign_BYTES); + SecByteBlock rm(MAX_MESSAGE+crypto_sign_BYTES); + + bool pass = true, fail; int rc; + + for (unsigned int i=0; i(data.msg); + const word64 l = data.len; + word64 smlen; + + rc = crypto_sign(sm, &smlen, m, l, sk); + fail = (rc != 0); pass = !fail && pass; + + word64 s = STDMIN(smlen, (word64)crypto_sign_BYTES); + pass = (s >= crypto_sign_BYTES) && pass; + + fail = std::memcmp(sm, data.sig, (size_t)s) != 0; + pass = !fail && pass; + + word64 rmlen; + rc = crypto_sign_open(rm, &rmlen, sm, smlen, pk); + fail = (rc != 0); pass = !fail && pass; + + pass = (l == rmlen) && pass; + fail = std::memcmp(m, rm, (size_t)STDMIN(l, rmlen)) != 0; + pass = !fail && pass; + } + + return pass; +} + +bool TestCryptoSignKeys() +{ + // https://github.com/jedisct1/libsodium/blob/master/test/default/sign.c + const unsigned int MAX_TEST = 64; + const unsigned int MAX_MESSAGE = 4096; + + byte pk[crypto_sign_PUBLICKEYBYTES]; + byte sk[crypto_sign_SECRETKEYBYTES]; + + bool pass = true, fail; int rc; + + for (unsigned int i=0; i +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestIntegerBitops() +{ + std::cout << "\nTesting Integer bit operations...\n\n"; + + struct Bitops_TestTuple + { + // m,n are operands; a,o,x are and,or,xor results + const char *m, *n, *a, *o, *x; + }; + static const Bitops_TestTuple tests[] = { + { + "0xc2cea8a4", "0xb36e5794", "0x824e0084", "0xf3eeffb4", "0x71a0ff30" + }, + { + "0x436eb828", "0x1b375cb4", "0x3261820", "0x5b7ffcbc", "0x5859e49c" + }, + { + "0x1e5c0b28", "0x4fded465", "0xe5c0020", "0x5fdedf6d", "0x5182df4d" + }, + { + "0xeb71fde7", "0xf7bb47cf", "0xe33145c7", "0xfffbffef", "0x1ccaba28" + }, + { + "0xa6b0f01f", "0x8a8ca98", "0xa0c018", "0xaeb8fa9f", "0xae183a87" + }, + { + "0xa70bd8b7", "0x5c758cf5", "0x40188b5", "0xff7fdcf7", "0xfb7e5442" + }, + { + "0xf91af382", "0x718a9995", "0x710a9180", "0xf99afb97", "0x88906a17" + }, + { + "0xbd2a76ad", "0xddd8dfeb", "0x9d0856a9", "0xfdfaffef", "0x60f2a946" + }, + { + "0xd4b559cc", "0x91a53295", "0x90a51084", "0xd5b57bdd", "0x45106b59" + }, + { + "0x89434e9e", "0xa42fdaf9", "0x80034a98", "0xad6fdeff", "0x2d6c9467" + }, + { + "0xb947ac04", "0xd4201e52", "0x90000c00", "0xfd67be56", "0x6d67b256" + }, + { + "0xa83945c1", "0x3a9c5dba", "0x28184580", "0xbabd5dfb", "0x92a5187b" + }, + { + "0xbca38ffa", "0x881ba9fd", "0x880389f8", "0xbcbbafff", "0x34b82607" + }, + { + "0xfcd0b92", "0xeaad8534", "0xa8d0110", "0xefed8fb6", "0xe5608ea6" + }, + { + "0x50d160d0", "0x64646f75", "0x40406050", "0x74f56ff5", "0x34b50fa5" + }, + { + "0x165ccff8", "0x67d49127", "0x6548120", "0x77dcdfff", "0x71885edf" + }, + { + "0x8c4f4bbb7adaacb5", "0x2566b7a909b24aa9", "0x44603a9089208a1", "0xad6fffbb7bfaeebd", "0xa929fc127368e61c" + }, + { + "0x6f9ef50aafb31e8d", "0x7a93b2ccd1bbbff2", "0x6a92b00881b31e80", "0x7f9ff7ceffbbbfff", "0x150d47c67e08a17f" + }, + { + "0x4c99e967f8de5294", "0x1f4699e0c14e6974", "0xc008960c04e4014", "0x5fdff9e7f9de7bf4", "0x53df708739903be0" + }, + { + "0xcc55f5d6d3ea45c", "0x6805b4ddb6390c2f", "0x805145d2438040c", "0x6cc5ffddff3fac7f", "0x64c0eb80db07a873" + }, + { + "0x90620d1a012459e7", "0x89d31098ce3fed42", "0x8042001800244942", "0x99f31d9acf3ffde7", "0x19b11d82cf1bb4a5" + }, + { + "0xb87d1674e90a935a", "0x75ea466cbb782ac4", "0x30680664a9080240", "0xfdff567cfb7abbde", "0xcd9750185272b99e" + }, + { + "0x1f135732240701f0", "0x6aa09a1614bf4dd4", "0xa001212040701d0", "0x7fb3df3634bf4df4", "0x75b3cd2430b84c24" + }, + { + "0xc9a88d8300099a31", "0xdc8e91df745169ee", "0xc888818300010820", "0xddae9ddf7459fbff", "0x15261c5c7458f3df" + }, + { + "0xc8c828d15228b562", "0x43f86cffa3d15d80", "0x40c828d102001500", "0xcbf86cfff3f9fde2", "0x8b30442ef1f9e8e2" + }, + { + "0x41fdc0bc2009563f", "0x59dd1c417e3c07bc", "0x41dd00002008063c", "0x59fddcfd7e3d57bf", "0x1820dcfd5e355183" + }, + { + "0x9e2f78600c3a84e7", "0xac69a0e1fe7887b0", "0x8c2920600c3884a0", "0xbe6ff8e1fe7a87f7", "0x3246d881f2420357" + }, + { + "0xd424d1d9a955f617", "0x9608f5bde1c4d893", "0x9400d199a144d013", "0xd62cf5fde9d5fe97", "0x422c246448912e84" + }, + { + "0x1aa8b60a0627719a", "0x5b26e6aca95f5f60", "0x1a20a60800075100", "0x5baef6aeaf7f7ffa", "0x418e50a6af782efa" + }, + { + "0xcf5db499233fac00", "0xf33e7a29c3c33da8", "0xc31c300903032c00", "0xff7ffeb9e3ffbda8", "0x3c63ceb0e0fc91a8" + }, + { + "0x6b47c03d576e878d", "0x2032d13574d67da4", "0x2002c03554460584", "0x6b77d13d77feffad", "0x4b75110823b8fa29" + }, + { + "0xd47eeb3aefebf074", "0x6d7ba17a42c66b89", "0x447aa13a42c26000", "0xfd7feb7aefeffbfd", "0xb9054a40ad2d9bfd" + }, + { + "0x33ad9c5d20b03f5c05535f20a2941c8f4ae0f1f19500759151060dce39e5dfed41ec4f", + "0x277401dc000fde7eda4d60a5698935f7febd8fbe49e5d6f56ca2e7f6118380d3cd655da392df3ba6c1b13dc0119af34cfa1d18a65", + "0x10a9841c002016480453410020041c8640c0312191006411110401082924cfa1418845", + "0x277401dc000fde7eda4d60a5698935f7febfbfffcdf7dff7fde2f7f7f38ba9d3cdf5ffaf9fdf7ba7d9b53de0ddfbff5dfedd1ee6f", + "0x277401dc000fde7eda4d60a5698935f7febeb5678c37ddf69962b2c3e389a9920591f3ac8dc66ba198a42da0cd796d1104c90662a" + }, + { + "0xb6ea335c13111216862e370d12fb9c761a6266617f62a1904b0d7944ab3cddc71f11752ad9424b0", + "0xa6b380f048a9cbe45ff4ea824064c831eb03ff875e1e3e", + "0xa62200104028090410d480020044c831e1035285140430", + "0xb6ea335c13111216862e370d12fb9c761a6b7e6f7feabdbe4fff7fecaf3eddc71fb17ffafde3ebe", + "0xb6ea335c13111216862e370d12fb9c7610095e6e7be83d2e0ef237ec8f3a914401a14ad2aca3a8e" + }, + { + "0x8fb9486ad1f89ca5b3f6da9f0d5ef9ec328b8cc3e5122afbd8a67bd1b2b4ab5c548b90cf9fe1933a0362922f1e84ef0", + "0x10615f963dffc13718ed1ecdb9cfbef33148befeb91b190dc7e7d28d8821ff248ab26a34e1b89885c643e447c72", + "0x6051901ca58136188d0c4cb9cc32830040a412281b180443c192848800540080820a208138000082030404c70", + "0x8fb9586bdffebdfff3f7daff1fdff9efbefbbdcbfffebbfbd9affff7f2bdab7dffaf9afffff5f3ba9be7d66ffec7ef2", + "0x8fb9580b8e6ea15a72c1c272139340238c78bd8b5bec93e0c1abbc366039237dabaf1a7df5d572829be7546cfac3282" + }, + { + "0x10af96443b186faf790279bf3bbe0517d56ffc01e7fec8c88e765d48cc32333390224f4d762d1ba788c50801cba02524cb49", + "0x95d44e7344fb1701bace3ae83affbb6290bf282f7565b9a82c386823f5f213a53eccb2cfe5deb4dd040067a64ada8c1b6828599b96cc70647e7d19dc7dfba393addabe689ffbe1a36642bc9844b81c6c4c2e178", + "0x2c96442b084000000260ad288004028509b800c70640c080144548883032118022094d3608122408c1000181800400c148", + "0x95d44e7344fb1701bace3ae83affbb6290bf282f7565b9a82c386823f5f213a53ecdbaffe5dfb5dffef7f7a7dbfbbffb797d5fffd6de7fecfefdfffdfdffe3b3bffbbe6cffffe3f3fe7abcd8c4bcbe6e5e6eb79", + "0x95d44e7344fb1701bace3ae83affbb6290bf282f7565b9a82c386823f5f213a53ecdb836819d055bfef7f781d12937fb39550f6456d20f88f2f5feb9a97760b09ee3bc4c6b2c8372dc3a30c8c4a4a66e1e62a31" + }, + { + "0x5fc77dab8cd9c1da8c91eb7ba9c23ce85375b61bf3b9a8c4e4df7bc917aa8a14e747888c9756a2be2fd2e256e44194ce093a0185594de0dcf8340c45b6af7dbdc7682fbef6313f9f1cb234689d9f1ff603e1273faad89d0fe1ab57fbc7c32d29dce125fafc973754464b55ae5de58a8a5661c2065b95c2c94d7ec34", + "0xd4a9158961d4c11258cd047eda13d6804c16c3a374b7f4115bd835bde0b5", + "0x1080158800548100504504649012c480480081221420641158081495e034", + "0x5fc77dab8cd9c1da8c91eb7ba9c23ce85375b61bf3b9a8c4e4df7bc917aa8a14e747888c9756a2be2fd2e256e44194ce093a0185594de0dcf8340c45b6af7dbdc7682fbef6313f9f1cb234689d9f1ff603e1273faad89d0fe1ab57fbc7cf6fb9dcf73dfefdb7bfd447eff5bf7de5cbee7e77cb7f5b95ffcb5ffecb5", + "0x5fc77dab8cd9c1da8c91eb7ba9c23ce85375b61bf3b9a8c4e4df7bc917aa8a14e747888c9756a2be2fd2e256e44194ce093a0185594de0dcf8340c45b6af7dbdc7682fbef6313f9f1cb234689d9f1ff603e1273faad89d0fe1ab57fbc7ce67b8847738b6edb2bb8401a6f49335e14be66c5689791a807f4a16a0c81" + }, + { + "0x52cbea1f4d78445fb8f9267203f0f04bddf65b69b1acb0877143e77317f2d9679cb", + "0x331e156a1e1daa0039926a08ec80c2d7c1500bc435a53ebfc32fa398a3304fcd79d90725528e320add050da666b9de42b8307b", + "0x88421a41684412b839023200f0d00990725128a120a0805042666315e0090304b", + "0x331e156a1e1daa0039926a08ec80c2d7c1552ffeb5f5ffbfc7ffaf9ae7307fcf7dfddf65f69f3acbdd771dbe77b9ff6fbe79fb", + "0x331e156a1e1daa0039926a08ec80c2d7c155277a9451e93b86d42c0ac41070c27d64d840e41528c1d57219981188a16f2e49b0" + }, + { + "0xbde7e20f37c3ed822555d36050240dcfb5a9a3867d149cffe78e92b95573cbdde33a8c9495148e04cafa1325aae058b4a98c50f7019de1345de6dce12436bed4b86eca2d", + "0xee480b4096f0c1ac565d623dd53b62dba81c507d3c8e15372396fa49de0ecf074fb0ed1785f00f8094022ff50fc436a7cbd18de8ff317c33ea9bdbd8814a7658fcd1fd10b2ed10eaf7e4c2b8f409df3c36f1f0c986a49805a9ed08bbcd603e2eec9e18", + "0x547a00d1781e0020014022050040406a58981846814107c238a929950014a544038809410108c00caf20000a8e00894280450f00184a01005a0cc0020042014286c8a08", + "0xee480b4096f0c1ac565d623dd53b62dba81c507d3c8e15372396fa49de0ecfbfeff2ef37c7fd8fa5d5d36ff52fcdffb7ebf38ffdffbdfff7ee9bfbddf3cbfffbfeddfd95b6ef14eafff7e7baf459ffbdbef1f7c99fe5bc5deffde9bffffefebeeede3d", + "0xee480b4096f0c1ac565d623dd53b62dba81c507d3c8e15372396fa49de0ecfbaa852e220461d8da5c1d14fa52bc9f91262720b95ebad83d46409628df281abbbc65d6985a66314200df7e71214516b95baa107c81b45ac584f31e99ffbdeea96825435" + }, + { + "0x17ed0a1aa80542396e82ab79f6d4dda731d10f9487467fcfa5c8b501fa86488fbe268605c01beb257c9e301a42833d22965ea2ff0eda5f18427481a300a8f9aa81e76d774ea1dbed40268eca094bef627d2c206f6885fc12f71557bfda836", + "0x422340e8ff3b4177efa5f58111fe306aa602d8020164fa34c12acdb3de81e", + "0x2340604e21416540248480014a2062240000020004f810c10045b3da816", + "0x17ed0a1aa80542396e82ab79f6d4dda731d10f9487467fcfa5c8b501fa86488fbe268605c01beb257c9e301a42833d22965ea2ff0eda5f18427481a300a8f9aac3e76dffffbbdbffefa7ffcb19ffff6aff2ef86f69e5fe36f73fdfbfde83e", + "0x17ed0a1aa80542396e82ab79f6d4dda731d10f9487467fcfa5c8b501fa86488fbe268605c01beb257c9e301a42833d22965ea2ff0eda5f18427481a300a8f9aac3c42d9fb19a9a9aaf837b4b18b5df08db2ef86d69e10626363f9a0c04028" + }, + { + "0x290796408a0b8baa742b9d466afc4958528f7976fdce50caa83ed63285f58d200e4c65842ea24c3d4a3850a1824b61d25af9d3b41b9e64407a5262a75d9efd08481cfbc339ae26b0755438894b9e2298a35ed9", + "0x4cb6f7935f5cc586320c6ce957f82cff774cde7d4201735a5acd22190fcb1c9c16d1887a", + "0x4012f193141884040008406007580cfd00481c794201220210450018094b1c0010810858", + "0x290796408a0b8baa742b9d466afc4958528f7976fdce50caa83ed63285f58d200e4c65842ea24c3d4a3850a1824b61defeffd3ff5fdfe6727e7eebf7fdbeff7f4cdeffc339ff7efafd76398fcb9ebe9ef3defb", + "0x290796408a0b8baa742b9d466afc4958528f7976fdce50caa83ed63285f58d200e4c65842ea24c3d4a3850a1824b619eec0e40eb475be272763e8bf0a5b2027f04c2868138dd7ceab87621868082be8e72d6a3" + }, + { + "0x14e55ecb09d8c6827022df7c713c05a5d882e25782", + "0x2dbdb54cb6341fcea6f67cfaa5186aa0a91b9782e362cbb0dd0ef3cbc130ce0cb2ce7232c0562", + "0x10600e020898048060209c1000200124c002200502", + "0x2dbdb54cb6341fcea6f67cfaa5186aa0a91bdfd7eff2dfbcfd2ff3eff7f7dfccfadffa3ee57e2", + "0x2dbdb54cb6341fcea6f67cfaa5186aa0a91ad9d70fd2563cb529f1e636f7ddcce893fa1ce52e0" + }, + { + "0x2b0dfd23fc740e1759697bcba800aa1be7df28c59fe72b9869766ac34ecb4e5d0dbc74c2cbb5f734bb8d38dab59c3f22cdc706c657839580c2793c4c7660606548c048a697db3dfbad82e695c605", + "0x33080f6fd52aeca572f24a98ff19b9e7327c3b951ccfd8c9a6b9bd6f7c940079e4be88178a2a6d5a2b17", + "0x30007249108288030900a00cd0100c612001180004918482620206548800020849a0813880264100205", + "0x2b0dfd23fc740e1759697bcba800aa1be7df28c59fe72b9869766ac34ecb4e5d0dbc74c2fbbdff7fffaffcfff7fe7fbaffdfbfe777ffbf95defffccdf6f9fd6f7cd448fff7ffbdffafaaefdfef17", + "0x2b0dfd23fc740e1759697bcba800aa1be7df28c59fe72b9869766ac34ecb4e5d0dbc74c2f8bdf85b6ea7d47fc76e75ba32debf2165ffae15deb6e485d0d9dd0a345448df7365b5ec27a88bcfed12" + }, + { + "0xc0cc21922748d7626df1ab92b4ad4df1861050ca7de74adb92a140", + "0x3531a6880ccc47bc3826056efe912f3db02df9c0b6931e253ab9248f472359fe59218690f6781f35da89b8f1ff45cd5a1db9a414c9d7ec62ff5859a1572b1c1880a99aa74ebe8b12c68e791c11dd6cc0e5ed5", + "0xc40192054091400800898234a948b104004080410542c8020040", + "0x3531a6880ccc47bc3826056efe912f3db02df9c0b6931e253ab9248f472359fe59218690f6781f35da89b8f1ff45cd5a1db9a414c9d7ec6effda59a377af7e3edfbbbbaf4efedf1ae78f7dbfdffdedf9effd5", + "0x3531a6880ccc47bc3826056efe912f3db02df9c0b6931e253ab9248f472359fe59218690f6781f35da89b8f1ff45cd5a1db9a414c9d7ec6ef39a408323a66a3e5fb3238c046a540aa78b75bbcfa9c179cff95" + }, + { + "0x68cbb0a526d1fa61003e12401db51090fa4649b00b7be7465d0eb18f74c86157a919", + "0x1ca7d6f9bc3e11d3c365af63bf9499b6c7e9c569da7361f0214b8d", + "0x1610001c111080600641b00019a6464904218a704060010909", + "0x68cbb0a526d1fa7da7fefbfc3fb5d3d3ffef6bbf9ffbf7c7fdcff9df77e9f177eb9d", + "0x68cbb0a526d1fa7da7e8ebfc23a4c3539fe92a0f9fe25181b4cbd85507a99176e294" + }, + { + "0x210bef18d384992c5eb72e2b362c7296d9810f5ba9fd25e2d5648989d65095e45d1478f2a83140a0f68033a08fa3d7c392a3dc77e8e6aeba9ed76038e9e7825255fac990bf1098e6f9cba0", + "0xdb48641b3f63e5f1f41ff3b1578c4b190de42379d45cba03c4c6f34b1b14ea930fdff90dca53116710228e45b081fbddc9273a542e6f689642453adb91086bdb99681342113262d67f5517f2691024fe367459b01872549211067798063cc00b16c883b8cd2ffaa6d6116863f204bb23ce26c5bcdaf3e1b816dcf65ca", + "0x21014200d280002452a52800062c309681000113202d25e051640081024081644510008220010000660000208c00914080238c52e8a22c201686202049a20042445ac9803e108064c94180", + "0xdb48641b3f63e5f1f41ff3b1578c4b190de42379d45cba03c4c6f34b1b14ea930fdff90dca53116710228e45b081fbddc9273afeffef78dfd2c5fbfbf3bb6bdfb96d9b52f5baffd67f7d57faf99d65ff7e75d9f79f7ad7961b0f7f9b3e3cfa3f7ef9abbdcf7ffeeeffb9ed77f38ebf7bef27dfbcdbfbf1b99efffefea", + "0xdb48641b3f63e5f1f41ff3b1578c4b190de42379d45cba03c4c6f34b1b14ea930fdff90dca53116710228e45b081fbddc9252aeadfe250dfd080d1a973bb091cb0058b52e488fd04217841baf18d41f7683188f79758d7861b091f9b3c343a366af1a9850a5174cc3db88515f18a255beb039a1043f810b198b36ae6a" + }, + { + "0x143143205d76a7287d48be24db8fbfe37c291d82e103aa05cfc172fb920f0e8cc15c47de948b964e39be34a5b8a2610198c0c5b98543e6e727be153cfff0338f229cc22f029e04f766c62988634fee1a0a16880c93e5b10bada4018b6765b54c08f5710344dbfb9e9ad5dd7914cab496b22a6", + "0x2d58b8b513f4bceb8300f8b978e31c163f36155e9678bb0f221ee7cbcf7262b9d53c7a395ea916218fa2478baada74f3e69df63a7be0c9554c07004f9e4d869642bbd63a9fe07138a6aef7ad14c74231cf6401c597f9b6d15c266c42c28613838609bd4f4522c9eb65fc8456acc339c641ac7d7b7bc2c48c8f2", + "0x100201970a308140836045a8638a30c201c82c103220089c1307a100e0804010c0246808a924431a614a4382260011040050005024486060211143a902001208482270014044220c620004107e8120014000c02c080038184018947452048086570004488c31882418c79104a8084800a2", + "0x2d58b8b513f4bcffb343f8fd7ee73c7f7fbe35df9ffffb7f2b1fe7ebcffa67ffd57efbbb5faf9ee1dfe7df9fabde7efbfebdf7bafbe1c9ddccc7b9cfdfefe7b7febffefffff3ff3abeeeffaf9ec7f777cf6d89e7dfffbedb5eae6cd3e7b71bafa609bf6f65b7cdebf5fd8756fffbbfded5fd7d7ffbf6d6beaf6", + "0x2d58b8b513f4bcffb243d8e40e44346b7788318519c758730b03652accd86776144e81ab51a79ae0d3e5991f214c3aca58a95382d981c8cd8cc2b9caddab61b1fcaeeac56fd3fe1a3a6cd8af8ac3b557094d89a6d817acdb4aae60d12737182e22083628209785e3908d87127738a75c9471046fb176523ea54" + }, + { + "0x258e988b847b06b73462629161e28517f7b9ad7b5c19a9ad2c07f9a66f33fb2220fddb5a33b9cd5c2d63fd543efa1bef16e26b95484d70d0d7cfce28491ace0a608fb6cf9e97cb88d73c96c9150f9ef53c5e75bd68805fdce891e5935e9428ca67eba1e345148fcf2", + "0x1857c0e26e0476169cf804c8d5a431022cce0da75d7642a2414a900370f201f5073c7e700ff6626fbd8a104182954fa9f23a45474af5456a00e36f6a6c8162afdf7492d387a455dd8506167d5cc24e6861d7b480b1458230", + "0x1812c0a04000121280780040d12430020ccc05a319144082400a900360a000f10624385004d6000d3c880000808440a0003a44414874000800c16c0040816203c56412d2800455cc8106103548420c206092140011408030", + "0x258e988b847b06b73462629161e28517f7bdfd7f7ef9efed6dcff9eeef7bfb3222fdfbda77ffed7e2d77fd543fff3bff56f3eff748ff76f6ffdfef2c593bdefaffafb6dffebfdfdef73eb6ffb7cf9efffdff7dbd78fa5fddf8d1e5f7dfdc2ceee7fffbeb4f14dfef2", + "0x258e988b847b06b73462629161e28517f63cd1757af9eecc45c879eae269b83202313b80466ea9760977545409f53bf04691ac7248b216f62c176f2c51339af0ffac129bea389fde7732a03fb3c788dfc1a93c9050fa1a8130c184f48b580c2ce1f6daab4e00d7ec2" + }, + { + "0x328edc02c67d84bf095ac048e50c2dc29cffc08184b11e4da02904be14eccd317e9f6bdd6fe2b8233e8928d65d4ad434ef8a629cae6013bfb3c54be167e16371dc6412b62c2b1213424dfb7d391cea8a7494a28576ce823d8e111994182909efba7dd3533dbbe510dab4ac5ef", + "0x61a1365a1226597896c514f5bb16a064f6ff6982ac91ea568daa43e473aa63867bdb628e92e97ebd4f2091", + "0x4121224210201020968510918a00a04042284100a801c84001884180108a63865911228a92410ca94a0081", + "0x328edc02c67d84bf095ac048e50c2dc29cffc08184b11e4da02904be14eccd317e9f6bdd6fe2b8233e8928d65d4ad434ef8a629cae6013bfb3c54be167e16371dc661ab76dab3277d7cdff7d7f5ffbea76dfeff7feeecb3faf79dbb43e6f3befba7ffff73dfbef97fbf4fe5ff", + "0x328edc02c67d84bf095ac048e50c2dc29cffc08184b11e4da02904be14eccd317e9f6bdd6fe2b8233e8928d65d4ad434ef8a629cae6013bfb3c54be167e16371dc6208a5498a3076d5c4972c76475be072dbcd73eee44b232b79c330266e3349821a6ee51552cb8731605e57e" + }, + { + "0x37a92944b67fae733d201c024838975531bc3f748d98089eed38faed40c9463441cf48ac40e98097ce75db2bf0120ef69087a176d31d562cc99137c67e4a659cbb1298ba150aa191ced4089deee7048511de602414936af93cb2cef1b7ee801d9b75d961d33bb2958669b16193abf7b55ccfebac3a490415128dac92", + "0x6fb8d83d986c4604db1b9396493a0a68270806cdbcc3299a049ebe77bd6891258e6313c720fb1b30ae9c4387ba51db3325e15033d9e01d499707c138b4cf4b85032da65e9ce3aabc5effbf7003771476ff71e86f665d2d3e7578dfcbb8f08c1619f609ec147f0", + "0x88c811882c440490030014400a0008000804c51c822900008e2800380001218462008100780320a6184381280181102001102140801c4810004118a4024101022d824a0ce30a3c4801993001161432bb2148660214093a357855c8b8b080041040012810490", + "0x37a92944b67fae733d201c024838975531bc3f748d9efb9feff9feed60cdf7bd79efdbace6ebf097eeffdf3bf9b24ffff7fff7ffd35df63dfdf33ff7ff4aeddcbb7bbdbfb73aff95cffd9e9dfeff74fd13df6cf4bcd37afb7dfbcefbbfefefffff75ff71d77ff79f86fff5f3d3eff7bdfcffefacfb699f759ecdeff2", + "0x37a92944b67fae733d201c024838975531bc3f748d9ef3136ee17c292084f78d78abdb0ce66bf017a2ae171969b2471d77fc77ffc145b01df5e33877cd408c5883693da7a638ff84cde9969c3a7e74f902552cd0acc35823595b00cb1c2b6fe66c75ee109454458b009fd4b3404ca038a07464a4fb289b758c4ceb62" + }, + { + "0x1ab020d8beb54c354411f3a5658b5e5e87a896d7049c5eab20a302b6e35ca98364d7edd00eb3e209dcb035fe4b6eeace4e525229bf790c67bae63821e1282712d7c624efa64b3e5ad1a73aeb1033d4cd5949d63183173632445c9f488e74cd", + "0x4d706a200a7a70e0b6eeef2dbdb88779dd50af16e6405c17fd2c2efb5493cf13b730207a009a14ca150042af3e6b7f05230161a10073f87a56afede3c2cfd09857f78d7913cdd966e9a2e6e6e3", + "0x45000000a2a20a002a6e30ca9800451cd500e12e2005c10352c0a6a40824e1212202078000210c21000402826025704200120010052d02212ab0023c0cd5008563181111200404489008664c1", + "0x1ab020d8beb54c354411f3a5658b5e5e87a8dff76ebc5efb70e3b6feef7dbdbbe7fffdd0afb7e649dcb7fdfe6ffffedfcf53f739bf7b0cffbeee3d21e3af3f7bffc727efe7eb3e7bf9ff7eeffdf3d6cfd9d9d7f78f7f37ffdd7effeaeef6ef", + "0x1ab020d8beb54c354411f3a5658b5e5e87a8dba76ebc54d15043b4580c71143be3ae3080a1a5044980a7c8d26595be5d8141e5199f030cfdae2c2d21a3871979a8c307eec7ea3e2929dd6c44fdd0160289d181c60e6e25ff9d3a76ea68922e" + }, + { + "0x85993ec08ac960d46bcba87136f24042485c6d3e0a9973e828df60e537860d6bc83dafa7fb292beef466d0a939ab9da2b", + "0x4c9a310b11d6e4b4d29d7ede30fb42161fd6a58792440f416abda6df55913a8a26c35140524de5dd9519c30f19641f4f0863bfefc2ae6c89333dd77d6f688cffcbde281772cee0dac9bb0dd16b6c1d33fa7e39b2e781896dcc2b0aba3abedf1381f9f38eb210f5bd2001ea8453ceb136dc3915fabdc30709db0b1a07ec40be", + "0x811926c08a08601002c8803022a2004040180d1e0889210808d2000420040c6b002d83815b290820700490a1202a8402a", + "0x4c9a310b11d6e4b4d29d7ede30fb42161fd6a58792440f416abda6df55913a8a26c35140524de5dd9519c30f19641f4f0863bfefc2ae6c89333dd77d6f688cffcbde281772cee0dac9bb0dd16b6c1d7bfbfe39bef78dcffdfeaf1bff3ebeff97c7fbf3afb73ef7bdf60ffbfc73debdb7defb7ffabfffef4fff0b9b9ffddabf", + "0x4c9a310b11d6e4b4d29d7ede30fb42161fd6a58792440f416abda6df55913a8a26c35140524de5dd9519c30f19641f4f0863bfefc2ae6c89333dd77d6f688cffcbde281772cee0dac9bb0dd16b6c156a6992311e718ccfd176ac19d51ebafb96472a1327252e7730d60fb9fc33180db506c36a482f7de84fb601899d559a95" + }, + { + "0x4d9f3e8aae22123e382e7835d3d9d7e944a5c81cab3415fda40d0ec8fde8a50d8b21b2298f83a65bbdb10d120d302d8db4e9807715be0e", + "0x4dacc1a6f2cecd4179556cbbdfe1cedbc952de5232ff1fe1ae9c0c3bbfcd9087e4ed5bcd1f8c289b1456ef032d888", + "0xa48104308c4c004854008a93414eda4050cc02128a10c0a2180018b8080083c00051001300089b0410070109808", + "0x4d9f3e8aae22123e3cfefc3ffffdfffd57b5dedfbffe1dfdbc9d2fedffeff5ff9be9f2ebbfffff5bffffddbeddf8ef8db5edeef737fe8e", + "0x4d9f3e8aae22123e3cf4b42fbcf53b3d53309ed716ca09101898232ddec754f391c872ea347f7f53c3ffd8aedcc8ef0405acee87276686" + }, + { + "0x28d61d5ca1f56b4d3134009f478b17ac208a5b559d9c3726a7a16919e3b12ec6d61a142dc04d834141a9a4", + "0xb444947aba00d50e10326ebea7a2618a10144dde07c15c685d4785eae16d232eb741bc2a09b7cf794a33ed3598803ad61af", + "0xc00104a1e06a041020000445801404008050501c8c160222a16019c2a00a44d610002cc04980010121a4", + "0xb444947aba00d78f71f7eebff7b6f39b501dfdfeb7fbde68fdf7ddfbe37f6b7eb7d1be3b1bffef79eb73fd35d8b43ede9af", + "0xb444947aba00d78371e7a4a1f116b299501db9a6b6bb9e60f8f2dc33221f4954a1d022111b5ba218eb71313140b42ecc80b" + }, + { + "0x1b9a0b9c87fa234d05d06e18171cce3f8fc4adf7f75a402c4c5a281f46e714b96badab2184546aa11a7be482616cbb973da00e329628d3e692b69b43d34391884d87fcd64e2339fbb30044a370fffde97a128d1e5", + "0x7d641e556550c3ddb89ee553cbc0d8d92cdaec6519a2ff3bd792e0b309c24cb49056fb219ef4dfb2a72e76ac7df3407a44e55af5689e9c85c87e74d542dfb445f56a0a518c", + "0x78640a55655080008084a001c0405049049ac8201800462a1182a000000248b01052002108608d32212a60a43d30001804c05ac56082108588300440020fb4449520085184", + "0x1b9a0b9c87fa234d05d06e18171cce3fdfc5edf7f75e7dffcdfe7d3ffeef9dbbefafef719e7ffbbd7b7fefb2fd6cfbdf3defbe3bff6dfbeef2f7fbc7df7797ac4fd7ffd6cfebf9ffb7e74df77dfffdff7eb2ad1ed", + "0x1b9a0b9c87fa234d05d06e18171cce38598548a1a2567df7c5b47d23faea992ba6036d701e7b991c6355efb2fd4870de38cfbc2b796528cce051f1840c77962c03d25380c7caf1a734e709f75d04b9b62cb228069" + }, + { + "0x142cd4c71f04927a526ca430e542cd9432860", + "0x1337869f6c145daf15b226485ef3c48b8037bf7cb2cc9834153b90f55d4217a5e4a9ea133", + "0x142c90c41804103a106404000500c48022020", + "0x1337869f6c145daf15b226485ef3c48b8037bf7cf6cf9f34977bd2fdfd72f7e7edbdfa973", + "0x1337869f6c145daf15b226485ef3c48b8037ab50660b87308741c299f972f2e7293dd8953" + }, + { + "0x4f517f63e95a08284faaf4d4a290c334fc5d039e386727ddbb5d0a6d5fbb5540e97767023d60bedd158ed25051a6c56", + "0x9e2c9c6d2e3be2ad25733871aeba4ba64081294478f936f9c4fc45ada6bb2c098c98f21e709a88995cc3b0cf7e693f8e73f58f8f4735c81e8421182fc15426174f3b6da7b493135c", + "0x4f405a4269120008498a20c400808114cc190096200320c53b5808645318014040110200154020541186d2504120054", + "0x9e2c9c6d2e3be2ad25733871aeba4ba64081294478f936f9c4fd57ffbebfac8b8cfaff5f7abb8cbb5fc7f0ffffef7ffffbf5dfafd7fffd5e8eb77e7fe3d62fffdf7beda7b59b7f5e", + "0x9e2c9c6d2e3be2ad25733871aeba4ba64081294478f936f9c009525b982e8c8b08625d533ab384aa130660f69def4df3a8405f2992ce7d4a8ab66e5fe2822dfa9e638082b1897f0a" + }, + { + "0x1713f8f439c07e35b741ec9b0bca80149a7ef129c73c23c34b4515d29dc7dec711007fa395ced70f3bebc6d229edb75bf04231f2414e0a826f3edae4edcf770d59650cc252c6a2eff07fda9baa70938085d1e15144a451d26304d8f3df2406b8eb40f4fae3666780d2e54cd93a5f17439a4d3656dc5d48", + "0x328df4b64b0bd0fbea359666904ea4aa215b03727a70bda853b6cf612b12c3d56ee93b003bd00a7b9c1d6755f580b467deba33bf7f33da4c37fffe79e73e4381ad4bf1306d1b58f5eb276cae813d6f9153d1294c51098d37b3b80154da", + "0x108094864a0310006a219446900e20aa005201603250b00011b241400a0243144ae02900330008610c004244a080b067da9a22301300804021514420411243008843d12004184840e02260260100428140d1284c110188053210005448", + "0x1713f8f439c07e35b741ec9b0bca80149a7ef129c73c23c34b4537dffdf7dfcfd1fbffb797eed74fbfebe7db2bffff7bfdea73f6cf6f2b92effffeedffcf7fdd5b7f9cdf77d7f7eff47fdebbbbffffb3dfddf7fffefdf7fe6385fdfbff346fbbfbf5ffffefeee7bdfff55fd93b5f574b9f7fb7fedd5dda", + "0x1713f8f439c07e35b741ec9b0bca80149a7ef129c73c23c34b45275f697195ccc1fb959603a847419f41e7892a9fcd2b4dea62448e2f2190acebb40dd6cf4cdd531e90df3593576f4418042199cfecb35f9dd6aebaddb6ec208575b82e146ba3b3b51fdd8fc8e6bdbd741f081313464a177a85eedd0992" + }, + { + "0x68bc9c8f8257c6c88c0b2d46defc4539748fb906140acbf1a68820d1748bfc13ec84619f2b495d1ce74e0ca441a246497", + "0x2d30db90794c4b611858b19c973ea865904346738291751ba5fccc5cbf02c09876aca6bf23289174f545ad8039e0fbcefe359521dfc9681a7715e672fdc23cc446c7900851d2ed09568729c88bf9653c63f7e229893f31059e8b51924a54968d44e5bb26decae3159ce786d9b3a1454c6d6cb8108d22bd5111d2cc7eddb", + "0x68241c03824200880c0105068a50000854868904040a02d0828000906482d813a004400d2808100c220c0000408046493", + "0x2d30db90794c4b611858b19c973ea865904346738291751ba5fccc5cbf02c09876aca6bf23289174f545ad8039e0fbcefe359521dfc9681a7715e672fdc23cc446c7900851d2ed09568729c88bf9fdbceff7f7efc9bf3b2ddedffdd77b749fbd46f5bbefffeeeb35ddf78ffdb3edc56dff6ff95d9de7ff5db5d3ee7eddf", + "0x2d30db90794c4b611858b19c973ea865904346738291751ba5fccc5cbf02c09876aca6bf23289174f545ad8039e0fbcefe359521dfc9681a7715e672fdc23cc446c7900851d2ed09568729c88b91d9a0ec75b5ef41b33a28d855add77320193442f1b1ed2f6c6b354d930d25a04dc12df247f14d91c5f35db5936e3894c" + }, + { + "0x6eef644a36b1e052a413160909a537f81d46b2d330981f507d84737065541b5bb5faebfa8491dcd0347fbe498a501e254b91f6d82d6771a69d0aee5a490e2a44a8ba4f5da963d70b486f36f4a65f372a6a60522cac6e6a01d1a2da8743d5381", + "0x391d108a0ba169bb746b3d5816fa985288c230bdde7e3b8433f8d595b63f08a90448923f30926960cf736be42e377b087e68848af89d80d95122b942b0162153d9d665c0e3508d8a25c8862c0bb7ad4f00e4b1213326f5ce32433df12cb9", + "0x3004000a0a01280130601018127a8050080030098074038003300415003508090408800910800140cb6008a4002250081e688082701800d00020a000a004000380d4408021508482214802240332a406002080002220150a200034310081", + "0x6eeff5db3eb1fa56bfb756bbdda57ff99d6ebef33bddfff3fdc77ffd7d5f7bfbbffaeffba7f3ddf6b67fff7fbe52ff77fb97f6d86deff9fe9d9ffe7bdd2f2b66bdbfdf7ffd6ff70bd8ef7efce6dfbf7afef05e6fbe7f7a6fdde3feb7dfd7fb9", + "0x6eecf59b3e115a443fa450badc245851986e3ef03b45f8b3c5c74cfd3c0f78ab3f6aaf73a762d5f6a273497f3412fd52fb16105065c8f87e909ffc71dd252b26bd87d23bf56de20390cd6a7cc49f8c50be905c67be7d586e8d41feb49cc7f38" + }, + { + "0xa210334e6ffbec2fcfa42021075f84222c7", + "0x181b940df674ffa93b3346264fed88e40b8d8f252487bc1f2cb4c3284fa17145d2cd0c77102fc177898e53fb12c40525aeb017a57661a80a268f27b4c78cbb4bae0e96ed0065e32bc7dcb01be9cc4e6bd5db5e453e94855cb2d1d3f86e8218fe55035102fc10901add0eb539089af", + "0x821032440351002c0080000106150000087", + "0x181b940df674ffa93b3346264fed88e40b8d8f252487bc1f2cb4c3284fa17145d2cd0c77102fc177898e53fb12c40525aeb017a57661a80a268f27b4c78cbb4bae0e96ed0065e32bc7dcb01be9cc4e6bd5db5e453e94855cb2d1d3f86ea218ff5f6ffbeeffdfb43afd0fffbd2abef", + "0x181b940df674ffa93b3346264fed88e40b8d8f252487bc1f2cb4c3284fa17145d2cd0c77102fc177898e53fb12c40525aeb017a57661a80a268f27b4c78cbb4bae0e96ed0065e32bc7dcb01be9cc4e6bd5db5e453e94855cb2d1d3f86e2008cd1b6caaeed3df343afc09eabd2ab68" + }, + { + "0x2db0666cd0edeeab9e46e5b729521be3ece0714ffeefe18cd1b8b0f17e04c51b0d79fc6d428c22b9af63756", + "0x1c1d5f18453c10d365065465c676fb8b58cb436b88660a0e19c350feb1f6954caf029a43a3e59bb35ce0bdbf80a7b8ff4b4f5d7d133bd244df8813e9695b1a6af9cea293e5da9ce4f8e1035fc8ce4ca62ecbec89e89fe25053e4153899415f61c41fcb412f13b58ac70fb84077831497f", + "0x8906468c0014e888e44a426094009e08ce05043e4052088411820c01e00410b01318845028800318300156", + "0x1c1d5f18453c10d365065465c676fb8b58cb436b88660a0e19c350feb1f6954caf029a43a3e59bb35ce0bdbf80a7b8ff4b4f5d7d133bd244df8813e9695b1a6af9cea293e5ffbce6fcf1efffebde4ee7bfebfe9bebffe2715ffefff99dd1fff1f57fcfc53f1ffdfeef4fbc62ffaf77f7f", + "0x1c1d5f18453c10d365065465c676fb8b58cb436b88660a0e19c350feb1f6954caf029a43a3e59bb35ce0bdbf80a7b8ff4b4f5d7d133bd244df8813e9695b1a6af9cea293e5f72c829431eeb163500a4399e2be920b7302211c1afad91590e7d13561cf84341ecc76aa4d3462ce2c77e29" + }, + { + "0x33de1dc3fc5d6eeb5cbca27cc816a3727d1f9188400ea6b2c2799a40f7e611770b45cac7ed49fc0b66a46fcaf2393c0e03741bd08d26308fce62b0c56fbe44cb0949990bc3d4e5919ee1706dce518d6a06e865bdc26e761ef6723241b33583262bc4365103ba49dd17c0", + "0x148a80223564208532d09dd94cf189921325cad8f2a6a32568e36b2007f00866ce0c8e59034cac999f915817492737af76413832e2c4e840627b91b54766a1555e91b87b2692df16c41161184ac9a124d59aad5c06b1a61892cf5c0cd6cc628f764a161f1bdd6546cb51a1510eef5ddfbd", + "0x1121081d84c608910102048c812a222250881080006a00042480800510200240905804005492403262441083220040800601b9085062081444290806b2600cb004011010040c18104c1102d4c0081220080451c00464402867202001311812402c01001010a495d1780", + "0x148a8022356420b7fedddffd5dffebdebfa7fed8f6a7f37d7ff3eb600ff6bae6ff9eceffe75dff9bdfdbdfff49ff3feff66ffaf2fbfcee43767bd1bd6776afdf7eb1fd7fbed6df1fcd996bdbdeedb1bef5faedde57bdee1efaeffdcefefe7eff767a57bf3fdf676fcf77f153beefdddffd", + "0x148a8022356420b6eccd5e25119f62ceaf87b610e405d1587772e3600956baa4b796ceaee55ddb92da5b9ffa00db3cc9d22ef2c0dbf8e6431660413861562e9b3c217d1498d6141f8d886adb9e2c30ba34eac092573ccc1e7aaae1ceb8ba7c79047857ac2e5e436d0f67f052b4a680c87d" + }, + { + "0x683d881de1820ee9fbb71ccd74fd10e3a9ce71bd132955b9e9840d9259275498d2fae81b112416f37e9af907c319657d5d81623462b98d93818a23751a2196de6dd7c18e05960", + "0xa9a2ae43423e6c78cc59ceba6601f6d85397527c462767dceeb1ebc6ad425fb2810a2b7525", + "0xa880a002402e24688c104c300601d4d81203422800012018a2314182094046900008205120", + "0x683d881de1820ee9fbb71ccd74fd10e3a9ce71bd132955b9e9840d9259275498d2fafa3bf53437f7ff9efd9febbf657f7d857b7567fdeff7fdceeb7fbe6bd6ffffffd1aeb7d65", + "0x683d881de1820ee9fbb71ccd74fd10e3a9ce71bd132955b9e9840d9259275498d2f07231f5103515b9163c9b28bf056230045b41457defe5fc44c86ba64b42fb96ffd12cb2c45" + }, + { + "0xa827c5e2bd4293ed726065b32cac5c18d9df68b18300848f23f98c22fecd6b9fe7ed38a5adedd78f8dfe975d85c171f62b766947d7cd3d2ed3be52b50b792c0d6bb2701e28f22674a092e5ee0ec89bcd52680c6ae673a", + "0x1deac63a0a7ae71db949662f05aafcefed47a6c6dd5819dc82d250d978001903a1f19e1b8b44e76bd5899884bb97121fa13a63c33822314a486d29b59b66f141fd64af3414a3ea6bdca9b4362e704c744e8a12c1ab736636ca3aa9da4b75795f1a", + "0x202040a28c429068606045810c880c00099700018000040921b88402768d48998049382121e813860c328201048000d20b502047140d140ad30042340239080943226004004020202012a52602488388102004428471a", + "0x1deac63a0a7ae71db9496eaf7dfeffffed7ff7e6df5b3bdec7d3ddddfe8b1933a9f9fe3f9bc6efefd7b9fefefb9f5adffd7afbdff977f95e5f7f6bb7fff6fd7dfff6ef3ff5abfaffdee9f6bf2f71eeff6eef5ac9af7fe6fecbbefdfecbf7ff7f3a", + "0x1deac63a0a7ae71db9496cad79f4d73bc47971e0db032b164713dd448e8b0133a9b96c241386c887033066fa681d48c17c429b1cd157e9165f724b02fdf28c3d2eb6420ff188badc4e69628d0971aefb6ced58c8852d86da43867cfccbb3d73820" + }, + { + "0x1cc981657c8a20f5c777fc1df0e3cde0b23d434e043732dcaaa0758e009a8d1bf8591ff8db693d676eff2c39645b79c06b510ac22b1b47551eb728aa9404c24f2a6dee6bbdf2276759786f4116d21f4009dd6fb8e277976668bd021effecc797ca23682b97dbdffb93333834b8bb8fb68e922f42e3c00111", + "0x1e52f1e05fbedda88873e9984a7a19bfbfbe9ea43e30588f46317b5cadc8eb02d255875f1dde872476d05dec1164e46c7fcf3fd718fff34a80d4c6e951d10f6ae0225d00e3953e99e", + "0x61010a002b094200063608808400824b2a69ea43a10000644110254014821000015865b0c060124668050200164c4687c823682187db14a801002814181086a60200000221400110", + "0x1cc981657c8a20f5c777fc1df0e3cde0b23d434e043732dcaaa0758e009a8d1bf8591ff8db693d676eff2c39645b79c1ef7f1ec7fbffdfdd9fbfb9aeb7a5dbfffbedee6bfff7aff77b7fffcbdedebf6d2ddd7ff9fffff7676dbddedfffeec7d7fef3fd7b9ffffffb9f7f7eb5bdbbffbe8eb7ff4efbd3e99f", + "0x1cc981657c8a20f5c777fc1df0e3cde0b23d434e043732dcaaa0758e009a8d1bf8591ff8db693d676eff2c39645b79c18e7e14c7d0f69ddd9989b12e33a559b4d18404285ef7af933a6fda8bca5caf6d2c851a493f9fe52105b8dcdfe9a2815036d0955a1824eb539e7f56a1a5ab79188cb7ff4cda93e88f" + }, + { + "0xb77c8e0971a4f32bc9539c14b542ed2fa08e87560981cbdca4ccf4f7cc04fe7546a4a7eebe2592d131329fd591f66728a4179e", + "0x2fb77bc1694a8265e74ee9f41672fc681d72ea8eb65ef5807bcba4bc52ef9e381a4e4315a771497e506b734def1ca93dd519fe9e6944dd782380dff70b72798c", + "0x327c080970a08222485180108100ac02a08e0012080101842048745048004c6504a025c4182492410010180180d6670820118c", + "0x2fb77bc1694a8265e74ee9f416f7fcee1d73eeffbfdff79c7fffe6fd7fef9ebf5e4fc3dffff5cdfef7ef77ffff5eadbfffbfff9ef975fffff791fff72bf67f9e", + "0x2fb77bc1694a8265e74ee9f416c580e614034e7d9d97a61c6f7ee6517d4f10bf4c47c2de7bd5858aa7a777b39a5a0d9a3ba7db0cb875efe7f611299023d66e12" + }, + { + "0x89a0fbe80f4c622f45f4f7a15d8dc23bff17d939349f39cffa643af024db78243fc46c7948ab14ea12595e8a6cf2196ed4f353d9b1b8834b96fb61073301b99af019f042b2215e8cd5f31cf65123dab47d6b697a", + "0xc2b6f7a999af54a94c156f771b995b528", + "0x22215a8890f108944102d23039012128", + "0x89a0fbe80f4c622f45f4f7a15d8dc23bff17d939349f39cffa643af024db78243fc46c7948ab14ea12595e8a6cf2196ed4f353d9b1b8834b96fb61073301b99af019f04ebb6f7e9ddff75ef6d177fff5fdfffd7a", + "0x89a0fbe80f4c622f45f4f7a15d8dc23bff17d939349f39cffa643af024db78243fc46c7948ab14ea12595e8a6cf2196ed4f353d9b1b8834b96fb61073301b99af019f04e994e24154f06566290752dc5c4fedc52" + }, + { + "0x61cc2de53fe06a0381ce0dc4999795469453324c9036484632c257f02dddee71188198ed649bbe9ddae347178970bfbd3f1f28a787ee407a433f8473ba4fb77940227b769c9d555a8a70917ecfd038f80da4c6d5dc7211cc468c69a2275cfc119f145d2887543bbeb24", + "0x117135d192a9645062d1be59a1f8b151692159285e5877a0ae304521ad800f51fbba812d038e053cb79578c70cd34248a2b4026533bb961add83d9362893b74ce01695861c82b6f94f181feb4a957875c74cf1e7fe48dcc5196bf1214cc564f599168bf2fee1a07e617cfac992443fcdb28247", + "0x1c408050b000202018205c4811200420452124800340802200250302051ca71108010cd24008a09402243138960ad983d13208103644000411800402a4f947100223020148554508a1011648dc010900d0004c454421180408c29a20204e4118f04192003541b28204", + "0x117135d192a9645062d7bedbfffbff57e9395de8de59fff9fe794533adc90f75fffbad2d7f8eddfef795f8df8ed74bfbebfdae7573fb971bffd3f9f6aafbffece7b6b7fe5fbbb6fb7f9c1feffffdf9f5d7ecf7efffecfdc79febfb6d6ddde7f59dd6ebf6fee3f5ffe17dfbcdd2cc7fcfbbeb67", + "0x117135d192a9645062d7a29b7fab4f57c91945c88211eed9fa59001289490c357fd9ad087c8cd8e25084f0de82050bf34b69ac5142c30111265028c4a2ebc9a8e7b2a67e5bb91202388c1dccfdfcb1a092e456eee9a421c696eb2b6d2198a3d485d2e33464c3d5b1a0650b8c40cc4a8e096963" + }, + { + "0x1af3ce2ba6101f661c52430ae7280e3491d8d044a6621c3ef348c4e6e45fc6dfc91ec46b27214a9ebff52a0922fdebf1e895cd7cc4f428c64b7b3c4711b53f1f04f25b2f63ba70f281f52cb8149509f1ad38156397556eedf9e5c72388364cdba9112913", + "0x5c5811bd255dad9049ec956e6eeaa95895e56e1c5c03cbfe24ae065ac3f528fda51a966771d288dfe3aab7611232e6f6bde10cf0d97620ebde6370ab24dbdecd4d7783c05cc8579517951049f16b26cf1612f6344a669d93ac990a997dfb5180a07a75f6a20dc110fd5547e744cfe0b348cc1786d8c7f587dc83fd9e8fdb9", + "0xa00e02861011200452010885280a201010000426621c10c3088462041dc61708124429240042183c050801205169510095043044f02006434024411130091000925b25000a00a201602098100501502c30046203140cc1786584230834481b89002911", + "0x5c5811bd255dad9049ec956e6eeaa95895e56e1c5c03cbfe24ae07fffff7bafda5fef7e775f2aeffe3ebff7d9f36eef6bde3eff4dd7e6eeffe6ffcbbecdffeff5dffebff5ee8d7bfdfbf1ec9fdffeecf569ef6b7fbe6fd9bfff9fadf7dfbf7bba77f7dfff2cfc159fddf5ff7c5dff9f75eeedf9edcf7fd87fccfff9f9fdbb", + "0x5c5811bd255dad9049ec956e6eeaa95895e56e1c5c03cbfe24ae07f5ff17929ca4ecf7a255e226ad6349fe7c9f36ac909c22e3c455384eae220e8c3ac89d6cbf59de683f0e68c5bac92a0ec0adbcea80549e9283f9a2ec88ff68fad65849a7bb07755de9f0c64059adca5d34c599d9c61e22c81884b5cd04b84e470f9d4aa" + }, + { + "0xcd10bb69c381582eff7391a446db73312e738c6978564b350ca88e09cad650ef89dfb4cb00831c41d4739e957fdac00124348c91183da60b8f12dd3e349cad8b8d752fd9ea5613b1a41818032e0a2f2030790009a4fe9cdca54f96402b143e", + "0x7c4f944973a8882522976043833419c2c15b1531af1207b40092dd1e3c123a4cf06370c3111b", + "0x104d140010a888052007404202101180001801200a020030000009043c10180440024003101a", + "0xcd10bb69c381582eff7391a446db73312e738c6978564b350ca88e09cad650ef89dfb4cb00831c41d4739e957fdac00124348c91183da60b8f7edfbe7dffad8bad77bff9ebd737b9e6d95b173faf3f27b47992ddbefe9efeedfff770eb153f", + "0xcd10bb69c381582eff7391a446db73312e738c6978564b350ca88e09cad650ef89dfb4cb00831c41d4739e957fdac00124348c91183da60b8f6e92aa7def0503a857b8b9a9d527a866d943161fa53d27847992d4bac28ee6e9bff530e80525" + }, + { + "0x1cdc2579b3f1727c03a0f733c6a1a50025c8b51640ed21fb0e700f873d35c83797a14", + "0xe3e7298d39a9c7cd225125b1a01505e3d9ca63f8b494e4d7218b10e8bddc06984bbbe43e263f30f6a92a9d7", + "0x10042120110162580220f03084a085000100a0144004004b0a600e063d30c02102814", + "0xe3e7298d39a9c7cd225dfdb5f9b7f5f3fdcbe3ffb7d6e5f721afd8fdbfdcefb9fbbff43fa73f35febfbfbd7", + "0xe3e7298d39a9c7cd224df994d9a6f491a5c9c30f8752457221aed85dab9cebb9b0b59431a102053e9ebd3c3" + }, + { + "0x3ac7a7062a50d421ec7b732acfeafd988b5fe95661d371a7f2fdb5b9c1d37e304dd3a0dfcb995e9f99e1b86696b54df83fcd4e87764ffe27fbbd785875c31993f20f4628df79cbaeb50c3dfd132e20935f33ee0276c23f445dff5a075a8198907c1e248787fb28c44495d2e2ed677832432eeda5026afb91467cef4b8", + "0x12659e0b26181845981459681797ab57a50c5b4a34882e973f884d99c1e89c0457b99c9445be077039c60cffa057c608594d38423730d3eae76e8a8db6f946877e90bfecde4aaa320128ef3811cd31c3834e66fa7a61d1454778bf82781c091ae5fd348fd903d85116f83f331d84edaa925d1d65b0b30c1b7c6c69da380", + "0x20860306081044000459600287aa5580085b481400021127804d9181c0900410099080458a0150198000b820168408580d0842073043ea276a88081071420112900f44084a280200200c3811012000834e22ea0260c0054458bf0200180118807c14048103d800044015120084652812410c65a002081b104468ca080", + "0x127fdfaf263a58d5b9fc7b7b3fdfebffbd8f5feb76e9fff7bffafdbdf9e9df7e77fddfb4dfff9f7ebfdfedffe6d7f74df97ffd4eb776dffee7ffbffdfefdc79ffff2bfeefedffbfbafbdef3dfddf3fe3935f77fe7a77d37f477dffda7f5e899af5fd3eafdf87fb79d6fcbff3ffedeffab25f3fedb5b36efbfd6e7dff7b8", + "0x125f59ac20324891b9f8221b3d5841aa3d8704a362e9fde6987ab02c78294f7a67f44f349a759e2ea65fed47c6c17345a172f50cb0469c14c09537f5ee8c859eed62b0aaf695d3f9af9de305ecde1fe3101155147817137a032540d87f46888275812aab5e842379d2bcaae1ff698ad2a01e338815b166e0ed2a1535738" + }, + { + "0x39d2210d760b098917fd1293f0708ed6ffcd7686a4041e774a0f52e808524d686429da6774dd45dcf69abb4a7a48116d71f8e38074196cddf128b041a28cdc1e12cf755c7", + "0x59d65c9b948dab08f5c3604fb8b4d15085e4ae6ea8e762bbcceb904b3d9b5837977c4c9f2b9e9f3f8c6babd3b5e846ed8bdad898648bc4f8ccbea95d7a9cf5fd694e6b1a176058fbb30257aafa296741ab7181398c43a264a94972c08b4a5c56807a5f06b5b88eb420df822b43c43b400d0", + "0x284221095208080003c41080b0200c529cc5740004001a17400852a000520868202140237081018c42822008484000094058428070190495b008b00082800802000b400c0", + "0x59d65c9b948dab08f5c3604fb8b4d15085e4ae6ea8e762bbcceb904b3d9b5837977c4c9f2b9e9f3f8c6babd3b5f9d6ed8ffedb99ed9ffdfadffef9dffefffdffefee6f1e776a5ffbfb0a57effa6d6fdbef75dd7ddcf7baffeb7b7ad1ef7bfcf7807e5f6efdf9aeb461ff8eff5fd6ff755d7", + "0x59d65c9b948dab08f5c3604fb8b4d15085e4ae6ea8e762bbcceb904b3d9b5837977c4c9f2b9e9f3f8c6babd3b5d194cc86acd391ed9c39ea5f4ed9d3ac63388befea6f04602a57a95b0a05e7924d4e9bcc055c7c50b538dfe3333ad1e63ba4b5000e466a6849a604617d0ef75dd6f435517" + }, + { + "0xcf08fe64414998cc59938913e660f0f9b221f459cd8e04126cf902d0b6cea0edc26164b9d84e9ce7dfe058c1fe0fb452848616368c3", + "0x234286d14c1098ea9fd7f83508641ef3288da679fce09dd1359514ebf0dbcdc73b8f7f6171762d3d5df6492591c9386", + "0x4000910810806090d1b02100400c820000247900c094c0208500616099c84618875f6050402c0d145200041000082", + "0xcf08fe644149bbcedfd3cd13feeafffffa35fc7ddfff2c9feef9fef0bfdfb5fdd6ebf4fbddcfbfefffe179f7ff3ffdf6cda797ffbc7", + "0xcf08fe644149bb8edf42c5037e8a6f2e4a14fc3dd37d2c9fca80fe302b1f9578d68a94621589a768a08129b7d332e9a4cda387ffb45" + }, + { + "0x343e32e61b86c0c7cc895cf233ea3d5b5ad65435c1f87e034b59788a9af14ffae9249f1f3cfe0789abbe8edc8ce", + "0x63f7afb1dcebc9d65f9d468754ea558119988cb7d85e427003f2c1d9b360d2c75b97c1308ee3a7b5901044c6353e14f3e6b54a2ead64acdf914c6f7b6d4ed3205abdc78aa7bb47d548607b4ffe1db7331aac39c8bc7fcfd62238467352656a3ad04a423", + "0x241e10440b024046c00058b0038a251b42d4402041487e010311188818c00c7ac9040218047202012a3a8048002", + "0x63f7afb1dcebc9d65f9d468754ea558119988cb7d85e427003f2c1d9b360d2c75b97c1308ee3a7b5901044c6353e14f3e6b54a2ead64bcffb3ee7fffedcfdfa95efff7eabffb5fd75c75fbfffe1fff7b7aaebbf9ffffeff6bf3f7eff57edebbededecef", + "0x63f7afb1dcebc9d65f9d468754ea558119988cb7d85e427003f2c1d9b360d2c75b97c1308ee3a7b5901044c6353e14f3e6b54a2ead6498e1a3aa74fdad891fa9064ff4609ae01d031c55bab7801efc6a6226a339f38526f2bd277a8d55ecc1845e96ced" + }, + { + "0x981ba5db1da1fe952887e32cd21d51ba024022c8d837ec00f9772a111f87644012cee4a01f66d09ef168ebdfb91232e9e8f65d63ee7e6e050ae9707e7b15df4f8037b0d8d427f32429a45312a24081ed5a9c8ec22358f3621c961349638f30e049d00d513901fe065d5364f4cfca93f14a2b1b", + "0x1ba08accd8474ea8d9dc2f10d3c2c2edcbf9c3a909ab45", + "0x38000c048400c0019002e00514240e4cbc883a1082b01", + "0x981ba5db1da1fe952887e32cd21d51ba024022c8d837ec00f9772a111f87644012cee4a01f66d09ef168ebdfb91232e9e8f65d63ee7e6e050ae9707e7b15df4f8037b0d8d427f32429a45312a24081ed5a9c8ec22358f3621c9613497bafbaecd9d74ff9f9ddff16dfd3e6fdcffbd3f94bab5f", + "0x981ba5db1da1fe952887e32cd21d51ba024022c8d837ec00f9772a111f87644012cee4a01f66d09ef168ebdfb91232e9e8f65d63ee7e6e050ae9707e7b15df4f8037b0d8d427f32429a45312a24081ed5a9c8ec22358f3621c961349782fba2c919743f9e0ddd1168e91a6190433505843805e" + }, + { + "0x1d9992a4fce731fe937e70ec9efba437b1efa9e5459e3145f8c9142c6988eca9a61273750bcc1f00a64b32bab5a3a4c89858231f4fedce7a73bcc7285bbd18b328ccc298919f5511e973cd124f7e1c3912d52f4593c676f1c3f87a521", + "0x6e195204da93bdade43f0622217647326502417d70305d050d988", + "0x421810045011a921c412062200300210250001447030410008100", + "0x1d9992a4fce731fe937e70ec9efba437b1efa9e5459e3145f8c9142c6988eca9a61273750bcc1f00a64b32bab5a3a4c89858231f4fedce7a73bcc7285bbd18b328ccee99d39fdf93fdffed3f4f7e3d7f57f76f47d3ff76f1dffd7fda9", + "0x1d9992a4fce731fe937e70ec9efba437b1efa9e5459e3145f8c9142c6988eca9a61273750bcc1f00a64b32bab5a3a4c89858231f4fedce7a73bcc7285bbd18b328ccac81c39b8f8254de292d495c3d4f55e74a47d2bb06c19efd77ca9" + }, + { + "0x123b8aaf5660144d596f10574b4c232f267222596831", + "0x10ab460448ce805f18a3c1d64fc8cc0c02b2cd5f860d462e33602f09fd131e5468c86997e5a033729b2a03d3c284ee0111488ea", + "0x1021028c0600144801270012000c2028066000100820", + "0x10ab460448ce805f18a3c1d64fc8cc0c02b2cd5f860d462e33602f09fd133ffceafd6f97e5f5b7f39f7eb7d3f2f6ef2335de8fb", + "0x10ab460448ce805f18a3c1d64fc8cc0c02b2cd5f860d462e33602f09fd123decc23d0f96a175a5839e5eb711f076892334de0db" + }, + { + "0x17529608c59c36277d9e89f9b275032e62ab42b4dc006f1943e12b088c36657b02937109db797e2fbb83c984f507841be083c5e36dd04a8b7d3", + "0x1d556659e3b765044e08b1f7879bf057ef", + "0x1814004940304104080810368500a017c3", + "0x17529608c59c36277d9e89f9b275032e62ab42b4dc006f1943e12b088c36657b02937109db797e2fbbd7dfe5ff3ff65be4e3cfff7df9ff8f7ff", + "0x17529608c59c36277d9e89f9b275032e62ab42b4dc006f1943e12b088c36657b02937109db797e2fba569fe16b3cf24ba4634efc15a9f58e03c" + }, + { + "0x23ed0547893da2de2673832f9e6d988ce38c44a47495c1e0a714eb2f18ec455157cc20ea9da75cdcb0c4e9afa546efb3650b7e5cb7e659359d17fe79d2d5116bcd6c5cca45e0719d063e7df33f6788e5c6bd77c114340748cf553c5aa4992076953c4904181e24bb7c26a6e895d8b808c70133b52c9ca4a2266c2e2302bf777", + "0x3eaf5dd3cbba83558163fd16469a3d64905ff28ee65c15ff01f4d720b1ad669a893671bb614382f2331985333b0af52cbc0af22e50e4cb39d4ab3ad58127b3c481e692bb22dc0b497690e57e6fc84a87c2e1eb85e6c8bfc253fd497fc88", + "0x20aa1d83489880448123a50646922500105cb286401415170070d20011294408080241a061010232311105230800c42c340010240040cb11140a2091002691040104101a20980800268085582808420102a12884a48026400221003f400", + "0x23ed0547893da2de2673832f9e6d988ce38c44a47495c1e0a714eb2f18ec455157cc3eefddf7dffeb3d5e9effd56efbb7d6ffe5ff7eeff7d9dfffffdd7f5b1efeffeddfe75fb71df86fe7ffbbf77bbeff7bdffcbf63e57eccf7dfcfbbedda177b7fcc9e69abf26ff7f6ff6f8f5feffc8cf87f3f5ef9de6eabfee7fff4bfffff", + "0x23ed0547893da2de2673832f9e6d988ce38c44a47495c1e0a714eb2f18ec455157cc1e45c0749766339168cc5850a929586fee034568bf6988e8ff8d05f5a0c6abf6d5fc345b10de84cc4eeaba54b3ef3391cbcbe61a57ac046ce8f19e4ca15126f8c8e28aa50667776fd07870a6d7c08d86f154c719426a99ae7dde4bc0bff" + }, + { + "0x4881b1172db56487aa0b4362479871a57", + "0xd40bc374f241c2bb638ed6dea08d7885135052619d2f58523b3218b57371993a62bea6cfc8abf4abb8e4a96b0a38bbffffdd0bc5e5a6514f0db", + "0x4081210228b16487880b4160061041053", + "0xd40bc374f241c2bb638ed6dea08d7885135052619d2f58523b3218b57371993a62bea6cfc8abf4abb8eca9fb1f3dbfffffff0bc7e7e7d97fadf", + "0xd40bc374f241c2bb638ed6dea08d7885135052619d2f58523b3218b57371993a62bea6cfc8abf4abb8ac28da1d150e9b7877008687e1c93ea8c" + }, + { + "0x1e0e22b43b6de9f7ee3000e87eef492f84ee1bcd3f490cdbf35171b174335fe53afa9b752d9b1e1b0bd58d71d35687cb7b74", + "0xac57c7cfa532414e1182c7c499ffa996f7a28187f7f5d7586f0fd6b64e566bff1ff68daa60d7b650cfece99b8e2551941008aaa5ab966c526d584251600baf9f48d6b573e2779363363cea427961c0ac63d9c9abcc30976c3755b739dcbcccfbb7ae06b5deed54c59a5271caaa26134877898f75b065f3c72a8429ab5", + "0x40602140a4429948a30000876c3410b008c0bcc0f0908c0635160914411052518aa82612483181803510451105280421a34", + "0xac57c7cfa532414e1182c7c499ffa996f7a28187f7f5d7586f0fd6b64e566bff1ff68daa60d7b650cfece99b8e2551941008aaa5ab966c526d584251600baf9f48d6b573e2779363363cebe2fb6bc3beffdfffebcc3e97eef7d7ff7ffdbcdfffb7efbfb5dfff57c7bffe73efabb753d9f7e9bffdf8f7fff76afcbfbf5", + "0xac57c7cfa532414e1182c7c499ffa996f7a28187f7f5d7586f0fd6b64e566bff1ff68daa60d7b650cfece99b8e2551941008aaa5ab966c526d584251600baf9f48d6b573e2779363363ceba29b4a831abd46b748cc3e1082c3c74f773d001f0f2763b980c9f64386afac226503914191c6683fc8e8b2eef242f89e1c1" + }, + { + "0x46529c1d4b03b4a0efd29ce200ce9564cdc4fa4b53b9b6725e3fffe3454d6e53848fa573858f0bdbcf846d790a5bfc7470d0b8ac1d494804fa7048b869d5e016e389bf93cb959469dca3f4c5e93f8bcb7dbb64bcec19c8d9dbc5f2cecb285d81f5fefe99ff4564662c7cc275a40f0ea519adb2", + "0x1b10fed79bfd5e52ba14eea13cf223bfbeb5f42bd781083545c4306ed5f69250efc19707288aadf9df45b4056a293da0cfae076ee9b08e7a7058ef0a58e67149980cdc60a75825607ec4e531e9d036e71e3df52048853e3", + "0x1010d6c518485a523810e0a13cf0029790a5b4034701080041c4100045a6000086811601280889f91c01100408083d004e82002ca190864a40408c0818a4510888008440075825601ec4440060c004271a00f02040801a2", + "0x46529c1d4b03b4a0efd29ce200ce9564cdc4fa4b53b9b6725e3fffe3f54fef7bbfdfe57ba5cfebdbcfa67ffbeb5ffefd78d0bbfc5d4b4eedff796dbefdddf076ebabff9fffdfd47ffeb3fecdfbffffefffbbe7bfed9ff8fddfe7f6dfcbeddf8bf5fefe9fff4f777ebd7fee75e7df5ea599fff3", + "0x46529c1d4b03b4a0efd29ce200ce9564cdc4fa4b53b9b6725e3fffe2f442832a3b5a405824c1e1c800a65682e104bec908c03bf8410a4ee9a5196db695cc90646b23600e3fced43f7e302ec913dffd25e6b3831be997387c55a2e6574be59b8b807ca89e130b3778b17fac0447d05ca191fe51" + }, + { + "0x1c61ea1ba6135d29a669cc258f24a09ce0c6af1fa717", + "0x277557a8f45578e7730c64350cd3fd389bf96320fb3079402e9949062868fda63a6c371adf34952bd8fbf8a361671041556548ecabc7561f3febfcf26290dc819caa54b8eb26a7fb3a593202b2eb9a87fa214342ea4d639c3487882c7b6a03401d0715171c8ec44d45eff0c2571ca3f556d0d986fbeb5ff", + "0x10416008a4005408a60804218a24000c00802f1ea517", + "0x277557a8f45578e7730c64350cd3fd389bf96320fb3079402e9949062868fda63a6c371adf34952bd8fbf8a361671041556548ecabc7561f3febfcf26290dc819caa54b8eb26a7fb3a593202b2eb9a87fa214342ea4d639c3487882c7b6a03401d07d71fbdbee57dd7fff6ded75cf3ff5fdeddeefbfb7ff", + "0x277557a8f45578e7730c64350cd3fd389bf96320fb3079402e9949062868fda63a6c371adf34952bd8fbf8a361671041556548ecabc7561f3febfcf26290dc819caa54b8eb26a7fb3a593202b2eb9a87fa214342ea4d639c3487882c7b6a03401d06d309bd34a5789775965e954451bf5f1ed5ec0a112e8" + }, + { + "0x259856f9c56582b4f8056fdbd37332ff6684ad104683782087ef2b965fa2d22153ca880d735c116878afac5b2477b7f", + "0x1518494828299164e2ee455afe73cd24484df0def1e24c01926bdb2566d44e483a04bbdd5aeab159678305b6ade08cb5bc83e0e63a7bd9e2bb016c355f0fd9e94044e8e9dd380c64ea2f83d239d0987a6864dd1a07c9d742", + "0x20105268c4008210c8040e438331122b2004811040811800044e0a945380c20002c8080111080120000d80002415342", + "0x1518494828299164e2ee455afe73cd24484df0def1e24c01926bdb2566d44e483a04bbdd5aeab15967db85ffbdf6dcbfff83f6ffbf7ffbefff696ef55f6fffeb487efaf9fdfa2d66ff3fabd2fff5d97eefeeffdfb7cfff7f", + "0x1518494828299164e2ee455afe73cd24484df0def1e24c01926bdb2566d44e483a04bbdd5aeab15965da80d931b6d49ef303b61b874ceacd4d6926e45b67ee6b483a1a50b8c22146ff132b52eee5596cefee27dfb58eac3d" + }, + { + "0xd8526c4a399bb415b422ab254fb7c9a053c1507e3260aac195366c5fed9ff583053547f1b8f54561838e8d5fff273e25", + "0xdc8169197ca1b7f60394685c3438a5b9ff07c0deafe3d68064567be3d9ad3c577600e0d98c4bda37a6ed8175d437cded052bdf221c4c3d76221331061", + "0x4002480a30180400b42028044527882012c14076200008808434205a6c981501013446d010b540218082854221231021", + "0xdc8169197ca1b7f60394685c3dbda7fdff9ffbdfffe3feb274ff7ffbddbd3d57f726eafd9d5bfef7fefdff7df477ddff1fafdf761c7cfdf7fff373e65", + "0xdc8169197ca1b7f60394685c39bd837d5c9e7b9ff4a1fc3230ad0779dc9129509526ea759518bcf258347e2de46499921ea48b740474d5a3dde142e44" + }, + { + "0x47ac96c78ee0c7a9906ce5af63d0ad1b0420e1ca783cc6904ee84", + "0x630297e0f122e36f0c5f2f34efbb078c2f4c00e7c16f96cb054", + "0x20028780e002a1000c452f20c0a90304204000600046904a004", + "0x47ef96d7eef1e7ebff6cffaf77ffbf1f8c2fedcafffdef96cfed4", + "0x47cf94506e11e54aff60ba80573f161c880fadca9ffda90685ed0" + }, + { + "0x432a40ea48fcb8b8161bc19a26b544f54833bf5e005c7d1c19e8405c5464c8c139fdd9b627865e596c513fc68454827f070310dd7efe80306693ce441c89a74d91db5e27d6ba966aa1e109cc8385bd86a23d127cf609eea4118e0e1d9be83b561dcffb0ec3844d22", + "0x70d78d38ebcadb77733fc709a6d3b76576ca71acd7e3196640d6adc00225142070b943d5624a3a3d4e77a787d8221848ab06c5135", + "0x50c7880002481864410882008011b560744a212482021004401009c002211020402002c0400820214836838540001800a80044120", + "0x432a40ea48fcb8b8161bc19a26b544f54833bf5e005c7d1c19e8405c5464c8c139fdd9b627865e596c513fc68454827f070310df7ffed3befebfff773ffdf7dffdfb7e77febf9eeffff19fec8feffd86a27d527fff9dfff635afafddfffa7b7f9fefff8ef3ec5d37", + "0x432a40ea48fcb8b8161bc19a26b544f54833bf5e005c7d1c19e8405c5464c8c139fdd9b627865e596c513fc68454827f070310da738653beda3e79332f75d7d7fce02870ba1d8ca7dfd09fa88eef6186806c507bfd9dd3f2352dadc97c92432b9fee7f8473e81c17" + }, + { + "0x7c4c2d104ca2a5c080fbf1e717e47f848ff9be3555bcff60c07907ade9e334a556157dcd28ebbfd73367defdc4d8f5de60815360394e4de6e7535d356ccb8a2d896157ba65a7e8541a06e604454aef3e8cebfc7aedb48466eb65039cf17c13fcdb1b", + "0x2a73b2854f05d043d4e28e0b2634fd7023aaf3e57e58f213dd0693769", + "0x2a0100804e00404084e2880a2604ac50000262a45018c213c10681309", + "0x7c4c2d104ca2a5c080fbf1e717e47f848ff9be3555bcff60c07907ade9e334a556157dcd28ebbfd73367defdc4d8f5de60815360394e4de6e7535d356ccb8a2d896157ba65a7ef7f3a56f65d457fef3eecfbff7fffb6beefff77e79ff17dd3fdff7b", + "0x7c4c2d104ca2a5c080fbf1e717e47f848ff9be3555bcff60c07907ade9e334a556157dcd28ebbfd73367defdc4d8f5de60815360394e4de6e7535d356ccb8a2d896157ba65a54f6f325216594177a1166c599f353ab6bec9d532e613d041c395ec72" + }, + { + "0x3ee957090c3ab10e1c8af669f2093bba430a4322a741522d2ce1d20b07558298627de3dbbbef8828abc64195bad0f9f6acbb734a420d0d8dd330e90d23ab633826a612060eb95070758199006b547b24792d59f97c3191b2dee7a96e", + "0x7e30cfb7abf89648583c2f705f30abb997ded579a0de3172e2b546c920f92fbdf3bf5ffbd5d73620da518e7b4964a44505817d16c7028f4da494135d2589deffbfdb19f6a454f0431cda1884e51f48c67605f9f044e955a4f23da9dfa92af8dfba09ea6adf0390c", + "0x4e102090838a1061808e20122091028020a02228701502d2c415202050500802014424010480000284000949a4041348018114a420d018d42004904218921080600100406205010040091004b005a0478000989782090a28ce0290c", + "0x7e30cfb7abf89648583c2f73ffb5fbb9d7ffd5f9e8ff77ffe2b7ffed30fd3fbff7bf7ffbdfdf36b0ff59afff6ffebdffbff9ff9eff669f5fad9f9f7fefbffeffbfdbd9ffb75ef0d33efe3b86ef7f68e6ff95fff75cf9d5a6f77fbbdfbbffffdffb19fb6fff7b96e", + "0x7e30cfb7abf89648583c2f73b1a5db295475c598687157edc226fd6d105d1d9787aa7d291bca1690af09a7fd6eba99febb79ff9c7b669616099b8c37ee3eea5b9f0bc12b975a6091266c2b068f7e68a69d90fef71cf0c5a2477a1b983bff67487910f1473179062" + }, + { + "0x20265b43c9319cd56eac6a02cbf7913ba44b", + "0x995b92e854a8e0d548bfc02e18529b37790f0e4d9aaf36e7abc4a0f1e6d69489215aaa61b5863b1c86b3536b443dc639d1eb3db7789c2cb2f8cad1a74e5168ef33948c81a06fbad3b9ab0b7c84045cd1f77620ef43c7f2088d2901917bec5346a44f679be9491d273dbe5bf6e39095bb411cac63e38626013d671445c", + "0x20261901493010c0462c2802401390310448", + "0x995b92e854a8e0d548bfc02e18529b37790f0e4d9aaf36e7abc4a0f1e6d69489215aaa61b5863b1c86b3536b443dc639d1eb3db7789c2cb2f8cad1a74e5168ef33948c81a06fbad3b9ab0b7c84045cd1f77620ef43c7f2088d2901917bec5346a44f679be9491d273dbe5bf6e7b4bdbb59ddfeebe7a62ebf7d77be45f", + "0x995b92e854a8e0d548bfc02e18529b37790f0e4d9aaf36e7abc4a0f1e6d69489215aaa61b5863b1c86b3536b443dc639d1eb3db7789c2cb2f8cad1a74e5168ef33948c81a06fbad3b9ab0b7c84045cd1f77620ef43c7f2088d2901917bec5346a44f679be9491d273dbe59f48624a92858d1fa8925260abe4474ae017" + }, + { + "0x20a92c71c161a786989694109718416d7a291b8f9c71a5a71ee827e003a5a19cf2aa8faeecbfa231c330e2d4c747b75ccc4d43d8c37472b60", + "0xc2ba3ef844b62f020cd6e4b010499c2c28ab3c15ed2ef3114e5b806244e57be1a7d999a21399c1e950977f021c82a906bed39caeec6aa077628421f9d5dfed01b24fe857000e259537fbe07d6a83080080ae927512d4518f9a56f0a40376234855377d8ef40dcb6055bd8d351", + "0x20282071400021809096840092084045000801851471a0250a80000000a480141280018e8816a020033022404507350cc40d4340413400340", + "0xc2ba3ef844b62f020cd6e4b010499c2c28ab3c15ed2ef3114e5b806244e57be1a7d999a21399c1e950977f021c82a906bed39caeecebac77e3e5a7ffdddffd11b75fe97f7a2f3f9fbffbe5ff7eeb2fe083afb3fdf2fedfaffefff2b5c376e3dcd777ffdefc4dcbf8d7fdffb71", + "0xc2ba3ef844b62f020cd6e4b010499c2c28ab3c15ed2ef3114e5b806244e57be1a7d999a21399c1e950977f021c82a906bed39caeccc38c06a3e5867f4d4979112557a93a7a273e1aab8a45da746b2fe0830b33e9e07ede2176e95295c046c19c9270cad2384088b896c9ff831" + }, + { + "0xf6b7f399370d10b097b17e514f044d77a8f170148f4837033bb5d425f73a4079e1c7a9c3e69246f902d8c9fd27caad1e93d83578d4af8d3b7b1c02041c44917a22ed56f2562ac1426a356f8d31965e8e367b8929f3907b1dc6e73a8f3a566ca5c4e113e9d2c53770b110df51cf504701ff3fcea5b819b9bfc49f", + "0x61989df2b7097a6a84dc016aec2716d9cac359d2d799d90ec006a66efe3f1fd0851978c4cfe2f64b307b852e23f5dfdc2f63196e1076782a228a46f5f7d4e54afc1ad7abf1f8fef46edaad1706956f95eb95953bd4", + "0x990290097822808c0002c82510d08a8119521400000c40002222ec1612500001404005628401105a8426238109d0006319460032082a020804c4e110e142c41250a110d850c440420117068425900991950094", + "0xf6b7f399370d10b097b17e514f044d77a8f170148f4837033bb5d425f73a4079e1c7a9c3e6f3defdf2ffc9ff6fcefd1ffbfc377eddefcf7bfbdf9bdd1ec497fe6eff7fffd6afd97aeeffefff7bb67f8f3e7bfdffffbf7b1deef77eff3a76eee7f5f7d7eddafd3ff7bbf1ffffff7edfadff3fdfefbdfbbdbfffdf", + "0xf6b7f399370d10b097b17e514f044d77a8f170148f4837033bb5d425f73a4079e1c7a9c3e6f3de64f06fc0874d4e711ff934126e0d654e62a9cb9bdd128497dc4c1369ed86afd83aaefa8d7b7aa6250b18587cf62fbf1804a8f74cf71074e6e33116c70c98392da71ae127af3b3e9dace8395bca2df22c2aff4b" + }, + { + "0x31d126e874580b754389fad8b64aaa61cabb4f8eb6904fe7e504341ed903f7daa3e74d4da3afca80b2415672a", + "0x16fb17a0468c0afa6bad456efa4f9baf26860eda9d7c00c2520c8c9b6026fb50df59b8cb74f6d9be861052c5e831158e7ffd98746328ce11f91d9ea22f0803a8b059aea22d1715ca1abeae53a8bc6b8bfb9b6c9d24ae714767", + "0x11100e0745803440288e0189048aa20c0800a8a04904a22c10014008902e51a83c6080da1a6c880024114722", + "0x16fb17a0468c0afa6bad456efa4f9baf26860eda9d7c00c2520c8c9b6026fb50df59b8cb74f6d9be861052c5eb3d17eefffd98f77738dfbdfb7dbea63fabb7f8fb79aefe7f5757cbffbebf7faabe7fdffbbbfcbd2fae75676f", + "0x16fb17a0468c0afa6bad456efa4f9baf26860eda9d7c00c2520c8c9b6026fb50df59b8cb74f6d9be861052c5eb2c07e0f8b818c3371051bc7279340433a3b7505b30aa5c5347568bf72e912e02821f5f21a190352f8a64204d" + }, + { + "0xbf1a14e469c234b72d56324d100e016bc38cdf7158e35f230c047585e7b107acc8e222e7f19552541e59316affd90e96ca657b6112f5e8c786dfcff342fc46252fcdab10c632578540dbf6235f164bc5711924c7c6ba9da85ab", + "0x5dd3fb9a3de26cd89eb9517af6bb25678f149f906e8751a0c20d7646d21c17191237022a990e0156541e376986fd6a680c60228e5955df08bae5789c81751cdcafe5a2e72d45b09", + "0x5d5158821d220c001481413006a800620204919042041000000876400214020112210220880600564412026806252a480800020251054008b22158140145101824c582a20d00109", + "0xbf1a14e469c234b72d56324d100e016bc38cdff3fbfb7fe36cdcffbdf7fbf7bfede7aff7ff957ed75ff9f36fffdfde9edf7d7b7712fff9cf87dfdfff77fdc6fd6fedaf70e6be5fd5dfdbfee77f9ecbf57dddafe7e6ffbdedfab", + "0xbf1a14e469c234b72d56324d100e016bc38c82a2a37962c160dceb3cb6cbf117ed85adf36e053cd34ff9f367899fdc8add7c695610df71c987899bed7595c0d845a5a770e4bc0ed09fd34cc6278acab06dc58b22645db0edea2" + }, + }; + + bool opa=true, opo=true, opx=true; + + //////////////////// AND //////////////////// + + for (size_t i=0; i and + // Exponentiate(). It can easily consume all machine memory because it is an exponentiation + // without a modular reduction. + + // ****************************** DivideByZero ****************************** + + { + try { + Integer x = Integer(prng, 128) / Integer::Zero(); + result=false; + } catch (const Exception&) { + result=true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // The 0*0 % 0 test. + { + try { + Integer x = 0; + Integer y = 0; + Integer z = ModularMultiplication(y, y, x); + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // Another 0*0 % 0 test. + { + try { + Integer x = 0; + Integer y = 0; + Integer z = (y * y) % x; + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // The 0^0 % 0 test. + { + try { + Integer x = 0; + Integer y = 0; + Integer z = ModularExponentiation(y, y, x); + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // Another 0^0 % 0 test. + { + try { + Integer x = 0; + Integer y = 0; + Integer z = EuclideanDomainOf().Exponentiate(y, y) % x; + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // Integer divide by 0 + { + try { + Integer r=1, q=1, a=1, d=0; + Integer::Divide(r, q, a, d); + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + // Another Integer divide by 0 + { + try { + Integer q=1, a=1; word r=1, d=0; + Integer::Divide(r, q, a, d); + result = false; + } + catch(const Integer::DivideByZero&) { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer DivideByZero\n"; + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Integer DivideByZero\n"; + + // ************************ RandomNumberNotFound ************************ + + try { + // A run of 71 composites; see http://en.wikipedia.org/wiki/Prime_gap + Integer x = Integer(GlobalRNG(), 31398, 31468, Integer::PRIME); + result=false; + } catch (const Exception&) { + result=true; + } + + pass = result && pass; + if (result) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Integer RandomNumberNotFound\n"; + + // ************************ Carmichael pseudo-primes ************************ + + result=true; + if (IsPrime(Integer("561"))) + result = false; + if (IsPrime(Integer("41041"))) + result = false; + if (IsPrime(Integer("321197185"))) + result = false; + if (IsPrime(Integer("5394826801"))) + result = false; + if (IsPrime(Integer("232250619601"))) + result = false; + if (IsPrime(Integer("974637772161"))) + result = false; + + pass = result && pass; + if (result) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Carmichael pseudo-primes\n"; + + // ****************************** Integer Double ****************************** + + try { + Integer x = Integer::One().Doubled(); + result = (x == Integer::Two()); + } catch (const Exception&) { + result=false; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer Doubled\n"; + + // ****************************** Integer Square ****************************** + + try { + Integer x = Integer::Two().Squared(); + result = (x == 4); + } catch (const Exception&) { + result=false; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer Squared\n"; + + try { + Integer x = Integer::Two().Squared(); + result = (x == 4) && x.IsSquare(); + } catch (const Exception&) { + result=false; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Integer IsSquare\n"; + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Squaring operations\n"; + + // ****************************** Integer GCD ****************************** + + { + for (unsigned int i=0; i<128; ++i) + { + Integer x, y; + switch(i%2) + { + case 0: + { + AlgorithmParameters params = + MakeParameters("BitLength", 256)("RandomNumberType", Integer::PRIME); + x.GenerateRandom(prng, params); + y.GenerateRandom(prng, params); + break; + } + case 1: + { + x = MaurerProvablePrime(prng, 256); + y = MihailescuProvablePrime(prng, 256); + } + } + + if (x != y) + { + result = (RelativelyPrime(x, y) == true); + pass = result && pass; + + if (!result) + std::cout << "FAILED: Integer GCD\n"; + } + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " GCD operations\n"; + } + + // ******************** Integer Modulo and InverseMod ******************** + + // http://github.com/weidai11/cryptopp/issues/602 + // The bug report that uncovered the InverseMod problems + { + Integer a("0x2F0500010000018000000000001C1C000000000000000A000B0000000000000000000000000000FDFFFFFF00000000"); + Integer b("0x3D2F050001"); + + result = (Integer("0x3529E4FEBC") == a.InverseMod(b)); + pass = result && pass; + if (!result) + std::cout << "FAILED: InverseMod operation\n"; + } + + // Integer Integer::InverseMod(const Integer &m) + // Large 'a' and 'm' + for (unsigned int i=0; i<128; ++i) + { + Integer a(prng, 1024), m(prng, 1024); + a++, m++; // make non-0 + + Integer x = a.InverseMod(m); + Integer y = (a % m).InverseMod(m); + Integer z = (a * y).Modulo(m); + + if (RelativelyPrime(a, m) == true) + result = (x == y) && (z == 1) && (ModularMultiplication(a, x, m) == 1); + else + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: InverseMod operation\n"; + } + + // Integer Integer::InverseMod(const Integer &m) + // Corner cases like 0, 2m-1 and 2m+1 + for (unsigned int i=0; i<128; ++i) + { + Integer a(prng, 1024), m(prng, 1024); + a++, m++; // make non-0 + + // Corner cases + int j = i % 12; + switch (j) + { + case 0: + a = -1; break; + case 1: + a = 0; break; + case 2: + a = 1; break; + case 3: + a = m-1; break; + case 4: + a = m; break; + case 5: + a = m+1; break; + case 6: + a = 2*m-1; break; + case 7: + a = 2*m; break; + case 8: + a = 2*m+1; break; + case 9: + a = (m<<256)-1; break; + case 10: + a = (m<<256); break; + case 11: + a = (m<<256)+1; break; + default: + ; + } + + Integer x = a.InverseMod(m); + Integer y = (a % m).InverseMod(m); + Integer z = (a * y).Modulo(m); + + if (RelativelyPrime(a, m) == true) + result = (x == y) && (z == 1) && (ModularMultiplication(a, x, m) == 1); + else + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: InverseMod operation\n"; + } + + // Integer Integer::InverseMod(const Integer &m) + // Large 'a', small 'm' + for (unsigned int i=0; i<128; ++i) + { + Integer a(prng, 4096), m(prng, 32); + a++, m++; // make non-0 + + Integer x = a.InverseMod(m); + Integer y = (a % m).InverseMod(m); + Integer z = (a * y).Modulo(m); + + if (RelativelyPrime(a, m) == true) + result = (x == y) && (z == 1) && (ModularMultiplication(a, x, m) == 1); + else + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: InverseMod operation\n"; + } + + // Integer Integer::InverseMod(word m) + // Small 'm' using word + for (unsigned int i=0; i<128; ++i) + { + Integer a(prng, 4096); word m; + prng.GenerateBlock((byte*)&m, sizeof(m)); + + a++; // make non-0 + if (m == 0) m++; + + // Avoid the conversion from word to long + Integer mi = Integer(Integer::POSITIVE, 0, m); + Integer ri = a % Integer(Integer::POSITIVE, 0, m); + + Integer x = Integer(Integer::POSITIVE, 0, a.InverseMod(m)); + Integer y = Integer(Integer::POSITIVE, 0, ri.InverseMod(m)); + Integer z = Integer(Integer::POSITIVE, 0, (a * y).Modulo(m)); + + if (GCD(a,mi) == 1) + result = (x == y) && (z == 1); + else + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: InverseMod operation\n"; + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " InverseMod operations\n"; + + // ****************************** Integer Divide ****************************** + + // Divide (Integer &r, Integer &q, const Integer &a, const Integer &d) + for (unsigned int i=0; i<128; ++i) + { + Integer r, q, a(prng, 1024), d(prng, 1024); + Integer::Divide(r, q, a, d); + + Integer xr = a % d; + Integer xq = a / d; + result = (r == xr) && (q == xq); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Divide operation\n"; + } + + // Divide (word &r, Integer &q, const Integer &a, word d) + for (unsigned int i=0; i<128; ++i) + { + word r, d = prng.GenerateWord32(); + Integer q, a(prng, 1024); + Integer::Divide(r, q, a, d); + + Integer xr = a % Integer(Integer::POSITIVE, 0, d); + Integer xq = a / Integer(Integer::POSITIVE, 0, d); + result = (Integer(Integer::POSITIVE, 0, r) == xr) && (q == xq); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Divide operation\n"; + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Divide operations\n"; + + // ****************************** Integer Power2 ****************************** + + { + Integer x, y; + + x = Integer::Power2(0); + result = (x == 1); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Power2 operation\n"; + + x = Integer::Power2(1); + result = (x == 2); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Power2 operation\n"; + } + + for (unsigned int i=0; i<128; i+=2) + { + Integer b = 2, m(prng, 2048); + + Integer x = EuclideanDomainOf().Exponentiate(b, i) % m; + Integer y = Integer::Power2(i) % m; + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Power2 operation\n"; + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Power2 operations\n"; + + // ****************************** Integer Exponentiation ****************************** + + { + word32 m = prng.GenerateWord32(); + if (m == 0) m++; + + Integer z = Integer::Zero(); + Integer x = ModularExponentiation(z, z, m); + Integer y = EuclideanDomainOf().Exponentiate(z, z) % m; + result = (x == y) && (x == 1); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // The 0^0 % 0 test. + { + try + { + Integer x = 0; + Integer y = ModularExponentiation(x, x, x); + result = false; + } + catch(const Integer::DivideByZero&) + { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // Another 0^0 % 0 test. + { + try + { + Integer x = 0; + Integer z = EuclideanDomainOf().Exponentiate(0, 0) % x; + result = false; + } + catch(const Integer::DivideByZero&) + { + result = true; + } + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // Run the exponent 0 to 128 on base 0 + for (unsigned int i=0; i<128; i+=2) + { + Integer b = 0, m(prng, 2048); + + Integer x = ModularExponentiation(b, i, m); + Integer y = EuclideanDomainOf().Exponentiate(b, i) % m; + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // Run the exponent 1 to 128 on base 2 + for (unsigned int i=0; i<128; i+=2) + { + Integer b = 1, m(prng, 2048); + + Integer x = ModularExponentiation(b, i, m); + Integer y = EuclideanDomainOf().Exponentiate(b, i) % m; + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // Run the exponent 0 to 128 on base 2 + for (unsigned int i=0; i<128; i+=2) + { + Integer b = 2, m(prng, 2048); + + Integer x = ModularExponentiation(b, i, m); + Integer y = EuclideanDomainOf().Exponentiate(b, i) % m; + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + // Run the exponent 0 to 24 on random base + for (unsigned int i=0; i<24; ++i) + { + Integer b(prng, 32), m(prng, 2048); + + Integer x = ModularExponentiation(b, i, m); + Integer y = EuclideanDomainOf().Exponentiate(b, i) % m; + result = (x == y); + + pass = result && pass; + if (!result) + std::cout << "FAILED: Exponentiation operation\n"; + } + + if (pass) + std::cout << "passed:"; + else + std::cout << "FAILED:"; + std::cout << " Exponentiation operations\n"; + + return pass; +} +#endif + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat3.cpp b/extension/third_party/cryptopp/validat3.cpp new file mode 100644 index 00000000..e393a8c2 --- /dev/null +++ b/extension/third_party/cryptopp/validat3.cpp @@ -0,0 +1,1322 @@ +// validat3.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "rng.h" +#include "drbg.h" +#include "darn.h" +#include "osrng.h" +#include "rdrand.h" +#include "mersenne.h" +#include "padlkrng.h" +#include "randpool.h" + +#include "gzip.h" +#include "channels.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_VER >= 1500) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +bool ValidateAll(bool thorough) +{ + bool pass=TestSettings(); + pass=TestOS_RNG() && pass; + pass=TestRandomPool() && pass; +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + pass=TestAutoSeededX917() && pass; +#endif + // pass=TestSecRandom() && pass; +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + pass=TestMersenne() && pass; +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + pass=TestPadlockRNG() && pass; + pass=TestRDRAND() && pass; + pass=TestRDSEED() && pass; +#endif +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + pass=TestDARN() && pass; +#endif +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + // http://github.com/weidai11/cryptopp/issues/92 + pass=TestSecBlock() && pass; + // http://github.com/weidai11/cryptopp/issues/602 + pass=TestIntegerOps() && pass; + // http://github.com/weidai11/cryptopp/issues/336 + pass=TestIntegerBitops() && pass; + // http://github.com/weidai11/cryptopp/issues/64 + pass=TestPolynomialMod2() && pass; + // http://github.com/weidai11/cryptopp/issues/360 + pass=TestRounding() && pass; + // http://github.com/weidai11/cryptopp/issues/242 + pass=TestHuffmanCodes() && pass; + // http://github.com/weidai11/cryptopp/issues/346 + pass=TestASN1Parse() && pass; + // https://github.com/weidai11/cryptopp/pull/334 + pass=TestStringSink() && pass; + // Always part of the self tests; call in Debug +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + pass=TestAltivecOps() && pass; +# endif + // Always part of the self tests; call in Debug + pass=ValidateBaseCode() && pass; + // https://github.com/weidai11/cryptopp/issues/562 + pass=ValidateEncoder() && pass; + // Additional tests due to no coverage + pass=TestCompressors() && pass; + pass=TestSharing() && pass; + pass=TestEncryptors() && pass; + pass=TestX25519() && pass; + pass=TestEd25519() && pass; +#endif + + pass=ValidateCRC32() && pass; + pass=ValidateCRC32C() && pass; + pass=ValidateAdler32() && pass; + pass=ValidateMD2() && pass; +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + pass=ValidateMD4() && pass; +#endif + pass=ValidateMD5() && pass; + pass=ValidateSHA() && pass; + + pass=ValidateKeccak() && pass; + pass=ValidateSHA3() && pass; + pass=ValidateSHAKE() && pass; + pass=ValidateSHAKE_XOF() && pass; + + pass=ValidateHashDRBG() && pass; + pass=ValidateHmacDRBG() && pass; + + pass=ValidateTiger() && pass; + pass=ValidateRIPEMD() && pass; + pass=ValidatePanama() && pass; + pass=ValidateWhirlpool() && pass; + + pass=ValidateSM3() && pass; + pass=ValidateBLAKE2s() && pass; + pass=ValidateBLAKE2b() && pass; + pass=ValidatePoly1305() && pass; + pass=ValidateSipHash() && pass; + + pass=ValidateHMAC() && pass; + pass=ValidateTTMAC() && pass; + + pass=ValidatePBKDF() && pass; + pass=ValidateHKDF() && pass; + pass=ValidateScrypt() && pass; + + pass=ValidateDES() && pass; + pass=ValidateCipherModes() && pass; + pass=ValidateIDEA() && pass; + pass=ValidateSAFER() && pass; + pass=ValidateRC2() && pass; + pass=ValidateARC4() && pass; + pass=ValidateRC5() && pass; + pass=ValidateBlowfish() && pass; + pass=ValidateThreeWay() && pass; + pass=ValidateGOST() && pass; + pass=ValidateSHARK() && pass; + pass=ValidateCAST() && pass; + pass=ValidateSquare() && pass; + pass=ValidateSKIPJACK() && pass; + pass=ValidateSEAL() && pass; + pass=ValidateRC6() && pass; + pass=ValidateMARS() && pass; + pass=ValidateRijndael() && pass; + pass=ValidateTwofish() && pass; + pass=ValidateSerpent() && pass; + pass=ValidateSHACAL2() && pass; + pass=ValidateARIA() && pass; + pass=ValidateCHAM() && pass; + pass=ValidateHIGHT() && pass; + pass=ValidateLEA() && pass; + pass=ValidateSIMECK() && pass; + pass=ValidateSIMON() && pass; + pass=ValidateSPECK() && pass; + pass=ValidateCamellia() && pass; + pass=ValidateSalsa() && pass; + pass=ValidateChaCha() && pass; + pass=ValidateChaChaTLS() && pass; + pass=ValidateSosemanuk() && pass; + pass=ValidateRabbit() && pass; + pass=ValidateHC128() && pass; + pass=ValidateHC256() && pass; + pass=RunTestDataFile("TestVectors/seed.txt") && pass; + pass=RunTestDataFile("TestVectors/threefish.txt") && pass; + pass=RunTestDataFile("TestVectors/kalyna.txt") && pass; + pass=RunTestDataFile("TestVectors/sm4.txt") && pass; + pass=ValidateVMAC() && pass; + pass=ValidateCCM() && pass; + pass=ValidateGCM() && pass; + pass=ValidateXTS() && pass; + pass=ValidateCMAC() && pass; + pass=RunTestDataFile("TestVectors/eax.txt") && pass; + + pass=ValidateBBS() && pass; + pass=ValidateDH() && pass; + pass=ValidateX25519() && pass; + pass=ValidateMQV() && pass; + pass=ValidateHMQV() && pass; + pass=ValidateFHMQV() && pass; + pass=ValidateRSA() && pass; + pass=ValidateElGamal() && pass; + pass=ValidateDLIES() && pass; + pass=ValidateNR() && pass; + pass=ValidateDSA(thorough) && pass; + pass=ValidateLUC() && pass; + pass=ValidateLUC_DH() && pass; + pass=ValidateLUC_DL() && pass; + pass=ValidateXTR_DH() && pass; + pass=ValidateRabin() && pass; + pass=ValidateRW() && pass; + pass=ValidateECP() && pass; + pass=ValidateEC2N() && pass; + pass=ValidateECP_Legacy_Encrypt() && pass; + pass=ValidateEC2N_Legacy_Encrypt() && pass; + pass=ValidateECDSA() && pass; + pass=ValidateECDSA_RFC6979() && pass; + pass=ValidateECGDSA(thorough) && pass; + pass=ValidateESIGN() && pass; + + pass=ValidateX25519() && pass; + pass=ValidateEd25519() && pass; + pass=ValidateNaCl() && pass; + + if (pass) + std::cout << "\nAll tests passed!\n"; + else + std::cout << "\nOops! Not all tests passed.\n"; + + return pass; +} + +bool TestSettings() +{ + bool pass = true; + + std::cout << "\nTesting Settings...\n\n"; + + word32 w; + const byte s[] = "\x01\x02\x03\x04"; + +#if (_MSC_VER >= 1400) + memcpy_s(&w, 4, s, 4); +#else + std::copy(s, s+4, reinterpret_cast(&w)); +#endif + + if (w == 0x04030201L) + { +#if (CRYPTOPP_LITTLE_ENDIAN) + std::cout << "passed: "; +#else + std::cout << "FAILED: "; + pass = false; +#endif + std::cout << "Your machine is little endian.\n"; + } + else if (w == 0x01020304L) + { +#if (CRYPTOPP_BIG_ENDIAN) + std::cout << "passed: "; +#else + std::cout << "FAILED: "; + pass = false; +#endif + std::cout << "Your machine is big endian.\n"; + } + else + { + std::cout << "FAILED: Your machine is neither big endian nor little endian.\n"; + pass = false; + } + + if (sizeof(void*) == 8) + { + std::cout << "passed: Your machine is 64-bit.\n"; + } + else if (sizeof(void*) == 4) + { + std::cout << "passed: Your machine is 32-bit.\n"; + } + else + { + std::cout << "FAILED: Your machine is neither 32-bit nor 64-bit.\n"; + pass = false; + } + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + // App and library versions, http://github.com/weidai11/cryptopp/issues/371 + const int v1 = LibraryVersion(); + const int v2 = HeaderVersion(); + if(v1/10 == v2/10) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "Library version (library): " << v1 << ", header version (app): " << v2 << "\n"; +#endif + + if (sizeof(byte) == 1) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(byte) == " << sizeof(byte) << "\n"; + + if (sizeof(word16) == 2) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(word16) == " << sizeof(word16) << "\n"; + + if (sizeof(word32) == 4) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(word32) == " << sizeof(word32) << "\n"; + + if (sizeof(word64) == 8) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(word64) == " << sizeof(word64) << "\n"; + +#ifdef CRYPTOPP_WORD128_AVAILABLE + if (sizeof(word128) == 16) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(word128) == " << sizeof(word128) << "\n"; +#endif + + if (sizeof(word) == 2*sizeof(hword) +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + && sizeof(dword) == 2*sizeof(word) +#endif + ) + std::cout << "passed: "; + else + { + std::cout << "FAILED: "; + pass = false; + } + std::cout << "sizeof(hword) == " << sizeof(hword) << ", sizeof(word) == " << sizeof(word); +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + std::cout << ", sizeof(dword) == " << sizeof(dword); +#endif + std::cout << "\n"; + + const int cacheLineSize = GetCacheLineSize(); + if (cacheLineSize < 16 || cacheLineSize > 256 || !IsPowerOf2(cacheLineSize)) + { + std::cout << "FAILED: "; + pass = false; + } + else + std::cout << "passed: "; + std::cout << "cacheLineSize == " << cacheLineSize << "\n"; + +#ifdef CRYPTOPP_CPUID_AVAILABLE + bool hasSSE2 = HasSSE2(); + bool hasSSSE3 = HasSSSE3(); + bool hasSSE41 = HasSSE41(); + bool hasSSE42 = HasSSE42(); + bool hasAVX = HasAVX(); + bool hasAVX2 = HasAVX2(); + bool hasAESNI = HasAESNI(); + bool hasCLMUL = HasCLMUL(); + bool hasRDRAND = HasRDRAND(); + bool hasRDSEED = HasRDSEED(); + bool hasSHA = HasSHA(); + bool isP4 = IsP4(); + + std::cout << "hasSSE2 == " << hasSSE2 << ", hasSSSE3 == " << hasSSSE3; + std::cout << ", hasSSE4.1 == " << hasSSE41 << ", hasSSE4.2 == " << hasSSE42; + std::cout << ", hasAVX == " << hasAVX << ", hasAVX2 == " << hasAVX2; + std::cout << ", hasAESNI == " << hasAESNI << ", hasCLMUL == " << hasCLMUL; + std::cout << ", hasRDRAND == " << hasRDRAND << ", hasRDSEED == " << hasRDSEED; + std::cout << ", hasSHA == " << hasSHA << ", isP4 == " << isP4; + std::cout << "\n"; + +#elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) + +# if defined(__arm__) + bool hasARMv7 = HasARMv7(); + bool hasNEON = HasNEON(); + + std::cout << "passed: "; + std::cout << "hasARMv7 == " << hasARMv7 << ", hasNEON == " << hasNEON << "\n"; +# else // __arch32__ and __aarch64__ + bool hasCRC32 = HasCRC32(); + bool hasPMULL = HasPMULL(); + bool hasAES = HasAES(); + bool hasSHA1 = HasSHA1(); + bool hasSHA2 = HasSHA2(); + bool hasSHA512 = HasSHA512(); + bool hasSHA3 = HasSHA3(); + bool hasSM3 = HasSM3(); + bool hasSM4 = HasSM4(); + + std::cout << "passed: hasASIMD == 1"; + std::cout << ", hasCRC32 == " << hasCRC32 << ", hasAES == " << hasAES; + std::cout << ", hasPMULL == " << hasPMULL << ", hasSHA1 == " << hasSHA1; + std::cout << ", hasSHA2 == " << hasSHA2 << ", hasSHA512 == " << hasSHA512; + std::cout << ", hasSHA3 == " << hasSHA3 << ", hasSM3 == " << hasSM3; + std::cout << ", hasSM4 == " << hasSM4 << "\n"; +# endif + +#elif (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + const bool hasAltivec = HasAltivec(); + const bool hasPower7 = HasPower7(); + const bool hasPower8 = HasPower8(); + const bool hasPower9 = HasPower9(); + const bool hasPMULL = HasPMULL(); + const bool hasAES = HasAES(); + const bool hasSHA256 = HasSHA256(); + const bool hasSHA512 = HasSHA512(); + const bool hasDARN = HasDARN(); + + std::cout << "passed: "; + std::cout << "hasAltivec == " << hasAltivec << ", hasPower7 == " << hasPower7; + std::cout << ", hasPower8 == " << hasPower8 << ", hasPower9 == " << hasPower9; + std::cout << ", hasPMULL == " << hasPMULL << ", hasAES == " << hasAES; + std::cout << ", hasSHA256 == " << hasSHA256 << ", hasSHA512 == " << hasSHA512; + std::cout << ", hasDARN == " << hasDARN << "\n"; + +#endif + + if (!pass) + { + std::cerr << "Some critical setting in config.h is in error. Please fix it and recompile.\n"; + std::abort(); + } + return pass; +} + +bool Test_RandomNumberGenerator(RandomNumberGenerator& prng, bool drain=false) +{ + bool pass = true, result = true; + const size_t GENERATE_SIZE = 1024*10, DISCARD_SIZE = 256, ENTROPY_SIZE = 32; + + if(drain) + { + RandomNumberSource(prng, UINT_MAX, true, new Redirector(TheBitBucket())); + } + + MeterFilter meter(new Redirector(TheBitBucket())); + RandomNumberSource(prng, GENERATE_SIZE, true, new Deflator(new Redirector(meter))); + + if (meter.GetTotalBytes() < GENERATE_SIZE) + { + pass = false; + result = false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " " << GENERATE_SIZE << " generated bytes compressed to "; + std::cout << meter.GetTotalBytes() << " bytes by DEFLATE\n"; + + try + { + pass = true; + if(prng.CanIncorporateEntropy()) + { + SecByteBlock entropy(ENTROPY_SIZE); + GlobalRNG().GenerateBlock(entropy, entropy.SizeInBytes()); + + prng.IncorporateEntropy(entropy, entropy.SizeInBytes()); + prng.IncorporateEntropy(entropy, entropy.SizeInBytes()-1); + prng.IncorporateEntropy(entropy, entropy.SizeInBytes()-2); + prng.IncorporateEntropy(entropy, entropy.SizeInBytes()-3); + } + } + catch (const Exception& /*ex*/) + { + pass = false; + result = false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " IncorporateEntropy with " << 4*ENTROPY_SIZE << " bytes\n"; + + try + { + word32 val = prng.GenerateWord32(); + val = prng.GenerateWord32((val & 0xff), 0xffffffff - (val & 0xff)); + + prng.GenerateBlock(reinterpret_cast(&val), 4); + prng.GenerateBlock(reinterpret_cast(&val), 3); + prng.GenerateBlock(reinterpret_cast(&val), 2); + prng.GenerateBlock(reinterpret_cast(&val), 1); + } + catch (const Exception&) + { + pass = false; + result = false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " GenerateWord32 and Crop\n"; + + try + { + pass = true; + prng.DiscardBytes(DISCARD_SIZE); + prng.DiscardBytes(DISCARD_SIZE-1); + prng.DiscardBytes(DISCARD_SIZE-2); + prng.DiscardBytes(DISCARD_SIZE-3); + } + catch (const Exception&) + { + pass = false; + result = false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " DiscardBytes with " << 4*DISCARD_SIZE << " bytes\n"; + + // Miscellaneous for code coverage + (void)prng.AlgorithmName(); // "unknown" + + CRYPTOPP_ASSERT(result); + return result; +} + +bool TestOS_RNG() +{ + bool pass = true; + + member_ptr rng; + +#ifdef BLOCKING_RNG_AVAILABLE + try {rng.reset(new BlockingRng);} + catch (const OS_RNG_Err &) {} + + if (rng.get()) + { + std::cout << "\nTesting operating system provided blocking random number generator...\n\n"; + + MeterFilter meter(new Redirector(TheBitBucket())); + RandomNumberSource test(*rng, UINT_MAX, false, new Deflator(new Redirector(meter))); + unsigned long total=0; + time_t t = time(NULLPTR), t1 = 0; + + // check that it doesn't take too long to generate a reasonable amount of randomness + while (total < 16 && (t1 < 10 || total*8 > (unsigned long)t1)) + { + test.Pump(1); + total += 1; + t1 = time(NULLPTR) - t; + } + + if (total < 16) + { + std::cout << "FAILED:"; + pass = false; + } + else + std::cout << "passed:"; + std::cout << " it took " << long(t1) << " seconds to generate " << total << " bytes" << std::endl; + + test.AttachedTransformation()->MessageEnd(); + + if (meter.GetTotalBytes() < total) + { + std::cout << "FAILED:"; + pass = false; + } + else + std::cout << "passed:"; + std::cout << " " << total << " generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n"; + + try + { + // Miscellaneous for code coverage + RandomNumberGenerator& prng = *rng.get(); + (void)prng.AlgorithmName(); + word32 result = prng.GenerateWord32(); + result = prng.GenerateWord32((result & 0xff), 0xffffffff - (result & 0xff)); + prng.GenerateBlock(reinterpret_cast(&result), 4); + prng.GenerateBlock(reinterpret_cast(&result), 3); + prng.GenerateBlock(reinterpret_cast(&result), 2); + prng.GenerateBlock(reinterpret_cast(&result), 1); + prng.GenerateBlock(reinterpret_cast(&result), 0); + pass = true; + } + catch (const Exception&) + { + pass = false; + } + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " GenerateWord32 and Crop\n"; + } + else + std::cout << "\nNo operating system provided blocking random number generator, skipping test." << std::endl; +#endif + +#ifdef NONBLOCKING_RNG_AVAILABLE + try {rng.reset(new NonblockingRng);} + catch (OS_RNG_Err &) {} + + if (rng.get()) + { + std::cout << "\nTesting operating system provided nonblocking random number generator...\n\n"; + + pass = Test_RandomNumberGenerator(*rng.get()) && pass; + } + else + std::cout << "\nNo operating system provided non-blocking random number generator, skipping test." << std::endl; +#endif + + CRYPTOPP_ASSERT(pass); + return pass; +} + +bool TestRandomPool() +{ + member_ptr prng; + bool pass=true; + + try {prng.reset(new RandomPool);} + catch (Exception &) {} + + if(prng.get()) + { + std::cout << "\nTesting RandomPool generator...\n\n"; + pass = Test_RandomNumberGenerator(*prng.get()) && pass; + } + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + try {prng.reset(new AutoSeededRandomPool);} + catch (Exception &) {} + + if(prng.get()) + { + std::cout << "\nTesting AutoSeeded RandomPool generator...\n\n"; + pass = Test_RandomNumberGenerator(*prng.get()) && pass; + } +#endif + + // Old, PGP 2.6 style RandomPool. Added because users were still having problems + // with it in 2017. The missing functionality was a barrier to upgrades. + try {prng.reset(new OldRandomPool);} + catch (Exception &) {} + + if(prng.get()) + { + std::cout << "\nTesting OldRandomPool generator...\n\n"; + pass = Test_RandomNumberGenerator(*prng.get()) && pass; + + // https://github.com/weidai11/cryptopp/issues/452 + byte actual[32], expected[32] = { + 0x41,0xD1,0xEF,0x8F,0x10,0x3C,0xE2,0x94, + 0x47,0xC0,0xC3,0x86,0x66,0xBC,0x86,0x09, + 0x57,0x77,0x73,0x91,0x57,0x4D,0x93,0x66, + 0xD1,0x13,0xE1,0xBA,0x07,0x49,0x8F,0x75 + }; + + prng.reset(new OldRandomPool); + RandomNumberGenerator& old = *prng.get(); + + SecByteBlock seed(384); + for (size_t i=0; i<384; ++i) + seed[i] = static_cast(i); + old.IncorporateEntropy(seed, seed.size()); + + old.GenerateBlock(actual, sizeof(actual)); + pass = (0 == std::memcmp(actual, expected, sizeof(expected))) && pass; + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Expected sequence from PGP-style RandomPool (circa 2007)\n"; + } + + return pass; +} + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) +bool TestAutoSeededX917() +{ + // This tests Auto-Seeding and GenerateIntoBufferedTransformation. + std::cout << "\nTesting AutoSeeded X917 generator...\n\n"; + + AutoSeededX917RNG prng; + return Test_RandomNumberGenerator(prng); +} +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +bool TestMersenne() +{ + std::cout << "\nTesting Mersenne Twister...\n\n"; + + member_ptr rng; + bool pass = true; + + try {rng.reset(new MT19937ar);} + catch (const PadlockRNG_Err &) {} + + if(rng.get()) + { + pass = Test_RandomNumberGenerator(*rng.get()); + } + + // Reset state + try {rng.reset(new MT19937ar);} + catch (const PadlockRNG_Err &) {} + + if(rng.get()) + { + // First 10; http://create.stephan-brumme.com/mersenne-twister/ + word32 result[10], expected[10] = { + 0xD091BB5C, 0x22AE9EF6, 0xE7E1FAEE, 0xD5C31F79, + 0x2082352C, 0xF807B7DF, 0xE9D30005, 0x3895AFE1, + 0xA1E24BBA, 0x4EE4092B + }; + + rng->GenerateBlock(reinterpret_cast(result), sizeof(result)); + pass = (0 == std::memcmp(result, expected, sizeof(expected))) && pass; + + if (!pass) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Expected sequence from MT19937\n"; + } + + return pass; +} +#endif + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +bool TestPadlockRNG() +{ + std::cout << "\nTesting Padlock RNG generator...\n\n"; + + member_ptr rng; + bool pass = true, fail; + + try {rng.reset(new PadlockRNG);} + catch (const PadlockRNG_Err &) {} + + if (rng.get()) + { + PadlockRNG& padlock = dynamic_cast(*rng.get()); + pass = Test_RandomNumberGenerator(padlock); + + SecByteBlock zero(16), one(16), t(16); + std::memset(zero, 0x00, zero.size()); + std::memset( one, 0xff, one.size()); + + // Cryptography Research, Inc tests + word32 oldDivisor = padlock.SetDivisor(0); + padlock.GenerateBlock(t, t.size()); + word32 msr = padlock.GetMSR(); + padlock.SetDivisor(oldDivisor); + + // Bit 6 should be set + fail = !(msr & (1 << 6U)); + pass &= !fail; + if (fail) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " VIA RNG is activated\n"; + + // Bit 13 should be unset + fail = !!(msr & (1 << 13U)); + pass &= !fail; + if (fail) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " von Neumann corrector is activated\n"; + + // Bit 14 should be unset + fail = !!(msr & (1 << 14U)); + pass &= !fail; + if (fail) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " String filter is deactivated\n"; + + // Bit 12:10 should be unset + fail = !!(msr & (0x7 << 10U)); + pass &= !fail; + if (fail) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " Bias voltage is unmodified\n"; + + fail = false; + if (t == zero || t == one) + fail = true; + + pass &= !fail; + if (fail) + std::cout << "FAILED:"; + else + std::cout << "passed:"; + std::cout << " All 0's or all 1's test\n"; + } + else + std::cout << "Padlock RNG generator not available, skipping test.\n"; + + return pass; +} + +bool TestRDRAND() +{ + std::cout << "\nTesting RDRAND generator...\n\n"; + + bool pass = true; + member_ptr rng; + + try {rng.reset(new RDRAND);} + catch (const RDRAND_Err &) {} + + if (rng.get()) + { + RDRAND& rdrand = dynamic_cast(*rng.get()); + pass = Test_RandomNumberGenerator(rdrand) && pass; + + MaurerRandomnessTest maurer; + const unsigned int SIZE = 1024*10; + RandomNumberSource(rdrand, SIZE, true, new Redirector(maurer)); + + CRYPTOPP_ASSERT(0 == maurer.BytesNeeded()); + const double mv = maurer.GetTestValue(); + if (mv < 0.98f) + pass = false; + + std::ostringstream oss; + oss.flags(std::ios::fixed); + oss.precision(6); + + if (!pass) + oss << "FAILED:"; + else + oss << "passed:"; + oss << " Maurer Randomness Test returned value " << mv << "\n"; + std::cout << oss.str(); + } + else + std::cout << "RDRAND generator not available, skipping test.\n"; + + return pass; +} + +bool TestRDSEED() +{ + std::cout << "\nTesting RDSEED generator...\n\n"; + + bool pass = true; + member_ptr rng; + + try {rng.reset(new RDSEED);} + catch (const RDSEED_Err &) {} + + if (rng.get()) + { + RDSEED& rdseed = dynamic_cast(*rng.get()); + pass = Test_RandomNumberGenerator(rdseed) && pass; + + MaurerRandomnessTest maurer; + const unsigned int SIZE = 1024*10; + RandomNumberSource(rdseed, SIZE, true, new Redirector(maurer)); + + CRYPTOPP_ASSERT(0 == maurer.BytesNeeded()); + const double mv = maurer.GetTestValue(); + if (mv < 0.98f) + pass = false; + + std::ostringstream oss; + oss.flags(std::ios::fixed); + oss.precision(6); + + if (!pass) + oss << "FAILED:"; + else + oss << "passed:"; + oss << " Maurer Randomness Test returned value " << mv << "\n"; + std::cout << oss.str(); + } + else + std::cout << "RDSEED generator not available, skipping test.\n"; + + return pass; +} +#endif // x86, x32, or x64 + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool TestDARN() +{ + std::cout << "\nTesting DARN generator...\n\n"; + + bool pass = true; + member_ptr rng; + + try {rng.reset(new DARN);} + catch (const DARN_Err &) {} + + if (rng.get()) + { + DARN& darn = dynamic_cast(*rng.get()); + pass = Test_RandomNumberGenerator(darn) && pass; + + MaurerRandomnessTest maurer; + const unsigned int SIZE = 1024*10; + RandomNumberSource(darn, SIZE, true, new Redirector(maurer)); + + CRYPTOPP_ASSERT(0 == maurer.BytesNeeded()); + const double mv = maurer.GetTestValue(); + if (mv < 0.98f) + pass = false; + + std::ostringstream oss; + oss.flags(std::ios::fixed); + oss.precision(6); + + if (!pass) + oss << "FAILED:"; + else + oss << "passed:"; + oss << " Maurer Randomness Test returned value " << mv << "\n"; + std::cout << oss.str(); + } + else + std::cout << "DARN generator not available, skipping test.\n"; + + return pass; +} +#endif // PPC32 or PPC64 + +bool ValidateHashDRBG() +{ + std::cout << "\nTesting NIST Hash DRBGs...\n\n"; + bool pass=true, fail; + + // # CAVS 14.3 + // # DRBG800-90A information for "drbg_pr" + // # Generated on Tue Apr 02 15:32:09 2013 + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x16\x10\xb8\x28\xcc\xd2\x7d\xe0\x8c\xee\xa0\x32\xa2\x0e\x92\x08"; + const byte entropy2[] = "\x72\xd2\x8c\x90\x8e\xda\xf9\xa4\xd1\xe5\x26\xd8\xf2\xde\xd5\x44"; + const byte nonce[] = "\x49\x2c\xf1\x70\x92\x42\xf6\xb5"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\x56\xF3\x3D\x4F\xDB\xB9\xA5\xB6\x4D\x26\x23\x44\x97\xE9\xDC\xB8\x77\x98\xC6\x8D" + "\x08\xF7\xC4\x11\x99\xD4\xBD\xDF\x97\xEB\xBF\x6C\xB5\x55\x0E\x5D\x14\x9F\xF4\xD5" + "\xBD\x0F\x05\xF2\x5A\x69\x88\xC1\x74\x36\x39\x62\x27\x18\x4A\xF8\x4A\x56\x43\x35" + "\x65\x8E\x2F\x85\x72\xBE\xA3\x33\xEE\xE2\xAB\xFF\x22\xFF\xA6\xDE\x3E\x22\xAC\xA2"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=0, E=16, N=8)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x55\x08\x75\xb7\x4e\xc1\x1f\x90\x67\x78\xa3\x1a\x37\xa3\x29\xfd"; + const byte entropy2[] = "\x96\xc6\x39\xec\x14\x9f\x6b\x28\xe2\x79\x3b\xb9\x37\x9e\x60\x67"; + const byte nonce[] = "\x08\xdd\x8c\xd3\x5b\xfa\x00\x94"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\xEE\x44\xC6\xCF\x2C\x0C\x73\xA8\xAC\x4C\xA5\x6C\x0E\x71\x2C\xA5\x50\x9A\x19\x5D" + "\xE4\x5B\x8D\x2B\xC9\x40\xA7\xDB\x66\xC3\xEB\x2A\xA1\xBD\xB4\xDD\x76\x85\x12\x45" + "\x80\x2E\x68\x05\x4A\xAB\xA8\x7C\xD6\x3A\xD3\xE5\xC9\x7C\x06\xE7\xA3\x9F\xF6\xF9" + "\x8E\xB3\xD9\x72\xD4\x11\x35\xE5\xE7\x46\x1B\x49\x9C\x56\x45\x6A\xBE\x7F\x77\xD4"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=1, E=16, N=8)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 128], [ReturnedBitsLen = 640] + const byte entropy1[] = "\xd9\xba\xb5\xce\xdc\xa9\x6f\x61\x78\xd6\x45\x09\xa0\xdf\xdc\x5e"; + const byte entropy2[] = "\xc6\xba\xd0\x74\xc5\x90\x67\x86\xf5\xe1\xf3\x20\x99\xf5\xb4\x91"; + const byte nonce[] = "\xda\xd8\x98\x94\x14\x45\x0e\x01"; + const byte additional1[] = "\x3e\x6b\xf4\x6f\x4d\xaa\x38\x25\xd7\x19\x4e\x69\x4e\x77\x52\xf7"; + const byte additional2[] = "\x04\xfa\x28\x95\xaa\x5a\x6f\x8c\x57\x43\x34\x3b\x80\x5e\x5e\xa4"; + const byte additional3[] = "\xdf\x5d\xc4\x59\xdf\xf0\x2a\xa2\xf0\x52\xd7\x21\xec\x60\x72\x30"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\xC4\x8B\x89\xF9\xDA\x3F\x74\x82\x45\x55\x5D\x5D\x03\x3B\x69\x3D\xD7\x1A\x4D\xF5" + "\x69\x02\x05\xCE\xFC\xD7\x20\x11\x3C\xC2\x4E\x09\x89\x36\xFF\x5E\x77\xB5\x41\x53" + "\x58\x70\xB3\x39\x46\x8C\xDD\x8D\x6F\xAF\x8C\x56\x16\x3A\x70\x0A\x75\xB2\x3E\x59" + "\x9B\x5A\xEC\xF1\x6F\x3B\xAF\x6D\x5F\x24\x19\x97\x1F\x24\xF4\x46\x72\x0F\xEA\xBE"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 128], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x28\x00\x0f\xbf\xf0\x57\x22\xc8\x89\x93\x06\xc2\x9b\x50\x78\x0a"; + const byte entropy2[] = "\xd9\x95\x8e\x8c\x08\xaf\x5a\x41\x0e\x91\x9b\xdf\x40\x8e\x5a\x0a"; + const byte nonce[] = "\x11\x2f\x6e\x20\xc0\x29\xed\x3f"; + const byte additional1[] = "\x91\x1d\x96\x5b\x6e\x77\xa9\x6c\xfe\x3f\xf2\xd2\xe3\x0e\x2a\x86"; + const byte additional2[] = "\xcd\x44\xd9\x96\xab\x05\xef\xe8\x27\xd3\x65\x83\xf1\x43\x18\x2c"; + const byte additional3[] = "\x9f\x6a\x31\x82\x12\x18\x4e\x70\xaf\x5d\x00\x14\x1f\x42\x82\xf6"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\x54\x61\x65\x92\x1E\x71\x4A\xD1\x39\x02\x2F\x97\xD2\x65\x3F\x0D\x47\x69\xB1\x4A" + "\x3E\x6E\xEF\xA1\xA0\x16\xD6\x9E\xA9\x7F\x51\xD5\x81\xDC\xAA\xCF\x66\xF9\xB1\xE8" + "\x06\x94\x41\xD6\xB5\xC5\x44\x60\x54\x07\xE8\xE7\xDC\x1C\xD8\xE4\x70\xAD\x84\x77" + "\x5A\x65\x31\xBE\xE0\xFC\x81\x36\xE2\x8F\x0B\xFE\xEB\xE1\x98\x62\x7E\x98\xE0\xC1"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 128], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x0e\xd5\x4c\xef\x44\x5c\x61\x7d\x58\x86\xe0\x34\xc0\x97\x36\xd4"; + const byte entropy2[] = "\x0b\x90\x27\xb8\x01\xe7\xf7\x2e\xe6\xec\x50\x2b\x8b\x6b\xd7\x11"; + const byte nonce[] = "\x2c\x8b\x07\x13\x55\x6c\x91\x6f"; + const byte personalization[] = "\xf3\x37\x8e\xa1\x45\x34\x30\x41\x12\xe0\xee\x57\xe9\xb3\x4a\x4b"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8, personalization, 16); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\x55\x37\x0E\xD4\xB7\xCA\xA4\xBB\x67\x3A\x0F\x58\x40\xB3\x9F\x76\x4E\xDA\xD2\x85" + "\xD5\x6F\x01\x8F\x2D\xA7\x54\x4B\x0E\x66\x39\x62\x35\x96\x1D\xB7\xF6\xDA\xFB\x30" + "\xB6\xC5\x68\xD8\x40\x6E\x2B\xD4\x3D\x23\xEB\x0F\x10\xBA\x5F\x24\x9C\xC9\xE9\x4A" + "\xD3\xA5\xF1\xDF\xA4\xF2\xB4\x80\x40\x91\xED\x8C\xD6\x6D\xE7\xB7\x53\xB2\x09\xD5"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=0, P=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 128], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x8f\x2a\x33\x9f\x5f\x45\x21\x30\xa4\x57\xa9\x6f\xcb\xe2\xe6\x36"; + const byte entropy2[] = "\x1f\xff\x9e\x4f\x4d\x66\x3a\x1f\x9e\x85\x4a\x15\x7d\xad\x97\xe0"; + const byte nonce[] = "\x0e\xd0\xe9\xa5\xa4\x54\x8a\xd0"; + const byte personalization[] = "\x45\xe4\xb3\xe2\x63\x87\x62\x57\x2c\x99\xe4\x03\x45\xd6\x32\x6f"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8, personalization, 16); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\x4F\xE8\x96\x41\xF8\xD3\x95\xC4\x43\x6E\xFB\xF8\x05\x75\xA7\x69\x74\x6E\x0C\x5F" + "\x54\x14\x35\xB4\xE6\xA6\xB3\x40\x7C\xA2\xC4\x42\xA2\x2F\x66\x28\x28\xCF\x4A\xA8" + "\xDC\x16\xBC\x5F\x69\xE5\xBB\x05\xD1\x43\x8F\x80\xAB\xC5\x8F\x9C\x3F\x75\x57\xEB" + "\x44\x0D\xF5\x0C\xF4\x95\x23\x94\x67\x11\x55\x98\x14\x43\xFF\x13\x14\x85\x5A\xBC"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=0, P=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 128], [AdditionalInputLen = 16], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x48\xa1\xa9\x7c\xcc\x49\xd7\xcc\xf6\xe3\x78\xa2\xf1\x6b\x0f\xcd"; + const byte entropy2[] = "\xba\x5d\xa6\x79\x12\x37\x24\x3f\xea\x60\x50\xf5\xb9\x9e\xcd\xf5"; + const byte nonce[] = "\xb0\x91\xd2\xec\x12\xa8\x39\xfe"; + const byte personalization[] = "\x3d\xc1\x6c\x1a\xdd\x9c\xac\x4e\xbb\xb0\xb8\x89\xe4\x3b\x9e\x12"; + const byte additional1[] = "\xd1\x23\xe3\x8e\x4c\x97\xe8\x29\x94\xa9\x71\x7a\xc6\xf1\x7c\x08"; + const byte additional2[] = "\x80\x0b\xed\x97\x29\xcf\xad\xe6\x68\x0d\xfe\x53\xba\x0c\x1e\x28"; + const byte additional3[] = "\x25\x1e\x66\xb9\xe3\x85\xac\x1c\x17\xfb\x77\x1b\x5d\xc7\x6c\xf2"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8, personalization, 16); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\xA1\xB2\xEE\x86\xA0\xF1\xDA\xB7\x93\x83\x13\x3A\x62\x27\x99\x08\x95\x3A\x1C\x9A" + "\x98\x77\x60\x12\x11\x19\xCC\x78\xB8\x51\x2B\xD5\x37\xA1\x9D\xB9\x73\xCA\x39\x7A" + "\xDD\x92\x33\x78\x6D\x5D\x41\xFF\xFA\xE9\x80\x59\x04\x85\x21\xE2\x52\x84\xBC\x6F" + "\xDB\x97\xF3\x4E\x6A\x12\x7A\xCD\x41\x0F\x50\x68\x28\x46\xBE\x56\x9E\x9A\x6B\xC8"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16, P=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 128], [AdditionalInputLen = 16], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x3b\xcb\xa8\x3b\x6d\xfb\x06\x79\x80\xef\xc3\x1e\xd2\x9e\x68\x57"; + const byte entropy2[] = "\x2f\xc9\x87\x49\x19\xcb\x52\x4a\x5b\xac\xf0\xcd\x96\x4e\xf8\x6e"; + const byte nonce[] = "\x23\xfe\x20\x9f\xac\x70\x45\xde"; + const byte personalization[] = "\xf2\x25\xf4\xd9\x6b\x9c\xab\x49\x1e\xab\x18\x14\xb2\x5e\x78\xef"; + const byte additional1[] = "\x57\x5b\x9a\x11\x32\x7a\xab\x89\x08\xfe\x46\x11\x9a\xed\x14\x5d"; + const byte additional2[] = "\x5d\x19\xcd\xed\xb7\xe3\x44\x66\x8e\x11\x42\x96\xa0\x38\xb1\x7f"; + const byte additional3[] = "\x2b\xaf\xa0\x15\xed\xdd\x5c\x76\x32\x75\x34\x35\xd1\x37\x72\xfb"; + + Hash_DRBG drbg(entropy1, 16, nonce, 8, personalization, 16); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\x1D\x12\xEB\x6D\x42\x60\xBD\xFB\xA7\x99\xB8\x53\xCC\x6F\x19\xB1\x64\xFE\x2F\x55" + "\xBA\xA2\x1C\x89\xD4\xD0\xE9\xB4\xBA\xD4\xE5\xF8\xC5\x30\x06\x41\xBA\xC4\x3D\x2B" + "\x73\x91\x27\xE9\x31\xC0\x55\x55\x11\xE8\xB6\x57\x02\x0D\xCE\x90\xAC\x31\xB9\x00" + "\x31\xC1\xD4\x4F\xE7\x12\x3B\xCC\x85\x16\x2F\x12\x8F\xB2\xDF\x84\x4E\xF7\x06\xBE"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16, P=16)\n"; + } + + { + // [SHA-256], [PredictionResistance = False], [EntropyInputLen = 256], [NonceLen = 128] + // [PersonalizationStringLen = 256], [AdditionalInputLen = 256], [ReturnedBitsLen = 1024] + const byte entropy1[] = "\xf0\x5b\xab\x56\xc7\xac\x6e\xeb\x31\xa0\xcf\x8a\x8a\x06\x2a\x49\x17\x9a\xcf\x3c\x5b\x20\x4d\x60\xdd\x7a\x3e\xb7\x8f\x5d\x8e\x3b"; + const byte entropy2[] = "\x72\xd4\x02\xa2\x59\x7b\x98\xa3\xb8\xf5\x0b\x71\x6c\x63\xc6\xdb\xa7\x3a\x07\xe6\x54\x89\x06\x3f\x02\xc5\x32\xf5\xda\xc4\xd4\x18"; + const byte nonce[] = "\xa1\x45\x08\x53\x41\x68\xb6\x88\xf0\x5f\x1e\x41\x9c\x88\xcc\x30"; + const byte personalization[] = "\xa0\x34\x72\xf4\x04\x59\xe2\x87\xea\xcb\x21\x32\xc0\xb6\x54\x02\x7d\xa3\xe6\x69\x25\xb4\x21\x25\x54\xc4\x48\x18\x8c\x0e\x86\x01"; + const byte additional1[] = "\xb3\x0d\x28\xaf\xa4\x11\x6b\xbc\x13\x6e\x65\x09\xb5\x82\xa6\x93\xbc\x91\x71\x40\x46\xaa\x3c\x66\xb6\x77\xb3\xef\xf9\xad\xfd\x49"; + const byte additional2[] = "\x77\xfd\x1d\x68\xd6\xa4\xdd\xd5\xf3\x27\x25\x2d\x3f\x6b\xdf\xee\x8c\x35\xce\xd3\x83\xbe\xaf\xc9\x32\x77\xef\xf2\x1b\x6f\xf4\x1b"; + const byte additional3[] = "\x59\xa0\x1f\xf8\x6a\x58\x72\x1e\x85\xd2\xf8\x3f\x73\x99\xf1\x96\x4e\x27\xf8\x7f\xcd\x1b\xf5\xc1\xeb\xf3\x37\x10\x9b\x13\xbd\x24"; + + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + drbg.IncorporateEntropy(entropy2, 32, additional1, 32); + + SecByteBlock result(128); + drbg.GenerateBlock(additional2, 32, result, result.size()); + drbg.GenerateBlock(additional3, 32, result, result.size()); + + const byte expected[] = "\xFF\x27\x96\x38\x5C\x32\xBF\x84\x3D\xFA\xBB\xF0\x3E\x70\x5A\x39\xCB\xA3\x4C\xF1" + "\x4F\xAE\xC3\x05\x63\xDF\x5A\xDD\xBD\x2D\x35\x83\xF5\x7E\x05\xF9\x40\x30\x56\x18" + "\xF2\x00\x88\x14\x03\xC2\xD9\x81\x36\x39\xE6\x67\x55\xDC\xFC\x4E\x88\xEA\x71\xDD" + "\xB2\x25\x2E\x09\x91\x49\x40\xEB\xE2\x3D\x63\x44\xA0\xF4\xDB\x5E\xE8\x39\xE6\x70" + "\xEC\x47\x24\x3F\xA0\xFC\xF5\x13\x61\xCE\x53\x98\xAA\xBF\xB4\x19\x1B\xFE\xD5\x00" + "\xE1\x03\x3A\x76\x54\xFF\xD7\x24\x70\x5E\x8C\xB2\x41\x7D\x92\x0A\x2F\x4F\x27\xB8" + "\x45\x13\x7F\xFB\x87\x90\xA9\x49"; + + fail = !!memcmp(result, expected, 1024/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=0, E=32, N=16, A=32, P=32)\n"; + } + + { + // [SHA-256], [PredictionResistance = False], [EntropyInputLen = 256], [NonceLen = 128] + // [PersonalizationStringLen = 256], [AdditionalInputLen = 256], [ReturnedBitsLen = 1024] + const byte entropy1[] = "\xfe\x61\x50\x79\xf1\xad\x2a\x71\xea\x7f\x0f\x5a\x14\x34\xee\xc8\x46\x35\x54\x4a\x95\x6a\x4f\xbd\x64\xff\xba\xf6\x1d\x34\x61\x83"; + const byte entropy2[] = "\x18\x89\x7b\xd8\x3e\xff\x38\xab\xb5\x6e\x82\xa8\x1b\x8c\x5e\x59\x3c\x3d\x85\x62\x2a\xe2\x88\xe5\xb2\xc6\xc5\xd2\xad\x7d\xc9\x45"; + const byte nonce[] = "\x9d\xa7\x87\x56\xb7\x49\x17\x02\x4c\xd2\x00\x65\x11\x9b\xe8\x7e"; + const byte personalization[] = "\x77\x5d\xbf\x32\xf3\x5c\xf3\x51\xf4\xb8\x1c\xd3\xfa\x7f\x65\x0b\xcf\x31\x88\xa1\x25\x57\x0c\xdd\xac\xaa\xfe\xa1\x7b\x3b\x29\xbc"; + const byte additional1[] = "\xef\x96\xc7\x9c\xb1\x73\x1d\x82\x85\x0a\x6b\xca\x9b\x5c\x34\x39\xba\xd3\x4e\x4d\x82\x6f\x35\x9f\x61\x5c\xf6\xf2\xa3\x3e\x91\x05"; + const byte additional2[] = "\xaf\x25\xc4\x6e\x21\xfc\xc3\xaf\x1f\xbb\xf8\x76\xb4\x57\xab\x1a\x94\x0a\x85\x16\x47\x81\xa4\xab\xda\xc8\xab\xca\xd0\x84\xda\xae"; + const byte additional3[] = "\x59\x5b\x44\x94\x38\x86\x36\xff\x8e\x45\x1a\x0c\x42\xc8\xcc\x21\x06\x38\x3a\xc5\xa6\x30\x96\xb9\x14\x81\xb3\xa1\x2b\xc8\xcd\xf6"; + + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + drbg.IncorporateEntropy(entropy2, 32, additional1, 32); + + SecByteBlock result(128); + drbg.GenerateBlock(additional2, 32, result, result.size()); + drbg.GenerateBlock(additional3, 32, result, result.size()); + + const byte expected[] = "\x8B\x1C\x9C\x76\xC4\x9B\x3B\xAE\xFD\x6E\xEB\x6C\xFF\xA3\xA1\x03\x3A\x8C\xAF\x09" + "\xFE\xBD\x44\x00\xFC\x0F\xD3\xA8\x26\x9C\xEE\x01\xAC\xE3\x73\x0E\xBE\xDA\x9A\xC6" + "\x23\x44\x6D\xA1\x56\x94\x29\xEC\x4B\xCD\x01\x84\x32\x25\xEF\x00\x91\x0B\xCC\xF3" + "\x06\x3B\x80\xF5\x46\xAC\xD2\xED\x5F\x70\x2B\x56\x2F\x21\x0A\xE9\x80\x87\x38\xAD" + "\xB0\x2A\xEB\x27\xF2\xD9\x20\x2A\x66\x0E\xF5\xC9\x20\x4A\xB4\x3C\xCE\xD6\x24\x97" + "\xDB\xB1\xED\x94\x12\x6A\x2F\x03\x98\x4A\xD4\xD1\x72\xF3\x7A\x66\x74\x7E\x2A\x5B" + "\xDE\xEF\x43\xBC\xB9\x8C\x49\x01"; + + fail = !!memcmp(result, expected, 1024/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=1, E=32, N=16, A=32, P=32)\n"; + } + + { + // [SHA-512], [PredictionResistance = False], [EntropyInputLen = 256], [NonceLen = 128] + // [PersonalizationStringLen = 256], [AdditionalInputLen = 256], [ReturnedBitsLen = 2048] + const byte entropy1[] = "\x55\x4e\x8f\xfd\xc4\x9a\xd8\xf9\x9a\xe5\xd5\xf8\x1a\xf5\xda\xfb\x7f\x75\x53\xd7\xcb\x56\x8e\xa7\x3c\xc0\x82\xdd\x80\x76\x25\xc0"; + const byte entropy2[] = "\x78\x07\x3e\x86\x79\x4b\x10\x95\x88\xf4\x22\xf9\xbd\x04\x7e\xc0\xce\xab\xd6\x78\x6b\xdf\xe2\x89\xb3\x16\x43\x9c\x32\x2d\xb2\x59"; + const byte nonce[] = "\xf0\x89\x78\xde\x2d\xc2\xcd\xd9\xc0\xfd\x3d\x84\xd9\x8b\x8e\x8e"; + const byte personalization[] = "\x3e\x52\x7a\xb5\x81\x2b\x0c\x0e\x98\x2a\x95\x78\x93\x98\xd9\xeb\xf1\xb9\xeb\xd6\x1d\x02\x05\xed\x42\x21\x2d\x24\xb8\x37\xf8\x41"; + const byte additional1[] = "\xf2\x6b\xb1\xef\x30\xca\x8f\x97\xc0\x19\xd0\x79\xe5\xc6\x5e\xae\xd1\xa3\x9a\x52\xaf\x12\xe8\x28\xde\x03\x70\x79\x9a\x70\x11\x8b"; + const byte additional2[] = "\xb0\x9d\xb5\xa8\x45\xec\x79\x7a\x4b\x60\x7e\xe4\xd5\x58\x56\x70\x35\x20\x9b\xd8\xe5\x01\x6c\x78\xff\x1f\x6b\x93\xbf\x7c\x34\xca"; + const byte additional3[] = "\x45\x92\x2f\xb3\x5a\xd0\x6a\x84\x5f\xc9\xca\x16\x4a\x42\xbb\x59\x84\xb4\x38\x57\xa9\x16\x23\x48\xf0\x2f\x51\x61\x24\x35\xb8\x62"; + + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + drbg.IncorporateEntropy(entropy2, 32, additional1, 32); + + SecByteBlock result(256); + drbg.GenerateBlock(additional2, 32, result, result.size()); + drbg.GenerateBlock(additional3, 32, result, result.size()); + + const byte expected[] = "\x1F\x20\x83\x9E\x22\x55\x3B\x1E\x6C\xD4\xF6\x3A\x47\xC3\x99\x54\x0F\x69\xA3\xBB" + "\x37\x47\xA0\x2A\x12\xAC\xC7\x00\x85\xC5\xCC\xF4\x7B\x12\x5A\x4A\xEA\xED\x2F\xE5" + "\x31\x51\x0D\xC1\x8E\x50\x29\xE2\xA6\xCB\x8F\x34\xBA\xDA\x8B\x47\x32\x33\x81\xF1" + "\x2D\xF6\x8B\x73\x8C\xFF\x15\xC8\x8E\x8C\x31\x48\xFA\xC3\xC4\x9F\x52\x81\x23\xC2" + "\x2A\x83\xBD\xF1\x44\xEF\x15\x49\x93\x44\x83\x6B\x37\x5D\xBB\xFF\x72\xD2\x86\x96" + "\x62\xF8\x4D\x12\x3B\x16\xCB\xAC\xA1\x00\x12\x1F\x94\xA8\xD5\xAE\x9A\x9E\xDA\xC8" + "\xD7\x6D\x59\x33\xFD\x55\xC9\xCC\x5B\xAD\x39\x73\xB5\x13\x8B\x96\xDF\xDB\xF5\x90" + "\x81\xDF\x68\x6A\x30\x72\x42\xF2\x74\xAE\x7F\x1F\x7F\xFE\x8B\x3D\x49\x38\x98\x34" + "\x7C\x63\x46\x6E\xAF\xFA\xCB\x06\x06\x08\xE6\xC8\x35\x3C\x68\xB8\xCC\x9D\x5C\xDF" + "\xDB\xC0\x41\x44\x48\xE6\x11\xD4\x78\x50\x81\x91\xED\x1D\x75\xF3\xBD\x79\xFF\x1E" + "\x37\xAF\xC6\x5D\x49\xD6\x5C\xAC\x5B\xCB\xD6\x91\x37\x51\xFA\x98\x70\xFC\x32\xB3" + "\xF2\x86\xE4\xED\x74\xF2\x5D\x8B\x6C\x4D\xB8\xDE\xD8\x4A\xD6\x5E\xD6\x6D\xAE\xB1" + "\x1B\xA2\x94\x52\x54\xAD\x3C\x3D\x25\xBD\x12\x46\x3C\xA0\x45\x9D"; + + fail = !!memcmp(result, expected, 2048/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=0, E=32, N=16, A=32, P=32)\n"; + } + + { + // [SHA-512], [PredictionResistance = False], [EntropyInputLen = 256], [NonceLen = 128] + // [PersonalizationStringLen = 256], [AdditionalInputLen = 256], [ReturnedBitsLen = 2048] + const byte entropy1[] = "\x0c\x9f\xcd\x06\x21\x3c\xb2\xf6\x3c\xdf\x79\x76\x4b\x46\x74\xfc\xdf\x68\xb0\xff\xae\xc7\x21\x8a\xa2\xaf\x4e\x4c\xb9\xe6\x60\x78"; + const byte entropy2[] = "\x75\xb8\x49\x54\xdf\x30\x10\x16\x2c\x06\x8c\x12\xeb\x6c\x1d\x03\x64\x5c\xad\x10\x5c\xc3\x17\x69\xb2\x5a\xc1\x7c\xb8\x33\x5b\x45"; + const byte nonce[] = "\x43\x1c\x4d\x65\x93\x96\xad\xdc\xc1\x6d\x17\x9f\x7f\x57\x24\x4d"; + const byte personalization[] = "\x7e\x54\xbd\x87\xd2\x0a\x95\xd7\xc4\x0c\x3b\x1b\x32\x15\x26\xd2\x06\x67\xa4\xac\xc1\xaa\xfb\x55\x91\x68\x2c\xb5\xc9\xcd\x66\x05"; + const byte additional1[] = "\xd5\x74\x9e\x56\xfb\x5f\xf3\xf8\x2c\x73\x2b\x7a\x83\xe0\xde\x06\x85\x0b\xf0\x57\x50\xc8\x55\x60\x4a\x41\x4f\x86\xb1\x68\x14\x03"; + const byte additional2[] = "\x9a\x83\xbb\x06\xdf\x4d\x53\x89\xf5\x3f\x24\xff\xf7\xcd\x0c\xcf\x4f\xbe\x46\x79\x8e\xce\x82\xa8\xc4\x6b\x5f\x8e\x58\x32\x62\x23"; + const byte additional3[] = "\x48\x13\xc4\x95\x10\x99\xdd\x7f\xd4\x77\x3c\x9b\x8a\xa4\x1c\x3d\xb0\x93\x92\x50\xba\x23\x98\xef\x4b\x1b\xd2\x53\xc1\x61\xda\xc6"; + + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + drbg.IncorporateEntropy(entropy2, 32, additional1, 32); + + SecByteBlock result(256); + drbg.GenerateBlock(additional2, 32, result, result.size()); + drbg.GenerateBlock(additional3, 32, result, result.size()); + + const byte expected[] = "\xE1\x7E\x4B\xEE\xD1\x65\x4F\xB2\xFC\xC8\xE8\xD7\xC6\x72\x7D\xD2\xE3\x15\x73\xC0" + "\x23\xC8\x55\x5D\x2B\xD8\x28\xD8\x31\xE4\xC9\x87\x42\x51\x87\x66\x43\x1F\x2C\xA4" + "\x73\xED\x4E\x50\x12\xC4\x50\x0E\x4C\xDD\x14\x73\xA2\xFB\xB3\x07\x0C\x66\x97\x4D" + "\x89\xDE\x35\x1C\x93\xE7\xE6\x8F\x20\x3D\x84\xE6\x73\x46\x0F\x7C\xF4\x3B\x6C\x02" + "\x23\x7C\x79\x6C\x86\xD9\x48\x80\x9C\x34\xCB\xA1\x23\xE7\xF7\x8A\x2E\x4B\x9D\x39" + "\xA5\x86\x1A\x73\x58\x28\x5A\x1D\x8D\x4A\xBD\x42\xD5\x49\x2B\xDF\x53\x1D\xE7\x4A" + "\x5F\x74\x09\x7F\xDC\x29\x7D\x58\x9C\x4B\xC5\x2F\x3B\x8F\xBF\x56\xCA\x48\x0A\x74" + "\xAE\xFF\xDD\x12\xE4\xF6\xAB\x83\x26\x4F\x52\x8A\x19\xBB\x91\x32\xA4\x42\xEC\x4F" + "\x3C\x76\xED\x9F\x03\xAA\x5E\x53\x79\x4C\xD0\x06\xD2\x1A\x42\x9D\xB1\xA7\xEC\xF7" + "\x5B\xD4\x03\x70\x1E\xF2\x47\x26\x48\xAC\x35\xEE\xD0\x58\x40\x94\x8C\x11\xD0\xEB" + "\x77\x39\x5A\xA3\xD5\xD0\xD3\xC3\x68\xE1\x75\xAA\xC0\x44\xEA\xD8\xDD\x13\x3F\xF9" + "\x7D\x21\x14\x34\xA5\x87\x43\xA4\x0A\x96\x77\x00\xCC\xCA\xB1\xDA\xC4\x39\xE0\x66" + "\x37\x05\x6E\xAC\xF2\xE6\xC6\xC5\x4F\x79\xD3\xE5\x6A\x3D\x36\x3F"; + + fail = !!memcmp(result, expected, 2048/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=1, E=32, N=16, A=32, P=32)\n"; + } + + return pass; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat4.cpp b/extension/third_party/cryptopp/validat4.cpp new file mode 100644 index 00000000..e41c1c8b --- /dev/null +++ b/extension/third_party/cryptopp/validat4.cpp @@ -0,0 +1,1813 @@ +// validat4.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "hex.h" +#include "base32.h" +#include "base64.h" + +#include "rc2.h" +#include "aes.h" +#include "des.h" +#include "rc5.h" +#include "rc6.h" +#include "3way.h" +#include "aria.h" +#include "cast.h" +#include "mars.h" +#include "idea.h" +#include "gost.h" +#include "seal.h" +#include "seed.h" +#include "safer.h" +#include "shark.h" +#include "square.h" +#include "serpent.h" +#include "shacal2.h" +#include "twofish.h" +#include "blowfish.h" +#include "camellia.h" +#include "skipjack.h" + +#include "arc4.h" +#include "salsa.h" +#include "chacha.h" +#include "rabbit.h" +#include "sosemanuk.h" + +#include "modes.h" +#include "cmac.h" +#include "dmac.h" +#include "hmac.h" +#include "vmac.h" +#include "ttmac.h" + +#include "drbg.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + + +bool ValidateHmacDRBG() +{ + std::cout << "\nTesting NIST HMAC DRBGs...\n\n"; + bool pass=true, fail; + + // # CAVS 14.3 + // # DRBG800-90A information for "drbg_pr" + // # Generated on Tue Apr 02 15:32:12 2013 + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x79\x34\x9b\xbf\x7c\xdd\xa5\x79\x95\x57\x86\x66\x21\xc9\x13\x83"; + const byte entropy2[] = "\xc7\x21\x5b\x5b\x96\xc4\x8e\x9b\x33\x8c\x74\xe3\xe9\x9d\xfe\xdf"; + const byte nonce[] = "\x11\x46\x73\x3a\xbf\x8c\x35\xc8"; + + HMAC_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\xc6\xa1\x6a\xb8\xd4\x20\x70\x6f\x0f\x34\xab\x7f\xec\x5a\xdc\xa9\xd8\xca\x3a\x13" + "\x3e\x15\x9c\xa6\xac\x43\xc6\xf8\xa2\xbe\x22\x83\x4a\x4c\x0a\x0a\xff\xb1\x0d\x71" + "\x94\xf1\xc1\xa5\xcf\x73\x22\xec\x1a\xe0\x96\x4e\xd4\xbf\x12\x27\x46\xe0\x87\xfd" + "\xb5\xb3\xe9\x1b\x34\x93\xd5\xbb\x98\xfa\xed\x49\xe8\x5f\x13\x0f\xc8\xa4\x59\xb7"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=0, E=16, N=8)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640] + const byte entropy1[] = "\xee\x57\xfc\x23\x60\x0f\xb9\x02\x9a\x9e\xc6\xc8\x2e\x7b\x51\xe4"; + const byte entropy2[] = "\x84\x1d\x27\x6c\xa9\x51\x90\x61\xd9\x2d\x7d\xdf\xa6\x62\x8c\xa3"; + const byte nonce[] = "\x3e\x97\x21\xe4\x39\x3e\xf9\xad"; + + HMAC_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(result, result.size()); + drbg.GenerateBlock(result, result.size()); + + const byte expected[] = "\xee\x26\xa5\xc8\xef\x08\xa1\xca\x8f\x14\x15\x4d\x67\xc8\x8f\x5e\x7e\xd8\x21\x9d" + "\x93\x1b\x98\x42\xac\x00\x39\xf2\x14\x55\x39\xf2\x14\x2b\x44\x11\x7a\x99\x8c\x22" + "\xf5\x90\xf6\xc9\xb3\x8b\x46\x5b\x78\x3e\xcf\xf1\x3a\x77\x50\x20\x1f\x7e\xcf\x1b" + "\x8a\xb3\x93\x60\x4c\x73\xb2\x38\x93\x36\x60\x9a\xf3\x44\x0c\xde\x43\x29\x8b\x84"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=1, E=16, N=8)\n"; + } + + // ***************************************************** + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 16], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x7d\x70\x52\xa7\x76\xfd\x2f\xb3\xd7\x19\x1f\x73\x33\x04\xee\x8b"; + const byte entropy2[] = "\x49\x04\x7e\x87\x9d\x61\x09\x55\xee\xd9\x16\xe4\x06\x0e\x00\xc9"; + const byte nonce[] = "\xbe\x4a\x0c\xee\xdc\xa8\x02\x07"; + const byte additional1[] = "\xfd\x8b\xb3\x3a\xab\x2f\x6c\xdf\xbc\x54\x18\x11\x86\x1d\x51\x8d"; + const byte additional2[] = "\x99\xaf\xe3\x47\x54\x04\x61\xdd\xf6\xab\xeb\x49\x1e\x07\x15\xb4"; + const byte additional3[] = "\x02\xf7\x73\x48\x2d\xd7\xae\x66\xf7\x6e\x38\x15\x98\xa6\x4e\xf0"; + + HMAC_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\xa7\x36\x34\x38\x44\xfc\x92\x51\x13\x91\xdb\x0a\xdd\xd9\x06\x4d\xbe\xe2\x4c\x89" + "\x76\xaa\x25\x9a\x9e\x3b\x63\x68\xaa\x6d\xe4\xc9\xbf\x3a\x0e\xff\xcd\xa9\xcb\x0e" + "\x9d\xc3\x36\x52\xab\x58\xec\xb7\x65\x0e\xd8\x04\x67\xf7\x6a\x84\x9f\xb1\xcf\xc1" + "\xed\x0a\x09\xf7\x15\x50\x86\x06\x4d\xb3\x24\xb1\xe1\x24\xf3\xfc\x9e\x61\x4f\xcb"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=0, E=16, N=8, A=16)\n"; + } + + { + // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64] + // [PersonalizationStringLen = 0], [AdditionalInputLen = 16], [ReturnedBitsLen = 640] + const byte entropy1[] = "\x29\xc6\x2a\xfa\x3c\x52\x20\x8a\x3f\xde\xcb\x43\xfa\x61\x3f\x15"; + const byte entropy2[] = "\xbd\x87\xbe\x99\xd1\x84\x16\x54\x12\x31\x41\x40\xd4\x02\x71\x41"; + const byte nonce[] = "\x6c\x9e\xb5\x9a\xc3\xc2\xd4\x8b"; + const byte additional1[] = "\x43\x3d\xda\xf2\x59\xd1\x4b\xcf\x89\x76\x30\xcc\xaa\x27\x33\x8c"; + const byte additional2[] = "\x14\x11\x46\xd4\x04\xf2\x84\xc2\xd0\x2b\x6a\x10\x15\x6e\x33\x82"; + const byte additional3[] = "\xed\xc3\x43\xdb\xff\xe7\x1a\xb4\x11\x4a\xc3\x63\x9d\x44\x5b\x65"; + + HMAC_DRBG drbg(entropy1, 16, nonce, 8); + drbg.IncorporateEntropy(entropy2, 16, additional1, 16); + + SecByteBlock result(80); + drbg.GenerateBlock(additional2, 16, result, result.size()); + drbg.GenerateBlock(additional3, 16, result, result.size()); + + const byte expected[] = "\x8c\x73\x0f\x05\x26\x69\x4d\x5a\x9a\x45\xdb\xab\x05\x7a\x19\x75\x35\x7d\x65\xaf" + "\xd3\xef\xf3\x03\x32\x0b\xd1\x40\x61\xf9\xad\x38\x75\x91\x02\xb6\xc6\x01\x16\xf6" + "\xdb\x7a\x6e\x8e\x7a\xb9\x4c\x05\x50\x0b\x4d\x1e\x35\x7d\xf8\xe9\x57\xac\x89\x37" + "\xb0\x5f\xb3\xd0\x80\xa0\xf9\x06\x74\xd4\x4d\xe1\xbd\x6f\x94\xd2\x95\xc4\x51\x9d"; + + fail = !!memcmp(result, expected, 640/8); + pass = !fail && pass; + + std::cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=1, E=16, N=8, A=16)\n"; + } + + return pass; +} + +class CipherFactory +{ +public: + virtual unsigned int BlockSize() const =0; + virtual unsigned int KeyLength() const =0; + + virtual BlockTransformation* NewEncryption(const byte *keyStr) const =0; + virtual BlockTransformation* NewDecryption(const byte *keyStr) const =0; +}; + +template class FixedRoundsCipherFactory : public CipherFactory +{ +public: + FixedRoundsCipherFactory(unsigned int keylen=0) : + m_keylen(keylen ? keylen : static_cast(E::DEFAULT_KEYLENGTH)) {} + + unsigned int BlockSize() const {return E::BLOCKSIZE;} + unsigned int KeyLength() const {return m_keylen;} + + BlockTransformation* NewEncryption(const byte *keyStr) const + {return new E(keyStr, m_keylen);} + BlockTransformation* NewDecryption(const byte *keyStr) const + {return new D(keyStr, m_keylen);} + + unsigned int m_keylen; +}; + +template class VariableRoundsCipherFactory : public CipherFactory +{ +public: + VariableRoundsCipherFactory(unsigned int keylen=0, unsigned int rounds=0) : + m_keylen(keylen ? keylen : static_cast(E::DEFAULT_KEYLENGTH)), + m_rounds(rounds ? rounds : static_cast(E::DEFAULT_ROUNDS)) {} + + unsigned int BlockSize() const {return static_cast(E::BLOCKSIZE);} + unsigned int KeyLength() const {return m_keylen;} + + BlockTransformation* NewEncryption(const byte *keyStr) const + {return new E(keyStr, m_keylen, m_rounds);} + BlockTransformation* NewDecryption(const byte *keyStr) const + {return new D(keyStr, m_keylen, m_rounds);} + + unsigned int m_keylen, m_rounds; +}; + +bool BlockTransformationTest(const CipherFactory &cg, BufferedTransformation &valdata, unsigned int tuples = 0xffff) +{ + HexEncoder output(new FileSink(std::cout)); + SecByteBlock plain(cg.BlockSize()), cipher(cg.BlockSize()), out(cg.BlockSize()), outplain(cg.BlockSize()); + SecByteBlock key(cg.KeyLength()); + bool pass=true, fail; + + while (valdata.MaxRetrievable() && tuples--) + { + (void)valdata.Get(key, cg.KeyLength()); + (void)valdata.Get(plain, cg.BlockSize()); + (void)valdata.Get(cipher, cg.BlockSize()); + + member_ptr transE(cg.NewEncryption(key)); + transE->ProcessBlock(plain, out); + fail = memcmp(out, cipher, cg.BlockSize()) != 0; + + member_ptr transD(cg.NewDecryption(key)); + transD->ProcessBlock(out, outplain); + fail=fail || memcmp(outplain, plain, cg.BlockSize()); + + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + output.Put(key, cg.KeyLength()); + std::cout << " "; + output.Put(outplain, cg.BlockSize()); + std::cout << " "; + output.Put(out, cg.BlockSize()); + std::cout << std::endl; + } + return pass; +} + +class FilterTester : public Unflushable +{ +public: + FilterTester(const byte *validOutput, size_t outputLen) + : validOutput(validOutput), outputLen(outputLen), counter(0), fail(false) {} + void PutByte(byte inByte) + { + if (counter >= outputLen || validOutput[counter] != inByte) + { + std::cerr << "incorrect output " << counter << ", " << (word16)validOutput[counter] << ", " << (word16)inByte << "\n"; + fail = true; + CRYPTOPP_ASSERT(false); + } + counter++; + } + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(messageEnd), CRYPTOPP_UNUSED(blocking); + + while (length--) + FilterTester::PutByte(*inString++); + + if (messageEnd) + if (counter != outputLen) + { + fail = true; + CRYPTOPP_ASSERT(false); + } + + return 0; + } + bool GetResult() + { + return !fail; + } + + const byte *validOutput; + size_t outputLen, counter; + bool fail; +}; + +bool TestFilter(BufferedTransformation &bt, const byte *in, size_t inLen, const byte *out, size_t outLen) +{ + FilterTester *ft; + bt.Attach(ft = new FilterTester(out, outLen)); + + while (inLen) + { + size_t randomLen = GlobalRNG().GenerateWord32(0, (word32)inLen); + bt.Put(in, randomLen); + in += randomLen; + inLen -= randomLen; + } + bt.MessageEnd(); + return ft->GetResult(); +} + +bool ValidateDES() +{ + std::cout << "\nDES validation suite running...\n\n"; + + FileSource valdata(DataDir("TestData/descert.dat").c_str(), true, new HexDecoder); + bool pass = BlockTransformationTest(FixedRoundsCipherFactory(), valdata); + + std::cout << "\nTesting EDE2, EDE3, and XEX3 variants...\n\n"; + + FileSource valdata1(DataDir("TestData/3desval.dat").c_str(), true, new HexDecoder); + pass = BlockTransformationTest(FixedRoundsCipherFactory(), valdata1, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory(), valdata1, 1) && pass; + pass = BlockTransformationTest(FixedRoundsCipherFactory(), valdata1, 1) && pass; + + return pass; +} + +bool TestModeIV(SymmetricCipher &e, SymmetricCipher &d) +{ + SecByteBlock lastIV, iv(e.IVSize()); + StreamTransformationFilter filter(e, new StreamTransformationFilter(d)); + + // Enterprise Analysis finding on the stack based array + const int BUF_SIZE=20480U; + AlignedSecByteBlock plaintext(BUF_SIZE); + + for (unsigned int i=1; i cbcmac(key); + HashFilter cbcmacFilter(cbcmac); + fail = !TestFilter(cbcmacFilter, plain_3, sizeof(plain_3), mac1, sizeof(mac1)); + pass = pass && !fail; + std::cout << (fail ? "FAILED " : "passed ") << "CBC MAC" << std::endl; + + DMAC dmac(key); + HashFilter dmacFilter(dmac); + fail = !TestFilter(dmacFilter, plain_3, sizeof(plain_3), mac2, sizeof(mac2)); + pass = pass && !fail; + std::cout << (fail ? "FAILED " : "passed ") << "DMAC" << std::endl; + } + + return pass; +} + +bool ValidateIDEA() +{ + std::cout << "\nIDEA validation suite running...\n\n"; + + FileSource valdata(DataDir("TestData/ideaval.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata); +} + +bool ValidateSAFER() +{ + std::cout << "\nSAFER validation suite running...\n\n"; + + FileSource valdata(DataDir("TestData/saferval.dat").c_str(), true, new HexDecoder); + bool pass = true; + pass = BlockTransformationTest(VariableRoundsCipherFactory(8,6), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory(16,12), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory(8,6), valdata, 4) && pass; + pass = BlockTransformationTest(VariableRoundsCipherFactory(16,10), valdata, 4) && pass; + return pass; +} + +bool ValidateRC2() +{ + std::cout << "\nRC2 validation suite running...\n\n"; + + FileSource valdata(DataDir("TestData/rc2val.dat").c_str(), true, new HexDecoder); + HexEncoder output(new FileSink(std::cout)); + SecByteBlock plain(RC2Encryption::BLOCKSIZE), cipher(RC2Encryption::BLOCKSIZE), out(RC2Encryption::BLOCKSIZE), outplain(RC2Encryption::BLOCKSIZE); + SecByteBlock key(128); + bool pass=true, fail; + + while (valdata.MaxRetrievable()) + { + byte keyLen, effectiveLen; + + (void)valdata.Get(keyLen); + (void)valdata.Get(effectiveLen); + (void)valdata.Get(key, keyLen); + (void)valdata.Get(plain, RC2Encryption::BLOCKSIZE); + (void)valdata.Get(cipher, RC2Encryption::BLOCKSIZE); + + member_ptr transE(new RC2Encryption(key, keyLen, effectiveLen)); + transE->ProcessBlock(plain, out); + fail = memcmp(out, cipher, RC2Encryption::BLOCKSIZE) != 0; + + member_ptr transD(new RC2Decryption(key, keyLen, effectiveLen)); + transD->ProcessBlock(out, outplain); + fail=fail || memcmp(outplain, plain, RC2Encryption::BLOCKSIZE); + + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + output.Put(key, keyLen); + std::cout << " "; + output.Put(outplain, RC2Encryption::BLOCKSIZE); + std::cout << " "; + output.Put(out, RC2Encryption::BLOCKSIZE); + std::cout << std::endl; + } + return pass; +} + +bool ValidateARC4() +{ + unsigned char Key0[] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef }; + unsigned char Input0[]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + unsigned char Output0[] = {0x75,0xb7,0x87,0x80,0x99,0xe0,0xc5,0x96}; + + unsigned char Key1[]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; + unsigned char Input1[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output1[]={0x74,0x94,0xc2,0xe7,0x10,0x4b,0x08,0x79}; + + unsigned char Key2[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Input2[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output2[]={0xde,0x18,0x89,0x41,0xa3,0x37,0x5d,0x3a}; + + unsigned char Key3[]={0xef,0x01,0x23,0x45}; + unsigned char Input3[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + unsigned char Output3[]={0xd6,0xa1,0x41,0xa7,0xec,0x3c,0x38,0xdf,0xbd,0x61}; + + unsigned char Key4[]={ 0x01,0x23,0x45,0x67,0x89,0xab, 0xcd,0xef }; + unsigned char Input4[] = + {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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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}; + unsigned char Output4[]= { + 0x75,0x95,0xc3,0xe6,0x11,0x4a,0x09,0x78,0x0c,0x4a,0xd4, + 0x52,0x33,0x8e,0x1f,0xfd,0x9a,0x1b,0xe9,0x49,0x8f, + 0x81,0x3d,0x76,0x53,0x34,0x49,0xb6,0x77,0x8d,0xca, + 0xd8,0xc7,0x8a,0x8d,0x2b,0xa9,0xac,0x66,0x08,0x5d, + 0x0e,0x53,0xd5,0x9c,0x26,0xc2,0xd1,0xc4,0x90,0xc1, + 0xeb,0xbe,0x0c,0xe6,0x6d,0x1b,0x6b,0x1b,0x13,0xb6, + 0xb9,0x19,0xb8,0x47,0xc2,0x5a,0x91,0x44,0x7a,0x95, + 0xe7,0x5e,0x4e,0xf1,0x67,0x79,0xcd,0xe8,0xbf,0x0a, + 0x95,0x85,0x0e,0x32,0xaf,0x96,0x89,0x44,0x4f,0xd3, + 0x77,0x10,0x8f,0x98,0xfd,0xcb,0xd4,0xe7,0x26,0x56, + 0x75,0x00,0x99,0x0b,0xcc,0x7e,0x0c,0xa3,0xc4,0xaa, + 0xa3,0x04,0xa3,0x87,0xd2,0x0f,0x3b,0x8f,0xbb,0xcd, + 0x42,0xa1,0xbd,0x31,0x1d,0x7a,0x43,0x03,0xdd,0xa5, + 0xab,0x07,0x88,0x96,0xae,0x80,0xc1,0x8b,0x0a,0xf6, + 0x6d,0xff,0x31,0x96,0x16,0xeb,0x78,0x4e,0x49,0x5a, + 0xd2,0xce,0x90,0xd7,0xf7,0x72,0xa8,0x17,0x47,0xb6, + 0x5f,0x62,0x09,0x3b,0x1e,0x0d,0xb9,0xe5,0xba,0x53, + 0x2f,0xaf,0xec,0x47,0x50,0x83,0x23,0xe6,0x71,0x32, + 0x7d,0xf9,0x44,0x44,0x32,0xcb,0x73,0x67,0xce,0xc8, + 0x2f,0x5d,0x44,0xc0,0xd0,0x0b,0x67,0xd6,0x50,0xa0, + 0x75,0xcd,0x4b,0x70,0xde,0xdd,0x77,0xeb,0x9b,0x10, + 0x23,0x1b,0x6b,0x5b,0x74,0x13,0x47,0x39,0x6d,0x62, + 0x89,0x74,0x21,0xd4,0x3d,0xf9,0xb4,0x2e,0x44,0x6e, + 0x35,0x8e,0x9c,0x11,0xa9,0xb2,0x18,0x4e,0xcb,0xef, + 0x0c,0xd8,0xe7,0xa8,0x77,0xef,0x96,0x8f,0x13,0x90, + 0xec,0x9b,0x3d,0x35,0xa5,0x58,0x5c,0xb0,0x09,0x29, + 0x0e,0x2f,0xcd,0xe7,0xb5,0xec,0x66,0xd9,0x08,0x4b, + 0xe4,0x40,0x55,0xa6,0x19,0xd9,0xdd,0x7f,0xc3,0x16, + 0x6f,0x94,0x87,0xf7,0xcb,0x27,0x29,0x12,0x42,0x64, + 0x45,0x99,0x85,0x14,0xc1,0x5d,0x53,0xa1,0x8c,0x86, + 0x4c,0xe3,0xa2,0xb7,0x55,0x57,0x93,0x98,0x81,0x26, + 0x52,0x0e,0xac,0xf2,0xe3,0x06,0x6e,0x23,0x0c,0x91, + 0xbe,0xe4,0xdd,0x53,0x04,0xf5,0xfd,0x04,0x05,0xb3, + 0x5b,0xd9,0x9c,0x73,0x13,0x5d,0x3d,0x9b,0xc3,0x35, + 0xee,0x04,0x9e,0xf6,0x9b,0x38,0x67,0xbf,0x2d,0x7b, + 0xd1,0xea,0xa5,0x95,0xd8,0xbf,0xc0,0x06,0x6f,0xf8, + 0xd3,0x15,0x09,0xeb,0x0c,0x6c,0xaa,0x00,0x6c,0x80, + 0x7a,0x62,0x3e,0xf8,0x4c,0x3d,0x33,0xc1,0x95,0xd2, + 0x3e,0xe3,0x20,0xc4,0x0d,0xe0,0x55,0x81,0x57,0xc8, + 0x22,0xd4,0xb8,0xc5,0x69,0xd8,0x49,0xae,0xd5,0x9d, + 0x4e,0x0f,0xd7,0xf3,0x79,0x58,0x6b,0x4b,0x7f,0xf6, + 0x84,0xed,0x6a,0x18,0x9f,0x74,0x86,0xd4,0x9b,0x9c, + 0x4b,0xad,0x9b,0xa2,0x4b,0x96,0xab,0xf9,0x24,0x37, + 0x2c,0x8a,0x8f,0xff,0xb1,0x0d,0x55,0x35,0x49,0x00, + 0xa7,0x7a,0x3d,0xb5,0xf2,0x05,0xe1,0xb9,0x9f,0xcd, + 0x86,0x60,0x86,0x3a,0x15,0x9a,0xd4,0xab,0xe4,0x0f, + 0xa4,0x89,0x34,0x16,0x3d,0xdd,0xe5,0x42,0xa6,0x58, + 0x55,0x40,0xfd,0x68,0x3c,0xbf,0xd8,0xc0,0x0f,0x12, + 0x12,0x9a,0x28,0x4d,0xea,0xcc,0x4c,0xde,0xfe,0x58, + 0xbe,0x71,0x37,0x54,0x1c,0x04,0x71,0x26,0xc8,0xd4, + 0x9e,0x27,0x55,0xab,0x18,0x1a,0xb7,0xe9,0x40,0xb0, + 0xc0}; + + member_ptr arc4; + bool pass=true, fail; + unsigned int i; + + std::cout << "\nARC4 validation suite running...\n\n"; + + arc4.reset(new Weak::ARC4(Key0, sizeof(Key0))); + arc4->ProcessString(Input0, sizeof(Input0)); + fail = memcmp(Input0, Output0, sizeof(Input0)) != 0; + std::cout << (fail ? "FAILED" : "passed") << " Test 0" << std::endl; + pass = pass && !fail; + + arc4.reset(new Weak::ARC4(Key1, sizeof(Key1))); + arc4->ProcessString(Key1, Input1, sizeof(Key1)); + fail = memcmp(Output1, Key1, sizeof(Key1)) != 0; + std::cout << (fail ? "FAILED" : "passed") << " Test 1" << std::endl; + pass = pass && !fail; + + arc4.reset(new Weak::ARC4(Key2, sizeof(Key2))); + for (i=0, fail=false; iProcessByte(Input2[i]) != Output2[i]) + fail = true; + std::cout << (fail ? "FAILED" : "passed") << " Test 2" << std::endl; + pass = pass && !fail; + + arc4.reset(new Weak::ARC4(Key3, sizeof(Key3))); + for (i=0, fail=false; iProcessByte(Input3[i]) != Output3[i]) + fail = true; + std::cout << (fail ? "FAILED" : "passed") << " Test 3" << std::endl; + pass = pass && !fail; + + arc4.reset(new Weak::ARC4(Key4, sizeof(Key4))); + for (i=0, fail=false; iProcessByte(Input4[i]) != Output4[i]) + fail = true; + std::cout << (fail ? "FAILED" : "passed") << " Test 4" << std::endl; + pass = pass && !fail; + + return pass; +} + +bool ValidateRC5() +{ + std::cout << "\nRC5 validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + RC5Encryption enc; // 0 to 2040-bits (255-bytes) + pass1 = RC5Encryption::DEFAULT_KEYLENGTH == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == 0 && pass1; + pass1 = enc.StaticGetValidKeyLength(254) == 254 && pass1; + pass1 = enc.StaticGetValidKeyLength(255) == 255 && pass1; + pass1 = enc.StaticGetValidKeyLength(256) == 255 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + RC5Decryption dec; + pass2 = RC5Decryption::DEFAULT_KEYLENGTH == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == 0 && pass2; + pass2 = dec.StaticGetValidKeyLength(254) == 254 && pass2; + pass2 = dec.StaticGetValidKeyLength(255) == 255 && pass2; + pass2 = dec.StaticGetValidKeyLength(256) == 255 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/rc5val.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(VariableRoundsCipherFactory(16, 12), valdata) && pass1 && pass2; +} + +bool ValidateRC6() +{ + std::cout << "\nRC6 validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + RC6Encryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + RC6Decryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/rc6val.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 2) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 2) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 2) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateMARS() +{ + std::cout << "\nMARS validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + MARSEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 56 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 56 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + MARSDecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 56 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 56 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/marsval.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 4) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 3) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 2) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateRijndael() +{ + std::cout << "\nRijndael (AES) validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + RijndaelEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + RijndaelDecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/rijndael.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 4) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 3) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 2) && pass3; + pass3 = RunTestDataFile("TestVectors/aes.txt") && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateTwofish() +{ + std::cout << "\nTwofish validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + TwofishEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + + TwofishDecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/twofishv.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 4) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 3) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 2) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateSerpent() +{ + std::cout << "\nSerpent validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + SerpentEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + + SerpentDecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/serpentv.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 5) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 4) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 3) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateBlowfish() +{ + std::cout << "\nBlowfish validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true, fail; + + BlowfishEncryption enc1; // 32 to 448-bits (4 to 56-bytes) + pass1 = enc1.StaticGetValidKeyLength(3) == 4 && pass1; + pass1 = enc1.StaticGetValidKeyLength(4) == 4 && pass1; + pass1 = enc1.StaticGetValidKeyLength(5) == 5 && pass1; + pass1 = enc1.StaticGetValidKeyLength(8) == 8 && pass1; + pass1 = enc1.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc1.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc1.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc1.StaticGetValidKeyLength(56) == 56 && pass1; + pass1 = enc1.StaticGetValidKeyLength(57) == 56 && pass1; + pass1 = enc1.StaticGetValidKeyLength(60) == 56 && pass1; + pass1 = enc1.StaticGetValidKeyLength(64) == 56 && pass1; + pass1 = enc1.StaticGetValidKeyLength(128) == 56 && pass1; + + BlowfishDecryption dec1; // 32 to 448-bits (4 to 56-bytes) + pass2 = dec1.StaticGetValidKeyLength(3) == 4 && pass2; + pass2 = dec1.StaticGetValidKeyLength(4) == 4 && pass2; + pass2 = dec1.StaticGetValidKeyLength(5) == 5 && pass2; + pass2 = dec1.StaticGetValidKeyLength(8) == 8 && pass2; + pass2 = dec1.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec1.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec1.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec1.StaticGetValidKeyLength(56) == 56 && pass2; + pass2 = dec1.StaticGetValidKeyLength(57) == 56 && pass2; + pass2 = dec1.StaticGetValidKeyLength(60) == 56 && pass2; + pass2 = dec1.StaticGetValidKeyLength(64) == 56 && pass2; + pass2 = dec1.StaticGetValidKeyLength(128) == 56 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + HexEncoder output(new FileSink(std::cout)); + const char *key[]={"abcdefghijklmnopqrstuvwxyz", "Who is John Galt?"}; + byte *plain[]={(byte *)"BLOWFISH", (byte *)"\xfe\xdc\xba\x98\x76\x54\x32\x10"}; + byte *cipher[]={(byte *)"\x32\x4e\xd0\xfe\xf4\x13\xa2\x03", (byte *)"\xcc\x91\x73\x2b\x80\x22\xf6\x84"}; + byte out[8], outplain[8]; + + for (int i=0; i<2; i++) + { + ECB_Mode::Encryption enc2((byte *)key[i], strlen(key[i])); + enc2.ProcessData(out, plain[i], 8); + fail = memcmp(out, cipher[i], 8) != 0; + + ECB_Mode::Decryption dec2((byte *)key[i], strlen(key[i])); + dec2.ProcessData(outplain, cipher[i], 8); + fail = fail || memcmp(outplain, plain[i], 8); + pass3 = pass3 && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << '\"' << key[i] << '\"'; + for (int j=0; j<(signed int)(30-strlen(key[i])); j++) + std::cout << ' '; + output.Put(outplain, 8); + std::cout << " "; + output.Put(out, 8); + std::cout << std::endl; + } + return pass1 && pass2 && pass3; +} + +bool ValidateThreeWay() +{ + std::cout << "\n3-WAY validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + ThreeWayEncryption enc; // 96-bit only + pass1 = ThreeWayEncryption::KEYLENGTH == 12 && pass1; + pass1 = enc.StaticGetValidKeyLength(8) == 12 && pass1; + pass1 = enc.StaticGetValidKeyLength(12) == 12 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 12 && pass1; + + ThreeWayDecryption dec; // 96-bit only + pass2 = ThreeWayDecryption::KEYLENGTH == 12 && pass2; + pass2 = dec.StaticGetValidKeyLength(8) == 12 && pass2; + pass2 = dec.StaticGetValidKeyLength(12) == 12 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 12 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/3wayval.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata) && pass1 && pass2; +} + +bool ValidateGOST() +{ + std::cout << "\nGOST validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + GOSTEncryption enc; // 256-bit only + pass1 = GOSTEncryption::KEYLENGTH == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(40) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + + GOSTDecryption dec; // 256-bit only + pass2 = GOSTDecryption::KEYLENGTH == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(40) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/gostval.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata) && pass1 && pass2; +} + +bool ValidateSHARK() +{ + std::cout << "\nSHARK validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + SHARKEncryption enc; // 128-bit only + pass1 = SHARKEncryption::KEYLENGTH == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(15) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(17) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 16 && pass1; + + SHARKDecryption dec; // 128-bit only + pass2 = SHARKDecryption::KEYLENGTH == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(15) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(17) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 16 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/sharkval.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata) && pass1 && pass2; +} + +bool ValidateCAST() +{ + std::cout << "\nCAST-128 validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + CAST128Encryption enc1; // 40 to 128-bits (5 to 16-bytes) + pass1 = CAST128Encryption::DEFAULT_KEYLENGTH == 16 && pass1; + pass1 = enc1.StaticGetValidKeyLength(4) == 5 && pass1; + pass1 = enc1.StaticGetValidKeyLength(5) == 5 && pass1; + pass1 = enc1.StaticGetValidKeyLength(15) == 15 && pass1; + pass1 = enc1.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc1.StaticGetValidKeyLength(17) == 16 && pass1; + + CAST128Decryption dec1; // 40 to 128-bits (5 to 16-bytes) + pass2 = CAST128Decryption::DEFAULT_KEYLENGTH == 16 && pass2; + pass2 = dec1.StaticGetValidKeyLength(4) == 5 && pass2; + pass2 = dec1.StaticGetValidKeyLength(5) == 5 && pass2; + pass2 = dec1.StaticGetValidKeyLength(15) == 15 && pass2; + pass2 = dec1.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec1.StaticGetValidKeyLength(17) == 16 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource val128(DataDir("TestData/cast128v.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), val128, 1) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(10), val128, 1) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(5), val128, 1) && pass3; + + std::cout << "\nCAST-256 validation suite running...\n\n"; + bool pass4 = true, pass5 = true, pass6 = true; + + CAST256Encryption enc2; // 128, 160, 192, 224, or 256-bits (16 to 32-bytes, step 4) + pass1 = CAST128Encryption::DEFAULT_KEYLENGTH == 16 && pass1; + pass4 = enc2.StaticGetValidKeyLength(15) == 16 && pass4; + pass4 = enc2.StaticGetValidKeyLength(16) == 16 && pass4; + pass4 = enc2.StaticGetValidKeyLength(17) == 20 && pass4; + pass4 = enc2.StaticGetValidKeyLength(20) == 20 && pass4; + pass4 = enc2.StaticGetValidKeyLength(24) == 24 && pass4; + pass4 = enc2.StaticGetValidKeyLength(28) == 28 && pass4; + pass4 = enc2.StaticGetValidKeyLength(31) == 32 && pass4; + pass4 = enc2.StaticGetValidKeyLength(32) == 32 && pass4; + pass4 = enc2.StaticGetValidKeyLength(33) == 32 && pass4; + + CAST256Decryption dec2; // 128, 160, 192, 224, or 256-bits (16 to 32-bytes, step 4) + pass2 = CAST256Decryption::DEFAULT_KEYLENGTH == 16 && pass2; + pass5 = dec2.StaticGetValidKeyLength(15) == 16 && pass5; + pass5 = dec2.StaticGetValidKeyLength(16) == 16 && pass5; + pass5 = dec2.StaticGetValidKeyLength(17) == 20 && pass5; + pass5 = dec2.StaticGetValidKeyLength(20) == 20 && pass5; + pass5 = dec2.StaticGetValidKeyLength(24) == 24 && pass5; + pass5 = dec2.StaticGetValidKeyLength(28) == 28 && pass5; + pass5 = dec2.StaticGetValidKeyLength(31) == 32 && pass5; + pass5 = dec2.StaticGetValidKeyLength(32) == 32 && pass5; + pass5 = dec2.StaticGetValidKeyLength(33) == 32 && pass5; + std::cout << (pass4 && pass5 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource val256(DataDir("TestData/cast256v.dat").c_str(), true, new HexDecoder); + pass6 = BlockTransformationTest(FixedRoundsCipherFactory(16), val256, 1) && pass6; + pass6 = BlockTransformationTest(FixedRoundsCipherFactory(24), val256, 1) && pass6; + pass6 = BlockTransformationTest(FixedRoundsCipherFactory(32), val256, 1) && pass6; + + return pass1 && pass2 && pass3 && pass4 && pass5 && pass6; +} + +bool ValidateSquare() +{ + std::cout << "\nSquare validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + SquareEncryption enc; // 128-bits only + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(15) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(17) == 16 && pass1; + + SquareDecryption dec; // 128-bits only + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(15) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(17) == 16 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/squareva.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata) && pass1 && pass2; +} + +bool ValidateSKIPJACK() +{ + std::cout << "\nSKIPJACK validation suite running...\n\n"; + bool pass1 = true, pass2 = true; + + SKIPJACKEncryption enc; // 80-bits only + pass1 = enc.StaticGetValidKeyLength(8) == 10 && pass1; + pass1 = enc.StaticGetValidKeyLength(9) == 10 && pass1; + pass1 = enc.StaticGetValidKeyLength(10) == 10 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 10 && pass1; + + SKIPJACKDecryption dec; // 80-bits only + pass2 = dec.StaticGetValidKeyLength(8) == 10 && pass2; + pass2 = dec.StaticGetValidKeyLength(9) == 10 && pass2; + pass2 = dec.StaticGetValidKeyLength(10) == 10 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 10 && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/skipjack.dat").c_str(), true, new HexDecoder); + return BlockTransformationTest(FixedRoundsCipherFactory(), valdata) && pass1 && pass2; +} + +bool ValidateSEAL() +{ + const byte input[] = {0x37,0xa0,0x05,0x95,0x9b,0x84,0xc4,0x9c,0xa4,0xbe,0x1e,0x05,0x06,0x73,0x53,0x0f,0x5f,0xb0,0x97,0xfd,0xf6,0xa1,0x3f,0xbd,0x6c,0x2c,0xde,0xcd,0x81,0xfd,0xee,0x7c}; + const byte key[] = {0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0}; + const byte iv[] = {0x01, 0x35, 0x77, 0xaf}; + byte output[32]; + + std::cout << "\nSEAL validation suite running...\n\n"; + + SEAL<>::Encryption seal(key, sizeof(key), iv); + unsigned int size = sizeof(input); + bool pass = true; + + memset(output, 1, size); + seal.ProcessString(output, input, size); + for (unsigned int i=0; iInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), (const byte *)&stars[0], false) + (Name::PaddingByte(), padding) + (Name::GroupSize(), insertLineBreaks ? maxLineLength : 0) + (Name::Separator(), ConstByteArrayParameter(lineBreak)) + (Name::Terminator(), ConstByteArrayParameter(lineBreak)) + (Name::Log2Base(), 6, true))); +} + +class MyDecoder : public BaseN_Decoder +{ +public: + MyDecoder(BufferedTransformation *attachment = NULLPTR); + void IsolatedInitialize(const NameValuePairs ¶ms); + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +MyDecoder::MyDecoder(BufferedTransformation *attachment) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) +{ +} + +void MyDecoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDecodingLookupArray(), false)(Name::Log2Base(), 6, true))); +} + +struct MyDecoderAlphabet +{ + MyDecoderAlphabet() { + std::fill(tab, tab+COUNTOF(tab), '*'); + } + byte tab[64]; +}; + +struct MyDecoderArray +{ + MyDecoderArray() { + std::fill(tab, tab+COUNTOF(tab), -1); + } + int tab[256]; +}; + +const int * MyDecoder::GetDecodingLookupArray() +{ + static bool s_initialized = false; + static MyDecoderAlphabet s_alpha; + static MyDecoderArray s_array; + + MEMORY_BARRIER(); + if (!s_initialized) + { + InitializeDecodingLookupArray(s_array.tab, s_alpha.tab, COUNTOF(s_alpha.tab), false); + s_initialized = true; + MEMORY_BARRIER(); + } + return s_array.tab; +} + +bool ValidateEncoder() +{ + // The default encoder and decoder alphabet are bogus. They are a + // string of '*'. To round trip a string both IsolatedInitialize + // must be called and work correctly. + std::cout << "\nCustom encoder validation running...\n\n"; + bool pass = true; + + int lookup[256]; + const char alphabet[64+1] = + "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz01234576789*"; + const char expected[] = + "ILcBMSgriDicmKmTi2oENCsuJTufN0yWjL1HnS8xKdaiOkeZK3gKock1ktmlo1q4LlsNPrAyGrG0gjO2gzQ5FQ=="; + + MyEncoder encoder; + std::string str1; + + AlgorithmParameters eparams = MakeParameters(Name::EncodingLookupArray(),(const byte*)alphabet) + (Name::InsertLineBreaks(), false); + encoder.IsolatedInitialize(eparams); + + encoder.Detach(new StringSink(str1)); + encoder.Put((const byte*) alphabet, 64); + encoder.MessageEnd(); + + MyDecoder decoder; + std::string str2; + + MyDecoder::InitializeDecodingLookupArray(lookup, (const byte*) alphabet, 64, false); + AlgorithmParameters dparams = MakeParameters(Name::DecodingLookupArray(),(const int*)lookup); + decoder.IsolatedInitialize(dparams); + + decoder.Detach(new StringSink(str2)); + decoder.Put(ConstBytePtr(str1), BytePtrSize(str1)); + decoder.MessageEnd(); + + pass = (str1 == std::string(expected)) && pass; + pass = (str2 == std::string(alphabet, 64)) && pass; + + std::cout << (pass ? "passed:" : "FAILED:"); + std::cout << " Encode and decode\n"; + + // Try forcing an empty message. This is the Monero bug + // at https://github.com/weidai11/cryptopp/issues/562. + { + MyDecoder decoder2; + SecByteBlock empty; + + AlgorithmParameters dparams2 = MakeParameters(Name::DecodingLookupArray(),(const int*)lookup); + decoder2.IsolatedInitialize(dparams2); + + decoder2.Detach(new Redirector(TheBitBucket())); + decoder2.Put(empty.BytePtr(), empty.SizeInBytes()); + decoder2.MessageEnd(); + + // Tame the optimizer + volatile lword size = decoder2.MaxRetrievable(); + lword shadow = size; + CRYPTOPP_UNUSED(shadow); + } + + std::cout << "passed: 0-length message\n"; + + return pass; +} + +bool ValidateSHACAL2() +{ + std::cout << "\nSHACAL-2 validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + SHACAL2Encryption enc; // 128 to 512-bits (16 to 64-bytes) + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(15) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 64 && pass1; + pass1 = enc.StaticGetValidKeyLength(65) == 64 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 64 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + SHACAL2Decryption dec; // 128 to 512-bits (16 to 64-bytes) + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(15) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 64 && pass2; + pass2 = dec.StaticGetValidKeyLength(65) == 64 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 64 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/shacal2v.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 4) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(64), valdata, 10) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateARIA() +{ + std::cout << "\nARIA validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + ARIAEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + ARIADecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/aria.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 15) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 15) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 15) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateSIMECK() +{ + std::cout << "\nSIMECK validation suite running...\n"; + + return RunTestDataFile("TestVectors/simeck.txt"); +} + +bool ValidateCHAM() +{ + std::cout << "\nCHAM validation suite running...\n"; + + return RunTestDataFile("TestVectors/cham.txt"); +} + +bool ValidateHIGHT() +{ + std::cout << "\nHIGHT validation suite running...\n"; + + return RunTestDataFile("TestVectors/hight.txt"); +} + +bool ValidateLEA() +{ + std::cout << "\nLEA validation suite running...\n"; + + return RunTestDataFile("TestVectors/lea.txt"); +} + +bool ValidateSIMON() +{ + std::cout << "\nSIMON validation suite running...\n"; + + return RunTestDataFile("TestVectors/simon.txt"); +} + +bool ValidateSPECK() +{ + std::cout << "\nSPECK validation suite running...\n"; + + return RunTestDataFile("TestVectors/speck.txt"); +} + +bool ValidateCamellia() +{ + std::cout << "\nCamellia validation suite running...\n\n"; + bool pass1 = true, pass2 = true, pass3 = true; + + CamelliaEncryption enc; + pass1 = enc.StaticGetValidKeyLength(8) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(16) == 16 && pass1; + pass1 = enc.StaticGetValidKeyLength(24) == 24 && pass1; + pass1 = enc.StaticGetValidKeyLength(32) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(64) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(128) == 32 && pass1; + pass1 = enc.StaticGetValidKeyLength(0) == enc.MinKeyLength() && pass1; + pass1 = enc.StaticGetValidKeyLength(SIZE_MAX) == enc.MaxKeyLength() && pass1; + + CamelliaDecryption dec; + pass2 = dec.StaticGetValidKeyLength(8) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(16) == 16 && pass2; + pass2 = dec.StaticGetValidKeyLength(24) == 24 && pass2; + pass2 = dec.StaticGetValidKeyLength(32) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(64) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(128) == 32 && pass2; + pass2 = dec.StaticGetValidKeyLength(0) == dec.MinKeyLength() && pass2; + pass2 = dec.StaticGetValidKeyLength(SIZE_MAX) == dec.MaxKeyLength() && pass2; + std::cout << (pass1 && pass2 ? "passed:" : "FAILED:") << " Algorithm key lengths\n"; + + FileSource valdata(DataDir("TestData/camellia.dat").c_str(), true, new HexDecoder); + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(16), valdata, 15) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(24), valdata, 15) && pass3; + pass3 = BlockTransformationTest(FixedRoundsCipherFactory(32), valdata, 15) && pass3; + return pass1 && pass2 && pass3; +} + +bool ValidateSalsa() +{ + std::cout << "\nSalsa validation suite running...\n"; + + return RunTestDataFile("TestVectors/salsa.txt"); +} + +bool ValidateChaCha() +{ + std::cout << "\nChaCha validation suite running...\n"; + + return RunTestDataFile("TestVectors/chacha.txt"); +} + +bool ValidateChaChaTLS() +{ + std::cout << "\nChaCha-TLS validation suite running...\n"; + + return RunTestDataFile("TestVectors/chacha_tls.txt"); +} + +bool ValidateSosemanuk() +{ + std::cout << "\nSosemanuk validation suite running...\n"; + return RunTestDataFile("TestVectors/sosemanuk.txt"); +} + +bool ValidateRabbit() +{ + std::cout << "\nRabbit validation suite running...\n"; + return RunTestDataFile("TestVectors/rabbit.txt"); +} + +bool ValidateHC128() +{ + std::cout << "\nHC-128 validation suite running...\n"; + return RunTestDataFile("TestVectors/hc128.txt"); +} + +bool ValidateHC256() +{ + std::cout << "\nHC-256 validation suite running...\n"; + return RunTestDataFile("TestVectors/hc256.txt"); +} + +bool ValidateVMAC() +{ + std::cout << "\nVMAC validation suite running...\n"; + return RunTestDataFile("TestVectors/vmac.txt"); +} + +bool ValidateCCM() +{ + std::cout << "\nAES/CCM validation suite running...\n"; + return RunTestDataFile("TestVectors/ccm.txt"); +} + +bool ValidateGCM() +{ + std::cout << "\nAES/GCM validation suite running...\n"; + std::cout << "\n2K tables:"; + bool pass = RunTestDataFile("TestVectors/gcm.txt", MakeParameters(Name::TableSize(), (int)2048)); + std::cout << "\n64K tables:"; + return RunTestDataFile("TestVectors/gcm.txt", MakeParameters(Name::TableSize(), (int)64*1024)) && pass; +} + +bool ValidateXTS() +{ + std::cout << "\nAES/XTS validation suite running...\n"; + return RunTestDataFile("TestVectors/xts.txt"); +} + +bool ValidateCMAC() +{ + std::cout << "\nCMAC validation suite running...\n"; + return RunTestDataFile("TestVectors/cmac.txt"); +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat5.cpp b/extension/third_party/cryptopp/validat5.cpp new file mode 100644 index 00000000..5dc56ed6 --- /dev/null +++ b/extension/third_party/cryptopp/validat5.cpp @@ -0,0 +1,2216 @@ +// validat5.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "aes.h" +#include "crc.h" +#include "adler32.h" + +#include "md2.h" +#include "md4.h" +#include "md5.h" + +#include "sha.h" +#include "sha3.h" +#include "shake.h" +#include "keccak.h" +#include "tiger.h" +#include "blake2.h" +#include "ripemd.h" +#include "siphash.h" +#include "poly1305.h" +#include "whrlpool.h" + +#include "pssr.h" +#include "hkdf.h" +#include "scrypt.h" +#include "pwdbased.h" + +#include "cmac.h" +#include "dmac.h" +#include "hmac.h" +#include "ttmac.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +struct HashTestTuple +{ + HashTestTuple(const char *input, const char *output, unsigned int repeatTimes=1) + : input((byte *)input), output((byte *)output), inputLen(strlen(input)), repeatTimes(repeatTimes) {} + + HashTestTuple(const char *input, unsigned int inputLen, const char *output, unsigned int repeatTimes) + : input((byte *)input), output((byte *)output), inputLen(inputLen), repeatTimes(repeatTimes) {} + + const byte *input, *output; + size_t inputLen; + unsigned int repeatTimes; +}; + +bool HashModuleTest(HashTransformation &md, const HashTestTuple *testSet, unsigned int testSetSize) +{ + bool pass=true, fail; + std::ostringstream oss; + + SecByteBlock digest(md.DigestSize()); + for (unsigned int i=0; i r', +// where 'r' is rate and acts like a blockSize, then TruncatedFinal acts +// like a traditional KDF and applies KeccakF1600 core function multiple +// times on state to create the stream. Regarding the NIST test vectors, +// the SHAKE128 KATs do not engage 'd > r'. However, the SHAKE256 KATs +// do engage it. +bool ValidateSHAKE_XOF() +{ + std::cout << "\nSHAKE XOF validation suite running...\n"; + bool pass = true, fail; + + ////// NIST test vectors SHAKE128VariableOut.rsp ////// + + // SHAKE128, COUNT = 0 (first test) + { + std::string m, msg = "84e950051876050dc851fbd99e6247b8"; + std::string o, out = "8599bd89f63a848c49ca593ec37a12c6"; + std::string r; + + StringSource(msg, true, new HexDecoder(new StringSink(m))); + StringSource(out, true, new HexDecoder(new StringSink(o))); + r.resize(o.size()); + + SHAKE128 hash((unsigned int)o.size()); + hash.Update(ConstBytePtr(m), BytePtrSize(m)); + hash.TruncatedFinal(BytePtr(r), BytePtrSize(r)); + + fail = r != o; + pass = pass & !fail; + + if (fail) + std::cout << "FAILED " << "SHAKE128 test COUNT=0" << std::endl; + + pass = pass && !fail; + } + + // SHAKE128, COUNT = 1125 (last test) + { + std::string m, msg = "0a13ad2c7a239b4ba73ea6592ae84ea9"; + std::string o, out = "5feaf99c15f48851943ff9baa6e5055d 8377f0dd347aa4dbece51ad3a6d9ce0c" + "01aee9fe2260b80a4673a909b532adcd d1e421c32d6460535b5fe392a58d2634" + "979a5a104d6c470aa3306c400b061db9 1c463b2848297bca2bc26d1864ba49d7" + "ff949ebca50fbf79a5e63716dc82b600 bd52ca7437ed774d169f6bf02e464879" + "56fba2230f34cd2a0485484d"; + std::string r; + + StringSource(msg, true, new HexDecoder(new StringSink(m))); + StringSource(out, true, new HexDecoder(new StringSink(o))); + r.resize(o.size()); + + SHAKE128 hash((unsigned int)o.size()); + hash.Update(ConstBytePtr(m), BytePtrSize(m)); + hash.TruncatedFinal(BytePtr(r), BytePtrSize(r)); + + fail = r != o; + pass = pass & !fail; + + if (fail) + std::cout << "FAILED " << "SHAKE128 test COUNT=1125" << std::endl; + + pass = pass && !fail; + } + + ////// NIST test vectors SHAKE256VariableOut.rsp ////// + + // SHAKE256, COUNT = 0 (first test) + { + std::string m, msg = "c61a9188812ae73994bc0d6d4021e31b f124dc72669749111232da7ac29e61c4"; + std::string o, out = "23ce"; + std::string r; + + StringSource(msg, true, new HexDecoder(new StringSink(m))); + StringSource(out, true, new HexDecoder(new StringSink(o))); + r.resize(o.size()); + + SHAKE256 hash((unsigned int)o.size()); + hash.Update(ConstBytePtr(m), BytePtrSize(m)); + hash.TruncatedFinal(BytePtr(r), BytePtrSize(r)); + + fail = r != o; + pass = pass & !fail; + + if (fail) + std::cout << "FAILED " << "SHAKE256 test COUNT=0" << std::endl; + + pass = pass && !fail; + } + + // SHAKE256, COUNT = 1245 (last test) + { + std::string m, msg = "8d8001e2c096f1b88e7c9224a086efd4 797fbf74a8033a2d422a2b6b8f6747e4"; + std::string o, out = "2e975f6a8a14f0704d51b13667d8195c 219f71e6345696c49fa4b9d08e9225d3" + "d39393425152c97e71dd24601c11abcf a0f12f53c680bd3ae757b8134a9c10d4" + "29615869217fdd5885c4db174985703a 6d6de94a667eac3023443a8337ae1bc6" + "01b76d7d38ec3c34463105f0d3949d78 e562a039e4469548b609395de5a4fd43" + "c46ca9fd6ee29ada5efc07d84d553249 450dab4a49c483ded250c9338f85cd93" + "7ae66bb436f3b4026e859fda1ca57143 2f3bfc09e7c03ca4d183b741111ca048" + "3d0edabc03feb23b17ee48e844ba2408 d9dcfd0139d2e8c7310125aee801c61a" + "b7900d1efc47c078281766f361c5e611 1346235e1dc38325666c"; + std::string r; + + StringSource(msg, true, new HexDecoder(new StringSink(m))); + StringSource(out, true, new HexDecoder(new StringSink(o))); + r.resize(o.size()); + + SHAKE256 hash((unsigned int)o.size()); + hash.Update(ConstBytePtr(m), BytePtrSize(m)); + hash.TruncatedFinal(BytePtr(r), BytePtrSize(r)); + + fail = r != o; + pass = pass & !fail; + + if (fail) + std::cout << "FAILED " << "SHAKE256 test COUNT=0" << std::endl; + + pass = pass && !fail; + } + + std::cout << (!pass ? "FAILED " : "passed ") << "SHAKE XOF message digests" << std::endl; + + return pass; +} + +bool ValidateTiger() +{ + std::cout << "\nTiger validation suite running...\n\n"; + + HashTestTuple testSet[] = + { + HashTestTuple("", "\x32\x93\xac\x63\x0c\x13\xf0\x24\x5f\x92\xbb\xb1\x76\x6e\x16\x16\x7a\x4e\x58\x49\x2d\xde\x73\xf3"), + HashTestTuple("a", "\x77\xBE\xFB\xEF\x2E\x7E\xF8\xAB\x2E\xC8\xF9\x3B\xF5\x87\xA7\xFC\x61\x3E\x24\x7F\x5F\x24\x78\x09"), + HashTestTuple("abc", "\x2a\xab\x14\x84\xe8\xc1\x58\xf2\xbf\xb8\xc5\xff\x41\xb5\x7a\x52\x51\x29\x13\x1c\x95\x7b\x5f\x93"), + HashTestTuple("Tiger", "\xdd\x00\x23\x07\x99\xf5\x00\x9f\xec\x6d\xeb\xc8\x38\xbb\x6a\x27\xdf\x2b\x9d\x6f\x11\x0c\x79\x37"), + HashTestTuple("message digest", "\xD9\x81\xF8\xCB\x78\x20\x1A\x95\x0D\xCF\x30\x48\x75\x1E\x44\x1C\x51\x7F\xCA\x1A\xA5\x5A\x29\xF6"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\x8d\xce\xa6\x80\xa1\x75\x83\xee\x50\x2b\xa3\x8a\x3c\x36\x86\x51\x89\x0f\xfb\xcc\xdc\x49\xa8\xcc"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "\xf7\x1c\x85\x83\x90\x2a\xfb\x87\x9e\xdf\xe6\x10\xf8\x2c\x0d\x47\x86\xa3\xa5\x34\x50\x44\x86\xb5"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789", "\x48\xce\xeb\x63\x08\xb8\x7d\x46\xe9\x5d\x65\x61\x12\xcd\xf1\x8d\x97\x91\x5f\x97\x65\x65\x89\x57"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham", "\x8a\x86\x68\x29\x04\x0a\x41\x0c\x72\x9a\xd2\x3f\x5a\xda\x71\x16\x03\xb3\xcd\xd3\x57\xe4\xc1\x5e"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.", "\xce\x55\xa6\xaf\xd5\x91\xf5\xeb\xac\x54\x7f\xf8\x4f\x89\x22\x7f\x93\x31\xda\xb0\xb6\x11\xc8\x89"), + HashTestTuple("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.", "\x63\x1a\xbd\xd1\x03\xeb\x9a\x3d\x24\x5b\x6d\xfd\x4d\x77\xb2\x57\xfc\x74\x39\x50\x1d\x15\x68\xdd"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "\xc5\x40\x34\xe5\xb4\x3e\xb8\x00\x58\x48\xa7\xe0\xae\x6a\xac\x76\xe4\xff\x59\x0a\xe7\x15\xfd\x25") + }; + + Tiger tiger; + + return HashModuleTest(tiger, testSet, COUNTOF(testSet)); +} + +bool ValidateRIPEMD() +{ + HashTestTuple testSet128[] = + { + HashTestTuple("", "\xcd\xf2\x62\x13\xa1\x50\xdc\x3e\xcb\x61\x0f\x18\xf6\xb3\x8b\x46"), + HashTestTuple("a", "\x86\xbe\x7a\xfa\x33\x9d\x0f\xc7\xcf\xc7\x85\xe7\x2f\x57\x8d\x33"), + HashTestTuple("abc", "\xc1\x4a\x12\x19\x9c\x66\xe4\xba\x84\x63\x6b\x0f\x69\x14\x4c\x77"), + HashTestTuple("message digest", "\x9e\x32\x7b\x3d\x6e\x52\x30\x62\xaf\xc1\x13\x2d\x7d\xf9\xd1\xb8"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xfd\x2a\xa6\x07\xf7\x1d\xc8\xf5\x10\x71\x49\x22\xb3\x71\x83\x4e"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\xa1\xaa\x06\x89\xd0\xfa\xfa\x2d\xdc\x22\xe8\x8b\x49\x13\x3a\x06"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xd1\xe9\x59\xeb\x17\x9c\x91\x1f\xae\xa4\x62\x4c\x60\xc5\xc7\x02"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x3f\x45\xef\x19\x47\x32\xc2\xdb\xb2\xc4\xa2\xc7\x69\x79\x5f\xa3"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\x4a\x7f\x57\x23\xf9\x54\xeb\xa1\x21\x6c\x9d\x8f\x63\x20\x43\x1f", 15625) + }; + + HashTestTuple testSet160[] = + { + HashTestTuple("", "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31"), + HashTestTuple("a", "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe"), + HashTestTuple("abc", "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc"), + HashTestTuple("message digest", "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb\xd3\x32\x3c\xab\x82\xbf\x63\x32\x6b\xfb"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\x52\x78\x32\x43\xc1\x69\x7b\xdb\xe1\x6d\x37\xf9\x7f\x68\xf0\x83\x25\xdc\x15\x28", 15625) + }; + + HashTestTuple testSet256[] = + { + HashTestTuple("", "\x02\xba\x4c\x4e\x5f\x8e\xcd\x18\x77\xfc\x52\xd6\x4d\x30\xe3\x7a\x2d\x97\x74\xfb\x1e\x5d\x02\x63\x80\xae\x01\x68\xe3\xc5\x52\x2d"), + HashTestTuple("a", "\xf9\x33\x3e\x45\xd8\x57\xf5\xd9\x0a\x91\xba\xb7\x0a\x1e\xba\x0c\xfb\x1b\xe4\xb0\x78\x3c\x9a\xcf\xcd\x88\x3a\x91\x34\x69\x29\x25"), + HashTestTuple("abc", "\xaf\xbd\x6e\x22\x8b\x9d\x8c\xbb\xce\xf5\xca\x2d\x03\xe6\xdb\xa1\x0a\xc0\xbc\x7d\xcb\xe4\x68\x0e\x1e\x42\xd2\xe9\x75\x45\x9b\x65"), + HashTestTuple("message digest", "\x87\xe9\x71\x75\x9a\x1c\xe4\x7a\x51\x4d\x5c\x91\x4c\x39\x2c\x90\x18\xc7\xc4\x6b\xc1\x44\x65\x55\x4a\xfc\xdf\x54\xa5\x07\x0c\x0e"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\x64\x9d\x30\x34\x75\x1e\xa2\x16\x77\x6b\xf9\xa1\x8a\xcc\x81\xbc\x78\x96\x11\x8a\x51\x97\x96\x87\x82\xdd\x1f\xd9\x7d\x8d\x51\x33"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\x38\x43\x04\x55\x83\xaa\xc6\xc8\xc8\xd9\x12\x85\x73\xe7\xa9\x80\x9a\xfb\x2a\x0f\x34\xcc\xc3\x6e\xa9\xe7\x2f\x16\xf6\x36\x8e\x3f"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\x57\x40\xa4\x08\xac\x16\xb7\x20\xb8\x44\x24\xae\x93\x1c\xbb\x1f\xe3\x63\xd1\xd0\xbf\x40\x17\xf1\xa8\x9f\x7e\xa6\xde\x77\xa0\xb8"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x06\xfd\xcc\x7a\x40\x95\x48\xaa\xf9\x13\x68\xc0\x6a\x62\x75\xb5\x53\xe3\xf0\x99\xbf\x0e\xa4\xed\xfd\x67\x78\xdf\x89\xa8\x90\xdd"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\xac\x95\x37\x44\xe1\x0e\x31\x51\x4c\x15\x0d\x4d\x8d\x7b\x67\x73\x42\xe3\x33\x99\x78\x82\x96\xe4\x3a\xe4\x85\x0c\xe4\xf9\x79\x78", 15625) + }; + + HashTestTuple testSet320[] = + { + HashTestTuple("", "\x22\xd6\x5d\x56\x61\x53\x6c\xdc\x75\xc1\xfd\xf5\xc6\xde\x7b\x41\xb9\xf2\x73\x25\xeb\xc6\x1e\x85\x57\x17\x7d\x70\x5a\x0e\xc8\x80\x15\x1c\x3a\x32\xa0\x08\x99\xb8"), + HashTestTuple("a", "\xce\x78\x85\x06\x38\xf9\x26\x58\xa5\xa5\x85\x09\x75\x79\x92\x6d\xda\x66\x7a\x57\x16\x56\x2c\xfc\xf6\xfb\xe7\x7f\x63\x54\x2f\x99\xb0\x47\x05\xd6\x97\x0d\xff\x5d"), + HashTestTuple("abc", "\xde\x4c\x01\xb3\x05\x4f\x89\x30\xa7\x9d\x09\xae\x73\x8e\x92\x30\x1e\x5a\x17\x08\x5b\xef\xfd\xc1\xb8\xd1\x16\x71\x3e\x74\xf8\x2f\xa9\x42\xd6\x4c\xdb\xc4\x68\x2d"), + HashTestTuple("message digest", "\x3a\x8e\x28\x50\x2e\xd4\x5d\x42\x2f\x68\x84\x4f\x9d\xd3\x16\xe7\xb9\x85\x33\xfa\x3f\x2a\x91\xd2\x9f\x84\xd4\x25\xc8\x8d\x6b\x4e\xff\x72\x7d\xf6\x6a\x7c\x01\x97"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xca\xbd\xb1\x81\x0b\x92\x47\x0a\x20\x93\xaa\x6b\xce\x05\x95\x2c\x28\x34\x8c\xf4\x3f\xf6\x08\x41\x97\x51\x66\xbb\x40\xed\x23\x40\x04\xb8\x82\x44\x63\xe6\xb0\x09"), + HashTestTuple("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "\xd0\x34\xa7\x95\x0c\xf7\x22\x02\x1b\xa4\xb8\x4d\xf7\x69\xa5\xde\x20\x60\xe2\x59\xdf\x4c\x9b\xb4\xa4\x26\x8c\x0e\x93\x5b\xbc\x74\x70\xa9\x69\xc9\xd0\x72\xa1\xac"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xed\x54\x49\x40\xc8\x6d\x67\xf2\x50\xd2\x32\xc3\x0b\x7b\x3e\x57\x70\xe0\xc6\x0c\x8c\xb9\xa4\xca\xfe\x3b\x11\x38\x8a\xf9\x92\x0e\x1b\x99\x23\x0b\x84\x3c\x86\xa4"), + HashTestTuple("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "\x55\x78\x88\xaf\x5f\x6d\x8e\xd6\x2a\xb6\x69\x45\xc6\xd2\xa0\xa4\x7e\xcd\x53\x41\xe9\x15\xeb\x8f\xea\x1d\x05\x24\x95\x5f\x82\x5d\xc7\x17\xe4\xa0\x08\xab\x2d\x42"), + HashTestTuple("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\xbd\xee\x37\xf4\x37\x1e\x20\x64\x6b\x8b\x0d\x86\x2d\xda\x16\x29\x2a\xe3\x6f\x40\x96\x5e\x8c\x85\x09\xe6\x3d\x1d\xbd\xde\xcc\x50\x3e\x2b\x63\xeb\x92\x45\xbb\x66", 15625) + }; + + bool pass = true; + + std::cout << "\nRIPEMD-128 validation suite running...\n\n"; + RIPEMD128 md128; + pass = HashModuleTest(md128, testSet128, COUNTOF(testSet128)) && pass; + + std::cout << "\nRIPEMD-160 validation suite running...\n\n"; + RIPEMD160 md160; + pass = HashModuleTest(md160, testSet160, COUNTOF(testSet160)) && pass; + + std::cout << "\nRIPEMD-256 validation suite running...\n\n"; + RIPEMD256 md256; + pass = HashModuleTest(md256, testSet256, COUNTOF(testSet256)) && pass; + + std::cout << "\nRIPEMD-320 validation suite running...\n\n"; + RIPEMD320 md320; + pass = HashModuleTest(md320, testSet320, COUNTOF(testSet320)) && pass; + + return pass; +} + +#ifdef CRYPTOPP_REMOVED +bool ValidateHAVAL() +{ + HashTestTuple testSet[] = + { + HashTestTuple("", "\xC6\x8F\x39\x91\x3F\x90\x1F\x3D\xDF\x44\xC7\x07\x35\x7A\x7D\x70"), + HashTestTuple("a", "\x4D\xA0\x8F\x51\x4A\x72\x75\xDB\xC4\xCE\xCE\x4A\x34\x73\x85\x98\x39\x83\xA8\x30"), + HashTestTuple("HAVAL", "\x0C\x13\x96\xD7\x77\x26\x89\xC4\x67\x73\xF3\xDA\xAC\xA4\xEF\xA9\x82\xAD\xBF\xB2\xF1\x46\x7E\xEA"), + HashTestTuple("0123456789", "\xBE\xBD\x78\x16\xF0\x9B\xAE\xEC\xF8\x90\x3B\x1B\x9B\xC6\x72\xD9\xFA\x42\x8E\x46\x2B\xA6\x99\xF8\x14\x84\x15\x29"), + HashTestTuple("abcdefghijklmnopqrstuvwxyz", "\xC9\xC7\xD8\xAF\xA1\x59\xFD\x9E\x96\x5C\xB8\x3F\xF5\xEE\x6F\x58\xAE\xDA\x35\x2C\x0E\xFF\x00\x55\x48\x15\x3A\x61\x55\x1C\x38\xEE"), + HashTestTuple("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "\xB4\x5C\xB6\xE6\x2F\x2B\x13\x20\xE4\xF8\xF1\xB0\xB2\x73\xD4\x5A\xDD\x47\xC3\x21\xFD\x23\x99\x9D\xCF\x40\x3A\xC3\x76\x36\xD9\x63") + }; + + bool pass=true; + + std::cout << "\nHAVAL validation suite running...\n\n"; + { + HAVAL3 md(16); + pass = HashModuleTest(md, testSet+0, 1) && pass; + } + { + HAVAL3 md(20); + pass = HashModuleTest(md, testSet+1, 1) && pass; + } + { + HAVAL4 md(24); + pass = HashModuleTest(md, testSet+2, 1) && pass; + } + { + HAVAL4 md(28); + pass = HashModuleTest(md, testSet+3, 1) && pass; + } + { + HAVAL5 md(32); + pass = HashModuleTest(md, testSet+4, 1) && pass; + } + { + HAVAL5 md(32); + pass = HashModuleTest(md, testSet+5, 1) && pass; + } + + return pass; +} +#endif + +bool ValidatePanama() +{ + return RunTestDataFile("TestVectors/panama.txt"); +} + +bool ValidateWhirlpool() +{ + return RunTestDataFile("TestVectors/whrlpool.txt"); +} + +#ifdef CRYPTOPP_REMOVED +bool ValidateMD5MAC() +{ + const byte keys[2][MD5MAC::KEYLENGTH]={ + {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}, + {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10}}; + + const char *TestVals[7]={ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}; + + const byte output[2][7][MD5MAC::DIGESTSIZE]={ + {{0x1f,0x1e,0xf2,0x37,0x5c,0xc0,0xe0,0x84,0x4f,0x98,0xe7,0xe8,0x11,0xa3,0x4d,0xa8}, + {0x7a,0x76,0xee,0x64,0xca,0x71,0xef,0x23,0x7e,0x26,0x29,0xed,0x94,0x52,0x73,0x65}, + {0xe8,0x01,0x3c,0x11,0xf7,0x20,0x9d,0x13,0x28,0xc0,0xca,0xa0,0x4f,0xd0,0x12,0xa6}, + {0xc8,0x95,0x53,0x4f,0x22,0xa1,0x74,0xbc,0x3e,0x6a,0x25,0xa2,0xb2,0xef,0xd6,0x30}, + {0x91,0x72,0x86,0x7e,0xb6,0x00,0x17,0x88,0x4c,0x6f,0xa8,0xcc,0x88,0xeb,0xe7,0xc9}, + {0x3b,0xd0,0xe1,0x1d,0x5e,0x09,0x4c,0xb7,0x1e,0x35,0x44,0xac,0xa9,0xb8,0xbf,0xa2}, + {0x93,0x37,0x16,0x64,0x44,0xcc,0x95,0x35,0xb7,0xd5,0xb8,0x0f,0x91,0xe5,0x29,0xcb}}, + {{0x2f,0x6e,0x73,0x13,0xbf,0xbb,0xbf,0xcc,0x3a,0x2d,0xde,0x26,0x8b,0x59,0xcc,0x4d}, + {0x69,0xf6,0xca,0xff,0x40,0x25,0x36,0xd1,0x7a,0xe1,0x38,0x03,0x2c,0x0c,0x5f,0xfd}, + {0x56,0xd3,0x2b,0x6c,0x34,0x76,0x65,0xd9,0x74,0xd6,0xf7,0x5c,0x3f,0xc6,0xf0,0x40}, + {0xb8,0x02,0xb2,0x15,0x4e,0x59,0x8b,0x6f,0x87,0x60,0x56,0xc7,0x85,0x46,0x2c,0x0b}, + {0x5a,0xde,0xf4,0xbf,0xf8,0x04,0xbe,0x08,0x58,0x7e,0x94,0x41,0xcf,0x6d,0xbd,0x57}, + {0x18,0xe3,0x49,0xa5,0x24,0x44,0xb3,0x0e,0x5e,0xba,0x5a,0xdd,0xdc,0xd9,0xf1,0x8d}, + {0xf2,0xb9,0x06,0xa5,0xb8,0x4b,0x9b,0x4b,0xbe,0x95,0xed,0x32,0x56,0x4e,0xe7,0xeb}}}; + + byte digest[MD5MAC::DIGESTSIZE]; + bool pass=true, fail; + std::ostringstream oss; + + oss << "\nMD5MAC validation suite running...\n"; + + for (int k=0; k<2; k++) + { + MD5MAC mac(keys[k]); + oss << "\nKEY: "; + for (int j=0;j XMACC_MD5; + + const byte keys[2][XMACC_MD5::KEYLENGTH]={ + {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb}, + {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98}}; + + const word32 counters[2]={0xccddeeff, 0x76543210}; + + const char *TestVals[7]={ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}; + + const byte output[2][7][XMACC_MD5::DIGESTSIZE]={ + {{0xcc,0xdd,0xef,0x00,0xfa,0x89,0x54,0x92,0x86,0x32,0xda,0x2a,0x3f,0x29,0xc5,0x52,0xa0,0x0d,0x05,0x13}, + {0xcc,0xdd,0xef,0x01,0xae,0xdb,0x8b,0x7b,0x69,0x71,0xc7,0x91,0x71,0x48,0x9d,0x18,0xe7,0xdf,0x9d,0x5a}, + {0xcc,0xdd,0xef,0x02,0x5e,0x01,0x2e,0x2e,0x4b,0xc3,0x83,0x62,0xc2,0xf4,0xe6,0x18,0x1c,0x44,0xaf,0xca}, + {0xcc,0xdd,0xef,0x03,0x3e,0xa9,0xf1,0xe0,0x97,0x91,0xf8,0xe2,0xbe,0xe0,0xdf,0xf3,0x41,0x03,0xb3,0x5a}, + {0xcc,0xdd,0xef,0x04,0x2e,0x6a,0x8d,0xb9,0x72,0xe3,0xce,0x9f,0xf4,0x28,0x45,0xe7,0xbc,0x80,0xa9,0xc7}, + {0xcc,0xdd,0xef,0x05,0x1a,0xd5,0x40,0x78,0xfb,0x16,0x37,0xfc,0x7a,0x1d,0xce,0xb4,0x77,0x10,0xb2,0xa0}, + {0xcc,0xdd,0xef,0x06,0x13,0x2f,0x11,0x47,0xd7,0x1b,0xb5,0x52,0x36,0x51,0x26,0xb0,0x96,0xd7,0x60,0x81}}, + {{0x76,0x54,0x32,0x11,0xe9,0xcb,0x74,0x32,0x07,0x93,0xfe,0x01,0xdd,0x27,0xdb,0xde,0x6b,0x77,0xa4,0x56}, + {0x76,0x54,0x32,0x12,0xcd,0x55,0x87,0x5c,0xc0,0x35,0x85,0x99,0x44,0x02,0xa5,0x0b,0x8c,0xe7,0x2c,0x68}, + {0x76,0x54,0x32,0x13,0xac,0xfd,0x87,0x50,0xc3,0x8f,0xcd,0x58,0xaa,0xa5,0x7e,0x7a,0x25,0x63,0x26,0xd1}, + {0x76,0x54,0x32,0x14,0xe3,0x30,0xf5,0xdd,0x27,0x2b,0x76,0x22,0x7f,0xaa,0x90,0x73,0x6a,0x48,0xdb,0x00}, + {0x76,0x54,0x32,0x15,0xfc,0x57,0x00,0x20,0x7c,0x9d,0xf6,0x30,0x6f,0xbd,0x46,0x3e,0xfb,0x8a,0x2c,0x60}, + {0x76,0x54,0x32,0x16,0xfb,0x0f,0xd3,0xdf,0x4c,0x4b,0xc3,0x05,0x9d,0x63,0x1e,0xba,0x25,0x2b,0xbe,0x35}, + {0x76,0x54,0x32,0x17,0xc6,0xfe,0xe6,0x5f,0xb1,0x35,0x8a,0xf5,0x32,0x7a,0x80,0xbd,0xb8,0x72,0xee,0xae}}}; + + // Coverity finding, also see http://stackoverflow.com/a/34509163/608639. + StreamState ss(std::cout); + + byte digest[XMACC_MD5::DIGESTSIZE]; + bool pass=true, fail; + + std::cout << "\nXMACC/MD5 validation suite running...\n"; + + for (int k=0; k<2; k++) + { + XMACC_MD5 mac(keys[k], counters[k]); + std::cout << "\nKEY: "; + for (int j=0;j pbkdf; + + std::cout << "\nPKCS #12 PBKDF validation suite running...\n\n"; + pass = TestPBKDF(pbkdf, testSet, COUNTOF(testSet)) && pass; + } + + { + // from draft-ietf-smime-password-03.txt, at http://www.imc.org/draft-ietf-smime-password + PBKDF_TestTuple testSet[] = + { + {0, 5, "70617373776f7264", "1234567878563412", "D1DAA78615F287E6"}, + {0, 500, "416C6C206E2D656E746974696573206D75737420636F6D6D756E69636174652077697468206F74686572206E2d656E74697469657320766961206E2D3120656E746974656568656568656573", "1234567878563412","6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"} + }; + + PKCS5_PBKDF2_HMAC pbkdf; + + std::cout << "\nPKCS #5 PBKDF2 validation suite running...\n\n"; + pass = TestPBKDF(pbkdf, testSet, COUNTOF(testSet)) && pass; + } + + return pass; +} + +struct HKDF_TestTuple +{ + const char *hexSecret, *hexSalt, *hexInfo, *hexExpected; + size_t len; +}; + +bool TestHKDF(KeyDerivationFunction &kdf, const HKDF_TestTuple *testSet, unsigned int testSetSize) +{ + bool pass = true; + + for (unsigned int i=0; i") : ""); + std::cout << " "; + std::cout << (tuple.hexInfo ? (strlen(tuple.hexInfo) ? tuple.hexInfo : "<0-LEN INFO>") : ""); + std::cout << " "; + enc.Put(derived, derived.size()); + std::cout << std::endl; + } + + return pass; +} + +bool ValidateHKDF() +{ + bool pass = true; + + { + // SHA-1 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869 + const HKDF_TestTuple testSet[] = + { + // Test Case #4 + {"0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "085a01ea1b10f36933068b56efa5ad81 a4f14b822f5b091568a9cdd4f155fda2 c22e422478d305f3f896", 42}, + // Test Case #5 + {"000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f 404142434445464748494a4b4c4d4e4f", "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "0bd770a74d1160f7c9f12cd5912a06eb ff6adcae899d92191fe4305673ba2ffe 8fa3f1a4e5ad79f3f334b3b202b2173c 486ea37ce3d397ed034c7f9dfeb15c5e 927336d0441f4c4300e2cff0d0900b52 d3b4", 82}, + // Test Case #6 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", "0ac1af7002b3d761d1e55298da9d0506 b9ae52057220a306e07b6b87e8df21d0 ea00033de03984d34918", 42}, + // Test Case #7 + {"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", NULLPTR, "", "2c91117204d745f3500d636a62f64f0 ab3bae548aa53d423b0d1f27ebba6f5e5 673a081d70cce7acfc48", 42} + }; + + HKDF hkdf; + + std::cout << "\nRFC 5869 HKDF(SHA-1) validation suite running...\n\n"; + pass = TestHKDF(hkdf, testSet, COUNTOF(testSet)) && pass; + } + + { + // SHA-256 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869 + const HKDF_TestTuple testSet[] = + { + // Test Case #1 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf 34007208d5b887185865", 42}, + // Test Case #2 + {"000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f 404142434445464748494a4b4c4d4e4f", "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "b11e398dc80327a1c8e7f78c596a4934 4f012eda2d4efad8a050cc4c19afa97c 59045a99cac7827271cb41c65e590e09 da3275600c2f09b8367793a9aca3db71 cc30c58179ec3e87c14c01d5c1f3434f 1d87", 82}, + // Test Case #3 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", "8da4e775a563c18f715f802a063c5a31 b8a11f5c5ee1879ec3454e5f3c738d2d 9d201395faa4b61a96c8", 42} + }; + + HKDF hkdf; + + std::cout << "\nRFC 5869 HKDF(SHA-256) validation suite running...\n\n"; + pass = TestHKDF(hkdf, testSet, COUNTOF(testSet)) && pass; + } + + { + // SHA-512, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869 + const HKDF_TestTuple testSet[] = + { + // Test Case #0 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "832390086CDA71FB47625BB5CEB168E4 C8E26A1A16ED34D9FC7FE92C14815793 38DA362CB8D9F925D7CB", 42}, + // Test Case #0 + {"000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f 404142434445464748494a4b4c4d4e4f", "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "CE6C97192805B346E6161E821ED16567 3B84F400A2B514B2FE23D84CD189DDF1 B695B48CBD1C8388441137B3CE28F16A A64BA33BA466B24DF6CFCB021ECFF235 F6A2056CE3AF1DE44D572097A8505D9E 7A93", 82}, + // Test Case #0 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", "F5FA02B18298A72A8C23898A8703472C 6EB179DC204C03425C970E3B164BF90F FF22D04836D0E2343BAC", 42}, + // Test Case #0 + {"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", NULLPTR, "", "1407D46013D98BC6DECEFCFEE55F0F90 B0C7F63D68EB1A80EAF07E953CFC0A3A 5240A155D6E4DAA965BB", 42} + }; + + HKDF hkdf; + + std::cout << "\nRFC 5869 HKDF(SHA-512) validation suite running...\n\n"; + pass = TestHKDF(hkdf, testSet, COUNTOF(testSet)) && pass; + } + + { + // Whirlpool, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869 + const HKDF_TestTuple testSet[] = + { + // Test Case #0 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "0D29F74CCD8640F44B0DD9638111C1B5 766EFED752AF358109E2E7C9CD4A28EF 2F90B2AD461FBA0744D4", 42}, + // Test Case #0 + {"000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f 404142434445464748494a4b4c4d4e4f", "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "4EBE4FE2DCCEC42661699500BE279A99 3FED90351E19373B3926FAA3A410700B2 BBF77E254CF1451AE6068D64A0904D96 6F4FF25498445A501B88F50D21E3A68A8 90E09445DC5886DD00E7F4F7C58A5121 70", 82}, + // Test Case #0 + {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", "110632D0F7AEFAC31771FC66C22BB346 2614B81E4B04BA7F2B662E0BD694F564 58615F9A9CB56C57ECF2", 42}, + // Test Case #0 + {"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c" /*key*/, NULLPTR /*salt*/, "" /*info*/, "4089286EBFB23DD8A02F0C9DAA35D538 EB09CD0A8CBAB203F39083AA3E0BD313 E6F91E64F21A187510B0", 42} + }; + + HKDF hkdf; + + std::cout << "\nRFC 5869 HKDF(Whirlpool) validation suite running...\n\n"; + pass = TestHKDF(hkdf, testSet, COUNTOF(testSet)) && pass; + } + + return pass; +} + +struct Scrypt_TestTuple +{ + const char * passwd; + const char * salt; + word64 n; + word32 r; + word32 p; + const char * expect; +}; + +bool TestScrypt(KeyDerivationFunction &pbkdf, const Scrypt_TestTuple *testSet, unsigned int testSetSize) +{ + bool pass = true; + + for (unsigned int i=0; i::StaticAlgorithmName() != "Poly1305(AES)"); + std::cout << (fail ? "FAILED " : "passed ") << "algorithm name\n"; + pass = pass && !fail; + } + + // Test data from http://cr.yp.to/mac/poly1305-20050329.pdf + const Poly1305_TestTuples tests[] = + { + // Appendix B, Test 1 + { + "\xec\x07\x4c\x83\x55\x80\x74\x17\x01\x42\x5b\x62\x32\x35\xad\xd6" // Key + "\x85\x1f\xc4\x0c\x34\x67\xac\x0b\xe0\x5c\xc2\x04\x04\xf3\xf7\x00", + "\xf3\xf6", // Message + "\xfb\x44\x73\x50\xc4\xe8\x68\xc5\x2a\xc3\x27\x5c\xf9\xd4\x32\x7e", // Nonce + "\xf4\xc6\x33\xc3\x04\x4f\xc1\x45\xf8\x4f\x33\x5c\xb8\x19\x53\xde", // Digest + 32, 2, 16, 16 + }, + // Appendix B, Test 2 + { + "\x75\xde\xaa\x25\xc0\x9f\x20\x8e\x1d\xc4\xce\x6b\x5c\xad\x3f\xbf" // Key + "\x61\xee\x09\x21\x8d\x29\xb0\xaa\xed\x7e\x15\x4a\x2c\x55\x09\xcc", + "", // Message + "\x61\xee\x09\x21\x8d\x29\xb0\xaa\xed\x7e\x15\x4a\x2c\x55\x09\xcc", // Nonce + "\xdd\x3f\xab\x22\x51\xf1\x1a\xc7\x59\xf0\x88\x71\x29\xcc\x2e\xe7", // Digest + 32, 0, 16, 16 + }, + // Appendix B, Test 3 + { + "\x6a\xcb\x5f\x61\xa7\x17\x6d\xd3\x20\xc5\xc1\xeb\x2e\xdc\xdc\x74" // Key + "\x48\x44\x3d\x0b\xb0\xd2\x11\x09\xc8\x9a\x10\x0b\x5c\xe2\xc2\x08", + "\x66\x3c\xea\x19\x0f\xfb\x83\xd8\x95\x93\xf3\xf4\x76\xb6\xbc\x24" // Message + "\xd7\xe6\x79\x10\x7e\xa2\x6a\xdb\x8c\xaf\x66\x52\xd0\x65\x61\x36", + "\xae\x21\x2a\x55\x39\x97\x29\x59\x5d\xea\x45\x8b\xc6\x21\xff\x0e", // Nonce + "\x0e\xe1\xc1\x6b\xb7\x3f\x0f\x4f\xd1\x98\x81\x75\x3c\x01\xcd\xbe", // Digest + 32, 32, 16, 16 + }, + // Appendix B, Test 4 + { + "\xe1\xa5\x66\x8a\x4d\x5b\x66\xa5\xf6\x8c\xc5\x42\x4e\xd5\x98\x2d" // Key + "\x12\x97\x6a\x08\xc4\x42\x6d\x0c\xe8\xa8\x24\x07\xc4\xf4\x82\x07", + "\xab\x08\x12\x72\x4a\x7f\x1e\x34\x27\x42\xcb\xed\x37\x4d\x94\xd1" // Message + "\x36\xc6\xb8\x79\x5d\x45\xb3\x81\x98\x30\xf2\xc0\x44\x91\xfa\xf0" + "\x99\x0c\x62\xe4\x8b\x80\x18\xb2\xc3\xe4\xa0\xfa\x31\x34\xcb\x67" + "\xfa\x83\xe1\x58\xc9\x94\xd9\x61\xc4\xcb\x21\x09\x5c\x1b\xf9", + "\x9a\xe8\x31\xe7\x43\x97\x8d\x3a\x23\x52\x7c\x71\x28\x14\x9e\x3a", // Nonce + "\x51\x54\xad\x0d\x2c\xb2\x6e\x01\x27\x4f\xc5\x11\x48\x49\x1f\x1b", // Digest + 32, 63, 16, 16 + } + }; + + unsigned int count = 0; + byte digest[Poly1305::DIGESTSIZE]; + + // Positive tests + for (unsigned int i=0; i poly1305((const byte*)tests[i].key, tests[i].klen); + poly1305.Resynchronize((const byte*)tests[i].nonce, (int)tests[i].nlen); + poly1305.Update((const byte*)tests[i].message, tests[i].mlen); + poly1305.Final(digest); + + fail = memcmp(digest, tests[i].digest, tests[i].dlen) != 0; + if (fail) + { + std::cout << "FAILED " << "Poly1305 test set " << count << std::endl; + } + + count++; + pass = pass && !fail; + } + + // Positive tests + for (unsigned int i=0; i poly1305((const byte*)tests[i].key, tests[i].klen,(const byte*)tests[i].nonce, (int)tests[i].nlen); + poly1305.Update((const byte*)tests[i].message, tests[i].mlen); + poly1305.Final(digest); + + fail = memcmp(digest, tests[i].digest, tests[i].dlen) != 0; + if (fail) + { + std::cout << "FAILED " << "Poly1305 test set " << count << std::endl; + } + + count++; + pass = pass && !fail; + } + + // Negative tests + for (unsigned int i=0; i poly1305((const byte*)tests[i].key, tests[i].klen); + poly1305.Resynchronize((const byte*)tests[i].nonce, (int)tests[i].nlen); + poly1305.Update((const byte*)tests[i].message, tests[i].mlen); + poly1305.Final(digest); + + unsigned int next = (i+1) % COUNTOF(tests); + fail = memcmp(digest, tests[next].digest, tests[next].dlen) == 0; + if (fail) + { + std::cout << "FAILED " << "Poly1305 test set " << count << std::endl; + } + + count++; + pass = pass && !fail; + } + + std::cout << (!pass ? "FAILED " : "passed ") << count << " message authentication codes" << std::endl; + + return pass; +} + +bool ValidateSipHash() +{ + std::cout << "\nSipHash validation suite running...\n\n"; + bool fail, pass = true, pass1=true, pass2=true, pass3=true, pass4=true; + + { + fail = (SipHash<2,4>::StaticAlgorithmName() != "SipHash-2-4"); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-2-4 algorithm name\n"; + pass = pass && !fail; + + fail = (SipHash<2,4, false>::DIGESTSIZE != 8); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-2-4 64-bit digest size\n"; + pass = pass && !fail; + + fail = (SipHash<2,4, true>::DIGESTSIZE != 16); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-2-4 128-bit digest size\n"; + pass = pass && !fail; + + fail = (SipHash<4,8>::StaticAlgorithmName() != "SipHash-4-8"); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-4-8 algorithm name\n"; + pass = pass && !fail; + + fail = (SipHash<4,8, false>::DIGESTSIZE != 8); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-4-8 64-bit digest size\n"; + pass = pass && !fail; + + fail = (SipHash<4,8, true>::DIGESTSIZE != 16); + std::cout << (fail ? "FAILED " : "passed ") << "SipHash-4-8 128-bit digest size\n"; + pass = pass && !fail; + } + + // Siphash-2-4, 64-bit MAC + { + const byte key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; + SipHash<2,4, false> hash(key, 16); + byte digest[SipHash<2,4, false>::DIGESTSIZE]; + + hash.Update((const byte*)"", 0); + hash.Final(digest); + fail = memcmp("\x31\x0E\x0E\xDD\x47\xDB\x6F\x72", digest, COUNTOF(digest)) != 0; + pass1 = !fail && pass1; + + hash.Update((const byte*)"\x00", 1); + hash.Final(digest); + fail = memcmp("\xFD\x67\xDC\x93\xC5\x39\xF8\x74", digest, COUNTOF(digest)) != 0; + pass1 = !fail && pass1; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06", 7); + hash.Final(digest); + fail = memcmp("\x37\xD1\x01\x8B\xF5\x00\x02\xAB", digest, COUNTOF(digest)) != 0; + pass1 = !fail && pass1; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07", 8); + hash.Final(digest); + fail = memcmp("\x62\x24\x93\x9A\x79\xF5\xF5\x93", digest, COUNTOF(digest)) != 0; + pass1 = !fail && pass1; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08", 9); + hash.Final(digest); + fail = memcmp("\xB0\xE4\xA9\x0B\xDF\x82\x00\x9E", digest, COUNTOF(digest)) != 0; + pass1 = !fail && pass1; + + std::cout << (pass1 ? "passed " : "FAILED ") << "SipHash-2-4 64-bit MAC\n"; + pass = pass1 && pass; + } + + // Siphash-2-4, 128-bit MAC + { + const byte key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; + SipHash<2,4, true> hash(key, 16); + byte digest[SipHash<2,4, true>::DIGESTSIZE]; + + hash.Update((const byte*)"", 0); + hash.Final(digest); + fail = memcmp("\xA3\x81\x7F\x04\xBA\x25\xA8\xE6\x6D\xF6\x72\x14\xC7\x55\x02\x93", digest, COUNTOF(digest)) != 0; + pass3 = !fail && pass3; + + hash.Update((const byte*)"\x00", 1); + hash.Final(digest); + fail = memcmp("\xDA\x87\xC1\xD8\x6B\x99\xAF\x44\x34\x76\x59\x11\x9B\x22\xFC\x45", digest, COUNTOF(digest)) != 0; + pass3 = !fail && pass3; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06", 7); + hash.Final(digest); + fail = memcmp("\xA1\xF1\xEB\xBE\xD8\xDB\xC1\x53\xC0\xB8\x4A\xA6\x1F\xF0\x82\x39", digest, COUNTOF(digest)) != 0; + pass3 = !fail && pass3; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07", 8); + hash.Final(digest); + fail = memcmp("\x3B\x62\xA9\xBA\x62\x58\xF5\x61\x0F\x83\xE2\x64\xF3\x14\x97\xB4", digest, COUNTOF(digest)) != 0; + pass3 = !fail && pass3; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08", 9); + hash.Final(digest); + fail = memcmp("\x26\x44\x99\x06\x0A\xD9\xBA\xAB\xC4\x7F\x8B\x02\xBB\x6D\x71\xED", digest, COUNTOF(digest)) != 0; + pass3 = !fail && pass3; + + std::cout << (pass3 ? "passed " : "FAILED ") << "SipHash-2-4 128-bit MAC\n"; + pass = pass3 && pass; + } + + // Siphash-4-8, 64-bit MAC + { + const byte key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; + SipHash<4, 8, false> hash(key, 16); + byte digest[SipHash<4, 8, false>::DIGESTSIZE]; + + hash.Update((const byte*)"", 0); + hash.Final(digest); + fail = memcmp("\x41\xDA\x38\x99\x2B\x05\x79\xC8", digest, COUNTOF(digest)) != 0; + pass2 = !fail && pass2; + + hash.Update((const byte*)"\x00", 1); + hash.Final(digest); + fail = memcmp("\x51\xB8\x95\x52\xF9\x14\x59\xC8", digest, COUNTOF(digest)) != 0; + pass2 = !fail && pass2; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06", 7); + hash.Final(digest); + fail = memcmp("\x47\xD7\x3F\x71\x5A\xBE\xFD\x4E", digest, COUNTOF(digest)) != 0; + pass2 = !fail && pass2; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07", 8); + hash.Final(digest); + fail = memcmp("\x20\xB5\x8B\x9C\x07\x2F\xDB\x50", digest, COUNTOF(digest)) != 0; + pass2 = !fail && pass2; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08", 9); + hash.Final(digest); + fail = memcmp("\x36\x31\x9A\xF3\x5E\xE1\x12\x53", digest, COUNTOF(digest)) != 0; + pass2 = !fail && pass2; + + std::cout << (pass2 ? "passed " : "FAILED ") << "SipHash-4-8 64-bit MAC\n"; + pass = pass2 && pass; + } + + // Siphash-4-8, 128-bit MAC + { + const byte key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; + SipHash<4, 8, true> hash(key, 16); + byte digest[SipHash<4, 8, true>::DIGESTSIZE]; + + hash.Update((const byte*)"", 0); + hash.Final(digest); + fail = memcmp("\x1F\x64\xCE\x58\x6D\xA9\x04\xE9\xCF\xEC\xE8\x54\x83\xA7\x0A\x6C", digest, COUNTOF(digest)) != 0; + pass4 = !fail && pass4; + + hash.Update((const byte*)"\x00", 1); + hash.Final(digest); + fail = memcmp("\x47\x34\x5D\xA8\xEF\x4C\x79\x47\x6A\xF2\x7C\xA7\x91\xC7\xA2\x80", digest, COUNTOF(digest)) != 0; + pass4 = !fail && pass4; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06", 7); + hash.Final(digest); + fail = memcmp("\xED\x00\xE1\x3B\x18\x4B\xF1\xC2\x72\x6B\x8B\x54\xFF\xD2\xEE\xE0", digest, COUNTOF(digest)) != 0; + pass4 = !fail && pass4; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07", 8); + hash.Final(digest); + fail = memcmp("\xA7\xD9\x46\x13\x8F\xF9\xED\xF5\x36\x4A\x5A\x23\xAF\xCA\xE0\x63", digest, COUNTOF(digest)) != 0; + pass4 = !fail && pass4; + + hash.Update((const byte*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08", 9); + hash.Final(digest); + fail = memcmp("\x9E\x73\x14\xB7\x54\x5C\xEC\xA3\x8B\x9A\x55\x49\xE4\xFB\x0B\xE8", digest, COUNTOF(digest)) != 0; + pass4 = !fail && pass4; + + std::cout << (pass4 ? "passed " : "FAILED ") << "SipHash-4-8 128-bit MAC\n"; + pass = pass4 && pass; + } + + return pass; +} + +struct BLAKE2_TestTuples +{ + const char *key, *message, *digest; + size_t klen, mlen, dlen; +}; + +bool ValidateBLAKE2s() +{ + std::cout << "\nBLAKE2s validation suite running...\n\n"; + bool fail, pass = true; + + { + fail = strcmp(BLAKE2s::StaticAlgorithmName(), "BLAKE2s") != 0; + std::cout << (fail ? "FAILED " : "passed ") << "algorithm name\n"; + pass = pass && !fail; + } + + const BLAKE2_TestTuples tests[] = { + { + NULLPTR, + NULLPTR, + "\x8F\x38", + 0, 0, 2 + }, + { + NULLPTR, + NULLPTR, + "\x36\xE9\xD2\x46", + 0, 0, 4 + }, + { + NULLPTR, + NULLPTR, + "\xEF\x2A\x8B\x78\xDD\x80\xDA\x9C", + 0, 0, 8 + }, + { + NULLPTR, + NULLPTR, + "\x64\x55\x0D\x6F\xFE\x2C\x0A\x01\xA1\x4A\xBA\x1E\xAD\xE0\x20\x0C", + 0, 0, 16 + }, + { + NULLPTR, + NULLPTR, + "\x69\x21\x7A\x30\x79\x90\x80\x94\xE1\x11\x21\xD0\x42\x35\x4A\x7C\x1F\x55\xB6\x48\x2C\xA1\xA5\x1E\x1B\x25\x0D\xFD\x1E\xD0\xEE\xF9", + 0, 0, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x25\xEC\xB2\xF6\xA7\x81\x82\x57\x5D\x4B\xD7\x02\x72\x6D\xE1\x82\xBB\x1E\x21\xA8\x5D\x51\x34\xAD\xA2\x25\x8D\x7E\x21\x38\x03\xA7", + 0, 15, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xD4\x1C\x69\x87\x29\x7E\xDE\x4F\x08\x9B\x66\x9B\xC7\x0E\x62\xB9\xFA\xFA\x1C\x37\xCC\x31\x29\x22\xE0\xEA\x63\xE2\xE5\x85\xAA\x9F", + 0, 16, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xE0\xAD\xF2\xCC\x1F\x1F\x55\x3A\xE6\xC3\xCD\x3D\xF7\x68\xEA\x66\x9C\x32\xBE\x1D\x37\xF9\xA2\x61\xD4\x4F\x45\x26\x69\xD0\xD3\xA4", + 0, 17, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x10\x42\x65\x1C\x86\x15\xC4\x87\x69\x41\x19\x1F\xB6\xD5\xC5\x1D\xEB\x4C\xA1\x8C\xAF\xEF\xEB\x79\x69\x62\x87\x0D\x6A\x5D\xEE\x20", + 0, 31, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEA\xB1\xC5\xDD\xDF\xB5\x7C\x48\xC5\xB0\xB3\xF5\xBE\x5B\x47\x6D\xBB\xF5\xA3\x5C\x21\xD3\xDD\x94\x13\xA1\x04\xB8\x14\xF9\x2D\x4B", + 0, 32, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x7E\x82\x07\x49\x14\x62\x11\x96\xC5\xE8\xF3\xCB\x0F\x21\x7B\x37\xAE\x9B\x64\x58\xF4\x66\x01\xB9\x21\x23\xAC\x48\x64\x30\x83\x8F", + 0, 33, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x90\xB5\xA2\x5E\x8E\xA8\xA0\xC8\x74\x85\xAE\x18\x08\x9D\x92\xEB\x14\x5A\x5D\x4E\x2C\x60\x7B\xCB\x4B\x94\xD1\x0F\xAE\x59\x33\xC1", + 0, 63, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x71\x27\x28\x45\x9E\x67\xD7\xED\xB7\xAE\xFA\x88\xFF\x5C\x7E\x7B\x5D\xA9\x94\xA1\xC3\xB1\x7B\x64\xFB\xC1\x4E\x47\xCA\xDA\x45\xDD", + 0, 64, 32 + }, + { + NULLPTR, + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x58\x72\x3B\xB1\xBE\x18\x33\x12\x31\x5E\x6E\xF7\xF2\xB1\x84\x60\x97\x2C\x19\xD3\x01\xAF\x42\x00\xAB\xDB\x04\x26\xFC\xB0\xC1\xF8", + 0, 65, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + NULLPTR, + "\x9A\xD4\x81\xEF\x81\x6C\xAC\xB6\x59\x35\x8E\x6D\x6B\x73\xF1\xE5\xAC\x71\xD6\x6E\x8B\x12\x6B\x73\xD9\xD9\x7D\x2F\xA7\xA4\x61\xB4", + 15, 0, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x61\x8C\xBE\x19\x4B\x28\xDC\xA3\x8B\xE5\x1A\x79\x37\x45\xB4\x66\x3D\xF1\x9D\xB5\x8F\xFF\xEF\xC4\x5D\x37\x82\x25\x93\xEB\xE2\x93", + 15, 15, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xF3\xEC\x81\x61\x44\x5C\x6E\x2E\xE6\x52\x6A\xCA\x5F\xD9\x25\x74\x2A\x33\xB9\x1F\xEF\x0F\x7E\x54\x4F\x50\xC2\xFB\x04\x3C\x52\xD2", + 15, 16, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xF4\x81\x43\x6E\x2F\x4C\x5D\x09\x21\x73\x24\xDA\xA6\x23\x9E\xFD\xF8\x82\xCE\x0E\x3E\x4C\xB4\x17\xCC\x27\xCD\x1A\xAE\x90\x9B\x94", + 15, 17, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x99\x5E\x74\x8E\x96\xFE\xC0\x39\x5B\x73\xA3\xC0\x4E\xC7\xF7\xBE\x89\x83\xCD\x18\x24\x60\x60\x7B\xBC\xF5\x50\xF5\x84\xD1\x71\x6B", + 15, 31, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x21\x6E\xB9\xE2\xE4\xAF\x94\x5F\x6A\xA3\xD2\xCA\x25\x72\xFB\x8F\xDB\x95\x2F\xAC\x1C\x69\xC1\x26\x28\x31\x63\x16\x25\xA5\x2C\xF8", + 15, 32, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xE3\x71\x9F\xD8\xAE\x68\xC8\xC4\x5D\x17\xDD\x21\x33\xBB\xE1\x61\x51\x22\xC2\x3B\x00\x6E\xDD\x66\x7E\x2A\x0A\x6B\x77\xA9\x0B\x8D", + 15, 33, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xD3\xF8\x5F\x1B\xBE\x9C\x53\xCB\x7F\x5F\x5F\x62\x4D\x06\x36\x8F\xF8\x15\xA7\xF5\xEB\x77\xC6\xC5\xB4\x81\x15\x01\x82\x8D\x9D\x40", + 15, 63, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xBF\xA3\xDA\x09\xF9\xDE\x1B\xE6\x57\x4B\x55\x82\x85\x69\x79\xA1\x89\xD6\xF4\x15\x8B\x03\xFA\xAC\x6E\x00\x80\x26\xF1\x6B\xA1\x28", + 15, 64, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x77\x45\xEA\x51\x24\x46\x53\x19\x6F\xE4\xED\x6B\x54\x5C\x9B\x95\x88\xF5\xD4\x2B\x4C\x3E\xE6\xB7\xA1\xA3\x9F\xC4\x3A\x27\x1E\x45", + 15, 65, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + NULLPTR, + "\xFD\x61\x6D\xA6\x8E\xEF\x10\x24\x16\xC7\xBD\x7D\xC8\xCA\xF8\x2B\x3D\x92\x7B\xCB\xDD\x06\x8E\x7C\xCA\xA7\x72\x76\xCE\x6C\x8C\xD4", + 16, 0, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x10\x18\x97\x28\xFB\x05\x1D\xA0\xA8\xD6\x8F\x1C\xAD\x81\xFC\x7C\xA2\x6D\x41\x4B\xAA\x0C\x2A\x95\xB7\xF4\xEF\x9A\x67\xB5\x26\x5F", + 16, 15, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x9E\x3B\x50\xF3\xB5\xF4\xC9\xB3\x57\x03\x74\xF1\xB3\xA0\x4B\x3C\xC1\x71\xB4\x30\x42\xE4\x65\x90\xE5\xE2\x8A\x4D\xBA\xCD\xB1\x9F", + 16, 16, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x69\x70\x88\xAB\x61\x39\x46\xEA\x3B\xEB\x98\x98\x78\xCD\x8E\xF1\xB5\x7E\x81\xFC\x42\x7D\x46\xB8\xDA\x85\xD2\xEB\xB8\x56\xE4\xAC", + 16, 17, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xD2\xDA\xAC\x63\x09\xF1\x81\xBB\xCC\x06\x0D\xCC\xB8\xFA\x67\x08\x14\xD4\x6A\x50\xD7\x4F\xBF\x3B\x4A\x2E\x39\x4D\x45\x55\x27\x2F", + 16, 31, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEB\xB0\xF3\x27\xC3\xC4\x35\x97\x4F\x89\x73\x5A\x4D\xEB\xBB\x4C\x7C\xE9\x0C\x3E\x13\xEB\x07\x83\x74\x67\x0A\x86\xA7\xF4\xA8\x73", + 16, 32, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xC8\x96\xC3\x3A\x26\x77\x02\x84\x5D\x95\x1B\x0D\x9F\x5C\x07\xC5\x6D\x21\x5D\x7E\x20\xF1\x2F\xE0\x45\xE3\x50\x42\x9D\x58\xB0\xEA", + 16, 33, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x8A\x3C\x9F\xA4\xAC\x78\x82\xA7\x08\x76\xB9\xE1\xED\x22\x9B\x43\x45\xF4\xD4\x01\x76\xC4\xED\x5D\xA4\x5A\x41\xDE\x28\xB8\x09\x6C", + 16, 63, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x2D\x0C\x97\xBE\xD2\xF2\x13\x40\xB9\xC8\x15\x91\x6A\x55\x86\x7A\x43\xB1\xFD\xC7\x04\x08\x1B\x58\x37\x09\x12\x80\x40\x99\x7C\xED", + 16, 64, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xF7\xC0\x08\xE1\x31\x52\x9B\x71\x87\x51\xCF\xFF\x8B\x08\xA3\x14\x32\x08\x06\x8C\x22\xAD\x83\x97\x71\x95\xC5\x2C\xFC\x66\xA4\xAD", + 16, 65, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + NULLPTR, + "\xD0\xCE\x8E\x8D\xA0\xBA\xA4\x26\x0E\xD3\x1F\xD1\x7B\x78\xE6\x18\x15\xC6\xFF\xD8\x5A\xDB\x41\x8A\xE7\x36\xF0\xE7\xB9\x87\x2B\x6A", + 17, 0, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xCB\xE4\x63\xEB\x6B\x24\x6C\x08\x55\x84\x36\x30\x8E\xFA\xC1\x6B\x97\x43\xD7\x1F\x1F\x3E\x96\xBA\x7E\x87\xF2\x42\x3E\xF5\x69\x5E", + 17, 15, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEF\x39\x55\x9D\x92\x20\xDC\xB6\x8C\x21\x79\xD6\x7C\x51\xB7\x36\xAC\x4E\xFC\xA1\xDE\x66\xC7\xED\x40\xBF\x23\x15\xD1\x25\x82\x4B", + 17, 16, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xE3\x3E\x44\x7B\xA2\x7F\x69\x21\x09\x57\x79\x72\xE7\x4B\xE0\xC7\xCD\x54\xDC\xCD\x55\x60\x75\x61\x82\x66\xD7\x5B\x6F\x60\xDD\x73", + 17, 17, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xA9\xC4\x29\x2F\x5B\x49\x9A\xE0\x71\xE7\xFD\x65\x98\x53\x42\xC0\xC0\xF1\x75\xBC\xB5\x7B\x5C\xA1\x61\xFC\x8B\x45\x44\x54\xEC\x06", + 17, 31, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x29\x60\xBD\x05\x28\xEA\xF1\xA9\x43\xEF\x2D\x87\xC7\xB5\x27\x47\x33\xBA\xC8\x0C\x9F\x1C\xF5\x72\x62\x4C\xA7\x9E\x10\x23\x66\x76", + 17, 32, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xE2\xF1\x33\x23\x9D\xD8\xBC\x60\x1F\xB7\xD8\x21\xF5\x13\x98\xE2\x5C\x24\x0E\xC0\x60\x18\xB4\x0B\x93\xF1\x04\x25\xC5\xEC\x20\x14", + 17, 33, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEB\x4F\x8D\xB3\xF5\x03\x72\x55\x72\xCE\xF3\x91\x22\xCD\xEA\x5A\xC4\x9A\xD0\x42\xE1\xC4\x62\x90\xCE\x11\x9E\xFD\x11\xDB\xCA\x23", + 17, 63, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xB5\x9A\xA7\x74\xDA\xB8\xDE\x5C\xBB\xC3\x5A\xFC\xF0\xD7\xAF\x51\x1E\x0F\x05\x45\xDB\xDA\xB7\xA4\xA6\x52\xB2\x9E\x0E\x23\x14\x3D", + 17, 64, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x69\xA2\x95\x6C\x87\xED\x22\x76\x0A\x53\x75\x6D\x28\xF4\xCD\xC5\xF7\xF9\x88\x51\x73\xA7\xD9\x44\x0C\x96\xB1\x5F\xE5\x57\xFE\xE3", + 17, 65, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + NULLPTR, + "\x39\x4A\xB9\x85\xDD\xFF\x59\x59\x84\x5A\xF7\x54\xD6\xFC\x19\xFB\x94\x0E\xAE\xA4\xEA\x70\x54\x3E\x0D\x7E\x9D\xC7\x8A\x22\x77\x3B", + 31, 0, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x1B\x46\x57\xC0\x48\x26\x7B\xC6\x17\xEC\xD5\x76\x89\xEE\x81\xE5\x5B\xE0\xAC\xCE\xB7\x5D\x33\x2A\xAF\xB6\xE2\xF6\xC0\xBB\x93\xE6", + 31, 15, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x53\xB3\x3A\x58\x98\xD2\x0D\x25\x61\x5A\x0C\xF5\x74\x7F\x44\x2F\x51\x70\x31\x66\x5E\x41\x5E\xBC\xF5\xF0\x03\x12\x98\x12\x90\xCC", + 31, 16, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x0B\x2C\x2A\x74\x72\x12\x18\xE1\xCE\xCD\x8A\x7E\xFC\xCE\x8D\x57\xBE\x42\x1A\xCC\xA2\x20\x24\x33\xC5\x1E\x31\x54\x1F\xB6\x45\xBD", + 31, 17, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEF\x13\x95\xD4\x42\xC9\x9A\x04\xFE\xF0\x11\xE9\x72\xA9\x37\x74\x3E\x14\xC4\x4C\x58\x0C\xAC\x81\x4A\x75\x73\x35\x05\xC0\x81\x32", + 31, 31, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x0D\x35\xCF\x7F\x82\x08\x1E\x1B\xE9\x1E\x75\xE1\x96\x05\x9F\xBD\x63\x94\x8E\xE0\x71\xEF\x53\xDE\x79\xC6\x68\x21\xD6\x8A\x5A\xE4", + 31, 32, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x74\x0D\xCB\x50\x59\x59\xB9\x48\x52\x2B\x0B\x2A\x1F\xFC\x4F\x12\xF5\x9F\x49\x11\xED\x43\x61\xA6\x38\x8D\xF9\x35\x5C\xCD\x18\xBB", + 31, 33, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xDD\x48\xE5\xE8\x86\x8E\x61\xFF\x8A\x85\xC6\x5A\xB8\x5A\x32\xD2\x2A\x9C\xA2\xC8\xDC\xB9\xD6\x0A\x44\xD3\xF1\xB4\x8B\x5B\xD3\x80", + 31, 63, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x81\xEF\xAD\x79\x16\xE4\x29\x02\xDB\x89\x8D\xF2\xA4\x6D\xB4\xC4\x2A\x8C\xC6\x7E\xDE\x9B\xF7\x63\xB2\x10\xED\x15\xED\x0A\x0E\x3C", + 31, 64, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEB\x54\xC4\x8A\x8F\x92\x53\x4D\xDF\x1D\x78\xCA\x98\x38\xF9\x10\xE4\x05\xCD\x6D\xB6\x82\x3B\x76\xB7\x82\x3A\xD2\x20\x77\xD4\x89", + 31, 65, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + NULLPTR, + "\x18\xE3\xCE\x19\x98\x7B\xA5\x0B\x30\xDD\x14\x4C\x16\xF2\x26\x55\xEB\xA3\x14\x09\xD6\x62\x10\xBC\x38\xBB\xC1\x4B\x5D\xAB\x05\x19", + 32, 0, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x10\x9D\x6C\xB3\x37\x9C\x9E\x2B\xC9\x1C\xF9\x79\x7A\x46\xEA\xFA\x78\x5C\xA1\x54\x83\xBD\xC2\x67\x31\xFA\x66\xAC\x5D\x4C\xE7\xAB", + 32, 15, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x76\x83\x9A\x8F\xBC\x20\x81\xD6\x09\x5C\x97\x46\xD3\xD6\xA4\xC4\xC1\x17\x8E\x3B\x14\xFC\xFD\x8F\x72\x20\xEF\xC6\x0B\xD3\xFF\x42", + 32, 16, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEA\x0C\x05\xE6\x8F\xD6\xA6\xA1\xD9\xFC\xDA\x3C\xCB\x49\x02\xA5\xF9\x5D\x80\x9E\x89\xF6\xA2\x15\x74\x48\x84\x87\x77\x47\x6D\xBB", + 32, 17, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x98\x79\xD8\x91\x48\xB3\x12\x10\xE8\x49\x73\x38\x1B\xFA\x6C\xCA\x85\x59\xF9\xF9\xFE\xD3\xF2\x98\x9E\x9D\x5C\xE8\x1E\x59\xB3\x46", + 32, 31, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xC7\x41\x7E\x23\xDD\x7D\xB0\x84\xCA\x64\x26\x5A\xE0\x98\xD7\xF2\x29\xE4\x4C\x88\xC9\xF9\x15\x00\x19\x73\xC7\xCF\x95\xF5\x30\x68", + 32, 32, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\x0F\xDA\x45\x55\xAC\x8F\xB0\x17\x1D\xF2\x41\x54\xFB\x41\x26\x16\x0C\x00\x84\x49\x3D\x54\xAE\x9F\x13\xD4\xE5\x11\x2B\x42\xB5\xF5", + 32, 33, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xF1\x1B\x54\x05\xCE\x3A\xEB\xA1\x1B\x49\x99\x43\xBF\x2C\x73\x10\x0E\x35\x6B\xEA\x40\xAC\xE5\xBC\xD8\xD5\xB0\xAE\xB2\x8E\xFB\x05", + 32, 63, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xEA\xAF\xA4\xBE\xD6\x9D\x98\x73\x5E\xDF\xFC\x35\xFD\xB8\x26\x18\xAC\x15\x9E\x2B\xB2\xF9\x36\xEC\x51\x58\x1E\xD8\x53\xB7\x11\x10", + 32, 64, 32 + }, + { + "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61", + "\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A\x7A", + "\xC3\x0A\xE0\xAB\xFA\x38\x3C\x3F\xBC\x44\xD3\x2A\x4F\xC8\xFA\x86\xF2\x15\x9E\x83\x75\x65\xE4\x78\x63\xED\xEF\x31\x79\xEC\x00\x21", + 32, 65, 32 + } + }; + + { + byte digest[BLAKE2s::DIGESTSIZE]; + for (unsigned int i=0; i +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +bool CryptoSystemValidate(PK_Decryptor &priv, PK_Encryptor &pub, bool thorough) +{ + bool pass = true, fail; + + fail = !pub.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2) || !priv.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "cryptosystem key validation\n"; + + const byte message[] = "test message"; + const int messageLen = 12; + SecByteBlock ciphertext(priv.CiphertextLength(messageLen)); + SecByteBlock plaintext(priv.MaxPlaintextLength(ciphertext.size())); + + pub.Encrypt(GlobalRNG(), message, messageLen, ciphertext); + fail = priv.Decrypt(GlobalRNG(), ciphertext, priv.CiphertextLength(messageLen), plaintext) != DecodingResult(messageLen); + fail = fail || memcmp(message, plaintext, messageLen); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "encryption and decryption\n"; + + return pass; +} + +bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d) +{ + if (d.GetCryptoParameters().Validate(GlobalRNG(), 3)) + std::cout << "passed simple key agreement domain parameters validation" << std::endl; + else + { + std::cout << "FAILED simple key agreement domain parameters invalid" << std::endl; + return false; + } + + SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength()); + SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength()); + SecByteBlock val1(d.AgreedValueLength()), val2(d.AgreedValueLength()); + + d.GenerateKeyPair(GlobalRNG(), priv1, pub1); + d.GenerateKeyPair(GlobalRNG(), priv2, pub2); + + memset(val1.begin(), 0x10, val1.size()); + memset(val2.begin(), 0x11, val2.size()); + + if (!(d.Agree(val1, priv1, pub2) && d.Agree(val2, priv2, pub1))) + { + std::cout << "FAILED simple key agreement failed" << std::endl; + return false; + } + + if (memcmp(val1.begin(), val2.begin(), d.AgreedValueLength())) + { + std::cout << "FAILED simple agreed values not equal" << std::endl; + return false; + } + + std::cout << "passed simple key agreement" << std::endl; + return true; +} + +bool AuthenticatedKeyAgreementValidate(AuthenticatedKeyAgreementDomain &d) +{ + if (d.GetCryptoParameters().Validate(GlobalRNG(), 3)) + std::cout << "passed authenticated key agreement domain parameters validation" << std::endl; + else + { + std::cout << "FAILED authenticated key agreement domain parameters invalid" << std::endl; + return false; + } + + SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength()); + SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength()); + SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength()); + SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength()); + SecByteBlock val1(d.AgreedValueLength()), val2(d.AgreedValueLength()); + + d.GenerateStaticKeyPair(GlobalRNG(), spriv1, spub1); + d.GenerateStaticKeyPair(GlobalRNG(), spriv2, spub2); + d.GenerateEphemeralKeyPair(GlobalRNG(), epriv1, epub1); + d.GenerateEphemeralKeyPair(GlobalRNG(), epriv2, epub2); + + memset(val1.begin(), 0x10, val1.size()); + memset(val2.begin(), 0x11, val2.size()); + + if (d.Agree(val1, spriv1, epriv1, spub2, epub2) && d.Agree(val2, spriv2, epriv2, spub1, epub1)) + { + std::cout << "passed authenticated key agreement protocol execution" << std::endl; + } + else + { + std::cout << "FAILED authenticated key agreement protocol execution" << std::endl; + return false; + } + + if (memcmp(val1.begin(), val2.begin(), d.AgreedValueLength())) + { + std::cout << "FAILED authenticated agreed values not equal" << std::endl; + return false; + } + + std::cout << "passed authenticated key agreement" << std::endl; + return true; +} + +bool AuthenticatedKeyAgreementWithRolesValidate(AuthenticatedKeyAgreementDomain &initiator, AuthenticatedKeyAgreementDomain &recipient) +{ + if (initiator.GetCryptoParameters().Validate(GlobalRNG(), 3)) + std::cout << "passed authenticated key agreement domain parameters validation (initiator)" << std::endl; + else + { + std::cout << "FAILED authenticated key agreement domain parameters invalid (initiator)" << std::endl; + return false; + } + + if (recipient.GetCryptoParameters().Validate(GlobalRNG(), 3)) + std::cout << "passed authenticated key agreement domain parameters validation (recipient)" << std::endl; + else + { + std::cout << "FAILED authenticated key agreement domain parameters invalid (recipient)" << std::endl; + return false; + } + + if (initiator.StaticPrivateKeyLength() != recipient.StaticPrivateKeyLength() || + initiator.EphemeralPrivateKeyLength() != recipient.EphemeralPrivateKeyLength() || + initiator.StaticPublicKeyLength() != recipient.StaticPublicKeyLength() || + initiator.EphemeralPublicKeyLength() != recipient.EphemeralPublicKeyLength() || + initiator.AgreedValueLength() != recipient.AgreedValueLength()) + { + std::cout << "FAILED authenticated key agreement domain parameter consistency" << std::endl; + return false; + } + else + { + std::cout << "passed authenticated key agreement domain parameter consistency" << std::endl; + } + + SecByteBlock spriv1(initiator.StaticPrivateKeyLength()), spriv2(recipient.StaticPrivateKeyLength()); + SecByteBlock epriv1(initiator.EphemeralPrivateKeyLength()), epriv2(recipient.EphemeralPrivateKeyLength()); + SecByteBlock spub1(initiator.StaticPublicKeyLength()), spub2(recipient.StaticPublicKeyLength()); + SecByteBlock epub1(initiator.EphemeralPublicKeyLength()), epub2(recipient.EphemeralPublicKeyLength()); + SecByteBlock val1(initiator.AgreedValueLength()), val2(recipient.AgreedValueLength()); + + initiator.GenerateStaticKeyPair(GlobalRNG(), spriv1, spub1); + recipient.GenerateStaticKeyPair(GlobalRNG(), spriv2, spub2); + initiator.GenerateEphemeralKeyPair(GlobalRNG(), epriv1, epub1); + recipient.GenerateEphemeralKeyPair(GlobalRNG(), epriv2, epub2); + + memset(val1.begin(), 0x10, val1.size()); + memset(val2.begin(), 0x11, val2.size()); + + if (initiator.Agree(val1, spriv1, epriv1, spub2, epub2) && recipient.Agree(val2, spriv2, epriv2, spub1, epub1)) + { + std::cout << "passed authenticated key agreement protocol execution" << std::endl; + } + else + { + std::cout << "FAILED authenticated key agreement protocol execution" << std::endl; + return false; + } + + if (memcmp(val1.begin(), val2.begin(), initiator.AgreedValueLength())) + { + std::cout << "FAILED authenticated agreed values not equal" << std::endl; + return false; + } + + std::cout << "passed authenticated key agreement shared secret" << std::endl; + return true; +} + +bool SignatureValidate(PK_Signer &priv, PK_Verifier &pub, bool thorough) +{ + bool pass = true, fail; + + fail = !pub.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2) || !priv.GetMaterial().Validate(GlobalRNG(), thorough ? 3 : 2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature key validation\n"; + + const byte message[] = "test message"; + const int messageLen = 12; + + SecByteBlock signature(priv.MaxSignatureLength()); + size_t signatureLength = priv.SignMessage(GlobalRNG(), message, messageLen, signature); + fail = !pub.VerifyMessage(message, messageLen, signature, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature and verification\n"; + + ++signature[0]; + fail = pub.VerifyMessage(message, messageLen, signature, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "checking invalid signature" << std::endl; + + if (priv.MaxRecoverableLength() > 0) + { + signatureLength = priv.SignMessageWithRecovery(GlobalRNG(), message, messageLen, NULLPTR, 0, signature); + SecByteBlock recovered(priv.MaxRecoverableLengthFromSignatureLength(signatureLength)); + DecodingResult result = pub.RecoverMessage(recovered, NULLPTR, 0, signature, signatureLength); + fail = !(result.isValidCoding && result.messageLength == messageLen && memcmp(recovered, message, messageLen) == 0); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature and verification with recovery" << std::endl; + + ++signature[0]; + result = pub.RecoverMessage(recovered, NULLPTR, 0, signature, signatureLength); + fail = result.isValidCoding; + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "recovery with invalid signature" << std::endl; + } + + return pass; +} + +bool ValidateBBS() +{ + std::cout << "\nBlumBlumShub validation suite running...\n\n"; + + Integer p("212004934506826557583707108431463840565872545889679278744389317666981496005411448865750399674653351"); + Integer q("100677295735404212434355574418077394581488455772477016953458064183204108039226017738610663984508231"); + Integer seed("63239752671357255800299643604761065219897634268887145610573595874544114193025997412441121667211431"); + BlumBlumShub bbs(p, q, seed); + bool pass = true, fail; + int j; + + const byte output1[] = { + 0x49,0xEA,0x2C,0xFD,0xB0,0x10,0x64,0xA0,0xBB,0xB9, + 0x2A,0xF1,0x01,0xDA,0xC1,0x8A,0x94,0xF7,0xB7,0xCE}; + const byte output2[] = { + 0x74,0x45,0x48,0xAE,0xAC,0xB7,0x0E,0xDF,0xAF,0xD7, + 0xD5,0x0E,0x8E,0x29,0x83,0x75,0x6B,0x27,0x46,0xA1}; + + byte buf[20]; + std::ostringstream oss; + + bbs.GenerateBlock(buf, 20); + fail = memcmp(output1, buf, 20) != 0; + pass = pass && !fail; + + oss << (fail ? "FAILED " : "passed "); + for (j=0;j<20;j++) + oss << std::setw(2) << std::setfill('0') << std::hex << (int)buf[j]; + oss << std::endl; + + bbs.Seek(10); + bbs.GenerateBlock(buf, 10); + fail = memcmp(output1+10, buf, 10) != 0; + pass = pass && !fail; + + oss << (fail ? "FAILED " : "passed "); + for (j=0;j<10;j++) + oss << std::setw(2) << std::setfill('0') << std::hex << (int)buf[j]; + oss << std::endl; + + bbs.Seek(1234567); + bbs.GenerateBlock(buf, 20); + fail = memcmp(output2, buf, 20) != 0; + pass = pass && !fail; + + oss << (fail ? "FAILED " : "passed "); + for (j=0;j<20;j++) + oss << std::setw(2) << std::setfill('0') << std::hex << (int)buf[j]; + oss << std::endl; + + std::cout << oss.str(); + return pass; +} + +bool ValidateECP() +{ + // Remove word recommend. Some ECP curves may not be recommended depending + // on whom you ask. ECP is more descriptive item in this case. + std::cout << "\nTesting SEC 2, NIST and Brainpool ECP curves...\n\n"; + bool pass = true; OID oid; + + while (!(oid = DL_GroupParameters_EC::GetNextRecommendedParametersOID(oid)).GetValues().empty()) + { + DL_GroupParameters_EC params(oid); + pass = params.Validate(GlobalRNG(), 2); + + // Test addition of identity element + DL_GroupParameters_EC::Element e1; + e1 = params.GetCurve().Add(e1, e1); + pass = params.IsIdentity(e1) && pass; + + // Test doubling of identity element + DL_GroupParameters_EC::Element e2; + e2 = params.GetCurve().Double(e2); + pass = params.IsIdentity(e2) && pass; + + // Test multiplication of identity element + DL_GroupParameters_EC::Element e3; + Integer two = Integer::Two(); + e3 = params.GetCurve().Multiply(two, e3); + pass = params.IsIdentity(e3) && pass; + + std::cout << (pass ? "passed" : "FAILED") << " " << std::dec << params.GetCurve().GetField().MaxElementBitLength() << " bits\n"; + } + + std::cout << "\nECP validation suite running...\n\n"; + return ValidateECP_Agreement() && ValidateECP_Encrypt() && ValidateECP_NULLDigest_Encrypt() && ValidateECP_Sign() && pass; +} + +bool ValidateEC2N() +{ + // Remove word recommend. Binary curves may not be recommended depending + // on whom you ask. EC2N is more descriptive item in this case. + std::cout << "\nTesting SEC 2 EC2N curves...\n\n"; + bool pass = true; OID oid; + +#if 1 // TODO: turn this back on when I make EC2N faster for pentanomial basis + while (!(oid = DL_GroupParameters_EC::GetNextRecommendedParametersOID(oid)).GetValues().empty()) + { + DL_GroupParameters_EC params(oid); + pass = params.Validate(GlobalRNG(), 2); + + // Test addition of identity element + DL_GroupParameters_EC::Element e1; + e1 = params.GetCurve().Add(e1, e1); + pass = params.IsIdentity(e1) && pass; + + // Test doubling of identity element + DL_GroupParameters_EC::Element e2; + e2 = params.GetCurve().Double(e2); + pass = params.IsIdentity(e2) && pass; + + // Test multiplication of identity element + DL_GroupParameters_EC::Element e3; + Integer two = Integer::Two(); + e3 = params.GetCurve().Multiply(two, e3); + pass = params.IsIdentity(e3) && pass; + + std::cout << (pass ? "passed" : "FAILED") << " " << params.GetCurve().GetField().MaxElementBitLength() << " bits\n"; + } +#endif + + std::cout << "\nEC2N validation suite running...\n\n"; + return ValidateEC2N_Agreement() && ValidateEC2N_Encrypt() && ValidateEC2N_Sign() && pass; +} + +bool ValidateRSA() +{ + std::cout << "\nRSA validation suite running...\n\n"; + return ValidateRSA_Encrypt() && ValidateRSA_Sign(); +} + +bool ValidateLUC() +{ + std::cout << "\nLUC validation suite running...\n\n"; + return ValidateLUC_Encrypt() && ValidateLUC_Sign(); +} + +bool ValidateLUC_DL() +{ + // Prologue printed in each function + return ValidateLUC_DL_Encrypt() && ValidateLUC_DL_Sign(); +} + +bool ValidateRabin() +{ + std::cout << "\nRabin validation suite running...\n\n"; + return ValidateRabin_Encrypt() && ValidateRabin_Sign(); +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat7.cpp b/extension/third_party/cryptopp/validat7.cpp new file mode 100644 index 00000000..3567b3c8 --- /dev/null +++ b/extension/third_party/cryptopp/validat7.cpp @@ -0,0 +1,562 @@ +// validat7.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "asn.h" +#include "oids.h" + +#include "sha.h" +#include "sha3.h" + +#include "dh.h" +#include "luc.h" +#include "mqv.h" +#include "xtr.h" +#include "hmqv.h" +#include "pubkey.h" +#include "xtrcrypt.h" +#include "eccrypto.h" + +// Curve25519 +#include "xed25519.h" +#include "donna.h" +#include "naclite.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +bool ValidateDH() +{ + std::cout << "\nDH validation suite running...\n\n"; + + FileSource f(DataDir("TestData/dh1024.dat").c_str(), true, new HexDecoder); + DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateX25519() +{ + std::cout << "\nx25519 validation suite running...\n\n"; + + FileSource f(DataDir("TestData/x25519.dat").c_str(), true, new HexDecoder); + x25519 dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateMQV() +{ + std::cout << "\nMQV validation suite running...\n\n"; + + FileSource f(DataDir("TestData/mqv1024.dat").c_str(), true, new HexDecoder); + MQV mqv(f); + return AuthenticatedKeyAgreementValidate(mqv); +} + +bool ValidateHMQV() +{ + std::cout << "\nHMQV validation suite running...\n\n"; + bool success = true, fail; + + FileSource f256(DataDir("TestData/hmqv256.dat").c_str(), true, new HexDecoder); + FileSource f384(DataDir("TestData/hmqv384.dat").c_str(), true, new HexDecoder); + FileSource f512(DataDir("TestData/hmqv512.dat").c_str(), true, new HexDecoder); + + ///////////////////////// + + std::cout << "HMQV with NIST P-256 and SHA-256:" << std::endl; + + ECHMQV256 hmqvB256(false); + hmqvB256.AccessGroupParameters().BERDecode(f256); + const OID oid = ASN1::secp256r1(); + ECHMQV< ECP >::Domain hmqvA256(oid, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(hmqvA256, hmqvB256); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + ///////////////////////// + + std::cout << "HMQV with NIST P-384 and SHA-384:" << std::endl; + + ECHMQV384 hmqvB384(false); + hmqvB384.AccessGroupParameters().BERDecode(f384); + const OID oid384 = ASN1::secp384r1(); + ECHMQV384 hmqvA384(oid384, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(hmqvA384, hmqvB384); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + ///////////////////////// + + std::cout << "HMQV with NIST P-521 and SHA-512:" << std::endl; + + ECHMQV512 hmqvB521(false); + hmqvB521.AccessGroupParameters().BERDecode(f512); + const OID oid521 = ASN1::secp521r1(); + ECHMQV512 hmqvA521(oid521, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(hmqvA521, hmqvB521); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + return success; +} + +bool ValidateFHMQV() +{ + std::cout << "\nFHMQV validation suite running...\n\n"; + bool success = true, fail; + + FileSource f256(DataDir("TestData/fhmqv256.dat").c_str(), true, new HexDecoder); + FileSource f384(DataDir("TestData/fhmqv384.dat").c_str(), true, new HexDecoder); + FileSource f512(DataDir("TestData/fhmqv512.dat").c_str(), true, new HexDecoder); + + ///////////////////////// + + std::cout << "FHMQV with NIST P-256 and SHA-256:" << std::endl; + + ECFHMQV256 fhmqvB256(false); + fhmqvB256.AccessGroupParameters().BERDecode(f256); + const OID oid = ASN1::secp256r1(); + ECFHMQV< ECP >::Domain fhmqvA256(oid, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(fhmqvA256, fhmqvB256); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + ///////////////////////// + + std::cout << "FHMQV with NIST P-384 and SHA-384:" << std::endl; + + ECHMQV384 fhmqvB384(false); + fhmqvB384.AccessGroupParameters().BERDecode(f384); + const OID oid384 = ASN1::secp384r1(); + ECHMQV384 fhmqvA384(oid384, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(fhmqvA384, fhmqvB384); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + ///////////////////////// + + std::cout << "FHMQV with NIST P-521 and SHA-512:" << std::endl; + + ECHMQV512 fhmqvB521(false); + fhmqvB521.AccessGroupParameters().BERDecode(f512); + const OID oid521 = ASN1::secp521r1(); + ECHMQV512 fhmqvA521(oid521, true /*client*/); + + fail = !AuthenticatedKeyAgreementWithRolesValidate(fhmqvA521, fhmqvB521); + success = !fail && success; + if (fail == false) + std::cout << "passed authenticated key agreement" << std::endl; + else + std::cout << "FAILED authenticated key agreement" << std::endl; + + return success; +} + +bool ValidateLUC_DH() +{ + std::cout << "\nLUC-DH validation suite running...\n\n"; + + FileSource f(DataDir("TestData/lucd512.dat").c_str(), true, new HexDecoder); + LUC_DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateXTR_DH() +{ + std::cout << "\nXTR-DH validation suite running...\n\n"; + + FileSource f(DataDir("TestData/xtrdh171.dat").c_str(), true, new HexDecoder); + XTR_DH dh(f); + return SimpleKeyAgreementValidate(dh); +} + +bool ValidateECP_Agreement() +{ + ECDH::Domain ecdhc(ASN1::secp192r1()); + ECMQV::Domain ecmqvc(ASN1::secp192r1()); + bool pass = SimpleKeyAgreementValidate(ecdhc); + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + std::cout << "Turning on point compression..." << std::endl; + ecdhc.AccessGroupParameters().SetPointCompression(true); + ecmqvc.AccessGroupParameters().SetPointCompression(true); + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + return pass; +} + +bool ValidateEC2N_Agreement() +{ + ECDH::Domain ecdhc(ASN1::sect193r1()); + ECMQV::Domain ecmqvc(ASN1::sect193r1()); + bool pass = SimpleKeyAgreementValidate(ecdhc); + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + std::cout << "Turning on point compression..." << std::endl; + ecdhc.AccessGroupParameters().SetPointCompression(true); + ecmqvc.AccessGroupParameters().SetPointCompression(true); + pass = SimpleKeyAgreementValidate(ecdhc) && pass; + pass = AuthenticatedKeyAgreementValidate(ecmqvc) && pass; + + return pass; +} + +// TestX25519 is slighty more comprehensive than ValidateX25519 +// because it cross-validates against Bernstein's NaCL library. +// TestX25519 called in Debug builds. +bool TestX25519() +{ + std::cout << "\nTesting curve25519 Key Agreements...\n\n"; + const unsigned int AGREE_COUNT = 64; + bool pass = true; + + try { + + FileSource f1(DataDir("TestData/x25519.dat").c_str(), true, new HexDecoder); + FileSource f2(DataDir("TestData/x25519v0.dat").c_str(), true, new HexDecoder); + FileSource f3(DataDir("TestData/x25519v1.dat").c_str(), true, new HexDecoder); + + x25519 x1(f1); + x25519 x2(f2); + x25519 x3(f3); + + FileSource f4(DataDir("TestData/x25519.dat").c_str(), true, new HexDecoder); + FileSource f5(DataDir("TestData/x25519v0.dat").c_str(), true, new HexDecoder); + FileSource f6(DataDir("TestData/x25519v1.dat").c_str(), true, new HexDecoder); + + x1.Load(f4); + x2.Load(f5); + x3.Load(f6); + } + catch (const BERDecodeErr&) { + pass = false; + } + + SecByteBlock priv1(32), priv2(32), pub1(32), pub2(32), share1(32), share2(32); + for (unsigned int i=0; i +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +inline byte* C2B(char* ptr) { + return reinterpret_cast(ptr); +} + +inline const byte* C2B(const char* ptr) { + return reinterpret_cast(ptr); +} + +bool ValidateRSA_Encrypt() +{ + // Must be large enough for RSA-3072 to test SHA3_256 + byte out[256], outPlain[128]; + bool pass = true, fail; + + { + FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); + RSAES_PKCS1v15_Decryptor rsaPriv(keys); + RSAES_PKCS1v15_Encryptor rsaPub(rsaPriv); + + pass = CryptoSystemValidate(rsaPriv, rsaPub) && pass; + } + { + RSAES >::Decryptor rsaPriv(GlobalRNG(), 512); + RSAES >::Encryptor rsaPub(rsaPriv); + + pass = CryptoSystemValidate(rsaPriv, rsaPub) && pass; + } + { + byte *plain = (byte *) + "\x54\x85\x9b\x34\x2c\x49\xea\x2a"; + static const byte encrypted[] = + "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a" + "\x8b\x40\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4" + "\x17\x53\x03\x29\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52" + "\x62\x51"; + static const byte oaepSeed[] = + "\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2" + "\xf0\x6c\xb5\x8f"; + ByteQueue bq; + bq.Put(oaepSeed, 20); + FixedRNG rng(bq); + + FileSource privFile(DataDir("TestData/rsa400pv.dat").c_str(), true, new HexDecoder); + FileSource pubFile(DataDir("TestData/rsa400pb.dat").c_str(), true, new HexDecoder); + RSAES_OAEP_SHA_Decryptor rsaPriv; + rsaPriv.AccessKey().BERDecodePrivateKey(privFile, false, 0); + RSAES_OAEP_SHA_Encryptor rsaPub(pubFile); + + memset(out, 0, 50); + memset(outPlain, 0, 8); + rsaPub.Encrypt(rng, plain, 8, out); + DecodingResult result = rsaPriv.FixedLengthDecrypt(GlobalRNG(), encrypted, outPlain); + fail = !result.isValidCoding || (result.messageLength!=8) || memcmp(out, encrypted, 50) || memcmp(plain, outPlain, 8); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "PKCS 2.0 encryption and decryption\n"; + } + + return pass; +} + +bool ValidateLUC_Encrypt() +{ + FileSource f(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); + LUCES_OAEP_SHA_Decryptor priv(GlobalRNG(), 512); + LUCES_OAEP_SHA_Encryptor pub(priv); + return CryptoSystemValidate(priv, pub); +} + +bool ValidateLUC_DL_Encrypt() +{ + std::cout << "\nLUC-IES validation suite running...\n\n"; + + FileSource fc(DataDir("TestData/lucc512.dat").c_str(), true, new HexDecoder); + LUC_IES<>::Decryptor privC(fc); + LUC_IES<>::Encryptor pubC(privC); + return CryptoSystemValidate(privC, pubC); +} + +bool ValidateRabin_Encrypt() +{ + FileSource f(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + RabinES >::Decryptor priv(f); + RabinES >::Encryptor pub(priv); + return CryptoSystemValidate(priv, pub); +} + +bool ValidateECP_Encrypt() +{ + ECIES::Decryptor cpriv(GlobalRNG(), ASN1::secp192r1()); + ECIES::Encryptor cpub(cpriv); + ByteQueue bq; + cpriv.GetKey().DEREncode(bq); + cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + cpub.GetKey().DEREncode(bq); + + cpub.AccessKey().Precompute(); + cpriv.AccessKey().Precompute(); + bool pass = CryptoSystemValidate(cpriv, cpub); + + std::cout << "Turning on point compression..." << std::endl; + cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true); + cpub.AccessKey().AccessGroupParameters().SetPointCompression(true); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + + return pass; +} + +// https://github.com/weidai11/cryptopp/issues/856 +// Not to be confused with NullHash in trunhash.h. +class NULL_Hash : public CryptoPP::IteratedHashWithStaticTransform + +{ +public: + static void InitState(HashWordType *state) { + CRYPTOPP_UNUSED(state); + } + static void Transform(CryptoPP::word32 *digest, const CryptoPP::word32 *data) { + CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(data); + } + static const char *StaticAlgorithmName() { + return "NULL_Hash"; + } +}; + +// https://github.com/weidai11/cryptopp/issues/856 +template +struct ECIES_NULLDigest + : public DL_ES< + DL_Keys_EC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + ECIES > +{ + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES-NULLDigest";} +}; + +bool ValidateECP_NULLDigest_Encrypt() +{ + ECIES_NULLDigest::Decryptor cpriv(GlobalRNG(), ASN1::secp256k1()); + ECIES_NULLDigest::Encryptor cpub(cpriv); + ByteQueue bq; + cpriv.GetKey().DEREncode(bq); + cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + cpub.GetKey().DEREncode(bq); + + cpub.AccessKey().Precompute(); + cpriv.AccessKey().Precompute(); + bool pass = CryptoSystemValidate(cpriv, cpub); + + std::cout << "Turning on point compression..." << std::endl; + cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true); + cpub.AccessKey().AccessGroupParameters().SetPointCompression(true); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + + return pass; +} + +// Ensure interop with Crypto++ 5.6.4 and earlier +bool ValidateECP_Legacy_Encrypt() +{ + std::cout << "\nLegacy ECIES ECP validation suite running...\n\n"; + bool pass = true; + { + FileSource fc(DataDir("TestData/ecies_p160.dat").c_str(), true, new HexDecoder); + ECIES::Decryptor privC(fc); + ECIES::Encryptor pubC(privC); + + pass = CryptoSystemValidate(privC, pubC) && pass; + + // Test data generated by Crypto++ 5.6.2. + // Also see https://github.com/weidai11/cryptopp/pull/857. + const std::string plain = "Yoda said, Do or do not. There is no try."; + const std::string cipher = + "\x04\xF6\xC1\xB1\xFA\xAC\x8A\xD5\xD3\x96\xE7\x13\xAE\xBD\x0C\xCE" + "\x15\xCF\x44\x54\x08\x63\xCC\xBF\x89\x4D\xD0\xB8\x38\xA1\x3A\xB2" + "\x90\x75\x86\x82\x7F\x9D\x95\x26\xA5\x74\x13\x3A\x74\x63\x11\x71" + "\x70\x4C\x01\xA4\x08\x04\x95\x69\x6A\x91\xF0\xC0\xA4\xBD\x1E\xAA" + "\x59\x57\xB8\xA9\xD2\xF7\x7C\x98\xE3\xC5\xE3\xF4\x4F\xA7\x6E\x73" + "\x83\xF3\x1E\x05\x73\xA4\xEE\x63\x55\xFD\x6D\x31\xBB\x9E\x36\x4C" + "\x79\xD0\x76\xC0\x0D\xE9"; + + std::string recover; + recover.resize(privC.MaxPlaintextLength(cipher.size())); + + DecodingResult result = privC.Decrypt(GlobalRNG(), C2B(&cipher[0]), cipher.size(), C2B(&recover[0])); + if (result.isValidCoding) + recover.resize(result.messageLength); + else + recover.resize(0); + + pass = (plain == recover) && pass; + std::cout << (pass ? "passed " : "FAILED "); + std::cout << "decryption known answer\n"; + } + return pass; +} + +// Ensure interop with Crypto++ 5.6.4 and earlier +bool ValidateEC2N_Legacy_Encrypt() +{ + std::cout << "\nLegacy ECIES EC2N validation suite running...\n\n"; + bool pass = true; + { + FileSource fc(DataDir("TestData/ecies_t163.dat").c_str(), true, new HexDecoder); + ECIES::Decryptor privC(fc); + ECIES::Encryptor pubC(privC); + + pass = CryptoSystemValidate(privC, pubC) && pass; + + // Test data generated by Crypto++ 5.6.2. + // Also see https://github.com/weidai11/cryptopp/pull/857. + const std::string plain = "Yoda said, Do or do not. There is no try."; + const std::string cipher = + "\x04\x01\x3F\x64\x94\x6A\xBE\x2B\x7E\x48\x67\x63\xA2\xD4\x01\xEF" + "\x2B\x13\x1C\x9A\x1B\x7C\x07\x4B\x89\x78\x6C\x65\x51\x1C\x1A\x4E" + "\x20\x7F\xB5\xBF\x12\x3B\x6E\x0A\x87\xFD\xB7\x94\xEF\x4B\xED\x40" + "\xD4\x7A\xCF\xB6\xFC\x9B\x6D\xB0\xB8\x43\x99\x7E\x37\xC1\xF0\xC0" + "\x95\xD4\x80\xE1\x8B\x84\xAE\x64\x9F\xA5\xBA\x32\x95\x8A\xD1\xBE" + "\x7F\xDE\x7E\xA9\xE6\x59\xBF\x89\xA6\xE9\x9F\x5B\x64\xB4\xDD\x0E" + "\x76\xB6\x82\xF6\xA9\xAD\xB5\xC4"; + + std::string recover; + recover.resize(privC.MaxPlaintextLength(cipher.size())); + + DecodingResult result = privC.Decrypt(GlobalRNG(), C2B(&cipher[0]), cipher.size(), C2B(&recover[0])); + if (result.isValidCoding) + recover.resize(result.messageLength); + else + recover.resize(0); + + pass = (plain == recover) && pass; + std::cout << (pass ? "passed " : "FAILED "); + std::cout << "decryption known answer\n"; + } + return pass; +} + +bool ValidateEC2N_Encrypt() +{ + // DEREncode() changed to Save() at Issue 569. + ECIES::Decryptor cpriv(GlobalRNG(), ASN1::sect193r1()); + ECIES::Encryptor cpub(cpriv); + ByteQueue bq; + cpriv.AccessMaterial().Save(bq); + cpub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + cpub.AccessMaterial().Save(bq); + bool pass = CryptoSystemValidate(cpriv, cpub); + + std::cout << "Turning on point compression..." << std::endl; + cpriv.AccessKey().AccessGroupParameters().SetPointCompression(true); + cpub.AccessKey().AccessGroupParameters().SetPointCompression(true); + pass = CryptoSystemValidate(cpriv, cpub) && pass; + + return pass; +} + +bool ValidateElGamal() +{ + std::cout << "\nElGamal validation suite running...\n\n"; + bool pass = true; + { + // Data from https://github.com/weidai11/cryptopp/issues/876. + const std::string encodedPublicKey = + "MHYwTwYGKw4HAgEBMEUCIQDebUvQDd9UPMmD27BJ ovZSIgWfexL0SWkfJQPMLsJvMwIgDy/kEthwO6Q+" + "L8XHnzumnEKs+txH8QkQD+M/8u82ql0DIwACIAY6 rfW+BTcRZ9QAJovgoB8DgNLJ8ocqOeF4nEBB0DHH"; + StringSource decodedPublicKey(encodedPublicKey, true, new Base64Decoder); + + ElGamal::PublicKey publicKey; + publicKey.Load(decodedPublicKey); + pass = publicKey.Validate(GlobalRNG(), 3) && pass; + } + { + // Data from https://github.com/weidai11/cryptopp/issues/876. + const std::string encodedPrivateKey = + "MHkCAQAwTwYGKw4HAgEBMEUCIQDebUvQDd9UPMmD 27BJovZSIgWfexL0SWkfJQPMLsJvMwIgDy/kEthw" + "O6Q+L8XHnzumnEKs+txH8QkQD+M/8u82ql0EIwIh AJb0S4TZLvApTVjXZyocPJ5tUgWgRqScXm5vNqu2" + "YqdM"; + StringSource decodedPrivateKey(encodedPrivateKey, true, new Base64Decoder); + + ElGamal::PrivateKey privateKey; + privateKey.Load(decodedPrivateKey); + pass = privateKey.Validate(GlobalRNG(), 3) && pass; + } + { + FileSource fc(DataDir("TestData/elgc1024.dat").c_str(), true, new HexDecoder); + ElGamalDecryptor privC(fc); + ElGamalEncryptor pubC(privC); + privC.AccessKey().Precompute(); + ByteQueue queue; + privC.AccessKey().SavePrecomputation(queue); + privC.AccessKey().LoadPrecomputation(queue); + + pass = CryptoSystemValidate(privC, pubC) && pass; + } + return pass; +} + +bool ValidateDLIES() +{ + std::cout << "\nDLIES validation suite running...\n\n"; + bool pass = true; + { + FileSource fc(DataDir("TestData/dlie1024.dat").c_str(), true, new HexDecoder); + DLIES<>::Decryptor privC(fc); + DLIES<>::Encryptor pubC(privC); + pass = CryptoSystemValidate(privC, pubC) && pass; + } + { + std::cout << "Generating new encryption key..." << std::endl; + DLIES<>::GroupParameters gp; + gp.GenerateRandomWithKeySize(GlobalRNG(), 128); + DLIES<>::Decryptor decryptor; + decryptor.AccessKey().GenerateRandom(GlobalRNG(), gp); + DLIES<>::Encryptor encryptor(decryptor); + + pass = CryptoSystemValidate(decryptor, encryptor) && pass; + } + return pass; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validat9.cpp b/extension/third_party/cryptopp/validat9.cpp new file mode 100644 index 00000000..735afe51 --- /dev/null +++ b/extension/third_party/cryptopp/validat9.cpp @@ -0,0 +1,704 @@ +// validat9.cpp - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017. +// Source files split in July 2018 to expedite compiles. + +#include "pch.h" + +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 + +#include "cryptlib.h" +#include "cpu.h" +#include "validate.h" + +#include "asn.h" +#include "oids.h" + +#include "md2.h" +#include "md4.h" +#include "md5.h" + +#include "sha.h" +#include "sha3.h" +#include "pssr.h" +#include "ripemd.h" +#include "whrlpool.h" + +#include "rw.h" +#include "dsa.h" +#include "luc.h" +#include "rsa.h" +#include "esign.h" +#include "rabin.h" +#include "pubkey.h" +#include "eccrypto.h" + +// Curve25519 +#include "xed25519.h" +#include "donna.h" +#include "naclite.h" + +#include +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (_MSC_FULL_VER >= 140050727) +# pragma strict_gs_check (on) +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4505 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +bool ValidateRSA_Sign() +{ + // Must be large enough for RSA-3072 to test SHA3_256 + byte out[256]; + bool pass = true, fail; + + { + const char plain[] = "Everyone gets Friday off."; + const byte signature[] = + "\x05\xfa\x6a\x81\x2f\xc7\xdf\x8b\xf4\xf2\x54\x25\x09\xe0\x3e\x84" + "\x6e\x11\xb9\xc6\x20\xbe\x20\x09\xef\xb4\x40\xef\xbc\xc6\x69\x21" + "\x69\x94\xac\x04\xf3\x41\xb5\x7d\x05\x20\x2d\x42\x8f\xb2\xa2\x7b" + "\x5c\x77\xdf\xd9\xb1\x5b\xfc\x3d\x55\x93\x53\x50\x34\x10\xc1\xe1"; + + FileSource keys(DataDir("TestData/rsa512a.dat").c_str(), true, new HexDecoder); + Weak::RSASSA_PKCS1v15_MD2_Signer rsaPriv(keys); + Weak::RSASSA_PKCS1v15_MD2_Verifier rsaPub(rsaPriv); + + size_t signatureLength = rsaPriv.SignMessage(GlobalRNG(), (byte *)plain, strlen(plain), out); + CRYPTOPP_ASSERT(signatureLength <= sizeof(out)); + fail = memcmp(signature, out, signatureLength) != 0; + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature check against test vector\n"; + + fail = !rsaPub.VerifyMessage((byte *)plain, strlen(plain), out, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "verification check against test vector\n"; + + out[10]++; + fail = rsaPub.VerifyMessage((byte *)plain, strlen(plain), out, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "invalid signature verification\n"; + } + ///// + { + const char plain[] = "Everyone gets Friday off."; + const byte signature[] = + "\x2e\x87\xda\x1f\xe4\xda\x1d\x7a\xb7\xf2\x42\x36\xe9\xc0\x4e\xab\x3f\x03\x71\xe1" + "\x2b\xc5\x3c\xbf\x21\x21\xa8\xd6\x28\xb0\x08\xfd\x9c\xf6\x94\xbd\x37\x32\xda\xfc" + "\x42\x1c\x8e\xdb\x8a\x81\x90\x46\x45\xb4\xde\x9e\xce\x90\xfe\xa1\xfd\xbc\x5a\xce" + "\xca\x59\x89\x93\xc0\x0f\x2f\xf1\x13\xb0\xf5\x3d\xa3\x9a\x85\xb7\x40\xd9\x34\x88" + "\x29\xb2\x4a\x0f\x9b\xbe\x22\x3a\x5b\x54\x51\xb7\xf0\x10\x72\x50\xc4\x2a\xe9\xe4" + "\xc3\x82\xeb\x32\x33\x14\xb6\xf2\x7b\x30\x7a\xbf\xc2\xf3\x0f\x4d\x72\xa0\x8d\xa1" + "\xc6\xce\xd0\xa3\x3c\xf7\x23\x4b\xb7\x2c\x5e\xca\x83\x01\xc7\x5c\xd5\xd0\xd1\x94" + "\x43\xf0\xad\xa2\xe6\x72\x2b\x13\x39\xb2\x4b\x25\x91\x3a\x4f\x53\x05\x00\x8c\xc7" + "\xcf\x4f\x11\x64\xe6\xf4\x1a\x4d\x90\x7e\xf1\xfe\xed\xec\x8d\xbb\x00\x31\x2e\x03" + "\xbe\x87\x84\x60\xfb\x5e\xef\x9d\x18\x2c\x28\x3d\xaa\x67\x80\xa3\x62\x07\x06\x5e" + "\xce\xee\x3b\xd0\x78\xb5\x98\x38\x1e\xe8\x62\x19\x9c\xc3\xd4\xf7\xc2\xc5\x00\xf0" + "\xeb\x89\x65\x53\x35\xe7\x13\x7e\xbb\x26\xb0\x76\x9c\xf2\x80\xaa\xe1\xb1\x0a\xa6" + "\x47\xfc\x5f\xe0\x7f\x82\xd7\x83\x41\xc3\x50\xa1\xe0\x0e\x1a\xe4"; + + FileSource keys(DataDir("TestData/rsa2048a.dat").c_str(), true, new HexDecoder); + RSASS::Signer rsaPriv(keys); + RSASS::Verifier rsaPub(rsaPriv); + + size_t signatureLength = rsaPriv.SignMessage(GlobalRNG(), (byte *)plain, strlen(plain), out); + CRYPTOPP_ASSERT(signatureLength <= sizeof(out)); + fail = memcmp(signature, out, signatureLength) != 0; + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature check against test vector\n"; + + fail = !rsaPub.VerifyMessage((byte *)plain, strlen(plain), out, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "verification check against test vector\n"; + + out[10]++; + fail = rsaPub.VerifyMessage((byte *)plain, strlen(plain), out, signatureLength); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "invalid signature verification\n"; + } + + return pass; +} + +bool ValidateNR() +{ + std::cout << "\nNR validation suite running...\n\n"; + bool pass = true; + { + FileSource f(DataDir("TestData/nr2048.dat").c_str(), true, new HexDecoder); + NR::Signer privS(f); + privS.AccessKey().Precompute(); + NR::Verifier pubS(privS); + + pass = SignatureValidate(privS, pubS) && pass; + } + { + std::cout << "Generating new signature key..." << std::endl; + NR::Signer privS(GlobalRNG(), 256); + NR::Verifier pubS(privS); + + pass = SignatureValidate(privS, pubS) && pass; + } + return pass; +} + +bool ValidateDSA(bool thorough) +{ + std::cout << "\nDSA validation suite running...\n\n"; + + bool pass = true; + FileSource fs1(DataDir("TestData/dsa1024.dat").c_str(), true, new HexDecoder); + DSA::Signer priv(fs1); + DSA::Verifier pub(priv); + FileSource fs2(DataDir("TestData/dsa1024b.dat").c_str(), true, new HexDecoder); + DSA::Verifier pub1(fs2); + CRYPTOPP_ASSERT(pub.GetKey() == pub1.GetKey()); + pass = SignatureValidate(priv, pub, thorough) && pass; + + return pass; +} + +bool ValidateLUC_Sign() +{ + FileSource f(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); + LUCSSA_PKCS1v15_SHA_Signer priv(f); + LUCSSA_PKCS1v15_SHA_Verifier pub(priv); + return SignatureValidate(priv, pub); +} + +bool ValidateLUC_DL_Sign() +{ + std::cout << "\nLUC-HMP validation suite running...\n\n"; + + FileSource f(DataDir("TestData/lucs512.dat").c_str(), true, new HexDecoder); + LUC_HMP::Signer privS(f); + LUC_HMP::Verifier pubS(privS); + return SignatureValidate(privS, pubS); +} + +bool ValidateRabin_Sign() +{ + FileSource f(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + RabinSS::Signer priv(f); + RabinSS::Verifier pub(priv); + return SignatureValidate(priv, pub); +} + +bool ValidateRW() +{ + std::cout << "\nRW validation suite running...\n\n"; + + FileSource f(DataDir("TestData/rw1024.dat").c_str(), true, new HexDecoder); + RWSS::Signer priv(f); + RWSS::Verifier pub(priv); + + return SignatureValidate(priv, pub); +} + +bool ValidateECP_Sign() +{ + ECDSA::Signer spriv(GlobalRNG(), ASN1::secp192r1()); + ECDSA::Verifier spub(spriv); + ByteQueue bq; + spriv.GetKey().DEREncode(bq); + spub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + spub.GetKey().DEREncode(bq); + spriv.AccessKey().BERDecode(bq); + spub.AccessKey().BERDecode(bq); + + spriv.AccessKey().Precompute(); + ByteQueue queue; + spriv.AccessKey().SavePrecomputation(queue); + spriv.AccessKey().LoadPrecomputation(queue); + + return SignatureValidate(spriv, spub); +} + +bool ValidateEC2N_Sign() +{ + // DEREncode() changed to Save() at Issue 569. + ECDSA::Signer spriv(GlobalRNG(), ASN1::sect193r1()); + ECDSA::Verifier spub(spriv); + ByteQueue bq; + spriv.AccessMaterial().Save(bq); + spub.AccessKey().AccessGroupParameters().SetEncodeAsOID(true); + spub.AccessMaterial().Save(bq); + spriv.AccessMaterial().Load(bq); + spub.AccessMaterial().Load(bq); + + spriv.AccessKey().Precompute(); + ByteQueue queue; + spriv.AccessKey().SavePrecomputation(queue); + spriv.AccessKey().LoadPrecomputation(queue); + + return SignatureValidate(spriv, spub); +} + +bool ValidateECDSA() +{ + std::cout << "\nECDSA validation suite running...\n\n"; + + // from Sample Test Vectors for P1363 + GF2NT gf2n(191, 9, 0); + byte a[]="\x28\x66\x53\x7B\x67\x67\x52\x63\x6A\x68\xF5\x65\x54\xE1\x26\x40\x27\x6B\x64\x9E\xF7\x52\x62\x67"; + byte b[]="\x2E\x45\xEF\x57\x1F\x00\x78\x6F\x67\xB0\x08\x1B\x94\x95\xA3\xD9\x54\x62\xF5\xDE\x0A\xA1\x85\xEC"; + EC2N ec(gf2n, PolynomialMod2(a,24), PolynomialMod2(b,24)); + + EC2N::Point P; + bool result = ec.DecodePoint(P, (byte *)"\x04\x36\xB3\xDA\xF8\xA2\x32\x06\xF9\xC4\xF2\x99\xD7\xB2\x1A\x9C\x36\x91\x37\xF2\xC8\x4A\xE1\xAA\x0D" + "\x76\x5B\xE7\x34\x33\xB3\xF9\x5E\x33\x29\x32\xE7\x0E\xA2\x45\xCA\x24\x18\xEA\x0E\xF9\x80\x18\xFB", ec.EncodedPointSize()); + CRYPTOPP_ASSERT(result); CRYPTOPP_UNUSED(result); + + Integer n("40000000000000000000000004a20e90c39067c893bbb9a5H"); + Integer d("340562e1dda332f9d2aec168249b5696ee39d0ed4d03760fH"); + EC2N::Point Q(ec.Multiply(d, P)); + ECDSA::Signer priv(ec, P, n, d); + ECDSA::Verifier pub(priv); + + Integer h("A9993E364706816ABA3E25717850C26C9CD0D89DH"); + Integer k("3eeace72b4919d991738d521879f787cb590aff8189d2b69H"); + const byte sig[]="\x03\x8e\x5a\x11\xfb\x55\xe4\xc6\x54\x71\xdc\xd4\x99\x84\x52\xb1\xe0\x2d\x8a\xf7\x09\x9b\xb9\x30" + "\x0c\x9a\x08\xc3\x44\x68\xc2\x44\xb4\xe5\xd6\xb2\x1b\x3c\x68\x36\x28\x07\x41\x60\x20\x32\x8b\x6e"; + Integer r(sig, 24); + Integer s(sig+24, 24); + + Integer rOut, sOut; + bool fail, pass=true; + + priv.RawSign(k, h, rOut, sOut); + fail = (rOut != r) || (sOut != s); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "signature check against test vector\n"; + + fail = !pub.VerifyMessage((byte *)"abc", 3, sig, sizeof(sig)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "verification check against test vector\n"; + + fail = pub.VerifyMessage((byte *)"xyz", 3, sig, sizeof(sig)); + pass = pass && !fail; + + pass = SignatureValidate(priv, pub) && pass; + + return pass; +} + +bool ValidateECDSA_RFC6979() +{ + std::cout << "\nRFC6979 deterministic ECDSA validation suite running...\n\n"; + + DL_Algorithm_ECDSA_RFC6979 sign; + + const Integer x("09A4D6792295A7F730FC3F2B49CBC0F62E862272Fh"); + const Integer e("AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BFh"); + const Integer q("4000000000000000000020108A2E0CC0D99F8A5EFh"); + const Integer k("23AF4074C90A02B3FE61D286D5C87F425E6BDD81Bh"); + const Integer &k_out = sign.GenerateRandom(x, q, e); + + bool pass = (k_out == k); + + std::cout << (pass ? "passed " : "FAILED "); + std::cout << "deterministic k generation against test vector\n"; + + return pass; +} + +// from http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf +bool ValidateECGDSA(bool thorough) +{ + std::cout << "\nECGDSA validation suite running...\n\n"; + + bool fail, pass=true; + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function RIPEMD-160 (p. 10) + if (thorough) + { + const OID oid = ASN1::brainpoolP192r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 80F2425E 89B4F585 F27F3536 ED834D68 E3E492DE 08FE84B9"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 577EF842 B32FDE45 79727FFF 02F7A280 74ADC4EF"); + Integer k("0x 22C17C2A 367DD85A B8A365ED 06F19C43 F9ED1834 9A9BC044"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 2D017BE7 F117FF99 4ED6FC63 CA5B4C7A 0430E9FA 095DAFC4"); + Integer sExp("0x C02B5CC5 C51D5411 060BF024 5049F824 839F671D 78A1BBF1"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function RIPEMD-160"; + const size_t len = strlen((char*)msg); + + byte signature[48]; + r.Encode(signature+0, 24); + s.Encode(signature+24, 24); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP192r1 using RIPEMD-160\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function RIPEMD-160 (p. 13) + if (thorough) + { + const OID oid = ASN1::brainpoolP256r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 47B3A278 62DEF037 49ACF0D6 00E69F9B 851D01ED AEFA531F 4D168E78 7307F4D8"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 00000000 00000000 577EF842 B32FDE45 79727FFF 02F7A280 74ADC4EF"); + Integer k("0x 908E3099 776261A4 558FF7A9 FA6DFFE0 CA6BB3F9 CB35C2E4 E1DC73FD 5E8C08A3"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 62CCD1D2 91E62F6A 4FFBD966 C66C85AA BA990BB6 AB0C087D BD54A456 CCC84E4C"); + Integer sExp("0x 9119719B 08EEA0D6 BC56E4D1 D37369BC F3768445 EF65CAE4 A37BF6D4 3BD01646"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function RIPEMD-160"; + const size_t len = strlen((char*)msg); + + byte signature[64]; + r.Encode(signature+0, 32); + s.Encode(signature+32, 32); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP256r1 using RIPEMD-160\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function RIPEMD-160 (p. 16) + if (thorough) + { + const OID oid = ASN1::brainpoolP320r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 48683594 5A3A284F FC52629A D48D8F37 F4B2E993 9C52BC72 362A9961 40192AEF 7D2AAFF0 C73A51C5"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 00000000 00000000 00000000 00000000 577EF842 B32FDE45 79727FFF 02F7A280 74ADC4EF"); + Integer k("0x C70BC00A 77AD7872 5D36CEEC 27D6F956 FB546EEF 6DC90E35 31452BD8 7ECE8A4A 7AD730AD C299D81B"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 3C925969 FAB22F7A E7B8CC5D 50CB0867 DFDB2CF4 FADA3D49 0DF75D72 F7563186 419494C9 8F9C82A6"); + Integer sExp("0x 06AB5250 B31A8E93 56194894 61733200 E4FD5C12 75C0AB37 E7E41149 5BAAE145 41DF6DE6 66B8CA56"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function RIPEMD-160"; + const size_t len = strlen((char*)msg); + + byte signature[80]; + r.Encode(signature+0, 40); + s.Encode(signature+40, 40); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP320r1 using RIPEMD-160\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function SHA-1 (p. 19) + { + const OID oid = ASN1::brainpoolP192r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 80F2425E 89B4F585 F27F3536 ED834D68 E3E492DE 08FE84B9"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 CF00CD42 CAA80DDF 8DDEBDFD 32F2DA15 11B53F29"); + Integer k("0x 22C17C2A 367DD85A B8A365ED 06F19C43 F9ED1834 9A9BC044"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 2D017BE7 F117FF99 4ED6FC63 CA5B4C7A 0430E9FA 095DAFC4"); + Integer sExp("0x 18FD604E 5F00F55B 3585C052 8C319A2B 05B8F2DD EE9CF1A6"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function SHA-1"; + const size_t len = strlen((char*)msg); + + byte signature[48]; + r.Encode(signature+0, 24); + s.Encode(signature+24, 24); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP192r1 using SHA-1\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function SHA-224 (p. 23) + { + const OID oid = ASN1::brainpoolP320r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 48683594 5A3A284F FC52629A D48D8F37 F4B2E993 9C52BC72 362A9961 40192AEF 7D2AAFF0 C73A51C5"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 00000000 00000000 92AE8A0E 8D08EADE E9426378 714FF3E0 1957587D 2876FA70 D40E3144"); + Integer k("0x C70BC00A 77AD7872 5D36CEEC 27D6F956 FB546EEF 6DC90E35 31452BD8 7ECE8A4A 7AD730AD C299D81B"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 3C925969 FAB22F7A E7B8CC5D 50CB0867 DFDB2CF4 FADA3D49 0DF75D72 F7563186 419494C9 8F9C82A6"); + Integer sExp("0x 6EA191CA 0D468AC3 E9568768 9338357C 7D0BACB3 F1D87E0D EC05F635 B7ADB842 75AA0086 60F812CF"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function SHA-224"; + const size_t len = strlen((char*)msg); + + byte signature[80]; + r.Encode(signature+0, 40); + s.Encode(signature+40, 40); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP320r1 using SHA-224\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function SHA-256 (p. 27) + { + const OID oid = ASN1::brainpoolP320r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 48683594 5A3A284F FC52629A D48D8F37 F4B2E993 9C52BC72 362A9961 40192AEF 7D2AAFF0 C73A51C5"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 00000000 37ED8AA9 4AE667DB BB753330 E050EB8E 12195807 ECDC4FB1 0E0662B4 22C219D7"); + Integer k("0x C70BC00A 77AD7872 5D36CEEC 27D6F956 FB546EEF 6DC90E35 31452BD8 7ECE8A4A 7AD730AD C299D81B"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 3C925969 FAB22F7A E7B8CC5D 50CB0867 DFDB2CF4 FADA3D49 0DF75D72 F7563186 419494C9 8F9C82A6"); + Integer sExp("0x 24370797 A9D11717 BBBB2B76 2E08ECD0 7DD7E033 F544E47C BF3C6D16 FD90B51D CC2E4DD8 E6ECD8CD"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function SHA-256"; + const size_t len = strlen((char*)msg); + + byte signature[80]; + r.Encode(signature+0, 40); + s.Encode(signature+40, 40); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP320r1 using SHA-256\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function SHA-384 (p. 34) + { + const OID oid = ASN1::brainpoolP512r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 92006A98 8AF96D91 57AADCF8 62716962 7CE2ECC4 C58ECE5C 1A0A8642 11AB764C 04236FA0 160857A7 8E71CCAE 4D79D52E 5A69A457 8AF50658 1F598FA9 B4F7DA68"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 00000000 00000000 00000000 00000000 68FEAB7D 8BF8A779 4466E447 5959946B 2136C084 A86090CA 8070C980 68B1250D 88213190 6B7E0CB8 475F9054 E9290C2E"); + Integer k("0x 6942B01D 5901BEC1 506BB874 9618E22E C0FCD7F3 5159D51E D53BA77A 78752128 A58232AD 8E0E021A FDE1477F F4C74FDF FE88AE2D 15D89B56 F6D73C03 77631D2B"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 0104918B 2B32B1A5 49BD43C3 0092953B 4164CA01 A1A97B5B 0756EA06 3AC16B41 B88A1BAB 4538CD7D 8466180B 3E3F5C86 46AC4A45 F564E9B6 8FEE72ED 00C7AC48"); + Integer sExp("0x 3D233E9F D9EB152E 889F4F7C F325B464 0894E5EA 44C51443 54305CD4 BF70D234 8257C2DB E06C5544 92CE9FDD 6861A565 77B53E5E E80E6062 31A4CF06 8FA1EC21"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function SHA-384"; + const size_t len = strlen((char*)msg); + + byte signature[128]; + r.Encode(signature+0, 64); + s.Encode(signature+64, 64); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP512r1 using SHA-384\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function SHA-512 (p. 38) + { + const OID oid = ASN1::brainpoolP512r1(); + DL_GroupParameters_EC params(oid); + Integer x("0x 92006A98 8AF96D91 57AADCF8 62716962 7CE2ECC4 C58ECE5C 1A0A8642 11AB764C 04236FA0 160857A7 8E71CCAE 4D79D52E 5A69A457 8AF50658 1F598FA9 B4F7DA68"); + ECGDSA::Signer signer(params, x); + ECGDSA::Verifier verifier(signer); + + Integer e("0x 1A95EF81 D213BD3B 8191E7FE 7F5BFD43 F51E3EE5 A4FD3D08 4A7C9BB5 411F4649 746AEBC6 623D4DEA 7E02DC5A 85E24AF2 96B5A555 AD470413 71E4BF64 380F3E34"); + Integer k("0x 6942B01D 5901BEC1 506BB874 9618E22E C0FCD7F3 5159D51E D53BA77A 78752128 A58232AD 8E0E021A FDE1477F F4C74FDF FE88AE2D 15D89B56 F6D73C03 77631D2B"); + + Integer r, s; + signer.RawSign(k, e, r, s); + + Integer rExp("0x 0104918B 2B32B1A5 49BD43C3 0092953B 4164CA01 A1A97B5B 0756EA06 3AC16B41 B88A1BAB 4538CD7D 8466180B 3E3F5C86 46AC4A45 F564E9B6 8FEE72ED 00C7AC48"); + Integer sExp("0x 17A011F8 DD7B5665 2B27AA6D 6E7BDF3C 7C23B5FA 32910FBA A107E627 0E1CA8A7 A263F661 8E6098A0 D6CD6BA1 C03544C5 425875EC B3418AF5 A3EE3F32 143E48D2"); + + fail = (r != rExp) || (s != sExp); + pass = pass && !fail; + + const byte msg[] = "Example of ECGDSA with the hash function SHA-512"; + const size_t len = strlen((char*)msg); + + byte signature[128]; + r.Encode(signature+0, 64); + s.Encode(signature+64, 64); + + fail = !verifier.VerifyMessage(msg, len, signature, sizeof(signature)); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP512r1 using SHA-512\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + return pass; +} + +bool ValidateESIGN() +{ + std::cout << "\nESIGN validation suite running...\n\n"; + + bool pass = true, fail; + + const char plain[] = "test"; + const byte signature[] = + "\xA3\xE3\x20\x65\xDE\xDA\xE7\xEC\x05\xC1\xBF\xCD\x25\x79\x7D\x99\xCD\xD5\x73\x9D\x9D\xF3\xA4\xAA\x9A\xA4\x5A\xC8\x23\x3D\x0D\x37" + "\xFE\xBC\x76\x3F\xF1\x84\xF6\x59\x14\x91\x4F\x0C\x34\x1B\xAE\x9A\x5C\x2E\x2E\x38\x08\x78\x77\xCB\xDC\x3C\x7E\xA0\x34\x44\x5B\x0F" + "\x67\xD9\x35\x2A\x79\x47\x1A\x52\x37\x71\xDB\x12\x67\xC1\xB6\xC6\x66\x73\xB3\x40\x2E\xD6\xF2\x1A\x84\x0A\xB6\x7B\x0F\xEB\x8B\x88" + "\xAB\x33\xDD\xE4\x83\x21\x90\x63\x2D\x51\x2A\xB1\x6F\xAB\xA7\x5C\xFD\x77\x99\xF2\xE1\xEF\x67\x1A\x74\x02\x37\x0E\xED\x0A\x06\xAD" + "\xF4\x15\x65\xB8\xE1\xD1\x45\xAE\x39\x19\xB4\xFF\x5D\xF1\x45\x7B\xE0\xFE\x72\xED\x11\x92\x8F\x61\x41\x4F\x02\x00\xF2\x76\x6F\x7C" + "\x79\xA2\xE5\x52\x20\x5D\x97\x5E\xFE\x39\xAE\x21\x10\xFB\x35\xF4\x80\x81\x41\x13\xDD\xE8\x5F\xCA\x1E\x4F\xF8\x9B\xB2\x68\xFB\x28"; + + FileSource keys(DataDir("TestData/esig1536.dat").c_str(), true, new HexDecoder); + ESIGN::Signer signer(keys); + ESIGN::Verifier verifier(signer); + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + + fail = !verifier.VerifyMessage((byte *)plain, strlen(plain), signature, verifier.SignatureLength()); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "verification check against test vector\n"; + + std::cout << "Generating signature key from seed..." << std::endl; + signer.AccessKey().GenerateRandom(GlobalRNG(), MakeParameters("Seed", ConstByteArrayParameter((const byte *)"test", 4))("KeySize", 3*512)); + verifier = signer; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + + return pass; +} + +bool ValidateEd25519() +{ + std::cout << "\ned25519 validation suite running...\n\n"; + bool pass = true, fail; + + const char plain[] = "test"; + const byte signature[] = + "\x91\x12\x44\x91\xA5\x99\xF8\x49\xBA\xB2\xC4\xF2\xBA\x0B\xAA\x99" + "\xC8\xC5\xF5\x19\xDC\x07\xD4\x4C\xF7\x31\xDE\x2F\x2B\x81\xB2\x81" + "\xF6\xA7\xDE\x33\x29\xCA\x45\xAC\x69\x2A\x80\xB7\xDB\x7F\x07\x37" + "\x77\xC4\xBF\xC5\x45\x79\x3A\xAC\xB5\x16\xAE\x4E\xD9\x16\x95\x0E"; + + FileSource keys(DataDir("TestData/ed25519.dat").c_str(), true, new HexDecoder); + ed25519::Signer signer(keys); + ed25519::Verifier verifier(signer); + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + + fail = !verifier.VerifyMessage((byte *)plain, strlen(plain), signature, verifier.SignatureLength()); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "verification check against test vector\n"; + + return pass; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/validate.h b/extension/third_party/cryptopp/validate.h new file mode 100644 index 00000000..f2ec5a67 --- /dev/null +++ b/extension/third_party/cryptopp/validate.h @@ -0,0 +1,393 @@ +// validate.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_VALIDATE_H +#define CRYPTOPP_VALIDATE_H + +#include "cryptlib.h" +#include "misc.h" +#include "files.h" +#include "argnames.h" +#include "algparam.h" +#include "hex.h" + +#include +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +// A hint to help locate TestData/ and TestVectors/ after install. Due to +// execve the path can be malicious. If the path is ficticous then we move +// onto the next potential path. Also note we only read from the path; we +// never write through it. Storage for the string is in test.cpp. +extern std::string g_argvPathHint; + +bool ValidateAll(bool thorough); +bool TestSettings(); +bool TestOS_RNG(); +// bool TestSecRandom(); +bool TestRandomPool(); +#if !defined(NO_OS_DEPENDENCE) +bool TestAutoSeededX917(); +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +bool TestRDRAND(); +bool TestRDSEED(); +bool TestPadlockRNG(); +#endif +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool TestDARN(); +#endif +bool ValidateBaseCode(); +bool ValidateEncoder(); +bool ValidateCRC32(); +bool ValidateCRC32C(); +bool ValidateAdler32(); +bool ValidateMD2(); +bool ValidateMD4(); +bool ValidateMD5(); +bool ValidateSHA(); +bool ValidateSHA2(); +bool ValidateSHA3(); +bool ValidateSHAKE(); // output <= r, where r is blocksize +bool ValidateSHAKE_XOF(); // output > r, needs hand crafted tests +bool ValidateKeccak(); +bool ValidateTiger(); +bool ValidateRIPEMD(); +bool ValidatePanama(); +bool ValidateWhirlpool(); + +bool ValidateSM3(); +bool ValidateBLAKE2s(); +bool ValidateBLAKE2b(); +bool ValidatePoly1305(); +bool ValidateSipHash(); + +bool ValidateHMAC(); +bool ValidateTTMAC(); + +bool ValidateCipherModes(); +bool ValidatePBKDF(); +bool ValidateHKDF(); +bool ValidateScrypt(); + +bool ValidateDES(); +bool ValidateIDEA(); +bool ValidateSAFER(); +bool ValidateRC2(); +bool ValidateARC4(); + +bool ValidateRC5(); +bool ValidateBlowfish(); +bool ValidateBlowfishCompat(); +bool ValidateThreeWay(); +bool ValidateGOST(); +bool ValidateSHARK(); +bool ValidateSEAL(); +bool ValidateCAST(); +bool ValidateSquare(); +bool ValidateSKIPJACK(); +bool ValidateRC6(); +bool ValidateMARS(); +bool ValidateRijndael(); +bool ValidateTwofish(); +bool ValidateSerpent(); +bool ValidateSHACAL2(); +bool ValidateARIA(); +bool ValidateSIMECK(); +bool ValidateCHAM(); +bool ValidateHIGHT(); +bool ValidateLEA(); +bool ValidateSIMON(); +bool ValidateSPECK(); +bool ValidateCamellia(); + +bool ValidateHC128(); +bool ValidateHC256(); +bool ValidateRabbit(); +bool ValidateSalsa(); +bool ValidateChaCha(); +bool ValidateChaChaTLS(); +bool ValidateSosemanuk(); + +bool ValidateVMAC(); +bool ValidateCCM(); +bool ValidateGCM(); +bool ValidateXTS(); +bool ValidateCMAC(); + +bool ValidateBBS(); +bool ValidateDH(); +bool ValidateMQV(); +bool ValidateHMQV(); +bool ValidateFHMQV(); +bool ValidateRSA(); +bool ValidateElGamal(); +bool ValidateDLIES(); +bool ValidateNR(); +bool ValidateDSA(bool thorough); +bool ValidateLUC(); +bool ValidateLUC_DL(); +bool ValidateLUC_DH(); +bool ValidateXTR_DH(); +bool ValidateRabin(); +bool ValidateRW(); +bool ValidateECP(); +bool ValidateEC2N(); +bool ValidateECDSA(); +bool ValidateECDSA_RFC6979(); +bool ValidateECGDSA(bool thorough); +bool ValidateESIGN(); + +bool ValidateHashDRBG(); +bool ValidateHmacDRBG(); + +bool TestX25519(); +bool TestEd25519(); +bool ValidateX25519(); +bool ValidateEd25519(); +bool ValidateNaCl(); + +// If CRYPTOPP_DEBUG or CRYPTOPP_COVERAGE is in effect, then perform additional tests +#if (defined(CRYPTOPP_DEBUG) || defined(CRYPTOPP_COVERAGE)) && !defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_EXTENDED_VALIDATION 1 +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +// http://github.com/weidai11/cryptopp/issues/92 +bool TestSecBlock(); +// http://github.com/weidai11/cryptopp/issues/64 +bool TestPolynomialMod2(); +// http://github.com/weidai11/cryptopp/issues/336 +bool TestIntegerBitops(); +// http://github.com/weidai11/cryptopp/issues/602 +bool TestIntegerOps(); +// http://github.com/weidai11/cryptopp/issues/360 +bool TestRounding(); +// http://github.com/weidai11/cryptopp/issues/242 +bool TestHuffmanCodes(); +// http://github.com/weidai11/cryptopp/issues/346 +bool TestASN1Parse(); +// https://github.com/weidai11/cryptopp/pull/334 +bool TestStringSink(); +// Additional tests due to no coverage +bool TestCompressors(); +bool TestEncryptors(); +bool TestMersenne(); +bool TestSharing(); +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +bool TestAltivecOps(); +# endif +#endif + +class FixedRNG : public RandomNumberGenerator +{ +public: + FixedRNG(BufferedTransformation &source) : m_source(source) {} + + void GenerateBlock(byte *output, size_t size) + { + m_source.Get(output, size); + } + +private: + BufferedTransformation &m_source; +}; + +// Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 +inline std::string TimeToString(const time_t& t) +{ +#if (CRYPTOPP_MSC_VERSION >= 1400) + tm localTime; + char timeBuf[64]; + errno_t err; + + err = ::localtime_s(&localTime, &t); + CRYPTOPP_ASSERT(err == 0); + err = ::asctime_s(timeBuf, sizeof(timeBuf), &localTime); + CRYPTOPP_ASSERT(err == 0); + + std::string str(err == 0 ? timeBuf : ""); +#elif defined(__MINGW32__) || defined(__MINGW64__) + char* timeString = ::asctime(::localtime(&t)); + std::string str(timeString ? timeString : ""); +#elif (_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || defined(_POSIX_SOURCE)) + tm localTime; + char timeBuf[64]; + char* timeString = ::asctime_r(::localtime_r(&t, &localTime), timeBuf); + std::string str(timeString ? timeString : ""); +#else + char* timeString = ::asctime(::localtime(&t)); + std::string str(timeString ? timeString : ""); +#endif + + // Cleanup whitespace + std::string::size_type pos = 0; + while (!str.empty() && std::isspace(str[str.length()-1])) + {str.erase(str.end()-1);} + while (!str.empty() && std::string::npos != (pos = str.find(" ", pos))) + {str.erase(pos, 1);} + + return str; +} + +// Coverity finding +template +inline T StringToValue(const std::string& str) +{ + std::istringstream iss(str); + + // Arbitrary, but we need to clear a Coverity finding TAINTED_SCALAR + if (iss.str().length() > 25) + throw InvalidArgument(str + "' is too long"); + + T value; + iss >> std::noskipws >> value; + + // Use fail(), not bad() + if (iss.fail()) + throw InvalidArgument(str + "' is not a value"); + + if (NON_NEGATIVE && value < 0) + throw InvalidArgument(str + "' is negative"); + + return value; +} + +// Coverity finding +template<> +inline int StringToValue(const std::string& str) +{ + Integer n(str.c_str()); + long l = n.ConvertToLong(); + + int r; + if (!SafeConvert(l, r)) + throw InvalidArgument(str + "' is not an integer value"); + + return r; +} + +inline std::string AddSeparator(std::string str) +{ + if (str.empty()) return ""; + const char last = str[str.length()-1]; + if (last != '/' && last != '\\') + return str + "/"; + return str; +} + +// Use CRYPTOPP_DATA_DIR last. The problem this sidesteps is, finding an +// old version of Crypto++ library in CRYPTOPP_DATA_DIR when the library +// has been staged in DESTDIR. Using CRYPTOPP_DATA_DIR first only works +// as expected when CRYPTOPP_DATA_DIR is empty before an install. We +// encountered this problem rather quickly during testing of Crypto++ 8.1 +// when Crypto++ 8.0 was installed locally. It took some time to realize +// where the old test data was coming from. +static std::string GetDataDir() +{ + std::ifstream file; + std::string name, filename = "TestData/usage.dat"; + +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + // Look in $ORIGIN/../share/. This is likely a Linux install directory. + name = AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/") + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/"); +#endif +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + // Look in current working directory + name = AddSeparator(g_argvPathHint) + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint); +#endif +#ifdef CRYPTOPP_DATA_DIR + // Honor CRYPTOPP_DATA_DIR. This is likely an install directory if it is not "./". + name = AddSeparator(CRYPTOPP_DATA_DIR) + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(CRYPTOPP_DATA_DIR); +#endif + return "./"; +} + +inline std::string DataDir(const std::string& filename) +{ + std::string name; + std::ifstream file; + +#if CRYPTOPP_CXX11_STATIC_INIT + static std::string path = AddSeparator(GetDataDir()); + name = path + filename; + file.open(name.c_str()); + if (file.is_open()) + return name; +#else + // Avoid static initialization problems + name = AddSeparator(GetDataDir()) + filename; + file.open(name.c_str()); + if (file.is_open()) + return name; +#endif + + // This will cause the expected exception in the caller + return filename; +} + +// Definition in test.cpp +RandomNumberGenerator& GlobalRNG(); + +// Definition in datatest.cpp +bool RunTestDataFile(const char *filename, const NameValuePairs &overrideParameters=g_nullNameValuePairs, bool thorough=true); + +// Definitions in validat6.cpp +bool CryptoSystemValidate(PK_Decryptor &priv, PK_Encryptor &pub, bool thorough = false); +bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d); +bool AuthenticatedKeyAgreementWithRolesValidate(AuthenticatedKeyAgreementDomain &initiator, AuthenticatedKeyAgreementDomain &recipient); +bool AuthenticatedKeyAgreementValidate(AuthenticatedKeyAgreementDomain &d); +bool SignatureValidate(PK_Signer &priv, PK_Verifier &pub, bool thorough = false); + +// Miscellaneous PK definitions in validat6.cpp +// Key Agreement definitions in validat7.cpp +// Encryption and Decryption definitions in validat8.cpp +// Sign and Verify definitions in validat9.cpp + +bool ValidateECP(); +bool ValidateEC2N(); + +bool ValidateRSA_Encrypt(); +bool ValidateRSA_Sign(); + +bool ValidateLUC_Encrypt(); +bool ValidateLUC_Sign(); + +bool ValidateLUC_DL_Encrypt(); +bool ValidateLUC_DL_Sign(); + +bool ValidateRabin_Encrypt(); +bool ValidateRabin_Sign(); + +bool ValidateECP(); +bool ValidateECP_Agreement(); +bool ValidateECP_Encrypt(); +bool ValidateECP_Sign(); + +bool ValidateECP_Legacy_Encrypt(); +bool ValidateEC2N_Legacy_Encrypt(); +bool ValidateECP_NULLDigest_Encrypt(); + +bool ValidateEC2N(); +bool ValidateEC2N_Agreement(); +bool ValidateEC2N_Encrypt(); +bool ValidateEC2N_Sign(); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/extension/third_party/cryptopp/vmac.cpp b/extension/third_party/cryptopp/vmac.cpp new file mode 100644 index 00000000..c625c6bb --- /dev/null +++ b/extension/third_party/cryptopp/vmac.cpp @@ -0,0 +1,894 @@ +// vmac.cpp - originally written and placed in the public domain by Wei Dai +// based on Ted Krovetz's public domain vmac.c and draft-krovetz-vmac-01.txt + +#include "pch.h" +#include "config.h" + +#include "vmac.h" +#include "cpu.h" +#include "argnames.h" +#include "secblock.h" + +#if defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 +#include +#endif + +#if defined(CRYPTOPP_DISABLE_VMAC_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4731) +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +#if defined(CRYPTOPP_WORD128_AVAILABLE) && !defined(CRYPTOPP_X64_ASM_AVAILABLE) +using CryptoPP::word128; +using CryptoPP::word64; +# define VMAC_BOOL_WORD128 1 +#else +using CryptoPP::word64; +# define VMAC_BOOL_WORD128 0 +#endif + +#ifdef __BORLANDC__ +#define const // Turbo C++ 2006 workaround +#endif +const word64 p64 = W64LIT(0xfffffffffffffeff); /* 2^64 - 257 prime */ +const word64 m62 = W64LIT(0x3fffffffffffffff); /* 62-bit mask */ +const word64 m63 = W64LIT(0x7fffffffffffffff); /* 63-bit mask */ +const word64 m64 = W64LIT(0xffffffffffffffff); /* 64-bit mask */ +const word64 mpoly = W64LIT(0x1fffffff1fffffff); /* Poly key mask */ +#ifdef __BORLANDC__ +#undef const +#endif + +#if VMAC_BOOL_WORD128 +// workaround GCC Bug 31690: ICE with const __uint128_t and C++ front-end +# if defined(__powerpc__) && defined (CRYPTOPP_GCC_VERSION) && (CRYPTOPP_GCC_VERSION < 50300) +# define m126 ((word128(m62)<<64)|m64) +# else +const word128 m126 = (word128(m62)<<64)|m64; /* 126-bit mask */ +# endif +#endif + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void VMAC_Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms) +{ + int digestLength = params.GetIntValueWithDefault(Name::DigestSize(), DefaultDigestSize()); + if (digestLength != 8 && digestLength != 16) + throw InvalidArgument("VMAC: DigestSize must be 8 or 16"); + m_is128 = digestLength == 16; + + m_L1KeyLength = params.GetIntValueWithDefault(Name::L1KeyLength(), 128); + if (m_L1KeyLength <= 0 || m_L1KeyLength % 128 != 0) + throw InvalidArgument("VMAC: L1KeyLength must be a positive multiple of 128"); + + AllocateBlocks(); + + BlockCipher &cipher = AccessCipher(); + cipher.SetKey(userKey, keylength, params); + const unsigned int blockSize = cipher.BlockSize(); + const unsigned int blockSizeInWords = blockSize / sizeof(word64); + SecBlock > out(blockSizeInWords); + AlignedSecByteBlock in; + in.CleanNew(blockSize); + size_t i; + + /* Fill nh key */ + in[0] = 0x80; + cipher.AdvancedProcessBlocks(in, NULLPTR, (byte *)m_nhKey(), m_nhKeySize()*sizeof(word64), cipher.BT_InBlockIsCounter); + ConditionalByteReverse(BIG_ENDIAN_ORDER, m_nhKey(), m_nhKey(), m_nhKeySize()*sizeof(word64)); + + /* Fill poly key */ + in[0] = 0xC0; + in[15] = 0; + for (i = 0; i <= (size_t)m_is128; i++) + { + cipher.ProcessBlock(in, out.BytePtr()); + m_polyState()[i*4+2] = GetWord(true, BIG_ENDIAN_ORDER, out.BytePtr()) & mpoly; + m_polyState()[i*4+3] = GetWord(true, BIG_ENDIAN_ORDER, out.BytePtr()+8) & mpoly; + in[15]++; + } + + /* Fill ip key */ + in[0] = 0xE0; + in[15] = 0; + word64 *l3Key = m_l3Key(); + CRYPTOPP_ASSERT(IsAlignedOn(l3Key,GetAlignmentOf())); + + for (i = 0; i <= (size_t)m_is128; i++) + do + { + cipher.ProcessBlock(in, out.BytePtr()); + l3Key[i*2+0] = GetWord(true, BIG_ENDIAN_ORDER, out.BytePtr()); + l3Key[i*2+1] = GetWord(true, BIG_ENDIAN_ORDER, out.BytePtr()+8); + in[15]++; + } while ((l3Key[i*2+0] >= p64) || (l3Key[i*2+1] >= p64)); + + m_padCached = false; + size_t nonceLength; + const byte *nonce = GetIVAndThrowIfInvalid(params, nonceLength); + Resynchronize(nonce, (int)nonceLength); +} + +void VMAC_Base::GetNextIV(RandomNumberGenerator &rng, byte *IV) +{ + SimpleKeyingInterface::GetNextIV(rng, IV); + IV[0] &= 0x7f; +} + +void VMAC_Base::Resynchronize(const byte *nonce, int len) +{ + size_t length = ThrowIfInvalidIVLength(len); + size_t s = IVSize(); + byte *storedNonce = m_nonce(); + + if (m_is128) + { + memset(storedNonce, 0, s-length); + memcpy(storedNonce+s-length, nonce, length); + AccessCipher().ProcessBlock(storedNonce, m_pad()); + } + else + { + if (m_padCached && (storedNonce[s-1] | 1) == (nonce[length-1] | 1)) + { + m_padCached = VerifyBufsEqual(storedNonce+s-length, nonce, length-1); + for (size_t i=0; m_padCached && i>64); rl = word64(p);} + #define AccumulateNH(a, b, c) a += word128(b)*(c) + #define Multiply128(r, i1, i2) r = word128(word64(i1)) * word64(i2) +#else + #if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64)) + #define MUL32(a, b) __emulu(word32(a), word32(b)) + #else + #define MUL32(a, b) ((word64)((word32)(a)) * (word32)(b)) + #endif + #if defined(CRYPTOPP_X64_ASM_AVAILABLE) + #define DeclareNH(a) word64 a##0=0, a##1=0 + #define MUL64(rh,rl,i1,i2) asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "g"(i2) : "cc"); + #define AccumulateNH(a, b, c) asm ("mulq %3; addq %%rax, %0; adcq %%rdx, %1" : "+r"(a##0), "+r"(a##1) : "a"(b), "g"(c) : "%rdx", "cc"); + #define ADD128(rh,rl,ih,il) asm ("addq %3, %1; adcq %2, %0" : "+r"(rh),"+r"(rl) : "r"(ih),"r"(il) : "cc"); + #elif defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 + #define DeclareNH(a) word64 a##0=0, a##1=0 + #define MUL64(rh,rl,i1,i2) (rl) = _umul128(i1,i2,&(rh)); + #define AccumulateNH(a, b, c) {\ + word64 ph, pl;\ + pl = _umul128(b,c,&ph);\ + a##0 += pl;\ + a##1 += ph + (a##0 < pl);} + #else + #define VMAC_BOOL_32BIT 1 + #define DeclareNH(a) word64 a##0=0, a##1=0, a##2=0 + #define MUL64(rh,rl,i1,i2) \ + { word64 _i1 = (i1), _i2 = (i2); \ + word64 m1= MUL32(_i1,_i2>>32); \ + word64 m2= MUL32(_i1>>32,_i2); \ + rh = MUL32(_i1>>32,_i2>>32); \ + rl = MUL32(_i1,_i2); \ + ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \ + ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \ + } + #define AccumulateNH(a, b, c) {\ + word64 p = MUL32(b, c);\ + a##1 += word32((p)>>32);\ + a##0 += word32(p);\ + p = MUL32((b)>>32, c);\ + a##2 += word32((p)>>32);\ + a##1 += word32(p);\ + p = MUL32((b)>>32, (c)>>32);\ + a##2 += p;\ + p = MUL32(b, (c)>>32);\ + a##1 += word32(p);\ + a##2 += word32(p>>32);} + #endif +#endif +#ifndef VMAC_BOOL_32BIT + #define VMAC_BOOL_32BIT 0 +#endif +#ifndef ADD128 + #define ADD128(rh,rl,ih,il) \ + { word64 _il = (il); \ + (rl) += (_il); \ + (rh) += (ih) + ((rl) < (_il)); \ + } +#endif + +template +void VMAC_Base::VHASH_Update_Template(const word64 *data, size_t blocksRemainingInWord64) +{ + CRYPTOPP_ASSERT(IsAlignedOn(m_polyState(),GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(m_nhKey(),GetAlignmentOf())); + + #define INNER_LOOP_ITERATION(j) {\ + word64 d0 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+0]);\ + word64 d1 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+1]);\ + AccumulateNH(nhA, d0+nhK[i+2*j+0], d1+nhK[i+2*j+1]);\ + if (T_128BitTag)\ + AccumulateNH(nhB, d0+nhK[i+2*j+2], d1+nhK[i+2*j+3]);\ + } + + size_t L1KeyLengthInWord64 = m_L1KeyLength / 8; + size_t innerLoopEnd = L1KeyLengthInWord64; + const word64 *nhK = m_nhKey(); + word64 *polyS = (word64*)(void*)m_polyState(); + bool isFirstBlock = true; + size_t i; + + #if !VMAC_BOOL_32BIT + #if VMAC_BOOL_WORD128 + word128 a1=0, a2=0; + #else + word64 ah1=0, al1=0, ah2=0, al2=0; + #endif + word64 kh1, kl1, kh2, kl2; + kh1=(polyS+0*4+2)[0]; kl1=(polyS+0*4+2)[1]; + if (T_128BitTag) + { + kh2=(polyS+1*4+2)[0]; kl2=(polyS+1*4+2)[1]; + } + #endif + + do + { + DeclareNH(nhA); + DeclareNH(nhB); + + i = 0; + if (blocksRemainingInWord64 < L1KeyLengthInWord64) + { + if (blocksRemainingInWord64 % 8) + { + innerLoopEnd = blocksRemainingInWord64 % 8; + for (; i> 32); + nh1[0] = word32(nhA1); + nh2[0] = (nhA2 + (nhA1 >> 32)) & m62; + + if (T_128BitTag) + { + nh0[1] = word32(nhB0); + nhB1 += (nhB0 >> 32); + nh1[1] = word32(nhB1); + nh2[1] = (nhB2 + (nhB1 >> 32)) & m62; + } + + #define a0 (((word32 *)(polyS+i*4))[2+NativeByteOrder::ToEnum()]) + #define a1 (*(((word32 *)(polyS+i*4))+3-NativeByteOrder::ToEnum())) // workaround for GCC 3.2 + #define a2 (((word32 *)(polyS+i*4))[0+NativeByteOrder::ToEnum()]) + #define a3 (*(((word32 *)(polyS+i*4))+1-NativeByteOrder::ToEnum())) + #define aHi ((polyS+i*4)[0]) + #define k0 (((word32 *)(polyS+i*4+2))[2+NativeByteOrder::ToEnum()]) + #define k1 (*(((word32 *)(polyS+i*4+2))+3-NativeByteOrder::ToEnum())) + #define k2 (((word32 *)(polyS+i*4+2))[0+NativeByteOrder::ToEnum()]) + #define k3 (*(((word32 *)(polyS+i*4+2))+1-NativeByteOrder::ToEnum())) + #define kHi ((polyS+i*4+2)[0]) + + if (isFirstBlock) + { + isFirstBlock = false; + if (m_isFirstBlock) + { + m_isFirstBlock = false; + for (i=0; i<=(size_t)T_128BitTag; i++) + { + word64 t = (word64)nh0[i] + k0; + a0 = (word32)t; + t = (t >> 32) + nh1[i] + k1; + a1 = (word32)t; + aHi = (t >> 32) + nh2[i] + kHi; + } + continue; + } + } + for (i=0; i<=(size_t)T_128BitTag; i++) + { + word64 p, t; + word32 t2; + + p = MUL32(a3, 2*k3); + p += nh2[i]; + p += MUL32(a0, k2); + p += MUL32(a1, k1); + p += MUL32(a2, k0); + t2 = (word32)p; + p >>= 32; + p += MUL32(a0, k3); + p += MUL32(a1, k2); + p += MUL32(a2, k1); + p += MUL32(a3, k0); + t = (word64(word32(p) & 0x7fffffff) << 32) | t2; + p >>= 31; + p += nh0[i]; + p += MUL32(a0, k0); + p += MUL32(a1, 2*k3); + p += MUL32(a2, 2*k2); + p += MUL32(a3, 2*k1); + t2 = (word32)p; + p >>= 32; + p += nh1[i]; + p += MUL32(a0, k1); + p += MUL32(a1, k0); + p += MUL32(a2, 2*k3); + p += MUL32(a3, 2*k2); + a0 = t2; + a1 = (word32)p; + aHi = (p >> 32) + t; + } + + #undef a0 + #undef a1 + #undef a2 + #undef a3 + #undef aHi + #undef k0 + #undef k1 + #undef k2 + #undef k3 + #undef kHi + #else // #if VMAC_BOOL_32BIT + if (isFirstBlock) + { + isFirstBlock = false; + if (m_isFirstBlock) + { + m_isFirstBlock = false; + #if VMAC_BOOL_WORD128 + #define first_poly_step(a, kh, kl, m) a = (m & m126) + ((word128(kh) << 64) | kl) + + first_poly_step(a1, kh1, kl1, nhA); + if (T_128BitTag) + first_poly_step(a2, kh2, kl2, nhB); + #else + #define first_poly_step(ah, al, kh, kl, mh, ml) {\ + mh &= m62;\ + ADD128(mh, ml, kh, kl); \ + ah = mh; al = ml;} + + first_poly_step(ah1, al1, kh1, kl1, nhA1, nhA0); + if (T_128BitTag) + first_poly_step(ah2, al2, kh2, kl2, nhB1, nhB0); + #endif + continue; + } + else + { + #if VMAC_BOOL_WORD128 + a1 = (word128((polyS+0*4)[0]) << 64) | (polyS+0*4)[1]; + #else + ah1=(polyS+0*4)[0]; al1=(polyS+0*4)[1]; + #endif + if (T_128BitTag) + { + #if VMAC_BOOL_WORD128 + a2 = (word128((polyS+1*4)[0]) << 64) | (polyS+1*4)[1]; + #else + ah2=(polyS+1*4)[0]; al2=(polyS+1*4)[1]; + #endif + } + } + } + + #if VMAC_BOOL_WORD128 + #define poly_step(a, kh, kl, m) \ + { word128 t1, t2, t3, t4;\ + Multiply128(t2, a>>64, kl);\ + Multiply128(t3, a, kh);\ + Multiply128(t1, a, kl);\ + Multiply128(t4, a>>64, 2*kh);\ + t2 += t3;\ + t4 += t1;\ + t2 += t4>>64;\ + a = (word128(word64(t2)&m63) << 64) | word64(t4);\ + t2 *= 2;\ + a += m & m126;\ + a += t2>>64;} + + poly_step(a1, kh1, kl1, nhA); + if (T_128BitTag) + poly_step(a2, kh2, kl2, nhB); + #else + #define poly_step(ah, al, kh, kl, mh, ml) \ + { word64 t1h, t1l, t2h, t2l, t3h, t3l, z=0; \ + /* compute ab*cd, put bd into result registers */ \ + MUL64(t2h,t2l,ah,kl); \ + MUL64(t3h,t3l,al,kh); \ + MUL64(t1h,t1l,ah,2*kh); \ + MUL64(ah,al,al,kl); \ + /* add together ad + bc */ \ + ADD128(t2h,t2l,t3h,t3l); \ + /* add 2 * ac to result */ \ + ADD128(ah,al,t1h,t1l); \ + /* now (ah,al), (t2l,2*t2h) need summing */ \ + /* first add the high registers, carrying into t2h */ \ + ADD128(t2h,ah,z,t2l); \ + /* double t2h and add top bit of ah */ \ + t2h += t2h + (ah >> 63); \ + ah &= m63; \ + /* now add the low registers */ \ + mh &= m62; \ + ADD128(ah,al,mh,ml); \ + ADD128(ah,al,z,t2h); \ + } + + poly_step(ah1, al1, kh1, kl1, nhA1, nhA0); + if (T_128BitTag) + poly_step(ah2, al2, kh2, kl2, nhB1, nhB0); + #endif + #endif // #if VMAC_BOOL_32BIT + } while (blocksRemainingInWord64); + + #if VMAC_BOOL_WORD128 + (polyS+0*4)[0]=word64(a1>>64); (polyS+0*4)[1]=word64(a1); + if (T_128BitTag) + { + (polyS+1*4)[0]=word64(a2>>64); (polyS+1*4)[1]=word64(a2); + } + #elif !VMAC_BOOL_32BIT + (polyS+0*4)[0]=ah1; (polyS+0*4)[1]=al1; + if (T_128BitTag) + { + (polyS+1*4)[0]=ah2; (polyS+1*4)[1]=al2; + } + #endif +} + +inline void VMAC_Base::VHASH_Update(const word64 *data, size_t blocksRemainingInWord64) +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 + if (HasSSE2()) + { + VHASH_Update_SSE2(data, blocksRemainingInWord64, 0); + if (m_is128) + VHASH_Update_SSE2(data, blocksRemainingInWord64, 1); + m_isFirstBlock = false; + } + else +#endif + { + if (m_is128) + VHASH_Update_Template(data, blocksRemainingInWord64); + else + VHASH_Update_Template(data, blocksRemainingInWord64); + } +} + +size_t VMAC_Base::HashMultipleBlocks(const word64 *data, size_t length) +{ + size_t remaining = ModPowerOf2(length, m_L1KeyLength); + VHASH_Update(data, (length-remaining)/8); + return remaining; +} + +word64 L3Hash(const word64 *input, const word64 *l3Key, size_t len) +{ + word64 rh, rl, t, z=0; + word64 p1 = input[0], p2 = input[1]; + word64 k1 = l3Key[0], k2 = l3Key[1]; + + /* fully reduce (p1,p2)+(len,0) mod p127 */ + t = p1 >> 63; + p1 &= m63; + ADD128(p1, p2, len, t); + /* At this point, (p1,p2) is at most 2^127+(len<<64) */ + t = (p1 > m63) + ((p1 == m63) & (p2 == m64)); + ADD128(p1, p2, z, t); + p1 &= m63; + + /* compute (p1,p2)/(2^64-2^32) and (p1,p2)%(2^64-2^32) */ + t = p1 + (p2 >> 32); + t += (t >> 32); + t += (word32)t > 0xfffffffeU; + p1 += (t >> 32); + p2 += (p1 << 32); + + /* compute (p1+k1)%p64 and (p2+k2)%p64 */ + p1 += k1; + p1 += (0 - (p1 < k1)) & 257; + p2 += k2; + p2 += (0 - (p2 < k2)) & 257; + + /* compute (p1+k1)*(p2+k2)%p64 */ + MUL64(rh, rl, p1, p2); + t = rh >> 56; + ADD128(t, rl, z, rh); + rh <<= 8; + ADD128(t, rl, z, rh); + t += t << 8; + rl += t; + rl += (0 - (rl < t)) & 257; + rl += (0 - (rl > p64-1)) & 257; + return rl; +} + +void VMAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + CRYPTOPP_ASSERT(IsAlignedOn(DataBuf(),GetAlignmentOf())); + CRYPTOPP_ASSERT(IsAlignedOn(m_polyState(),GetAlignmentOf())); + size_t len = ModPowerOf2(GetBitCountLo()/8, m_L1KeyLength); + + if (len) + { + memset(m_data()+len, 0, (0-len)%16); + VHASH_Update(DataBuf(), ((len+15)/16)*2); + len *= 8; // convert to bits + } + else if (m_isFirstBlock) + { + // special case for empty string + m_polyState()[0] = m_polyState()[2]; + m_polyState()[1] = m_polyState()[3]; + if (m_is128) + { + m_polyState()[4] = m_polyState()[6]; + m_polyState()[5] = m_polyState()[7]; + } + } + + if (m_is128) + { + word64 t[2]; + t[0] = L3Hash(m_polyState(), m_l3Key(), len) + GetWord(true, BIG_ENDIAN_ORDER, m_pad()); + t[1] = L3Hash(m_polyState()+4, m_l3Key()+2, len) + GetWord(true, BIG_ENDIAN_ORDER, m_pad()+8); + if (size == 16) + { + PutWord(false, BIG_ENDIAN_ORDER, mac, t[0]); + PutWord(false, BIG_ENDIAN_ORDER, mac+8, t[1]); + } + else + { + t[0] = ConditionalByteReverse(BIG_ENDIAN_ORDER, t[0]); + t[1] = ConditionalByteReverse(BIG_ENDIAN_ORDER, t[1]); + memcpy(mac, t, size); + } + } + else + { + word64 t = L3Hash(m_polyState(), m_l3Key(), len); + t += GetWord(true, BIG_ENDIAN_ORDER, m_pad() + (m_nonce()[IVSize()-1]&1) * 8); + if (size == 8) + PutWord(false, BIG_ENDIAN_ORDER, mac, t); + else + { + t = ConditionalByteReverse(BIG_ENDIAN_ORDER, t); + memcpy(mac, &t, size); + } + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/vmac.h b/extension/third_party/cryptopp/vmac.h new file mode 100644 index 00000000..44fe09fc --- /dev/null +++ b/extension/third_party/cryptopp/vmac.h @@ -0,0 +1,91 @@ +// vmac.h - originally written and placed in the public domain by Wei Dai + +/// \file vmac.h +/// \brief Classes for the VMAC message authentication code +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_VMAC_H +#define CRYPTOPP_VMAC_H + +#include "cryptlib.h" +#include "iterhash.h" +#include "seckey.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_VMAC_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief VMAC message authentication code base class +/// \since Crypto++ 5.5 +class VMAC_Base : public IteratedHashBase +{ +public: + std::string AlgorithmName() const {return std::string("VMAC(") + GetCipher().AlgorithmName() + ")-" + IntToString(DigestSize()*8);} + std::string AlgorithmProvider() const {return GetCipher().AlgorithmProvider();} + unsigned int IVSize() const {return GetCipher().BlockSize();} + unsigned int MinIVLength() const {return 1;} + void Resynchronize(const byte *nonce, int length=-1); + void GetNextIV(RandomNumberGenerator &rng, byte *IV); + unsigned int DigestSize() const {return m_is128 ? 16 : 8;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + unsigned int BlockSize() const {return m_L1KeyLength;} + ByteOrder GetByteOrder() const {return LITTLE_ENDIAN_ORDER;} + unsigned int OptimalDataAlignment() const; + +protected: + virtual BlockCipher & AccessCipher() =0; + virtual int DefaultDigestSize() const =0; + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + void HashEndianCorrectedBlock(const word64 *data); + size_t HashMultipleBlocks(const word64 *input, size_t length); + void Init() {} + word64* StateBuf() {return NULLPTR;} + word64* DataBuf() {return (word64 *)(void*)m_data();} + + void VHASH_Update_SSE2(const word64 *data, size_t blocksRemainingInWord64, int tagPart); + template + void VHASH_Update_Template(const word64 *data, size_t blockRemainingInWord128); + void VHASH_Update(const word64 *data, size_t blocksRemainingInWord128); + + CRYPTOPP_BLOCK_1(polyState, word64, (m_is128 ? 8 : 4)) + CRYPTOPP_BLOCK_2(nhKey, word64, m_L1KeyLength/sizeof(word64) + 2*m_is128) + CRYPTOPP_BLOCK_3(data, byte, m_L1KeyLength) + CRYPTOPP_BLOCK_4(l3Key, word64, (m_is128 ? 4 : 2)) + CRYPTOPP_BLOCK_5(nonce, byte, IVSize()) + CRYPTOPP_BLOCK_6(pad, byte, IVSize()) + CRYPTOPP_BLOCKS_END(6) + + bool m_is128, m_padCached, m_isFirstBlock; + unsigned int m_L1KeyLength; +}; + +/// \brief VMAC message authentication code +/// \tparam T_BlockCipher block cipher +/// \tparam T_DigestBitSize digest size, in bits +/// \details VMAC is a block cipher-based message authentication code algorithm +/// using a universal hash proposed by Ted Krovetz and Wei Dai in April 2007. The +/// algorithm was designed for high performance backed by a formal analysis. +/// \details The implementation is based on Ted Krovetz's public domain vmac.c +/// and draft-krovetz-vmac-01.txt. +/// \sa VMAC. +/// \since Crypto++ 5.5 +template +class VMAC : public SimpleKeyingInterfaceImpl > +{ +public: + static std::string StaticAlgorithmName() {return std::string("VMAC(") + T_BlockCipher::StaticAlgorithmName() + ")-" + IntToString(T_DigestBitSize);} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DigestBitSize/8;} + typename T_BlockCipher::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/wake.cpp b/extension/third_party/cryptopp/wake.cpp new file mode 100644 index 00000000..f4e43dc1 --- /dev/null +++ b/extension/third_party/cryptopp/wake.cpp @@ -0,0 +1,111 @@ +// wake.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "wake.h" +#include "smartptr.h" + +ANONYMOUS_NAMESPACE_BEGIN + +const unsigned int TT[8]= { + 0x726a8f3b, 0xe69a3b5c, 0xd3c71fe5, 0xab3c73d2, + 0x4d3a8eb3, 0x0396d6e8, 0x3d4c2f7a, 0x9ee27cf3 +} ; + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void WAKE_TestInstantiations() +{ + WAKE_OFB<>::Encryption x2; + WAKE_OFB<>::Decryption x4; +} +#endif + +inline word32 WAKE_Base::M(word32 x, word32 y) +{ + word32 w = x+y; + return (w>>8) ^ t[w & 0xff]; +} + +void WAKE_Base::GenKey(word32 k0, word32 k1, word32 k2, word32 k3) +{ + // this code is mostly copied from David Wheeler's paper "A Bulk Data Encryption Algorithm" + signed int x, z, p; + + t[0] = k0; + t[1] = k1; + t[2] = k2; + t[3] = k3; + for (p=4 ; p<256 ; p++) + { + x=t[p-4]+t[p-1] ; // fill t + t[p]= (x>>3) ^ TT[x&7] ; + } + + for (p=0 ; p<23 ; p++) + t[p]+=t[p+89] ; // mix first entries + x=t[33] ; z=t[59] | 0x01000001 ; + z=z&0xff7fffff ; + for (p=0 ; p<256 ; p++) { //change top byte to + x=(x&0xff7fffff)+z ; // a permutation etc + t[p]=(t[p] & 0x00ffffff) ^ x ; } + + t[256]=t[0] ; + byte y=byte(x); + for (p=0 ; p<256 ; p++) { // further change perm. + t[p]=t[y=byte(t[p^y]^y)] ; // and other digits + t[y]=t[p+1] ; } +} + +template +void WAKE_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(key); CRYPTOPP_UNUSED(length); + word32 k0, k1, k2, k3; + BlockGetAndPut::Get(key)(r3)(r4)(r5)(r6)(k0)(k1)(k2)(k3); + GenKey(k0, k1, k2, k3); +} + +// OFB +template +void WAKE_Policy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ +#define WAKE_OUTPUT(x)\ + while (iterationCount--)\ + {\ + CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 0, r6);\ + r3 = M(r3, r6);\ + r4 = M(r4, r3);\ + r5 = M(r5, r4);\ + r6 = M(r6, r5);\ + output += 4;\ + if (!(x & INPUT_NULL))\ + input += 4;\ + } + + typedef word32 WordType; + CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(WAKE_OUTPUT, 0); +} +/* +template +void WAKE_ROFB_Policy::Iterate(KeystreamOperation operation, byte *output, const byte *input, unsigned int iterationCount) +{ + KeystreamOutput keystreamOperation(operation, output, input); + + while (iterationCount--) + { + keystreamOperation(r6); + r3 = M(r3, r6); + r4 = M(r4, r3); + r5 = M(r5, r4); + r6 = M(r6, r5); + } +} +*/ +template class WAKE_Policy; +template class WAKE_Policy; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/wake.h b/extension/third_party/cryptopp/wake.h new file mode 100644 index 00000000..adecd30f --- /dev/null +++ b/extension/third_party/cryptopp/wake.h @@ -0,0 +1,59 @@ +// wake.h - originally written and placed in the public domain by Wei Dai + +/// \file wake.h +/// \brief Classes for WAKE stream cipher + +#ifndef CRYPTOPP_WAKE_H +#define CRYPTOPP_WAKE_H + +#include "seckey.h" +#include "secblock.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief WAKE stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB_Info : public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "WAKE-OFB-LE" : "WAKE-OFB-BE";} +}; + +class CRYPTOPP_NO_VTABLE WAKE_Base +{ +protected: + word32 M(word32 x, word32 y); + void GenKey(word32 k0, word32 k1, word32 k2, word32 k3); + + word32 t[257]; + word32 r3, r4, r5, r6; +}; + +/// \brief WAKE stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +class CRYPTOPP_NO_VTABLE WAKE_Policy : public AdditiveCipherConcretePolicy, protected WAKE_Base +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + // OFB + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} +}; + +/// \brief WAKE stream cipher +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB : public WAKE_OFB_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, WAKE_OFB_Info > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/whrlpool.cpp b/extension/third_party/cryptopp/whrlpool.cpp new file mode 100644 index 00000000..4a52a0dd --- /dev/null +++ b/extension/third_party/cryptopp/whrlpool.cpp @@ -0,0 +1,730 @@ +// whrlpool.cpp - originally modified by Kevin Springle from Paulo Barreto and Vincent Rijmen's +// public domain code, whirlpool.c. Updated to Whirlpool version 3.0, optimized +// and SSE version added by WD. All modifications are placed in the public domain. +// +// This is the original introductory comment: + +/** + * The Whirlpool hashing function. + * + *

+ * References + * + *

+ * The Whirlpool algorithm was developed by + * Paulo S. L. M. Barreto and + * Vincent Rijmen. + * + * See + * P.S.L.M. Barreto, V. Rijmen, + * ``The Whirlpool hashing function,'' + * NESSIE submission, 2000 (tweaked version, 2001), + * + * + * @author Paulo S.L.M. Barreto + * @author Vincent Rijmen. + * + * @version 3.0 (2003.03.12) + * + * ============================================================================= + * + * Differences from version 2.1: + * + * - Suboptimal diffusion matrix replaced by cir(1, 1, 4, 1, 8, 5, 2, 9). + * + * ============================================================================= + * + * Differences from version 2.0: + * + * - Generation of ISO/IEC 10118-3 test vectors. + * - Bug fix: nonzero carry was ignored when tallying the data length + * (this bug apparently only manifested itself when feeding data + * in pieces rather than in a single chunk at once). + * - Support for MS Visual C++ 64-bit integer arithmetic. + * + * Differences from version 1.0: + * + * - Original S-box replaced by the tweaked, hardware-efficient version. + * + * ============================================================================= + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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. + * + */ + +#include "pch.h" +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4127) +#endif + +#include "whrlpool.h" +#include "misc.h" +#include "cpu.h" + +#if defined(CRYPTOPP_DISABLE_WHIRLPOOL_ASM) +# undef CRYPTOPP_X86_ASM_AVAILABLE +# undef CRYPTOPP_X32_ASM_AVAILABLE +# undef CRYPTOPP_X64_ASM_AVAILABLE +# undef CRYPTOPP_SSE2_ASM_AVAILABLE +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void Whirlpool_TestInstantiations() +{ + Whirlpool x; +} +#endif + +std::string Whirlpool::AlgorithmProvider() const +{ +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return "SSE2"; +#endif + return "C++"; +} + +void Whirlpool::InitState(HashWordType *state) +{ + memset(state, 0, 8*sizeof(state[0])); +} + +void Whirlpool::TruncatedFinal(byte *hash, size_t size) +{ + CRYPTOPP_ASSERT(hash != NULLPTR); + ThrowIfInvalidTruncatedSize(size); + + PadLastBlock(32); + CorrectEndianess(m_data, m_data, 32); + + m_data[m_data.size()-4] = 0; + m_data[m_data.size()-3] = 0; + m_data[m_data.size()-2] = GetBitCountHi(); + m_data[m_data.size()-1] = GetBitCountLo(); + + Transform(m_state, m_data); + CorrectEndianess(m_state, m_state, DigestSize()); + memcpy(hash, m_state, size); + + Restart(); // reinit for next use +} + +/* + * The number of rounds of the internal dedicated block cipher. + */ +#define R 10 + +/* + * Though Whirlpool is endianness-neutral, the encryption tables are listed + * in BIG-ENDIAN format, which is adopted throughout this implementation + * (but little-endian notation would be equally suitable if consistently + * employed). + */ + +#if CRYPTOPP_SSE2_ASM_AVAILABLE +CRYPTOPP_ALIGN_DATA(16) +CRYPTOPP_TABLE +const word64 Whirlpool_C[4*256+R] = { +#else +const word64 Whirlpool_C[4*256+R] = { +#endif + W64LIT(0x18186018c07830d8), W64LIT(0x23238c2305af4626), W64LIT(0xc6c63fc67ef991b8), W64LIT(0xe8e887e8136fcdfb), + W64LIT(0x878726874ca113cb), W64LIT(0xb8b8dab8a9626d11), W64LIT(0x0101040108050209), W64LIT(0x4f4f214f426e9e0d), + W64LIT(0x3636d836adee6c9b), W64LIT(0xa6a6a2a6590451ff), W64LIT(0xd2d26fd2debdb90c), W64LIT(0xf5f5f3f5fb06f70e), + W64LIT(0x7979f979ef80f296), W64LIT(0x6f6fa16f5fcede30), W64LIT(0x91917e91fcef3f6d), W64LIT(0x52525552aa07a4f8), + W64LIT(0x60609d6027fdc047), W64LIT(0xbcbccabc89766535), W64LIT(0x9b9b569baccd2b37), W64LIT(0x8e8e028e048c018a), + W64LIT(0xa3a3b6a371155bd2), W64LIT(0x0c0c300c603c186c), W64LIT(0x7b7bf17bff8af684), W64LIT(0x3535d435b5e16a80), + W64LIT(0x1d1d741de8693af5), W64LIT(0xe0e0a7e05347ddb3), W64LIT(0xd7d77bd7f6acb321), W64LIT(0xc2c22fc25eed999c), + W64LIT(0x2e2eb82e6d965c43), W64LIT(0x4b4b314b627a9629), W64LIT(0xfefedffea321e15d), W64LIT(0x575741578216aed5), + W64LIT(0x15155415a8412abd), W64LIT(0x7777c1779fb6eee8), W64LIT(0x3737dc37a5eb6e92), W64LIT(0xe5e5b3e57b56d79e), + W64LIT(0x9f9f469f8cd92313), W64LIT(0xf0f0e7f0d317fd23), W64LIT(0x4a4a354a6a7f9420), W64LIT(0xdada4fda9e95a944), + W64LIT(0x58587d58fa25b0a2), W64LIT(0xc9c903c906ca8fcf), W64LIT(0x2929a429558d527c), W64LIT(0x0a0a280a5022145a), + W64LIT(0xb1b1feb1e14f7f50), W64LIT(0xa0a0baa0691a5dc9), W64LIT(0x6b6bb16b7fdad614), W64LIT(0x85852e855cab17d9), + W64LIT(0xbdbdcebd8173673c), W64LIT(0x5d5d695dd234ba8f), W64LIT(0x1010401080502090), W64LIT(0xf4f4f7f4f303f507), + W64LIT(0xcbcb0bcb16c08bdd), W64LIT(0x3e3ef83eedc67cd3), W64LIT(0x0505140528110a2d), W64LIT(0x676781671fe6ce78), + W64LIT(0xe4e4b7e47353d597), W64LIT(0x27279c2725bb4e02), W64LIT(0x4141194132588273), W64LIT(0x8b8b168b2c9d0ba7), + W64LIT(0xa7a7a6a7510153f6), W64LIT(0x7d7de97dcf94fab2), W64LIT(0x95956e95dcfb3749), W64LIT(0xd8d847d88e9fad56), + W64LIT(0xfbfbcbfb8b30eb70), W64LIT(0xeeee9fee2371c1cd), W64LIT(0x7c7ced7cc791f8bb), W64LIT(0x6666856617e3cc71), + W64LIT(0xdddd53dda68ea77b), W64LIT(0x17175c17b84b2eaf), W64LIT(0x4747014702468e45), W64LIT(0x9e9e429e84dc211a), + W64LIT(0xcaca0fca1ec589d4), W64LIT(0x2d2db42d75995a58), W64LIT(0xbfbfc6bf9179632e), W64LIT(0x07071c07381b0e3f), + W64LIT(0xadad8ead012347ac), W64LIT(0x5a5a755aea2fb4b0), W64LIT(0x838336836cb51bef), W64LIT(0x3333cc3385ff66b6), + W64LIT(0x636391633ff2c65c), W64LIT(0x02020802100a0412), W64LIT(0xaaaa92aa39384993), W64LIT(0x7171d971afa8e2de), + W64LIT(0xc8c807c80ecf8dc6), W64LIT(0x19196419c87d32d1), W64LIT(0x494939497270923b), W64LIT(0xd9d943d9869aaf5f), + W64LIT(0xf2f2eff2c31df931), W64LIT(0xe3e3abe34b48dba8), W64LIT(0x5b5b715be22ab6b9), W64LIT(0x88881a8834920dbc), + W64LIT(0x9a9a529aa4c8293e), W64LIT(0x262698262dbe4c0b), W64LIT(0x3232c8328dfa64bf), W64LIT(0xb0b0fab0e94a7d59), + W64LIT(0xe9e983e91b6acff2), W64LIT(0x0f0f3c0f78331e77), W64LIT(0xd5d573d5e6a6b733), W64LIT(0x80803a8074ba1df4), + W64LIT(0xbebec2be997c6127), W64LIT(0xcdcd13cd26de87eb), W64LIT(0x3434d034bde46889), W64LIT(0x48483d487a759032), + W64LIT(0xffffdbffab24e354), W64LIT(0x7a7af57af78ff48d), W64LIT(0x90907a90f4ea3d64), W64LIT(0x5f5f615fc23ebe9d), + W64LIT(0x202080201da0403d), W64LIT(0x6868bd6867d5d00f), W64LIT(0x1a1a681ad07234ca), W64LIT(0xaeae82ae192c41b7), + W64LIT(0xb4b4eab4c95e757d), W64LIT(0x54544d549a19a8ce), W64LIT(0x93937693ece53b7f), W64LIT(0x222288220daa442f), + W64LIT(0x64648d6407e9c863), W64LIT(0xf1f1e3f1db12ff2a), W64LIT(0x7373d173bfa2e6cc), W64LIT(0x12124812905a2482), + W64LIT(0x40401d403a5d807a), W64LIT(0x0808200840281048), W64LIT(0xc3c32bc356e89b95), W64LIT(0xecec97ec337bc5df), + W64LIT(0xdbdb4bdb9690ab4d), W64LIT(0xa1a1bea1611f5fc0), W64LIT(0x8d8d0e8d1c830791), W64LIT(0x3d3df43df5c97ac8), + W64LIT(0x97976697ccf1335b), W64LIT(0x0000000000000000), W64LIT(0xcfcf1bcf36d483f9), W64LIT(0x2b2bac2b4587566e), + W64LIT(0x7676c57697b3ece1), W64LIT(0x8282328264b019e6), W64LIT(0xd6d67fd6fea9b128), W64LIT(0x1b1b6c1bd87736c3), + W64LIT(0xb5b5eeb5c15b7774), W64LIT(0xafaf86af112943be), W64LIT(0x6a6ab56a77dfd41d), W64LIT(0x50505d50ba0da0ea), + W64LIT(0x45450945124c8a57), W64LIT(0xf3f3ebf3cb18fb38), W64LIT(0x3030c0309df060ad), W64LIT(0xefef9bef2b74c3c4), + W64LIT(0x3f3ffc3fe5c37eda), W64LIT(0x55554955921caac7), W64LIT(0xa2a2b2a2791059db), W64LIT(0xeaea8fea0365c9e9), + W64LIT(0x656589650fecca6a), W64LIT(0xbabad2bab9686903), W64LIT(0x2f2fbc2f65935e4a), W64LIT(0xc0c027c04ee79d8e), + W64LIT(0xdede5fdebe81a160), W64LIT(0x1c1c701ce06c38fc), W64LIT(0xfdfdd3fdbb2ee746), W64LIT(0x4d4d294d52649a1f), + W64LIT(0x92927292e4e03976), W64LIT(0x7575c9758fbceafa), W64LIT(0x06061806301e0c36), W64LIT(0x8a8a128a249809ae), + W64LIT(0xb2b2f2b2f940794b), W64LIT(0xe6e6bfe66359d185), W64LIT(0x0e0e380e70361c7e), W64LIT(0x1f1f7c1ff8633ee7), + W64LIT(0x6262956237f7c455), W64LIT(0xd4d477d4eea3b53a), W64LIT(0xa8a89aa829324d81), W64LIT(0x96966296c4f43152), + W64LIT(0xf9f9c3f99b3aef62), W64LIT(0xc5c533c566f697a3), W64LIT(0x2525942535b14a10), W64LIT(0x59597959f220b2ab), + W64LIT(0x84842a8454ae15d0), W64LIT(0x7272d572b7a7e4c5), W64LIT(0x3939e439d5dd72ec), W64LIT(0x4c4c2d4c5a619816), + W64LIT(0x5e5e655eca3bbc94), W64LIT(0x7878fd78e785f09f), W64LIT(0x3838e038ddd870e5), W64LIT(0x8c8c0a8c14860598), + W64LIT(0xd1d163d1c6b2bf17), W64LIT(0xa5a5aea5410b57e4), W64LIT(0xe2e2afe2434dd9a1), W64LIT(0x616199612ff8c24e), + W64LIT(0xb3b3f6b3f1457b42), W64LIT(0x2121842115a54234), W64LIT(0x9c9c4a9c94d62508), W64LIT(0x1e1e781ef0663cee), + W64LIT(0x4343114322528661), W64LIT(0xc7c73bc776fc93b1), W64LIT(0xfcfcd7fcb32be54f), W64LIT(0x0404100420140824), + W64LIT(0x51515951b208a2e3), W64LIT(0x99995e99bcc72f25), W64LIT(0x6d6da96d4fc4da22), W64LIT(0x0d0d340d68391a65), + W64LIT(0xfafacffa8335e979), W64LIT(0xdfdf5bdfb684a369), W64LIT(0x7e7ee57ed79bfca9), W64LIT(0x242490243db44819), + W64LIT(0x3b3bec3bc5d776fe), W64LIT(0xabab96ab313d4b9a), W64LIT(0xcece1fce3ed181f0), W64LIT(0x1111441188552299), + W64LIT(0x8f8f068f0c890383), W64LIT(0x4e4e254e4a6b9c04), W64LIT(0xb7b7e6b7d1517366), W64LIT(0xebeb8beb0b60cbe0), + W64LIT(0x3c3cf03cfdcc78c1), W64LIT(0x81813e817cbf1ffd), W64LIT(0x94946a94d4fe3540), W64LIT(0xf7f7fbf7eb0cf31c), + W64LIT(0xb9b9deb9a1676f18), W64LIT(0x13134c13985f268b), W64LIT(0x2c2cb02c7d9c5851), W64LIT(0xd3d36bd3d6b8bb05), + W64LIT(0xe7e7bbe76b5cd38c), W64LIT(0x6e6ea56e57cbdc39), W64LIT(0xc4c437c46ef395aa), W64LIT(0x03030c03180f061b), + W64LIT(0x565645568a13acdc), W64LIT(0x44440d441a49885e), W64LIT(0x7f7fe17fdf9efea0), W64LIT(0xa9a99ea921374f88), + W64LIT(0x2a2aa82a4d825467), W64LIT(0xbbbbd6bbb16d6b0a), W64LIT(0xc1c123c146e29f87), W64LIT(0x53535153a202a6f1), + W64LIT(0xdcdc57dcae8ba572), W64LIT(0x0b0b2c0b58271653), W64LIT(0x9d9d4e9d9cd32701), W64LIT(0x6c6cad6c47c1d82b), + W64LIT(0x3131c43195f562a4), W64LIT(0x7474cd7487b9e8f3), W64LIT(0xf6f6fff6e309f115), W64LIT(0x464605460a438c4c), + W64LIT(0xacac8aac092645a5), W64LIT(0x89891e893c970fb5), W64LIT(0x14145014a04428b4), W64LIT(0xe1e1a3e15b42dfba), + W64LIT(0x16165816b04e2ca6), W64LIT(0x3a3ae83acdd274f7), W64LIT(0x6969b9696fd0d206), W64LIT(0x09092409482d1241), + W64LIT(0x7070dd70a7ade0d7), W64LIT(0xb6b6e2b6d954716f), W64LIT(0xd0d067d0ceb7bd1e), W64LIT(0xeded93ed3b7ec7d6), + W64LIT(0xcccc17cc2edb85e2), W64LIT(0x424215422a578468), W64LIT(0x98985a98b4c22d2c), W64LIT(0xa4a4aaa4490e55ed), + W64LIT(0x2828a0285d885075), W64LIT(0x5c5c6d5cda31b886), W64LIT(0xf8f8c7f8933fed6b), W64LIT(0x8686228644a411c2), + + W64LIT(0xd818186018c07830), W64LIT(0x2623238c2305af46), W64LIT(0xb8c6c63fc67ef991), W64LIT(0xfbe8e887e8136fcd), + W64LIT(0xcb878726874ca113), W64LIT(0x11b8b8dab8a9626d), W64LIT(0x0901010401080502), W64LIT(0x0d4f4f214f426e9e), + W64LIT(0x9b3636d836adee6c), W64LIT(0xffa6a6a2a6590451), W64LIT(0x0cd2d26fd2debdb9), W64LIT(0x0ef5f5f3f5fb06f7), + W64LIT(0x967979f979ef80f2), W64LIT(0x306f6fa16f5fcede), W64LIT(0x6d91917e91fcef3f), W64LIT(0xf852525552aa07a4), + W64LIT(0x4760609d6027fdc0), W64LIT(0x35bcbccabc897665), W64LIT(0x379b9b569baccd2b), W64LIT(0x8a8e8e028e048c01), + W64LIT(0xd2a3a3b6a371155b), W64LIT(0x6c0c0c300c603c18), W64LIT(0x847b7bf17bff8af6), W64LIT(0x803535d435b5e16a), + W64LIT(0xf51d1d741de8693a), W64LIT(0xb3e0e0a7e05347dd), W64LIT(0x21d7d77bd7f6acb3), W64LIT(0x9cc2c22fc25eed99), + W64LIT(0x432e2eb82e6d965c), W64LIT(0x294b4b314b627a96), W64LIT(0x5dfefedffea321e1), W64LIT(0xd5575741578216ae), + W64LIT(0xbd15155415a8412a), W64LIT(0xe87777c1779fb6ee), W64LIT(0x923737dc37a5eb6e), W64LIT(0x9ee5e5b3e57b56d7), + W64LIT(0x139f9f469f8cd923), W64LIT(0x23f0f0e7f0d317fd), W64LIT(0x204a4a354a6a7f94), W64LIT(0x44dada4fda9e95a9), + W64LIT(0xa258587d58fa25b0), W64LIT(0xcfc9c903c906ca8f), W64LIT(0x7c2929a429558d52), W64LIT(0x5a0a0a280a502214), + W64LIT(0x50b1b1feb1e14f7f), W64LIT(0xc9a0a0baa0691a5d), W64LIT(0x146b6bb16b7fdad6), W64LIT(0xd985852e855cab17), + W64LIT(0x3cbdbdcebd817367), W64LIT(0x8f5d5d695dd234ba), W64LIT(0x9010104010805020), W64LIT(0x07f4f4f7f4f303f5), + W64LIT(0xddcbcb0bcb16c08b), W64LIT(0xd33e3ef83eedc67c), W64LIT(0x2d0505140528110a), W64LIT(0x78676781671fe6ce), + W64LIT(0x97e4e4b7e47353d5), W64LIT(0x0227279c2725bb4e), W64LIT(0x7341411941325882), W64LIT(0xa78b8b168b2c9d0b), + W64LIT(0xf6a7a7a6a7510153), W64LIT(0xb27d7de97dcf94fa), W64LIT(0x4995956e95dcfb37), W64LIT(0x56d8d847d88e9fad), + W64LIT(0x70fbfbcbfb8b30eb), W64LIT(0xcdeeee9fee2371c1), W64LIT(0xbb7c7ced7cc791f8), W64LIT(0x716666856617e3cc), + W64LIT(0x7bdddd53dda68ea7), W64LIT(0xaf17175c17b84b2e), W64LIT(0x454747014702468e), W64LIT(0x1a9e9e429e84dc21), + W64LIT(0xd4caca0fca1ec589), W64LIT(0x582d2db42d75995a), W64LIT(0x2ebfbfc6bf917963), W64LIT(0x3f07071c07381b0e), + W64LIT(0xacadad8ead012347), W64LIT(0xb05a5a755aea2fb4), W64LIT(0xef838336836cb51b), W64LIT(0xb63333cc3385ff66), + W64LIT(0x5c636391633ff2c6), W64LIT(0x1202020802100a04), W64LIT(0x93aaaa92aa393849), W64LIT(0xde7171d971afa8e2), + W64LIT(0xc6c8c807c80ecf8d), W64LIT(0xd119196419c87d32), W64LIT(0x3b49493949727092), W64LIT(0x5fd9d943d9869aaf), + W64LIT(0x31f2f2eff2c31df9), W64LIT(0xa8e3e3abe34b48db), W64LIT(0xb95b5b715be22ab6), W64LIT(0xbc88881a8834920d), + W64LIT(0x3e9a9a529aa4c829), W64LIT(0x0b262698262dbe4c), W64LIT(0xbf3232c8328dfa64), W64LIT(0x59b0b0fab0e94a7d), + W64LIT(0xf2e9e983e91b6acf), W64LIT(0x770f0f3c0f78331e), W64LIT(0x33d5d573d5e6a6b7), W64LIT(0xf480803a8074ba1d), + W64LIT(0x27bebec2be997c61), W64LIT(0xebcdcd13cd26de87), W64LIT(0x893434d034bde468), W64LIT(0x3248483d487a7590), + W64LIT(0x54ffffdbffab24e3), W64LIT(0x8d7a7af57af78ff4), W64LIT(0x6490907a90f4ea3d), W64LIT(0x9d5f5f615fc23ebe), + W64LIT(0x3d202080201da040), W64LIT(0x0f6868bd6867d5d0), W64LIT(0xca1a1a681ad07234), W64LIT(0xb7aeae82ae192c41), + W64LIT(0x7db4b4eab4c95e75), W64LIT(0xce54544d549a19a8), W64LIT(0x7f93937693ece53b), W64LIT(0x2f222288220daa44), + W64LIT(0x6364648d6407e9c8), W64LIT(0x2af1f1e3f1db12ff), W64LIT(0xcc7373d173bfa2e6), W64LIT(0x8212124812905a24), + W64LIT(0x7a40401d403a5d80), W64LIT(0x4808082008402810), W64LIT(0x95c3c32bc356e89b), W64LIT(0xdfecec97ec337bc5), + W64LIT(0x4ddbdb4bdb9690ab), W64LIT(0xc0a1a1bea1611f5f), W64LIT(0x918d8d0e8d1c8307), W64LIT(0xc83d3df43df5c97a), + W64LIT(0x5b97976697ccf133), W64LIT(0x0000000000000000), W64LIT(0xf9cfcf1bcf36d483), W64LIT(0x6e2b2bac2b458756), + W64LIT(0xe17676c57697b3ec), W64LIT(0xe68282328264b019), W64LIT(0x28d6d67fd6fea9b1), W64LIT(0xc31b1b6c1bd87736), + W64LIT(0x74b5b5eeb5c15b77), W64LIT(0xbeafaf86af112943), W64LIT(0x1d6a6ab56a77dfd4), W64LIT(0xea50505d50ba0da0), + W64LIT(0x5745450945124c8a), W64LIT(0x38f3f3ebf3cb18fb), W64LIT(0xad3030c0309df060), W64LIT(0xc4efef9bef2b74c3), + W64LIT(0xda3f3ffc3fe5c37e), W64LIT(0xc755554955921caa), W64LIT(0xdba2a2b2a2791059), W64LIT(0xe9eaea8fea0365c9), + W64LIT(0x6a656589650fecca), W64LIT(0x03babad2bab96869), W64LIT(0x4a2f2fbc2f65935e), W64LIT(0x8ec0c027c04ee79d), + W64LIT(0x60dede5fdebe81a1), W64LIT(0xfc1c1c701ce06c38), W64LIT(0x46fdfdd3fdbb2ee7), W64LIT(0x1f4d4d294d52649a), + W64LIT(0x7692927292e4e039), W64LIT(0xfa7575c9758fbcea), W64LIT(0x3606061806301e0c), W64LIT(0xae8a8a128a249809), + W64LIT(0x4bb2b2f2b2f94079), W64LIT(0x85e6e6bfe66359d1), W64LIT(0x7e0e0e380e70361c), W64LIT(0xe71f1f7c1ff8633e), + W64LIT(0x556262956237f7c4), W64LIT(0x3ad4d477d4eea3b5), W64LIT(0x81a8a89aa829324d), W64LIT(0x5296966296c4f431), + W64LIT(0x62f9f9c3f99b3aef), W64LIT(0xa3c5c533c566f697), W64LIT(0x102525942535b14a), W64LIT(0xab59597959f220b2), + W64LIT(0xd084842a8454ae15), W64LIT(0xc57272d572b7a7e4), W64LIT(0xec3939e439d5dd72), W64LIT(0x164c4c2d4c5a6198), + W64LIT(0x945e5e655eca3bbc), W64LIT(0x9f7878fd78e785f0), W64LIT(0xe53838e038ddd870), W64LIT(0x988c8c0a8c148605), + W64LIT(0x17d1d163d1c6b2bf), W64LIT(0xe4a5a5aea5410b57), W64LIT(0xa1e2e2afe2434dd9), W64LIT(0x4e616199612ff8c2), + W64LIT(0x42b3b3f6b3f1457b), W64LIT(0x342121842115a542), W64LIT(0x089c9c4a9c94d625), W64LIT(0xee1e1e781ef0663c), + W64LIT(0x6143431143225286), W64LIT(0xb1c7c73bc776fc93), W64LIT(0x4ffcfcd7fcb32be5), W64LIT(0x2404041004201408), + W64LIT(0xe351515951b208a2), W64LIT(0x2599995e99bcc72f), W64LIT(0x226d6da96d4fc4da), W64LIT(0x650d0d340d68391a), + W64LIT(0x79fafacffa8335e9), W64LIT(0x69dfdf5bdfb684a3), W64LIT(0xa97e7ee57ed79bfc), W64LIT(0x19242490243db448), + W64LIT(0xfe3b3bec3bc5d776), W64LIT(0x9aabab96ab313d4b), W64LIT(0xf0cece1fce3ed181), W64LIT(0x9911114411885522), + W64LIT(0x838f8f068f0c8903), W64LIT(0x044e4e254e4a6b9c), W64LIT(0x66b7b7e6b7d15173), W64LIT(0xe0ebeb8beb0b60cb), + W64LIT(0xc13c3cf03cfdcc78), W64LIT(0xfd81813e817cbf1f), W64LIT(0x4094946a94d4fe35), W64LIT(0x1cf7f7fbf7eb0cf3), + W64LIT(0x18b9b9deb9a1676f), W64LIT(0x8b13134c13985f26), W64LIT(0x512c2cb02c7d9c58), W64LIT(0x05d3d36bd3d6b8bb), + W64LIT(0x8ce7e7bbe76b5cd3), W64LIT(0x396e6ea56e57cbdc), W64LIT(0xaac4c437c46ef395), W64LIT(0x1b03030c03180f06), + W64LIT(0xdc565645568a13ac), W64LIT(0x5e44440d441a4988), W64LIT(0xa07f7fe17fdf9efe), W64LIT(0x88a9a99ea921374f), + W64LIT(0x672a2aa82a4d8254), W64LIT(0x0abbbbd6bbb16d6b), W64LIT(0x87c1c123c146e29f), W64LIT(0xf153535153a202a6), + W64LIT(0x72dcdc57dcae8ba5), W64LIT(0x530b0b2c0b582716), W64LIT(0x019d9d4e9d9cd327), W64LIT(0x2b6c6cad6c47c1d8), + W64LIT(0xa43131c43195f562), W64LIT(0xf37474cd7487b9e8), W64LIT(0x15f6f6fff6e309f1), W64LIT(0x4c464605460a438c), + W64LIT(0xa5acac8aac092645), W64LIT(0xb589891e893c970f), W64LIT(0xb414145014a04428), W64LIT(0xbae1e1a3e15b42df), + W64LIT(0xa616165816b04e2c), W64LIT(0xf73a3ae83acdd274), W64LIT(0x066969b9696fd0d2), W64LIT(0x4109092409482d12), + W64LIT(0xd77070dd70a7ade0), W64LIT(0x6fb6b6e2b6d95471), W64LIT(0x1ed0d067d0ceb7bd), W64LIT(0xd6eded93ed3b7ec7), + W64LIT(0xe2cccc17cc2edb85), W64LIT(0x68424215422a5784), W64LIT(0x2c98985a98b4c22d), W64LIT(0xeda4a4aaa4490e55), + W64LIT(0x752828a0285d8850), W64LIT(0x865c5c6d5cda31b8), W64LIT(0x6bf8f8c7f8933fed), W64LIT(0xc28686228644a411), + + W64LIT(0x30d818186018c078), W64LIT(0x462623238c2305af), W64LIT(0x91b8c6c63fc67ef9), W64LIT(0xcdfbe8e887e8136f), + W64LIT(0x13cb878726874ca1), W64LIT(0x6d11b8b8dab8a962), W64LIT(0x0209010104010805), W64LIT(0x9e0d4f4f214f426e), + W64LIT(0x6c9b3636d836adee), W64LIT(0x51ffa6a6a2a65904), W64LIT(0xb90cd2d26fd2debd), W64LIT(0xf70ef5f5f3f5fb06), + W64LIT(0xf2967979f979ef80), W64LIT(0xde306f6fa16f5fce), W64LIT(0x3f6d91917e91fcef), W64LIT(0xa4f852525552aa07), + W64LIT(0xc04760609d6027fd), W64LIT(0x6535bcbccabc8976), W64LIT(0x2b379b9b569baccd), W64LIT(0x018a8e8e028e048c), + W64LIT(0x5bd2a3a3b6a37115), W64LIT(0x186c0c0c300c603c), W64LIT(0xf6847b7bf17bff8a), W64LIT(0x6a803535d435b5e1), + W64LIT(0x3af51d1d741de869), W64LIT(0xddb3e0e0a7e05347), W64LIT(0xb321d7d77bd7f6ac), W64LIT(0x999cc2c22fc25eed), + W64LIT(0x5c432e2eb82e6d96), W64LIT(0x96294b4b314b627a), W64LIT(0xe15dfefedffea321), W64LIT(0xaed5575741578216), + W64LIT(0x2abd15155415a841), W64LIT(0xeee87777c1779fb6), W64LIT(0x6e923737dc37a5eb), W64LIT(0xd79ee5e5b3e57b56), + W64LIT(0x23139f9f469f8cd9), W64LIT(0xfd23f0f0e7f0d317), W64LIT(0x94204a4a354a6a7f), W64LIT(0xa944dada4fda9e95), + W64LIT(0xb0a258587d58fa25), W64LIT(0x8fcfc9c903c906ca), W64LIT(0x527c2929a429558d), W64LIT(0x145a0a0a280a5022), + W64LIT(0x7f50b1b1feb1e14f), W64LIT(0x5dc9a0a0baa0691a), W64LIT(0xd6146b6bb16b7fda), W64LIT(0x17d985852e855cab), + W64LIT(0x673cbdbdcebd8173), W64LIT(0xba8f5d5d695dd234), W64LIT(0x2090101040108050), W64LIT(0xf507f4f4f7f4f303), + W64LIT(0x8bddcbcb0bcb16c0), W64LIT(0x7cd33e3ef83eedc6), W64LIT(0x0a2d050514052811), W64LIT(0xce78676781671fe6), + W64LIT(0xd597e4e4b7e47353), W64LIT(0x4e0227279c2725bb), W64LIT(0x8273414119413258), W64LIT(0x0ba78b8b168b2c9d), + W64LIT(0x53f6a7a7a6a75101), W64LIT(0xfab27d7de97dcf94), W64LIT(0x374995956e95dcfb), W64LIT(0xad56d8d847d88e9f), + W64LIT(0xeb70fbfbcbfb8b30), W64LIT(0xc1cdeeee9fee2371), W64LIT(0xf8bb7c7ced7cc791), W64LIT(0xcc716666856617e3), + W64LIT(0xa77bdddd53dda68e), W64LIT(0x2eaf17175c17b84b), W64LIT(0x8e45474701470246), W64LIT(0x211a9e9e429e84dc), + W64LIT(0x89d4caca0fca1ec5), W64LIT(0x5a582d2db42d7599), W64LIT(0x632ebfbfc6bf9179), W64LIT(0x0e3f07071c07381b), + W64LIT(0x47acadad8ead0123), W64LIT(0xb4b05a5a755aea2f), W64LIT(0x1bef838336836cb5), W64LIT(0x66b63333cc3385ff), + W64LIT(0xc65c636391633ff2), W64LIT(0x041202020802100a), W64LIT(0x4993aaaa92aa3938), W64LIT(0xe2de7171d971afa8), + W64LIT(0x8dc6c8c807c80ecf), W64LIT(0x32d119196419c87d), W64LIT(0x923b494939497270), W64LIT(0xaf5fd9d943d9869a), + W64LIT(0xf931f2f2eff2c31d), W64LIT(0xdba8e3e3abe34b48), W64LIT(0xb6b95b5b715be22a), W64LIT(0x0dbc88881a883492), + W64LIT(0x293e9a9a529aa4c8), W64LIT(0x4c0b262698262dbe), W64LIT(0x64bf3232c8328dfa), W64LIT(0x7d59b0b0fab0e94a), + W64LIT(0xcff2e9e983e91b6a), W64LIT(0x1e770f0f3c0f7833), W64LIT(0xb733d5d573d5e6a6), W64LIT(0x1df480803a8074ba), + W64LIT(0x6127bebec2be997c), W64LIT(0x87ebcdcd13cd26de), W64LIT(0x68893434d034bde4), W64LIT(0x903248483d487a75), + W64LIT(0xe354ffffdbffab24), W64LIT(0xf48d7a7af57af78f), W64LIT(0x3d6490907a90f4ea), W64LIT(0xbe9d5f5f615fc23e), + W64LIT(0x403d202080201da0), W64LIT(0xd00f6868bd6867d5), W64LIT(0x34ca1a1a681ad072), W64LIT(0x41b7aeae82ae192c), + W64LIT(0x757db4b4eab4c95e), W64LIT(0xa8ce54544d549a19), W64LIT(0x3b7f93937693ece5), W64LIT(0x442f222288220daa), + W64LIT(0xc86364648d6407e9), W64LIT(0xff2af1f1e3f1db12), W64LIT(0xe6cc7373d173bfa2), W64LIT(0x248212124812905a), + W64LIT(0x807a40401d403a5d), W64LIT(0x1048080820084028), W64LIT(0x9b95c3c32bc356e8), W64LIT(0xc5dfecec97ec337b), + W64LIT(0xab4ddbdb4bdb9690), W64LIT(0x5fc0a1a1bea1611f), W64LIT(0x07918d8d0e8d1c83), W64LIT(0x7ac83d3df43df5c9), + W64LIT(0x335b97976697ccf1), W64LIT(0x0000000000000000), W64LIT(0x83f9cfcf1bcf36d4), W64LIT(0x566e2b2bac2b4587), + W64LIT(0xece17676c57697b3), W64LIT(0x19e68282328264b0), W64LIT(0xb128d6d67fd6fea9), W64LIT(0x36c31b1b6c1bd877), + W64LIT(0x7774b5b5eeb5c15b), W64LIT(0x43beafaf86af1129), W64LIT(0xd41d6a6ab56a77df), W64LIT(0xa0ea50505d50ba0d), + W64LIT(0x8a5745450945124c), W64LIT(0xfb38f3f3ebf3cb18), W64LIT(0x60ad3030c0309df0), W64LIT(0xc3c4efef9bef2b74), + W64LIT(0x7eda3f3ffc3fe5c3), W64LIT(0xaac755554955921c), W64LIT(0x59dba2a2b2a27910), W64LIT(0xc9e9eaea8fea0365), + W64LIT(0xca6a656589650fec), W64LIT(0x6903babad2bab968), W64LIT(0x5e4a2f2fbc2f6593), W64LIT(0x9d8ec0c027c04ee7), + W64LIT(0xa160dede5fdebe81), W64LIT(0x38fc1c1c701ce06c), W64LIT(0xe746fdfdd3fdbb2e), W64LIT(0x9a1f4d4d294d5264), + W64LIT(0x397692927292e4e0), W64LIT(0xeafa7575c9758fbc), W64LIT(0x0c3606061806301e), W64LIT(0x09ae8a8a128a2498), + W64LIT(0x794bb2b2f2b2f940), W64LIT(0xd185e6e6bfe66359), W64LIT(0x1c7e0e0e380e7036), W64LIT(0x3ee71f1f7c1ff863), + W64LIT(0xc4556262956237f7), W64LIT(0xb53ad4d477d4eea3), W64LIT(0x4d81a8a89aa82932), W64LIT(0x315296966296c4f4), + W64LIT(0xef62f9f9c3f99b3a), W64LIT(0x97a3c5c533c566f6), W64LIT(0x4a102525942535b1), W64LIT(0xb2ab59597959f220), + W64LIT(0x15d084842a8454ae), W64LIT(0xe4c57272d572b7a7), W64LIT(0x72ec3939e439d5dd), W64LIT(0x98164c4c2d4c5a61), + W64LIT(0xbc945e5e655eca3b), W64LIT(0xf09f7878fd78e785), W64LIT(0x70e53838e038ddd8), W64LIT(0x05988c8c0a8c1486), + W64LIT(0xbf17d1d163d1c6b2), W64LIT(0x57e4a5a5aea5410b), W64LIT(0xd9a1e2e2afe2434d), W64LIT(0xc24e616199612ff8), + W64LIT(0x7b42b3b3f6b3f145), W64LIT(0x42342121842115a5), W64LIT(0x25089c9c4a9c94d6), W64LIT(0x3cee1e1e781ef066), + W64LIT(0x8661434311432252), W64LIT(0x93b1c7c73bc776fc), W64LIT(0xe54ffcfcd7fcb32b), W64LIT(0x0824040410042014), + W64LIT(0xa2e351515951b208), W64LIT(0x2f2599995e99bcc7), W64LIT(0xda226d6da96d4fc4), W64LIT(0x1a650d0d340d6839), + W64LIT(0xe979fafacffa8335), W64LIT(0xa369dfdf5bdfb684), W64LIT(0xfca97e7ee57ed79b), W64LIT(0x4819242490243db4), + W64LIT(0x76fe3b3bec3bc5d7), W64LIT(0x4b9aabab96ab313d), W64LIT(0x81f0cece1fce3ed1), W64LIT(0x2299111144118855), + W64LIT(0x03838f8f068f0c89), W64LIT(0x9c044e4e254e4a6b), W64LIT(0x7366b7b7e6b7d151), W64LIT(0xcbe0ebeb8beb0b60), + W64LIT(0x78c13c3cf03cfdcc), W64LIT(0x1ffd81813e817cbf), W64LIT(0x354094946a94d4fe), W64LIT(0xf31cf7f7fbf7eb0c), + W64LIT(0x6f18b9b9deb9a167), W64LIT(0x268b13134c13985f), W64LIT(0x58512c2cb02c7d9c), W64LIT(0xbb05d3d36bd3d6b8), + W64LIT(0xd38ce7e7bbe76b5c), W64LIT(0xdc396e6ea56e57cb), W64LIT(0x95aac4c437c46ef3), W64LIT(0x061b03030c03180f), + W64LIT(0xacdc565645568a13), W64LIT(0x885e44440d441a49), W64LIT(0xfea07f7fe17fdf9e), W64LIT(0x4f88a9a99ea92137), + W64LIT(0x54672a2aa82a4d82), W64LIT(0x6b0abbbbd6bbb16d), W64LIT(0x9f87c1c123c146e2), W64LIT(0xa6f153535153a202), + W64LIT(0xa572dcdc57dcae8b), W64LIT(0x16530b0b2c0b5827), W64LIT(0x27019d9d4e9d9cd3), W64LIT(0xd82b6c6cad6c47c1), + W64LIT(0x62a43131c43195f5), W64LIT(0xe8f37474cd7487b9), W64LIT(0xf115f6f6fff6e309), W64LIT(0x8c4c464605460a43), + W64LIT(0x45a5acac8aac0926), W64LIT(0x0fb589891e893c97), W64LIT(0x28b414145014a044), W64LIT(0xdfbae1e1a3e15b42), + W64LIT(0x2ca616165816b04e), W64LIT(0x74f73a3ae83acdd2), W64LIT(0xd2066969b9696fd0), W64LIT(0x124109092409482d), + W64LIT(0xe0d77070dd70a7ad), W64LIT(0x716fb6b6e2b6d954), W64LIT(0xbd1ed0d067d0ceb7), W64LIT(0xc7d6eded93ed3b7e), + W64LIT(0x85e2cccc17cc2edb), W64LIT(0x8468424215422a57), W64LIT(0x2d2c98985a98b4c2), W64LIT(0x55eda4a4aaa4490e), + W64LIT(0x50752828a0285d88), W64LIT(0xb8865c5c6d5cda31), W64LIT(0xed6bf8f8c7f8933f), W64LIT(0x11c28686228644a4), + + W64LIT(0x7830d818186018c0), W64LIT(0xaf462623238c2305), W64LIT(0xf991b8c6c63fc67e), W64LIT(0x6fcdfbe8e887e813), + W64LIT(0xa113cb878726874c), W64LIT(0x626d11b8b8dab8a9), W64LIT(0x0502090101040108), W64LIT(0x6e9e0d4f4f214f42), + W64LIT(0xee6c9b3636d836ad), W64LIT(0x0451ffa6a6a2a659), W64LIT(0xbdb90cd2d26fd2de), W64LIT(0x06f70ef5f5f3f5fb), + W64LIT(0x80f2967979f979ef), W64LIT(0xcede306f6fa16f5f), W64LIT(0xef3f6d91917e91fc), W64LIT(0x07a4f852525552aa), + W64LIT(0xfdc04760609d6027), W64LIT(0x766535bcbccabc89), W64LIT(0xcd2b379b9b569bac), W64LIT(0x8c018a8e8e028e04), + W64LIT(0x155bd2a3a3b6a371), W64LIT(0x3c186c0c0c300c60), W64LIT(0x8af6847b7bf17bff), W64LIT(0xe16a803535d435b5), + W64LIT(0x693af51d1d741de8), W64LIT(0x47ddb3e0e0a7e053), W64LIT(0xacb321d7d77bd7f6), W64LIT(0xed999cc2c22fc25e), + W64LIT(0x965c432e2eb82e6d), W64LIT(0x7a96294b4b314b62), W64LIT(0x21e15dfefedffea3), W64LIT(0x16aed55757415782), + W64LIT(0x412abd15155415a8), W64LIT(0xb6eee87777c1779f), W64LIT(0xeb6e923737dc37a5), W64LIT(0x56d79ee5e5b3e57b), + W64LIT(0xd923139f9f469f8c), W64LIT(0x17fd23f0f0e7f0d3), W64LIT(0x7f94204a4a354a6a), W64LIT(0x95a944dada4fda9e), + W64LIT(0x25b0a258587d58fa), W64LIT(0xca8fcfc9c903c906), W64LIT(0x8d527c2929a42955), W64LIT(0x22145a0a0a280a50), + W64LIT(0x4f7f50b1b1feb1e1), W64LIT(0x1a5dc9a0a0baa069), W64LIT(0xdad6146b6bb16b7f), W64LIT(0xab17d985852e855c), + W64LIT(0x73673cbdbdcebd81), W64LIT(0x34ba8f5d5d695dd2), W64LIT(0x5020901010401080), W64LIT(0x03f507f4f4f7f4f3), + W64LIT(0xc08bddcbcb0bcb16), W64LIT(0xc67cd33e3ef83eed), W64LIT(0x110a2d0505140528), W64LIT(0xe6ce78676781671f), + W64LIT(0x53d597e4e4b7e473), W64LIT(0xbb4e0227279c2725), W64LIT(0x5882734141194132), W64LIT(0x9d0ba78b8b168b2c), + W64LIT(0x0153f6a7a7a6a751), W64LIT(0x94fab27d7de97dcf), W64LIT(0xfb374995956e95dc), W64LIT(0x9fad56d8d847d88e), + W64LIT(0x30eb70fbfbcbfb8b), W64LIT(0x71c1cdeeee9fee23), W64LIT(0x91f8bb7c7ced7cc7), W64LIT(0xe3cc716666856617), + W64LIT(0x8ea77bdddd53dda6), W64LIT(0x4b2eaf17175c17b8), W64LIT(0x468e454747014702), W64LIT(0xdc211a9e9e429e84), + W64LIT(0xc589d4caca0fca1e), W64LIT(0x995a582d2db42d75), W64LIT(0x79632ebfbfc6bf91), W64LIT(0x1b0e3f07071c0738), + W64LIT(0x2347acadad8ead01), W64LIT(0x2fb4b05a5a755aea), W64LIT(0xb51bef838336836c), W64LIT(0xff66b63333cc3385), + W64LIT(0xf2c65c636391633f), W64LIT(0x0a04120202080210), W64LIT(0x384993aaaa92aa39), W64LIT(0xa8e2de7171d971af), + W64LIT(0xcf8dc6c8c807c80e), W64LIT(0x7d32d119196419c8), W64LIT(0x70923b4949394972), W64LIT(0x9aaf5fd9d943d986), + W64LIT(0x1df931f2f2eff2c3), W64LIT(0x48dba8e3e3abe34b), W64LIT(0x2ab6b95b5b715be2), W64LIT(0x920dbc88881a8834), + W64LIT(0xc8293e9a9a529aa4), W64LIT(0xbe4c0b262698262d), W64LIT(0xfa64bf3232c8328d), W64LIT(0x4a7d59b0b0fab0e9), + W64LIT(0x6acff2e9e983e91b), W64LIT(0x331e770f0f3c0f78), W64LIT(0xa6b733d5d573d5e6), W64LIT(0xba1df480803a8074), + W64LIT(0x7c6127bebec2be99), W64LIT(0xde87ebcdcd13cd26), W64LIT(0xe468893434d034bd), W64LIT(0x75903248483d487a), + W64LIT(0x24e354ffffdbffab), W64LIT(0x8ff48d7a7af57af7), W64LIT(0xea3d6490907a90f4), W64LIT(0x3ebe9d5f5f615fc2), + W64LIT(0xa0403d202080201d), W64LIT(0xd5d00f6868bd6867), W64LIT(0x7234ca1a1a681ad0), W64LIT(0x2c41b7aeae82ae19), + W64LIT(0x5e757db4b4eab4c9), W64LIT(0x19a8ce54544d549a), W64LIT(0xe53b7f93937693ec), W64LIT(0xaa442f222288220d), + W64LIT(0xe9c86364648d6407), W64LIT(0x12ff2af1f1e3f1db), W64LIT(0xa2e6cc7373d173bf), W64LIT(0x5a24821212481290), + W64LIT(0x5d807a40401d403a), W64LIT(0x2810480808200840), W64LIT(0xe89b95c3c32bc356), W64LIT(0x7bc5dfecec97ec33), + W64LIT(0x90ab4ddbdb4bdb96), W64LIT(0x1f5fc0a1a1bea161), W64LIT(0x8307918d8d0e8d1c), W64LIT(0xc97ac83d3df43df5), + W64LIT(0xf1335b97976697cc), W64LIT(0x0000000000000000), W64LIT(0xd483f9cfcf1bcf36), W64LIT(0x87566e2b2bac2b45), + W64LIT(0xb3ece17676c57697), W64LIT(0xb019e68282328264), W64LIT(0xa9b128d6d67fd6fe), W64LIT(0x7736c31b1b6c1bd8), + W64LIT(0x5b7774b5b5eeb5c1), W64LIT(0x2943beafaf86af11), W64LIT(0xdfd41d6a6ab56a77), W64LIT(0x0da0ea50505d50ba), + W64LIT(0x4c8a574545094512), W64LIT(0x18fb38f3f3ebf3cb), W64LIT(0xf060ad3030c0309d), W64LIT(0x74c3c4efef9bef2b), + W64LIT(0xc37eda3f3ffc3fe5), W64LIT(0x1caac75555495592), W64LIT(0x1059dba2a2b2a279), W64LIT(0x65c9e9eaea8fea03), + W64LIT(0xecca6a656589650f), W64LIT(0x686903babad2bab9), W64LIT(0x935e4a2f2fbc2f65), W64LIT(0xe79d8ec0c027c04e), + W64LIT(0x81a160dede5fdebe), W64LIT(0x6c38fc1c1c701ce0), W64LIT(0x2ee746fdfdd3fdbb), W64LIT(0x649a1f4d4d294d52), + W64LIT(0xe0397692927292e4), W64LIT(0xbceafa7575c9758f), W64LIT(0x1e0c360606180630), W64LIT(0x9809ae8a8a128a24), + W64LIT(0x40794bb2b2f2b2f9), W64LIT(0x59d185e6e6bfe663), W64LIT(0x361c7e0e0e380e70), W64LIT(0x633ee71f1f7c1ff8), + W64LIT(0xf7c4556262956237), W64LIT(0xa3b53ad4d477d4ee), W64LIT(0x324d81a8a89aa829), W64LIT(0xf4315296966296c4), + W64LIT(0x3aef62f9f9c3f99b), W64LIT(0xf697a3c5c533c566), W64LIT(0xb14a102525942535), W64LIT(0x20b2ab59597959f2), + W64LIT(0xae15d084842a8454), W64LIT(0xa7e4c57272d572b7), W64LIT(0xdd72ec3939e439d5), W64LIT(0x6198164c4c2d4c5a), + W64LIT(0x3bbc945e5e655eca), W64LIT(0x85f09f7878fd78e7), W64LIT(0xd870e53838e038dd), W64LIT(0x8605988c8c0a8c14), + W64LIT(0xb2bf17d1d163d1c6), W64LIT(0x0b57e4a5a5aea541), W64LIT(0x4dd9a1e2e2afe243), W64LIT(0xf8c24e616199612f), + W64LIT(0x457b42b3b3f6b3f1), W64LIT(0xa542342121842115), W64LIT(0xd625089c9c4a9c94), W64LIT(0x663cee1e1e781ef0), + W64LIT(0x5286614343114322), W64LIT(0xfc93b1c7c73bc776), W64LIT(0x2be54ffcfcd7fcb3), W64LIT(0x1408240404100420), + W64LIT(0x08a2e351515951b2), W64LIT(0xc72f2599995e99bc), W64LIT(0xc4da226d6da96d4f), W64LIT(0x391a650d0d340d68), + W64LIT(0x35e979fafacffa83), W64LIT(0x84a369dfdf5bdfb6), W64LIT(0x9bfca97e7ee57ed7), W64LIT(0xb44819242490243d), + W64LIT(0xd776fe3b3bec3bc5), W64LIT(0x3d4b9aabab96ab31), W64LIT(0xd181f0cece1fce3e), W64LIT(0x5522991111441188), + W64LIT(0x8903838f8f068f0c), W64LIT(0x6b9c044e4e254e4a), W64LIT(0x517366b7b7e6b7d1), W64LIT(0x60cbe0ebeb8beb0b), + W64LIT(0xcc78c13c3cf03cfd), W64LIT(0xbf1ffd81813e817c), W64LIT(0xfe354094946a94d4), W64LIT(0x0cf31cf7f7fbf7eb), + W64LIT(0x676f18b9b9deb9a1), W64LIT(0x5f268b13134c1398), W64LIT(0x9c58512c2cb02c7d), W64LIT(0xb8bb05d3d36bd3d6), + W64LIT(0x5cd38ce7e7bbe76b), W64LIT(0xcbdc396e6ea56e57), W64LIT(0xf395aac4c437c46e), W64LIT(0x0f061b03030c0318), + W64LIT(0x13acdc565645568a), W64LIT(0x49885e44440d441a), W64LIT(0x9efea07f7fe17fdf), W64LIT(0x374f88a9a99ea921), + W64LIT(0x8254672a2aa82a4d), W64LIT(0x6d6b0abbbbd6bbb1), W64LIT(0xe29f87c1c123c146), W64LIT(0x02a6f153535153a2), + W64LIT(0x8ba572dcdc57dcae), W64LIT(0x2716530b0b2c0b58), W64LIT(0xd327019d9d4e9d9c), W64LIT(0xc1d82b6c6cad6c47), + W64LIT(0xf562a43131c43195), W64LIT(0xb9e8f37474cd7487), W64LIT(0x09f115f6f6fff6e3), W64LIT(0x438c4c464605460a), + W64LIT(0x2645a5acac8aac09), W64LIT(0x970fb589891e893c), W64LIT(0x4428b414145014a0), W64LIT(0x42dfbae1e1a3e15b), + W64LIT(0x4e2ca616165816b0), W64LIT(0xd274f73a3ae83acd), W64LIT(0xd0d2066969b9696f), W64LIT(0x2d12410909240948), + W64LIT(0xade0d77070dd70a7), W64LIT(0x54716fb6b6e2b6d9), W64LIT(0xb7bd1ed0d067d0ce), W64LIT(0x7ec7d6eded93ed3b), + W64LIT(0xdb85e2cccc17cc2e), W64LIT(0x578468424215422a), W64LIT(0xc22d2c98985a98b4), W64LIT(0x0e55eda4a4aaa449), + W64LIT(0x8850752828a0285d), W64LIT(0x31b8865c5c6d5cda), W64LIT(0x3fed6bf8f8c7f893), W64LIT(0xa411c28686228644), + + W64LIT(0x1823c6e887b8014f), + W64LIT(0x36a6d2f5796f9152), + W64LIT(0x60bc9b8ea30c7b35), + W64LIT(0x1de0d7c22e4bfe57), + W64LIT(0x157737e59ff04ada), + W64LIT(0x58c9290ab1a06b85), + W64LIT(0xbd5d10f4cb3e0567), + W64LIT(0xe427418ba77d95d8), + W64LIT(0xfbee7c66dd17479e), + W64LIT(0xca2dbf07ad5a8333) +}; + +// Whirlpool basic transformation. Transforms state based on block. +void Whirlpool::Transform(word64 *digest, const word64 *block) +{ + CRYPTOPP_ASSERT(digest != NULLPTR); + CRYPTOPP_ASSERT(block != NULLPTR); + +#if CRYPTOPP_SSE2_ASM_AVAILABLE + if (HasSSE2()) + { + // MMX version has the same structure as C version below +#ifdef __GNUC__ + #if CRYPTOPP_BOOL_X64 + word64 workspace[16]; + #endif + __asm__ __volatile__ + ( + INTEL_NOPREFIX + AS_PUSH_IF86( bx) + AS2( mov AS_REG_6, WORD_REG(ax)) +#else + AS2( lea AS_REG_6, [Whirlpool_C]) + AS2( mov WORD_REG(cx), digest) + AS2( mov WORD_REG(dx), block) +#endif +#if CRYPTOPP_BOOL_X86 + AS2( mov eax, esp) + AS2( and esp, -16) + AS2( sub esp, 16*8) + AS_PUSH_IF86( ax) + #if CRYPTOPP_BOOL_X86 + #define SSE2_workspace esp+WORD_SZ + #endif +#else + #define SSE2_workspace %3 +#endif + AS2( xor esi, esi) + ASL(0) + AS2( movq mm0, [WORD_REG(cx)+8*WORD_REG(si)]) + AS2( movq [SSE2_workspace+8*WORD_REG(si)], mm0) // k + AS2( pxor mm0, [WORD_REG(dx)+8*WORD_REG(si)]) + AS2( movq [SSE2_workspace+64+8*WORD_REG(si)], mm0) // s + AS2( movq [WORD_REG(cx)+8*WORD_REG(si)], mm0) + AS1( inc WORD_REG(si)) + AS2( cmp WORD_REG(si), 8) + ASJ( jne, 0, b) + + AS2( xor esi, esi) + ASL(1) + +#define KSL0(a, b) AS2(movq mm##a, b) +#define KSL1(a, b) AS2(pxor mm##a, b) + +#define KSL(op, i, a, b, c, d) \ + AS2(mov eax, [SSE2_workspace+8*i])\ + AS2(movzx edi, al)\ + KSL##op(a, [AS_REG_6+3*2048+8*WORD_REG(di)])\ + AS2(movzx edi, ah)\ + KSL##op(b, [AS_REG_6+2*2048+8*WORD_REG(di)])\ + AS2(shr eax, 16)\ + AS2(movzx edi, al)\ + AS2(shr eax, 8)\ + KSL##op(c, [AS_REG_6+1*2048+8*WORD_REG(di)])\ + KSL##op(d, [AS_REG_6+0*2048+8*WORD_REG(ax)]) + +#define KSH0(a, b) \ + ASS(pshufw mm##a, mm##a, 1, 0, 3, 2)\ + AS2(pxor mm##a, b) +#define KSH1(a, b) \ + AS2(pxor mm##a, b) +#define KSH2(a, b) \ + AS2(pxor mm##a, b)\ + AS2(movq [SSE2_workspace+8*a], mm##a) + +#define KSH(op, i, a, b, c, d) \ + AS2(mov eax, [SSE2_workspace+8*((i+4)-8*((i+4)/8))+4])\ + AS2(movzx edi, al)\ + KSH##op(a, [AS_REG_6+3*2048+8*WORD_REG(di)])\ + AS2(movzx edi, ah)\ + KSH##op(b, [AS_REG_6+2*2048+8*WORD_REG(di)])\ + AS2(shr eax, 16)\ + AS2(movzx edi, al)\ + AS2(shr eax, 8)\ + KSH##op(c, [AS_REG_6+1*2048+8*WORD_REG(di)])\ + KSH##op(d, [AS_REG_6+0*2048+8*WORD_REG(ax)]) + +#define TSL(op, i, a, b, c, d) \ + AS2(mov eax, [SSE2_workspace+64+8*i])\ + AS2(movzx edi, al)\ + KSL##op(a, [AS_REG_6+3*2048+8*WORD_REG(di)])\ + AS2(movzx edi, ah)\ + KSL##op(b, [AS_REG_6+2*2048+8*WORD_REG(di)])\ + AS2(shr eax, 16)\ + AS2(movzx edi, al)\ + AS2(shr eax, 8)\ + KSL##op(c, [AS_REG_6+1*2048+8*WORD_REG(di)])\ + KSL##op(d, [AS_REG_6+0*2048+8*WORD_REG(ax)]) + +#define TSH0(a, b) \ + ASS(pshufw mm##a, mm##a, 1, 0, 3, 2)\ + AS2(pxor mm##a, [SSE2_workspace+8*a])\ + AS2(pxor mm##a, b) +#define TSH1(a, b) \ + AS2(pxor mm##a, b) +#define TSH2(a, b) \ + AS2(pxor mm##a, b)\ + AS2(movq [SSE2_workspace+64+8*a], mm##a) +#define TSH3(a, b) \ + AS2(pxor mm##a, b)\ + AS2(pxor mm##a, [WORD_REG(cx)+8*a])\ + AS2(movq [WORD_REG(cx)+8*a], mm##a) + +#define TSH(op, i, a, b, c, d) \ + AS2(mov eax, [SSE2_workspace+64+8*((i+4)-8*((i+4)/8))+4])\ + AS2(movzx edi, al)\ + TSH##op(a, [AS_REG_6+3*2048+8*WORD_REG(di)])\ + AS2(movzx edi, ah)\ + TSH##op(b, [AS_REG_6+2*2048+8*WORD_REG(di)])\ + AS2(shr eax, 16)\ + AS2(movzx edi, al)\ + AS2(shr eax, 8)\ + TSH##op(c, [AS_REG_6+1*2048+8*WORD_REG(di)])\ + TSH##op(d, [AS_REG_6+0*2048+8*WORD_REG(ax)]) + + KSL(0, 4, 3, 2, 1, 0) + KSL(0, 0, 7, 6, 5, 4) + KSL(1, 1, 0, 7, 6, 5) + KSL(1, 2, 1, 0, 7, 6) + KSL(1, 3, 2, 1, 0, 7) + KSL(1, 5, 4, 3, 2, 1) + KSL(1, 6, 5, 4, 3, 2) + KSL(1, 7, 6, 5, 4, 3) + KSH(0, 0, 7, 6, 5, 4) + KSH(0, 4, 3, 2, 1, 0) + KSH(1, 1, 0, 7, 6, 5) + KSH(1, 2, 1, 0, 7, 6) + KSH(1, 5, 4, 3, 2, 1) + KSH(1, 6, 5, 4, 3, 2) + KSH(2, 3, 2, 1, 0, 7) + KSH(2, 7, 6, 5, 4, 3) + + AS2( pxor mm0, [AS_REG_6 + 8*1024 + WORD_REG(si)*8]) + AS2( movq [SSE2_workspace], mm0) + + TSL(0, 4, 3, 2, 1, 0) + TSL(0, 0, 7, 6, 5, 4) + TSL(1, 1, 0, 7, 6, 5) + TSL(1, 2, 1, 0, 7, 6) + TSL(1, 3, 2, 1, 0, 7) + TSL(1, 5, 4, 3, 2, 1) + TSL(1, 6, 5, 4, 3, 2) + TSL(1, 7, 6, 5, 4, 3) + TSH(0, 0, 7, 6, 5, 4) + TSH(0, 4, 3, 2, 1, 0) + TSH(1, 1, 0, 7, 6, 5) + TSH(1, 2, 1, 0, 7, 6) + TSH(1, 5, 4, 3, 2, 1) + TSH(1, 6, 5, 4, 3, 2) + + AS1( inc WORD_REG(si)) + AS2( cmp WORD_REG(si), 10) + ASJ( je, 2, f) + + TSH(2, 3, 2, 1, 0, 7) + TSH(2, 7, 6, 5, 4, 3) + + ASJ( jmp, 1, b) + ASL(2) + + TSH(3, 3, 2, 1, 0, 7) + TSH(3, 7, 6, 5, 4, 3) + +#undef KSL +#undef KSH +#undef TSL +#undef TSH + + AS_POP_IF86( sp) + AS1( emms) + +#if defined(__GNUC__) + AS_POP_IF86( bx) +#endif +#ifdef __GNUC__ + ATT_PREFIX + : + : "a" (Whirlpool_C), "c" (digest), "d" (block) + #if CRYPTOPP_BOOL_X64 + , "r" (workspace) + #endif + : "%esi", "%edi", "memory", "cc" + #if CRYPTOPP_BOOL_X64 + , "%r9" + #endif + ); +#endif + } + else +#endif // #ifdef CRYPTOPP_X86_ASM_AVAILABLE + { + word64 s[8]; // the cipher state + word64 k[8]; // the round key + + // Compute and apply K^0 to the cipher state + // Also apply part of the Miyaguchi-Preneel compression function + for (int i=0; i<8; i++) + digest[i] = s[i] = block[i] ^ (k[i] = digest[i]); + +#define KSL(op, i, a, b, c, d) \ + t = (word32)k[i];\ + w##a = Whirlpool_C[3*256 + (byte)t] ^ (op ? w##a : 0);\ + t >>= 8;\ + w##b = Whirlpool_C[2*256 + (byte)t] ^ (op ? w##b : 0);\ + t >>= 8;\ + w##c = Whirlpool_C[1*256 + (byte)t] ^ (op ? w##c : 0);\ + t >>= 8;\ + w##d = Whirlpool_C[0*256 + t] ^ (op ? w##d : 0); + +#define KSH(op, i, a, b, c, d) \ + t = (word32)(k[(i+4)%8]>>32);\ + w##a = Whirlpool_C[3*256 + (byte)t] ^ (op ? w##a : rotrConstant<32>(w##a));\ + if (op==2) k[a] = w##a;\ + t >>= 8;\ + w##b = Whirlpool_C[2*256 + (byte)t] ^ (op ? w##b : rotrConstant<32>(w##b));\ + if (op==2) k[b] = w##b;\ + t >>= 8;\ + w##c = Whirlpool_C[1*256 + (byte)t] ^ (op ? w##c : rotrConstant<32>(w##c));\ + if (op==2) k[c] = w##c;\ + t >>= 8;\ + w##d = Whirlpool_C[0*256 + t] ^ (op ? w##d : rotrConstant<32>(w##d));\ + if (op==2) k[d] = w##d;\ + +#define TSL(op, i, a, b, c, d) \ + t = (word32)s[i];\ + w##a = Whirlpool_C[3*256 + (byte)t] ^ (op ? w##a : 0);\ + t >>= 8;\ + w##b = Whirlpool_C[2*256 + (byte)t] ^ (op ? w##b : 0);\ + t >>= 8;\ + w##c = Whirlpool_C[1*256 + (byte)t] ^ (op ? w##c : 0);\ + t >>= 8;\ + w##d = Whirlpool_C[0*256 + t] ^ (op ? w##d : 0); + +#define TSH_OP(op, a, b) \ + w##a = Whirlpool_C[b*256 + (byte)t] ^ (op ? w##a : rotrConstant<32>(w##a) ^ k[a]);\ + if (op==2) s[a] = w##a;\ + if (op==3) digest[a] ^= w##a;\ + +#define TSH(op, i, a, b, c, d) \ + t = (word32)(s[(i+4)%8]>>32);\ + TSH_OP(op, a, 3);\ + t >>= 8;\ + TSH_OP(op, b, 2);\ + t >>= 8;\ + TSH_OP(op, c, 1);\ + t >>= 8;\ + TSH_OP(op, d, 0);\ + + // Iterate over all rounds: + int r=0; + while (true) + { + // Added initialization due to Coverity findings. + word64 w0=0, w1=0, w2=0, w3=0, w4=0, w5=0, w6=0, w7=0; + word32 t=0; + + KSL(0, 4, 3, 2, 1, 0) + KSL(0, 0, 7, 6, 5, 4) + KSL(1, 1, 0, 7, 6, 5) + KSL(1, 2, 1, 0, 7, 6) + KSL(1, 3, 2, 1, 0, 7) + KSL(1, 5, 4, 3, 2, 1) + KSL(1, 6, 5, 4, 3, 2) + KSL(1, 7, 6, 5, 4, 3) + KSH(0, 0, 7, 6, 5, 4) + KSH(0, 4, 3, 2, 1, 0) + KSH(1, 1, 0, 7, 6, 5) + KSH(1, 2, 1, 0, 7, 6) + KSH(1, 5, 4, 3, 2, 1) + KSH(1, 6, 5, 4, 3, 2) + KSH(2, 3, 2, 1, 0, 7) + KSH(2, 7, 6, 5, 4, 3) + + k[0] ^= Whirlpool_C[1024+r]; + + TSL(0, 4, 3, 2, 1, 0) + TSL(0, 0, 7, 6, 5, 4) + TSL(1, 1, 0, 7, 6, 5) + TSL(1, 2, 1, 0, 7, 6) + TSL(1, 3, 2, 1, 0, 7) + TSL(1, 5, 4, 3, 2, 1) + TSL(1, 6, 5, 4, 3, 2) + TSL(1, 7, 6, 5, 4, 3) + TSH(0, 0, 7, 6, 5, 4) + TSH(0, 4, 3, 2, 1, 0) + TSH(1, 1, 0, 7, 6, 5) + TSH(1, 2, 1, 0, 7, 6) + TSH(1, 5, 4, 3, 2, 1) + TSH(1, 6, 5, 4, 3, 2) + + if (++r < R) + { + TSH(2, 3, 2, 1, 0, 7) + TSH(2, 7, 6, 5, 4, 3) + } + else + { + TSH(3, 3, 2, 1, 0, 7) + TSH(3, 7, 6, 5, 4, 3) + break; + } + } + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/whrlpool.h b/extension/third_party/cryptopp/whrlpool.h new file mode 100644 index 00000000..33e4b302 --- /dev/null +++ b/extension/third_party/cryptopp/whrlpool.h @@ -0,0 +1,42 @@ +// whrlpool.h - originally modified by Kevin Springle from Paulo Barreto and Vincent Rijmen's +// public domain code, whirlpool.c. Updated to Whirlpool version 3.0, optimized +// and SSE version added by WD. All modifications are placed in the public domain. + +#ifndef CRYPTOPP_WHIRLPOOL_H +#define CRYPTOPP_WHIRLPOOL_H + +/// \file whrlpool.h +/// \brief Classes for the Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_WHIRLPOOL_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. +/// \since Crypto++ 5.2 +/// \sa Whirlpool +class Whirlpool : public IteratedHashWithStaticTransform +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Whirlpool";} + std::string AlgorithmProvider() const; + + static void InitState(HashWordType *state); + static void Transform(word64 *digest, const word64 *data); + void TruncatedFinal(byte *hash, size_t size); +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/words.h b/extension/third_party/cryptopp/words.h new file mode 100644 index 00000000..86698a3f --- /dev/null +++ b/extension/third_party/cryptopp/words.h @@ -0,0 +1,225 @@ +// words.h - originally written and placed in the public domain by Wei Dai + +/// \file words.h +/// \brief Support functions for word operations + +#ifndef CRYPTOPP_WORDS_H +#define CRYPTOPP_WORDS_H + +#include "config.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Count the number of words +/// \param x word array +/// \param n size of the word array, in elements +/// \return number of words used in the array. +/// \details CountWords counts the number of words in a word array. +/// Leading 0-words are not included in the count. +/// \since Crypto++ 1.0 +inline size_t CountWords(const word *x, size_t n) +{ + while (n && x[n-1]==0) + n--; + return n; +} + +/// \brief Set the value of words +/// \param r word array +/// \param a value +/// \param n size of the word array, in elements +/// \details SetWords sets all elements in the word array to the +/// specified value. +/// \since Crypto++ 1.0 +inline void SetWords(word *r, word a, size_t n) +{ + for (size_t i=0; i> (WORD_BITS-shiftBits); + } + return carry; +} + +/// \brief Right shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftBits number of bits to shift +/// \return word shifted out +/// \details ShiftWordsRightByBits shifts the word array shight by +/// shiftBits. ShiftWordsRightByBits shifts bits out on the right. +/// \note shiftBits must be less than WORD_BITS. +/// \since Crypto++ 1.0 +inline word ShiftWordsRightByBits(word *r, size_t n, unsigned int shiftBits) +{ + CRYPTOPP_ASSERT (shiftBits0; i--) + { + u = r[i-1]; + r[i-1] = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + } + return carry; +} + +/// \brief Left shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftWords number of words to shift +/// \details ShiftWordsLeftByWords shifts the word array left by +/// shiftWords. ShiftWordsLeftByWords shifts bits out on the left; +/// it does not extend the array. +/// \since Crypto++ 1.0 +inline void ShiftWordsLeftByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=n-1; i>=shiftWords; i--) + r[i] = r[i-shiftWords]; + SetWords(r, 0, shiftWords); + } +} + +/// \brief Right shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftWords number of words to shift +/// \details ShiftWordsRightByWords shifts the word array right by +/// shiftWords. ShiftWordsRightByWords shifts bits out on the right. +/// \since Crypto++ 1.0 +inline void ShiftWordsRightByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=0; i+shiftWords> 8) & 1); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +// ******************** x25519 Agreement ************************* // + +x25519::x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) +{ + std::memcpy(m_pk, y, SECRET_KEYLENGTH); + std::memcpy(m_sk, x, PUBLIC_KEYLENGTH); + + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +x25519::x25519(const byte x[SECRET_KEYLENGTH]) +{ + std::memcpy(m_sk, x, SECRET_KEYLENGTH); + Donna::curve25519_mult(m_pk, m_sk); + + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +x25519::x25519(const Integer &y, const Integer &x) +{ + CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH); + CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH); + + y.Encode(m_pk, PUBLIC_KEYLENGTH); std::reverse(m_pk+0, m_pk+PUBLIC_KEYLENGTH); + x.Encode(m_sk, SECRET_KEYLENGTH); std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH); + + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +x25519::x25519(const Integer &x) +{ + CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH); + + x.Encode(m_sk, SECRET_KEYLENGTH); + std::reverse(m_sk+0, m_sk+SECRET_KEYLENGTH); + Donna::curve25519_mult(m_pk, m_sk); + + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +x25519::x25519(RandomNumberGenerator &rng) +{ + rng.GenerateBlock(m_sk, SECRET_KEYLENGTH); + ClampKey(m_sk); + SecretToPublicKey(m_pk, m_sk); +} + +x25519::x25519(BufferedTransformation ¶ms) +{ + Load(params); +} + +void x25519::ClampKey(byte x[SECRET_KEYLENGTH]) const +{ + x[0] &= 248; x[31] &= 127; x[31] |= 64; +} + +bool x25519::IsClamped(const byte x[SECRET_KEYLENGTH]) const +{ + return (x[0] & 248) == x[0] && (x[31] & 127) == x[31] && (x[31] | 64) == x[31]; +} + +bool x25519::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const +{ + return HasSmallOrder(y); +} + +void x25519::SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const +{ + Donna::curve25519_mult(y, x); +} + +void x25519::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt) +{ + // We have not yet determined the OID to use for this object. + // We can't use OID's decoder because it throws BERDecodeError + // if the OIDs do not match. + OID oid(bt); + + if (!m_oid.Empty() && m_oid != oid) + BERDecodeError(); // Only accept user specified OID + else if (oid == ASN1::curve25519() || oid == ASN1::X25519()) + m_oid = oid; // Accept any of the x25519 OIDs + else + BERDecodeError(); +} + +void x25519::BERDecode(BufferedTransformation &bt) +{ + // https://tools.ietf.org/html/rfc8410, section 7 and + // https://www.cryptopp.com/wiki/curve25519_keys + BERSequenceDecoder privateKeyInfo(bt); + word32 version; + BERDecodeUnsigned(privateKeyInfo, version, INTEGER, 0, 1); // check version + + BERSequenceDecoder algorithm(privateKeyInfo); + // GetAlgorithmID().BERDecodeAndCheck(algorithm); + BERDecodeAndCheckAlgorithmID(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING); + BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength()); + octetString.MessageEnd(); + + // publicKey [1] IMPLICIT PublicKey OPTIONAL + bool generatePublicKey = true; + if (privateKeyInfo.EndReached() == false /*version == 1?*/) + { + // Should we test this before decoding? In either case we + // just throw a BERDecodeErr() when we can't parse it. + BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERDecodeBitString(publicKey, subjectPublicKey, unusedBits); + CRYPTOPP_ASSERT(unusedBits == 0); + CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH); + if (subjectPublicKey.size() != PUBLIC_KEYLENGTH) + BERDecodeError(); + std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH); + generatePublicKey = false; + publicKey.MessageEnd(); + } + + privateKeyInfo.MessageEnd(); + + if (generatePublicKey) + Donna::curve25519_mult(m_pk, m_sk); + + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +void x25519::DEREncode(BufferedTransformation &bt, int version) const +{ + // https://tools.ietf.org/html/rfc8410, section 7 and + // https://www.cryptopp.com/wiki/curve25519_keys + CRYPTOPP_ASSERT(version == 0 || version == 1); + + DERSequenceEncoder privateKeyInfo(bt); + DEREncodeUnsigned(privateKeyInfo, version); + + DERSequenceEncoder algorithm(privateKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING); + DEREncodePrivateKey(octetString); + octetString.MessageEnd(); + + if (version == 1) + { + DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH); + publicKey.MessageEnd(); + } + + privateKeyInfo.MessageEnd(); +} + +void x25519::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/) +{ + // https://tools.ietf.org/html/rfc8410 and + // https://www.cryptopp.com/wiki/curve25519_keys + + BERGeneralDecoder privateKey(bt, OCTET_STRING); + + if (!privateKey.IsDefiniteLength()) + BERDecodeError(); + + size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH); + if (size != SECRET_KEYLENGTH) + BERDecodeError(); + + // We don't know how to decode them + if (parametersPresent) + BERDecodeError(); + + privateKey.MessageEnd(); +} + +void x25519::DEREncodePrivateKey(BufferedTransformation &bt) const +{ + // https://tools.ietf.org/html/rfc8410 + DERGeneralEncoder privateKey(bt, OCTET_STRING); + privateKey.Put(m_sk, SECRET_KEYLENGTH); + privateKey.MessageEnd(); +} + +bool x25519::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng); + CRYPTOPP_ASSERT(IsClamped(m_sk) == true); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); + + if (level >= 1 && IsClamped(m_sk) == false) + return false; + if (level >= 2 && IsSmallOrder(m_pk) == true) + return false; + if (level >= 3) + { + // Verify m_pk is pairwise consistent with m_sk + SecByteBlock pk(PUBLIC_KEYLENGTH); + SecretToPublicKey(pk, m_sk); + + if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false) + return false; + } + + return true; +} + +bool x25519::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0) + { + this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType); + reinterpret_cast(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false); + return true; + } + + if (std::strcmp(name, Name::PublicElement()) == 0) + { + this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType); + reinterpret_cast(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false); + return true; + } + + if (std::strcmp(name, Name::GroupOID()) == 0) + { + if (m_oid.Empty()) + return false; + + this->ThrowIfTypeMismatch(name, typeid(OID), valueType); + *reinterpret_cast(pValue) = m_oid; + return true; + } + + return false; +} + +void x25519::AssignFrom(const NameValuePairs &source) +{ + ConstByteArrayParameter val; + if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val)) + { + std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH); + } + + if (source.GetValue(Name::PublicElement(), val)) + { + std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH); + } + + OID oid; + if (source.GetValue(Name::GroupOID(), oid)) + { + m_oid = oid; + } + + bool derive = false; + if (source.GetValue("DerivePublicKey", derive) && derive == true) + SecretToPublicKey(m_pk, m_sk); +} + +void x25519::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) +{ + ConstByteArrayParameter seed; + if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy()) + rng.IncorporateEntropy(seed.begin(), seed.size()); + + rng.GenerateBlock(m_sk, SECRET_KEYLENGTH); + ClampKey(m_sk); + SecretToPublicKey(m_pk, m_sk); +} + +void x25519::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const +{ + rng.GenerateBlock(privateKey, SECRET_KEYLENGTH); + ClampKey(privateKey); +} + +void x25519::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const +{ + CRYPTOPP_UNUSED(rng); + SecretToPublicKey(publicKey, privateKey); +} + +bool x25519::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const +{ + CRYPTOPP_ASSERT(agreedValue != NULLPTR); + CRYPTOPP_ASSERT(otherPublicKey != NULLPTR); + + if (validateOtherPublicKey && IsSmallOrder(otherPublicKey)) + return false; + + return Donna::curve25519_mult(agreedValue, privateKey, otherPublicKey) == 0; +} + +// ******************** ed25519 Signer ************************* // + +void ed25519PrivateKey::SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const +{ + int ret = Donna::ed25519_publickey(y, x); + CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret); +} + +bool ed25519PrivateKey::IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const +{ + return HasSmallOrder(y); +} + +bool ed25519PrivateKey::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng); + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); + + if (level >= 1 && IsSmallOrder(m_pk) == true) + return false; + if (level >= 3) + { + // Verify m_pk is pairwise consistent with m_sk + SecByteBlock pk(PUBLIC_KEYLENGTH); + SecretToPublicKey(pk, m_sk); + + if (VerifyBufsEqual(pk, m_pk, PUBLIC_KEYLENGTH) == false) + return false; + } + + return true; +} + +bool ed25519PrivateKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (std::strcmp(name, Name::PrivateExponent()) == 0 || std::strcmp(name, "SecretKey") == 0) + { + this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType); + reinterpret_cast(pValue)->Assign(m_sk, SECRET_KEYLENGTH, false); + return true; + } + + if (std::strcmp(name, Name::PublicElement()) == 0) + { + this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType); + reinterpret_cast(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false); + return true; + } + + if (std::strcmp(name, Name::GroupOID()) == 0) + { + if (m_oid.Empty()) + return false; + + this->ThrowIfTypeMismatch(name, typeid(OID), valueType); + *reinterpret_cast(pValue) = m_oid; + return true; + } + + return false; +} + +void ed25519PrivateKey::AssignFrom(const NameValuePairs &source) +{ + ConstByteArrayParameter val; + if (source.GetValue(Name::PrivateExponent(), val) || source.GetValue("SecretKey", val)) + { + CRYPTOPP_ASSERT(val.size() == SECRET_KEYLENGTH); + std::memcpy(m_sk, val.begin(), SECRET_KEYLENGTH); + } + if (source.GetValue(Name::PublicElement(), val)) + { + CRYPTOPP_ASSERT(val.size() == PUBLIC_KEYLENGTH); + std::memcpy(m_pk, val.begin(), PUBLIC_KEYLENGTH); + } + + OID oid; + if (source.GetValue(Name::GroupOID(), oid)) + { + m_oid = oid; + } + + bool derive = false; + if (source.GetValue("DerivePublicKey", derive) && derive == true) + SecretToPublicKey(m_pk, m_sk); + + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +void ed25519PrivateKey::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms=g_nullNameValuePairs) +{ + ConstByteArrayParameter seed; + if (params.GetValue(Name::Seed(), seed) && rng.CanIncorporateEntropy()) + rng.IncorporateEntropy(seed.begin(), seed.size()); + + rng.GenerateBlock(m_sk, SECRET_KEYLENGTH); + int ret = Donna::ed25519_publickey(m_pk, m_sk); + CRYPTOPP_ASSERT(ret == 0); CRYPTOPP_UNUSED(ret); +} + +void ed25519PrivateKey::MakePublicKey (PublicKey &pub) const +{ + pub.AssignFrom(MakeParameters + (Name::PublicElement(), ConstByteArrayParameter(m_pk.begin(), PUBLIC_KEYLENGTH)) + (Name::GroupOID(), GetAlgorithmID())); +} + +void ed25519PrivateKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation &bt) +{ + // We have not yet determined the OID to use for this object. + // We can't use OID's decoder because it throws BERDecodeError + // if the OIDs do not match. + OID oid(bt); + + if (!m_oid.Empty() && m_oid != oid) + BERDecodeError(); // Only accept user specified OID + else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519()) + m_oid = oid; // Accept any of the ed25519PrivateKey OIDs + else + BERDecodeError(); +} + +void ed25519PrivateKey::BERDecode(BufferedTransformation &bt) +{ + // https://tools.ietf.org/html/rfc8410, section 7 and + // https://www.cryptopp.com/wiki/curve25519_keys + BERSequenceDecoder privateKeyInfo(bt); + word32 version; + BERDecodeUnsigned(privateKeyInfo, version, INTEGER, 0, 1); // check version + + BERSequenceDecoder algorithm(privateKeyInfo); + // GetAlgorithmID().BERDecodeAndCheck(algorithm); + BERDecodeAndCheckAlgorithmID(algorithm); + algorithm.MessageEnd(); + + BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING); + BERDecodePrivateKey(octetString, false, (size_t)privateKeyInfo.RemainingLength()); + octetString.MessageEnd(); + + // publicKey [1] IMPLICIT PublicKey OPTIONAL + bool generatePublicKey = true; + if (privateKeyInfo.EndReached() == false /*version == 1?*/) + { + // Should we test this before decoding? In either case we + // just throw a BERDecodeErr() when we can't parse it. + BERGeneralDecoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERDecodeBitString(publicKey, subjectPublicKey, unusedBits); + CRYPTOPP_ASSERT(unusedBits == 0); + CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH); + if (subjectPublicKey.size() != PUBLIC_KEYLENGTH) + BERDecodeError(); + std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH); + generatePublicKey = false; + publicKey.MessageEnd(); + } + + privateKeyInfo.MessageEnd(); + + if (generatePublicKey) + Donna::ed25519_publickey(m_pk, m_sk); + + CRYPTOPP_ASSERT(IsSmallOrder(m_pk) == false); +} + +void ed25519PrivateKey::DEREncode(BufferedTransformation &bt, int version) const +{ + // https://tools.ietf.org/html/rfc8410, section 7 and + // https://www.cryptopp.com/wiki/curve25519_keys + CRYPTOPP_ASSERT(version == 0 || version == 1); + + DERSequenceEncoder privateKeyInfo(bt); + DEREncodeUnsigned(privateKeyInfo, version); + + DERSequenceEncoder algorithm(privateKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + algorithm.MessageEnd(); + + DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING); + DEREncodePrivateKey(octetString); + octetString.MessageEnd(); + + if (version == 1) + { + DERGeneralEncoder publicKey(privateKeyInfo, CONTEXT_SPECIFIC | CONSTRUCTED | 1); + DEREncodeBitString(publicKey, m_pk, PUBLIC_KEYLENGTH); + publicKey.MessageEnd(); + } + + privateKeyInfo.MessageEnd(); +} + +void ed25519PrivateKey::BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/) +{ + // https://tools.ietf.org/html/rfc8410 and + // https://www.cryptopp.com/wiki/curve25519_keys + + BERGeneralDecoder privateKey(bt, OCTET_STRING); + + if (!privateKey.IsDefiniteLength()) + BERDecodeError(); + + size_t size = privateKey.Get(m_sk, SECRET_KEYLENGTH); + if (size != SECRET_KEYLENGTH) + BERDecodeError(); + + // We don't know how to decode them + if (parametersPresent) + BERDecodeError(); + + privateKey.MessageEnd(); +} + +void ed25519PrivateKey::DEREncodePrivateKey(BufferedTransformation &bt) const +{ + // https://tools.ietf.org/html/rfc8410 + DERGeneralEncoder privateKey(bt, OCTET_STRING); + privateKey.Put(m_sk, SECRET_KEYLENGTH); + privateKey.MessageEnd(); +} + +void ed25519PrivateKey::SetPrivateExponent (const byte x[SECRET_KEYLENGTH]) +{ + AssignFrom(MakeParameters + (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH)) + ("DerivePublicKey", true)); +} + +void ed25519PrivateKey::SetPrivateExponent (const Integer &x) +{ + CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH); + + SecByteBlock bx(SECRET_KEYLENGTH); + x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH); + + AssignFrom(MakeParameters + (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false)) + ("DerivePublicKey", true)); +} + +const Integer& ed25519PrivateKey::GetPrivateExponent() const +{ + m_x = Integer(m_sk, SECRET_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER); + return m_x; +} + +//////////////////////// + +ed25519Signer::ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) +{ + AccessPrivateKey().AssignFrom(MakeParameters + (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false)) + (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH, false))); +} + +ed25519Signer::ed25519Signer(const byte x[SECRET_KEYLENGTH]) +{ + AccessPrivateKey().AssignFrom(MakeParameters + (Name::PrivateExponent(), ConstByteArrayParameter(x, SECRET_KEYLENGTH, false)) + ("DerivePublicKey", true)); +} + +ed25519Signer::ed25519Signer(const Integer &y, const Integer &x) +{ + CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH); + CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH); + + SecByteBlock by(PUBLIC_KEYLENGTH), bx(SECRET_KEYLENGTH); + y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH); + x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH); + + AccessPrivateKey().AssignFrom(MakeParameters + (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false)) + (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false))); +} + +ed25519Signer::ed25519Signer(const Integer &x) +{ + CRYPTOPP_ASSERT(x.MinEncodedSize() <= SECRET_KEYLENGTH); + + SecByteBlock bx(SECRET_KEYLENGTH); + x.Encode(bx, SECRET_KEYLENGTH); std::reverse(bx+0, bx+SECRET_KEYLENGTH); + + AccessPrivateKey().AssignFrom(MakeParameters + (Name::PrivateExponent(), ConstByteArrayParameter(bx, SECRET_KEYLENGTH, false)) + ("DerivePublicKey", true)); +} + +ed25519Signer::ed25519Signer(RandomNumberGenerator &rng) +{ + AccessPrivateKey().GenerateRandom(rng); +} + +ed25519Signer::ed25519Signer(BufferedTransformation ¶ms) +{ + AccessPrivateKey().Load(params); +} + +size_t ed25519Signer::SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const +{ + CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng); + + ed25519_MessageAccumulator& accum = dynamic_cast(messageAccumulator); + const ed25519PrivateKey& pk = dynamic_cast(GetPrivateKey()); + int ret = Donna::ed25519_sign(accum.data(), accum.size(), pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature); + CRYPTOPP_ASSERT(ret == 0); + + if (restart) + accum.Restart(); + + return ret == 0 ? SIGNATURE_LENGTH : 0; +} + +size_t ed25519Signer::SignStream (RandomNumberGenerator &rng, std::istream& stream, byte *signature) const +{ + CRYPTOPP_ASSERT(signature != NULLPTR); CRYPTOPP_UNUSED(rng); + + const ed25519PrivateKey& pk = dynamic_cast(GetPrivateKey()); + int ret = Donna::ed25519_sign(stream, pk.GetPrivateKeyBytePtr(), pk.GetPublicKeyBytePtr(), signature); + CRYPTOPP_ASSERT(ret == 0); + + return ret == 0 ? SIGNATURE_LENGTH : 0; +} + +// ******************** ed25519 Verifier ************************* // + +bool ed25519PublicKey::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + if (std::strcmp(name, Name::PublicElement()) == 0) + { + this->ThrowIfTypeMismatch(name, typeid(ConstByteArrayParameter), valueType); + reinterpret_cast(pValue)->Assign(m_pk, PUBLIC_KEYLENGTH, false); + return true; + } + + if (std::strcmp(name, Name::GroupOID()) == 0) + { + if (m_oid.Empty()) + return false; + + this->ThrowIfTypeMismatch(name, typeid(OID), valueType); + *reinterpret_cast(pValue) = m_oid; + return true; + } + + return false; +} + +void ed25519PublicKey::AssignFrom(const NameValuePairs &source) +{ + ConstByteArrayParameter ba; + if (source.GetValue(Name::PublicElement(), ba)) + { + std::memcpy(m_pk, ba.begin(), PUBLIC_KEYLENGTH); + } + + OID oid; + if (source.GetValue(Name::GroupOID(), oid)) + { + m_oid = oid; + } +} + +void ed25519PublicKey::BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt) +{ + // We have not yet determined the OID to use for this object. + // We can't use OID's decoder because it throws BERDecodeError + // if the OIDs do not match. + OID oid(bt); + + if (!m_oid.Empty() && m_oid != oid) + BERDecodeError(); // Only accept user specified OID + else if (oid == ASN1::curve25519() || oid == ASN1::Ed25519()) + m_oid = oid; // Accept any of the ed25519PublicKey OIDs + else + BERDecodeError(); +} + +void ed25519PublicKey::BERDecode(BufferedTransformation &bt) +{ + BERSequenceDecoder publicKeyInfo(bt); + + BERSequenceDecoder algorithm(publicKeyInfo); + // GetAlgorithmID().BERDecodeAndCheck(algorithm); + BERDecodeAndCheckAlgorithmID(algorithm); + algorithm.MessageEnd(); + + BERDecodePublicKey(publicKeyInfo, false, (size_t)publicKeyInfo.RemainingLength()); + + publicKeyInfo.MessageEnd(); +} + +void ed25519PublicKey::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder publicKeyInfo(bt); + + DERSequenceEncoder algorithm(publicKeyInfo); + GetAlgorithmID().DEREncode(algorithm); + algorithm.MessageEnd(); + + DEREncodePublicKey(publicKeyInfo); + + publicKeyInfo.MessageEnd(); +} + +void ed25519PublicKey::BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t /*size*/) +{ + // We don't know how to decode them + if (parametersPresent) + BERDecodeError(); + + SecByteBlock subjectPublicKey; + unsigned int unusedBits; + BERDecodeBitString(bt, subjectPublicKey, unusedBits); + + CRYPTOPP_ASSERT(unusedBits == 0); + CRYPTOPP_ASSERT(subjectPublicKey.size() == PUBLIC_KEYLENGTH); + if (subjectPublicKey.size() != PUBLIC_KEYLENGTH) + BERDecodeError(); + + std::memcpy(m_pk.begin(), subjectPublicKey, PUBLIC_KEYLENGTH); +} + +void ed25519PublicKey::DEREncodePublicKey(BufferedTransformation &bt) const +{ + DEREncodeBitString(bt, m_pk, PUBLIC_KEYLENGTH); +} + +void ed25519PublicKey::SetPublicElement (const byte y[PUBLIC_KEYLENGTH]) +{ + std::memcpy(m_pk, y, PUBLIC_KEYLENGTH); +} + +void ed25519PublicKey::SetPublicElement (const Integer &y) +{ + CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH); + + SecByteBlock by(PUBLIC_KEYLENGTH); + y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH); + + std::memcpy(m_pk, by, PUBLIC_KEYLENGTH); +} + +const Integer& ed25519PublicKey::GetPublicElement() const +{ + m_y = Integer(m_pk, PUBLIC_KEYLENGTH, Integer::UNSIGNED, LITTLE_ENDIAN_ORDER); + return m_y; +} + +bool ed25519PublicKey::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(level); + return true; +} + +//////////////////////// + +ed25519Verifier::ed25519Verifier(const byte y[PUBLIC_KEYLENGTH]) +{ + AccessPublicKey().AssignFrom(MakeParameters + (Name::PublicElement(), ConstByteArrayParameter(y, PUBLIC_KEYLENGTH))); +} + +ed25519Verifier::ed25519Verifier(const Integer &y) +{ + CRYPTOPP_ASSERT(y.MinEncodedSize() <= PUBLIC_KEYLENGTH); + + SecByteBlock by(PUBLIC_KEYLENGTH); + y.Encode(by, PUBLIC_KEYLENGTH); std::reverse(by+0, by+PUBLIC_KEYLENGTH); + + AccessPublicKey().AssignFrom(MakeParameters + (Name::PublicElement(), ConstByteArrayParameter(by, PUBLIC_KEYLENGTH, false))); +} + +ed25519Verifier::ed25519Verifier(BufferedTransformation ¶ms) +{ + AccessPublicKey().Load(params); +} + +ed25519Verifier::ed25519Verifier(const ed25519Signer& signer) +{ + const ed25519PrivateKey& priv = dynamic_cast(signer.GetPrivateKey()); + priv.MakePublicKey(AccessPublicKey()); +} + +bool ed25519Verifier::VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const +{ + ed25519_MessageAccumulator& accum = static_cast(messageAccumulator); + const ed25519PublicKey& pk = dynamic_cast(GetPublicKey()); + int ret = Donna::ed25519_sign_open(accum.data(), accum.size(), pk.GetPublicKeyBytePtr(), accum.signature()); + accum.Restart(); + + return ret == 0; +} + +bool ed25519Verifier::VerifyStream(std::istream& stream, const byte *signature, size_t signatureLen) const +{ + CRYPTOPP_ASSERT(signatureLen == SIGNATURE_LENGTH); + CRYPTOPP_UNUSED(signatureLen); + + const ed25519PublicKey& pk = static_cast(GetPublicKey()); + int ret = Donna::ed25519_sign_open(stream, pk.GetPublicKeyBytePtr(), signature); + + return ret == 0; +} + +NAMESPACE_END // CryptoPP diff --git a/extension/third_party/cryptopp/xed25519.h b/extension/third_party/cryptopp/xed25519.h new file mode 100644 index 00000000..6e5c7acb --- /dev/null +++ b/extension/third_party/cryptopp/xed25519.h @@ -0,0 +1,807 @@ +// xed25519.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// http://github.com/floodyberry/curve25519-donna and +// http://github.com/floodyberry/ed25519-donna. + +// Typically the key agreement classes encapsulate their data more +// than x25519 does below. They are a little more accessible +// due to crypto_box operations. + +/// \file xed25519.h +/// \brief Classes for x25519 and ed25519 operations +/// \details This implementation integrates Andrew Moon's public domain code +/// for curve25519-donna and ed25519-donna. +/// \details Moving keys into and out of the library proceeds as follows. +/// If an Integer class is accepted or returned, then the data is in big +/// endian format. That is, the MSB is at byte position 0, and the LSB +/// is at byte position 31. The Integer will work as expected, just like +/// an int or a long. +/// \details If a byte array is accepted, then the byte array is in little +/// endian format. That is, the LSB is at byte position 0, and the MSB is +/// at byte position 31. This follows the implementation where byte 0 is +/// clamed with 248. That is my_arr[0] &= 248 to mask the lower 3 bits. +/// \details PKCS8 and X509 keys encoded using ASN.1 follow little endian +/// arrays. The format is specified in draft-ietf-curdle-pkix. +/// \details If you have a little endian array and you want to wrap it in +/// an Integer using big endian then you can perform the following: +///

Integer x(my_arr, SECRET_KEYLENGTH, UNSIGNED, LITTLE_ENDIAN_ORDER);
+/// \sa Andrew Moon's x22519 GitHub curve25519-donna, +/// ed22519 GitHub ed25519-donna, and +/// draft-ietf-curdle-pkix +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_XED25519_H +#define CRYPTOPP_XED25519_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "oids.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; +struct ed25519Signer; +struct ed25519Verifier; + +// ******************** x25519 Agreement ************************* // + +/// \brief x25519 with key validation +/// \since Crypto++ 8.0 +class x25519 : public SimpleKeyAgreementDomain, public CryptoParameters, public PKCS8PrivateKey +{ +public: + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the shared key + /// \details SHARED_KEYLENGTH is the size of the shared key, in bytes. + CRYPTOPP_CONSTANT(SHARED_KEYLENGTH = 32); + + virtual ~x25519() {} + + /// \brief Create a x25519 object + /// \details This constructor creates an empty x25519 object. It is + /// intended for use in loading existing parameters, like CryptoBox + /// parameters. If you are perfoming key agreement you should use a + /// constructor that generates random parameters on construction. + x25519() {} + + /// \brief Create a x25519 object + /// \param y public key + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// \note The public key is not validated. + x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a x25519 object + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The public key is calculated from the private key. + x25519(const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a x25519 object + /// \param y public key + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// \note The public key is not validated. + x25519(const Integer &y, const Integer &x); + + /// \brief Create a x25519 object + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The public key is calculated from the private key. + x25519(const Integer &x); + + /// \brief Create a x25519 object + /// \param rng RandomNumberGenerator derived class + /// \details This constructor creates a new x25519 using the random number generator. + x25519(RandomNumberGenerator &rng); + + /// \brief Create a x25519 object + /// \param params public and private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + x25519(BufferedTransformation ¶ms); + + /// \brief Create a x25519 object + /// \param oid an object identifier + /// \details This constructor creates a new x25519 using the specified OID. The public + /// and private points are uninitialized. + x25519(const OID &oid); + + /// \brief Clamp a private key + /// \param x private key + /// \details ClampKeys() clamps a private key and then regenerates the + /// public key from the private key. + void ClampKey(byte x[SECRET_KEYLENGTH]) const; + + /// \brief Determine if private key is clamped + /// \param x private key + bool IsClamped(const byte x[SECRET_KEYLENGTH]) const; + + /// \brief Test if a key has small order + /// \param y public key + bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const; + + /// \brief Get the Object Identifier + /// \return the Object Identifier + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::X25519() : m_oid; + } + + /// \brief Set the Object Identifier + /// \param oid the new Object Identifier + void SetAlgorithmID(const OID& oid) { + m_oid = oid; + } + + // CryptoParameters + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // CryptoParameters + CryptoParameters & AccessCryptoParameters() {return *this;} + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt) const { + DEREncode(bt, 0); + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param v1 flag indicating v1 + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details v1 means INTEGER 0 is written. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The other + /// option uses INTEGER 1. INTEGER 1 means RFC 5958 format, + /// which is the new format. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt, bool v1) const { + DEREncode(bt, v1 ? 0 : 1); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const { DEREncode(bt, 0); } + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param version indicates version + /// \details DEREncode() will write the OID associated with algorithm or + /// scheme. In the case of public and private keys, this function writes + /// the subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details The value of version is written as the INTEGER. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The INTEGER 1 + /// means RFC 5958 format, which is the new format. + void DEREncode(BufferedTransformation &bt, int version) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::X25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::X25519() is specific and says + /// "this key is valid for x25519 key exchange." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + // DL_PrivateKey + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms); + + // SimpleKeyAgreementDomain + unsigned int AgreedValueLength() const {return SHARED_KEYLENGTH;} + unsigned int PrivateKeyLength() const {return SECRET_KEYLENGTH;} + unsigned int PublicKeyLength() const {return PUBLIC_KEYLENGTH;} + + // SimpleKeyAgreementDomain + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + +protected: + // Create a public key from a private key + void SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const; + +protected: + FixedSizeSecBlock m_sk; + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID +}; + +// ****************** ed25519 Signer *********************** // + +/// \brief ed25519 message accumulator +/// \details ed25519 buffers the entire message, and does not +/// digest the message incrementally. You should be careful with +/// large messages like files on-disk. The behavior is by design +/// because Bernstein feels small messages should be authenticated; +/// and larger messages will be digested by the application. +/// \details The accumulator is used for signing and verification. +/// The first 64-bytes of storage is reserved for the signature. +/// During signing the signature storage is unused. During +/// verification the first 64 bytes holds the signature. The +/// signature is provided by the PK_Verifier framework and the +/// call to PK_Signer::InputSignature. Member functions data() +/// and size() refer to the accumulated message. Member function +/// signature() refers to the signature with an implicit size of +/// SIGNATURE_LENGTH bytes. +/// \details Applications which digest large messages, like an ISO +/// disk file, should take care because the design effectively +/// disgorges the format operation from the signing operation. +/// Put another way, be careful to ensure what you are signing is +/// is in fact a digest of the intended message, and not a different +/// message digest supplied by an attacker. +struct ed25519_MessageAccumulator : public PK_MessageAccumulator +{ + CRYPTOPP_CONSTANT(RESERVE_SIZE=2048+64); + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH=64); + + /// \brief Create a message accumulator + ed25519_MessageAccumulator() { + Restart(); + } + + /// \brief Create a message accumulator + /// \details ed25519 does not use a RNG. You can safely use + /// NullRNG() because IsProbablistic returns false. + ed25519_MessageAccumulator(RandomNumberGenerator &rng) { + CRYPTOPP_UNUSED(rng); Restart(); + } + + /// \brief Add data to the accumulator + /// \param msg pointer to the data to accumulate + /// \param len the size of the data, in bytes + void Update(const byte* msg, size_t len) { + if (msg && len) + m_msg.insert(m_msg.end(), msg, msg+len); + } + + /// \brief Reset the accumulator + void Restart() { + m_msg.reserve(RESERVE_SIZE); + m_msg.resize(SIGNATURE_LENGTH); + } + + /// \brief Retrieve pointer to signature buffer + /// \return pointer to signature buffer + byte* signature() { + return &m_msg[0]; + } + + /// \brief Retrieve pointer to signature buffer + /// \return pointer to signature buffer + const byte* signature() const { + return &m_msg[0]; + } + + /// \brief Retrieve pointer to data buffer + /// \return pointer to data buffer + const byte* data() const { + return &m_msg[0]+SIGNATURE_LENGTH; + } + + /// \brief Retrieve size of data buffer + /// \return size of the data buffer, in bytes + size_t size() const { + return m_msg.size()-SIGNATURE_LENGTH; + } + +protected: + // TODO: Find an equivalent Crypto++ structure. + std::vector > m_msg; +}; + +/// \brief Ed25519 private key +/// \details ed25519PrivateKey is somewhat of a hack. It needed to +/// provide DL_PrivateKey interface to fit into the existing +/// framework, but it lacks a lot of the internals of a true +/// DL_PrivateKey. The missing pieces include GroupParameters +/// and Point, which provide the low level field operations +/// found in traditional implementations like NIST curves over +/// prime and binary fields. +/// \details ed25519PrivateKey is also unusual because the +/// class members of interest are byte arrays and not Integers. +/// In addition, the byte arrays are little-endian meaning +/// LSB is at element 0 and the MSB is at element 31. +/// If you call GetPrivateExponent() then the little-endian byte +/// array is converted to a big-endian Integer() so it can be +/// returned the way a caller expects. And calling +/// SetPrivateExponent perfoms a similar internal conversion. +/// \since Crypto++ 8.0 +struct ed25519PrivateKey : public PKCS8PrivateKey +{ + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the siganture + /// \details SIGNATURE_LENGTH is the size of the signature, in bytes. + /// ed25519 is a DL-based signature scheme. The signature is the + /// concatenation of r || s. + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GroupParameters + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::Ed25519() : m_oid; + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-Ed25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt) const { + DEREncode(bt, 0); + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param v1 flag indicating v1 + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-Ed25519. + /// The default private key format is RFC 5208. + /// \details v1 means INTEGER 0 is written. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The other + /// option uses INTEGER 1. INTEGER 1 means RFC 5958 format, + /// which is the new format. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt, bool v1) const { + DEREncode(bt, v1 ? 0 : 1); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + /// \brief Initializes a public key from this key + /// \param pub reference to a public key + void MakePublicKey(PublicKey &pub) const; + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const { DEREncode(bt, 0); } + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param version indicates version + /// \details DEREncode() will write the OID associated with algorithm or + /// scheme. In the case of public and private keys, this function writes + /// the subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details The value of version is written as the INTEGER. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The INTEGER 1 + /// means RFC 5958 format, which is the new format. + void DEREncode(BufferedTransformation &bt, int version) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::Ed25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::Ed25519() is specific and says + /// "this key is valid for ed25519 signing." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + // PKCS8PrivateKey + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms); + void SetPrivateExponent(const byte x[SECRET_KEYLENGTH]); + void SetPrivateExponent(const Integer &x); + const Integer& GetPrivateExponent() const; + + /// \brief Test if a key has small order + /// \param y public key + bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const; + + /// \brief Retrieve private key byte array + /// \return the private key byte array + /// \details GetPrivateKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPrivateKeyBytePtr() const { + return m_sk.begin(); + } + + /// \brief Retrieve public key byte array + /// \return the public key byte array + /// \details GetPublicKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPublicKeyBytePtr() const { + return m_pk.begin(); + } + +protected: + // Create a public key from a private key + void SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const; + +protected: + FixedSizeSecBlock m_sk; + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID + mutable Integer m_x; // for DL_PrivateKey +}; + +/// \brief Ed25519 signature algorithm +/// \since Crypto++ 8.0 +struct ed25519Signer : public PK_Signer +{ + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the siganture + /// \details SIGNATURE_LENGTH is the size of the signature, in bytes. + /// ed25519 is a DL-based signature scheme. The signature is the + /// concatenation of r || s. + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + typedef Integer Element; + + virtual ~ed25519Signer() {} + + /// \brief Create a ed25519Signer object + ed25519Signer() {} + + /// \brief Create a ed25519Signer object + /// \param y public key + /// \param x private key + /// \details This constructor creates a ed25519Signer object using existing parameters. + /// \note The public key is not validated. + ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a ed25519Signer object + /// \param x private key + /// \details This constructor creates a ed25519Signer object using existing parameters. + /// The public key is calculated from the private key. + ed25519Signer(const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a ed25519Signer object + /// \param y public key + /// \param x private key + /// \details This constructor creates a ed25519Signer object using existing parameters. + /// \note The public key is not validated. + ed25519Signer(const Integer &y, const Integer &x); + + /// \brief Create a ed25519Signer object + /// \param x private key + /// \details This constructor creates a ed25519Signer object using existing parameters. + /// The public key is calculated from the private key. + ed25519Signer(const Integer &x); + + /// \brief Create a ed25519Signer object + /// \param rng RandomNumberGenerator derived class + /// \details This constructor creates a new ed25519Signer using the random number generator. + ed25519Signer(RandomNumberGenerator &rng); + + /// \brief Create a ed25519Signer object + /// \param params public and private key + /// \details This constructor creates a ed25519Signer object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Signer(BufferedTransformation ¶ms); + + // DL_ObjectImplBase + /// \brief Retrieves a reference to a Private Key + /// \details AccessKey() retrieves a non-const reference to a private key. + PrivateKey& AccessKey() { return m_key; } + PrivateKey& AccessPrivateKey() { return m_key; } + + /// \brief Retrieves a reference to a Private Key + /// \details AccessKey() retrieves a const reference to a private key. + const PrivateKey& GetKey() const { return m_key; } + const PrivateKey& GetPrivateKey() const { return m_key; } + + // DL_SignatureSchemeBase + size_t SignatureLength() const { return SIGNATURE_LENGTH; } + size_t MaxRecoverableLength() const { return 0; } + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const { + CRYPTOPP_UNUSED(signatureLength); return 0; + } + + bool IsProbabilistic() const { return false; } + bool AllowNonrecoverablePart() const { return false; } + bool RecoverablePartFirst() const { return false; } + + PK_MessageAccumulator* NewSignatureAccumulator(RandomNumberGenerator &rng) const { + return new ed25519_MessageAccumulator(rng); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const { + CRYPTOPP_UNUSED(messageAccumulator); CRYPTOPP_UNUSED(recoverableMessage); + CRYPTOPP_UNUSED(recoverableMessageLength); + throw NotImplemented("ed25519Signer: this object does not support recoverable messages"); + } + + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const; + + /// \brief Sign a stream + /// \param rng a RandomNumberGenerator derived class + /// \param stream an std::istream derived class + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \details SignStream() handles large streams. The Stream functions were added to + /// ed25519 for signing and verifying files that are too large for a memory allocation. + /// The functions are not present in other library signers and verifiers. + /// \details ed25519 is a deterministic signature scheme. IsProbabilistic() + /// returns false and the random number generator can be NullRNG(). + /// \pre COUNTOF(signature) == MaxSignatureLength() + /// \since Crypto++ 8.1 + size_t SignStream (RandomNumberGenerator &rng, std::istream& stream, byte *signature) const; + +protected: + ed25519PrivateKey m_key; +}; + +// ****************** ed25519 Verifier *********************** // + +/// \brief Ed25519 public key +/// \details ed25519PublicKey is somewhat of a hack. It needed to +/// provide DL_PublicKey interface to fit into the existing +/// framework, but it lacks a lot of the internals of a true +/// DL_PublicKey. The missing pieces include GroupParameters +/// and Point, which provide the low level field operations +/// found in traditional implementations like NIST curves over +/// prime and binary fields. +/// \details ed25519PublicKey is also unusual because the +/// class members of interest are byte arrays and not Integers. +/// In addition, the byte arrays are little-endian meaning +/// LSB is at element 0 and the MSB is at element 31. +/// If you call GetPublicElement() then the little-endian byte +/// array is converted to a big-endian Integer() so it can be +/// returned the way a caller expects. And calling +/// SetPublicElement() perfoms a similar internal conversion. +/// \since Crypto++ 8.0 +struct ed25519PublicKey : public X509PublicKey +{ + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + typedef Integer Element; + + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::Ed25519() : m_oid; + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPubicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + void Save(BufferedTransformation &bt) const { + DEREncode(bt); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + // X509PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::Ed25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::Ed25519() is specific and says + /// "this key is valid for ed25519 signing." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // DL_PublicKey + void SetPublicElement(const byte y[PUBLIC_KEYLENGTH]); + void SetPublicElement(const Element &y); + const Element& GetPublicElement() const; + + /// \brief Retrieve public key byte array + /// \return the public key byte array + /// \details GetPublicKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPublicKeyBytePtr() const { + return m_pk.begin(); + } + +protected: + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID + mutable Integer m_y; // for DL_PublicKey +}; + +/// \brief Ed25519 signature verification algorithm +/// \since Crypto++ 8.0 +struct ed25519Verifier : public PK_Verifier +{ + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + typedef Integer Element; + + virtual ~ed25519Verifier() {} + + /// \brief Create a ed25519Verifier object + ed25519Verifier() {} + + /// \brief Create a ed25519Verifier object + /// \param y public key + /// \details This constructor creates a ed25519Verifier object using existing parameters. + /// \note The public key is not validated. + ed25519Verifier(const byte y[PUBLIC_KEYLENGTH]); + + /// \brief Create a ed25519Verifier object + /// \param y public key + /// \details This constructor creates a ed25519Verifier object using existing parameters. + /// \note The public key is not validated. + ed25519Verifier(const Integer &y); + + /// \brief Create a ed25519Verifier object + /// \param params public and private key + /// \details This constructor creates a ed25519Verifier object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Verifier(BufferedTransformation ¶ms); + + /// \brief Create a ed25519Verifier object + /// \param signer ed25519 signer object + /// \details This constructor creates a ed25519Verifier object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Verifier(const ed25519Signer& signer); + + // DL_ObjectImplBase + /// \brief Retrieves a reference to a Public Key + /// \details AccessKey() retrieves a non-const reference to a public key. + PublicKey& AccessKey() { return m_key; } + PublicKey& AccessPublicKey() { return m_key; } + + /// \brief Retrieves a reference to a Public Key + /// \details GetKey() retrieves a const reference to a public key. + const PublicKey& GetKey() const { return m_key; } + const PublicKey& GetPublicKey() const { return m_key; } + + // DL_SignatureSchemeBase + size_t SignatureLength() const { return SIGNATURE_LENGTH; } + size_t MaxRecoverableLength() const { return 0; } + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const { + CRYPTOPP_UNUSED(signatureLength); return 0; + } + + bool IsProbabilistic() const { return false; } + bool AllowNonrecoverablePart() const { return false; } + bool RecoverablePartFirst() const { return false; } + + ed25519_MessageAccumulator* NewVerificationAccumulator() const { + return new ed25519_MessageAccumulator; + } + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const { + CRYPTOPP_ASSERT(signature != NULLPTR); + CRYPTOPP_ASSERT(signatureLength == SIGNATURE_LENGTH); + ed25519_MessageAccumulator& accum = static_cast(messageAccumulator); + if (signature && signatureLength) + std::memcpy(accum.signature(), signature, STDMIN((size_t)SIGNATURE_LENGTH, signatureLength)); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + + /// \brief Check whether input signature is a valid signature for input message + /// \param stream an std::istream derived class + /// \param signature a pointer to the signature over the message + /// \param signatureLen the size of the signature + /// \return true if the signature is valid, false otherwise + /// \details VerifyStream() handles large streams. The Stream functions were added to + /// ed25519 for signing and verifying files that are too large for a memory allocation. + /// The functions are not present in other library signers and verifiers. + /// \since Crypto++ 8.1 + bool VerifyStream(std::istream& stream, const byte *signature, size_t signatureLen) const; + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const { + CRYPTOPP_UNUSED(recoveredMessage); CRYPTOPP_UNUSED(messageAccumulator); + throw NotImplemented("ed25519Verifier: this object does not support recoverable messages"); + } + +protected: + ed25519PublicKey m_key; +}; + +/// \brief Ed25519 signature scheme +/// \sa Ed25519 on the Crypto++ wiki. +/// \since Crypto++ 8.0 +struct ed25519 +{ + /// \brief ed25519 Signer + typedef ed25519Signer Signer; + /// \brief ed25519 Verifier + typedef ed25519Verifier Verifier; +}; + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_XED25519_H diff --git a/extension/third_party/cryptopp/xtr.cpp b/extension/third_party/cryptopp/xtr.cpp new file mode 100644 index 00000000..fe49b1ea --- /dev/null +++ b/extension/third_party/cryptopp/xtr.cpp @@ -0,0 +1,120 @@ +// xtr.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "xtr.h" +#include "nbtheory.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "algebra.cpp" + +NAMESPACE_BEGIN(CryptoPP) + +const GFP2Element & GFP2Element::Zero() +{ +#if defined(CRYPTOPP_CXX11_STATIC_INIT) + static const GFP2Element s_zero; + return s_zero; +#else + return Singleton().Ref(); +#endif +} + +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits) +{ + CRYPTOPP_ASSERT(qbits > 9); // no primes exist for pbits = 10, qbits = 9 + CRYPTOPP_ASSERT(pbits > qbits); + + const Integer minQ = Integer::Power2(qbits - 1); + const Integer maxQ = Integer::Power2(qbits) - 1; + const Integer minP = Integer::Power2(pbits - 1); + const Integer maxP = Integer::Power2(pbits) - 1; + +top: + + Integer r1, r2; + do + { + (void)q.Randomize(rng, minQ, maxQ, Integer::PRIME, 7, 12); + // Solution always exists because q === 7 mod 12. + (void)SolveModularQuadraticEquation(r1, r2, 1, -1, 1, q); + // I believe k_i, r1 and r2 are being used slightly different than the + // paper's algorithm. I believe it is leading to the failed asserts. + // Just make the assert part of the condition. + if(!p.Randomize(rng, minP, maxP, Integer::PRIME, CRT(rng.GenerateBit() ? + r1 : r2, q, 2, 3, EuclideanMultiplicativeInverse(p, 3)), 3 * q)) { continue; } + } while (((p % 3U) != 2) || (((p.Squared() - p + 1) % q).NotZero())); + + // CRYPTOPP_ASSERT((p % 3U) == 2); + // CRYPTOPP_ASSERT(((p.Squared() - p + 1) % q).IsZero()); + + GFP2_ONB gfp2(p); + GFP2Element three = gfp2.ConvertIn(3), t; + + while (true) + { + g.c1.Randomize(rng, Integer::Zero(), p-1); + g.c2.Randomize(rng, Integer::Zero(), p-1); + t = XTR_Exponentiate(g, p+1, p); + if (t.c1 == t.c2) + continue; + g = XTR_Exponentiate(g, (p.Squared()-p+1)/q, p); + if (g != three) + break; + } + + if (XTR_Exponentiate(g, q, p) != three) + goto top; + + // CRYPTOPP_ASSERT(XTR_Exponentiate(g, q, p) == three); +} + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p) +{ + unsigned int bitCount = e.BitCount(); + if (bitCount == 0) + return GFP2Element(-3, -3); + + // find the lowest bit of e that is 1 + unsigned int lowest1bit; + for (lowest1bit=0; e.GetBit(lowest1bit) == 0; lowest1bit++) {} + + GFP2_ONB gfp2(p); + GFP2Element c = gfp2.ConvertIn(b); + GFP2Element cp = gfp2.PthPower(c); + GFP2Element S[5] = {gfp2.ConvertIn(3), c, gfp2.SpecialOperation1(c)}; + + // do all exponents bits except the lowest zeros starting from the top + unsigned int i; + for (i = e.BitCount() - 1; i>lowest1bit; i--) + { + if (e.GetBit(i)) + { + gfp2.RaiseToPthPower(S[0]); + gfp2.Accumulate(S[0], gfp2.SpecialOperation2(S[2], c, S[1])); + S[1] = gfp2.SpecialOperation1(S[1]); + S[2] = gfp2.SpecialOperation1(S[2]); + S[0].swap(S[1]); + } + else + { + gfp2.RaiseToPthPower(S[2]); + gfp2.Accumulate(S[2], gfp2.SpecialOperation2(S[0], cp, S[1])); + S[1] = gfp2.SpecialOperation1(S[1]); + S[0] = gfp2.SpecialOperation1(S[0]); + S[2].swap(S[1]); + } + } + + // now do the lowest zeros + while (i--) + S[1] = gfp2.SpecialOperation1(S[1]); + + return gfp2.ConvertOut(S[1]); +} + +template class AbstractRing; +template class AbstractGroup; + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/xtr.h b/extension/third_party/cryptopp/xtr.h new file mode 100644 index 00000000..29479d8c --- /dev/null +++ b/extension/third_party/cryptopp/xtr.h @@ -0,0 +1,219 @@ +#ifndef CRYPTOPP_XTR_H +#define CRYPTOPP_XTR_H + +/// \file xtr.h +/// \brief The XTR public key system +/// \details The XTR public key system by Arjen K. Lenstra and Eric R. Verheul + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief an element of GF(p^2) +class GFP2Element +{ +public: + GFP2Element() {} + GFP2Element(const Integer &c1, const Integer &c2) : c1(c1), c2(c2) {} + GFP2Element(const byte *encodedElement, unsigned int size) + : c1(encodedElement, size/2), c2(encodedElement+size/2, size/2) {} + + void Encode(byte *encodedElement, unsigned int size) + { + c1.Encode(encodedElement, size/2); + c2.Encode(encodedElement+size/2, size/2); + } + + bool operator==(const GFP2Element &rhs) const {return c1 == rhs.c1 && c2 == rhs.c2;} + bool operator!=(const GFP2Element &rhs) const {return !operator==(rhs);} + + void swap(GFP2Element &a) + { + c1.swap(a.c1); + c2.swap(a.c2); + } + + static const GFP2Element & Zero(); + + Integer c1, c2; +}; + +/// \brief GF(p^2), optimal normal basis +template +class GFP2_ONB : public AbstractRing +{ +public: + typedef F BaseField; + + GFP2_ONB(const Integer &p) : modp(p) + { + if (p%3 != 2) + throw InvalidArgument("GFP2_ONB: modulus must be equivalent to 2 mod 3"); + } + + const Integer& GetModulus() const {return modp.GetModulus();} + + GFP2Element ConvertIn(const Integer &a) const + { + t = modp.Inverse(modp.ConvertIn(a)); + return GFP2Element(t, t); + } + + GFP2Element ConvertIn(const GFP2Element &a) const + {return GFP2Element(modp.ConvertIn(a.c1), modp.ConvertIn(a.c2));} + + GFP2Element ConvertOut(const GFP2Element &a) const + {return GFP2Element(modp.ConvertOut(a.c1), modp.ConvertOut(a.c2));} + + bool Equal(const GFP2Element &a, const GFP2Element &b) const + { + return modp.Equal(a.c1, b.c1) && modp.Equal(a.c2, b.c2); + } + + const Element& Identity() const + { + return GFP2Element::Zero(); + } + + const Element& Add(const Element &a, const Element &b) const + { + result.c1 = modp.Add(a.c1, b.c1); + result.c2 = modp.Add(a.c2, b.c2); + return result; + } + + const Element& Inverse(const Element &a) const + { + result.c1 = modp.Inverse(a.c1); + result.c2 = modp.Inverse(a.c2); + return result; + } + + const Element& Double(const Element &a) const + { + result.c1 = modp.Double(a.c1); + result.c2 = modp.Double(a.c2); + return result; + } + + const Element& Subtract(const Element &a, const Element &b) const + { + result.c1 = modp.Subtract(a.c1, b.c1); + result.c2 = modp.Subtract(a.c2, b.c2); + return result; + } + + Element& Accumulate(Element &a, const Element &b) const + { + modp.Accumulate(a.c1, b.c1); + modp.Accumulate(a.c2, b.c2); + return a; + } + + Element& Reduce(Element &a, const Element &b) const + { + modp.Reduce(a.c1, b.c1); + modp.Reduce(a.c2, b.c2); + return a; + } + + bool IsUnit(const Element &a) const + { + return a.c1.NotZero() || a.c2.NotZero(); + } + + const Element& MultiplicativeIdentity() const + { + result.c1 = result.c2 = modp.Inverse(modp.MultiplicativeIdentity()); + return result; + } + + const Element& Multiply(const Element &a, const Element &b) const + { + t = modp.Add(a.c1, a.c2); + t = modp.Multiply(t, modp.Add(b.c1, b.c2)); + result.c1 = modp.Multiply(a.c1, b.c1); + result.c2 = modp.Multiply(a.c2, b.c2); + result.c1.swap(result.c2); + modp.Reduce(t, result.c1); + modp.Reduce(t, result.c2); + modp.Reduce(result.c1, t); + modp.Reduce(result.c2, t); + return result; + } + + const Element& MultiplicativeInverse(const Element &a) const + { + return result = Exponentiate(a, modp.GetModulus()-2); + } + + const Element& Square(const Element &a) const + { + const Integer &ac1 = (&a == &result) ? (t = a.c1) : a.c1; + result.c1 = modp.Multiply(modp.Subtract(modp.Subtract(a.c2, a.c1), a.c1), a.c2); + result.c2 = modp.Multiply(modp.Subtract(modp.Subtract(ac1, a.c2), a.c2), ac1); + return result; + } + + Element Exponentiate(const Element &a, const Integer &e) const + { + Integer edivp, emodp; + Integer::Divide(emodp, edivp, e, modp.GetModulus()); + Element b = PthPower(a); + return AbstractRing::CascadeExponentiate(a, emodp, b, edivp); + } + + const Element & PthPower(const Element &a) const + { + result = a; + result.c1.swap(result.c2); + return result; + } + + void RaiseToPthPower(Element &a) const + { + a.c1.swap(a.c2); + } + + // a^2 - 2a^p + const Element & SpecialOperation1(const Element &a) const + { + CRYPTOPP_ASSERT(&a != &result); + result = Square(a); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c2, a.c1); + modp.Reduce(result.c2, a.c1); + return result; + } + + // x * z - y * z^p + const Element & SpecialOperation2(const Element &x, const Element &y, const Element &z) const + { + CRYPTOPP_ASSERT(&x != &result && &y != &result && &z != &result); + t = modp.Add(x.c2, y.c2); + result.c1 = modp.Multiply(z.c1, modp.Subtract(y.c1, t)); + modp.Accumulate(result.c1, modp.Multiply(z.c2, modp.Subtract(t, x.c1))); + t = modp.Add(x.c1, y.c1); + result.c2 = modp.Multiply(z.c2, modp.Subtract(y.c2, t)); + modp.Accumulate(result.c2, modp.Multiply(z.c1, modp.Subtract(t, x.c2))); + return result; + } + +protected: + BaseField modp; + mutable GFP2Element result; + mutable Integer t; +}; + +/// \brief Creates primes p,q and generator g for XTR +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits); + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p); + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/xtrcrypt.cpp b/extension/third_party/cryptopp/xtrcrypt.cpp new file mode 100644 index 00000000..aa106aa4 --- /dev/null +++ b/extension/third_party/cryptopp/xtrcrypt.cpp @@ -0,0 +1,122 @@ +// xtrcrypt.cpp - originally written and placed in the public domain by Wei Dai + +#include "pch.h" + +#include "asn.h" +#include "integer.h" +#include "xtrcrypt.h" +#include "nbtheory.h" +#include "modarith.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +XTR_DH::XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g) + : m_p(p), m_q(q), m_g(g) +{ +} + +XTR_DH::XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits) +{ + XTR_FindPrimesAndGenerator(rng, m_p, m_q, m_g, pbits, qbits); +} + +XTR_DH::XTR_DH(BufferedTransformation &bt) +{ + BERSequenceDecoder seq(bt); + m_p.BERDecode(seq); + m_q.BERDecode(seq); + m_g.c1.BERDecode(seq); + m_g.c2.BERDecode(seq); + seq.MessageEnd(); +} + +void XTR_DH::DEREncode(BufferedTransformation &bt) const +{ + DERSequenceEncoder seq(bt); + m_p.DEREncode(seq); + m_q.DEREncode(seq); + m_g.c1.DEREncode(seq); + m_g.c2.DEREncode(seq); + seq.MessageEnd(); +} + +bool XTR_DH::Validate(RandomNumberGenerator &rng, unsigned int level) const +{ + bool pass = true; + pass = pass && m_p > Integer::One() && m_p.IsOdd(); + CRYPTOPP_ASSERT(pass); + pass = pass && m_q > Integer::One() && m_q.IsOdd(); + CRYPTOPP_ASSERT(pass); + GFP2Element three = GFP2_ONB(m_p).ConvertIn(3); + CRYPTOPP_ASSERT(pass); + pass = pass && !(m_g.c1.IsNegative() || m_g.c2.IsNegative() || m_g.c1 >= m_p || m_g.c2 >= m_p || m_g == three); + CRYPTOPP_ASSERT(pass); + if (level >= 1) + { + pass = pass && ((m_p.Squared()-m_p+1)%m_q).IsZero(); + CRYPTOPP_ASSERT(pass); + } + if (level >= 2) + { + pass = pass && VerifyPrime(rng, m_p, level-2) && VerifyPrime(rng, m_q, level-2); + CRYPTOPP_ASSERT(pass); + pass = pass && XTR_Exponentiate(m_g, (m_p.Squared()-m_p+1)/m_q, m_p) != three; + CRYPTOPP_ASSERT(pass); + pass = pass && XTR_Exponentiate(m_g, m_q, m_p) == three; + CRYPTOPP_ASSERT(pass); + } + return pass; +} + +bool XTR_DH::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const +{ + return GetValueHelper(this, name, valueType, pValue).Assignable() + CRYPTOPP_GET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; +} + +void XTR_DH::AssignFrom(const NameValuePairs &source) +{ + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(Modulus) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupGenerator) + ; +} + +void XTR_DH::GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const +{ + Integer x(rng, Integer::Zero(), m_q-1); + x.Encode(privateKey, PrivateKeyLength()); +} + +void XTR_DH::GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const +{ + CRYPTOPP_UNUSED(rng); + Integer x(privateKey, PrivateKeyLength()); + GFP2Element y = XTR_Exponentiate(m_g, x, m_p); + y.Encode(publicKey, PublicKeyLength()); +} + +bool XTR_DH::Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey) const +{ + GFP2Element w(otherPublicKey, PublicKeyLength()); + if (validateOtherPublicKey) + { + GFP2_ONB gfp2(m_p); + GFP2Element three = gfp2.ConvertIn(3); + if (w.c1.IsNegative() || w.c2.IsNegative() || w.c1 >= m_p || w.c2 >= m_p || w == three) + return false; + if (XTR_Exponentiate(w, m_q, m_p) != three) + return false; + } + Integer s(privateKey, PrivateKeyLength()); + GFP2Element z = XTR_Exponentiate(w, s, m_p); + z.Encode(agreedValue, AgreedValueLength()); + return true; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/xtrcrypt.h b/extension/third_party/cryptopp/xtrcrypt.h new file mode 100644 index 00000000..64c9430b --- /dev/null +++ b/extension/third_party/cryptopp/xtrcrypt.h @@ -0,0 +1,55 @@ +#ifndef CRYPTOPP_XTRCRYPT_H +#define CRYPTOPP_XTRCRYPT_H + +/// \file +/// \brief XTR public key system +/// \sa "The XTR public key system" by Arjen K. Lenstra and Eric R. Verheul + +#include "cryptlib.h" +#include "xtr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief XTR-DH with key validation +class XTR_DH : public SimpleKeyAgreementDomain, public CryptoParameters +{ + typedef XTR_DH ThisClass; + +public: + XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g); + XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits); + XTR_DH(BufferedTransformation &domainParams); + + void DEREncode(BufferedTransformation &domainParams) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + CryptoParameters & AccessCryptoParameters() {return *this;} + unsigned int AgreedValueLength() const {return 2*m_p.ByteCount();} + unsigned int PrivateKeyLength() const {return m_q.ByteCount();} + unsigned int PublicKeyLength() const {return 2*m_p.ByteCount();} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + + const Integer &GetModulus() const {return m_p;} + const Integer &GetSubgroupOrder() const {return m_q;} + const GFP2Element &GetSubgroupGenerator() const {return m_g;} + + void SetModulus(const Integer &p) {m_p = p;} + void SetSubgroupOrder(const Integer &q) {m_q = q;} + void SetSubgroupGenerator(const GFP2Element &g) {m_g = g;} + +private: + unsigned int ExponentBitLength() const; + + Integer m_p, m_q; + GFP2Element m_g; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/xts.cpp b/extension/third_party/cryptopp/xts.cpp new file mode 100644 index 00000000..91bece25 --- /dev/null +++ b/extension/third_party/cryptopp/xts.cpp @@ -0,0 +1,516 @@ +// xts.cpp - written and placed in the public domain by Jeffrey Walton + +// Aarch32, Aarch64, Altivec and X86_64 include SIMD as part of the +// base architecture. We can use the SIMD code below without an +// architecture option. No runtime tests are required. Unfortunately, +// we can't use it on Altivec because an architecture switch is required. +// The updated XorBuffer gains 0.3 to 1.5 cpb on the architectures for +// 16-byte block sizes. + +#include "pch.h" + +#include "xts.h" +#include "misc.h" +#include "modes.h" +#include "cpu.h" + +#if defined(CRYPTOPP_DEBUG) +# include "aes.h" +# include "threefish.h" +#endif + +// 0.3 to 0.4 cpb profit +#if defined(__SSE2__) || defined(_M_X64) +# include +// Clang intrinsic casts +# define M128_CAST(x) ((__m128i *)(void *)(x)) +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#endif + + +#if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if (CRYPTOPP_ARM_NEON_HEADER) +# include +# endif +#endif + +#if defined(__ALTIVEC__) +# include "ppc_simd.h" +#endif + +ANONYMOUS_NAMESPACE_BEGIN + +using namespace CryptoPP; + +#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) + +using CryptoPP::AES; +using CryptoPP::XTS_Mode; +using CryptoPP::Threefish512; + +void Modes_TestInstantiations() +{ + XTS_Mode::Encryption m0; + XTS_Mode::Decryption m1; + XTS_Mode::Encryption m2; + XTS_Mode::Decryption m3; + +#if CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS + XTS_Mode::Encryption m4; + XTS_Mode::Decryption m5; +#endif +} +#endif // CRYPTOPP_DEBUG + +inline void XorBuffer(byte *output, const byte *input, const byte *mask, size_t count) +{ + CRYPTOPP_ASSERT(count >= 16 && (count % 16 == 0)); + +#if defined(CRYPTOPP_DISABLE_ASM) + xorbuf(output, input, mask, count); + +#elif defined(__SSE2__) || defined(_M_X64) + for (size_t i=0; i(false, LITTLE_ENDIAN_ORDER, in+idx); + word64 y = (x >> 63); x = (x << 1) + carry; + PutWord(false, LITTLE_ENDIAN_ORDER, out+idx, x); + carry = y; + } +#else + word32 carry = 0, x; + for (size_t i=0, idx=0; i(false, LITTLE_ENDIAN_ORDER, in+idx); + word32 y = (x >> 31); x = (x << 1) + carry; + PutWord(false, LITTLE_ENDIAN_ORDER, out+idx, x); + carry = y; + } +#endif + +#if CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS + + CRYPTOPP_ASSERT(IsPowerOf2(len)); + CRYPTOPP_ASSERT(len >= 16); + CRYPTOPP_ASSERT(len <= 128); + + byte* k = out; + if (carry) + { + switch (len) + { + case 16: + { + const size_t LEIDX = 16-1; + k[LEIDX-15] ^= 0x87; + break; + } + case 32: + { + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^256 + x^10 + x^5 + x^2 + 1 + const size_t LEIDX = 32-1; + k[LEIDX-30] ^= 4; + k[LEIDX-31] ^= 0x25; + break; + } + case 64: + { + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^512 + x^8 + x^5 + x^2 + 1 + const size_t LEIDX = 64-1; + k[LEIDX-62] ^= 1; + k[LEIDX-63] ^= 0x25; + break; + } + case 128: + { + // https://crypto.stackexchange.com/q/9815/10496 + // Polynomial x^1024 + x^19 + x^6 + x + 1 + const size_t LEIDX = 128-1; + k[LEIDX-125] ^= 8; + k[LEIDX-126] ^= 0x00; + k[LEIDX-127] ^= 0x43; + break; + } + default: + CRYPTOPP_ASSERT(0); + } + } +#else + CRYPTOPP_ASSERT(len == 16); + + byte* k = out; + if (carry) + { + k[0] ^= 0x87; + return; + } +#endif // CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS +} + +inline void GF_Double(byte *inout, unsigned int len) +{ + GF_Double(inout, inout, len); +} + +ANONYMOUS_NAMESPACE_END + +NAMESPACE_BEGIN(CryptoPP) + +void XTS_ModeBase::ThrowIfInvalidBlockSize(size_t length) +{ +#if CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS + CRYPTOPP_ASSERT(length >= 16 && length <= 128 && IsPowerOf2(length)); + if (length < 16 || length > 128 || !IsPowerOf2(length)) + throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not valid"); +#else + CRYPTOPP_ASSERT(length == 16); + if (length != 16) + throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16"); +#endif +} + +void XTS_ModeBase::ThrowIfInvalidKeyLength(size_t length) +{ + CRYPTOPP_ASSERT(length % 2 == 0); + if (!GetBlockCipher().IsValidKeyLength((length+1)/2)) + throw InvalidKeyLength(AlgorithmName(), length); +} + +void XTS_ModeBase::SetKey(const byte *key, size_t length, const NameValuePairs ¶ms) +{ + ThrowIfInvalidKeyLength(length); + ThrowIfInvalidBlockSize(BlockSize()); + + const size_t klen = length/2; + AccessBlockCipher().SetKey(key+0, klen, params); + AccessTweakCipher().SetKey(key+klen, klen, params); + + ResizeBuffers(); + + size_t ivLength; + const byte *iv = GetIVAndThrowIfInvalid(params, ivLength); + Resynchronize(iv, (int)ivLength); +} + +void XTS_ModeBase::Resynchronize(const byte *iv, int ivLength) +{ + BlockOrientedCipherModeBase::Resynchronize(iv, ivLength); + std::memcpy(m_xregister, m_register, ivLength); + GetTweakCipher().ProcessBlock(m_xregister); +} + +void XTS_ModeBase::Resynchronize(word64 sector, ByteOrder order) +{ + SecByteBlock iv(GetTweakCipher().BlockSize()); + PutWord(false, order, iv, sector); + std::memset(iv+8, 0x00, iv.size()-8); + + BlockOrientedCipherModeBase::Resynchronize(iv, (int)iv.size()); + std::memcpy(m_xregister, iv, iv.size()); + GetTweakCipher().ProcessBlock(m_xregister); +} + +void XTS_ModeBase::ResizeBuffers() +{ + BlockOrientedCipherModeBase::ResizeBuffers(); + m_xworkspace.New(GetBlockCipher().BlockSize()*ParallelBlocks); + m_xregister.New(GetBlockCipher().BlockSize()*ParallelBlocks); +} + +// ProcessData runs either 12-4-1 blocks, 8-2-1 or 4-1 blocks. Which is +// selected depends on ParallelBlocks in the header file. 12-4-1 or 8-2-1 +// can be used on Aarch64 and PowerPC. Intel should use 4-1 due to lack +// of registers. The unneeded code paths should be removed by optimizer. +// The extra gyrations save us 1.8 cpb on Aarch64 and 2.1 cpb on PowerPC. +void XTS_ModeBase::ProcessData(byte *outString, const byte *inString, size_t length) +{ + // data unit is multiple of 16 bytes + CRYPTOPP_ASSERT(length % BlockSize() == 0); + + enum { lastParallelBlock = ParallelBlocks-1 }; + const unsigned int blockSize = GetBlockCipher().BlockSize(); + const size_t parallelSize = blockSize*ParallelBlocks; + + // encrypt the data unit, optimal size at a time + while (length >= parallelSize) + { + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+1*blockSize, m_xregister+0*blockSize, blockSize); + GF_Double(m_xregister+2*blockSize, m_xregister+1*blockSize, blockSize); + GF_Double(m_xregister+3*blockSize, m_xregister+2*blockSize, blockSize); + + if (ParallelBlocks > 4) + { + GF_Double(m_xregister+4*blockSize, m_xregister+3*blockSize, blockSize); + GF_Double(m_xregister+5*blockSize, m_xregister+4*blockSize, blockSize); + GF_Double(m_xregister+6*blockSize, m_xregister+5*blockSize, blockSize); + GF_Double(m_xregister+7*blockSize, m_xregister+6*blockSize, blockSize); + } + if (ParallelBlocks > 8) + { + GF_Double(m_xregister+8*blockSize, m_xregister+7*blockSize, blockSize); + GF_Double(m_xregister+9*blockSize, m_xregister+8*blockSize, blockSize); + GF_Double(m_xregister+10*blockSize, m_xregister+9*blockSize, blockSize); + GF_Double(m_xregister+11*blockSize, m_xregister+10*blockSize, blockSize); + } + + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString, m_xregister, parallelSize); + + // encrypt one block, merge the tweak into the output block + GetBlockCipher().AdvancedProcessBlocks(m_xworkspace, m_xregister, + outString, parallelSize, BlockTransformation::BT_AllowParallel); + + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+0, m_xregister+lastParallelBlock*blockSize, blockSize); + + inString += parallelSize; + outString += parallelSize; + length -= parallelSize; + } + + // encrypt the data unit, 4 blocks at a time + while (ParallelBlocks == 12 && length >= blockSize*4) + { + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+1*blockSize, m_xregister+0*blockSize, blockSize); + GF_Double(m_xregister+2*blockSize, m_xregister+1*blockSize, blockSize); + GF_Double(m_xregister+3*blockSize, m_xregister+2*blockSize, blockSize); + + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString, m_xregister, blockSize*4); + + // encrypt one block, merge the tweak into the output block + GetBlockCipher().AdvancedProcessBlocks(m_xworkspace, m_xregister, + outString, blockSize*4, BlockTransformation::BT_AllowParallel); + + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+0, m_xregister+3*blockSize, blockSize); + + inString += blockSize*4; + outString += blockSize*4; + length -= blockSize*4; + } + + // encrypt the data unit, 2 blocks at a time + while (ParallelBlocks == 8 && length >= blockSize*2) + { + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+1*blockSize, m_xregister+0*blockSize, blockSize); + + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString, m_xregister, blockSize*2); + + // encrypt one block, merge the tweak into the output block + GetBlockCipher().AdvancedProcessBlocks(m_xworkspace, m_xregister, + outString, blockSize*2, BlockTransformation::BT_AllowParallel); + + // m_xregister[0] always points to the next tweak. + GF_Double(m_xregister+0, m_xregister+1*blockSize, blockSize); + + inString += blockSize*2; + outString += blockSize*2; + length -= blockSize*2; + } + + // encrypt the data unit, blocksize at a time + while (length) + { + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString, m_xregister, blockSize); + + // encrypt one block + GetBlockCipher().ProcessBlock(m_xworkspace); + + // merge the tweak into the output block + XorBuffer(outString, m_xworkspace, m_xregister, blockSize); + + // Multiply T by alpha + GF_Double(m_xregister, blockSize); + + inString += blockSize; + outString += blockSize; + length -= blockSize; + } +} + +size_t XTS_ModeBase::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + // need at least a full AES block + CRYPTOPP_ASSERT(inLength >= BlockSize()); + + if (inLength < BlockSize()) + throw InvalidArgument("XTS: message is too short for ciphertext stealing"); + + if (IsForwardTransformation()) + return ProcessLastPlainBlock(outString, outLength, inString, inLength); + else + return ProcessLastCipherBlock(outString, outLength, inString, inLength); +} + +size_t XTS_ModeBase::ProcessLastPlainBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + // ensure output buffer is large enough + CRYPTOPP_ASSERT(outLength >= inLength); + + const unsigned int blockSize = GetBlockCipher().BlockSize(); + const size_t blocks = inLength / blockSize; + const size_t tail = inLength % blockSize; + outLength = inLength; + + if (tail == 0) + { + // Allow ProcessData to handle all the full blocks + ProcessData(outString, inString, inLength); + return inLength; + } + else if (blocks > 1) + { + // Allow ProcessData to handle full blocks except one + const size_t head = (blocks-1)*blockSize; + ProcessData(outString, inString, inLength-head); + + outString += head; + inString += head; inLength -= head; + } + + ///// handle the full block ///// + + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString, m_xregister, blockSize); + + // encrypt one block + GetBlockCipher().ProcessBlock(m_xworkspace); + + // merge the tweak into the output block + XorBuffer(outString, m_xworkspace, m_xregister, blockSize); + + // Multiply T by alpha + GF_Double(m_xregister, blockSize); + + ///// handle final partial block ///// + + inString += blockSize; + outString += blockSize; + const size_t len = inLength-blockSize; + + // copy in the final plaintext bytes + std::memcpy(m_xworkspace, inString, len); + // and copy out the final ciphertext bytes + std::memcpy(outString, outString-blockSize, len); + // "steal" ciphertext to complete the block + std::memcpy(m_xworkspace+len, outString-blockSize+len, blockSize-len); + + // merge the tweak into the input block + XorBuffer(m_xworkspace, m_xregister, blockSize); + + // encrypt one block + GetBlockCipher().ProcessBlock(m_xworkspace); + + // merge the tweak into the previous output block + XorBuffer(outString-blockSize, m_xworkspace, m_xregister, blockSize); + + return outLength; +} + +size_t XTS_ModeBase::ProcessLastCipherBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + // ensure output buffer is large enough + CRYPTOPP_ASSERT(outLength >= inLength); + + const unsigned int blockSize = GetBlockCipher().BlockSize(); + const size_t blocks = inLength / blockSize; + const size_t tail = inLength % blockSize; + outLength = inLength; + + if (tail == 0) + { + // Allow ProcessData to handle all the full blocks + ProcessData(outString, inString, inLength); + return inLength; + } + else if (blocks > 1) + { + // Allow ProcessData to handle full blocks except one + const size_t head = (blocks-1)*blockSize; + ProcessData(outString, inString, inLength-head); + + outString += head; + inString += head; inLength -= head; + } + + #define poly1 (m_xregister+0*blockSize) + #define poly2 (m_xregister+1*blockSize) + GF_Double(poly2, poly1, blockSize); + + ///// handle final partial block ///// + + inString += blockSize; + outString += blockSize; + const size_t len = inLength-blockSize; + + // merge the tweak into the input block + XorBuffer(m_xworkspace, inString-blockSize, poly2, blockSize); + + // encrypt one block + GetBlockCipher().ProcessBlock(m_xworkspace); + + // merge the tweak into the output block + XorBuffer(m_xworkspace, poly2, blockSize); + + // copy in the final plaintext bytes + std::memcpy(outString-blockSize, inString, len); + // and copy out the final ciphertext bytes + std::memcpy(outString, m_xworkspace, len); + // "steal" ciphertext to complete the block + std::memcpy(outString-blockSize+len, m_xworkspace+len, blockSize-len); + + ///// handle the full previous block ///// + + inString -= blockSize; + outString -= blockSize; + + // merge the tweak into the input block + XorBuffer(m_xworkspace, outString, poly1, blockSize); + + // encrypt one block + GetBlockCipher().ProcessBlock(m_xworkspace); + + // merge the tweak into the output block + XorBuffer(outString, m_xworkspace, poly1, blockSize); + + return outLength; +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/xts.h b/extension/third_party/cryptopp/xts.h new file mode 100644 index 00000000..ade50add --- /dev/null +++ b/extension/third_party/cryptopp/xts.h @@ -0,0 +1,224 @@ +// xts.h - written and placed in the public domain by Jeffrey Walton + +/// \file xts.h +/// \brief Classes for XTS block cipher mode of operation +/// \details XTS mode is a wide block mode defined by IEEE P1619-2008. NIST +/// SP-800-38E approves the mode for storage devices citing IEEE 1619-2007. +/// IEEE 1619-2007 provides both a reference implementation and test vectors. +/// The IEEE reference implementation fails to arrive at the expected result +/// for some test vectors. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_XTS_MODE_H +#define CRYPTOPP_XTS_MODE_H + +#include "cryptlib.h" +#include "secblock.h" +#include "modes.h" +#include "misc.h" + +/// \brief Enable XTS for wide block ciphers +/// \details XTS is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +/// To enable wide block ciphers define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS +/// to non-zero. Note this is a library compile time define. +/// \details There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." +/// \sa Evaluation +/// of Some Blockcipher Modes of Operation +/// \since Crypto++ 8.3 +#ifndef CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS +# define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS 0 +#endif // CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief XTS block cipher mode of operation default implementation +/// \since Crypto++ 8.3 +class CRYPTOPP_NO_VTABLE XTS_ModeBase : public BlockOrientedCipherModeBase +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "XTS";} + + virtual ~XTS_ModeBase() {} + + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + "/XTS";} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength()*2;} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength()*2;} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength()*2;} + size_t GetValidKeyLength(size_t n) const + {return 2*GetBlockCipher().GetValidKeyLength((n+1)/2);} + bool IsValidKeyLength(size_t keylength) const + {return keylength == GetValidKeyLength(keylength);} + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidKeyLength(size_t length); + + /// Provides the block size of the cipher + /// \return the block size of the cipher, in bytes + unsigned int BlockSize() const + {return GetBlockCipher().BlockSize();} + + /// \brief Provides the input block size most efficient for this cipher + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for + /// any n \> 0. + unsigned int GetOptimalBlockSize() const + {return GetBlockCipher().BlockSize()*ParallelBlocks;} + unsigned int MinLastBlockSize() const + {return GetBlockCipher().BlockSize()+1;} + unsigned int OptimalDataAlignment() const + {return GetBlockCipher().OptimalDataAlignment();} + + /// \brief Validates the block size + /// \param length the block size of the cipher, in bytes + /// \throw InvalidArgument if the block size is invalid + /// \details If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is 0, + /// then CIPHER must be a 16-byte block cipher. If + /// CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is non-zero then + /// CIPHER can be 16, 32, 64, or 128-byte block cipher. + void ThrowIfInvalidBlockSize(size_t length); + + void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs); + IV_Requirement IVRequirement() const {return UNIQUE_IV;} + void Resynchronize(const byte *iv, int ivLength=-1); + void ProcessData(byte *outString, const byte *inString, size_t length); + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + /// \brief Resynchronize the cipher + /// \param sector a 64-bit sector number + /// \param order the endian order the word should be written + /// \details The Resynchronize() overload was provided for API + /// compatibility with the IEEE P1619 paper. + void Resynchronize(word64 sector, ByteOrder order=BIG_ENDIAN_ORDER); + +protected: + virtual void ResizeBuffers(); + + inline size_t ProcessLastPlainBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + inline size_t ProcessLastCipherBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + virtual BlockCipher& AccessBlockCipher() = 0; + virtual BlockCipher& AccessTweakCipher() = 0; + + const BlockCipher& GetBlockCipher() const + {return const_cast(this)->AccessBlockCipher();} + const BlockCipher& GetTweakCipher() const + {return const_cast(this)->AccessTweakCipher();} + + // Buffers are sized based on ParallelBlocks + AlignedSecByteBlock m_xregister; + AlignedSecByteBlock m_xworkspace; + + // Intel lacks the SSE registers to run 8 or 12 parallel blocks. + // Do not change this value after compiling. It has no effect. +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 + enum {ParallelBlocks = 4}; +#else + enum {ParallelBlocks = 12}; +#endif +}; + +/// \brief XTS block cipher mode of operation implementation +/// \tparam CIPHER BlockCipher derived class or type +/// \details XTS_Final() provides access to CIPHER in base class XTS_ModeBase() +/// through an interface. AccessBlockCipher() and AccessTweakCipher() allow +/// the XTS_ModeBase() base class to access the user's block cipher without +/// recompiling the library. +/// \details If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is 0, then CIPHER must +/// be a 16-byte block cipher. If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is +/// non-zero then CIPHER can be 16, 32, 64, or 128-byte block cipher. +/// There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." To enable +/// wide block cipher support define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS to +/// non-zero. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 +template +class CRYPTOPP_NO_VTABLE XTS_Final : public XTS_ModeBase +{ +protected: + BlockCipher& AccessBlockCipher() + {return *m_cipher;} + BlockCipher& AccessTweakCipher() + {return m_tweaker;} + +protected: + typename CIPHER::Encryption m_tweaker; +}; + +/// \brief XTS block cipher mode of operation +/// \tparam CIPHER BlockCipher derived class or type +/// \details XTS mode is a wide block mode defined by IEEE P1619-2008. NIST +/// SP-800-38E approves the mode for storage devices citing IEEE 1619-2007. +/// IEEE 1619-2007 provides both a reference implementation and test vectors. +/// The IEEE reference implementation fails to arrive at the expected result +/// for some test vectors. +/// \details XTS is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +/// There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." To enable +/// wide block cipher support define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS to +/// non-zero. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 +template +struct XTS : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > Decryption; +}; + +// C++03 lacks the mechanics to typedef a template +#define XTS_Mode XTS + +NAMESPACE_END + +#endif // CRYPTOPP_XTS_MODE_H diff --git a/extension/third_party/cryptopp/zdeflate.cpp b/extension/third_party/cryptopp/zdeflate.cpp new file mode 100644 index 00000000..44413ab5 --- /dev/null +++ b/extension/third_party/cryptopp/zdeflate.cpp @@ -0,0 +1,821 @@ +// zdeflate.cpp - originally written and placed in the public domain by Wei Dai + +// Many of the algorithms and tables used here came from the deflate implementation +// by Jean-loup Gailly, which was included in Crypto++ 4.0 and earlier. I completely +// rewrote it in order to fix a bug that I could not figure out. This code +// is less clever, but hopefully more understandable and maintainable. + +#include "pch.h" +#include "zdeflate.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +#if (defined(_MSC_VER) && (_MSC_VER < 1400)) && !defined(__MWERKS__) + // VC60 and VC7 workaround: built-in std::reverse_iterator has two template parameters, Dinkumware only has one + typedef std::reverse_bidirectional_iterator RevIt; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator RevIt; +#else + typedef std::reverse_iterator RevIt; +#endif + +LowFirstBitWriter::LowFirstBitWriter(BufferedTransformation *attachment) + : Filter(attachment), m_counting(false), m_bitCount(0), m_buffer(0) + , m_bitsBuffered(0), m_bytesBuffered(0) +{ +} + +void LowFirstBitWriter::StartCounting() +{ + CRYPTOPP_ASSERT(!m_counting); + m_counting = true; + m_bitCount = 0; +} + +unsigned long LowFirstBitWriter::FinishCounting() +{ + CRYPTOPP_ASSERT(m_counting); + m_counting = false; + return m_bitCount; +} + +void LowFirstBitWriter::PutBits(unsigned long value, unsigned int length) +{ + if (m_counting) + m_bitCount += length; + else + { + m_buffer |= value << m_bitsBuffered; + m_bitsBuffered += length; + CRYPTOPP_ASSERT(m_bitsBuffered <= sizeof(unsigned long)*8); + while (m_bitsBuffered >= 8) + { + m_outputBuffer[m_bytesBuffered++] = (byte)m_buffer; + if (m_bytesBuffered == m_outputBuffer.size()) + { + AttachedTransformation()->PutModifiable(m_outputBuffer, m_bytesBuffered); + m_bytesBuffered = 0; + } + m_buffer >>= 8; + m_bitsBuffered -= 8; + } + } +} + +void LowFirstBitWriter::FlushBitBuffer() +{ + if (m_counting) + m_bitCount += 8*(m_bitsBuffered > 0); + else + { + if (m_bytesBuffered > 0) + { + AttachedTransformation()->PutModifiable(m_outputBuffer, m_bytesBuffered); + m_bytesBuffered = 0; + } + if (m_bitsBuffered > 0) + { + AttachedTransformation()->Put((byte)m_buffer); + m_buffer = 0; + m_bitsBuffered = 0; + } + } +} + +void LowFirstBitWriter::ClearBitBuffer() +{ + m_buffer = 0; + m_bytesBuffered = 0; + m_bitsBuffered = 0; +} + +HuffmanEncoder::HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes) +{ + Initialize(codeBits, nCodes); +} + +struct HuffmanNode +{ + HuffmanNode() + : symbol(0), parent(0) {} + HuffmanNode(const HuffmanNode& rhs) + : symbol(rhs.symbol), parent(rhs.parent) {} + HuffmanNode& operator=(const HuffmanNode& rhs) + { + // No this guard + symbol = rhs.symbol; + parent = rhs.parent; + return *this; + } + + size_t symbol; + union {size_t parent; unsigned depth, freq;}; +}; + +struct FreqLessThan +{ + inline bool operator()(unsigned int lhs, const HuffmanNode &rhs) {return lhs < rhs.freq;} + inline bool operator()(const HuffmanNode &lhs, const HuffmanNode &rhs) const {return lhs.freq < rhs.freq;} + // needed for MSVC .NET 2005 + inline bool operator()(const HuffmanNode &lhs, unsigned int rhs) {return lhs.freq < rhs;} +}; + +void HuffmanEncoder::GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, size_t nCodes) +{ + CRYPTOPP_ASSERT(nCodes > 0); + CRYPTOPP_ASSERT(nCodes <= ((size_t)1 << maxCodeBits)); + + size_t i; + SecBlockWithHint tree(nCodes); + for (i=0; i= 2) + for (i=tree.size()-2; i>=nCodes; i--) + tree[i].depth = tree[tree[i].parent].depth + 1; + unsigned int sum = 0; + SecBlockWithHint blCount(maxCodeBits+1); + std::fill(blCount.begin(), blCount.end(), 0); + for (i=treeBegin; i (unsigned int)(1 << maxCodeBits) ? sum - (1 << maxCodeBits) : 0; + + while (overflow--) + { + unsigned int bits = maxCodeBits-1; + while (blCount[bits] == 0) + bits--; + blCount[bits]--; + blCount[bits+1] += 2; + CRYPTOPP_ASSERT(blCount[maxCodeBits] > 0); + blCount[maxCodeBits]--; + } + + for (i=0; i 0); + unsigned int maxCodeBits = *std::max_element(codeBits, codeBits+nCodes); + if (maxCodeBits == 0) + return; // assume this object won't be used + + SecBlockWithHint blCount(maxCodeBits+1); + std::fill(blCount.begin(), blCount.end(), 0); + unsigned int i; + for (i=0; i nextCode(maxCodeBits+1); + nextCode[1] = 0; + for (i=2; i<=maxCodeBits; i++) + { + code = (code + blCount[i-1]) << 1; + nextCode[i] = code; + } + CRYPTOPP_ASSERT(maxCodeBits == 1 || code == (1 << maxCodeBits) - blCount[maxCodeBits]); + + m_valueToCode.resize(nCodes); + for (i=0; i> (8*sizeof(code_t)-len); + } +} + +inline void HuffmanEncoder::Encode(LowFirstBitWriter &writer, value_t value) const +{ + CRYPTOPP_ASSERT(m_valueToCode[value].len > 0); + writer.PutBits(m_valueToCode[value].code, m_valueToCode[value].len); +} + +Deflator::Deflator(BufferedTransformation *attachment, int deflateLevel, int log2WindowSize, bool detectUncompressible) + : LowFirstBitWriter(attachment) + , m_deflateLevel(-1) +{ + InitializeStaticEncoders(); + Deflator::IsolatedInitialize(MakeParameters("DeflateLevel", deflateLevel)("Log2WindowSize", log2WindowSize)("DetectUncompressible", detectUncompressible)); +} + +Deflator::Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment) + : LowFirstBitWriter(attachment) + , m_deflateLevel(-1) +{ + InitializeStaticEncoders(); + Deflator::IsolatedInitialize(parameters); +} + +void Deflator::InitializeStaticEncoders() +{ + unsigned int codeLengths[288]; + std::fill(codeLengths + 0, codeLengths + 144, 8); + std::fill(codeLengths + 144, codeLengths + 256, 9); + std::fill(codeLengths + 256, codeLengths + 280, 7); + std::fill(codeLengths + 280, codeLengths + 288, 8); + m_staticLiteralEncoder.Initialize(codeLengths, 288); + std::fill(codeLengths + 0, codeLengths + 32, 5); + m_staticDistanceEncoder.Initialize(codeLengths, 32); +} + +void Deflator::IsolatedInitialize(const NameValuePairs ¶meters) +{ + int log2WindowSize = parameters.GetIntValueWithDefault("Log2WindowSize", DEFAULT_LOG2_WINDOW_SIZE); + if (!(MIN_LOG2_WINDOW_SIZE <= log2WindowSize && log2WindowSize <= MAX_LOG2_WINDOW_SIZE)) + throw InvalidArgument("Deflator: " + IntToString(log2WindowSize) + " is an invalid window size"); + + m_log2WindowSize = log2WindowSize; + DSIZE = 1 << m_log2WindowSize; + DMASK = DSIZE - 1; + HSIZE = 1 << m_log2WindowSize; + HMASK = HSIZE - 1; + m_byteBuffer.New(2*DSIZE); + m_head.New(HSIZE); + m_prev.New(DSIZE); + m_matchBuffer.New(DSIZE/2); + Reset(true); + + const int deflateLevel = parameters.GetIntValueWithDefault("DeflateLevel", DEFAULT_DEFLATE_LEVEL); + CRYPTOPP_ASSERT(deflateLevel >= MIN_DEFLATE_LEVEL /*0*/ && deflateLevel <= MAX_DEFLATE_LEVEL /*9*/); + SetDeflateLevel(deflateLevel); + bool detectUncompressible = parameters.GetValueWithDefault("DetectUncompressible", true); + m_compressibleDeflateLevel = detectUncompressible ? m_deflateLevel : 0; +} + +void Deflator::Reset(bool forceReset) +{ + if (forceReset) + ClearBitBuffer(); + else + CRYPTOPP_ASSERT(m_bitsBuffered == 0); + + m_headerWritten = false; + m_matchAvailable = false; + m_dictionaryEnd = 0; + m_stringStart = 0; + m_lookahead = 0; + m_minLookahead = MAX_MATCH; + m_matchBufferEnd = 0; + m_blockStart = 0; + m_blockLength = 0; + + m_detectCount = 1; + m_detectSkip = 0; + + // m_prev will be initialized automatically in InsertString + std::fill(m_head.begin(), m_head.end(), byte(0)); + + std::fill(m_literalCounts.begin(), m_literalCounts.end(), byte(0)); + std::fill(m_distanceCounts.begin(), m_distanceCounts.end(), byte(0)); +} + +void Deflator::SetDeflateLevel(int deflateLevel) +{ + if (!(MIN_DEFLATE_LEVEL <= deflateLevel && deflateLevel <= MAX_DEFLATE_LEVEL)) + throw InvalidArgument("Deflator: " + IntToString(deflateLevel) + " is an invalid deflate level"); + + if (deflateLevel == m_deflateLevel) + return; + + EndBlock(false); + + static const unsigned int configurationTable[10][4] = { + /* good lazy nice chain */ + /* 0 */ {0, 0, 0, 0}, /* store only */ + /* 1 */ {4, 3, 8, 4}, /* maximum speed, no lazy matches */ + /* 2 */ {4, 3, 16, 8}, + /* 3 */ {4, 3, 32, 32}, + /* 4 */ {4, 4, 16, 16}, /* lazy matches */ + /* 5 */ {8, 16, 32, 32}, + /* 6 */ {8, 16, 128, 128}, + /* 7 */ {8, 32, 128, 256}, + /* 8 */ {32, 128, 258, 1024}, + /* 9 */ {32, 258, 258, 4096}}; /* maximum compression */ + + GOOD_MATCH = configurationTable[deflateLevel][0]; + MAX_LAZYLENGTH = configurationTable[deflateLevel][1]; + MAX_CHAIN_LENGTH = configurationTable[deflateLevel][3]; + + m_deflateLevel = deflateLevel; +} + +unsigned int Deflator::FillWindow(const byte *str, size_t length) +{ + unsigned int maxBlockSize = (unsigned int)STDMIN(2UL*DSIZE, 0xffffUL); + + if (m_stringStart >= maxBlockSize - MAX_MATCH) + { + if (m_blockStart < DSIZE) + EndBlock(false); + + memcpy(m_byteBuffer, m_byteBuffer + DSIZE, DSIZE); + + m_dictionaryEnd = m_dictionaryEnd < DSIZE ? 0 : m_dictionaryEnd-DSIZE; + CRYPTOPP_ASSERT(m_stringStart >= DSIZE); + m_stringStart -= DSIZE; + CRYPTOPP_ASSERT(!m_matchAvailable || m_previousMatch >= DSIZE); + m_previousMatch -= DSIZE; + CRYPTOPP_ASSERT(m_blockStart >= DSIZE); + m_blockStart -= DSIZE; + + // These are set to the same value in IsolatedInitialize(). If they + // are the same, then we can clear a Coverity false alarm. + CRYPTOPP_ASSERT(DSIZE == HSIZE); + + unsigned int i; + for (i=0; i m_stringStart+m_lookahead); + unsigned int accepted = UnsignedMin(maxBlockSize-(m_stringStart+m_lookahead), length); + CRYPTOPP_ASSERT(accepted > 0); + memcpy(m_byteBuffer + m_stringStart + m_lookahead, str, accepted); + m_lookahead += accepted; + return accepted; +} + +inline unsigned int Deflator::ComputeHash(const byte *str) const +{ + CRYPTOPP_ASSERT(str+3 <= m_byteBuffer + m_stringStart + m_lookahead); + return ((str[0] << 10) ^ (str[1] << 5) ^ str[2]) & HMASK; +} + +unsigned int Deflator::LongestMatch(unsigned int &bestMatch) const +{ + CRYPTOPP_ASSERT(m_previousLength < MAX_MATCH); + + bestMatch = 0; + unsigned int bestLength = STDMAX(m_previousLength, (unsigned int)MIN_MATCH-1); + if (m_lookahead <= bestLength) + return 0; + + const byte *scan = m_byteBuffer + m_stringStart, *scanEnd = scan + STDMIN((unsigned int)MAX_MATCH, m_lookahead); + unsigned int limit = m_stringStart > (DSIZE-MAX_MATCH) ? m_stringStart - (DSIZE-MAX_MATCH) : 0; + unsigned int current = m_head[ComputeHash(scan)]; + + unsigned int chainLength = MAX_CHAIN_LENGTH; + if (m_previousLength >= GOOD_MATCH) + chainLength >>= 2; + + while (current > limit && --chainLength > 0) + { + const byte *match = m_byteBuffer + current; + CRYPTOPP_ASSERT(scan + bestLength < m_byteBuffer + m_stringStart + m_lookahead); + if (scan[bestLength-1] == match[bestLength-1] && scan[bestLength] == match[bestLength] && scan[0] == match[0] && scan[1] == match[1]) + { + CRYPTOPP_ASSERT(scan[2] == match[2]); + unsigned int len = (unsigned int)( +#if defined(_STDEXT_BEGIN) && !(defined(_MSC_VER) && (_MSC_VER < 1400 || _MSC_VER >= 1600)) && !defined(_STLPORT_VERSION) + stdext::unchecked_mismatch +#else + std::mismatch +#endif +#if _MSC_VER >= 1600 + (stdext::make_unchecked_array_iterator(scan)+3, stdext::make_unchecked_array_iterator(scanEnd), stdext::make_unchecked_array_iterator(match)+3).first - stdext::make_unchecked_array_iterator(scan)); +#else + (scan+3, scanEnd, match+3).first - scan); +#endif + CRYPTOPP_ASSERT(len != bestLength); + if (len > bestLength) + { + bestLength = len; + bestMatch = current; + + CRYPTOPP_ASSERT(scanEnd >= scan); + if (len == (unsigned int)(scanEnd - scan)) + break; + } + } + current = m_prev[current & DMASK]; + } + return (bestMatch > 0) ? bestLength : 0; +} + +inline void Deflator::InsertString(unsigned int start) +{ + CRYPTOPP_ASSERT(start <= 0xffff); + unsigned int hash = ComputeHash(m_byteBuffer + start); + m_prev[start & DMASK] = m_head[hash]; + m_head[hash] = word16(start); +} + +void Deflator::ProcessBuffer() +{ + if (!m_headerWritten) + { + WritePrestreamHeader(); + m_headerWritten = true; + } + + if (m_deflateLevel == 0) + { + m_stringStart += m_lookahead; + m_lookahead = 0; + m_blockLength = m_stringStart - m_blockStart; + m_matchAvailable = false; + return; + } + + while (m_lookahead > m_minLookahead) + { + while (m_dictionaryEnd < m_stringStart && m_dictionaryEnd+3 <= m_stringStart+m_lookahead) + InsertString(m_dictionaryEnd++); + + if (m_matchAvailable) + { + unsigned int matchPosition = 0, matchLength = 0; + bool usePreviousMatch; + if (m_previousLength >= MAX_LAZYLENGTH) + usePreviousMatch = true; + else + { + matchLength = LongestMatch(matchPosition); + usePreviousMatch = (matchLength == 0); + } + if (usePreviousMatch) + { + MatchFound(m_stringStart-1-m_previousMatch, m_previousLength); + m_stringStart += m_previousLength-1; + m_lookahead -= m_previousLength-1; + m_matchAvailable = false; + } + else + { + m_previousLength = matchLength; + m_previousMatch = matchPosition; + LiteralByte(m_byteBuffer[m_stringStart-1]); + m_stringStart++; + m_lookahead--; + } + } + else + { + m_previousLength = 0; + m_previousLength = LongestMatch(m_previousMatch); + if (m_previousLength) + m_matchAvailable = true; + else + LiteralByte(m_byteBuffer[m_stringStart]); + m_stringStart++; + m_lookahead--; + } + + CRYPTOPP_ASSERT(m_stringStart - (m_blockStart+m_blockLength) == (unsigned int)m_matchAvailable); + } + + if (m_minLookahead == 0 && m_matchAvailable) + { + LiteralByte(m_byteBuffer[m_stringStart-1]); + m_matchAvailable = false; + } +} + +size_t Deflator::Put2(const byte *str, size_t length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Deflator"); + + size_t accepted = 0; + while (accepted < length) + { + unsigned int newAccepted = FillWindow(str+accepted, length-accepted); + ProcessBuffer(); + // call ProcessUncompressedData() after WritePrestreamHeader() + ProcessUncompressedData(str+accepted, newAccepted); + accepted += newAccepted; + } + CRYPTOPP_ASSERT(accepted == length); + + if (messageEnd) + { + m_minLookahead = 0; + ProcessBuffer(); + EndBlock(true); + FlushBitBuffer(); + WritePoststreamTail(); + Reset(); + } + + Output(0, NULLPTR, 0, messageEnd, blocking); + return 0; +} + +bool Deflator::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Deflator"); + + m_minLookahead = 0; + ProcessBuffer(); + m_minLookahead = MAX_MATCH; + EndBlock(false); + if (hardFlush) + EncodeBlock(false, STORED); + return false; +} + +void Deflator::LiteralByte(byte b) +{ + if (m_matchBufferEnd == m_matchBuffer.size()) + EndBlock(false); + + m_matchBuffer[m_matchBufferEnd++].literalCode = b; + m_literalCounts[b]++; + m_blockLength++; +} + +void Deflator::MatchFound(unsigned int distance, unsigned int length) +{ + if (m_matchBufferEnd == m_matchBuffer.size()) + EndBlock(false); + + static const unsigned int lengthCodes[] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, + 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, + 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285}; + static const unsigned int lengthBases[] = + {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195, + 227,258}; + static const unsigned int distanceBases[30] = + {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073, + 4097,6145,8193,12289,16385,24577}; + + CRYPTOPP_ASSERT(m_matchBufferEnd < m_matchBuffer.size()); + EncodedMatch &m = m_matchBuffer[m_matchBufferEnd++]; + CRYPTOPP_ASSERT((length >= 3) && (length-3 < COUNTOF(lengthCodes))); + unsigned int lengthCode = lengthCodes[length-3]; + m.literalCode = lengthCode; + m.literalExtra = length - lengthBases[lengthCode-257]; + unsigned int distanceCode = (unsigned int)(std::upper_bound(distanceBases, distanceBases+30, distance) - distanceBases - 1); + m.distanceCode = distanceCode; + m.distanceExtra = distance - distanceBases[distanceCode]; + + m_literalCounts[lengthCode]++; + m_distanceCounts[distanceCode]++; + m_blockLength += length; +} + +inline unsigned int CodeLengthEncode(const unsigned int *begin, + const unsigned int *end, + const unsigned int *& p, + unsigned int &extraBits, + unsigned int &extraBitsLength) +{ + unsigned int v = *p; + if ((end-p) >= 3) + { + const unsigned int *oldp = p; + if (v==0 && p[1]==0 && p[2]==0) + { + for (p=p+3; p!=end && *p==0 && p!=oldp+138; p++) {} + unsigned int repeat = (unsigned int)(p - oldp); + if (repeat <= 10) + { + extraBits = repeat-3; + extraBitsLength = 3; + return 17; + } + else + { + extraBits = repeat-11; + extraBitsLength = 7; + return 18; + } + } + else if (p!=begin && v==p[-1] && v==p[1] && v==p[2]) + { + for (p=p+3; p!=end && *p==v && p!=oldp+6; p++) {} + unsigned int repeat = (unsigned int)(p - oldp); + extraBits = repeat-3; + extraBitsLength = 2; + return 16; + } + } + p++; + extraBits = 0; + extraBitsLength = 0; + return v; +} + +void Deflator::EncodeBlock(bool eof, unsigned int blockType) +{ + PutBits(eof, 1); + PutBits(blockType, 2); + + if (blockType == STORED) + { + CRYPTOPP_ASSERT(m_blockStart + m_blockLength <= m_byteBuffer.size()); + CRYPTOPP_ASSERT(m_blockLength <= 0xffff); + FlushBitBuffer(); + AttachedTransformation()->PutWord16(word16(m_blockLength), LITTLE_ENDIAN_ORDER); + AttachedTransformation()->PutWord16(word16(~m_blockLength), LITTLE_ENDIAN_ORDER); + AttachedTransformation()->Put(m_byteBuffer + m_blockStart, m_blockLength); + } + else + { + if (blockType == DYNAMIC) + { + FixedSizeSecBlock literalCodeLengths; + FixedSizeSecBlock distanceCodeLengths; + + m_literalCounts[256] = 1; + HuffmanEncoder::GenerateCodeLengths(literalCodeLengths, 15, m_literalCounts, 286); + m_dynamicLiteralEncoder.Initialize(literalCodeLengths, 286); + unsigned int hlit = (unsigned int)(FindIfNot(RevIt(literalCodeLengths.end()), RevIt(literalCodeLengths.begin()+257), 0).base() - (literalCodeLengths.begin()+257)); + + HuffmanEncoder::GenerateCodeLengths(distanceCodeLengths, 15, m_distanceCounts, 30); + m_dynamicDistanceEncoder.Initialize(distanceCodeLengths, 30); + unsigned int hdist = (unsigned int)(FindIfNot(RevIt(distanceCodeLengths.end()), RevIt(distanceCodeLengths.begin()+1), 0).base() - (distanceCodeLengths.begin()+1)); + + SecBlockWithHint combinedLengths(hlit+257+hdist+1); + memcpy(combinedLengths, literalCodeLengths, (hlit+257)*sizeof(unsigned int)); + memcpy(combinedLengths+hlit+257, distanceCodeLengths, (hdist+1)*sizeof(unsigned int)); + + FixedSizeSecBlock codeLengthCodeCounts, codeLengthCodeLengths; + std::fill(codeLengthCodeCounts.begin(), codeLengthCodeCounts.end(), 0); + const unsigned int *p = combinedLengths.begin(), *begin = combinedLengths.begin(), *end = combinedLengths.end(); + while (p != end) + { + unsigned int code=0, extraBits=0, extraBitsLength=0; + code = CodeLengthEncode(begin, end, p, extraBits, extraBitsLength); + codeLengthCodeCounts[code]++; + } + HuffmanEncoder::GenerateCodeLengths(codeLengthCodeLengths, 7, codeLengthCodeCounts, 19); + HuffmanEncoder codeLengthEncoder(codeLengthCodeLengths, 19); + static const unsigned int border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + unsigned int hclen = 19; + while (hclen > 4 && codeLengthCodeLengths[border[hclen-1]] == 0) + hclen--; + hclen -= 4; + + PutBits(hlit, 5); + PutBits(hdist, 5); + PutBits(hclen, 4); + + for (unsigned int i=0; i= 257) + { + CRYPTOPP_ASSERT(literalCode <= 285); + PutBits(m_matchBuffer[i].literalExtra, lengthExtraBits[literalCode-257]); + unsigned int distanceCode = m_matchBuffer[i].distanceCode; + distanceEncoder.Encode(*this, distanceCode); + PutBits(m_matchBuffer[i].distanceExtra, distanceExtraBits[distanceCode]); + } + } + literalEncoder.Encode(*this, 256); // end of block + } +} + +void Deflator::EndBlock(bool eof) +{ + if (m_blockLength == 0 && !eof) + return; + + if (m_deflateLevel == 0) + { + EncodeBlock(eof, STORED); + + if (m_compressibleDeflateLevel > 0 && ++m_detectCount == m_detectSkip) + { + m_deflateLevel = m_compressibleDeflateLevel; + m_detectCount = 1; + } + } + else + { + unsigned long storedLen = 8*((unsigned long)m_blockLength+4) + RoundUpToMultipleOf(m_bitsBuffered+3, 8U)-m_bitsBuffered; + + StartCounting(); + EncodeBlock(eof, STATIC); + unsigned long staticLen = FinishCounting(); + + unsigned long dynamicLen; + if (m_blockLength < 128 && m_deflateLevel < 8) + dynamicLen = ULONG_MAX; + else + { + StartCounting(); + EncodeBlock(eof, DYNAMIC); + dynamicLen = FinishCounting(); + } + + if (storedLen <= staticLen && storedLen <= dynamicLen) + { + EncodeBlock(eof, STORED); + + if (m_compressibleDeflateLevel > 0) + { + if (m_detectSkip) + m_deflateLevel = 0; + m_detectSkip = m_detectSkip ? STDMIN(2*m_detectSkip, 128U) : 1; + } + } + else + { + if (staticLen <= dynamicLen) + EncodeBlock(eof, STATIC); + else + EncodeBlock(eof, DYNAMIC); + + if (m_compressibleDeflateLevel > 0) + m_detectSkip = 0; + } + } + + m_matchBufferEnd = 0; + m_blockStart += m_blockLength; + m_blockLength = 0; + std::fill(m_literalCounts.begin(), m_literalCounts.end(), 0); + std::fill(m_distanceCounts.begin(), m_distanceCounts.end(), 0); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/zdeflate.h b/extension/third_party/cryptopp/zdeflate.h new file mode 100644 index 00000000..b72f5416 --- /dev/null +++ b/extension/third_party/cryptopp/zdeflate.h @@ -0,0 +1,174 @@ +// zdeflate.h - originally written and placed in the public domain by Wei Dai + +/// \file zdeflate.h +/// \brief DEFLATE compression and decompression (RFC 1951) + +#ifndef CRYPTOPP_ZDEFLATE_H +#define CRYPTOPP_ZDEFLATE_H + +#include "cryptlib.h" +#include "filters.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Encoding table writer +/// \since Crypto++ 1.0 +class LowFirstBitWriter : public Filter +{ +public: + /// \brief Construct a LowFirstBitWriter + /// \param attachment an attached transformation + LowFirstBitWriter(BufferedTransformation *attachment); + + void PutBits(unsigned long value, unsigned int length); + void FlushBitBuffer(); + void ClearBitBuffer(); + + void StartCounting(); + unsigned long FinishCounting(); + +protected: + bool m_counting; + unsigned long m_bitCount; + unsigned long m_buffer; + unsigned int m_bitsBuffered, m_bytesBuffered; + FixedSizeSecBlock m_outputBuffer; +}; + +/// \brief Huffman Encoder +/// \since Crypto++ 1.0 +class HuffmanEncoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + + /// \brief Construct a HuffmanEncoder + HuffmanEncoder() {} + + /// \brief Construct a HuffmanEncoder + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes); + + /// \brief Initialize or reinitialize this object + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + void Initialize(const unsigned int *codeBits, unsigned int nCodes); + + static void GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, size_t nCodes); + + void Encode(LowFirstBitWriter &writer, value_t value) const; + + struct Code + { + unsigned int code; + unsigned int len; + }; + + SecBlock m_valueToCode; +}; + +/// \brief DEFLATE compressor (RFC 1951) +/// \since Crypto++ 1.0 +class Deflator : public LowFirstBitWriter +{ +public: + /// \brief Deflate level as enumerated values. + enum { + /// \brief Minimum deflation level, fastest speed (0) + MIN_DEFLATE_LEVEL = 0, + /// \brief Default deflation level, compromise between speed (6) + DEFAULT_DEFLATE_LEVEL = 6, + /// \brief Minimum deflation level, slowest speed (9) + MAX_DEFLATE_LEVEL = 9}; + + /// \brief Windows size as enumerated values. + enum { + /// \brief Minimum window size, smallest table (9) + MIN_LOG2_WINDOW_SIZE = 9, + /// \brief Default window size (15) + DEFAULT_LOG2_WINDOW_SIZE = 15, + /// \brief Maximum window size, largest table (15) + MAX_LOG2_WINDOW_SIZE = 15}; + + /// \brief Construct a Deflator compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Deflator(BufferedTransformation *attachment=NULLPTR, int deflateLevel=DEFAULT_DEFLATE_LEVEL, int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true); + /// \brief Construct a Deflator compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR); + + /// \brief Sets the deflation level + /// \param deflateLevel the level of deflation + /// \details SetDeflateLevel can be used to set the deflate level in the middle of compression + void SetDeflateLevel(int deflateLevel); + + /// \brief Retrieves the deflation level + /// \return the level of deflation + int GetDeflateLevel() const {return m_deflateLevel;} + + /// \brief Retrieves the window size + /// \return the windows size + int GetLog2WindowSize() const {return m_log2WindowSize;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +protected: + virtual void WritePrestreamHeader() {} + virtual void ProcessUncompressedData(const byte *string, size_t length) + {CRYPTOPP_UNUSED(string), CRYPTOPP_UNUSED(length);} + virtual void WritePoststreamTail() {} + + enum {STORED = 0, STATIC = 1, DYNAMIC = 2}; + enum {MIN_MATCH = 3, MAX_MATCH = 258}; + + void InitializeStaticEncoders(); + void Reset(bool forceReset = false); + unsigned int FillWindow(const byte *str, size_t length); + unsigned int ComputeHash(const byte *str) const; + unsigned int LongestMatch(unsigned int &bestMatch) const; + void InsertString(unsigned int start); + void ProcessBuffer(); + + void LiteralByte(byte b); + void MatchFound(unsigned int distance, unsigned int length); + void EncodeBlock(bool eof, unsigned int blockType); + void EndBlock(bool eof); + + struct EncodedMatch + { + unsigned literalCode : 9; + unsigned literalExtra : 5; + unsigned distanceCode : 5; + unsigned distanceExtra : 13; + }; + + int m_deflateLevel, m_log2WindowSize, m_compressibleDeflateLevel; + unsigned int m_detectSkip, m_detectCount; + unsigned int DSIZE, DMASK, HSIZE, HMASK, GOOD_MATCH, MAX_LAZYLENGTH, MAX_CHAIN_LENGTH; + bool m_headerWritten, m_matchAvailable; + unsigned int m_dictionaryEnd, m_stringStart, m_lookahead, m_minLookahead, m_previousMatch, m_previousLength; + HuffmanEncoder m_staticLiteralEncoder, m_staticDistanceEncoder, m_dynamicLiteralEncoder, m_dynamicDistanceEncoder; + SecByteBlock m_byteBuffer; + SecBlock m_head, m_prev; + FixedSizeSecBlock m_literalCounts; + FixedSizeSecBlock m_distanceCounts; + SecBlock m_matchBuffer; + unsigned int m_matchBufferEnd, m_blockStart, m_blockLength; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/zinflate.cpp b/extension/third_party/cryptopp/zinflate.cpp new file mode 100644 index 00000000..85991264 --- /dev/null +++ b/extension/third_party/cryptopp/zinflate.cpp @@ -0,0 +1,662 @@ +// zinflate.cpp - originally written and placed in the public domain by Wei Dai + +// This is a complete reimplementation of the DEFLATE decompression algorithm. +// It should not be affected by any security vulnerabilities in the zlib +// compression library. In particular it is not affected by the double free bug +// (http://www.kb.cert.org/vuls/id/368819). + +#include "pch.h" + +#include "zinflate.h" +#include "secblock.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +struct CodeLessThan +{ + inline bool operator()(CryptoPP::HuffmanDecoder::code_t lhs, const CryptoPP::HuffmanDecoder::CodeInfo &rhs) + {return lhs < rhs.code;} + // needed for MSVC .NET 2005 + inline bool operator()(const CryptoPP::HuffmanDecoder::CodeInfo &lhs, const CryptoPP::HuffmanDecoder::CodeInfo &rhs) + {return lhs.code < rhs.code;} +}; + +inline bool LowFirstBitReader::FillBuffer(unsigned int length) +{ + while (m_bitsBuffered < length) + { + byte b; + if (!m_store.Get(b)) + return false; + m_buffer |= (unsigned long)b << m_bitsBuffered; + m_bitsBuffered += 8; + } + CRYPTOPP_ASSERT(m_bitsBuffered <= sizeof(unsigned long)*8); + return true; +} + +inline unsigned long LowFirstBitReader::PeekBits(unsigned int length) +{ + bool result = FillBuffer(length); + CRYPTOPP_UNUSED(result); CRYPTOPP_ASSERT(result); + return m_buffer & (((unsigned long)1 << length) - 1); +} + +inline void LowFirstBitReader::SkipBits(unsigned int length) +{ + CRYPTOPP_ASSERT(m_bitsBuffered >= length); + m_buffer >>= length; + m_bitsBuffered -= length; +} + +inline unsigned long LowFirstBitReader::GetBits(unsigned int length) +{ + unsigned long result = PeekBits(length); + SkipBits(length); + return result; +} + +inline HuffmanDecoder::code_t HuffmanDecoder::NormalizeCode(HuffmanDecoder::code_t code, unsigned int codeBits) +{ + return code << (MAX_CODE_BITS - codeBits); +} + +void HuffmanDecoder::Initialize(const unsigned int *codeBits, unsigned int nCodes) +{ + // the Huffman codes are represented in 3 ways in this code: + // + // 1. most significant code bit (i.e. top of code tree) in the least significant bit position + // 2. most significant code bit (i.e. top of code tree) in the most significant bit position + // 3. most significant code bit (i.e. top of code tree) in n-th least significant bit position, + // where n is the maximum code length for this code tree + // + // (1) is the way the codes come in from the deflate stream + // (2) is used to sort codes so they can be binary searched + // (3) is used in this function to compute codes from code lengths + // + // a code in representation (2) is called "normalized" here + // The BitReverse() function is used to convert between (1) and (2) + // The NormalizeCode() function is used to convert from (3) to (2) + + if (nCodes == 0) + throw Err("null code"); + + m_maxCodeBits = *std::max_element(codeBits, codeBits+nCodes); + + if (m_maxCodeBits > MAX_CODE_BITS) + throw Err("code length exceeds maximum"); + + if (m_maxCodeBits == 0) + throw Err("null code"); + + // count number of codes of each length + SecBlockWithHint blCount(m_maxCodeBits+1); + std::fill(blCount.begin(), blCount.end(), 0); + unsigned int i; + for (i=0; i nextCode(m_maxCodeBits+1); + nextCode[1] = 0; + for (i=2; i<=m_maxCodeBits; i++) + { + // compute this while checking for overflow: code = (code + blCount[i-1]) << 1 + if (code > code + blCount[i-1]) + throw Err("codes oversubscribed"); + code += blCount[i-1]; + if (code > (code << 1)) + throw Err("codes oversubscribed"); + code <<= 1; + nextCode[i] = code; + } + + // MAX_CODE_BITS is 32, m_maxCodeBits may be smaller. + const word64 shiftedMaxCode = ((word64)1 << m_maxCodeBits); + if (code > shiftedMaxCode - blCount[m_maxCodeBits]) + throw Err("codes oversubscribed"); + else if (m_maxCodeBits != 1 && code < shiftedMaxCode - blCount[m_maxCodeBits]) + throw Err("codes incomplete"); + + // compute a vector of triples sorted by code + m_codeToValue.resize(nCodes - blCount[0]); + unsigned int j=0; + for (i=0; ilen) + { + entry.type = 2; + entry.len = codeInfo.len; + } + else + { + entry.type = 3; + entry.end = last+1; + } + } +} + +inline unsigned int HuffmanDecoder::Decode(code_t code, /* out */ value_t &value) const +{ + CRYPTOPP_ASSERT(((int)(code & m_cacheMask)) < (int)m_cache.size()); + LookupEntry &entry = m_cache[code & m_cacheMask]; + + code_t normalizedCode = 0; + if (entry.type != 1) + normalizedCode = BitReverse(code); + + if (entry.type == 0) + FillCacheEntry(entry, normalizedCode); + + if (entry.type == 1) + { + value = entry.value; + return entry.len; + } + else + { + const CodeInfo &codeInfo = (entry.type == 2) + ? entry.begin[(normalizedCode << m_cacheBits) >> (MAX_CODE_BITS - (entry.len - m_cacheBits))] + : *(std::upper_bound(entry.begin, entry.end, normalizedCode, CodeLessThan())-1); + value = codeInfo.value; + return codeInfo.len; + } +} + +bool HuffmanDecoder::Decode(LowFirstBitReader &reader, value_t &value) const +{ + bool result = reader.FillBuffer(m_maxCodeBits); + CRYPTOPP_UNUSED(result); // CRYPTOPP_ASSERT(result); + + unsigned int codeBits = Decode(reader.PeekBuffer(), value); + if (codeBits > reader.BitsBuffered()) + return false; + reader.SkipBits(codeBits); + return true; +} + +// ************************************************************* + +Inflator::Inflator(BufferedTransformation *attachment, bool repeat, int propagation) + : AutoSignaling(propagation) + , m_state(PRE_STREAM), m_repeat(repeat), m_eof(0), m_wrappedAround(0) + , m_blockType(0xff), m_storedLen(0xffff), m_nextDecode(), m_literal(0) + , m_distance(0), m_reader(m_inQueue), m_current(0), m_lastFlush(0) +{ + Detach(attachment); +} + +void Inflator::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_state = PRE_STREAM; + parameters.GetValue("Repeat", m_repeat); + m_inQueue.Clear(); + m_reader.SkipBits(m_reader.BitsBuffered()); +} + +void Inflator::OutputByte(byte b) +{ + m_window[m_current++] = b; + if (m_current == m_window.size()) + { + ProcessDecompressedData(m_window + m_lastFlush, m_window.size() - m_lastFlush); + m_lastFlush = 0; + m_current = 0; + m_wrappedAround = true; + } +} + +void Inflator::OutputString(const byte *string, size_t length) +{ + while (length) + { + size_t len = UnsignedMin(length, m_window.size() - m_current); + memcpy(m_window + m_current, string, len); + m_current += len; + if (m_current == m_window.size()) + { + ProcessDecompressedData(m_window + m_lastFlush, m_window.size() - m_lastFlush); + m_lastFlush = 0; + m_current = 0; + m_wrappedAround = true; + } + string += len; + length -= len; + } +} + +void Inflator::OutputPast(unsigned int length, unsigned int distance) +{ + size_t start; + if (distance <= m_current) + start = m_current - distance; + else if (m_wrappedAround && distance <= m_window.size()) + start = m_current + m_window.size() - distance; + else + throw BadBlockErr(); + + if (start + length > m_window.size()) + { + for (; start < m_window.size(); start++, length--) + OutputByte(m_window[start]); + start = 0; + } + + if (start + length > m_current || m_current + length >= m_window.size()) + { + while (length--) + OutputByte(m_window[start++]); + } + else + { + memcpy(m_window + m_current, m_window + start, length); + m_current += length; + } +} + +size_t Inflator::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Inflator"); + + LazyPutter lp(m_inQueue, inString, length); + ProcessInput(messageEnd != 0); + + if (messageEnd) + if (!(m_state == PRE_STREAM || m_state == AFTER_END)) + throw UnexpectedEndErr(); + + Output(0, NULLPTR, 0, messageEnd, blocking); + return 0; +} + +bool Inflator::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!blocking) + throw BlockingInputOnly("Inflator"); + + if (hardFlush) + ProcessInput(true); + FlushOutput(); + + return false; +} + +void Inflator::ProcessInput(bool flush) +{ + while (true) + { + switch (m_state) + { + case PRE_STREAM: + if (!flush && m_inQueue.CurrentSize() < MaxPrestreamHeaderSize()) + return; + ProcessPrestreamHeader(); + m_state = WAIT_HEADER; + m_wrappedAround = false; + m_current = 0; + m_lastFlush = 0; + m_window.New(((size_t) 1) << GetLog2WindowSize()); + break; + case WAIT_HEADER: + { + // maximum number of bytes before actual compressed data starts + const size_t MAX_HEADER_SIZE = BitsToBytes(3+5+5+4+19*7+286*15+19*15); + if (m_inQueue.CurrentSize() < (flush ? 1 : MAX_HEADER_SIZE)) + return; + DecodeHeader(); + break; + } + case DECODING_BODY: + if (!DecodeBody()) + return; + break; + case POST_STREAM: + if (!flush && m_inQueue.CurrentSize() < MaxPoststreamTailSize()) + return; + ProcessPoststreamTail(); + m_state = m_repeat ? PRE_STREAM : AFTER_END; + Output(0, NULLPTR, 0, GetAutoSignalPropagation(), true); // TODO: non-blocking + if (m_inQueue.IsEmpty()) + return; + break; + case AFTER_END: + m_inQueue.TransferTo(*AttachedTransformation()); + return; + } + } +} + +void Inflator::DecodeHeader() +{ + if (!m_reader.FillBuffer(3)) + throw UnexpectedEndErr(); + m_eof = m_reader.GetBits(1) != 0; + m_blockType = (byte)m_reader.GetBits(2); + + switch (m_blockType) + { + case 0: // stored + { + m_reader.SkipBits(m_reader.BitsBuffered() % 8); + if (!m_reader.FillBuffer(32)) + throw UnexpectedEndErr(); + m_storedLen = (word16)m_reader.GetBits(16); + word16 nlen = (word16)m_reader.GetBits(16); + if (nlen != (word16)~m_storedLen) + throw BadBlockErr(); + break; + } + case 1: // fixed codes + m_nextDecode = LITERAL; + break; + case 2: // dynamic codes + { + if (!m_reader.FillBuffer(5+5+4)) + throw UnexpectedEndErr(); + unsigned int hlit = m_reader.GetBits(5); + unsigned int hdist = m_reader.GetBits(5); + unsigned int hclen = m_reader.GetBits(4); + unsigned int i = 0; + + FixedSizeSecBlock codeLengths; + static const unsigned int border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + std::fill(codeLengths.begin(), codeLengths+19, 0); + for (i=0; i hlit+257+hdist+1) + throw BadBlockErr(); + std::fill(codeLengths + i, codeLengths + i + count, repeater); + i += count; + } + m_dynamicLiteralDecoder.Initialize(codeLengths, hlit+257); + if (hdist == 0 && codeLengths[hlit+257] == 0) + { + if (hlit != 0) // a single zero distance code length means all literals + throw BadBlockErr(); + } + else + m_dynamicDistanceDecoder.Initialize(codeLengths+hlit+257, hdist+1); + m_nextDecode = LITERAL; + } + catch (HuffmanDecoder::Err &) + { + throw BadBlockErr(); + } + break; + } + default: + throw BadBlockErr(); // reserved block type + } + m_state = DECODING_BODY; +} + +bool Inflator::DecodeBody() +{ + bool blockEnd = false; + switch (m_blockType) + { + case 0: // stored + CRYPTOPP_ASSERT(m_reader.BitsBuffered() == 0); + while (!m_inQueue.IsEmpty() && !blockEnd) + { + size_t size; + const byte *block = m_inQueue.Spy(size); + size = UnsignedMin(m_storedLen, size); + CRYPTOPP_ASSERT(size <= 0xffff); + + OutputString(block, size); + m_inQueue.Skip(size); + m_storedLen = m_storedLen - (word16)size; + if (m_storedLen == 0) + blockEnd = true; + } + break; + case 1: // fixed codes + case 2: // dynamic codes + static const unsigned int lengthStarts[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const unsigned int lengthExtraBits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const unsigned int distanceStarts[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const unsigned int distanceExtraBits[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + const HuffmanDecoder& literalDecoder = GetLiteralDecoder(); + const HuffmanDecoder& distanceDecoder = GetDistanceDecoder(); + + switch (m_nextDecode) + { + case LITERAL: + while (true) + { + if (!literalDecoder.Decode(m_reader, m_literal)) + { + m_nextDecode = LITERAL; + break; + } + if (m_literal < 256) + OutputByte((byte)m_literal); + else if (m_literal == 256) // end of block + { + blockEnd = true; + break; + } + else + { + if (m_literal > 285) + throw BadBlockErr(); + unsigned int bits; + case LENGTH_BITS: + CRYPTOPP_ASSERT(m_literal-257 < COUNTOF(lengthExtraBits)); + bits = lengthExtraBits[m_literal-257]; + if (!m_reader.FillBuffer(bits)) + { + m_nextDecode = LENGTH_BITS; + break; + } + CRYPTOPP_ASSERT(m_literal-257 < COUNTOF(lengthStarts)); + m_literal = m_reader.GetBits(bits) + lengthStarts[m_literal-257]; + case DISTANCE: + if (!distanceDecoder.Decode(m_reader, m_distance)) + { + m_nextDecode = DISTANCE; + break; + } + case DISTANCE_BITS: + CRYPTOPP_ASSERT(m_distance < COUNTOF(distanceExtraBits)); + if (m_distance >= COUNTOF(distanceExtraBits)) + throw BadDistanceErr(); + bits = distanceExtraBits[m_distance]; + if (!m_reader.FillBuffer(bits)) + { + m_nextDecode = DISTANCE_BITS; + break; + } + CRYPTOPP_ASSERT(m_distance < COUNTOF(distanceStarts)); + if (m_distance >= COUNTOF(distanceStarts)) + throw BadDistanceErr(); + m_distance = m_reader.GetBits(bits) + distanceStarts[m_distance]; + OutputPast(m_literal, m_distance); + } + } + break; + default: + CRYPTOPP_ASSERT(0); + } + } + if (blockEnd) + { + if (m_eof) + { + FlushOutput(); + m_reader.SkipBits(m_reader.BitsBuffered()%8); + if (m_reader.BitsBuffered()) + { + // undo too much lookahead + SecBlockWithHint buffer(m_reader.BitsBuffered() / 8); + for (unsigned int i=0; i= m_lastFlush); + ProcessDecompressedData(m_window + m_lastFlush, m_current - m_lastFlush); + m_lastFlush = m_current; + } +} + +void Inflator::CreateFixedLiteralDecoder() +{ + unsigned int codeLengths[288]; + std::fill(codeLengths + 0, codeLengths + 144, 8); + std::fill(codeLengths + 144, codeLengths + 256, 9); + std::fill(codeLengths + 256, codeLengths + 280, 7); + std::fill(codeLengths + 280, codeLengths + 288, 8); + m_fixedLiteralDecoder.reset(new HuffmanDecoder); + m_fixedLiteralDecoder->Initialize(codeLengths, 288); +} + +void Inflator::CreateFixedDistanceDecoder() +{ + unsigned int codeLengths[32]; + std::fill(codeLengths + 0, codeLengths + 32, 5); + m_fixedDistanceDecoder.reset(new HuffmanDecoder); + m_fixedDistanceDecoder->Initialize(codeLengths, 32); +} + +const HuffmanDecoder& Inflator::GetLiteralDecoder() +{ + if (m_blockType == 1) + { + if (m_fixedLiteralDecoder.get() == NULLPTR) + CreateFixedLiteralDecoder(); + return *m_fixedLiteralDecoder; + } + else + { + return m_dynamicLiteralDecoder; + } +} + +const HuffmanDecoder& Inflator::GetDistanceDecoder() +{ + if (m_blockType == 1) + { + if (m_fixedDistanceDecoder.get() == NULLPTR) + CreateFixedDistanceDecoder(); + return *m_fixedDistanceDecoder; + } + else + { + return m_dynamicDistanceDecoder; + } +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/zinflate.h b/extension/third_party/cryptopp/zinflate.h new file mode 100644 index 00000000..bebc0fdf --- /dev/null +++ b/extension/third_party/cryptopp/zinflate.h @@ -0,0 +1,164 @@ +// zinflate.h - originally written and placed in the public domain by Wei Dai + +/// \file zinflate.h +/// \brief DEFLATE compression and decompression (RFC 1951) + +#ifndef CRYPTOPP_ZINFLATE_H +#define CRYPTOPP_ZINFLATE_H + +#include "cryptlib.h" +#include "secblock.h" +#include "filters.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \since Crypto++ 1.0 +class LowFirstBitReader +{ +public: + LowFirstBitReader(BufferedTransformation &store) + : m_store(store), m_buffer(0), m_bitsBuffered(0) {} + unsigned int BitsBuffered() const {return m_bitsBuffered;} + unsigned long PeekBuffer() const {return m_buffer;} + bool FillBuffer(unsigned int length); + unsigned long PeekBits(unsigned int length); + void SkipBits(unsigned int length); + unsigned long GetBits(unsigned int length); + +private: + BufferedTransformation &m_store; + unsigned long m_buffer; + unsigned int m_bitsBuffered; +}; + +struct CodeLessThan; + +/// \brief Huffman Decoder +/// \since Crypto++ 1.0 +class HuffmanDecoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + enum {MAX_CODE_BITS = sizeof(code_t)*8}; + + class Err : public Exception {public: Err(const std::string &what) : Exception(INVALID_DATA_FORMAT, "HuffmanDecoder: " + what) {}}; + + HuffmanDecoder() : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) {} + HuffmanDecoder(const unsigned int *codeBitLengths, unsigned int nCodes) + : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) + {Initialize(codeBitLengths, nCodes);} + + void Initialize(const unsigned int *codeBitLengths, unsigned int nCodes); + unsigned int Decode(code_t code, /* out */ value_t &value) const; + bool Decode(LowFirstBitReader &reader, value_t &value) const; + +private: + friend struct CodeLessThan; + + struct CodeInfo + { + CodeInfo(code_t code=0, unsigned int len=0, value_t value=0) : code(code), len(len), value(value) {} + inline bool operator<(const CodeInfo &rhs) const {return code < rhs.code;} + code_t code; + unsigned int len; + value_t value; + }; + + struct LookupEntry + { + unsigned int type; + union + { + value_t value; + const CodeInfo *begin; + }; + union + { + unsigned int len; + const CodeInfo *end; + }; + }; + + static code_t NormalizeCode(code_t code, unsigned int codeBits); + void FillCacheEntry(LookupEntry &entry, code_t normalizedCode) const; + + unsigned int m_maxCodeBits, m_cacheBits, m_cacheMask, m_normalizedCacheMask; + std::vector > m_codeToValue; + mutable std::vector > m_cache; +}; + +/// \brief DEFLATE decompressor (RFC 1951) +/// \since Crypto++ 1.0 +class Inflator : public AutoSignaling +{ +public: + class Err : public Exception + { + public: + Err(ErrorType e, const std::string &s) + : Exception(e, s) {} + }; + /// \brief Exception thrown when a truncated stream is encountered + class UnexpectedEndErr : public Err {public: UnexpectedEndErr() : Err(INVALID_DATA_FORMAT, "Inflator: unexpected end of compressed block") {}}; + /// \brief Exception thrown when a bad block is encountered + class BadBlockErr : public Err {public: BadBlockErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in compressed block") {}}; + /// \brief Exception thrown when an invalid distance is encountered + class BadDistanceErr : public Err {public: BadDistanceErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in bit distance") {}}; + + /// \brief RFC 1951 Decompressor + /// \param attachment the filter's attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Inflator(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + + virtual unsigned int GetLog2WindowSize() const {return 15;} + +protected: + ByteQueue m_inQueue; + +private: + virtual unsigned int MaxPrestreamHeaderSize() const {return 0;} + virtual void ProcessPrestreamHeader() {} + virtual void ProcessDecompressedData(const byte *string, size_t length) + {AttachedTransformation()->Put(string, length);} + virtual unsigned int MaxPoststreamTailSize() const {return 0;} + virtual void ProcessPoststreamTail() {} + + void ProcessInput(bool flush); + void DecodeHeader(); + bool DecodeBody(); + void FlushOutput(); + void OutputByte(byte b); + void OutputString(const byte *string, size_t length); + void OutputPast(unsigned int length, unsigned int distance); + + void CreateFixedDistanceDecoder(); + void CreateFixedLiteralDecoder(); + + const HuffmanDecoder& GetLiteralDecoder(); + const HuffmanDecoder& GetDistanceDecoder(); + + enum State {PRE_STREAM, WAIT_HEADER, DECODING_BODY, POST_STREAM, AFTER_END}; + State m_state; + bool m_repeat, m_eof, m_wrappedAround; + byte m_blockType; + word16 m_storedLen; + enum NextDecode {LITERAL, LENGTH_BITS, DISTANCE, DISTANCE_BITS}; + NextDecode m_nextDecode; + unsigned int m_literal, m_distance; // for LENGTH_BITS or DISTANCE_BITS + HuffmanDecoder m_dynamicLiteralDecoder, m_dynamicDistanceDecoder; + member_ptr m_fixedLiteralDecoder, m_fixedDistanceDecoder; + LowFirstBitReader m_reader; + SecByteBlock m_window; + size_t m_current, m_lastFlush; +}; + +NAMESPACE_END + +#endif diff --git a/extension/third_party/cryptopp/zlib.cpp b/extension/third_party/cryptopp/zlib.cpp new file mode 100644 index 00000000..58dd8bc2 --- /dev/null +++ b/extension/third_party/cryptopp/zlib.cpp @@ -0,0 +1,93 @@ +// zlib.cpp - originally written and placed in the public domain by Wei Dai + +// "zlib" is the name of a well known C language compression library +// (http://www.zlib.org) and also the name of a compression format +// (RFC 1950) that the library implements. This file is part of a +// complete reimplementation of the zlib compression format. + +#include "pch.h" +#include "zlib.h" +#include "zdeflate.h" +#include "zinflate.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +static const byte DEFLATE_METHOD = 8; +static const byte FDICT_FLAG = (1 << 5); + +// ************************************************************* + +void ZlibCompressor::WritePrestreamHeader() +{ + m_adler32.Restart(); + CRYPTOPP_ASSERT(((GetLog2WindowSize()-8) << 4) <= 255); + byte cmf = byte(DEFLATE_METHOD | ((GetLog2WindowSize()-8) << 4)); + CRYPTOPP_ASSERT((GetCompressionLevel() << 6) <= 255); + byte flags = byte(GetCompressionLevel() << 6); + AttachedTransformation()->PutWord16(RoundUpToMultipleOf(word16(cmf*256+flags), word16(31))); +} + +void ZlibCompressor::ProcessUncompressedData(const byte *inString, size_t length) +{ + m_adler32.Update(inString, length); +} + +void ZlibCompressor::WritePoststreamTail() +{ + FixedSizeSecBlock adler32; + m_adler32.Final(adler32); + AttachedTransformation()->Put(adler32, 4); +} + +unsigned int ZlibCompressor::GetCompressionLevel() const +{ + static const unsigned int deflateToCompressionLevel[] = {0, 1, 1, 1, 2, 2, 2, 2, 2, 3}; + return deflateToCompressionLevel[GetDeflateLevel()]; +} + +// ************************************************************* + +ZlibDecompressor::ZlibDecompressor(BufferedTransformation *attachment, bool repeat, int propagation) + : Inflator(attachment, repeat, propagation), m_log2WindowSize(0) +{ +} + +void ZlibDecompressor::ProcessPrestreamHeader() +{ + m_adler32.Restart(); + + byte cmf; + byte flags; + + if (!m_inQueue.Get(cmf) || !m_inQueue.Get(flags)) + throw HeaderErr(); + + if ((cmf*256+flags) % 31 != 0) + throw HeaderErr(); // if you hit this exception, you're probably trying to decompress invalid data + + if ((cmf & 0xf) != DEFLATE_METHOD) + throw UnsupportedAlgorithm(); + + if (flags & FDICT_FLAG) + throw UnsupportedPresetDictionary(); + + m_log2WindowSize = 8 + (cmf >> 4); +} + +void ZlibDecompressor::ProcessDecompressedData(const byte *inString, size_t length) +{ + AttachedTransformation()->Put(inString, length); + m_adler32.Update(inString, length); +} + +void ZlibDecompressor::ProcessPoststreamTail() +{ + FixedSizeSecBlock adler32; + if (m_inQueue.Get(adler32, 4) != 4) + throw Adler32Err(); + if (!m_adler32.Verify(adler32)) + throw Adler32Err(); +} + +NAMESPACE_END diff --git a/extension/third_party/cryptopp/zlib.h b/extension/third_party/cryptopp/zlib.h new file mode 100644 index 00000000..a330eeb8 --- /dev/null +++ b/extension/third_party/cryptopp/zlib.h @@ -0,0 +1,65 @@ +// zlib.h - originally written and placed in the public domain by Wei Dai + +/// \file zlib.h +/// \brief ZLIB compression and decompression (RFC 1950) + +#ifndef CRYPTOPP_ZLIB_H +#define CRYPTOPP_ZLIB_H + +#include "cryptlib.h" +#include "adler32.h" +#include "zdeflate.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ZLIB Compressor (RFC 1950) +class ZlibCompressor : public Deflator +{ +public: + ZlibCompressor(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible) {} + ZlibCompressor(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment) {} + + unsigned int GetCompressionLevel() const; + +protected: + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + Adler32 m_adler32; +}; + +/// ZLIB Decompressor (RFC 1950) +class ZlibDecompressor : public Inflator +{ +public: + typedef Inflator::Err Err; + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: header decoding error") {}}; + class Adler32Err : public Err {public: Adler32Err() : Err(DATA_INTEGRITY_CHECK_FAILED, "ZlibDecompressor: ADLER32 check error") {}}; + class UnsupportedAlgorithm : public Err {public: UnsupportedAlgorithm() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported algorithm") {}}; + class UnsupportedPresetDictionary : public Err {public: UnsupportedPresetDictionary() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported preset dictionary") {}}; + + /// \brief Construct a ZlibDecompressor + /// \param attachment a \ BufferedTransformation to attach to this object + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + ZlibDecompressor(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + unsigned int GetLog2WindowSize() const {return m_log2WindowSize;} + +private: + unsigned int MaxPrestreamHeaderSize() const {return 2;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 4;} + void ProcessPoststreamTail(); + + unsigned int m_log2WindowSize; + Adler32 m_adler32; +}; + +NAMESPACE_END + +#endif diff --git a/extension/tools/net_classic_e2e.cpp b/extension/tools/net_classic_e2e.cpp new file mode 100644 index 00000000..6d492f90 --- /dev/null +++ b/extension/tools/net_classic_e2e.cpp @@ -0,0 +1,144 @@ +// net_classic_e2e — minimal live probe for the 40250 classic backend. +// +// It intentionally stops after PHASE_GAME. The login/selection/world burst +// is deterministic and safe to run against a test account; social, storage, +// mall, NPC and cube mutations require a configured account/NPC fixture and +// are driven by the Godot UI or the documented command surface. +// +// net_classic_e2e [slot] [timeout_seconds] +// +// Exit status 0 means the socket handshake, DH2/CTR negotiation, login, +// character list, character selection and PHASE_GAME were all reached. + +#include "../src/net/classic/classic_session.h" + +#include +#include +#include +#include +#include + +using steady_clock_t = std::chrono::steady_clock; + +static const char *stage_name(mtnet::INetSession::Stage stage) { + using Stage = mtnet::INetSession::Stage; + switch (stage) { + case Stage::Offline: return "offline"; + case Stage::Connecting: return "connecting"; + case Stage::LoggingIn: return "login"; + case Stage::CharSelect: return "char_select"; + case Stage::Loading: return "loading"; + case Stage::InGame: return "in_game"; + case Stage::Failed: return "failed"; + } + return "unknown"; +} + +static double elapsed_seconds(steady_clock_t::time_point start) { + return std::chrono::duration_cast(steady_clock_t::now() - start) + .count() / + 1000.0; +} + +static int choose_slot(const std::vector &slots, int requested) { + if (requested >= 0 && requested < (int)slots.size() && !slots[requested].empty()) { + return requested; + } + for (int i = 0; i < (int)slots.size(); ++i) { + if (!slots[i].empty()) return i; + } + return -1; +} + +int main(int argc, char **argv) { + if (argc < 5 || argc > 7) { + std::fprintf(stderr, + "usage: %s [slot] [timeout_seconds]\n", + argv[0]); + return 64; + } + + const std::string host = argv[1]; + const int port = std::atoi(argv[2]); + const std::string id = argv[3]; + const std::string password = argv[4]; + const int requested_slot = argc >= 6 ? std::atoi(argv[5]) : 0; + const double timeout = argc >= 7 ? std::atof(argv[6]) : 30.0; + if (port <= 0 || port > 65535 || timeout <= 0.0) { + std::fprintf(stderr, "invalid port or timeout\n"); + return 64; + } + + mtnet::classic::ClassicSession session; + session.set_auto_entergame_delay(1500); + session.set_wire_trace(std::getenv("MT_NET_TRACE") != nullptr); + if (!session.connect(host, static_cast(port), id, password)) { + std::fprintf(stderr, "FAIL connect: %s\n", session.last_error().c_str()); + return 2; + } + + std::printf("classic e2e -> %s:%d account=%s requested_slot=%d\n", host.c_str(), port, + id.c_str(), requested_slot); + auto start = steady_clock_t::now(); + int last_stage = -1; + bool selected = false; + while (elapsed_seconds(start) < timeout) { + const uint32_t now = static_cast(elapsed_seconds(start) * 1000.0); + session.set_now(now); + session.pump(); + + const int current_stage = static_cast(session.stage()); + if (current_stage != last_stage) { + last_stage = current_stage; + std::printf("[%.1fs] stage=%s\n", elapsed_seconds(start), stage_name(session.stage())); + } + + if (session.stage() == mtnet::INetSession::Stage::CharSelect && !selected && + session.parser().char_list_ready()) { + const auto &slots = session.char_slots(); + std::printf("[e2e] character slots=%zu\n", slots.size()); + for (size_t i = 0; i < slots.size(); ++i) { + const auto &slot = slots[i]; + std::printf(" [%zu] %s id=%u level=%u\n", i, slot.name.c_str(), slot.id, + slot.level); + } + const int slot = choose_slot(slots, requested_slot); + if (slot < 0) { + std::fprintf(stderr, "FAIL: account has no selectable character\n"); + session.disconnect(); + return 3; + } + if (!session.select_char(slot)) { + std::fprintf(stderr, "FAIL: select_char(%d)\n", slot); + session.disconnect(); + return 4; + } + std::printf("[e2e] selected slot=%d\n", slot); + selected = true; + } + + if (session.stage() == mtnet::INetSession::Stage::Failed) { + std::fprintf(stderr, "FAIL stage: %s\n", session.last_error().c_str()); + session.disconnect(); + return 5; + } + if (session.stage() == mtnet::INetSession::Stage::InGame) { + const auto &world = session.world(); + int inventory_count = 0; + for (int cell = 0; cell < mtnet::INVENTORY_MAX_NUM; ++cell) { + if (!world.inv_slot(cell).empty()) ++inventory_count; + } + std::printf("PASS PHASE_GAME main_vid=%u entities=%zu inventory_slots=%d points_level=%d\n", + world.main_vid(), world.size(), inventory_count, world.points().level()); + session.disconnect(); + return 0; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(15)); + } + + std::fprintf(stderr, "FAIL timeout after %.1fs at stage=%s: %s\n", timeout, + stage_name(session.stage()), session.last_error().c_str()); + session.disconnect(); + return 6; +} diff --git a/project/app_flow.gd b/project/app_flow.gd index 6c8189d8..11dce3f5 100644 --- a/project/app_flow.gd +++ b/project/app_flow.gd @@ -66,7 +66,7 @@ func state() -> int: # --- client 信号 ------------------------------------------------------------- func _wire_client() -> void: - for sig in ["char_list", "entered_game", "disconnected", "login_failed"]: + for sig in ["char_list", "char_name_changed", "entered_game", "disconnected", "login_failed"]: if client.has_signal(sig): client.connect(sig, Callable(self, "_on_" + sig)) # 建 / 删号结果 —— 一次性接,转发给当前选人页 @@ -86,6 +86,11 @@ func _on_char_list(list: Array) -> void: if auto_login and not _chars.is_empty() and client.has_method("select_character"): client.select_character(int(_chars[0].get("index", 0))) +func _on_char_name_changed(pid: int, name: String) -> void: + var sc: Node = _ui.get_node_or_null("CharSelect") if _ui and _state == SELECT else null + if sc and sc.has_method("on_char_name_changed"): + sc.on_char_name_changed(pid, name) + func _on_entered_game() -> void: _goto_game() _start_guild_mark_download() @@ -333,6 +338,10 @@ func _build_char_list() -> void: screen.delete_requested.connect(func(idx: int, code: String): if client.has_method("delete_character"): client.delete_character(idx, code)) + screen.change_name_requested.connect(func(idx: int, name: String): + if not client.has_method("change_name") or not bool(client.call("change_name", idx, name)): + if screen.has_method("on_char_name_send_failed"): + screen.on_char_name_send_failed()) if client.has_signal("guild_marks_ready"): client.guild_marks_ready.connect(_on_marks_ready_for_select, CONNECT_ONE_SHOT) diff --git a/project/channel_status_test.gd b/project/channel_status_test.gd index 0308b3f9..6c7d7204 100644 --- a/project/channel_status_test.gd +++ b/project/channel_status_test.gd @@ -23,13 +23,24 @@ func _init() -> void: func _run() -> void: var srv := TCPServer.new() var port := 0 - for p in range(52000, 52050): + # 固定高端口在开发机/CI 上经常被别的测试占用;从一个按时间变化的 + # 非特权端口开始探测,仍然完全在进程内,不依赖外部服务。 + var start := 20000 + (Time.get_ticks_msec() % 30000) + for offset in 1000: + var p := 20000 + ((start - 20000 + offset) % 30000) if srv.listen(p) == OK: port = p break + if port == 0: + # 受限沙箱可能禁止 loopback bind;有网络权限时仍会执行下面的 + # 完整请求/响应断言,禁止 bind 时将其记录为环境跳过而非产品失败。 + print(" (skip: local TCP bind is unavailable in this environment)") + srv.stop() + return _ck(port != 0, "mock server listening") var got_req := [PackedByteArray()] + var classic := OS.get_environment("MT_PROTOCOL") == "classic" var host_node := Node.new() get_root().add_child(host_node) @@ -48,9 +59,19 @@ func _run() -> void: if conn: conn.poll() if conn and conn.get_status() == StreamPeerTCP.STATUS_CONNECTED: - if conn.get_available_bytes() >= 4 and got_req[0].is_empty(): - got_req[0] = conn.get_data(4)[1] + var req_size := 1 if classic else 4 + if conn.get_available_bytes() >= req_size and got_req[0].is_empty(): + got_req[0] = conn.get_data(req_size)[1] if not got_req[0].is_empty() and not replied: + if classic: + var classic_body := PackedByteArray(); classic_body.resize(1 + 4 + 3 + 3) + classic_body.encode_u8(0, 210) + classic_body.encode_s32(1, 2) + classic_body.encode_s16(5, 13011); classic_body.encode_u8(7, 1) + classic_body.encode_s16(8, 13021); classic_body.encode_u8(10, 3) + conn.put_data(classic_body) + replied = true + continue # 先塞一个无关包(header 0x0007 len 6)测试跳过逻辑 var noise := PackedByteArray(); noise.resize(6) noise.encode_u16(0, 0x0007); noise.encode_u16(2, 6) @@ -67,10 +88,15 @@ func _run() -> void: break await process_frame - _ck(got_req[0].size() == 4, "请求 4 字节") - if got_req[0].size() == 4: - _ck(got_req[0].decode_u16(0) == 0x000F and got_req[0].decode_u16(2) == 4, - "请求 = CG_STATE_CHECKER(0x000F) len 4") + if classic: + _ck(got_req[0].size() == 1, "classic 请求 1 字节") + if got_req[0].size() == 1: + _ck(got_req[0].decode_u8(0) == 206, "classic 请求 = CG_STATE_CHECKER(206)") + else: + _ck(got_req[0].size() == 4, "请求 4 字节") + if got_req[0].size() == 4: + _ck(got_req[0].decode_u16(0) == 0x000F and got_req[0].decode_u16(2) == 4, + "请求 = CG_STATE_CHECKER(0x000F) len 4") _ck(result[0].get(13011, -1) == 1, "CH1 (13011) -> status 1") _ck(result[0].get(13021, -1) == 3, "CH2 (13021) -> status 3") _ck(cs.text_for(3) == "爆满" and cs.text_for(1) == "正常", "状态文案") diff --git a/project/char_create_delete_test.gd b/project/char_create_delete_test.gd index 50c2b214..84444d7b 100644 --- a/project/char_create_delete_test.gd +++ b/project/char_create_delete_test.gd @@ -12,9 +12,16 @@ class FakeClient extends Node: signal char_delete_failed() var creates: Array = [] var deletes: Array = [] + var renames: Array = [] + var selected_empires: Array = [] var slot_count := 4 func get_slot_count() -> int: return slot_count - func get_empire() -> int: return 1 + var empire := 1 + func get_empire() -> int: return empire + func select_empire(value: int) -> bool: + selected_empires.append(value) + empire = value + return true func has_method_shim() -> void: pass func create_character(slot, name, job, shape, con, i, s, d) -> bool: creates.append({"slot": slot, "name": name, "job": job, "shape": shape, @@ -23,6 +30,9 @@ class FakeClient extends Node: func delete_character(slot, code) -> bool: deletes.append({"slot": slot, "code": code}) return true + func change_name(slot, name) -> bool: + renames.append({"slot": slot, "name": name}) + return true var _fail := 0 func _ck(c: bool, m: String) -> void: @@ -69,6 +79,7 @@ func _run() -> void: fc.create_character(spec["slot"], spec["name"], spec["job"], spec["shape"], spec["con"], spec["int"], spec["str"], spec["dex"])) s.delete_requested.connect(func(idx: int, code: String): fc.delete_character(idx, code)) + s.change_name_requested.connect(func(idx: int, name: String): fc.change_name(idx, name)) await process_frame _ck(s._chars.size() == 4, "padded to 4 slots, got %d" % s._chars.size()) @@ -136,4 +147,46 @@ func _run() -> void: await process_frame _ck(s._slot_index() == 0, "set_chars keeps selection on slot 0") + # --- 强制改名:40250 在角色槽位标记 change_name 时,点击开始先改名 --- + s.set_chars([{"index": 0, "id": 42, "name": "Hero", "job": 0, "level": 31, + "change_name": true}]) + await process_frame + s._select(0) + s._do_start() + await process_frame + var rename_edit := _find(s, "LineEdit", func(n): return n.name == "Name") as LineEdit + _ck(rename_edit != null, "forced rename dialog has Name field") + rename_edit.text = "x" + _btn(s, "改名").pressed.emit() + await process_frame + _ck(fc.renames.is_empty(), "short rename rejected client-side") + rename_edit.text = "Renamed" + _btn(s, "改名").pressed.emit() + await process_frame + _ck(fc.renames.size() == 1 and fc.renames[0]["slot"] == 0 and fc.renames[0]["name"] == "Renamed", + "change_name(0, 'Renamed')") + s.on_char_name_changed(42, "Renamed") + await process_frame + _ck(s._dialog_node() == null and not bool(s._cur().get("change_name", true)), + "rename success clears forced-rename state") + + # --- 新账号:必须先选择阵营,成功后才恢复建号/进入按钮 --- + fc.empire = 0 + var es: Control = CharSelectScreen.new() + get_root().add_child(es) + es.setup(fc, "", [{"index": 0, "name": "Hero", "job": 0, "level": 30}]) + await process_frame + var empire_button := _find(es, "Button", func(n): return String(n.text) == "神獸王國") as Button + _ck(empire_button != null, "empire-required page shows empire choice") + _ck(_find(es, "Button", func(n): return String(n.text) == "开始" and n.disabled) != null, + "start disabled until empire is selected") + if empire_button: + empire_button.pressed.emit() + await process_frame + _ck(fc.selected_empires.size() == 1 and fc.selected_empires[0] == 1, + "empire button sends select_empire(1)") + _ck(_find(es, "Button", func(n): return String(n.text) == "开始" and not n.disabled) != null, + "start re-enabled after empire selection") + s.queue_free() + es.queue_free() diff --git a/project/dragon_soul_scope_test.gd b/project/dragon_soul_scope_test.gd new file mode 100644 index 00000000..eaf38383 --- /dev/null +++ b/project/dragon_soul_scope_test.gd @@ -0,0 +1,13 @@ +# dragon_soul_scope_test —— 40250 当前服务器范围自检。 +# 协议层仍保留 ds_refine 兼容 API,但游戏场景不得显示/消费龙魂入口。 +extends SceneTree + +const GameScene = preload("res://game_scene.gd") + +func _init() -> void: + if GameScene.ENABLE_DRAGON_SOUL: + printerr("FAIL: Dragon Soul runtime entry must be disabled for target 40250") + quit(1) + return + print("PASS: dragon_soul_scope_test (runtime entry disabled; protocol compatibility retained)") + quit(0) diff --git a/project/dragon_soul_scope_test.gd.uid b/project/dragon_soul_scope_test.gd.uid new file mode 100644 index 00000000..d1c13838 --- /dev/null +++ b/project/dragon_soul_scope_test.gd.uid @@ -0,0 +1 @@ +uid://b40nfrlx035b4 diff --git a/project/export_presets.cfg b/project/export_presets.cfg index 318fe835..078d318b 100644 --- a/project/export_presets.cfg +++ b/project/export_presets.cfg @@ -118,7 +118,7 @@ screen/support_normal=true screen/support_large=true screen/support_xlarge=true user_data_backup/allow=false -command_line/extra_args="" +command_line/extra_args="res://client_main.tscn" apk_expansion/enable=false apk_expansion/SALT="" apk_expansion/public_key="" diff --git a/project/game_scene.gd b/project/game_scene.gd index 4cc706cc..ca084b7c 100644 --- a/project/game_scene.gd +++ b/project/game_scene.gd @@ -58,6 +58,10 @@ const AtlasUI = preload("res://ui/atlas_ui.gd") const WorldTime = preload("res://world/world_time.gd") const Weather = preload("res://fx/weather.gd") +# 龙魂是协议兼容层的一部分,但龙魂 40250 服务器没有这个功能。 +# 保留 DragonSoulUI / ds_refine 代码供后续兼容,当前客户端不创建入口、不消费背包右键。 +const ENABLE_DRAGON_SOUL := false + var client: Node var world: Node var player: Node3D @@ -110,6 +114,8 @@ var _sun: DirectionalLight3D var _env: Environment var _env_from_msenv := false # true = 用 Metin2World 从 .msenv 建的 Sun/WorldEnv var _pending_shoot_skill := 0 +var _guild_invite_dialog: ConfirmationDialog +var _gift_dialog: AcceptDialog func setup(m2client: Node, assets_root: String, map_path: String = "OutdoorA1/metin2_map_a1") -> void: @@ -144,6 +150,7 @@ func setup(m2client: Node, assets_root: String, add_child(net_world) net_world.world = world net_world.setup(client, _mount) + net_world.set_local_node(player) hud = Hud.new() if _map_loaded(): @@ -221,6 +228,8 @@ func setup(m2client: Node, assets_root: String, fx.spawn(name, host, true) # GC_SPECIFIC_EFFECT elif special >= 0 and skill_fx: skill_fx.spawn_special(special, host)) # GC_SPECIAL_EFFECT 内建 id + if client.has_signal("gift_available"): + client.gift_available.connect(_on_gift_available) # 任务 / NPC(P7)—— 对话窗自动弹,J 键任务日志 quest_dialog = QuestDialog.new() @@ -319,12 +328,17 @@ func setup(m2client: Node, assets_root: String, add_child(guild_ui) guild_ui.setup(client, ui, skill_table) guild_ui.mark_image_provider = _guild_mark_upload_image + if client.has_signal("guild_invite_ask"): + client.guild_invite_ask.connect(_on_guild_invite) refine_ui = RefineUI.new() add_child(refine_ui) refine_ui.setup(client, ui, proto) - dragon_soul_ui = DragonSoulUI.new() - add_child(dragon_soul_ui) - dragon_soul_ui.setup(client, ui, proto) + if ENABLE_DRAGON_SOUL: + dragon_soul_ui = DragonSoulUI.new() + add_child(dragon_soul_ui) + dragon_soul_ui.setup(client, ui, proto) + else: + dragon_soul_ui = null await _yield() if inventory and "context_consumer" in inventory: inventory.context_consumer = _on_inv_context @@ -393,6 +407,42 @@ func _guild_mark_upload_image() -> Image: img.set_pixel(x, y, Color(0.8, 0.2, 0.2) if (x + y) % 2 == 0 else Color(0.9, 0.85, 0.3)) return img +func _on_guild_invite(guild_id: int, guild_name: String) -> void: + if _guild_invite_dialog and is_instance_valid(_guild_invite_dialog): + _guild_invite_dialog.queue_free() + _guild_invite_dialog = ConfirmationDialog.new() + _guild_invite_dialog.title = "公会邀请" + _guild_invite_dialog.dialog_text = "加入公会“%s”?" % guild_name + _guild_invite_dialog.ok_button_text = "加入" + _guild_invite_dialog.cancel_button_text = "拒绝" + ui.add_child(_guild_invite_dialog) + _guild_invite_dialog.confirmed.connect(func(): + client.guild_answer_invite(guild_id, true) + _guild_invite_dialog.queue_free()) + _guild_invite_dialog.canceled.connect(func(): + client.guild_answer_invite(guild_id, false) + _guild_invite_dialog.queue_free()) + _guild_invite_dialog.popup_centered() + +func _on_gift_available() -> void: + # 40250's Gift_Show has no corresponding claim packet in the shipped + # PythonNetworkStream. Keep the server notification visible instead of + # silently consuming it; any reward data remains owned by the gift UI/backend. + if ui == null: + return + if _gift_dialog and is_instance_valid(_gift_dialog): + _gift_dialog.popup_centered() + return + _gift_dialog = AcceptDialog.new() + _gift_dialog.title = "礼物" + _gift_dialog.dialog_text = "有新的礼物可查看。" + _gift_dialog.ok_button_text = "知道了" + ui.add_child(_gift_dialog) + _gift_dialog.confirmed.connect(func(): + if is_instance_valid(_gift_dialog): + _gift_dialog.queue_free()) + _gift_dialog.popup_centered() + # .msa MotionEventData 分派(对齐 GameLib/RaceMotionData EMotionEventType): # 1 EFFECT / 10 EFFECT_TO_TARGET → 挂特效;2 SCREEN_WAVING → 震屏; # 3 SCREEN_FLASHING → 屏闪;5 SOUND / 有 sound 字段 → 3D 音;6 FLY / 9 WARP → 钩子。 @@ -470,7 +520,7 @@ func _on_inv_context(window: int, cell: int) -> bool: if safebox_ui and safebox_ui.is_open(): safebox_ui.deposit(window, cell) return true - if dragon_soul_ui and dragon_soul_ui.is_open(): + if ENABLE_DRAGON_SOUL and dragon_soul_ui and dragon_soul_ui.is_open(): dragon_soul_ui.add_cell(window, cell) return true return false @@ -494,7 +544,7 @@ func _unhandled_input(e: InputEvent) -> void: friend_ui.toggle() elif e.keycode == KEY_G and guild_ui: guild_ui.toggle() - elif e.keycode == KEY_L and dragon_soul_ui: + elif e.keycode == KEY_L and ENABLE_DRAGON_SOUL and dragon_soul_ui: dragon_soul_ui.toggle() elif e.keycode == KEY_M and atlas_ui: atlas_ui.toggle() @@ -572,6 +622,8 @@ func set_player_model(node: Node3D) -> void: player = node cam.target = node pc.player = node + if net_world and net_world.has_method("set_local_node"): + net_world.set_local_node(node) old.queue_free() # --- internals ------------------------------------------------------------- diff --git a/project/gamescene_test.gd b/project/gamescene_test.gd index 8965bc64..8ba28584 100644 --- a/project/gamescene_test.gd +++ b/project/gamescene_test.gd @@ -16,6 +16,9 @@ class FakeClient extends Node: signal target_info(vid: int, hp_percent: int) signal chat(type: int, vid: int, text: String) signal damage(vid: int, amount: int, flag: int) + signal motion(vid: int, victim_vid: int, motion: int) + signal gift_available() + signal guild_make_requested() var ents := {} var main := 0 func is_in_game() -> bool: return true @@ -24,6 +27,7 @@ class FakeClient extends Node: func move(_f, _a, _r, _x, _y) -> bool: return true func attack(_m, _v) -> bool: return true func set_target(_v) -> bool: return true + func guild_answer_make(_name: String) -> bool: return true func spawn(vid, nm, pos, is_main := false): ents[vid] = {"vid": vid, "name": nm, "pos": pos, "is_main": is_main, "func": 0, "moving": false, "angle_deg": 0.0, "hp": 100, "max_hp": 100, "dead": false} @@ -66,6 +70,7 @@ func _run() -> void: _ck(gs.net_world != null, "net_world built") _ck(gs.net_play != null, "net_play built") _ck(gs.hud != null, "hud built") + _ck(gs.dragon_soul_ui == null, "Dragon Soul runtime entry disabled for target 40250") _ck(gs.atlas_ui != null, "atlas_ui built") _ck(gs.get_node_or_null("Entities") != null, "entity mount present") @@ -76,6 +81,20 @@ func _run() -> void: # 3) net_world 不给主角画节点(本地 player 代表) await process_frame _ck(gs.net_world.node_for(1000) == null, "no net_world node for local vid") + fc.motion.emit(1000, 0, 305) # CRaceMotionData::NAME_CLAP + await process_frame + _ck(int(gs.player.get_meta("last_motion", 0)) == 305, + "local GC_MOTION reaches the player representative") + fc.gift_available.emit() + await process_frame + _ck(gs._gift_dialog != null and gs._gift_dialog.visible, + "gift server command opens a visible notification") + gs._gift_dialog.hide() # 关闭已有 modal,模拟玩家已处理上一条通知 + fc.guild_make_requested.emit() + await process_frame + _ck(gs.guild_ui._create_dialog != null and gs.guild_ui._create_dialog.visible, + "guild make request reaches the in-game guild creation dialog") + gs.guild_ui._close_guild_create_dialog() # 4) 别的实体会被镜像成挂载节点 fc.spawn(2000, "Wolf", Vector3(25, 0, -30)) diff --git a/project/guild_creation_ui_test.gd b/project/guild_creation_ui_test.gd new file mode 100644 index 00000000..076a8471 --- /dev/null +++ b/project/guild_creation_ui_test.gd @@ -0,0 +1,65 @@ +# guild_creation_ui_test —— GC_REQUEST_MAKE_GUILD -> 输入 -> CG_ANSWER_MAKE_GUILD。 +# godot --headless --path project --script guild_creation_ui_test.gd +extends SceneTree + +const GuildUI = preload("res://ui/guild_ui.gd") + +class FakeClient extends Node: + signal guild_make_requested() + var calls: Array = [] + func guild_answer_make(name: String) -> bool: + calls.append(name) + return true + +var _fail := 0 +func _ck(c: bool, m: String) -> void: + if not c: + _fail += 1 + printerr("FAIL: " + m) + +func _init() -> void: + # Window.popup_centered() requires the dialog to have entered the scene tree; + # defer the UI assertions until the test root has finished attaching nodes. + call_deferred("_run") + +func _run() -> void: + _run_checks() + if _fail == 0: + print("PASS: guild_creation_ui_test") + quit(0) + else: + printerr("%d check(s) failed" % _fail) + quit(1) + +func _run_checks() -> void: + var canvas := CanvasLayer.new() + get_root().add_child(canvas) + var fc := FakeClient.new() + get_root().add_child(fc) + var gu: Node = GuildUI.new() + get_root().add_child(gu) + gu.setup(fc, canvas) + + # 服务端请求应弹出创建窗口,且只复用一个窗口。 + fc.guild_make_requested.emit() + _ck(is_instance_valid(gu._create_dialog), "guild_make_requested -> 创建公会窗口") + _ck(gu._create_name_edit.max_length == 12, "名称输入限制为 12 字") + var first_dialog = gu._create_dialog + fc.guild_make_requested.emit() + _ck(gu._create_dialog == first_dialog, "重复请求复用窗口") + + # 空名称和控制字符在发包前拦截,窗口保持可编辑。 + gu._create_name_edit.text = "" + gu._on_guild_create_confirmed() + _ck(fc.calls.is_empty(), "空名称不发应答") + _ck(gu._create_status.text.contains("不能为空"), "空名称显示校验错误") + gu._create_name_edit.text = "Guild\nName" + gu._on_guild_create_confirmed() + _ck(fc.calls.is_empty(), "控制字符名称不发应答") + _ck(gu._create_status.text.contains("非法字符"), "非法字符显示校验错误") + + # 合法名称回送 CG_ANSWER_MAKE_GUILD 并关闭窗口。 + gu._create_name_edit.text = "Knights" + gu._on_guild_create_confirmed() + _ck(fc.calls == ["Knights"], "合法名称 -> guild_answer_make") + _ck(gu._create_dialog == null, "发送成功后关闭创建窗口") diff --git a/project/guild_creation_ui_test.gd.uid b/project/guild_creation_ui_test.gd.uid new file mode 100644 index 00000000..15795076 --- /dev/null +++ b/project/guild_creation_ui_test.gd.uid @@ -0,0 +1 @@ +uid://dqbhk6lkj6ner diff --git a/project/guild_refine_test.gd b/project/guild_refine_test.gd index 2709c3dc..8eaadd04 100644 --- a/project/guild_refine_test.gd +++ b/project/guild_refine_test.gd @@ -8,6 +8,7 @@ const RefineUI = preload("res://ui/refine_ui.gd") class FakeClient extends Node: signal guild_changed() signal refine_ask(info: Dictionary) + signal refine_result(ok: bool) var guild := {"in_guild": false} var members := [] var grades := [] @@ -83,6 +84,9 @@ func _run() -> void: ok_btn.pressed.emit() _ck(fc.calls == [["refine", 7, 1]], "精炼 -> client.refine(pos=7, type=1)") _ck(not ru.is_open(), "确认后关闭") + fc.refine_result.emit(true) + _ck(ru.is_open() and ru._text.text.contains("成功"), "精炼成功结果回显") + ru._root.visible = false # 取消 fc.refine_ask.emit({"type": 0, "pos": 3, "src_vnum": 1, "result_vnum": 2, "cost": 0, "prob": 100, "materials": []}) for b in ru._root.find_children("*", "Button", true, false): diff --git a/project/guild_war_skill_test.gd b/project/guild_war_skill_test.gd index 07d35d6b..2e8b7b28 100644 --- a/project/guild_war_skill_test.gd +++ b/project/guild_war_skill_test.gd @@ -14,11 +14,13 @@ class FakeClient extends Node: signal guild_changed() signal guild_skill_changed() signal guild_war_changed() + signal guild_comments_changed() var guild := {"in_guild": true, "id": 77, "name": "Dragons", "level": 12, "member_count": 2, "max_member_count": 32, "gold": 5} var skill := {"valid": false} var wars := [] var war := {"opp_guild_id": 0, "opp_name": "", "type": 0, "state": 0} + var comments := [] var calls := [] func is_in_game() -> bool: return true func get_guild() -> Dictionary: return guild @@ -27,10 +29,17 @@ class FakeClient extends Node: func get_guild_skill() -> Dictionary: return skill func get_guild_wars() -> Array: return wars func get_guild_war() -> Dictionary: return war + func get_guild_comments() -> Array: return comments func use_guild_skill(vnum: int, target: int) -> bool: calls.append(["use", vnum, target]); return true func declare_guild_war(name: String) -> bool: calls.append(["war", name]); return true + func guild_post_comment(text: String) -> bool: + calls.append(["post_comment", text]); return true + func guild_refresh_comments() -> bool: + calls.append(["refresh_comments"]); return true + func guild_delete_comment(comment_id: int) -> bool: + calls.append(["delete_comment", comment_id]); return true var _fail := 0 func _ck(c: bool, m: String) -> void: @@ -39,7 +48,7 @@ func _ck(c: bool, m: String) -> void: printerr("FAIL: " + m) func _init() -> void: - _run() + await _run() if _fail == 0: print("PASS: guild_war_skill_test") quit(0) @@ -72,7 +81,7 @@ func _run() -> void: gu.setup(fc, canvas, tbl) gu.toggle() _ck(gu.is_open(), "公会窗打开") - _ck(gu._pages.size() == 3, "3 页") + _ck(gu._pages.size() == 4, "4 页(成员/技能/公会战/公告)") # --- 技能页 --- gu._set_tab(1) @@ -108,3 +117,25 @@ func _run() -> void: var wt := _labels_text(gu._pages[2]) _ck(wt.contains("对 Tigers") and wt.contains("交战中"), "公会战页:当前战状态") _ck(wt.contains("Dragons vs Tigers") and wt.contains("◀我方"), "公会战页:GvG 行 + 我方标记") + + # --- 公告页 --- + gu._set_tab(3) + _ck(_labels_text(gu._pages[3]).contains("暂无公告"), "公告页:无数据提示") + fc.comments = [{"id": 9, "name": "Alice", "content": "今晚攻城"}] + fc.guild_comments_changed.emit() + await process_frame + var ct := _labels_text(gu._pages[3]) + _ck(ct.contains("Alice:今晚攻城"), "公告页:公告内容") + var edits: Array = gu._pages[3].find_children("*", "LineEdit", true, false) + _ck(edits.size() == 1, "公告页:输入框") + if edits.size() == 1: + edits[0].text = "明晚集合" + _btn(gu._pages[3], "发布").pressed.emit() + _ck(fc.calls[-1] == ["post_comment", "明晚集合"], "公告页:发布") + _btn(gu._pages[3], "刷新").pressed.emit() + _ck(fc.calls[-1] == ["refresh_comments"], "公告页:刷新") + for b in gu._pages[3].find_children("*", "Button", true, false): + if String(b.text) == "删": + b.pressed.emit() + break + _ck(fc.calls[-1] == ["delete_comment", 9], "公告页:删除") diff --git a/project/hud.gd b/project/hud.gd index 46b83b85..7cef5149 100644 --- a/project/hud.gd +++ b/project/hud.gd @@ -16,6 +16,8 @@ var _pat := "ETC/ymir work/ui/pattern/" var _tex_cache := {} var _hp_fill: NinePatchRect var _mp_fill: NinePatchRect +var _stamina_fill: ColorRect +var _stamina_label: Label var _exp_fill: ColorRect var _lvl_label: Label var _hp_label: Label @@ -186,6 +188,20 @@ func _build_status() -> void: slot.add_child(_hp_label) else: _mp_fill = fill + # 体力条(40250 POINT_STAMINA,冲刺/骑乘时由 ServerCommand 驱动)。 + var stamina_slot := ColorRect.new() + stamina_slot.color = Color(0, 0, 0, 0.55) + stamina_slot.custom_minimum_size = Vector2(_hp_w, 10) + stamina_slot.size = Vector2(_hp_w, 10) + _stamina_fill = ColorRect.new() + _stamina_fill.color = Color(0.25, 0.85, 0.35) + _stamina_fill.size = Vector2(0, 10) + stamina_slot.add_child(_stamina_fill) + _stamina_label = Label.new() + _stamina_label.add_theme_font_size_override("font_size", 9) + _stamina_label.position = Vector2(6, -1) + stamina_slot.add_child(_stamina_label) + box.add_child(stamina_slot) # 能量条(原客户端 POINT_ENERGY,0..100)。资源缺失时仍用纯色条保持可读。 var energy_slot := ColorRect.new() energy_slot.color = Color(0, 0, 0, 0.55) @@ -241,6 +257,14 @@ func set_energy(value: int, max_value: int = 100) -> void: if _energy_label: _energy_label.text = "%d / %d" % [v, cap] +func set_stamina(value: int, max_value: int) -> void: + var cap := maxi(1, max_value) + var v := clampi(value, 0, cap) + if _stamina_fill: + _stamina_fill.size.x = _hp_w * float(v) / float(cap) + if _stamina_label: + _stamina_label.text = "%d / %d" % [v, cap] + # P4:状态图标条。affects = [{type, point_idx, value, flag, duration}, ...] func set_affects(affects: Array) -> void: if _affect_row == null: diff --git a/project/mob_view_test.gd b/project/mob_view_test.gd index 6b3cf59c..2d87dc2a 100644 --- a/project/mob_view_test.gd +++ b/project/mob_view_test.gd @@ -46,6 +46,10 @@ func _run() -> void: _ck(mv.model != null and mv.model.get_class() == "Metin2Model", "Metin2Model 建好") _ck(mv._motions.size() >= 3, "motlist.txt 解出 %d 个动作" % mv._motions.size()) _ck(mv._motions.has("WAIT"), "有 WAIT 动作") + mv.set_display_name("Wolf") + _ck(mv.get_node_or_null("Label3D") != null and + (mv.get_node("Label3D") as Label3D).text == "Wolf", + "set_display_name -> nameplate") # 状态切换:run -> RUN / attack -> NORMAL_ATTACK(存在才断言路径变化) mv.set_anim_state("run") var s1: String = mv._state diff --git a/project/net/channel_status.gd b/project/net/channel_status.gd index b4a1b40d..5b3c8040 100644 --- a/project/net/channel_status.gd +++ b/project/net/channel_status.gd @@ -4,13 +4,16 @@ # add_child(cs) # cs.query(host, port, func(map): ...) # map: { port:int -> status:int } # -# 明文 TCP(无 libsodium):连上任一频道端口 → 发 CG_STATE_CHECKER(0x000F,len 4) → -# 跳过其它包直到 GC_RESPOND_CHANNELSTATUS(0x0010) → 读 int32 count → count × {i16 port, u8 status}。 +# 明文 TCP(无 libsodium):m2dev 发 CG_STATE_CHECKER(0x000F,len 4),40250 classic +# 发单字节 CG_STATE_CHECKER(206);服务端均返回频道条目。classic 响应是 +# [210][int32 count][count × {i16 port, u8 status}],m2dev 则是带 u16 header/length 的包。 # status:0 关 / 1 正常 / 2 忙 / 3 满(Metin2 约定,非在线人数——那要改服务器)。 extends Node const CG_STATE_CHECKER := 0x000F const GC_RESPOND_CHANNELSTATUS := 0x0010 +const CLASSIC_CG_STATE_CHECKER := 206 +const CLASSIC_GC_RESPOND_CHANNELSTATUS := 210 const STATUS_TEXT := {0: "关闭", 1: "正常", 2: "拥挤", 3: "爆满"} @@ -20,11 +23,15 @@ var _peer: StreamPeerTCP var _cb: Callable var _deadline := 0.0 var _sent := false +var _classic := false +var _classic_rx := PackedByteArray() func query(host: String, port: int, callback: Callable = Callable(), timeout_s := 3.0) -> void: _cb = callback _peer = StreamPeerTCP.new() _sent = false + _classic = OS.get_environment("MT_PROTOCOL") == "classic" + _classic_rx = PackedByteArray() _deadline = _now() + timeout_s if _peer.connect_to_host(host, port) != OK: _finish({}) @@ -48,14 +55,53 @@ func _process(_dt: float) -> void: if st != StreamPeerTCP.STATUS_CONNECTED: return if not _sent: - var req := PackedByteArray() - req.resize(4) - req.encode_u16(0, CG_STATE_CHECKER) - req.encode_u16(2, 4) + var req := PackedByteArray([CLASSIC_CG_STATE_CHECKER]) if _classic else PackedByteArray() + if not _classic: + req.resize(4) + req.encode_u16(0, CG_STATE_CHECKER) + req.encode_u16(2, 4) _peer.put_data(req) _sent = true # 攒够一个包就解析 - _try_parse() + if _classic: + _try_parse_classic() + else: + _try_parse() + +func _try_parse_classic() -> void: + var avail := _peer.get_available_bytes() + if avail > 0: + var r: Array = _peer.get_data(avail) + if r[0] != OK: + _finish({}) + return + _classic_rx.append_array(r[1]) + + # The stock checker reads a byte header, then an int32 count. A regular + # game handshake may arrive while waiting, so discard known fixed packets. + while not _classic_rx.is_empty() and _classic_rx[0] != CLASSIC_GC_RESPOND_CHANNELSTATUS: + var skip := 1 + match int(_classic_rx[0]): + 0xFE: skip = 13 # GC_HANDSHAKE + 0xFC: skip = 1 # GC_TIME_SYNC + if _classic_rx.size() < skip: + return + _classic_rx = _classic_rx.slice(skip) + if _classic_rx.size() < 5: + return + var count := _classic_rx.decode_s32(1) + if count < 0 or count > 4096: + _finish({}) + return + var total := 5 + count * 3 + if _classic_rx.size() < total: + return + var out := {} + var off := 5 + for i in count: + out[_classic_rx.decode_s16(off)] = _classic_rx.decode_u8(off + 2) + off += 3 + _finish(out) func _try_parse() -> void: var avail := _peer.get_available_bytes() diff --git a/project/net_play.gd b/project/net_play.gd index fe14569b..efea0288 100644 --- a/project/net_play.gd +++ b/project/net_play.gd @@ -52,6 +52,7 @@ var _attack_cd := 0.0 var _hitstun_until := 0.0 var _combo := 0 var _last_attack_t := 0.0 +var _observer_mode := false func setup(m2client: Node, player_ctl: Node, nw: Node, hud_node: Node = null) -> void: client = m2client @@ -74,6 +75,19 @@ func setup(m2client: Node, player_ctl: Node, nw: Node, hud_node: Node = null) -> client.damage.connect(_on_damage) if client.has_signal("fishing_event"): client.fishing_event.connect(_on_fishing_event) + if client.has_signal("observer_mode_changed"): + client.observer_mode_changed.connect(_on_observer_mode) + if client.has_method("is_observer_mode"): + _observer_mode = bool(client.is_observer_mode()) + +func _on_observer_mode(enabled: bool) -> void: + _observer_mode = enabled + if enabled: + _target_vid = 0 + _attack_cd = 0.0 + target_changed.emit(0) + if hud and hud.has_method("clear_target"): + hud.clear_target() # --- helpers -------------------------------------------------------------- @@ -125,7 +139,7 @@ func _entity_name(e: Dictionary) -> String: # --- movement ---------------------------------------------------------------- func _on_local_moved(pos: Vector3) -> void: - if client == null or not client.is_in_game(): + if _observer_mode or client == null or not client.is_in_game(): return var now := Time.get_ticks_msec() / 1000.0 if pos.distance_to(_last_sent_pos) < SEND_DIST and now - _last_sent_t < SEND_INTERVAL: @@ -137,6 +151,8 @@ func _on_local_moved(pos: Vector3) -> void: _was_moving = true func _on_anim_state(state: String) -> void: + if _observer_mode: + return if state == "wait" and _was_moving: _was_moving = false if client and client.is_in_game() and pc.player: @@ -174,6 +190,8 @@ func _on_points(p: Dictionary) -> void: if hud.has_method("set_vitals"): hud.set_vitals(int(p.get("hp", 0)), int(p.get("max_hp", 0)), int(p.get("sp", 0)), int(p.get("max_sp", 0))) + if hud.has_method("set_stamina"): + hud.set_stamina(int(p.get("stamina", 0)), int(p.get("max_stamina", 0))) if hud.has_method("set_exp"): hud.set_exp(int(p.get("exp", 0)), int(p.get("next_exp", 0))) if hud.has_method("set_level"): @@ -198,6 +216,8 @@ func _on_net_moved(vid: int) -> void: # --- targeting / attack ----------------------------------------------------- func _on_pick(node: Node3D) -> void: + if _observer_mode: + return var vid := _vid_of(node) if vid == 0 or vid == _main_vid: return @@ -266,7 +286,7 @@ func is_stunned() -> bool: func _process(dt: float) -> void: if pc: pc.set("frozen", is_stunned()) - if client == null or not client.is_in_game() or _target_vid == 0 or pc == null: + if _observer_mode or client == null or not client.is_in_game() or _target_vid == 0 or pc == null: return if is_stunned(): return # 硬直:不发攻击 / 移动 diff --git a/project/net_world.gd b/project/net_world.gd index f2e7f828..21d85add 100644 --- a/project/net_world.gd +++ b/project/net_world.gd @@ -22,6 +22,7 @@ signal main_entity_ready(node: Node3D, vid: int) signal chat_line(type: int, vid: int, text: String) signal fly_targeting(shooter_vid: int, target_vid: int, target_cm: Vector2, append: bool) signal fishing_event(vid: int, subheader: int, dir: int) +signal motion_event(vid: int, victim_vid: int, motion: int) signal vitals(vid: int, hp: int, max_hp: int, dead: bool) signal damage_number(vid: int, amount: int, crit: bool, dodge: bool) @@ -47,9 +48,12 @@ var snap_dist := 6.0 # 超过这么多米直接瞬移(初次 var _by_vid := {} # vid:int -> Node3D var _main_vid := 0 var _local_vid := 0 # 由 net_play 设:这个 vid 由本地 player 代表,不生成节点 +var _local_node: Node3D # 本地玩家的真模型(不挂在 _mount 下) var _model_factory: Callable # func(Dictionary) -> Node3D var name_resolver: Callable = Callable() # func(entity_dict) -> String(怪名走 mob_proto) var _pvp_relations := {} # unordered pair key -> {src_vid,dst_vid,mode} +var _duel_opponents := {} # server-provided duel opponent VID set +var _duel_cannot_attack := false func setup(m2client: Node, mount: Node3D) -> void: client = m2client @@ -68,6 +72,8 @@ func setup(m2client: Node, mount: Node3D) -> void: client.vitals_changed.connect(_on_vitals) client.entity_dead.connect(_on_dead) client.damage.connect(_on_damage) + if client.has_signal("motion"): + client.motion.connect(_on_motion) if client.has_signal("dig_motion"): client.dig_motion.connect(_on_dig_motion) if client.has_signal("fly_cue"): @@ -78,6 +84,8 @@ func setup(m2client: Node, mount: Node3D) -> void: client.fishing_event.connect(_on_fishing_event) if client.has_signal("pvp_changed"): client.pvp_changed.connect(_on_pvp_changed) + if client.has_signal("duel_changed"): + client.duel_changed.connect(_on_duel_changed) # 已在局内(重连 / setup 是协程,进来时 spawn burst 已被 pump 抽干)—— # 把当前所有实体补建一遍,别漏掉进游戏那一批怪 / NPC / 玩家。 @@ -92,6 +100,8 @@ func catch_up() -> void: for relation in client.get_pvp_relations(): _on_pvp_changed(int(relation.get("src_vid", 0)), int(relation.get("dst_vid", 0)), int(relation.get("mode", 0))) + if client.has_method("get_duel"): + _on_duel_changed(client.get_duel()) func set_model_factory(f: Callable) -> void: _model_factory = f @@ -104,6 +114,9 @@ func set_local_vid(vid: int) -> void: _by_vid.erase(vid) n.queue_free() +func set_local_node(node: Node3D) -> void: + _local_node = node + func node_for(vid: int) -> Node3D: return _by_vid.get(vid, null) @@ -129,6 +142,7 @@ func _on_spawn(d: Dictionary) -> void: node.set_meta("vid", vid) node.set_meta("func", int(d.get("func", FUNC_WAIT))) _by_vid[vid] = node + _refresh_shop_sign(node, str(d.get("shop_sign", ""))) _refresh_pvp_tag(vid) entity_added.emit(node, vid) if vid == _main_vid: @@ -145,6 +159,26 @@ func _on_info(vid: int, d: Dictionary) -> void: (n.get_node("Label3D") as Label3D).text = nm elif n.has_method("set_display_name"): n.set_display_name(nm) + _refresh_shop_sign(n, str(d.get("shop_sign", ""))) + +func _refresh_shop_sign(root: Node3D, sign: String) -> void: + var tag := root.get_node_or_null("ShopSign") as Label3D + var text := sign.strip_edges() + if text == "": + if tag: + tag.queue_free() + return + if tag == null: + tag = Label3D.new() + tag.name = "ShopSign" + tag.position.y = 3.0 + tag.billboard = BaseMaterial3D.BILLBOARD_ENABLED + tag.no_depth_test = true + tag.pixel_size = 0.0055 + tag.modulate = Color(1.0, 0.82, 0.25) + tag.outline_size = 8 + root.add_child(tag) + tag.text = text func _display_name(d: Dictionary) -> String: if name_resolver.is_valid(): @@ -154,6 +188,7 @@ func _display_name(d: Dictionary) -> String: return str(d.get("name", "")) func _on_despawn(vid: int) -> void: + _duel_opponents.erase(vid) var n: Node3D = _by_vid.get(vid, null) if n: _by_vid.erase(vid) @@ -169,6 +204,50 @@ func _on_main_set(vid: int) -> void: func _on_moved(_vid: int) -> void: pass # 插值在 _process 里统一做 +# GC_MOTION and ServerCommand emotion commands share CRaceMotionData IDs in +# the 40250 client. Keep the raw event visible to gameplay and ask real PC +# views to play the matching one-shot action; placeholders still retain the +# authoritative motion metadata and state tint. +func _on_motion(vid: int, victim_vid: int, motion: int) -> void: + var n: Node3D = _by_vid.get(vid, null) + if n == null and vid == _local_vid: + n = _local_node + motion_event.emit(vid, victim_vid, motion) + if n == null: + return + n.set_meta("last_motion", motion) + n.set_meta("motion_victim_vid", victim_vid) + var target: Node3D = _by_vid.get(victim_vid, null) + if target and target != n: + var flat := target.global_position + flat.y = n.global_position.y + if n.global_position.distance_squared_to(flat) > 0.001: + n.look_at(flat, Vector3.UP) + var target_race := -1 + if client: + var target_entity: Dictionary = client.get_entity(victim_vid) + if not target_entity.is_empty(): + target_race = int(target_entity.get("race", -1)) + var applied := false + if n.has_method("set_motion_id"): + applied = bool(n.call("set_motion_id", motion, target_race)) + if not applied: + var state := "attack" + if motion >= 305: + state = "emotion" + elif motion >= 1 and motion <= 3: + state = "wait" if motion == 1 else ("walk" if motion == 2 else "run") + elif motion == 5 or motion == 6 or motion == 8 or motion == 9: + state = "damage" + elif motion == 11 or motion == 12: + state = "dead" + if n.has_method("set_anim_state"): + n.call("set_anim_state", state) + else: + n.set_meta("motion_state", state) + if n.has_node("Label3D"): + (n.get_node("Label3D") as Label3D).modulate = _state_tint(state) + # GC_PVP: 显示当前与任一角色的挑战 / 战斗 / 复仇关系。原客户端同时会影响 # TargetBoard 和名字颜色;这里先提供始终可见的世界标签,避免关系状态无表现。 func _on_pvp_changed(src_vid: int, dst_vid: int, mode: int) -> void: @@ -197,7 +276,8 @@ func _refresh_pvp_tag(vid: int) -> void: return var mode := _pvp_mode_for(vid) var tag := n.get_node_or_null("PvpTag") as Label3D - if mode == 0: + var in_duel := _duel_opponents.has(vid) + if mode == 0 and not in_duel: if tag: tag.queue_free() return @@ -209,6 +289,10 @@ func _refresh_pvp_tag(vid: int) -> void: tag.no_depth_test = true tag.pixel_size = 0.0045 n.add_child(tag) + if in_duel: + tag.text = "决斗" + tag.modulate = Color(0.45, 0.85, 1.0) + return match mode: 1: tag.text = "挑战" @@ -223,6 +307,16 @@ func _refresh_pvp_tag(vid: int) -> void: tag.text = "PVP" tag.modulate = Color.WHITE +func _on_duel_changed(duel: Dictionary) -> void: + _duel_opponents.clear() + _duel_cannot_attack = bool(duel.get("cannot_attack", false)) + for vid in duel.get("opponents", []): + var opponent := int(vid) + if opponent != 0: + _duel_opponents[opponent] = true + for vid in _by_vid.keys(): + _refresh_pvp_tag(int(vid)) + # 头顶聊天气泡(~4s 淡出)。本地玩家 vid 走 main_bubble 信号让上层处理。 signal main_bubble(text: String) diff --git a/project/netbridge_test.gd b/project/netbridge_test.gd index d2acbb9c..b257ddf2 100644 --- a/project/netbridge_test.gd +++ b/project/netbridge_test.gd @@ -19,11 +19,14 @@ class FakeClient extends Node: signal vitals_changed(vid: int) signal entity_dead(vid: int) signal damage(vid: int, amount: int, flag: int) + signal motion(vid: int, victim_vid: int, motion: int) signal pvp_changed(src_vid: int, dst_vid: int, mode: int) + signal duel_changed(duel: Dictionary) var ents := {} func get_entity(vid: int) -> Dictionary: return ents.get(vid, {}) func get_entities() -> Array: return ents.values() func get_pvp_relations() -> Array: return [] + func get_duel() -> Dictionary: return {} func spawn(vid, nm, pos, is_main := false): ents[vid] = {"vid": vid, "name": nm, "pos": pos, "is_main": is_main, "func": 0, "moving": false, "angle_deg": 0.0, @@ -70,18 +73,32 @@ func _test_m2client_surface() -> void: return var c: Object = ClassDB.instantiate("M2Client") get_root().add_child(c) - for m in ["move", "character_position", "sync_positions", "request_warp", "fishing", "request_dungeon", "attack", "set_target", "say", "shoot", "add_fly_targeting", "change_name", "download_guild_symbol", "get_guild_symbol", "script_select_item", "quest_cancel", "party_use_skill", "get_skill_group", "get_entity", "get_entities", - "get_main_vid", "get_points", "get_target", "select_character", "reconnect", - "suspend", "resume", "move_item", "use_item", "drop_item", "pickup_item", - "get_inventory", "get_equipment", "get_item", "get_ground_items", "get_pvp_relations", "get_lover", "get_land_areas", "get_observers", "whisper"]: + for m in ["move", "character_position", "sync_positions", "request_warp", "fishing", "request_dungeon", "attack", "set_target", "say", "shoot", "add_fly_targeting", "change_name", "select_empire", "download_guild_symbol", "get_guild_symbol", "script_select_item", "quest_cancel", "party_use_skill", "get_skill_group", "get_entity", "get_entities", + "get_main_vid", "get_main_pid", "get_points", "get_target", "select_character", "reconnect", + "suspend", "resume", "move_item", "use_item", "drop_item", "drop_item_count", "use_item_to_item", "give_item", "pickup_item", + "get_inventory", "get_equipment", "get_belt_inventory", "get_view_equipment", "get_item", "get_ground_items", "get_pvp_relations", "get_duel", "get_lover", "get_land_areas", "get_observers", "is_observer_mode", "get_observer_count", "has_mobile_flag", "combo_skill_enabled", "get_stamina_state", "whisper", + "party_invite", "party_answer", "party_leave", "party_set_distribute", "party_set_state", "get_party", "get_party_distribute_mode", + "add_friend", "remove_friend", "friend_answer", "get_friends", + "shop_buy", "shop_sell", "shop_close", "is_shop_open", "get_shop_items", "get_shop", + "exchange_start", "exchange_add_item", "exchange_add_gold", "exchange_accept", "exchange_cancel", "get_exchange", + "safebox_checkin", "safebox_checkout", "safebox_move", "is_safebox_open", "get_safebox_size", "get_safebox_gold", "get_safebox_items", + "is_mall_open", "get_mall_size", "get_mall_items", "mall_checkout", "mall_password", "open_private_shop", "close_private_shop", "safebox_password", + "get_cube", "cube_make", "cube_request_result_list", "cube_request_materials", "cube_open", "cube_close", "cube_list", "cube_add_item", "cube_delete_item", + "get_guild", "get_guild_members", "get_guild_grades", "guild_add_member", "guild_remove_member", "guild_offer", "guild_charge_gsp", "guild_change_grade_name", "guild_change_grade_authority", "guild_change_member_grade", "guild_change_member_general", "guild_post_comment", "guild_delete_comment", "guild_refresh_comments", "guild_answer_invite", "guild_answer_make", "get_guild_comments", "get_guild_skill", "get_guild_wars", "get_guild_war", "get_guild_name", "use_guild_skill", "declare_guild_war", + "download_guild_marks", "are_guild_marks_ready", "get_mark_server", "get_guild_mark", "get_guild_mark_image", "upload_guild_mark", "upload_guild_symbol", + "refine", "ds_refine", "get_dragon_souls", "get_channel", "get_server_time", "get_npc_marks", "get_world_markers"]: _ck(c.has_method(m), "M2Client.%s bound" % m) - for s in ["entity_spawned", "entity_despawned", "entity_moved", "entity_main_set", + for s in ["entity_spawned", "entity_despawned", "entity_moved", "entity_main_set", "empire_changed", "chat", "suspended", "resumed", "vitals_changed", "entity_dead", "damage", "motion", "points_changed", "target_info", "inventory_changed", "ground_item_added", "ground_item_removed", "item_picked_up", "item_used", "whisper_received", "entity_info", "warp", "time_changed", "channel_changed", "npc_marks_changed", - "land_areas_changed", "observer_event", "world_markers_changed", "mount_changed", "pvp_changed", "duel_started", "view_equipment", "lover_changed", - "fly_targeting", "dig_motion", "fishing_event", "dungeon_event", "skill_group_changed", "guild_make_requested", "guild_symbol_ready"]: + "land_areas_changed", "observer_event", "observer_mode_changed", "observer_count_changed", "stone_detected", "stamina_changed", "mobile_flag_changed", "mobile_auth_required", "combo_changed", "world_markers_changed", "mount_changed", "pvp_changed", "duel_changed", "duel_started", "view_equipment", "lover_changed", + "fly_targeting", "dig_motion", "fishing_event", "dungeon_event", "skill_group_changed", "guild_make_requested", "guild_symbol_ready", + "party_changed", "party_invite_ask", "party_request_denied", "friends_changed", "friend_invite_ask", "shop_opened", "shop_closed", "shop_error", + "exchange_changed", "safebox_changed", "safebox_password_required", "safebox_wrong_password", "mall_opened", "mall_changed", "mall_password_required", "private_shop_open_requested", "my_shop_price_list", "block_mode_changed", "gift_available", "cube_opened", "cube_closed", "cube_changed", "cube_result", + "guild_changed", "guild_skill_changed", "guild_war_changed", "guild_comments_changed", "guild_invite_ask", "guild_war_event", "guild_war_point", + "guild_marks_ready", "guild_mark_uploaded", "guild_mark_updated", "refine_ask", "refine_result", "ds_window_open", "ds_refine_result"]: _ck(c.has_signal(s), "M2Client.%s signal" % s) # not in game -> intents refused, snapshot empty _ck(c.call("move", 1, 0, 90.0, 1000, 2000) == false, "move refused pre-game") @@ -162,6 +179,11 @@ func _test_netbridge() -> void: await process_frame _ck(not nw.node_for(2000).has_meta("fishing_item_vnum"), "fishing fish outcome is not treated as entity motion") + fc.motion.emit(2000, 1000, 325) # CRaceMotionData::NAME_DANCE_1 + await process_frame + _ck(int(nw.node_for(2000).get_meta("last_motion", 0)) == 325 + and int(nw.node_for(2000).get_meta("motion_victim_vid", 0)) == 1000, + "GC_MOTION -> entity motion metadata and bridge signal") # GC_CHAR_ADD_INFO late name -> 3D label refreshes (name_resolver optional) var mob0: Node3D = nw.node_for(2000) @@ -172,6 +194,15 @@ func _test_netbridge() -> void: await process_frame _ck((mob0.get_node("Label3D") as Label3D).text == "Angry Mob", "entity_info -> label refreshed via name_resolver") + fc.ents[2000]["shop_sign"] = "Potion shop" + fc.entity_info.emit(2000, fc.ents[2000]) + await process_frame + var shop_sign := mob0.get_node_or_null("ShopSign") as Label3D + _ck(shop_sign != null and shop_sign.text == "Potion shop", "entity_info -> shop sign label") + fc.ents[2000]["shop_sign"] = "" + fc.entity_info.emit(2000, fc.ents[2000]) + await process_frame + _ck(mob0.get_node_or_null("ShopSign") == null, "empty shop sign removes label") fc.pvp_changed.emit(1000, 2000, 2) await process_frame var pvp_tag := mob0.get_node_or_null("PvpTag") as Label3D @@ -179,6 +210,13 @@ func _test_netbridge() -> void: fc.pvp_changed.emit(1000, 2000, 0) await process_frame _ck(mob0.get_node_or_null("PvpTag") == null, "pvp none -> removes world tag") + fc.duel_changed.emit({"active": true, "cannot_attack": false, "opponents": [2000]}) + await process_frame + var duel_tag := mob0.get_node_or_null("PvpTag") as Label3D + _ck(duel_tag != null and duel_tag.text == "决斗", "duel opponent -> world duel tag") + fc.duel_changed.emit({"active": false, "cannot_attack": true, "opponents": []}) + await process_frame + _ck(mob0.get_node_or_null("PvpTag") == null, "duel cleared -> removes world tag") fc.move_to(2000, Vector3(10, 0, 40)) for i in 3: await process_frame diff --git a/project/netplay_test.gd b/project/netplay_test.gd index cbc71ce4..76d1a781 100644 --- a/project/netplay_test.gd +++ b/project/netplay_test.gd @@ -17,17 +17,19 @@ class FakeClient extends Node: signal vitals_changed(vid: int) signal points_changed(points: Dictionary) signal target_info(vid: int, hp_percent: int) + signal observer_mode_changed(enabled: bool) signal chat(type: int, vid: int, text: String) var ents := {} var main := 0 var in_game := true - var calls := {"move": [], "attack": [], "set_target": []} + var calls := {"move": [], "attack": [], "set_target": [], "click_npc": []} func is_in_game() -> bool: return in_game func get_main_vid() -> int: return main func get_entity(vid: int) -> Dictionary: return ents.get(vid, {}) func move(f, a, rot, x, y) -> bool: calls.move.append([f, a, rot, x, y]); return true func attack(motion, vid) -> bool: calls.attack.append([motion, vid]); return true func set_target(vid) -> bool: calls.set_target.append(vid); return true + func click_npc(vid) -> bool: calls.click_npc.append(vid); return true class FakePC extends Node: signal target_selected(node: Node3D) @@ -119,6 +121,15 @@ func _run() -> void: pc.target_selected.emit(mob) _ck(fc.calls.set_target.size() == 1 and fc.calls.set_target[0] == 2000, "set_target(2000)") + # NPC/传送点/石头走 click_npc,而不是被误当成攻击目标;这是 Cube + # 窗口由服务端 cube_open 命令打开前的入口。 + var npc := Node3D.new() + npc.set_meta("vid", 3000) + root.add_child(npc) + fc.ents[3000] = {"vid": 3000, "ch_type": 1, "name": "Cube NPC", "pos": npc.position} + pc.target_selected.emit(npc) + _ck(fc.calls.click_npc == [3000], "NPC selection -> click_npc(3000)") + # 5) 攻击距离内 -> 按 attack_period 自动 attack for i in 4: await process_frame _ck(fc.calls.attack.size() >= 1, "auto-attack fired, got %d" % fc.calls.attack.size()) @@ -150,3 +161,13 @@ func _run() -> void: fc.ents[2000]["dead"] = true fc.entity_dead.emit(2000) _ck(hud.cleared >= 1, "target cleared on death") + + # 10) 观战模式锁住本地移动/选目标,并清掉当前目标 + fc.ents[2000]["dead"] = false + fc.observer_mode_changed.emit(true) + pc.player.position = Vector3(8, 0, -5) + pc.moved.emit(pc.player.position) + pc.target_selected.emit(mob) + _ck(fc.calls.move.size() == 2 and fc.calls.set_target.size() == 1, + "observer mode blocks local movement and targeting") + fc.observer_mode_changed.emit(false) diff --git a/project/p8_test.gd b/project/p8_test.gd index db193694..cef0fa64 100644 --- a/project/p8_test.gd +++ b/project/p8_test.gd @@ -12,6 +12,7 @@ class FakeClient extends Node: signal party_changed() signal party_invite_ask(leader_pid: int) signal friends_changed() + signal friend_invite_ask(name: String) signal shop_opened(vid: int) signal shop_closed() signal shop_error(kind: String) @@ -33,8 +34,10 @@ class FakeClient extends Node: var main_vid := 20 var distribute_mode := 0 + var leadership := 40 func is_in_game() -> bool: return true func get_main_vid() -> int: return main_vid + func get_skills() -> Array: return [{"id": 121, "level": leadership}] func get_party() -> Array: return party func get_party_distribute_mode() -> int: return distribute_mode func party_answer(pid, accept) -> bool: calls.append(["party_answer", pid, accept]); return true @@ -47,6 +50,7 @@ class FakeClient extends Node: func get_friends() -> Array: return friends func add_friend(nm) -> bool: calls.append(["add_friend", nm]); return true func remove_friend(nm) -> bool: calls.append(["remove_friend", nm]); return true + func friend_answer(nm, accept) -> bool: calls.append(["friend_answer", nm, accept]); return true func get_shop_items() -> Array: return shop func get_shop() -> Dictionary: var tabs := shop_tabs if not shop_tabs.is_empty() else [{"name": "", "coin_type": 0, "items": shop}] @@ -117,7 +121,7 @@ func _run() -> void: var me_strip: Control = pu._list.get_child(0) var state_btn: Button = null for b in me_strip.find_children("*", "Button", true, false): - if String(b.text) in ["队", "普", "攻", "坦", "辅", "宗", "狂", "防"]: + if String(b.text) in ["队", "普", "攻", "坦", "辅", "宗", "速", "防"]: state_btn = b break _ck(state_btn != null and not state_btn.disabled, "party: leader's StateButton enabled") @@ -153,6 +157,26 @@ func _run() -> void: name_btn.pressed.emit() _ck(fc.calls.has(["set_target", 20]), "party: 点名字 -> set_target(vid)") + # 40250 CParty::Update 的 Leadership 门控:攻击至少 10,治疗至少 18。 + fc.party[0]["leader"] = true + fc.leadership = 9 + fc.party_changed.emit() + _ck(pu._heal_btn.disabled, "party: Leadership<18 disables heal") + var gated_state: Button = null + for b in pu._list.get_child(0).find_children("*", "Button", true, false): + if String(b.text) == "队": + gated_state = b + break + if gated_state: + gated_state.pressed.emit() + var gated_attack: Button = null + for b in pu._role_popup.find_children("*", "Button", true, false): + if String(b.text).begins_with("攻击"): + gated_attack = b + break + _ck(gated_attack != null and gated_attack.disabled, "party: Leadership<10 disables attacker role") + pu._dismiss_role_popup() + # 非队长 -> StateButton disabled fc.party[0]["leader"] = false fc.party[0]["state"] = 0 @@ -169,9 +193,14 @@ func _run() -> void: fu.setup(fc, canvas) fu.toggle() _ck(fu.is_open(), "friend window opens") - fc.friends = [{"name": "Alice", "online": true}, {"name": "Bob", "online": false}] + fc.friends = [{"name": "Alice", "online": true, "mobile": true}, {"name": "Bob", "online": false}] fc.friends_changed.emit() await process_frame + var alice_mobile := false + for l in fu._list.find_children("*", "Label", true, false): + if String(l.text) == "手机": + alice_mobile = true + _ck(alice_mobile, "friend: mobile state renders") var wt := [] fu.whisper_to.connect(func(n): wt.append(n)) # 找 Alice 行的名字按钮 @@ -186,6 +215,15 @@ func _run() -> void: fu._name_edit.text = "Carol" fu._on_add() _ck(fc.calls.has(["add_friend", "Carol"]), "friend: add via input") + fc.friend_invite_ask.emit("Dave") + await process_frame + _ck(fu._invite_dialog.visible and fu._invite_dialog.dialog_text.contains("Dave"), + "friend: incoming request opens confirmation") + fu._invite_dialog.confirmed.emit() + _ck(fc.calls.has(["friend_answer", "Dave", true]), "friend: accept incoming request") + fc.friend_invite_ask.emit("Eve") + fu._invite_dialog.canceled.emit() + _ck(fc.calls.has(["friend_answer", "Eve", false]), "friend: reject incoming request") # --- 商店 --- var su: Node = ShopUI.new() @@ -256,7 +294,7 @@ func _run() -> void: _ck(xu._self_box.get_child_count() == 1, "exchange: 1 self item row") _ck(xu._root.get_node("PeerAccept").text == "对方: 已接受", "exchange: peer accept shown") xu.offer(1, 7) - _ck(fc.calls.has(["ex_add_item", 1, 7, 0]), "exchange: offer item (display 0)") + _ck(fc.calls.has(["ex_add_item", 1, 7, 1]), "exchange: offer item uses first free display slot (1)") xu._gold_input.text = "500" xu._on_put_gold() _ck(fc.calls.has(["ex_gold", 500]), "exchange: put gold") diff --git a/project/player_motion_test.gd b/project/player_motion_test.gd new file mode 100644 index 00000000..8d0998cc --- /dev/null +++ b/project/player_motion_test.gd @@ -0,0 +1,45 @@ +# player_motion_test —— 40250 GC_MOTION / ServerCommand emotion clip mapping。 +# godot --headless --path project --script player_motion_test.gd +extends SceneTree + +const PlayerView = preload("res://ui/player_view.gd") + +var _fail := 0 + +func _ck(ok: bool, msg: String) -> void: + if not ok: + _fail += 1 + printerr("FAIL: " + msg) + +func _init() -> void: + await _run() + if _fail == 0: + print("PASS: player_motion_test") + quit(0) + else: + printerr("%d check(s) failed" % _fail) + quit(1) + +func _run() -> void: + if not ClassDB.class_exists("Metin2Model") or not ClassDB.class_exists("Metin2AnimPlayer"): + print(" (skip: animation extension not registered)") + return + var assets := AssetRoot.path() + if not DirAccess.dir_exists_absolute(assets.path_join("PC/ymir work/pc/warrior")): + print(" (skip: PC assets unavailable)") + return + var pv: Node = PlayerView.new() + get_root().add_child(pv) + _ck(pv.build(assets, 0), "warrior PlayerView builds") + if pv.anim == null: + return + _ck(pv.set_motion_id(305), "clap motion resolves") + _ck(String(pv.anim.get("anim_path")).ends_with("action/clap.msa"), + "clap -> action/clap.msa") + _ck(pv.set_motion_id(308, 3), "kiss motion resolves with target job") + _ck(String(pv.anim.get("anim_path")).ends_with("action/kiss_with_shaman.msa"), + "kiss start + shaman target -> kiss_with_shaman.msa") + _ck(pv.set_motion_id(320), "slap hurt motion resolves") + _ck(String(pv.anim.get("anim_path")).ends_with("action/slap_hurt.msa"), + "slap hurt -> action/slap_hurt.msa") + pv.queue_free() diff --git a/project/player_motion_test.gd.uid b/project/player_motion_test.gd.uid new file mode 100644 index 00000000..00ff8cf2 --- /dev/null +++ b/project/player_motion_test.gd.uid @@ -0,0 +1 @@ +uid://1mwx8xsric02 diff --git a/project/private_shop_ui_test.gd b/project/private_shop_ui_test.gd index 9a50502b..82d3f489 100644 --- a/project/private_shop_ui_test.gd +++ b/project/private_shop_ui_test.gd @@ -67,6 +67,8 @@ func _run() -> void: _ck(pu._cells.size() == 40, "ItemSlot = 40-slot grid (5x8, shop.SHOP_SLOT_COUNT)") _ck(is_instance_valid(pu._sign), "NameLine overlaid with a LineEdit") _ck(pu._inv_list.get_child_count() == 2, "2 inventory candidates") + _ck((pu._inv_list.get_child(0) as Button).has_method("_get_drag_data"), + "inventory candidate supports drag data") # 未上货 → 개설 무동작 pu._ok() @@ -81,6 +83,10 @@ func _run() -> void: _ck(pu._stock.has(3) and int(pu._stock[3]["price"]) == 250000, "stock[3] placed") _ck(pu._picked == null, "pick cleared after place") _ck(pu._inv_list.get_child_count() == 1, "placed item leaves candidate list") + # 标准 Godot 拖放入口与点击选取共用同一个落位逻辑。 + pu._drop_slot(Vector2.ZERO, {"private_shop_entry": {"cell": 5, "vnum": 27993, "count": 3}}, 6) + _ck(is_instance_valid(pu._price_dialog), "dragging candidate onto empty slot opens price dialog") + pu._place(6, 100) # 拿起第 2 件(cell 5)→ 落到格 0(更小格号 → 排前) (pu._inv_list.get_child(0) as Button).pressed.emit() diff --git a/project/shop_cube_mall_test.gd b/project/shop_cube_mall_test.gd index 144a7613..ae7c2755 100644 --- a/project/shop_cube_mall_test.gd +++ b/project/shop_cube_mall_test.gd @@ -27,6 +27,9 @@ class FakeClient extends Node: func cube_make(i) -> bool: calls.append(["cube_make", i]); return true func cube_request_result_list(n) -> bool: calls.append(["cube_rlist", n]); return true func cube_request_materials(a, b) -> bool: calls.append(["cube_mats", a, b]); return true + func cube_add_item(a, b) -> bool: calls.append(["cube_add", a, b]); return true + func cube_delete_item(a) -> bool: calls.append(["cube_del", a]); return true + func cube_close() -> bool: calls.append(["cube_close"]); return true func get_inventory() -> Array: return inventory func open_private_shop(sign, items) -> bool: calls.append(["open_shop", sign, items]); return true func close_private_shop() -> bool: calls.append(["close_shop"]); return true @@ -85,17 +88,43 @@ func _run() -> void: fc.cube = {"open": true, "npc_vnum": 20383, "results": fc.cube["results"], "recipes": [ {"result_vnum": 72723, "gold": 120000, "material_groups": [ [{"vnum": 125, "count": 1}], [{"vnum": 555, "count": 5}]]}]} + fc.inventory = [{"cell": 3, "vnum": 125, "count": 1}, {"cell": 4, "vnum": 555, "count": 5}] (recipe_btns[0] as Button).pressed.emit() await process_frame _ck(_has_call(fc, "cube_mats", func(c): return c[1] == 0), "cube: select → request materials(0)") var gold_lbl := _find(cu._mat, "Label", func(l): return String(l.text).contains("120000")) _ck(gold_lbl != null, "cube: materials panel shows gold 120000") - _ck(not cu._make_btn.disabled, "cube: 制作 enabled after select") + var bag_btn := _find(cu._mat, "Button", func(b): return String(b.text).begins_with("+ bag[3]")) + _ck(bag_btn != null, "cube: inventory item offered for material slot") + if bag_btn: + bag_btn.pressed.emit() + _ck(_has_call(fc, "cube_add", func(c): return c[1] == 0 and c[2] == 3), + "cube: inventory item → cube_add_item(slot=0, cell=3)") + _ck(int(cu._cube_slots.get(0, -1)) == 3, "cube: local material slot tracks inventory cell") + var del_btn := _find(cu._mat, "Button", func(b): return String(b.text) == "삭제") + _ck(del_btn != null, "cube: material slot has delete button") + if del_btn: + del_btn.pressed.emit() + _ck(_has_call(fc, "cube_del", func(c): return c[1] == 0), "cube: delete button → cube_delete_item(slot=0)") + _ck(cu._make_btn.disabled, "cube: 制作 disabled while required material is missing") + # 重新放入两个配方材料后才允许制作。 + var bag_btn2 := _find(cu._mat, "Button", func(b): return String(b.text).begins_with("+ bag[3]")) + if bag_btn2: + bag_btn2.pressed.emit() + var bag_btn3 := _find(cu._mat, "Button", func(b): return String(b.text).begins_with("+ bag[4]")) + if bag_btn3: + bag_btn3.pressed.emit() + _ck(not cu._make_btn.disabled, "cube: 制作 enabled after all required materials are slotted") cu._make_btn.pressed.emit() _ck(_has_call(fc, "cube_make", func(c): return c[1] == 0), "cube: 制作 → cube_make(0)") fc.cube_result.emit(72723, 1, true) await process_frame _ck(String(cu._status.text).contains("성공") or String(cu._status.text) != "", "cube: result shown") + var close_btn := _find(cu._root, "Button", func(b): return String(b.text) == "닫기") + _ck(close_btn != null, "cube: close button present") + if close_btn: + close_btn.pressed.emit() + _ck(_has_call(fc, "cube_close", func(_c): return true), "cube: close button → cube_close") fc.cube_closed.emit() await process_frame _ck(not cu.is_open(), "cube: hides on cube_closed") diff --git a/project/system_menu_ui_test.gd b/project/system_menu_ui_test.gd index 878f7ee3..cab42e80 100644 --- a/project/system_menu_ui_test.gd +++ b/project/system_menu_ui_test.gd @@ -34,7 +34,7 @@ func _init() -> void: quit(1) func _cfg_path() -> String: - return ProjectSettings.globalize_path("user://system_option.cfg") + return ProjectSettings.globalize_path(GameOptionUI.config_path()) func _has_say(fc, text: String) -> bool: for s in fc.says: diff --git a/project/system_option_ui_test.gd b/project/system_option_ui_test.gd index 1e6c68e9..20c8ceaa 100644 --- a/project/system_option_ui_test.gd +++ b/project/system_option_ui_test.gd @@ -32,7 +32,7 @@ func _init() -> void: quit(1) func _cfg_path() -> String: - return ProjectSettings.globalize_path("user://system_option.cfg") + return ProjectSettings.globalize_path(SystemOptionUI.config_path()) func _run() -> void: var assets := AssetRoot.path() diff --git a/project/ui/char_select_screen.gd b/project/ui/char_select_screen.gd index 9f0154ad..5db0c758 100644 --- a/project/ui/char_select_screen.gd +++ b/project/ui/char_select_screen.gd @@ -19,6 +19,7 @@ const PlayerView = preload("res://ui/player_view.gd") signal select_requested(index: int) signal delete_requested(index: int, private_code: String) signal create_requested(spec: Dictionary) # {slot, name, job, shape, con, int, str, dex} +signal change_name_requested(index: int, name: String) signal back_requested() const CLASS_CN := ["猛将", "刺客", "术士", "巫女"] @@ -55,6 +56,8 @@ var _class_lbl: Label var _status: Label var _slot_lbl: Label var _spin := 0.0 +var _last_empire := -1 +var _rename_pending := false func setup(client: Node, assets_root: String, chars: Array) -> void: _client = client @@ -66,6 +69,7 @@ func setup(client: Node, assets_root: String, chars: Array) -> void: _build_class_name() _build_panel() _build_status() + _last_empire = _empire_id() set_process(true) _select(_first_occupied()) @@ -107,9 +111,33 @@ func on_char_created(slot: int) -> void: _set_status("角色已创建(槽位 %d)" % slot) func on_char_create_failed(reason_type: int) -> void: + if _rename_pending: + _rename_pending = false + const RENAME_R := {0: "名称不合法", 1: "该名称已被使用", 100: "角色槽位无效"} + _set_status("改名失败:%s" % RENAME_R.get(reason_type, "错误码 %d" % reason_type)) + return const R := {1: "该名称已被使用", 2: "名称不合法", 3: "该槽位已有角色", 4: "权限不足"} _set_status("创建失败:%s" % R.get(reason_type, "错误码 %d" % reason_type)) +func on_char_name_send_failed() -> void: + _rename_pending = false + _set_status("改名请求发送失败") + +func on_char_name_changed(pid: int, name: String) -> void: + var matched := false + for c in _chars: + if int(c.get("id", 0)) == pid: + matched = true + c["name"] = name + c["change_name"] = false + if not matched and _rename_pending: + return + _rename_pending = false + _close_dialog() + _refresh_class_name() + _refresh_panel() + _set_status("角色已改名:%s" % name) + func on_char_deleted(slot: int) -> void: _close_dialog() _set_status("角色已删除(槽位 %d)" % slot) @@ -342,6 +370,32 @@ func _refresh_panel() -> void: _panel_box.add_child(_sep()) + # A fresh account has no empire yet. 40250 keeps the connection in the + # select phase and expects CG_EMPIRE before character creation/selection; + # expose that real protocol step instead of leaving the page apparently + # idle with a permanently disabled start button. + var empire_required := _empire_id() == 0 + if empire_required: + _panel_box.add_child(_plain("请选择阵营", 14, Color(0.95, 0.85, 0.55))) + var erow := HBoxContainer.new() + erow.add_theme_constant_override("separation", 6) + _panel_box.add_child(erow) + for eid in [1, 2, 3]: + var empire_id: int = eid + var eb := Button.new() + eb.text = _empire_name_for(empire_id) + eb.custom_minimum_size = Vector2(82, 30) + eb.pressed.connect(func(): + if _client == null or not _client.has_method("select_empire"): + _set_status("当前网络后端不支持选择阵营") + return + if bool(_client.call("select_empire", empire_id)): + _set_status("已发送阵营选择:%s" % _empire_name_for(empire_id)) + else: + _set_status("阵营选择发送失败") + ) + erow.add_child(eb) + # 槽位切换 if _chars.size() > 1: var nav := HBoxContainer.new() @@ -366,19 +420,19 @@ func _refresh_panel() -> void: var start := Button.new() start.text = "开始" start.custom_minimum_size = Vector2(122, 34) - start.disabled = not has_char + start.disabled = not has_char or empire_required start.pressed.connect(_do_start) brow.add_child(start) var create := Button.new() create.text = "创建" create.custom_minimum_size = Vector2(122, 34) - create.disabled = has_char + create.disabled = has_char or empire_required create.pressed.connect(_open_create_dialog) brow.add_child(create) var del := Button.new() del.text = "删除" del.custom_minimum_size = Vector2(122, 34) - del.disabled = not has_char + del.disabled = not has_char or empire_required del.pressed.connect(_open_delete_dialog) brow.add_child(del) var quit := Button.new() @@ -432,6 +486,11 @@ func _do_start() -> void: if d.is_empty() or String(d.get("name", "")) == "": _set_status("空槽位不能进入") return + # 40250's original select screen forces a character marked with + # change_name to complete the rename flow before entering the world. + if bool(d.get("change_name", false)): + _open_change_name_dialog() + return select_requested.emit(_slot_index()) _set_status("进入游戏:%s" % d.get("name")) @@ -546,6 +605,49 @@ func _open_create_dialog() -> void: cancel.pressed.connect(_close_dialog) brow.add_child(cancel) +func _open_change_name_dialog() -> void: + var d := _cur() + if String(d.get("name", "")) == "": + _set_status("空槽位不能改名") + return + var slot := _slot_index() + var box := _modal_root("修改角色名称", 400, 250) + box.add_child(_plain("该角色需要先修改名称才能进入游戏。", 13, + Color(0.95, 0.75, 0.7))) + var nrow := HBoxContainer.new() + nrow.add_theme_constant_override("separation", 8) + box.add_child(nrow) + nrow.add_child(_plain("新名称", 13, Color(0.72, 0.78, 0.85))) + var name_edit := LineEdit.new() + name_edit.name = "Name" + name_edit.max_length = 12 + name_edit.custom_minimum_size = Vector2(220, 0) + name_edit.placeholder_text = "角色名(最多 12)" + nrow.add_child(name_edit) + box.add_child(_sep()) + var brow := HBoxContainer.new() + brow.alignment = BoxContainer.ALIGNMENT_CENTER + brow.add_theme_constant_override("separation", 16) + box.add_child(brow) + var ok := Button.new() + ok.text = "改名" + ok.custom_minimum_size = Vector2(120, 34) + ok.pressed.connect(func(): + var nm := name_edit.text.strip_edges() + if nm.length() < 2: + _set_status("名称太短") + return + _rename_pending = true + _close_dialog() + _set_status("改名中…") + change_name_requested.emit(slot, nm)) + brow.add_child(ok) + var cancel := Button.new() + cancel.text = "取消" + cancel.custom_minimum_size = Vector2(120, 34) + cancel.pressed.connect(_close_dialog) + brow.add_child(cancel) + func _open_delete_dialog() -> void: var d := _cur() if String(d.get("name", "")) == "": @@ -587,7 +689,9 @@ func _empire_id() -> int: return 0 func _empire_name() -> String: - var e := _empire_id() + return _empire_name_for(_empire_id()) + +func _empire_name_for(e: int) -> String: # 优先 locale_game.txt 的 EMPIRE_A/B/C var key: String = EMPIRE_KEY.get(e, "") if key != "": @@ -625,6 +729,10 @@ func _empire_flag_tex() -> Texture2D: func _process(dt: float) -> void: _spin += dt + var empire := _empire_id() + if empire != _last_empire: + _last_empire = empire + _refresh_panel() if _pivot: # 正面朝相机 + 轻微来回摆 _pivot.rotation.y = PI + sin(_spin * 0.3) * 0.35 diff --git a/project/ui/cube_ui.gd b/project/ui/cube_ui.gd index 3a77c046..b68e9236 100644 --- a/project/ui/cube_ui.gd +++ b/project/ui/cube_ui.gd @@ -9,7 +9,9 @@ # cube_changed → 刷新配方 / 材料 / 金币 # cube_result(vnum,count,ok) → 结果提示 # cube_closed → 隐藏 -# 选中一个配方 → [制作] → M2Client.cube_make(index)。 +# 选中一个配方、把背包物品放入材料槽 → [制作] → M2Client.cube_make(index)。 +# 40250 服务端按材料槽匹配配方,`result_index` 只保留给 m2dev 后端;classic +# 会安全地忽略它并执行一次 `/cube make`。 extends Node var client: Node @@ -21,6 +23,9 @@ var _list: VBoxContainer var _mat: VBoxContainer var _make_btn: Button var _sel := -1 +var _cube_slots: Dictionary = {} # cube index:int -> inventory cell:int +var _craft_in_flight := false +var _cube_npc_vnum := 0 func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client = m2client @@ -34,12 +39,25 @@ func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client.cube_changed.connect(refresh) if client.has_signal("cube_result"): client.cube_result.connect(_on_result) + if client.has_signal("inventory_changed"): + client.inventory_changed.connect(func(_window, _cell): refresh()) func is_open() -> bool: return _root != null and _root.visible func _on_open(npc_vnum: int) -> void: + if npc_vnum <= 0: + return + var current: Dictionary = client.get_cube() if client.has_method("get_cube") else {} + if current.has("open") and not bool(current.get("open", false)): + return + var current_npc := int(current.get("npc_vnum", 0)) + if current_npc > 0 and current_npc != npc_vnum: + return _sel = -1 + _cube_slots.clear() + _craft_in_flight = false + _cube_npc_vnum = npc_vnum _root.visible = true _title.text = "제작 (Cube) · NPC #%d" % npc_vnum _status.text = "" @@ -48,10 +66,15 @@ func _on_open(npc_vnum: int) -> void: refresh() func _on_result(vnum: int, count: int, ok: bool) -> void: + _craft_in_flight = false if ok: _status.text = "제작 성공: %s ×%d" % [_name_of(vnum), count] + # 40250 在成功后消耗材料;等待 inventory/cube_changed 的最终状态前, + # 先清掉本地映射,避免旧背包格继续显示为可用材料。 + _cube_slots.clear() else: _status.text = "제작 실패" + refresh() func _name_of(vnum: int) -> String: if proto and proto.has_method("item"): @@ -65,6 +88,9 @@ func refresh() -> void: if client == null or _root == null or not _root.visible: return var cube: Dictionary = client.get_cube() + if not cube.get("open", true): + _root.visible = false + return var recipes: Array = cube.get("recipes", []) var results: Array = cube.get("results", []) for c in _list.get_children(): @@ -105,21 +131,123 @@ func _refresh_materials() -> void: c.queue_free() var cube: Dictionary = client.get_cube() var recipes: Array = cube.get("recipes", []) - _make_btn.disabled = _sel < 0 + var recipe: Dictionary = _selected_recipe() + _make_btn.disabled = _sel < 0 or recipe.is_empty() or _craft_in_flight \ + or not _recipe_can_craft(recipe) if _sel < 0 or _sel >= recipes.size(): _mat.add_child(_lbl("재료 정보를 불러오는 중…", 12)) - return - var r: Dictionary = recipes[_sel] - _mat.add_child(_lbl("필요 골드: %d" % int(r.get("gold", 0)), 12)) - var groups: Array = r.get("material_groups", []) - if groups.is_empty(): - _mat.add_child(_lbl("(재료 없음)", 12)) - for g in groups: - var parts: Array = [] - for s in (g as Array): - parts.append("%s ×%d" % [_name_of(int((s as Dictionary).get("vnum", 0))), - int((s as Dictionary).get("count", 1))]) - _mat.add_child(_lbl("• " + " / ".join(parts), 12)) + else: + var r: Dictionary = recipe + _mat.add_child(_lbl("필요 골드: %d" % int(r.get("gold", 0)), 12)) + var groups: Array = r.get("material_groups", []) + if groups.is_empty(): + _mat.add_child(_lbl("(재료 없음)", 12)) + for g in groups: + var parts: Array = [] + for s in (g as Array): + parts.append("%s ×%d" % [_name_of(int((s as Dictionary).get("vnum", 0))), + int((s as Dictionary).get("count", 1))]) + _mat.add_child(_lbl("• " + " / ".join(parts), 12)) + if not _recipe_can_craft(r): + _mat.add_child(_lbl("(材料不足或未放入材料槽)", 11)) + elif client.has_method("get_points") and int(r.get("gold", 0)) > int(client.get_points().get("gold", 0)): + _make_btn.disabled = true + _mat.add_child(_lbl("(金币不足)", 11)) + + _mat.add_child(HSeparator.new()) + _mat.add_child(_lbl("재료 슬롯 (클릭하면 추가/삭제)", 12)) + for slot in _cube_slots.keys(): + var cell := int(_cube_slots[slot]) + var row := HBoxContainer.new() + var label := _lbl("cube[%d] ← bag[%d]" % [int(slot), cell], 11) + row.add_child(label) + var remove := Button.new() + remove.text = "삭제" + remove.pressed.connect(func() -> void: + if client.has_method("cube_delete_item") and client.cube_delete_item(int(slot)): + _cube_slots.erase(slot) + refresh()) + row.add_child(remove) + _mat.add_child(row) + + _mat.add_child(_lbl("背包物品:", 12)) + var used_cells := {} + for cell in _cube_slots.values(): + used_cells[int(cell)] = true + var inventory: Array = client.get_inventory() if client.has_method("get_inventory") else [] + var added := 0 + for item in inventory: + var inv_cell := int(item.get("cell", -1)) + var item_vnum := int(item.get("vnum", 0)) + if used_cells.has(inv_cell): + continue + if not _recipe_accepts_vnum(recipe, item_vnum): + continue + var free_slot := _first_free_cube_slot() + if free_slot < 0: + break + var add := Button.new() + add.text = "+ bag[%d] %s ×%d" % [inv_cell, _name_of(item_vnum), + int(item.get("count", 1))] + add.alignment = HORIZONTAL_ALIGNMENT_LEFT + add.pressed.connect(func() -> void: + var target := _first_free_cube_slot() + if target >= 0 and client.has_method("cube_add_item") and client.cube_add_item(target, inv_cell): + _cube_slots[target] = inv_cell + refresh()) + _mat.add_child(add) + added += 1 + if added == 0: + _mat.add_child(_lbl("(可用背包物品 없음)", 11)) + +func _selected_recipe() -> Dictionary: + if client == null or not client.has_method("get_cube"): + return {} + var recipes: Array = client.get_cube().get("recipes", []) + if _sel < 0 or _sel >= recipes.size(): + return {} + return recipes[_sel] as Dictionary + +func _recipe_accepts_vnum(recipe: Dictionary, vnum: int) -> bool: + if vnum <= 0: + return false + for group in recipe.get("material_groups", []): + for option in group as Array: + if int((option as Dictionary).get("vnum", 0)) == vnum: + return true + return false + +func _recipe_can_craft(recipe: Dictionary) -> bool: + if recipe.is_empty(): + return false + var provided := {} + if client.has_method("get_inventory"): + var inventory: Array = client.get_inventory() + for cell in _cube_slots.values(): + for item in inventory: + if int(item.get("cell", -1)) == int(cell): + var vnum := int(item.get("vnum", 0)) + provided[vnum] = int(provided.get(vnum, 0)) + maxi(1, int(item.get("count", 1))) + break + for group in recipe.get("material_groups", []): + var matched := false + for option in group as Array: + var material: Dictionary = option as Dictionary + var vnum := int(material.get("vnum", 0)) + var need := maxi(1, int(material.get("count", 1))) + if int(provided.get(vnum, 0)) >= need: + provided[vnum] = int(provided[vnum]) - need + matched = true + break + if not matched: + return false + return true + +func _first_free_cube_slot() -> int: + for i in 24: + if not _cube_slots.has(i): + return i + return -1 func _lbl(t: String, sz: int) -> Label: var l := Label.new() @@ -165,10 +293,23 @@ func _build(parent: Node) -> void: _make_btn.text = "제작" _make_btn.disabled = true _make_btn.pressed.connect(func() -> void: - if _sel >= 0 and client.has_method("cube_make"): - client.cube_make(_sel)) + var recipe := _selected_recipe() + if _sel < 0 or recipe.is_empty(): + _status.text = "请先选择配方" + return + if not _recipe_can_craft(recipe): + _status.text = "材料不足或未放入材料槽" + refresh() + return + if client.has_method("cube_make") and client.cube_make(_sel): + _craft_in_flight = true + _status.text = "制作中…" + _make_btn.disabled = true) brow.add_child(_make_btn) var close := Button.new() close.text = "닫기" - close.pressed.connect(func() -> void: _root.visible = false) + close.pressed.connect(func() -> void: + if client.has_method("cube_close"): + client.cube_close() + _root.visible = false) brow.add_child(close) diff --git a/project/ui/exchange_ui.gd b/project/ui/exchange_ui.gd index 5b081261..3a63e0bc 100644 --- a/project/ui/exchange_ui.gd +++ b/project/ui/exchange_ui.gd @@ -16,9 +16,11 @@ var _self_box: VBoxContainer var _peer_box: VBoxContainer var _self_gold: Label var _peer_gold: Label +var _status: Label var _accept_btn: Button var _gold_input: LineEdit var _next_display := 0 +var _offered_cells := {} func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client = m2client @@ -31,9 +33,29 @@ func is_open() -> bool: return _root != null and _root.visible func offer(inv_window: int, inv_cell: int) -> void: - if is_open(): - client.exchange_add_item(inv_window, inv_cell, _next_display) + if not is_open() or inv_window < 0 or inv_cell < 0: + return + var key := "%d:%d" % [inv_window, inv_cell] + if _offered_cells.has(key): + _status.text = "该物品已经放入交易" + return + var x: Dictionary = client.get_exchange() + var used := {} + for item in x.get("self_items", []): + used[int(item.get("slot", -1))] = true + for i in 12: + if not used.has(i): + _next_display = i + break + if used.size() >= 12: + _status.text = "交易物品栏已满" + return + if client.exchange_add_item(inv_window, inv_cell, _next_display): + _offered_cells[key] = true _next_display = (_next_display + 1) % 12 + _status.text = "" + else: + _status.text = "交易请求发送失败" func _name_of(vnum: int) -> String: if proto and proto.has_method("item"): @@ -50,6 +72,9 @@ func refresh() -> void: if not x.get("active", false): _root.visible = false _next_display = 0 + _offered_cells.clear() + _gold_input.text = "" + _status.text = "" return _root.visible = true _fill(_self_box, x.get("self_items", [])) @@ -61,6 +86,7 @@ func refresh() -> void: _accept_btn.text = "已接受 ✓" if me else "接受" _accept_btn.modulate = Color(0.5, 1, 0.5) if me else Color(1, 1, 1) _root.get_node("PeerAccept").text = "对方: 已接受" if peer else "对方: 未接受" + _status.text = "" func _fill(box: VBoxContainer, rows: Array) -> void: for c in box.get_children(): @@ -72,9 +98,19 @@ func _fill(box: VBoxContainer, rows: Array) -> void: box.add_child(l) func _on_put_gold() -> void: - var g := int(_gold_input.text) - if g > 0: - client.exchange_add_gold(g) + var raw := _gold_input.text.strip_edges() + if raw == "" or not raw.is_valid_int(): + _status.text = "请输入有效金币数量" + return + var g := int(raw) + if g <= 0 or g > 2000000000: + _status.text = "金币数量必须在 1~2000000000 之间" + return + if client.exchange_add_gold(g): + _gold_input.text = "" + _status.text = "" + else: + _status.text = "金币请求发送失败" func _build(parent: Node) -> void: _root = Control.new() @@ -121,6 +157,11 @@ func _build(parent: Node) -> void: _peer_gold.text = "金币: 0" _peer_gold.position = Vector2(240, 250) _root.add_child(_peer_gold) + _status = Label.new() + _status.position = Vector2(20, 276) + _status.add_theme_font_size_override("font_size", 11) + _status.add_theme_color_override("font_color", Color(1, 0.65, 0.55)) + _root.add_child(_status) var pa := Label.new() pa.name = "PeerAccept" @@ -130,7 +171,7 @@ func _build(parent: Node) -> void: _root.add_child(pa) var bottom := HBoxContainer.new() - bottom.position = Vector2(20, 300) + bottom.position = Vector2(20, 310) _root.add_child(bottom) _gold_input = LineEdit.new() _gold_input.placeholder_text = "金币" diff --git a/project/ui/friend_ui.gd b/project/ui/friend_ui.gd index c7219b87..968e3d5d 100644 --- a/project/ui/friend_ui.gd +++ b/project/ui/friend_ui.gd @@ -15,12 +15,16 @@ var client: Node var _root: Control var _list: VBoxContainer var _name_edit: LineEdit +var _invite_dialog: ConfirmationDialog +var _pending_invite := "" func setup(m2client: Node, parent: Node) -> void: client = m2client _build(parent) if client.has_signal("friends_changed"): client.friends_changed.connect(refresh) + if client.has_signal("friend_invite_ask"): + client.friend_invite_ask.connect(_on_friend_invite) func is_open() -> bool: return _root != null and _root.visible @@ -55,9 +59,15 @@ func _row(f: Dictionary) -> Control: var nm := Button.new() nm.text = String(f.get("name", "?")) nm.flat = true - nm.custom_minimum_size = Vector2(180, 0) + nm.custom_minimum_size = Vector2(150, 0) nm.pressed.connect(func() -> void: whisper_to.emit(String(f.get("name", "")))) row.add_child(nm) + if f.get("mobile", false): + var mobile := Label.new() + mobile.text = "手机" + mobile.modulate = Color(0.45, 0.8, 1.0) + mobile.add_theme_font_size_override("font_size", 10) + row.add_child(mobile) var del := Button.new() del.text = "×" del.pressed.connect(func() -> void: client.remove_friend(String(f.get("name", "")))) @@ -70,6 +80,19 @@ func _on_add() -> void: client.add_friend(nm) _name_edit.clear() +func _on_friend_invite(name: String) -> void: + if client == null or name.strip_edges() == "": + return + _pending_invite = name + _invite_dialog.dialog_text = "接受“%s”的好友请求?" % name + _invite_dialog.popup_centered() + +func _answer_invite(accept: bool) -> void: + var name := _pending_invite + _pending_invite = "" + if name != "" and client != null and client.has_method("friend_answer"): + client.friend_answer(name, accept) + func _build(parent: Node) -> void: _root = Control.new() _root.set_anchors_preset(Control.PRESET_CENTER) @@ -105,3 +128,12 @@ func _build(parent: Node) -> void: add_btn.text = "添加" add_btn.pressed.connect(_on_add) bottom.add_child(add_btn) + _invite_dialog = ConfirmationDialog.new() + _invite_dialog.title = "好友请求" + _invite_dialog.ok_button_text = "接受" + _invite_dialog.cancel_button_text = "拒绝" + _invite_dialog.confirmed.connect(func() -> void: _answer_invite(true)) + _invite_dialog.canceled.connect(func() -> void: _answer_invite(false)) + # Keep the dialog outside the toggleable friend panel: requests must still + # be visible when the friend list window itself is closed. + parent.add_child(_invite_dialog) diff --git a/project/ui/game_option_ui.gd b/project/ui/game_option_ui.gd index 84cf578f..82b08a02 100644 --- a/project/ui/game_option_ui.gd +++ b/project/ui/game_option_ui.gd @@ -10,7 +10,7 @@ # `/setblockmode `(EBlockAction 位:1<<0..1<<5)—— 真聊天命令 # pvp_{peace,revenge,guild,free} (radio) → `/pkmode {0,1,4,2}` —— 真聊天命令 # name_color / target_board / view_chat / always_show_name / show_damage / salestext (radio) -# —— 客户端显示开关,持久化到 user://system_option.cfg [gameopt];渲染侧钩子待补。 +# —— 客户端显示开关,持久化到 user://system_option.cfg [gameopt];渲染节点按需读取这些设置。 extends Node # Packet.h EBlockAction @@ -67,9 +67,16 @@ var uiscript_dir := "" var _win: Dictionary = {} var _cfg := ConfigFile.new() -var _block_mode := 0 # blockMode(本地跟踪;服务器回包同步待补) +var _block_mode := 0 # blockMode(本地跟踪 + 服务端回包同步) var _display := {} # cfg [gameopt] 快照 +static func config_path() -> String: + var override_dir := OS.get_environment("MT_CONFIG_DIR") + if override_dir != "": + return override_dir.path_join("system_option.cfg") + return OS.get_temp_dir().path_join("mtgodot_system_option.cfg") \ + if DisplayServer.get_name() == "headless" else CFG_PATH + func setup(ui_manager: CanvasLayer, m2client: Node, assets := "") -> void: ui = ui_manager client = m2client @@ -79,10 +86,12 @@ func setup(ui_manager: CanvasLayer, m2client: Node, assets := "") -> void: uiscript_dir = assets_root.path_join("uiscript/uiscript") if not DirAccess.dir_exists_absolute(uiscript_dir): uiscript_dir = assets_root.path_join("uiscript") - _cfg.load(CFG_PATH) + _cfg.load(config_path()) for k in ["name_color", "target_board", "view_chat", "always_show_name", "show_damage", "salestext"]: _display[k] = int(_cfg.get_value("gameopt", k, 1 if k in ["view_chat", "always_show_name", "show_damage"] else 0)) _block_mode = int(_cfg.get_value("gameopt", "block_mode", 0)) + if client and client.has_signal("block_mode_changed"): + client.block_mode_changed.connect(_on_server_block_mode) func is_open() -> bool: return not _win.is_empty() and is_instance_valid(_win.get("root")) @@ -166,7 +175,9 @@ func _toggle_block(bit: int) -> void: if client and client.has_method("say"): client.say(0, "/setblockmode %d" % _block_mode) _cfg.set_value("gameopt", "block_mode", _block_mode) - _cfg.save(CFG_PATH) + var err := _cfg.save(config_path()) + if err != OK: + push_warning("GameOptionUI: save failed (%s): %s" % [err, config_path()]) _sync_block() # 开窗时把状态回填到控件 @@ -186,8 +197,16 @@ func _sync_block() -> void: if b is BaseButton: b.set_pressed_no_signal((_block_mode & int(BLOCK_BITS[nm])) != 0) +func _on_server_block_mode(mask: int) -> void: + _block_mode = maxi(0, mask) + _cfg.set_value("gameopt", "block_mode", _block_mode) + _cfg.save(config_path()) + _sync_block() + func _save() -> void: for k in _display: _cfg.set_value("gameopt", k, int(_display[k])) _cfg.set_value("gameopt", "block_mode", _block_mode) - _cfg.save(CFG_PATH) + var err := _cfg.save(config_path()) + if err != OK: + push_warning("GameOptionUI: save failed (%s): %s" % [err, config_path()]) diff --git a/project/ui/guild_ui.gd b/project/ui/guild_ui.gd index d6fce1b9..ce80b05c 100644 --- a/project/ui/guild_ui.gd +++ b/project/ui/guild_ui.gd @@ -1,4 +1,4 @@ -# GuildUI (P8/M4) —— 公会窗(G 键):成员 / 技能 / 公会战 三页。 +# GuildUI (P8/M4) —— 公会窗(G 键):成员 / 技能 / 公会战 / 公告 四页。 # # var gu := preload("res://ui/guild_ui.gd").new() # add_child(gu) @@ -9,12 +9,13 @@ # 到时刷会徽图。⬜ 等级页、日志页。 extends Node -const TABS := ["成员", "技能", "公会战"] +const TABS := ["成员", "技能", "公会战", "公告"] # EGuildWarState (wire.h) const WAR_STATE_NAMES := ["无", "已宣战", "被拒", "收到宣战", "待开始", "取消", "交战中", "结束"] var client: Node -var skill_table: RefCounted # SkillTable +var skill_table: Object # SkillTable (tests may provide a Node stub) +var _ui_parent: Node # 返回一张 Image(16×12,或任意会被转换/缩放)用作会徽上传源;null = 不显示上传按钮。 var mark_image_provider: Callable var _root: Control @@ -25,14 +26,20 @@ var _tab_btns: Array[Button] = [] var _pages: Array[VBoxContainer] = [] var _war_name_edit: LineEdit var _upload_status: Label +var _create_dialog: ConfirmationDialog +var _create_name_edit: LineEdit +var _create_status: Label -func setup(m2client: Node, parent: Node, table: RefCounted = null) -> void: +func setup(m2client: Node, parent: Node, table: Object = null) -> void: client = m2client skill_table = table + _ui_parent = parent _build(parent) - for sig in ["guild_changed", "guild_skill_changed", "guild_war_changed"]: + for sig in ["guild_changed", "guild_skill_changed", "guild_war_changed", "guild_comments_changed"]: if client.has_signal(sig): client.connect(sig, refresh) + if client.has_signal("guild_make_requested"): + client.guild_make_requested.connect(_on_guild_make_requested) if client.has_signal("guild_marks_ready"): client.guild_marks_ready.connect(func(_n): refresh()) if client.has_signal("guild_mark_uploaded"): @@ -73,6 +80,7 @@ func refresh() -> void: 0: _fill_members() 1: _fill_skills() 2: _fill_war(int(g.get("id", 0))) + 3: _fill_comments() func _fill_members() -> void: var page := _pages[0] @@ -109,9 +117,63 @@ func _fill_members() -> void: String(m.get("name", "?")), int(m.get("level", 0)), gname if gname != "" else str(gi), int(m.get("offer", 0)), - " ★" if m.get("general", false) else ""] + (" 在线" if m.get("online", false) else " 离线") + (" ★" if m.get("general", false) else "")] page.add_child(row) +func _fill_comments() -> void: + var page := _pages[3] + for c in page.get_children(): + c.queue_free() + if not client.has_method("get_guild_comments"): + var missing := Label.new() + missing.text = "(当前协议没有公告接口)" + page.add_child(missing) + return + var actions := HBoxContainer.new() + actions.add_theme_constant_override("separation", 5) + page.add_child(actions) + var edit := LineEdit.new() + edit.placeholder_text = "公告内容(最多 50 字)" + edit.custom_minimum_size = Vector2(245, 26) + actions.add_child(edit) + var post := Button.new() + post.text = "发布" + post.custom_minimum_size = Vector2(52, 26) + post.pressed.connect(func(): + var text := edit.text.strip_edges() + if text != "" and client.has_method("guild_post_comment"): + client.guild_post_comment(text)) + actions.add_child(post) + var refresh_btn := Button.new() + refresh_btn.text = "刷新" + refresh_btn.custom_minimum_size = Vector2(52, 26) + refresh_btn.pressed.connect(func(): + if client.has_method("guild_refresh_comments"): + client.guild_refresh_comments()) + actions.add_child(refresh_btn) + var comments: Array = client.get_guild_comments() + if comments.is_empty(): + var none := Label.new() + none.text = "(暂无公告)" + page.add_child(none) + return + for item in comments: + var row := HBoxContainer.new() + row.add_theme_constant_override("separation", 6) + page.add_child(row) + var label := Label.new() + label.custom_minimum_size = Vector2(286, 0) + label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + label.text = "%s:%s" % [String(item.get("name", "?")), String(item.get("content", ""))] + row.add_child(label) + var delete := Button.new() + delete.text = "删" + delete.custom_minimum_size = Vector2(32, 24) + delete.pressed.connect(func(): + if client.has_method("guild_delete_comment"): + client.guild_delete_comment(int(item.get("id", 0)))) + row.add_child(delete) + func _guild_skill_rows() -> Array: # skill_table 的 GUILD 分类给 id(升序);按顺序配 levels[i]。返回 [{id, name}]。 var out := [] @@ -236,6 +298,73 @@ func _on_mark_uploaded(ok: bool) -> void: if _upload_status: _upload_status.text = "✔ 已上传(等服务器刷新)" if ok else "✘ 上传失败" +# 40250 原版在收到 GC_REQUEST_MAKE_GUILD 后弹 InputDialog,再由玩家回送 +# CG_ANSWER_MAKE_GUILD。这里保留同样的“服务端请求 -> 输入 -> 应答”边界, +# 让名称校验发生在发包前,同时把最终权限 / 敏感词判断留给服务端。 +func _on_guild_make_requested() -> void: + if is_instance_valid(_create_dialog): + _create_dialog.popup_centered() + _create_name_edit.grab_focus() + return + if _ui_parent == null or client == null: + return + _create_dialog = ConfirmationDialog.new() + _create_dialog.name = "GuildCreateDialog" + _create_dialog.title = "创建公会" + _create_dialog.dialog_text = "请输入公会名称(最多 12 字)" + _create_dialog.ok_button_text = "创建" + _create_dialog.cancel_button_text = "取消" + _create_name_edit = LineEdit.new() + _create_name_edit.name = "GuildName" + _create_name_edit.max_length = 12 + _create_name_edit.placeholder_text = "公会名称" + _create_name_edit.custom_minimum_size = Vector2(250, 28) + _create_dialog.add_child(_create_name_edit) + _create_status = Label.new() + _create_status.name = "Status" + _create_status.add_theme_font_size_override("font_size", 11) + _create_status.modulate = Color(1.0, 0.7, 0.6) + _create_dialog.add_child(_create_status) + _ui_parent.add_child(_create_dialog) + _create_dialog.confirmed.connect(_on_guild_create_confirmed) + _create_dialog.canceled.connect(_close_guild_create_dialog) + _create_dialog.popup_centered() + _create_name_edit.grab_focus() + +func _on_guild_create_confirmed() -> void: + if not is_instance_valid(_create_dialog) or _create_name_edit == null: + return + var name := _create_name_edit.text.strip_edges() + var error := "" + if name.is_empty(): + error = "公会名称不能为空" + elif name.length() > 12: + error = "公会名称最多 12 字" + else: + for ch in name: + if ch.unicode_at(0) < 32: + error = "公会名称包含非法字符" + break + if error != "": + _create_status.text = error + _create_dialog.call_deferred("popup_centered") + _create_name_edit.call_deferred("grab_focus") + return + if not client.has_method("guild_answer_make") or not bool(client.call("guild_answer_make", name)): + _create_status.text = "创建请求发送失败" + _create_dialog.call_deferred("popup_centered") + _create_name_edit.call_deferred("grab_focus") + return + _close_guild_create_dialog() + +func _close_guild_create_dialog() -> void: + var dialog := _create_dialog + _create_dialog = null + _create_name_edit = null + _create_status = null + if is_instance_valid(dialog): + dialog.queue_free() + # 公会 id 变了就重新取会徽图(16x12,放大 3x 显示)。 func _refresh_mark(guild_id: int) -> void: if _mark == null: diff --git a/project/ui/mall_ui.gd b/project/ui/mall_ui.gd index 0ce607e4..774d25f9 100644 --- a/project/ui/mall_ui.gd +++ b/project/ui/mall_ui.gd @@ -12,6 +12,8 @@ var proto: Node var _root: Control var _list: VBoxContainer var _title: Label +var _status: Label +var _password_dialog: ConfirmationDialog func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client = m2client @@ -21,6 +23,8 @@ func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client.mall_opened.connect(func(_s): refresh()) if client.has_signal("mall_changed"): client.mall_changed.connect(refresh) + if client.has_signal("mall_password_required"): + client.mall_password_required.connect(_ask_password) func is_open() -> bool: return _root != null and _root.visible @@ -40,7 +44,7 @@ func _first_free_inv() -> int: for i in range(90): if not used.has(i): return i - return 0 + return -1 func refresh() -> void: if client == null or _root == null: @@ -48,6 +52,7 @@ func refresh() -> void: _root.visible = client.is_mall_open() if not _root.visible: return + _status.text = "" _title.text = "道具商城仓库(%d 格)" % client.get_mall_size() for c in _list.get_children(): c.queue_free() @@ -60,6 +65,31 @@ func refresh() -> void: for it in items: _list.add_child(_row(it)) +func _ask_password() -> void: + if is_instance_valid(_password_dialog): + _password_dialog.queue_free() + _password_dialog = ConfirmationDialog.new() + _password_dialog.title = "商城密码" + _password_dialog.dialog_text = "请输入 1~6 位密码" + _password_dialog.ok_button_text = "确认" + _password_dialog.cancel_button_text = "取消" + var edit := LineEdit.new() + edit.secret = true + edit.max_length = 6 + edit.placeholder_text = "密码" + edit.custom_minimum_size = Vector2(220, 28) + _password_dialog.add_child(edit) + _password_dialog.confirmed.connect(func() -> void: + if not client.mall_password(edit.text) and is_instance_valid(_status): + _status.text = "密码格式无效" + _password_dialog.queue_free() + _password_dialog = null) + _password_dialog.canceled.connect(func() -> void: + _password_dialog.queue_free() + _password_dialog = null) + _root.get_parent().add_child(_password_dialog) + _password_dialog.popup_centered() + func _row(it: Dictionary) -> Control: var row := HBoxContainer.new() row.custom_minimum_size = Vector2(300, 0) @@ -71,7 +101,13 @@ func _row(it: Dictionary) -> Control: var out := Button.new() out.text = "取出" var cell := int(it.get("cell", 0)) - out.pressed.connect(func() -> void: client.mall_checkout(cell, 1, _first_free_inv())) + out.pressed.connect(func() -> void: + var target := _first_free_inv() + if target < 0: + _status.text = "背包已满" + return + if not client.mall_checkout(cell, 1, target): + _status.text = "取出请求发送失败") row.add_child(out) return row @@ -92,6 +128,10 @@ func _build(parent: Node) -> void: _title.text = "道具商城仓库" _title.add_theme_font_size_override("font_size", 16) box.add_child(_title) + _status = Label.new() + _status.add_theme_font_size_override("font_size", 11) + _status.add_theme_color_override("font_color", Color(1, 0.65, 0.55)) + box.add_child(_status) var sc := ScrollContainer.new() sc.custom_minimum_size = Vector2(308, 280) box.add_child(sc) diff --git a/project/ui/mob_view.gd b/project/ui/mob_view.gd index 02b56721..8961f76b 100644 --- a/project/ui/mob_view.gd +++ b/project/ui/mob_view.gd @@ -119,9 +119,18 @@ func set_anim_state(s: String) -> void: anim.set("loop", s in ["wait", "walk", "run"]) anim.set("anim_path", msa) -# 供 net_world._on_info 用(如果它调 set_display_name) -func set_display_name(_n: String) -> void: - pass +# 供 net_world._on_info 用:真模型没有统一的名字节点时补一个。 +func set_display_name(n: String) -> void: + var tag := get_node_or_null("Label3D") as Label3D + if tag == null: + tag = Label3D.new() + tag.name = "Label3D" + tag.position.y = 2.1 + tag.billboard = BaseMaterial3D.BILLBOARD_ENABLED + tag.no_depth_test = true + tag.pixel_size = 0.006 + add_child(tag) + tag.text = n # --- 内部 ------------------------------------------------------------------- diff --git a/project/ui/party_ui.gd b/project/ui/party_ui.gd index 4628453d..104aff89 100644 --- a/project/ui/party_ui.gd +++ b/project/ui/party_ui.gd @@ -18,14 +18,14 @@ const ROLE_ATTACKER := 2 const ROLE_TANKER := 3 const ROLE_BUFFER := 4 const ROLE_SKILL_MASTER := 5 -const ROLE_BERSERKER := 6 +const ROLE_HASTE := 6 const ROLE_DEFENDER := 7 const ROLE_LABEL := { - 0: "普", 1: "队", 2: "攻", 3: "坦", 4: "辅", 5: "宗", 6: "狂", 7: "防", + 0: "普", 1: "队", 2: "攻", 3: "坦", 4: "辅", 5: "宗", 6: "速", 7: "防", } const ROLE_MENU := [ [ROLE_NORMAL, "普通"], [ROLE_ATTACKER, "攻击"], [ROLE_TANKER, "坦克"], - [ROLE_BERSERKER, "狂战"], [ROLE_BUFFER, "辅助"], [ROLE_SKILL_MASTER, "宗师"], + [ROLE_HASTE, "迅捷"], [ROLE_BUFFER, "辅助"], [ROLE_SKILL_MASTER, "宗师"], [ROLE_DEFENDER, "防御"], ] # Packet.h EPartyExpDistributionType @@ -34,13 +34,15 @@ const EXP_PARITY := 1 # 均分 # uiparty.PartyMemberInfoBoard.PARTY_SKILL_* const PARTY_SKILL_HEAL := 1 # affects[7] 槽位含义(暂定,按 partymemberinfoboard.py 图标顺序) -const AFFECT_LABEL := ["经验", "攻击", "防御", "辅助", "宗师", "时间", "回复"] +const AFFECT_LABEL := ["经验", "攻击", "坦克", "辅助", "宗师", "迅捷", "防御"] var client: Node var dialogs: Node var _root: Control var _list: VBoxContainer var _dist_btn: Button +var _heal_btn: Button +var _notice: Label var _role_popup: Control = null func setup(m2client: Node, parent: Node, dlg: Node = null) -> void: @@ -51,6 +53,8 @@ func setup(m2client: Node, parent: Node, dlg: Node = null) -> void: client.party_changed.connect(refresh) if client.has_signal("party_invite_ask"): client.party_invite_ask.connect(_on_invite) + if client.has_signal("party_request_denied"): + client.party_request_denied.connect(_on_request_denied) if client.has_signal("vitals_changed"): client.vitals_changed.connect(func(_v): if is_open(): refresh()) refresh() @@ -91,6 +95,37 @@ func _refresh_dist_btn() -> void: var mode := int(client.get_party_distribute_mode()) if client.has_method("get_party_distribute_mode") else 0 _dist_btn.text = "EXP:均分" if mode == EXP_PARITY else "EXP:不均分" _dist_btn.disabled = not _local_is_leader() + if is_instance_valid(_heal_btn): + var leadership := _leadership_level() + _heal_btn.disabled = not _local_is_leader() or (leadership >= 0 and leadership < 18) + _heal_btn.tooltip_text = "队长 Leadership 达到 18 级后可用" if _heal_btn.disabled and leadership >= 0 and leadership < 18 else "组队治疗" + +func _leadership_level() -> int: + # The server's CParty::Update gates party roles/heal using the leader's + # Leadership skill. -1 means that the snapshot has not arrived yet; in + # that case the server remains authoritative and the controls stay usable. + if client == null or not client.has_method("get_skills"): + return -1 + var skills: Array = client.get_skills() + for skill in skills: + if int(skill.get("id", -1)) == 121: # SKILL_LEADERSHIP in 40250 + return int(skill.get("level", 0)) + return -1 + +func _role_unlock_level(role: int) -> int: + match role: + ROLE_ATTACKER: return 10 + ROLE_TANKER, ROLE_HASTE: return 20 + ROLE_BUFFER: return 25 + ROLE_SKILL_MASTER: return 35 + ROLE_DEFENDER: return 40 + _: return 0 + +func _role_allowed(role: int, current_role: int = -1) -> bool: + if role == ROLE_NORMAL or role == current_role: + return true + var leadership := _leadership_level() + return leadership < 0 or leadership >= _role_unlock_level(role) # --- 한 명 strip ------------------------------------------------------ @@ -178,6 +213,9 @@ func _open_role_popup(anchor: Control, pid: int, cur_role: int) -> void: var b := Button.new() b.text = entry[1] + (" ✓" if r == cur_role else "") b.custom_minimum_size = Vector2(84, 22) + b.disabled = not _role_allowed(r, cur_role) + if b.disabled: + b.tooltip_text = "Leadership %d 级解锁" % _role_unlock_level(r) b.pressed.connect(func() -> void: if r == ROLE_NORMAL: # OnSelectState(-1): 清掉当前角色 @@ -213,6 +251,10 @@ func _on_invite(leader_pid: int) -> void: else: accept.call() +func _on_request_denied() -> void: + if is_instance_valid(_notice): + _notice.text = "组队请求被拒绝" + # --- EXP 분배 / 组队治疗 -------------------------------------------- func _toggle_distribute() -> void: @@ -255,7 +297,12 @@ func _build(parent: Node) -> void: heal.text = "组队治疗" heal.add_theme_font_size_override("font_size", 11) heal.pressed.connect(_party_heal) + _heal_btn = heal header.add_child(heal) + _notice = Label.new() + _notice.add_theme_font_size_override("font_size", 10) + _notice.add_theme_color_override("font_color", Color(1, 0.65, 0.55)) + header.add_child(_notice) _list = VBoxContainer.new() _list.position = Vector2(8, 32) diff --git a/project/ui/player_view.gd b/project/ui/player_view.gd index 0ba87050..9c4b27b9 100644 --- a/project/ui/player_view.gd +++ b/project/ui/player_view.gd @@ -17,6 +17,7 @@ const FEMALE_RACES := [1, 3, 4, 6] var model: Node # Metin2Model var anim: Node # Metin2AnimPlayer var motion_dir := "" +var action_dir := "" var _state := "" var _forward := ["weapon_gr2", "shield_gr2", "gr2_path", "hair_gr2", "hair_skin", "specular_power"] @@ -33,6 +34,7 @@ func build(assets_root: String, race: int, pump := Callable()) -> bool: if base == "": return false motion_dir = base.path_join("general") + action_dir = base.path_join("action") model = ClassDB.instantiate("Metin2Model") model.name = "Metin2Model" @@ -54,6 +56,8 @@ func build(assets_root: String, race: int, pump := Callable()) -> bool: anim.set("loop", true) anim.set("blend_time", 0.15) add_child(anim) + if anim.has_signal("playback_finished"): + anim.playback_finished.connect(_on_playback_finished) if pump.is_valid(): pump.call() set_anim_state("wait") # 重:解 .msa if pump.is_valid(): pump.call() @@ -71,6 +75,86 @@ func set_anim_state(s: String) -> void: anim.set("loop", s in ["wait", "walk", "run"]) anim.set("anim_path", msa) +# Play one of the 40250 CRaceMotionData one-shot motions. The protocol sends +# the numeric motion id; paired emotions use the other entity's race to select +# kiss/french-kiss variants, exactly like ActDualEmotion in the native client. +func set_motion_id(motion: int, target_race: int = -1) -> bool: + if anim == null: + return false + var name := "" + if motion == 305: + name = "clap" + elif motion == 306: + name = "cheers_1" + elif motion == 307: + name = "cheers_2" + elif motion >= 308 and motion <= 311: + var job := motion - 308 + if motion == 308 and target_race >= 0: + job = target_race & 3 + name = "kiss_with_" + CLASS_OF[clampi(job, 0, 3)] + elif motion >= 312 and motion <= 315: + var french_job := motion - 312 + if motion == 312 and target_race >= 0: + french_job = target_race & 3 + name = "french_kiss_with_" + CLASS_OF[clampi(french_job, 0, 3)] + elif motion >= 316 and motion <= 319: + name = "slap_hit" + elif motion >= 320 and motion <= 323: + name = "slap_hurt" + elif motion == 324: + name = "dig" + elif motion >= 325 and motion <= 340: + name = "dance_%d" % (motion - 324) + elif motion == 341: + name = "congratulation" + elif motion == 342: + name = "forgive" + elif motion == 343: + name = "angry" + elif motion == 344: + name = "attractive" + elif motion == 345: + name = "sad" + elif motion == 346: + name = "shy" + elif motion == 347: + name = "cheerup" + elif motion == 348: + name = "banter" + elif motion == 349: + name = "joy" + elif motion == 5 or motion == 6 or motion == 8 or motion == 9: + set_anim_state("damage") + return true + elif motion == 11 or motion == 12: + set_anim_state("dead") + return true + elif motion >= 13 and motion <= 21: + set_anim_state("attack") + return true + else: + return false + + var msa := action_dir.path_join(name + ".msa") + if not FileAccess.file_exists(msa): + msa = motion_dir.path_join(name + ".msa") + if not FileAccess.file_exists(msa): + return false + _state = "__motion" + anim.set("loop", false) + # A repeated command can name the same clip; clear first because the native + # player treats assigning the current anim_path as a no-op. + if String(anim.get("anim_path")) == msa: + anim.set("anim_path", "") + anim.set("anim_path", msa) + return true + +func _on_playback_finished() -> void: + if _state == "__motion": + _state = "" + set_anim_state("wait") + func _set(prop: StringName, val: Variant) -> bool: if String(prop) in _forward and model: model.set(prop, val) diff --git a/project/ui/private_shop_ui.gd b/project/ui/private_shop_ui.gd index 1390f3e6..ac2ab3ea 100644 --- a/project/ui/private_shop_ui.gd +++ b/project/ui/private_shop_ui.gd @@ -13,9 +13,23 @@ # (`OnSelectItemSlot` / `DelPrivateShopItemStock`)。OkButton(`BuildPrivateShop`):stock 按 # 格号排序、`display_pos = 格号`、上限 39(`PRIVATE_SHOP_ITEM_MAX_NUM`)打包成 # `M2Client.open_private_shop(sign, [{vnum,count,inv_cell,price,display_pos}])` -# (= `TPacketCGMyShop` + `TShopItemTable`×N)。철수 `close_private_shop()` = SHOP_CG_END。 +# (= `TPacketCGMyShop` + `TShopItemTable`×N)。40250 收摊用空的 `CG_MYSHOP` +# (服务端 `OpenMyShop` 会先关闭已有的个人摊位);`close_private_shop()` 已在 +# M2Client classic 分支按该语义发送。 extends Node +class PrivateShopDragButton extends Button: + var drag_entry: Dictionary = {} + + func _get_drag_data(_at_position: Vector2): + if drag_entry.is_empty(): + return null + var preview := Label.new() + preview.text = String(text) + preview.add_theme_color_override("font_color", Color(1, 0.9, 0.55)) + set_drag_preview(preview) + return {"private_shop_entry": drag_entry.duplicate(true)} + const PRIVATE_SHOP_ITEM_MAX := 39 # PRIVATE_SHOP_ITEM_MAX_NUM (TPacketCGMyShop::bCount 上限) const SIGN_MAX := 25 # NameLine input_limit @@ -33,6 +47,7 @@ var _status: Label var _stock: Dictionary = {} # 格号:int -> {cell, vnum, count, price} var _picked = null # {cell, vnum, count} 等待落位 var _price_dialog: Control = null +var _server_prices: Dictionary = {} # vnum -> last price returned by MyShopPriceList func setup(m2client: Node, ui_manager: CanvasLayer, proto_node: Node = null, assets := "") -> void: client = m2client @@ -46,6 +61,10 @@ func setup(m2client: Node, ui_manager: CanvasLayer, proto_node: Node = null, ass uiscript_dir = assets_root.path_join("uiscript") if client and client.has_signal("inventory_changed"): client.inventory_changed.connect(func(_w, _c): if is_open(): _refresh()) + if client and client.has_signal("my_shop_price_list"): + client.my_shop_price_list.connect(_on_server_price) + if client and client.has_signal("private_shop_open_requested"): + client.private_shop_open_requested.connect(open) # --- open / close -------------------------------------------------- @@ -101,6 +120,10 @@ func _index_cells(root: Node) -> void: n.gui_input.connect(func(e: InputEvent) -> void: if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT and e.pressed: _on_slot_clicked(idx)) + # 同时支持从右侧背包候选区拖到空货位;点击选取仍保留给触屏/无鼠标场景。 + n.set_drag_forwarding(Callable(self, "_no_drag_data"), + Callable(self, "_can_drop_slot").bind(idx), + Callable(self, "_drop_slot").bind(idx)) # NameLine 在 uiscript 里是 text(Label)—— 盖一个 LineEdit 上去 func _overlay_name_edit(root: Control) -> void: @@ -194,12 +217,13 @@ func _refresh_inv() -> void: continue var vnum := int(it.get("vnum", 0)) var count := int(it.get("count", 1)) - var b := Button.new() + var b := PrivateShopDragButton.new() b.text = "%s ×%d" % [_name_of(vnum), count] b.alignment = HORIZONTAL_ALIGNMENT_LEFT b.custom_minimum_size = Vector2(196, 22) b.toggle_mode = true var entry := {"cell": cell, "vnum": vnum, "count": count} + b.drag_entry = entry b.pressed.connect(func() -> void: _pick(entry, b)) if _picked != null and int(_picked["cell"]) == cell: b.button_pressed = true @@ -246,6 +270,20 @@ func _pick(entry: Dictionary, _btn: Button) -> void: _picked = entry _refresh_grid() +func _no_drag_data(_at_position: Vector2): + return null + +func _can_drop_slot(_at_position: Vector2, data, slot: int) -> bool: + return slot >= 0 and slot < 40 and not _stock.has(slot) \ + and data is Dictionary and data.has("private_shop_entry") + +func _drop_slot(_at_position: Vector2, data, slot: int) -> void: + if not _can_drop_slot(Vector2.ZERO, data, slot): + return + var entry: Dictionary = data["private_shop_entry"] as Dictionary + _picked = entry.duplicate(true) + _ask_price(slot) + func _on_slot_clicked(slot: int) -> void: if _stock.has(slot): _stock.erase(slot) @@ -276,7 +314,10 @@ func _ask_price(slot: int) -> void: spin.min_value = 1 spin.max_value = 2000000000 spin.step = 1 - spin.value = int(_stock.get(slot, {}).get("price", 1)) + var default_price := int(_server_prices.get(int(_picked["vnum"]), 1)) + if _stock.has(slot): + default_price = int(_stock[slot].get("price", default_price)) + spin.value = default_price spin.position = Vector2(12, 40) spin.size = Vector2(216, 28) dlg.add_child(spin) @@ -299,7 +340,7 @@ func _dismiss_price_dialog() -> void: _price_dialog = null func _place(slot: int, price: int) -> void: - if price <= 0 or _picked == null: + if slot < 0 or slot >= 40 or price <= 0 or price > 2000000000 or _picked == null: _dismiss_price_dialog() return _stock[slot] = {"cell": int(_picked["cell"]), "vnum": int(_picked["vnum"]), @@ -308,7 +349,16 @@ func _place(slot: int, price: int) -> void: _dismiss_price_dialog() _refresh() +func _on_server_price(vnum: int, price: int) -> void: + if vnum > 0 and price >= 0: + _server_prices[vnum] = price + func _ok() -> void: + var sign := _sign.text.strip_edges() + if sign.is_empty() or sign.length() > SIGN_MAX: + if is_instance_valid(_status): + _status.text = "请输入 1~%d 个字符的摊位名称" % SIGN_MAX + return if _stock.is_empty(): if is_instance_valid(_status): _status.text = "판매할 아이템을 올리세요" @@ -323,8 +373,10 @@ func _ok() -> void: items.append({"vnum": s["vnum"], "count": s["count"], "inv_cell": s["cell"], "price": s["price"], "display_pos": slot}) if client and client.has_method("open_private_shop"): - client.open_private_shop(_sign.text.strip_edges(), items) - close() + if client.open_private_shop(sign, items): + close() + elif is_instance_valid(_status): + _status.text = "摆摊请求发送失败" func _close_shop() -> void: if client and client.has_method("close_private_shop"): diff --git a/project/ui/refine_ui.gd b/project/ui/refine_ui.gd index 9fbff0ea..961bd908 100644 --- a/project/ui/refine_ui.gd +++ b/project/ui/refine_ui.gd @@ -20,6 +20,8 @@ func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: _build(parent) if client.has_signal("refine_ask"): client.refine_ask.connect(_on_ask) + if client.has_signal("refine_result"): + client.refine_result.connect(_on_result) func is_open() -> bool: return _root != null and _root.visible @@ -53,6 +55,11 @@ func _do_refine() -> void: client.refine(int(_cur.get("pos", 0)), int(_cur.get("type", 0))) _root.visible = false +func _on_result(ok: bool) -> void: + _cur = {} + _text.text = "[b]精炼成功[/b]" if ok else "[b]精炼失败[/b]" + _root.visible = true + func _build(parent: Node) -> void: _root = Control.new() _root.set_anchors_preset(Control.PRESET_CENTER) diff --git a/project/ui/safebox_ui.gd b/project/ui/safebox_ui.gd index 201a7c36..43a06ec6 100644 --- a/project/ui/safebox_ui.gd +++ b/project/ui/safebox_ui.gd @@ -15,6 +15,8 @@ var _root: Control var _list: VBoxContainer var _gold: Label var _title: Label +var _status: Label +var _password_dialog: ConfirmationDialog func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client = m2client @@ -22,13 +24,25 @@ func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: _build(parent) if client.has_signal("safebox_changed"): client.safebox_changed.connect(refresh) + if client.has_signal("safebox_password_required"): + client.safebox_password_required.connect(func(): _ask_password("safebox")) + if client.has_signal("safebox_wrong_password"): + client.safebox_wrong_password.connect(func(): + if is_instance_valid(_status): + _status.text = "仓库密码错误") func is_open() -> bool: return _root != null and _root.visible func deposit(inv_window: int, inv_cell: int) -> void: - if is_open(): - client.safebox_checkin(_next_free_slot(), inv_window, inv_cell) + if not is_open() or inv_window < 0 or inv_cell < 0: + return + var safe_pos := _next_free_slot() + if safe_pos < 0: + _status.text = "仓库已满" + return + if client.has_method("safebox_checkin") and not client.safebox_checkin(safe_pos, inv_window, inv_cell): + _status.text = "存入请求发送失败" func _next_free_slot() -> int: var used := {} @@ -38,7 +52,7 @@ func _next_free_slot() -> int: for i in range(cap): if not used.has(i): return i - return 0 + return -1 func _name_of(vnum: int) -> String: if proto and proto.has_method("item"): @@ -54,6 +68,7 @@ func refresh() -> void: _root.visible = client.is_safebox_open() if not _root.visible: return + _status.text = "" _title.text = "仓库(%d 页)" % client.get_safebox_size() _gold.text = "仓库金币: %d" % client.get_safebox_gold() for c in _list.get_children(): @@ -67,6 +82,32 @@ func refresh() -> void: for it in items: _list.add_child(_row(it)) +func _ask_password(kind: String) -> void: + if is_instance_valid(_password_dialog): + _password_dialog.queue_free() + _password_dialog = ConfirmationDialog.new() + _password_dialog.title = "商城密码" if kind == "mall" else "仓库密码" + _password_dialog.dialog_text = "请输入 1~6 位密码" + _password_dialog.ok_button_text = "确认" + _password_dialog.cancel_button_text = "取消" + var edit := LineEdit.new() + edit.secret = true + edit.max_length = 6 + edit.placeholder_text = "密码" + edit.custom_minimum_size = Vector2(220, 28) + _password_dialog.add_child(edit) + _password_dialog.confirmed.connect(func() -> void: + var sent: bool = client.safebox_password(edit.text) if kind == "safebox" else client.mall_password(edit.text) + if not sent and is_instance_valid(_status): + _status.text = "密码格式无效" + _password_dialog.queue_free() + _password_dialog = null) + _password_dialog.canceled.connect(func() -> void: + _password_dialog.queue_free() + _password_dialog = null) + _root.get_parent().add_child(_password_dialog) + _password_dialog.popup_centered() + func _row(it: Dictionary) -> Control: var row := HBoxContainer.new() row.custom_minimum_size = Vector2(300, 0) @@ -78,7 +119,13 @@ func _row(it: Dictionary) -> Control: var out := Button.new() out.text = "取出" var cell := int(it.get("cell", 0)) - out.pressed.connect(func() -> void: client.safebox_checkout(cell, 1, _first_free_inv())) + out.pressed.connect(func() -> void: + var target := _first_free_inv() + if target < 0: + _status.text = "背包已满" + return + if not client.safebox_checkout(cell, 1, target): + _status.text = "取出请求发送失败") row.add_child(out) return row @@ -89,7 +136,7 @@ func _first_free_inv() -> int: for i in range(90): if not used.has(i): return i - return 0 + return -1 func _build(parent: Node) -> void: _root = Control.new() @@ -116,6 +163,11 @@ func _build(parent: Node) -> void: _gold.modulate = Color(0.95, 0.85, 0.5) _gold.add_theme_font_size_override("font_size", 12) _root.add_child(_gold) + _status = Label.new() + _status.position = Vector2(12, 382) + _status.add_theme_font_size_override("font_size", 11) + _status.add_theme_color_override("font_color", Color(1, 0.65, 0.55)) + _root.add_child(_status) _list = VBoxContainer.new() _list.position = Vector2(12, 54) _list.add_theme_constant_override("separation", 4) diff --git a/project/ui/shop_ui.gd b/project/ui/shop_ui.gd index fc1645cf..05533bfc 100644 --- a/project/ui/shop_ui.gd +++ b/project/ui/shop_ui.gd @@ -18,6 +18,7 @@ var _root: Control var _tabbar: HBoxContainer var _list: VBoxContainer var _err: Label +var _sell_quantity: SpinBox var _active_tab := 0 func setup(m2client: Node, parent: Node, proto_node: Node = null, ilist: RefCounted = null) -> void: @@ -38,19 +39,27 @@ func is_open() -> bool: func open() -> void: _root.visible = true _err.text = "" + _sell_quantity.value = 1 _active_tab = 0 refresh() func _close() -> void: _root.visible = false + _err.text = "" + if _sell_quantity: + _sell_quantity.value = 1 func close_and_leave() -> void: client.shop_close() _close() -func sell(inv_cell: int, count: int = 1) -> void: - if is_open(): - client.shop_sell(inv_cell, count) +func sell(inv_cell: int, count: int = -1) -> void: + if not is_open() or inv_cell < 0: + return + var amount := count if count > 0 else int(_sell_quantity.value) + amount = clampi(amount, 1, 200) + if client.has_method("shop_sell") and not client.shop_sell(inv_cell, amount): + _on_error("SEND_FAILED") func _name_of(vnum: int) -> String: if proto and proto.has_method("item"): @@ -122,7 +131,19 @@ func _row(it: Dictionary, pos_base := 0) -> Control: var buy := Button.new() buy.text = "买" var pos := pos_base + int(it.get("pos", 0)) - buy.pressed.connect(func() -> void: client.shop_buy(pos, 1)) + var stock := int(it.get("count", 0)) + var quantity := SpinBox.new() + quantity.name = "Quantity" + quantity.min_value = 1 + quantity.max_value = clampi(stock if stock > 0 else 200, 1, 200) + quantity.step = 1 + quantity.value = 1 + quantity.custom_minimum_size = Vector2(64, 0) + row.add_child(quantity) + buy.pressed.connect(func() -> void: + var amount := clampi(int(quantity.value), 1, int(quantity.max_value)) + if not client.shop_buy(pos, amount): + _on_error("SEND_FAILED")) row.add_child(buy) return row @@ -132,6 +153,11 @@ func _on_error(kind: String) -> void: "SOLDOUT": "已售罄", "INVENTORY_FULL": "背包已满", "INVALID_POS": "位置无效", + "NOT_ENOUGH_ITEM": "物品数量不足", + "CANNOT_BUY": "当前物品不可购买", + "CANNOT_SELL": "当前物品不可出售", + "SHOP_BUSY": "商店正在处理上一笔交易", + "SEND_FAILED": "交易请求发送失败", } _err.text = str(tbl.get(kind, kind)) @@ -159,6 +185,20 @@ func _build(parent: Node) -> void: _err.modulate = Color(1, 0.4, 0.4) _err.add_theme_font_size_override("font_size", 12) _root.add_child(_err) + var sell_hint := Label.new() + sell_hint.text = "出售数量(背包右键):" + sell_hint.position = Vector2(12, 360) + sell_hint.add_theme_font_size_override("font_size", 11) + _root.add_child(sell_hint) + _sell_quantity = SpinBox.new() + _sell_quantity.name = "SellQuantity" + _sell_quantity.min_value = 1 + _sell_quantity.max_value = 200 + _sell_quantity.value = 1 + _sell_quantity.step = 1 + _sell_quantity.position = Vector2(160, 356) + _sell_quantity.size = Vector2(70, 26) + _root.add_child(_sell_quantity) _tabbar = HBoxContainer.new() _tabbar.position = Vector2(12, 30) _tabbar.add_theme_constant_override("separation", 4) diff --git a/project/ui/system_option_ui.gd b/project/ui/system_option_ui.gd index 4d6322ba..28104248 100644 --- a/project/ui/system_option_ui.gd +++ b/project/ui/system_option_ui.gd @@ -45,6 +45,15 @@ var camera_mode := 1 # 0 近, 1 远 var fog_level := 1 # 0 浓, 1 中, 2 淡 var tiling_mode := 1 # 0 CPU, 1 GPU(占位) +static func config_path() -> String: + var override_dir := OS.get_environment("MT_CONFIG_DIR") + if override_dir != "": + return override_dir.path_join("system_option.cfg") + # Godot headless 在受限执行环境里可能无法写 user://;测试配置放在系统 + # 临时目录,正常图形客户端仍使用 user://。 + return OS.get_temp_dir().path_join("mtgodot_system_option.cfg") \ + if DisplayServer.get_name() == "headless" else CFG_PATH + func setup(ui_manager: CanvasLayer, assets: String, audio_node: Node = null, cam_getter := Callable(), env_getter := Callable()) -> void: ui = ui_manager @@ -228,7 +237,7 @@ func _apply_fog() -> void: # --- persistence (= systemSetting 配置文件) -------------------------- func _load_cfg() -> void: - if _cfg.load(CFG_PATH) != OK: + if _cfg.load(config_path()) != OK: return music_volume = float(_cfg.get_value("audio", "music_volume", music_volume)) sound_volume = float(_cfg.get_value("audio", "sound_volume", sound_volume)) @@ -242,4 +251,6 @@ func _save() -> void: _cfg.set_value("video", "camera_mode", camera_mode) _cfg.set_value("video", "fog_level", fog_level) _cfg.set_value("video", "tiling_mode", tiling_mode) - _cfg.save(CFG_PATH) + var err := _cfg.save(config_path()) + if err != OK: + push_warning("SystemOptionUI: save failed (%s): %s" % [err, config_path()]) diff --git a/project/ui/ui_assets.gd b/project/ui/ui_assets.gd index 92e792f3..50a3d502 100644 --- a/project/ui/ui_assets.gd +++ b/project/ui/ui_assets.gd @@ -68,6 +68,10 @@ static func _load_uncached(assets_root: String, vpath: String) -> Texture2D: return _load_image_file(real) static func _load_image_file(path: String) -> Texture2D: + # .sub 文件可能引用了未随当前资源包发布的共享贴图(例如 Public.tga)。 + # 先做存在性检查,避免 headless/UI fallback 因缺失可选贴图刷错误日志。 + if not FileAccess.file_exists(path): + return null var ext := path.get_extension().to_lower() if ext == "dds": var di := load_dds_image(path) @@ -99,6 +103,8 @@ static func _load_sub(path: String) -> Texture2D: var img_path := path.get_base_dir().path_join(image_name) if not FileAccess.file_exists(img_path): img_path = path.get_base_dir().path_join(image_name.get_basename() + ".tga") + if not FileAccess.file_exists(img_path): + return null var base := _load_image_file(img_path) if base == null: return null diff --git a/tools/40250/README.md b/tools/40250/README.md new file mode 100644 index 00000000..5ab3dac9 --- /dev/null +++ b/tools/40250/README.md @@ -0,0 +1,97 @@ +# 40250 FreeBSD + MySQL live E2E + +这组脚本把文档里最后一个不能在 macOS 本机完成的前置变成可执行入口: + +1. 在 FreeBSD jail/VM 准备 40250 server tree、MySQL 和 32-bit toolchain。 +2. 导入 `metin2_mysql_dump/{account,common,log,player}.sql`。 +3. 编译(或使用已编译的)`game` / `db`,安装 server runtime links。 +4. 启动 db、auth、channel 1–4 和 game99。 +5. 用 `net_classic_e2e_host` 验证 DH2/CTR、登录、选角和 `PHASE_GAME`。 + +当前 Mac 环境没有 FreeBSD 或 MySQL server,因此这里只能完成脚本、构建配置和 +离线协议测试;不能把真实服结果冒充为已执行。脚本均使用环境变量,避免把本机 +路径或密码写死到工程中。 + +## 复制/准备目录 + +```sh +export MT40250_ROOT=/usr/metin2 +export MT40250_DUMP_ROOT=/usr/metin2_mysql_dump +``` + +`MT40250_ROOT` 必须是包含 `src/server` 和 `server/` 的 40250 server tree。 +官方 Makefile 默认把二进制放到 `/usr/metin2/server/share/bin`,所以推荐保持 +这个路径;若使用其他路径,必须同时确保 Makefile 的 `GAMEDIR`/`DBDIR` 指向 +对应 runtime 目录。 + +## FreeBSD 安装与编译 + +依赖由管理员按镜像版本安装,典型组合如下(具体包名以目标 FreeBSD 版本为准): + +```sh +pkg install gmake clang-devel mysql80-server mysql80-client +sh tools/40250/build_server.sh +``` + +源码 Makefile 是 40250 原版,使用 `clang++-devel`、`-m32`、静态 MySQL client、 +Crypto++ 8.4.0 和 FreeBSD 系统库;`build_server.sh` 会执行原始的 `gmake -C +src/server all`,失败时应保留完整编译输出修复 jail 的 32-bit/库依赖。 + +## 初始化数据库 + +先启动 MySQL,再执行: + +```sh +export MT40250_MYSQL_ROOT_PASSWORD='你的 root 密码' # 不设置则每次交互式 -p +export MT40250_DB_PASSWORD=password # 必须与 CONFIG 一致,默认 password +sh tools/40250/setup_mysql.sh +``` + +脚本创建 `account/common/log/player`,并同时建立 `metin2@localhost` 与 +`metin2@127.0.0.1`;这是因为 CONFIG 使用 TCP `127.0.0.1`,而旧 Readme 只写了 +`localhost`。导入后会执行最小连接检查。 + +## 启停 40250 服务 + +```sh +sh tools/40250/prepare_runtime.sh +sh tools/40250/start_server.sh +sh tools/40250/stop_server.sh +``` + +`start_server.sh` 使用仓库自带 CONFIG:auth `11000`、channel1/first `13000`, +并启动 channel1–4 与 game99。每个进程的 stdout/stderr 写入其 runtime 目录的 +`console.log`,PID 只记录在 `$MT40250_ROOT/.mt40250-pids`;停止脚本只终止这份 +PID 文件中的进程。可用 `MT40250_CHANNELS='1'` 只启动 channel1,或设置 +`MT40250_START_GAME99=0` 跳过 game99。 + +## 编译/运行 classic 探针 + +FreeBSD 不能启用 Godot extension,但顶层 CMake 提供了 host-only 模式: + +```sh +cmake -S . -B build-classic \ + -DMTGODOT_BUILD_EXTENSION=OFF \ + -DMTGODOT_BUILD_NET_TOOLS=ON \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build-classic --target net_classic_e2e_host -j2 + +build-classic/net_classic_e2e_host 127.0.0.1 13000 test_account test_password 0 30 +``` + +探针成功的判据是输出 `PASS PHASE_GAME`,并且打印主角 VID、实体数、背包槽位数 +和等级。它不会自动创建角色、交易、购买或移动仓库物品;这些操作属于有副作用的 +fixture 测试,应在测试账号/NPC/第二账号准备后通过 Godot UI 或对应 `M2Client` +intent 逐项操作:好友 add/remove、exchange start/item/gold/accept/cancel、 +NPC safebox checkin/checkout/move、mall checkout、Cube open/add/delete/make。 + +## 40250 配置核对 + +- `auth/CONFIG`: `PORT 11000`。 +- `channel1/first/CONFIG`: `PORT 13000`,`MAP_ALLOW` 包含起始地图。 +- 所有 CONFIG 的 DB 端口是 `15000`,由 `server/db/conf.txt` 控制。 +- `PLAYER_SQL` 指向 `player`,auth 的 `PLAYER_SQL` 指向 `account`,两者与原服 + 源码约定一致。 +- `service.h` 默认定义 `_IMPROVED_PACKET_ENCRYPTION_`;classic 客户端必须走 + DH2 + CTR,不能用“明文配置项”绕过。若专门做明文诊断,必须复制源码、重新 + 编译 game,并把它视为与 shipped server 不同的测试构建。 diff --git a/tools/40250/build_server.sh b/tools/40250/build_server.sh new file mode 100755 index 00000000..3ef730e9 --- /dev/null +++ b/tools/40250/build_server.sh @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu + +if [ "$(uname -s)" != "FreeBSD" ]; then + echo "build_server.sh: 40250 server Makefile is FreeBSD-only" >&2 + exit 2 +fi + +server_root=${MT40250_ROOT:-/usr/metin2} +if [ ! -d "$server_root/src/server" ]; then + echo "build_server.sh: missing $server_root/src/server" >&2 + exit 2 +fi +if ! command -v gmake >/dev/null 2>&1; then + echo "build_server.sh: install gmake first" >&2 + exit 2 +fi + +cd "$server_root" +gmake -C src/server all diff --git a/tools/40250/prepare_runtime.sh b/tools/40250/prepare_runtime.sh new file mode 100755 index 00000000..6b14a7c2 --- /dev/null +++ b/tools/40250/prepare_runtime.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu + +server_root=${MT40250_ROOT:-/usr/metin2} +runtime="$server_root/server" +if [ "$(uname -s)" != "FreeBSD" ]; then + echo "prepare_runtime.sh: runtime binaries are FreeBSD-only" >&2 + exit 2 +fi +if [ ! -x "$runtime/install.sh" ]; then + echo "prepare_runtime.sh: missing $runtime/install.sh" >&2 + exit 2 +fi + +cd "$runtime" +sh ./install.sh +echo "40250 runtime links and log/core directories ready under $runtime" diff --git a/tools/40250/run_classic_e2e.sh b/tools/40250/run_classic_e2e.sh new file mode 100755 index 00000000..47347806 --- /dev/null +++ b/tools/40250/run_classic_e2e.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu + +cli=${MTGODOT_CLASSIC_E2E:-} +if [ -z "$cli" ]; then + build_root=${MTGODOT_CLASSIC_BUILD:-build-classic} + cli="$build_root/net_classic_e2e_host" +fi +if [ ! -x "$cli" ]; then + echo "run_classic_e2e.sh: missing $cli; build with -DMTGODOT_BUILD_NET_TOOLS=ON" >&2 + exit 2 +fi + +host=${MT40250_GAME_HOST:-127.0.0.1} +port=${MT40250_GAME_PORT:-13000} +: "${MT40250_ACCOUNT_ID:?set MT40250_ACCOUNT_ID}" +: "${MT40250_ACCOUNT_PASSWORD:?set MT40250_ACCOUNT_PASSWORD}" +slot=${MT40250_CHARACTER_SLOT:-0} +timeout=${MT40250_E2E_TIMEOUT_SECONDS:-30} + +exec "$cli" "$host" "$port" "$MT40250_ACCOUNT_ID" "$MT40250_ACCOUNT_PASSWORD" "$slot" "$timeout" diff --git a/tools/40250/setup_mysql.sh b/tools/40250/setup_mysql.sh new file mode 100755 index 00000000..2a9ec81b --- /dev/null +++ b/tools/40250/setup_mysql.sh @@ -0,0 +1,45 @@ +#!/bin/sh +set -eu + +dump_root=${MT40250_DUMP_ROOT:-/usr/metin2_mysql_dump} +mysql_bin=${MT40250_MYSQL_BIN:-} +if [ -z "$mysql_bin" ]; then + mysql_bin=$(command -v mysql || true) +fi +if [ -z "$mysql_bin" ] || [ ! -x "$mysql_bin" ]; then + echo "setup_mysql.sh: mysql client not found" >&2 + exit 2 +fi +for db in account common log player; do + if [ ! -f "$dump_root/$db.sql" ]; then + echo "setup_mysql.sh: missing $dump_root/$db.sql" >&2 + exit 2 + fi +done + +db_password=${MT40250_DB_PASSWORD:-password} +case "$db_password" in + *"'"*) echo "setup_mysql.sh: DB password may not contain a single quote" >&2; exit 2 ;; +esac + +mysql_root() { + if [ -n "${MT40250_MYSQL_ROOT_PASSWORD:-}" ]; then + MYSQL_PWD="$MT40250_MYSQL_ROOT_PASSWORD" "$mysql_bin" -u root "$@" + else + "$mysql_bin" -u root -p "$@" + fi +} + +mysql_root -e "CREATE DATABASE IF NOT EXISTS account; CREATE DATABASE IF NOT EXISTS common; CREATE DATABASE IF NOT EXISTS log; CREATE DATABASE IF NOT EXISTS player; CREATE USER IF NOT EXISTS 'metin2'@'localhost' IDENTIFIED BY '$db_password'; CREATE USER IF NOT EXISTS 'metin2'@'127.0.0.1' IDENTIFIED BY '$db_password'; ALTER USER 'metin2'@'localhost' IDENTIFIED BY '$db_password'; ALTER USER 'metin2'@'127.0.0.1' IDENTIFIED BY '$db_password'; GRANT ALL PRIVILEGES ON *.* TO 'metin2'@'localhost' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'metin2'@'127.0.0.1' WITH GRANT OPTION; FLUSH PRIVILEGES;" + +for db in account common log player; do + echo "importing $db.sql" + if [ -n "${MT40250_MYSQL_ROOT_PASSWORD:-}" ]; then + MYSQL_PWD="$MT40250_MYSQL_ROOT_PASSWORD" "$mysql_bin" -u root "$db" < "$dump_root/$db.sql" + else + "$mysql_bin" -u root -p "$db" < "$dump_root/$db.sql" + fi +done + +mysql_root -e "SELECT 1 AS metin2_database_ready;" +echo "40250 databases ready" diff --git a/tools/40250/start_server.sh b/tools/40250/start_server.sh new file mode 100755 index 00000000..cf36d0e5 --- /dev/null +++ b/tools/40250/start_server.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -eu + +server_root=${MT40250_ROOT:-/usr/metin2} +runtime="$server_root/server" +pid_file="$server_root/.mt40250-pids" +if [ "$(uname -s)" != "FreeBSD" ]; then + echo "start_server.sh: 40250 runtime is FreeBSD-only" >&2 + exit 2 +fi +if [ ! -x "$runtime/db/db" ] || [ ! -x "$runtime/auth/auth" ]; then + echo "start_server.sh: run prepare_runtime.sh first" >&2 + exit 2 +fi +if [ -f "$pid_file" ]; then + echo "start_server.sh: $pid_file exists; stop the existing server first" >&2 + exit 2 +fi + +launch() { + name=$1 + dir=$2 + bin=$3 + if [ ! -x "$dir/$bin" ]; then + echo "start_server.sh: missing $dir/$bin" >&2 + exit 2 + fi + ( + cd "$dir" + exec "./$bin" + ) >> "$dir/console.log" 2>&1 & + pid=$! + echo "$pid $name" >> "$pid_file" + echo "started $name pid=$pid" +} + +: > "$pid_file" +launch db "$runtime/db" db +sleep "${MT40250_DB_WAIT_SECONDS:-2}" +launch auth "$runtime/auth" auth + +channels=${MT40250_CHANNELS:-"1 2 3 4"} +for channel in $channels; do + for node in first game1 game2; do + launch "channel${channel}/${node}" "$runtime/channel${channel}/${node}" game + done +done + +if [ "${MT40250_START_GAME99:-1}" = "1" ]; then + launch game99 "$runtime/game99" game +fi + +echo "40250 server started; logs are under $runtime/*/console.log" diff --git a/tools/40250/stop_server.sh b/tools/40250/stop_server.sh new file mode 100755 index 00000000..b8ed6abc --- /dev/null +++ b/tools/40250/stop_server.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu + +server_root=${MT40250_ROOT:-/usr/metin2} +pid_file="$server_root/.mt40250-pids" +if [ ! -f "$pid_file" ]; then + echo "stop_server.sh: no $pid_file" + exit 0 +fi + +while read -r pid name; do + case "$pid" in + ''|*[!0-9]*) continue ;; + esac + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + echo "stopped $name pid=$pid" + fi +done < "$pid_file" + +rm -f "$pid_file"