From 8721db90fcc8e05c39e04058d15b3be2e4281b89 Mon Sep 17 00:00:00 2001 From: Dutchman101 <12105539+Dutchman101@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:01:24 +0000 Subject: [PATCH 01/23] Update CEF to 126.2.4+g5e718e0+chromium-126.0.6478.62 Fixes crash (libcef @ 0x05814CB1) --- utils/buildactions/install_cef.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/buildactions/install_cef.lua b/utils/buildactions/install_cef.lua index 288fe10362..1f520c2290 100644 --- a/utils/buildactions/install_cef.lua +++ b/utils/buildactions/install_cef.lua @@ -9,8 +9,8 @@ local CEF_URL_PREFIX = "https://cef-builds.spotifycdn.com/cef_binary_" local CEF_URL_SUFFIX = "_windows32_minimal.tar.bz2" -- Change here to update CEF version -local CEF_VERSION = "126.2.0+g5c56e98+chromium-126.0.6478.62" -local CEF_HASH = "c32e4fc19ad8ffae54eba08c8d57148b6d25487a8ab0c37db5fd20ccf19fd34d" +local CEF_VERSION = "126.2.4+g5e718e0+chromium-126.0.6478.62" +local CEF_HASH = "59c00bc49a600674643d09af717ccd91eca2458310c94ab22b56db80bbca4928" function make_cef_download_url() return CEF_URL_PREFIX..http.escapeUrlParam(CEF_VERSION)..CEF_URL_SUFFIX From 13c38fcfe8c5fd277ffb251f75bf6db35dc50410 Mon Sep 17 00:00:00 2001 From: Pot Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:03:56 +0000 Subject: [PATCH 02/23] Update client en_US pot [ci skip] --- .../MTA/locale/en_US/client.pot | 3737 +++++++++-------- 1 file changed, 1869 insertions(+), 1868 deletions(-) diff --git a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot index 801286d0e7..57c5cea0ed 100644 --- a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot +++ b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: MTA San Andreas 1.x\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-16 01:10+0000\n" +"POT-Creation-Date: 2024-06-20 22:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,6 +18,44 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +#. Create buttons +#. OK button +#: Client/gui/CGUIMessageBox_Impl.cpp:64 Client/core/CSettings.cpp:127 +#: Client/core/CSettings.cpp:4785 Client/core/CVersionUpdater.cpp:1607 +#: Client/core/CVersionUpdater.cpp:1823 Client/core/CVersionUpdater.cpp:1916 +#: Client/core/CVersionUpdater.cpp:1938 Client/core/CVersionUpdater.cpp:1956 +#: Client/core/CVersionUpdater.cpp:1968 Client/core/CVersionUpdater.cpp:2120 +#: Client/core/CVersionUpdater.cpp:2129 Client/core/CVersionUpdater.cpp:2138 +#: Client/core/CVersionUpdater.cpp:2152 Client/loader/Dialogs.cpp:133 +msgid "OK" +msgstr "" + +#. Cancel button +#: Client/gui/CGUIMessageBox_Impl.cpp:68 Client/core/CSettings.cpp:132 +#: Client/core/CSettings.cpp:4784 Client/core/CVersionUpdater.cpp:1790 +#: Client/core/CVersionUpdater.cpp:1806 Client/core/CVersionUpdater.cpp:1841 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:123 +#: Client/loader/Dialogs.cpp:136 +msgid "Cancel" +msgstr "" + +#. ///////////////////////////////////////////////////////////////////////// +#. +#. Dialog strings +#. +#. +#. ///////////////////////////////////////////////////////////////////////// +#: Client/gui/CGUIMessageBox_Impl.cpp:72 Client/core/CSettings.cpp:1389 +#: Client/core/CSettings.cpp:1413 Client/core/CSettings.cpp:4489 +#: Client/core/CSettings.cpp:4563 Client/core/CSettings.cpp:4593 +#: Client/core/CSettings.cpp:4642 Client/core/CQuestionBox.cpp:195 +#: Client/core/CVersionUpdater.cpp:1572 Client/core/CVersionUpdater.cpp:1590 +#: Client/core/CVersionUpdater.cpp:1859 Client/core/CVersionUpdater.cpp:1878 +#: Client/core/CMainMenu.cpp:1200 Client/core/ServerBrowser/CServerInfo.cpp:479 +#: Client/loader/Dialogs.cpp:131 +msgid "Yes" +msgstr "" + #: Client/game_sa/CSettingsSA.cpp:753 msgid "Can't find valid screen resolution." msgstr "" @@ -31,48 +69,29 @@ msgstr "" msgid "MTA: San Andreas" msgstr "" -#: Client/loader/CInstallManager.cpp:361 Client/loader/Utils.cpp:968 -#, c-format -msgid "" -"MTA:SA needs Administrator access for the following task:\n" -"\n" -" '%s'\n" -"\n" -"Please confirm in the next window." -msgstr "" - -#: Client/loader/CInstallManager.cpp:376 -#, c-format -msgid "" -"MTA:SA could not complete the following task:\n" -"\n" -" '%s'\n" -msgstr "" - -#: Client/loader/CInstallManager.cpp:426 -msgid "" -"** The crash was caused by a graphics driver error **\n" -"\n" -"** Please update your graphics drivers **" -msgstr "" - -#: Client/loader/CInstallManager.cpp:532 -msgid "Install updated MTA:SA files" -msgstr "" - -#: Client/loader/CInstallManager.cpp:552 +#. Even the default skin doesn't work, so give up +#: Client/core/CGUI.cpp:86 msgid "" -"Could not update due to file conflicts. Please close other applications and " -"retry" +"The skin you selected could not be loaded, and the default skin also could " +"not be loaded, please reinstall MTA." msgstr "" -#. Show timeout message and disconnect -#. Display an error, reset the error status and exit #. Show a message that the connection timed out and abort #. Show failed message and abort the attempt -#: Client/loader/CInstallManager.cpp:552 Client/loader/CInstallManager.cpp:561 -#: Client/loader/MainFunctions.cpp:252 Client/loader/MainFunctions.cpp:267 -#: Client/loader/MainFunctions.cpp:269 Client/loader/MainFunctions.cpp:846 +#. Show timeout message and disconnect +#. Display an error, reset the error status and exit +#: Client/core/CGUI.cpp:87 Client/core/CSettings.cpp:2941 +#: Client/core/CSettings.cpp:4166 Client/core/CSettings.cpp:4194 +#: Client/core/CSettings.cpp:4764 Client/core/CConnectManager.cpp:80 +#: Client/core/CConnectManager.cpp:111 Client/core/CConnectManager.cpp:127 +#: Client/core/CConnectManager.cpp:263 Client/core/CConnectManager.cpp:321 +#: Client/core/CConnectManager.cpp:404 Client/core/CConnectManager.cpp:411 +#: Client/core/CConnectManager.cpp:421 Client/core/CCore.cpp:1275 +#: Client/core/CCore.cpp:1288 Client/core/ServerBrowser/CServerBrowser.cpp:1278 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1300 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1357 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1406 +#: Client/core/DXHook/CDirect3DHook9.cpp:127 #: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:145 #: Client/mods/deathmatch/logic/CClientGame.cpp:636 #: Client/mods/deathmatch/logic/CClientGame.cpp:710 @@ -85,1404 +104,1358 @@ msgstr "" #: Client/mods/deathmatch/logic/CClientGame.cpp:1368 #: Client/mods/deathmatch/logic/CClientGame.cpp:1417 #: Client/mods/deathmatch/logic/CClientGame.cpp:1429 -#: Client/core/CConnectManager.cpp:80 Client/core/CConnectManager.cpp:111 -#: Client/core/CConnectManager.cpp:127 Client/core/CConnectManager.cpp:263 -#: Client/core/CConnectManager.cpp:321 Client/core/CConnectManager.cpp:404 -#: Client/core/CConnectManager.cpp:411 Client/core/CConnectManager.cpp:421 -#: Client/core/CCore.cpp:1275 Client/core/CCore.cpp:1288 -#: Client/core/CSettings.cpp:2941 Client/core/CSettings.cpp:4166 -#: Client/core/CSettings.cpp:4194 Client/core/CSettings.cpp:4764 -#: Client/core/CGUI.cpp:87 Client/core/DXHook/CDirect3DHook9.cpp:127 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1278 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1300 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1357 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1406 +#: Client/loader/MainFunctions.cpp:252 Client/loader/MainFunctions.cpp:267 +#: Client/loader/MainFunctions.cpp:269 Client/loader/MainFunctions.cpp:846 +#: Client/loader/CInstallManager.cpp:552 Client/loader/CInstallManager.cpp:561 #: Shared/mods/deathmatch/logic/CLatentTransferManager.cpp:378 #: Shared/sdk/SharedUtil.Misc.hpp:137 msgid "Error" msgstr "" -#: Client/loader/CInstallManager.cpp:561 -#, c-format -msgid "Multi Theft Auto has not been installed properly, please reinstall. %s" +#: Client/core/CCredits.cpp:34 +msgid "Programming" msgstr "" -#: Client/loader/CInstallManager.cpp:613 -msgid "Create GTA:SA junctions" +#: Client/core/CCredits.cpp:63 +msgid "Contributors" msgstr "" -#: Client/loader/CInstallManager.cpp:657 -msgid "MTA:SA cannot launch because copying a file failed:" +#: Client/core/CCredits.cpp:84 +msgid "Game Design / Scripting" msgstr "" -#: Client/loader/CInstallManager.cpp:663 Client/loader/CInstallManager.cpp:703 -msgid "MTA:SA cannot launch because an MTA:SA file is incorrect or missing:" +#: Client/core/CCredits.cpp:104 +msgid "Language Localization" msgstr "" -#: Client/loader/CInstallManager.cpp:672 -msgid "Copy MTA:SA files" +#: Client/core/CCredits.cpp:110 +msgid "Patch contributors" msgstr "" -#: Client/loader/CInstallManager.cpp:695 Client/loader/CInstallManager.cpp:773 -msgid "MTA:SA cannot launch because a GTA:SA file is incorrect or missing:" +#: Client/core/CCredits.cpp:234 +msgid "Special Thanks" msgstr "" -#: Client/loader/CInstallManager.cpp:780 -msgid "Patch GTA:SA dependency" +#: Client/core/CCredits.cpp:265 +msgid "" +"This software and project makes use of the following libraries and software:" msgstr "" -#: Client/loader/CInstallManager.cpp:828 -msgid "" -"MTA:SA cannot launch because the GTA:SA executable is incorrect or missing:" +#: Client/core/CScreenShot.cpp:104 +#, c-format +msgid "Screenshot got %d bytes, but expected %d" msgstr "" -#: Client/loader/CInstallManager.cpp:832 -msgid "" -"Please check your anti-virus for a false-positive detection, try to add an " -"exception for the GTA:SA executable and restart MTA:SA." +#: Client/core/CScreenShot.cpp:110 +msgid "Screenshot failed" msgstr "" -#: Client/loader/CInstallManager.cpp:838 -msgid "Generate GTA:SA" +#: Client/core/CScreenShot.cpp:160 +#, c-format +msgid "Screenshot taken: '%s'" msgstr "" -#: Client/loader/CInstallManager.cpp:853 -msgid "MTA:SA cannot launch because the GTA:SA executable is not loadable:" +#. Create the window +#: Client/core/CNewsBrowser.cpp:153 +msgid "NEWS" msgstr "" -#: Client/loader/CInstallManager.cpp:860 Client/loader/CInstallManager.cpp:883 -msgid "Patch GTA:SA" +#. News link +#: Client/core/CNewsBrowser.cpp:171 Client/core/CNewsBrowser.cpp:172 +msgid "Visit latest news article" msgstr "" -#: Client/loader/CInstallManager.cpp:876 -msgid "MTA:SA cannot launch because patching GTA:SA has failed:" +#: Client/core/CKeyBinds.cpp:186 +msgid "Fire" msgstr "" -#: Client/loader/CInstallManager.cpp:1057 Client/core/CCore.cpp:811 -#, c-format -msgid "MTA:SA cannot continue because drive %s does not have enough space." +#: Client/core/CKeyBinds.cpp:187 +msgid "Next weapon" msgstr "" -#: Client/loader/CInstallManager.cpp:1113 -msgid "Missing file:" +#: Client/core/CKeyBinds.cpp:188 +msgid "Previous weapon" msgstr "" -#: Client/loader/CInstallManager.cpp:1117 -msgid "If MTA fails to load, please re-install GTA:SA" +#: Client/core/CKeyBinds.cpp:189 +msgid "Forwards" msgstr "" -#: Client/loader/CInstallManager.cpp:1152 -msgid "Update install settings" +#: Client/core/CKeyBinds.cpp:190 +msgid "Backwards" msgstr "" -#: Client/loader/CInstallManager.cpp:1291 -msgid "Update compatibility settings" +#: Client/core/CKeyBinds.cpp:191 Client/core/CSettings.cpp:2240 +#: Client/core/CSettings.cpp:2268 +msgid "Left" msgstr "" -#: Client/loader/Utils.cpp:534 Client/loader/Dialogs.cpp:890 -msgid "Searching for Grand Theft Auto San Andreas" +#: Client/core/CKeyBinds.cpp:192 Client/core/CSettings.cpp:2242 +#: Client/core/CSettings.cpp:2269 +msgid "Right" msgstr "" -#: Client/loader/Utils.cpp:536 Client/loader/Dialogs.cpp:893 -msgid "Please start Grand Theft Auto San Andreas" +#: Client/core/CKeyBinds.cpp:193 +msgid "Zoom in" msgstr "" -#: Client/loader/Utils.cpp:600 -msgid "Select your Grand Theft Auto: San Andreas Installation Directory" +#: Client/core/CKeyBinds.cpp:194 +msgid "Zoom out" msgstr "" -#: Client/loader/Utils.cpp:1069 -#, c-format -msgid "Error loading %s module! (%s)" +#: Client/core/CKeyBinds.cpp:195 +msgid "Enter/Exit" msgstr "" -#: Client/loader/Utils.cpp:1394 Client/loader/Dialogs.cpp:914 -msgid "Copying files..." +#: Client/core/CKeyBinds.cpp:196 +msgid "Change camera" msgstr "" -#: Client/loader/Utils.cpp:1454 Client/loader/Dialogs.cpp:919 -msgid "Copy finished early. Everything OK." +#. 10 +#: Client/core/CKeyBinds.cpp:197 +msgid "Jump" msgstr "" -#: Client/loader/Utils.cpp:1460 Client/loader/Dialogs.cpp:924 -msgid "Finishing..." +#: Client/core/CKeyBinds.cpp:198 +msgid "Sprint" msgstr "" -#: Client/loader/Utils.cpp:1462 Client/loader/Dialogs.cpp:928 -msgid "Done!" +#: Client/core/CKeyBinds.cpp:199 +msgid "Look behind" msgstr "" -#: Client/loader/Utils.cpp:1502 -#, c-format -msgid "" -"New installation of %s detected.\n" -"\n" -"Do you want to copy your settings from %s ?" +#: Client/core/CKeyBinds.cpp:200 +msgid "Crouch" msgstr "" -#: Client/loader/Utils.cpp:1541 -#, c-format -msgid "GTA:SA had trouble opening the file '%s'" +#: Client/core/CKeyBinds.cpp:201 +msgid "Action" msgstr "" -#: Client/loader/Utils.cpp:1563 -#, c-format -msgid "GTA:SA is missing the file '%s'." +#: Client/core/CKeyBinds.cpp:202 +msgid "Walk" msgstr "" -#: Client/loader/Utils.cpp:1588 -msgid "GTA:SA had trouble loading a model." +#: Client/core/CKeyBinds.cpp:203 +msgid "Vehicle fire" msgstr "" -#: Client/loader/Utils.cpp:1590 -msgid "If you recently modified gta3.img, then try reinstalling GTA:SA." +#: Client/core/CKeyBinds.cpp:204 +msgid "Vehicle secondary fire" msgstr "" -#: Client/loader/Utils.cpp:1615 -msgid "GTA:SA had trouble adding an upgrade to a vehicle." +#: Client/core/CKeyBinds.cpp:205 +msgid "Vehicle left" msgstr "" -#: Client/loader/Utils.cpp:1634 -#, c-format -msgid "GTA:SA found errors in the file '%s'" +#: Client/core/CKeyBinds.cpp:206 +msgid "Vehicle right" msgstr "" -#: Client/loader/Utils.cpp:1716 -msgid "Did your computer restart when playing MTA:SA?" +#. 20 +#: Client/core/CKeyBinds.cpp:207 +msgid "Steer forwards/down" msgstr "" -#: Client/loader/Utils.cpp:1781 -msgid "Please terminate the following programs before continuing:" +#: Client/core/CKeyBinds.cpp:208 +msgid "Steer backwards/up" msgstr "" -#. ///////////////////////////////////////////////////////////////////////// -#. -#. Dialog strings -#. -#. -#. ///////////////////////////////////////////////////////////////////////// -#: Client/loader/Dialogs.cpp:131 Client/gui/CGUIMessageBox_Impl.cpp:72 -#: Client/core/CQuestionBox.cpp:195 Client/core/CSettings.cpp:1389 -#: Client/core/CSettings.cpp:1413 Client/core/CSettings.cpp:4489 -#: Client/core/CSettings.cpp:4563 Client/core/CSettings.cpp:4593 -#: Client/core/CSettings.cpp:4642 Client/core/CVersionUpdater.cpp:1572 -#: Client/core/CVersionUpdater.cpp:1590 Client/core/CVersionUpdater.cpp:1859 -#: Client/core/CVersionUpdater.cpp:1878 Client/core/CMainMenu.cpp:1200 -#: Client/core/ServerBrowser/CServerInfo.cpp:479 -msgid "Yes" +#: Client/core/CKeyBinds.cpp:209 +msgid "Accelerate" msgstr "" -#: Client/loader/Dialogs.cpp:132 Client/core/CQuestionBox.cpp:194 -#: Client/core/CSettings.cpp:1388 Client/core/CSettings.cpp:1412 -#: Client/core/CSettings.cpp:4488 Client/core/CSettings.cpp:4562 -#: Client/core/CSettings.cpp:4592 Client/core/CSettings.cpp:4641 -#: Client/core/CVersionUpdater.cpp:1571 Client/core/CVersionUpdater.cpp:1589 -#: Client/core/CVersionUpdater.cpp:1858 Client/core/CVersionUpdater.cpp:1877 -#: Client/core/CMainMenu.cpp:1199 Client/core/ServerBrowser/CServerInfo.cpp:479 -msgid "No" +#: Client/core/CKeyBinds.cpp:210 +msgid "Brake/Reverse" msgstr "" -#. Create buttons -#. OK button -#: Client/loader/Dialogs.cpp:133 Client/gui/CGUIMessageBox_Impl.cpp:64 -#: Client/core/CSettings.cpp:127 Client/core/CSettings.cpp:4785 -#: Client/core/CVersionUpdater.cpp:1607 Client/core/CVersionUpdater.cpp:1823 -#: Client/core/CVersionUpdater.cpp:1916 Client/core/CVersionUpdater.cpp:1938 -#: Client/core/CVersionUpdater.cpp:1956 Client/core/CVersionUpdater.cpp:1968 -#: Client/core/CVersionUpdater.cpp:2120 Client/core/CVersionUpdater.cpp:2129 -#: Client/core/CVersionUpdater.cpp:2138 Client/core/CVersionUpdater.cpp:2152 -msgid "OK" +#: Client/core/CKeyBinds.cpp:211 +msgid "Radio next" msgstr "" -#: Client/loader/Dialogs.cpp:134 -msgid "Quit" +#: Client/core/CKeyBinds.cpp:212 +msgid "Radio previous" msgstr "" -#: Client/loader/Dialogs.cpp:135 -#: Client/core/ServerBrowser/CServerBrowser.cpp:556 -msgid "Help" -msgstr "" - -#. Cancel button -#: Client/loader/Dialogs.cpp:136 -#: Client/mods/deathmatch/logic/CLocalServer.cpp:123 -#: Client/gui/CGUIMessageBox_Impl.cpp:68 Client/core/CSettings.cpp:132 -#: Client/core/CSettings.cpp:4784 Client/core/CVersionUpdater.cpp:1790 -#: Client/core/CVersionUpdater.cpp:1806 Client/core/CVersionUpdater.cpp:1841 -msgid "Cancel" +#: Client/core/CKeyBinds.cpp:213 +msgid "Radio user track skip" msgstr "" -#: Client/loader/Dialogs.cpp:151 -msgid "MTA: San Andreas has encountered a problem" +#: Client/core/CKeyBinds.cpp:214 +msgid "Horn" msgstr "" -#: Client/loader/Dialogs.cpp:152 -msgid "Crash information" +#: Client/core/CKeyBinds.cpp:215 +msgid "Sub-mission" msgstr "" -#: Client/loader/Dialogs.cpp:153 -msgid "" -"Tick the check box to send this crash info to MTA devs using the 'internet'" +#: Client/core/CKeyBinds.cpp:216 +msgid "Handbrake" msgstr "" -#: Client/loader/Dialogs.cpp:154 -msgid "Doing so will increase the chance of this crash being fixed." +#. 30 +#: Client/core/CKeyBinds.cpp:217 +msgid "Vehicle look left" msgstr "" -#: Client/loader/Dialogs.cpp:155 -msgid "Do you want to restart MTA: San Andreas ?" +#: Client/core/CKeyBinds.cpp:218 +msgid "Vehicle look right" msgstr "" -#: Client/loader/Dialogs.cpp:162 -msgid "MTA: San Andreas - Warning" +#: Client/core/CKeyBinds.cpp:219 +msgid "Vehicle look behind" msgstr "" -#: Client/loader/Dialogs.cpp:163 -msgid "" -"Your Grand Theft Auto: San Andreas install directory contains these files:" +#: Client/core/CKeyBinds.cpp:220 +msgid "Vehicle mouse look" msgstr "" -#: Client/loader/Dialogs.cpp:165 -msgid "" -"These files are not required and may interfere with the graphical features " -"in this version of MTA:SA.\n" -"\n" -"It is recommended that you remove or rename these files." +#: Client/core/CKeyBinds.cpp:221 +msgid "Special control left" msgstr "" -#: Client/loader/Dialogs.cpp:167 -msgid "Keep these files, but also show this warning on next start" +#: Client/core/CKeyBinds.cpp:222 +msgid "Special control right" msgstr "" -#: Client/loader/Dialogs.cpp:168 -msgid "Do not remind me about these files again" +#: Client/core/CKeyBinds.cpp:223 +msgid "Special control down" msgstr "" -#: Client/loader/Dialogs.cpp:169 -msgid "Rename these files from *.dll to *.dll.bak" +#: Client/core/CKeyBinds.cpp:224 +msgid "Special control up" msgstr "" -#: Client/loader/Dialogs.cpp:170 -msgid "Show me these files" +#: Client/core/CKeyBinds.cpp:225 +msgid "Aim weapon" msgstr "" -#: Client/loader/Dialogs.cpp:171 -msgid "Play MTA:SA" +#: Client/core/CKeyBinds.cpp:226 +msgid "Conversation yes" msgstr "" -#: Client/loader/Dialogs.cpp:177 -msgid "MTA: San Andreas - Confusing options" +#. 40 +#: Client/core/CKeyBinds.cpp:227 +msgid "Conversation no" msgstr "" -#: Client/loader/Dialogs.cpp:178 -msgid "NVidia Optimus detected!" +#: Client/core/CKeyBinds.cpp:228 +msgid "Group control forwards" msgstr "" -#: Client/loader/Dialogs.cpp:179 -msgid "Try each option and see what works:" +#: Client/core/CKeyBinds.cpp:229 +msgid "Group control backwards" msgstr "" -#: Client/loader/Dialogs.cpp:180 -msgid "A - Standard NVidia" +#: Client/core/CJoystickManager.cpp:1578 +msgid "Accelerate Axis" msgstr "" -#: Client/loader/Dialogs.cpp:181 -msgid "B - Alternate NVidia" +#: Client/core/CJoystickManager.cpp:1580 +msgid "Brake Axis" msgstr "" -#: Client/loader/Dialogs.cpp:182 -msgid "C - Standard Intel" +#. Create window (with frame) if it will fit inside the screen resolution +#: Client/core/CSettings.cpp:84 +msgid "SETTINGS" msgstr "" -#: Client/loader/Dialogs.cpp:183 -msgid "D - Alternate Intel" +#: Client/core/CSettings.cpp:116 +msgid "Multiplayer" msgstr "" -#: Client/loader/Dialogs.cpp:184 -msgid "If you get desperate, this might help:" +#: Client/core/CSettings.cpp:117 +msgid "Video" msgstr "" -#: Client/loader/Dialogs.cpp:185 -msgid "If you have already selected an option that works, this might help:" +#: Client/core/CSettings.cpp:118 +msgid "Audio" msgstr "" -#: Client/loader/Dialogs.cpp:186 -msgid "Force windowed mode" +#: Client/core/CSettings.cpp:119 +msgid "Binds" msgstr "" -#: Client/loader/Dialogs.cpp:187 -msgid "Don't show again" +#: Client/core/CSettings.cpp:120 +msgid "Controls" msgstr "" -#: Client/loader/Dialogs.cpp:195 -msgid "Warning: Could not detect anti-virus product" +#: Client/core/CSettings.cpp:121 +msgid "Interface" msgstr "" -#: Client/loader/Dialogs.cpp:197 -msgid "" -"MTA could not detect an anti-virus on your PC.\n" -"\n" -"Viruses interfere with MTA and degrade your gameplay experience.\n" -"\n" -"Press 'Help' for more information." +#: Client/core/CSettings.cpp:122 +msgid "Web Browser" msgstr "" -#: Client/loader/Dialogs.cpp:200 -msgid "I have already installed an anti-virus" +#: Client/core/CSettings.cpp:123 +msgid "Advanced" msgstr "" -#: Client/loader/Dialogs.cpp:202 -msgid "" -"I will not install an anti-virus.\n" -"I want my PC to lag and be part of a botnet." +#: Client/core/CSettings.cpp:147 Client/core/CSettings.cpp:338 +#: Client/core/CSettings.cpp:617 Client/core/CSettings.cpp:889 +msgid "Load defaults" msgstr "" -#: Client/loader/Dialogs.cpp:901 Client/loader/Install.cpp:852 -msgid "Installing update..." +#. * +#. * Controls tab +#. * +#: Client/core/CSettings.cpp:157 Client/core/CSettings.cpp:181 +msgid "Mouse sensitivity:" msgstr "" -#: Client/loader/Dialogs.cpp:909 Client/loader/Install.cpp:934 -msgid "Extracting files..." +#. VerticalAimSensitivity +#: Client/core/CSettings.cpp:157 Client/core/CSettings.cpp:199 +msgid "Vertical aim sensitivity:" msgstr "" -#: Client/loader/MainFunctions.cpp:248 -msgid "" -"Trouble restarting MTA:SA\n" -"\n" -"If the problem persists, open Task Manager and\n" -"stop the 'gta_sa.exe' and 'Multi Theft Auto.exe' processes\n" -"\n" -"\n" -"Try to launch MTA:SA again?" +#. Mouse Options +#: Client/core/CSettings.cpp:160 +msgid "Mouse options" msgstr "" -#: Client/loader/MainFunctions.cpp:266 -msgid "" -"Another instance of MTA is already running.\n" -"\n" -"If this problem persists, please restart your computer" +#: Client/core/CSettings.cpp:167 +msgid "Invert mouse vertically" msgstr "" -#: Client/loader/MainFunctions.cpp:269 -msgid "" -"Another instance of MTA is already running.\n" -"\n" -"Do you want to terminate it?" +#: Client/core/CSettings.cpp:171 +msgid "Steer with mouse" msgstr "" -#: Client/loader/MainFunctions.cpp:294 -msgid "" -"Are you having problems running MTA:SA?.\n" -"\n" -"Do you want to revert to an earlier version?" +#: Client/core/CSettings.cpp:175 +msgid "Fly with mouse" msgstr "" -#: Client/loader/MainFunctions.cpp:324 -msgid "" -"There seems to be a problem launching MTA:SA.\n" -"Resetting GTA settings can sometimes fix this problem.\n" -"\n" -"Do you want to reset GTA settings now?" +#. Joypad options +#: Client/core/CSettings.cpp:217 +msgid "Joypad options" msgstr "" -#: Client/loader/MainFunctions.cpp:339 -msgid "" -"GTA settings have been reset.\n" -"\n" -"Press OK to continue." +#: Client/core/CSettings.cpp:230 +msgid "Standard controls (Mouse + Keyboard)" msgstr "" -#: Client/loader/MainFunctions.cpp:344 -#, c-format -msgid "File could not be deleted: '%s'" +#: Client/core/CSettings.cpp:237 +msgid "Classic controls (Joypad)" msgstr "" -#. No settings to delete, or can't find them -#: Client/loader/MainFunctions.cpp:352 -msgid "" -"Are you having problems running MTA:SA?.\n" -"\n" -"Do you want to see some online help?" +#: Client/core/CSettings.cpp:274 +msgid "Dead Zone" msgstr "" -#. Inform user -#: Client/loader/MainFunctions.cpp:388 -msgid "" -"Are you having problems running MTA:SA?.\n" -"\n" -"Do you want to change the following setting?" +#: Client/core/CSettings.cpp:279 +msgid "Saturation" msgstr "" -#: Client/loader/MainFunctions.cpp:389 Client/core/CSettings.cpp:662 -#: Client/core/CSettings.cpp:1004 -msgid "Fullscreen mode:" +#: Client/core/CSettings.cpp:285 +msgid "Use the 'Binds' tab for joypad buttons." msgstr "" -#: Client/loader/MainFunctions.cpp:389 Client/core/CSettings.cpp:670 -#: Client/core/CSettings.cpp:1615 -msgid "Borderless window" +#: Client/core/CSettings.cpp:324 +msgid "Left Stick" msgstr "" -#: Client/loader/MainFunctions.cpp:431 -msgid "" -"Are you having problems running MTA:SA?.\n" -"\n" -"Try disabling the following products for GTA and MTA:" +#: Client/core/CSettings.cpp:330 +msgid "Right Stick" msgstr "" -#: Client/loader/MainFunctions.cpp:465 -msgid "" -"WARNING\n" -"\n" -"MTA:SA has detected unusual activity.\n" -"Please run a virus scan to ensure your system is secure.\n" -"\n" +#: Client/core/CSettings.cpp:345 +msgid "DESCRIPTION" msgstr "" -#: Client/loader/MainFunctions.cpp:468 -#, c-format -msgid "The detected file was: %s\n" +#: Client/core/CSettings.cpp:346 +msgid "KEY" msgstr "" -#: Client/loader/MainFunctions.cpp:602 -msgid "" -"An instance of GTA: San Andreas is already running. It needs to be " -"terminated before MTA:SA can be started. Do you want to do that now?" +#: Client/core/CSettings.cpp:348 +msgid "ALT. KEY" msgstr "" -#: Client/loader/MainFunctions.cpp:603 Client/loader/MainFunctions.cpp:610 -#: Client/loader/MainFunctions.cpp:1219 -#: Client/core/ServerBrowser/CServerInfo.cpp:319 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1380 -msgid "Information" +#. * +#. * Multiplayer tab +#. * +#: Client/core/CSettings.cpp:353 Client/core/CSettings.cpp:356 +msgid "Nick:" msgstr "" -#: Client/loader/MainFunctions.cpp:609 -msgid "" -"Unable to terminate GTA: San Andreas. If the problem persists, please " -"restart your computer." +#: Client/core/CSettings.cpp:378 +msgid "Save server passwords" msgstr "" -#: Client/loader/MainFunctions.cpp:632 -msgid "" -"Registry entries are missing. Please reinstall Multi Theft Auto: San Andreas." +#: Client/core/CSettings.cpp:383 +msgid "Auto-refresh server browser" msgstr "" -#: Client/loader/MainFunctions.cpp:638 -msgid "" -"The path to your installation of GTA: San Andreas contains unsupported " -"(unicode) characters. Please move your Grand Theft Auto: San Andreas " -"installation to a compatible path that contains only standard ASCII " -"characters and reinstall Multi Theft Auto: San Andreas." +#: Client/core/CSettings.cpp:388 +msgid "Allow screen upload" msgstr "" -#: Client/loader/MainFunctions.cpp:648 -msgid "" -"The path to your installation of 'MTA:SA' or 'GTA: San Andreas'\n" -"contains a ';' (semicolon).\n" -"\n" -" If you experience problems when running MTA:SA,\n" -" move your installation(s) to a path that does not contain a semicolon." +#: Client/core/CSettings.cpp:393 +msgid "Allow external sounds" msgstr "" -#: Client/loader/MainFunctions.cpp:810 -msgid "" -"Load failed. Please ensure that the latest data files have been installed " -"correctly." +#: Client/core/CSettings.cpp:398 +msgid "Always show download window" msgstr "" -#: Client/loader/MainFunctions.cpp:819 -#, c-format -msgid "Load failed. Please ensure that %s is installed correctly." +#: Client/core/CSettings.cpp:403 +msgid "Allow connecting with Discord Rich Presence" msgstr "" -#: Client/loader/MainFunctions.cpp:826 -#, c-format -msgid "Load failed. Could not find gta_sa.exe in %s." +#: Client/core/CSettings.cpp:408 +msgid "Use customized GTA:SA files" msgstr "" -#: Client/loader/MainFunctions.cpp:836 -#, c-format -msgid "" -"Load failed. %s exists in the GTA directory. Please delete before continuing." +#: Client/core/CSettings.cpp:413 +msgid "Map rendering options" msgstr "" -#: Client/loader/MainFunctions.cpp:845 -#, c-format -msgid "Main file has an incorrect name (%s)" +#: Client/core/CSettings.cpp:419 Client/core/CSettings.cpp:628 +msgid "Opacity:" msgstr "" -#: Client/loader/MainFunctions.cpp:856 -msgid "" -"Main file is unsigned. Possible virus activity.\n" -"\n" -"See online help if MTA does not work correctly." +#. * +#. * Audio tab +#. * +#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:448 +msgid "Master volume:" msgstr "" -#: Client/loader/MainFunctions.cpp:882 -#, c-format -msgid "" -"Data file %s is missing. Possible virus activity.\n" -"\n" -"Consider reinstalling Multi Theft Auto for your security.\n" -"See online help if MTA does not work correctly." +#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:467 +msgid "Radio volume:" msgstr "" -#: Client/loader/MainFunctions.cpp:893 -#, c-format -msgid "" -"Data file %s is modified. Possible virus activity.\n" -"\n" -"Consider reinstalling Multi Theft Auto for your security.\n" -"See online help if MTA does not work correctly." +#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:486 +msgid "SFX volume:" msgstr "" -#: Client/loader/MainFunctions.cpp:907 -msgid "" -".asi files are in the 'MTA:SA' or 'GTA: San Andreas' installation " -"directory.\n" -"\n" -"Remove these .asi files if you experience problems with MTA:SA." +#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:505 +msgid "MTA volume:" msgstr "" -#: Client/loader/MainFunctions.cpp:1009 -msgid "" -"File version mismatch error. Reinstall MTA:SA if you experience problems.\n" +#: Client/core/CSettings.cpp:440 Client/core/CSettings.cpp:524 +msgid "Voice volume:" msgstr "" -#: Client/loader/MainFunctions.cpp:1018 -msgid "Some files are missing. Reinstall MTA:SA if you experience problems.\n" +#: Client/core/CSettings.cpp:440 Client/core/CSettings.cpp:565 +msgid "Play mode:" msgstr "" -#: Client/loader/MainFunctions.cpp:1030 -msgid "" -"MTA:SA is not compatible with Windows 'Safe Mode'.\n" -"\n" -"Please restart your PC.\n" +#. * +#. * Webbrowser tab +#. * +#: Client/core/CSettings.cpp:442 Client/core/CSettings.cpp:630 +#: Client/core/CSettings.cpp:904 Client/core/CSettings.cpp:2018 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:51 +msgid "General" msgstr "" -#: Client/loader/MainFunctions.cpp:1123 -msgid "Fix configuration issue" +#: Client/core/CSettings.cpp:543 +msgid "Radio options" msgstr "" -#. Try to relaunch as admin if not done so already -#: Client/loader/MainFunctions.cpp:1157 -msgid "Fix elevation required error" +#: Client/core/CSettings.cpp:549 +msgid "Radio Equalizer" msgstr "" -#: Client/loader/MainFunctions.cpp:1164 -#, c-format -msgid "" -"Could not start Grand Theft Auto: San Andreas. Please try restarting, or if " -"the problem persists,contact MTA at www.multitheftauto.com. \n" -"\n" -"[%s]" +#: Client/core/CSettings.cpp:554 +msgid "Radio Auto-tune" msgstr "" -#: Client/loader/MainFunctions.cpp:1219 -msgid "" -"GTA: San Andreas may not have launched correctly. Do you want to terminate " -"it?" +#: Client/core/CSettings.cpp:559 +msgid "Usertrack options" msgstr "" -#: Client/loader/Install.cpp:265 -msgid "Unknown" +#: Client/core/CSettings.cpp:573 Client/core/CSettings.cpp:3087 +msgid "Radio" msgstr "" -#: Client/loader/Install.cpp:272 -#, c-format -msgid "" -"The file '%s' is currently locked by %zu processes.\n" -"\n" -"Do you want to terminate the following processes and continue updating?\n" -"\n" -"%s" +#: Client/core/CSettings.cpp:574 Client/core/CSettings.cpp:3089 +msgid "Random" msgstr "" -#: Client/loader/Install.cpp:479 -#, c-format -msgid "" -"Your installation may be corrupt now.\n" -"\n" -"%zu out of %zu files could not be restored from the backup.\n" -"\n" -"You should reinstall Multi Theft Auto from www.multitheftauto.com\n" -"or try running the update with administrator rights." +#: Client/core/CSettings.cpp:575 Client/core/CSettings.cpp:3091 +msgid "Sequential" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:36 -msgid "This version has expired." +#: Client/core/CSettings.cpp:578 +msgid "Automatic Media Scan" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:56 -msgid "disconnect from the game" +#: Client/core/CSettings.cpp:585 +msgid "Mute options" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:57 -msgid "shows the nametags" +#: Client/core/CSettings.cpp:591 +msgid "Mute All sounds when minimized" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:58 -msgid "shows the chatbox" +#: Client/core/CSettings.cpp:596 +msgid "Mute Radio sounds when minimized" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:59 -msgid "shows the network statistics" +#: Client/core/CSettings.cpp:601 +msgid "Mute SFX sounds when minimized" msgstr "" -#. Key commands (registered as 'mod commands', can be disabled) -#: Client/mods/deathmatch/CClient.cpp:63 -msgid "open the chat input" +#: Client/core/CSettings.cpp:606 +msgid "Mute MTA sounds when minimized" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:64 -msgid "transmits voice to other players" +#: Client/core/CSettings.cpp:611 +msgid "Mute Voice sounds when minimized" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:65 -msgid "enters a car as passenger" +#. * +#. * Video tab +#. * +#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:636 +msgid "Resolution:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:66 -msgid "next radio channel" +#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:683 +msgid "FOV:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:67 -msgid "previous radio channel" +#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:699 +msgid "Draw Distance:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:68 -msgid "enables the radar view" +#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:717 +msgid "Brightness:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:69 -msgid "zooms the radar in" +#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:735 +msgid "FX Quality:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:70 -msgid "zooms the radar out" +#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:749 +msgid "Anisotropic filtering:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:71 -msgid "moves the radar north" +#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:776 +msgid "Anti-aliasing:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:72 -msgid "moves the radar south" +#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:790 +msgid "Aspect Ratio:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:73 -msgid "moves the radar east" +#: Client/core/CSettings.cpp:648 +msgid "Windowed" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:74 -msgid "moves the radar west" +#: Client/core/CSettings.cpp:654 +msgid "DPI aware" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:75 -msgid "attaches the radar" +#: Client/core/CSettings.cpp:662 Client/core/CSettings.cpp:1004 +#: Client/loader/MainFunctions.cpp:389 +msgid "Fullscreen mode:" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:76 -msgid "reduces radar opacity" +#: Client/core/CSettings.cpp:669 Client/core/CSettings.cpp:1613 +msgid "Standard" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:77 -msgid "increases radar opacity" +#: Client/core/CSettings.cpp:670 Client/core/CSettings.cpp:1615 +#: Client/loader/MainFunctions.cpp:389 +msgid "Borderless window" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:78 -msgid "toggles radar help text" -msgstr "" +#: Client/core/CSettings.cpp:671 Client/core/CSettings.cpp:1617 +msgid "Borderless keep res" +msgstr "" -#: Client/mods/deathmatch/CClient.cpp:79 -msgid "sends a message to the targetted player" +#: Client/core/CSettings.cpp:675 +msgid "Mip Mapping" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:80 -msgid "changes to the next weapon whilst in a vehicle" +#: Client/core/CSettings.cpp:743 Client/core/CSettings.cpp:1517 +msgid "Low" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:81 -msgid "changes to the previous weapon whilst in a vehicle" +#: Client/core/CSettings.cpp:744 Client/core/CSettings.cpp:1519 +msgid "Medium" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:82 -msgid "outputs info about the current server" +#: Client/core/CSettings.cpp:745 Client/core/CSettings.cpp:1086 +#: Client/core/CSettings.cpp:1521 Client/core/CSettings.cpp:3145 +msgid "High" msgstr "" -#. ACHTUNG" Should this be handled by the atomic cvar setter? -#: Client/mods/deathmatch/CClient.cpp:85 -msgid "defines the scale multiplier of all text-displays" +#: Client/core/CSettings.cpp:746 Client/core/CSettings.cpp:1523 +msgid "Very high" msgstr "" -#. Development mode -#: Client/mods/deathmatch/CClient.cpp:92 -msgid "(Development mode) shows the colshapes" +#: Client/core/CSettings.cpp:761 Client/core/CSettings.cpp:784 +#: Client/core/CSettings.cpp:1017 Client/core/CSettings.cpp:1071 +#: Client/core/CSettings.cpp:1201 Client/core/CSettings.cpp:1527 +#: Client/core/CSettings.cpp:3152 Client/core/CSettings.cpp:3184 +#: Client/core/CSettings.cpp:3206 Client/core/CSettings.cpp:4234 +msgid "Off" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:93 -msgid "(Development mode) prints world sound ids into the debug window" +#: Client/core/CSettings.cpp:785 Client/core/CSettings.cpp:1529 +msgid "1x" msgstr "" -#. Throw the error and disconnect -#: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:141 -#, c-format -msgid "Download error: %s" +#: Client/core/CSettings.cpp:786 Client/core/CSettings.cpp:1531 +msgid "2x" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:506 -msgid "Disconnected: Invalid nickname" +#: Client/core/CSettings.cpp:787 Client/core/CSettings.cpp:1533 +msgid "3x" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:510 -msgid "Disconnect from server" +#: Client/core/CSettings.cpp:800 Client/core/CSettings.cpp:1019 +#: Client/core/CSettings.cpp:1539 Client/core/CSettings.cpp:3154 +msgid "Auto" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:514 -#, c-format -msgid "" -"Disconnected: Serial is banned.\n" -"Reason: %s" +#: Client/core/CSettings.cpp:801 Client/core/CSettings.cpp:1541 +msgid "4:3" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:520 -#, c-format -msgid "" -"Disconnected: You are banned.\n" -"Reason: %s" +#: Client/core/CSettings.cpp:802 Client/core/CSettings.cpp:1543 +msgid "16:10" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:526 -#, c-format -msgid "" -"Disconnected: Account is banned.\n" -"Reason: %s" +#: Client/core/CSettings.cpp:803 Client/core/CSettings.cpp:1545 +msgid "16:9" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:531 -msgid "Disconnected: Version mismatch" +#: Client/core/CSettings.cpp:806 +msgid "HUD Match Aspect Ratio" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:535 -msgid "Disconnected: Join flood. Please wait a minute, then reconnect." +#: Client/core/CSettings.cpp:812 +msgid "Volumetric Shadows" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:539 -#, c-format -msgid "" -"Disconnected: Server from different branch.\n" -"Information: %s" +#: Client/core/CSettings.cpp:816 +msgid "Grass effect" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:544 -#, c-format -msgid "" -"Disconnected: Bad version.\n" -"Information: %s" +#: Client/core/CSettings.cpp:820 +msgid "Heat haze" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:549 -#, c-format -msgid "" -"Disconnected: Server is running a newer build.\n" -"Information: %s" +#: Client/core/CSettings.cpp:824 +msgid "Tyre Smoke etc" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:554 -#, c-format -msgid "" -"Disconnected: Server is running an older build.\n" -"Information: %s" +#: Client/core/CSettings.cpp:828 +msgid "Dynamic ped shadows" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:559 -msgid "Disconnected: Nick already in use" +#: Client/core/CSettings.cpp:832 +msgid "Motion blur" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:563 -msgid "Disconnected: Player element could not be created." +#: Client/core/CSettings.cpp:837 +msgid "Full Screen Minimize" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:567 -#, c-format -msgid "Disconnected: Server refused the connection: %s" +#: Client/core/CSettings.cpp:849 +msgid "Enable Device Selection Dialog" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:572 -msgid "Disconnected: Serial verification failed" +#: Client/core/CSettings.cpp:861 +msgid "Show unsafe resolutions" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:576 -#, c-format -msgid "Disconnected: Connection desync %s" +#: Client/core/CSettings.cpp:873 +msgid "Render vehicles always in high detail" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:585 -#, c-format -msgid "Disconnected: You were kicked by %s" +#: Client/core/CSettings.cpp:877 +msgid "Render peds always in high detail" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:590 -#, c-format -msgid "Disconnected: You were banned by %s" +#: Client/core/CSettings.cpp:881 +msgid "Corona rain reflections" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:601 -msgid "Disconnected: Server shutdown or restarting" +#: Client/core/CSettings.cpp:910 +msgid "Enable remote websites" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:621 -msgid "You were kicked from the game" +#: Client/core/CSettings.cpp:915 +msgid "Enable Javascript on remote websites" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:622 -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:633 -msgid "This server requires a non-modifed gta_sa.exe" +#: Client/core/CSettings.cpp:920 +msgid "Custom blacklist" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:623 -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:634 -msgid "Please replace gta_sa.exe" +#: Client/core/CSettings.cpp:931 Client/core/CSettings.cpp:966 +msgid "Enter a domain e.g. google.com" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:624 -msgid "This server does not allow custom D3D9.DLLs" +#: Client/core/CSettings.cpp:939 +msgid "Block" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:625 -msgid "Remove D3D9.DLL from your GTA install directory and restart MTA" +#: Client/core/CSettings.cpp:947 Client/core/CSettings.cpp:982 +msgid "Domain" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:626 -msgid "This server does not allow virtual machines" +#: Client/core/CSettings.cpp:949 Client/core/CSettings.cpp:984 +msgid "Remove domain" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:627 -msgid "This server requires driver signing to be enabled" +#. Reset vecTemp +#: Client/core/CSettings.cpp:955 +msgid "Custom whitelist" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:628 -msgid "Please restart your PC" +#: Client/core/CSettings.cpp:974 Client/cefweb/CWebsiteRequests.cpp:51 +msgid "Allow" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:629 -msgid "This server has detected missing anti-cheat components" +#. Misc section label +#: Client/core/CSettings.cpp:997 +msgid "Misc" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:630 -msgid "Try restarting MTA" +#. Fast clothes loading +#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1010 +#: Client/core/CSettings.cpp:4803 +msgid "Fast CJ clothes loading:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:631 -msgid "This server requires a non-modifed gta3.img and gta_int.img" +#. Browser scan speed +#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1024 +#: Client/core/CSettings.cpp:4805 +msgid "Browser speed:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:632 -msgid "Please replace gta3.img or gta_int.img" +#. Single download +#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1038 +#: Client/core/CSettings.cpp:4807 +msgid "Single connection:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:635 -msgid "This server does not allow Wine" +#. Packet tag +#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1051 +#: Client/core/CSettings.cpp:4809 +msgid "Packet tag:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:636 -msgid "Ensure no other program is modifying MTA:SA" +#. Progress animation +#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1064 +#: Client/core/CSettings.cpp:4811 +msgid "Progress animation:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:650 -msgid "Time Remaining: " +#. Process priority +#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1077 +#: Client/core/CSettings.cpp:4801 +msgid "Process priority:" msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:660 -#, c-format -msgid "%d day" -msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" +#. Debug setting +#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1091 +#: Client/core/CSettings.cpp:4813 +msgid "Debug setting:" +msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:662 -#, c-format -msgid "%d hour" -msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" +#. Streaming memory +#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1114 +#: Client/core/CSettings.cpp:4815 +msgid "Streaming memory:" +msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:664 -#, c-format -msgid "%d minute" -msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" +#. Update build type +#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1215 +msgid "Update build type:" +msgstr "" -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:666 -#, c-format -msgid "%d second" -msgid_plural "%d seconds" -msgstr[0] "" -msgstr[1] "" +#. UpdateAutoInstall +#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1194 +msgid "Install important updates:" +msgstr "" -#. Display the error -#: Client/mods/deathmatch/logic/CPacketHandler.cpp:670 -msgid "Disconnected" +#: Client/core/CSettings.cpp:1018 Client/core/CSettings.cpp:1046 +#: Client/core/CSettings.cpp:1059 Client/core/CSettings.cpp:3156 +#: Client/core/CSettings.cpp:3172 Client/core/CSettings.cpp:3179 +msgid "On" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:37 -msgid "HOST GAME" +#: Client/core/CSettings.cpp:1031 Client/core/CSettings.cpp:3161 +msgid "Very slow" msgstr "" -#. * -#. * Webbrowser tab -#. * -#: Client/mods/deathmatch/logic/CLocalServer.cpp:51 -#: Client/core/CSettings.cpp:442 Client/core/CSettings.cpp:630 -#: Client/core/CSettings.cpp:904 Client/core/CSettings.cpp:2018 -msgid "General" +#: Client/core/CSettings.cpp:1032 Client/core/CSettings.cpp:1045 +#: Client/core/CSettings.cpp:1058 Client/core/CSettings.cpp:1072 +#: Client/core/CSettings.cpp:1098 Client/core/CSettings.cpp:1110 +#: Client/core/CSettings.cpp:1202 Client/core/CSettings.cpp:1222 +#: Client/core/CSettings.cpp:3163 Client/core/CSettings.cpp:3170 +#: Client/core/CSettings.cpp:3177 Client/core/CSettings.cpp:3186 +#: Client/core/CSettings.cpp:3199 +msgid "Default" msgstr "" -#. m_pTabs->CreateTab ( "Gamemode" ); -#: Client/mods/deathmatch/logic/CLocalServer.cpp:53 -msgid "Resources" +#: Client/core/CSettings.cpp:1033 Client/core/CSettings.cpp:3165 +msgid "Fast" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:55 -#: Client/mods/deathmatch/logic/CLocalServer.cpp:57 -msgid "Server name:" +#: Client/core/CSettings.cpp:1084 Client/core/CSettings.cpp:3141 +msgid "Normal" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:64 -#: Client/mods/deathmatch/logic/CLocalServer.cpp:66 -msgid "Password:" +#: Client/core/CSettings.cpp:1085 Client/core/CSettings.cpp:3143 +msgid "Above normal" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:73 -#: Client/mods/deathmatch/logic/CLocalServer.cpp:75 -msgid "Max players:" +#: Client/core/CSettings.cpp:1121 +msgid "Min" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:82 -#: Client/mods/deathmatch/logic/CLocalServer.cpp:84 -msgid "Broadcast:" +#: Client/core/CSettings.cpp:1134 +msgid "Max" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:86 -msgid "LAN" +#. Windows 8 compatibility +#: Client/core/CSettings.cpp:1141 +msgid "Windows 8 compatibility:" msgstr "" -#. Create the tabs -#: Client/mods/deathmatch/logic/CLocalServer.cpp:90 -#: Client/core/ServerBrowser/CServerBrowser.cpp:133 -msgid "Internet" +#: Client/core/CSettings.cpp:1145 +msgid "16-bit color" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:99 -msgid "Selected" +#: Client/core/CSettings.cpp:1150 +msgid "Mouse fix" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:116 -msgid "All" +#. Cache path info +#: Client/core/CSettings.cpp:1168 +msgid "Client resource files:" msgstr "" -#: Client/mods/deathmatch/logic/CLocalServer.cpp:118 -msgid "Start" +#: Client/core/CSettings.cpp:1172 +msgid "Show in Explorer" msgstr "" -#: Client/mods/deathmatch/logic/CResource.cpp:372 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1084 Client/core/CCore.cpp:674 -#: Client/core/CSettings.cpp:3483 -msgid "In-game" +#. Auto updater section label +#: Client/core/CSettings.cpp:1187 Client/core/CSettings.cpp:1190 +msgid "Auto updater" msgstr "" -#: Client/mods/deathmatch/logic/CTransferBox.cpp:25 -msgid "Map download progress:" +#. Check for updates +#: Client/core/CSettings.cpp:1228 +msgid "Check for update now" msgstr "" -#: Client/mods/deathmatch/logic/CTransferBox.cpp:28 -msgid "Download Progress:" +#: Client/core/CSettings.cpp:1382 +msgid "Some settings will be changed when you next start MTA" msgstr "" -#. Find our largest piece of text, so we can size accordingly -#: Client/mods/deathmatch/logic/CTransferBox.cpp:42 -#: Client/mods/deathmatch/logic/CTransferBox.cpp:105 -#, c-format -msgid "%s of %s" +#: Client/core/CSettings.cpp:1383 +msgid "" +"\n" +"\n" +"Do you want to restart now?" msgstr "" -#: Client/mods/deathmatch/logic/CTransferBox.cpp:44 -#: Client/mods/deathmatch/logic/CTransferBox.cpp:65 -msgid "Disconnect to cancel download" +#: Client/core/CSettings.cpp:1386 +msgid "RESTART REQUIRED" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 -msgid "Flying a UFO around" +#: Client/core/CSettings.cpp:1388 Client/core/CSettings.cpp:1412 +#: Client/core/CSettings.cpp:4488 Client/core/CSettings.cpp:4562 +#: Client/core/CSettings.cpp:4592 Client/core/CSettings.cpp:4641 +#: Client/core/CQuestionBox.cpp:194 Client/core/CVersionUpdater.cpp:1571 +#: Client/core/CVersionUpdater.cpp:1589 Client/core/CVersionUpdater.cpp:1858 +#: Client/core/CVersionUpdater.cpp:1877 Client/core/CMainMenu.cpp:1199 +#: Client/core/ServerBrowser/CServerInfo.cpp:479 Client/loader/Dialogs.cpp:132 +msgid "No" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 -msgid "Cruising around" +#: Client/core/CSettings.cpp:1406 +msgid "Some settings will be changed when you disconnect the current server" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 -msgid "Riding the waves of" +#: Client/core/CSettings.cpp:1407 +msgid "" +"\n" +"\n" +"Do you want to disconnect now?" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 -msgid "Riding the train in" +#: Client/core/CSettings.cpp:1410 +msgid "DISCONNECT REQUIRED" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 -msgid "Flying around" +#. Update the joystick name +#: Client/core/CSettings.cpp:1737 +msgid "Joypad not detected - Check connections and restart game" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 -msgid "Riding around" +#: Client/core/CSettings.cpp:1932 +msgid "Binding axis" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 -msgid "Monster truckin' around" +#: Client/core/CSettings.cpp:1932 +msgid "Move an axis to bind, or escape to clear" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 -msgid "Quaddin' around" +#: Client/core/CSettings.cpp:2009 +msgid "Language:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 -msgid "Bunny hopping around" +#: Client/core/CSettings.cpp:2009 +msgid "Skin:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 -msgid "Doing weird stuff in" +#: Client/core/CSettings.cpp:2009 +msgid "Presets:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:378 -msgid "Climbing around in" +#: Client/core/CSettings.cpp:2058 +msgid "Chat" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:379 -#: Client/mods/deathmatch/logic/CClientGame.cpp:380 -msgid "Doing a drive-by in" +#: Client/core/CSettings.cpp:2075 +msgid "Load" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:381 -msgid "Blub blub..." +#: Client/core/CSettings.cpp:2087 +msgid "Colors" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:382 -msgid "Breathing water" +#: Client/core/CSettings.cpp:2088 +msgid "Layout" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:383 -msgid "Drowning in" +#: Client/core/CSettings.cpp:2089 Client/core/CSettings.cpp:2335 +msgid "Options" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:384 -msgid "Ducking for cover in" +#: Client/core/CSettings.cpp:2095 +msgid "Chat Background" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:385 -msgid "Fighting in" +#: Client/core/CSettings.cpp:2095 +msgid "Chat Text" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:386 -msgid "Throwing fists in" +#: Client/core/CSettings.cpp:2095 +msgid "Input Background" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:387 -msgid "Blastin' fools in" +#: Client/core/CSettings.cpp:2095 +msgid "Input Text" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:388 -msgid "Shooting up" +#: Client/core/CSettings.cpp:2118 +msgid "Lines:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:389 -msgid "Jetpacking in" +#: Client/core/CSettings.cpp:2118 +msgid "Scale:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:390 -msgid "Literally on fire in" +#: Client/core/CSettings.cpp:2118 +msgid "Width:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:391 -msgid "Burning up in" +#: Client/core/CSettings.cpp:2121 +msgid "Size" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:392 -msgid "Swimming in" +#: Client/core/CSettings.cpp:2170 +msgid "after" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:393 -msgid "Floating around in" +#: Client/core/CSettings.cpp:2170 +msgid "for" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:394 -msgid "Being chased by a shark" +#: Client/core/CSettings.cpp:2170 +msgid "sec" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:395 -msgid "Choking to death in" +#: Client/core/CSettings.cpp:2173 +msgid "Fading" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:528 Client/core/CCore.cpp:674 -#: Client/core/CSettings.cpp:3479 Client/core/CMainMenu.cpp:304 -msgid "Main menu" +#: Client/core/CSettings.cpp:2179 +msgid "Fade out old lines" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:636 -#: Client/mods/deathmatch/logic/CClientGame.cpp:734 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1300 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1357 -msgid "Invalid nickname! Please go to Settings and set a new one!" +#: Client/core/CSettings.cpp:2219 +msgid "Horizontal:" msgstr "" -#. Display the status box -#: Client/mods/deathmatch/logic/CClientGame.cpp:652 -#: Client/core/CConnectManager.cpp:148 -msgid "CONNECTING" +#: Client/core/CSettings.cpp:2219 +msgid "Vertical:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:652 -msgid "Entering the game ..." +#: Client/core/CSettings.cpp:2219 +msgid "Text-Align:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:710 -msgid "" -"Not connected; please use Quick Connect or the 'connect' command to connect " -"to a server." +#: Client/core/CSettings.cpp:2219 +msgid "X-Offset:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:756 -msgid "Could not start the local server. See console for details." +#: Client/core/CSettings.cpp:2220 +msgid "Y-Offset:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:766 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 -msgid "Local Server" -msgstr "" - -#: Client/mods/deathmatch/logic/CClientGame.cpp:766 -msgid "Starting local server ..." +#: Client/core/CSettings.cpp:2226 +msgid "Position" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1014 -msgid "Area 51" +#: Client/core/CSettings.cpp:2241 Client/core/CSettings.cpp:2255 +msgid "Center" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1023 -msgid "Walking around " +#: Client/core/CSettings.cpp:2254 +msgid "Top" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1172 -#, c-format -msgid "You were kicked from the game ( %s )" +#: Client/core/CSettings.cpp:2256 +msgid "Bottom" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 -msgid "Connecting to local server..." +#: Client/core/CSettings.cpp:2304 +msgid "Font" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1252 -msgid "Error connecting to server." +#: Client/core/CSettings.cpp:2341 +msgid "Hide background when not typing" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1262 -msgid "Connecting to local server timed out. See console for details." +#: Client/core/CSettings.cpp:2346 +msgid "Nickname completion using the \"Tab\" key" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1331 -#: Client/core/CConnectManager.cpp:263 -msgid "Connection timed out" +#: Client/core/CSettings.cpp:2351 +msgid "Allow server to flash the window" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1368 -msgid "Connection with the server was lost" +#: Client/core/CSettings.cpp:2356 +msgid "Allow tray balloon notifications" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1379 -#: Client/core/CConnectManager.cpp:277 Client/core/CConnectManager.cpp:281 -msgid "Disconnected: unknown protocol error" +#: Client/core/CSettings.cpp:2361 +msgid "Chat text black/white outline" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1383 -#: Client/core/CConnectManager.cpp:285 -msgid "Disconnected: disconnected remotely" +#. Create a messagebox to notify the user +#. SString strText = SString::Printf ( "Press a key to bind to '%s'", pItemBind->GetText ().c_str () ); +#. Create a messagebox to notify the user +#. sSString strText = SString::Printf ( "Press a key to bind to '%s'", pItemBind->GetText ().c_str () ); +#: Client/core/CSettings.cpp:2610 Client/core/CSettings.cpp:2617 +msgid "Press a key to bind, or escape to clear" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1387 -#: Client/core/CConnectManager.cpp:289 -msgid "Disconnected: connection lost remotely" +#: Client/core/CSettings.cpp:2611 +msgid "Binding a primary key" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1391 -#: Client/core/CConnectManager.cpp:293 -msgid "Disconnected: you are banned from this server" +#: Client/core/CSettings.cpp:2618 +msgid "Binding a secondary key" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1395 -msgid "Disconnected: the server is currently full" +#: Client/core/CSettings.cpp:2694 +msgid "GTA GAME CONTROLS" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1399 -#: Client/core/CConnectManager.cpp:300 -msgid "Disconnected: disconnected from the server" +#: Client/core/CSettings.cpp:2696 +msgid "MULTIPLAYER CONTROLS" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1403 -#: Client/core/CConnectManager.cpp:304 -msgid "Disconnected: connection to the server was lost" +#: Client/core/CSettings.cpp:2941 Client/core/CSettings.cpp:4764 +msgid "Your nickname contains invalid characters!" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1407 -msgid "Disconnected: invalid password specified" +#: Client/core/CSettings.cpp:3479 Client/core/CCore.cpp:674 +#: Client/core/CMainMenu.cpp:304 +#: Client/mods/deathmatch/logic/CClientGame.cpp:528 +msgid "Main menu" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1411 -#: Client/core/CConnectManager.cpp:311 -msgid "Disconnected: connection was refused" +#: Client/core/CSettings.cpp:3483 Client/core/CCore.cpp:674 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1084 +#: Client/mods/deathmatch/logic/CResource.cpp:372 +msgid "In-game" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1429 -msgid "MTA Client verification failed!" +#: Client/core/CSettings.cpp:3778 +msgid "Red:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 -msgid "In a ditch" +#: Client/core/CSettings.cpp:3778 +msgid "Green:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 -msgid "En-route to hospital" +#: Client/core/CSettings.cpp:3778 +msgid "Blue:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 -msgid "Meeting their maker" +#: Client/core/CSettings.cpp:3778 +msgid "Transparency:" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 -msgid "Regretting their decisions" +#: Client/core/CSettings.cpp:3781 +msgid "Color" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 -msgid "Wasted" +#: Client/core/CSettings.cpp:3858 +msgid "Preview" msgstr "" -#. Couldn't create render target for CPostEffects -#: Client/multiplayer_sa/CMultiplayerSA_CrashFixHacks.cpp:1360 -msgid "Problem with graphics driver" +#: Client/core/CSettings.cpp:4166 +msgid "Please disconnect before changing language" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:19 -msgid "Website requests" +#: Client/core/CSettings.cpp:4194 +msgid "Please disconnect before changing skin" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:27 +#: Client/core/CSettings.cpp:4482 msgid "" -"The server requests the following websites in order to load them (later):" +"Volmetric shadows can cause some systems to slow down.\n" +"\n" +"Are you sure you want to enable them?" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:33 -msgid "NEVER ENTER SENSITIVE DATA TO PROTECT THEM FROM BEING STOLEN" +#: Client/core/CSettings.cpp:4486 +msgid "PERFORMANCE WARNING" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:46 -msgid "Remember decision" +#: Client/core/CSettings.cpp:4506 +msgid "" +"Screen upload is required by some servers for anti-cheat purposes.\n" +"\n" +"(The chat box and GUI is excluded from the upload)\n" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:51 Client/core/CSettings.cpp:974 -msgid "Allow" +#: Client/core/CSettings.cpp:4508 +msgid "SCREEN UPLOAD INFORMATION" msgstr "" -#: Client/cefweb/CWebsiteRequests.cpp:57 -msgid "Deny" +#: Client/core/CSettings.cpp:4523 +msgid "" +"Some scripts may play sounds, such as radio, from the internet.\n" +"\n" +"Disabling this setting may decrease network\n" +"bandwidth consumption.\n" msgstr "" -#: Client/core/CConnectManager.cpp:79 -msgid "Connecting failed. Invalid nick provided!" +#: Client/core/CSettings.cpp:4526 +msgid "EXTERNAL SOUNDS" msgstr "" -#: Client/core/CConnectManager.cpp:110 -msgid "Connecting failed. Invalid host provided!" +#: Client/core/CSettings.cpp:4555 +msgid "" +"It seems that you have the Rich Presence connection option enabled.\n" +"Do you want to allow servers to share their data?\n" +"\n" +"This includes yours unique ID identifier." msgstr "" -#: Client/core/CConnectManager.cpp:126 -#, c-format -msgid "Connecting to %s at port %u failed!" +#: Client/core/CSettings.cpp:4560 +msgid "CONSENT TO ALLOW DATA SHARING" msgstr "" -#. Display the status box -#: Client/core/CConnectManager.cpp:147 -#, c-format -msgid "Connecting to %s:%u ..." +#: Client/core/CSettings.cpp:4584 +msgid "" +"Some files in your GTA:SA data directory are customized.\n" +"MTA will only use these modified files if this check box is ticked.\n" +"\n" +"However, CUSTOMIZED GTA:SA FILES ARE BLOCKED BY MANY SERVERS\n" +"\n" +"Are you sure you want to use them?" msgstr "" -#. Failed loading the mod -#: Client/core/CConnectManager.cpp:403 -#, c-format -msgid "No such mod installed (%s)" +#: Client/core/CSettings.cpp:4590 Client/core/CVersionUpdater.cpp:2081 +msgid "CUSTOMIZED GTA:SA FILES" msgstr "" -#: Client/core/CConnectManager.cpp:411 -msgid "Bad server response (2)" +#: Client/core/CSettings.cpp:4633 +msgid "" +"Enabling DPI awareness is an experimental feature and\n" +"we only recommend it when you play MTA:SA on a scaled monitor.\n" +"You may experience graphical issues if you enable this option.\n" +"\n" +"Are you sure you want to enable this option?" msgstr "" -#: Client/core/CConnectManager.cpp:421 -msgid "Bad server response (1)" +#: Client/core/CSettings.cpp:4639 +msgid "EXPERIMENTAL FEATURE" msgstr "" -#: Client/core/CCommandFuncs.cpp:24 -msgid "***[ COMMAND HELP ]***\n" +#: Client/core/CSettings.cpp:4782 +msgid "Please enter a nickname" msgstr "" -#: Client/core/CCommandFuncs.cpp:158 -#, c-format -msgid "* The time is %d:%02d:%02d" +#: Client/core/CSettings.cpp:4783 +msgid "" +"Please enter a nickname to be used ingame. \n" +"This will be your name when you connect to and play in a server" msgstr "" -#: Client/core/CCommandFuncs.cpp:242 -msgid "connect: Syntax is 'connect [ ]'" +#: Client/core/CSettings.cpp:4801 +msgid "Very experimental feature." msgstr "" -#: Client/core/CCommandFuncs.cpp:250 Client/core/CCommandFuncs.cpp:318 -msgid "connect: Bad port number" +#: Client/core/CSettings.cpp:4803 +msgid "Stops stalls with CJ variations (Uses 65MB more RAM)" msgstr "" -#: Client/core/CCommandFuncs.cpp:272 Client/core/CCommandFuncs.cpp:333 -#, c-format -msgid "connect: Connecting to %s:%u..." +#: Client/core/CSettings.cpp:4805 +msgid "Older routers may require a slower scan speed." msgstr "" -#: Client/core/CCommandFuncs.cpp:276 Client/core/CCommandFuncs.cpp:337 -#, c-format -msgid "connect: could not connect to %s:%u!" +#: Client/core/CSettings.cpp:4807 +msgid "Switch on to use only one connection when downloading." msgstr "" -#: Client/core/CCommandFuncs.cpp:281 -msgid "connect: Failed to unload current mod" +#: Client/core/CSettings.cpp:4809 +msgid "Tag network packets to help ISPs identify MTA traffic." msgstr "" -#: Client/core/CCommandFuncs.cpp:371 -msgid "Bound all controls from GTA" +#: Client/core/CSettings.cpp:4811 +msgid "Spinning circle animation at the bottom of the screen" msgstr "" -#: Client/core/CCommandFuncs.cpp:385 -msgid "Saved configuration file" +#: Client/core/CSettings.cpp:4813 +msgid "Select default always. (This setting is not saved)" msgstr "" -#. Print it -#: Client/core/CCommandFuncs.cpp:451 -#, c-format -msgid "* Your serial is: %s" +#: Client/core/CSettings.cpp:4815 +msgid "Maximum is usually best" msgstr "" -#. TRANSLATORS: Replace with your language native name -#: Client/core/CLocalization.cpp:16 -msgid "English" +#: Client/core/CSettings.cpp:4817 Client/core/CSettings.cpp:4819 +msgid "Auto updater:" msgstr "" -#. Unknown command -#: Client/core/CCommands.cpp:216 -msgid "Unknown command or cvar: " +#: Client/core/CSettings.cpp:4817 +msgid "Select default unless you like filling out bug reports." msgstr "" -#: Client/core/CCore.cpp:813 Shared/mods/deathmatch/logic/Utils.cpp:111 +#: Client/core/CSettings.cpp:4819 +msgid "Select default to automatically install important updates." +msgstr "" + +#: Client/core/CSettings.cpp:4821 +msgid "16-bit color:" +msgstr "" + +#: Client/core/CSettings.cpp:4821 +msgid "Enable 16 bit color modes - Requires MTA restart" +msgstr "" + +#: Client/core/CSettings.cpp:4823 +msgid "Mouse fix:" +msgstr "" + +#: Client/core/CSettings.cpp:4823 +msgid "Mouse movement fix - May need PC restart" +msgstr "" + +#. Create window +#: Client/core/CConsole.cpp:417 +msgid "CONSOLE" +msgstr "" + +#: Client/core/CConnectManager.cpp:79 +msgid "Connecting failed. Invalid nick provided!" +msgstr "" + +#: Client/core/CConnectManager.cpp:110 +msgid "Connecting failed. Invalid host provided!" +msgstr "" + +#: Client/core/CConnectManager.cpp:126 +#, c-format +msgid "Connecting to %s at port %u failed!" +msgstr "" + +#. Display the status box +#: Client/core/CConnectManager.cpp:147 +#, c-format +msgid "Connecting to %s:%u ..." +msgstr "" + +#. Display the status box +#: Client/core/CConnectManager.cpp:148 +#: Client/mods/deathmatch/logic/CClientGame.cpp:652 +msgid "CONNECTING" +msgstr "" + +#: Client/core/CConnectManager.cpp:263 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1331 +msgid "Connection timed out" +msgstr "" + +#: Client/core/CConnectManager.cpp:277 Client/core/CConnectManager.cpp:281 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1379 +msgid "Disconnected: unknown protocol error" +msgstr "" + +#: Client/core/CConnectManager.cpp:285 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1383 +msgid "Disconnected: disconnected remotely" +msgstr "" + +#: Client/core/CConnectManager.cpp:289 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1387 +msgid "Disconnected: connection lost remotely" +msgstr "" + +#: Client/core/CConnectManager.cpp:293 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1391 +msgid "Disconnected: you are banned from this server" +msgstr "" + +#: Client/core/CConnectManager.cpp:300 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1399 +msgid "Disconnected: disconnected from the server" +msgstr "" + +#: Client/core/CConnectManager.cpp:304 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1403 +msgid "Disconnected: connection to the server was lost" +msgstr "" + +#: Client/core/CConnectManager.cpp:311 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1411 +msgid "Disconnected: connection was refused" +msgstr "" + +#. Failed loading the mod +#: Client/core/CConnectManager.cpp:403 +#, c-format +msgid "No such mod installed (%s)" +msgstr "" + +#: Client/core/CConnectManager.cpp:411 +msgid "Bad server response (2)" +msgstr "" + +#: Client/core/CConnectManager.cpp:421 +msgid "Bad server response (1)" +msgstr "" + +#. Unknown command +#: Client/core/CCommands.cpp:216 +msgid "Unknown command or cvar: " +msgstr "" + +#: Client/core/CCore.cpp:811 Client/loader/CInstallManager.cpp:1057 +#, c-format +msgid "MTA:SA cannot continue because drive %s does not have enough space." +msgstr "" + +#: Client/core/CCore.cpp:813 Shared/mods/deathmatch/logic/Utils.cpp:111 msgid "Fatal error" msgstr "" @@ -1594,1690 +1567,1718 @@ msgstr "" msgid "for developers: reload news" msgstr "" -#: Client/core/CCredits.cpp:34 -msgid "Programming" +#. TRANSLATORS: Replace with your language native name +#: Client/core/CLocalization.cpp:16 +msgid "English" msgstr "" -#: Client/core/CCredits.cpp:63 -msgid "Contributors" +#: Client/core/CQuestionBox.cpp:192 Shared/sdk/SharedUtil.Misc.hpp:688 +msgid "Do you want to see some on-line help about this problem ?" msgstr "" -#: Client/core/CCredits.cpp:84 -msgid "Game Design / Scripting" +#: Client/core/CVersionUpdater.cpp:626 +msgid "Busy" msgstr "" -#: Client/core/CCredits.cpp:104 -msgid "Language Localization" +#: Client/core/CVersionUpdater.cpp:626 +msgid "Can't check for updates right now" msgstr "" -#: Client/core/CCredits.cpp:110 -msgid "Patch contributors" +#: Client/core/CVersionUpdater.cpp:1567 Client/core/CVersionUpdater.cpp:1587 +#: Client/core/CVersionUpdater.cpp:1605 +#, c-format +msgid "MTA:SA %s required" msgstr "" -#: Client/core/CCredits.cpp:234 -msgid "Special Thanks" +#: Client/core/CVersionUpdater.cpp:1568 +#, c-format +msgid "" +"An updated version of MTA:SA %s is required to join the selected server.\n" +"\n" +"Do you want to download and install MTA:SA %s ?" msgstr "" -#: Client/core/CCredits.cpp:265 -msgid "" -"This software and project makes use of the following libraries and software:" +#: Client/core/CVersionUpdater.cpp:1588 +#, c-format +msgid "Do you want to launch MTA:SA %s and connect to this server ?" msgstr "" -#: Client/core/CQuestionBox.cpp:192 Shared/sdk/SharedUtil.Misc.hpp:688 -msgid "Do you want to see some on-line help about this problem ?" +#: Client/core/CVersionUpdater.cpp:1606 +msgid "" +"It is not possible to connect at this time.\n" +"\n" +"Please try later." msgstr "" -#. Create window (with frame) if it will fit inside the screen resolution -#: Client/core/CSettings.cpp:84 -msgid "SETTINGS" +#: Client/core/CVersionUpdater.cpp:1788 +msgid "Connecting" msgstr "" -#: Client/core/CSettings.cpp:116 -msgid "Multiplayer" +#: Client/core/CVersionUpdater.cpp:1789 Client/core/CVersionUpdater.cpp:1805 +msgid "Please wait..." msgstr "" -#: Client/core/CSettings.cpp:117 -msgid "Video" +#: Client/core/CVersionUpdater.cpp:1804 +msgid "CHECKING" msgstr "" -#: Client/core/CSettings.cpp:118 -msgid "Audio" +#: Client/core/CVersionUpdater.cpp:1821 Client/core/CVersionUpdater.cpp:1914 +msgid "UPDATE CHECK" msgstr "" -#: Client/core/CSettings.cpp:119 -msgid "Binds" +#: Client/core/CVersionUpdater.cpp:1822 +msgid "No update needed" msgstr "" -#: Client/core/CSettings.cpp:120 -msgid "Controls" +#: Client/core/CVersionUpdater.cpp:1839 +msgid "DOWNLOADING" msgstr "" -#: Client/core/CSettings.cpp:121 -msgid "Interface" +#: Client/core/CVersionUpdater.cpp:1840 +msgid "waiting..." msgstr "" -#: Client/core/CSettings.cpp:122 -msgid "Web Browser" +#: Client/core/CVersionUpdater.cpp:1856 +msgid "MANDATORY UPDATE" msgstr "" -#: Client/core/CSettings.cpp:123 -msgid "Advanced" +#: Client/core/CVersionUpdater.cpp:1857 +msgid "" +"To join this server, you must update MTA.\n" +"\n" +" Do you want to update now ?" msgstr "" -#: Client/core/CSettings.cpp:147 Client/core/CSettings.cpp:338 -#: Client/core/CSettings.cpp:617 Client/core/CSettings.cpp:889 -msgid "Load defaults" +#: Client/core/CVersionUpdater.cpp:1875 +msgid "OPTIONAL UPDATE" msgstr "" -#. * -#. * Controls tab -#. * -#: Client/core/CSettings.cpp:157 Client/core/CSettings.cpp:181 -msgid "Mouse sensitivity:" +#: Client/core/CVersionUpdater.cpp:1876 +msgid "" +"Server says an update is recommended, but not essential.\n" +"\n" +" Do you want to update now ?" msgstr "" -#. VerticalAimSensitivity -#: Client/core/CSettings.cpp:157 Client/core/CSettings.cpp:199 -msgid "Vertical aim sensitivity:" +#: Client/core/CVersionUpdater.cpp:1915 +msgid "" +"Update not currently avalable.\n" +"\n" +"Please check www.mtasa.com" msgstr "" -#. Mouse Options -#: Client/core/CSettings.cpp:160 -msgid "Mouse options" +#: Client/core/CVersionUpdater.cpp:1936 Client/core/CVersionUpdater.cpp:2118 +msgid "ERROR SAVING" msgstr "" -#: Client/core/CSettings.cpp:167 -msgid "Invert mouse vertically" +#: Client/core/CVersionUpdater.cpp:1937 Client/core/CVersionUpdater.cpp:2119 +msgid "Unable to create the file." msgstr "" -#: Client/core/CSettings.cpp:171 -msgid "Steer with mouse" +#: Client/core/CVersionUpdater.cpp:1945 Client/core/CVersionUpdater.cpp:1954 +#: Client/core/CVersionUpdater.cpp:2127 Client/core/CVersionUpdater.cpp:2136 +msgid "ERROR DOWNLOADING" msgstr "" -#: Client/core/CSettings.cpp:175 -msgid "Fly with mouse" +#: Client/core/CVersionUpdater.cpp:1946 Client/core/CVersionUpdater.cpp:2128 +msgid "The downloaded file appears to be incorrect." msgstr "" -#. Joypad options -#: Client/core/CSettings.cpp:217 -msgid "Joypad options" +#: Client/core/CVersionUpdater.cpp:1955 Client/core/CVersionUpdater.cpp:2137 +msgid "For some reason." msgstr "" -#: Client/core/CSettings.cpp:230 -msgid "Standard controls (Mouse + Keyboard)" +#: Client/core/CVersionUpdater.cpp:1966 Client/core/CVersionUpdater.cpp:2150 +msgid "DOWNLOAD COMPLETE" msgstr "" -#: Client/core/CSettings.cpp:237 -msgid "Classic controls (Joypad)" +#: Client/core/CVersionUpdater.cpp:1990 +msgid " - Unknown problem in _DialogUpdateResult" msgstr "" -#: Client/core/CSettings.cpp:274 -msgid "Dead Zone" +#: Client/core/CVersionUpdater.cpp:2088 Client/core/CVersionUpdater.cpp:2098 +msgid "Ok" msgstr "" -#: Client/core/CSettings.cpp:279 -msgid "Saturation" +#: Client/core/CVersionUpdater.cpp:2096 +msgid "ERROR" msgstr "" -#: Client/core/CSettings.cpp:285 -msgid "Use the 'Binds' tab for joypad buttons." +#: Client/core/CVersionUpdater.cpp:2097 +msgid "" +"Some MTA:SA data files are missing.\n" +"\n" +"\n" +"Please reinstall MTA:SA" msgstr "" -#: Client/core/CSettings.cpp:324 -msgid "Left Stick" +#: Client/core/CVersionUpdater.cpp:2774 +#, c-format +msgid "%3d %% completed" msgstr "" -#: Client/core/CSettings.cpp:330 -msgid "Right Stick" +#: Client/core/CVersionUpdater.cpp:2777 +#, c-format +msgid "" +"\n" +"\n" +"Waiting for response - %-3d" msgstr "" -#: Client/core/CSettings.cpp:345 -msgid "DESCRIPTION" +#: Client/core/CCommandFuncs.cpp:24 +msgid "***[ COMMAND HELP ]***\n" msgstr "" -#: Client/core/CSettings.cpp:346 -msgid "KEY" +#: Client/core/CCommandFuncs.cpp:158 +#, c-format +msgid "* The time is %d:%02d:%02d" msgstr "" -#: Client/core/CSettings.cpp:348 -msgid "ALT. KEY" +#: Client/core/CCommandFuncs.cpp:242 +msgid "connect: Syntax is 'connect [ ]'" msgstr "" -#. * -#. * Multiplayer tab -#. * -#: Client/core/CSettings.cpp:353 Client/core/CSettings.cpp:356 -msgid "Nick:" +#: Client/core/CCommandFuncs.cpp:250 Client/core/CCommandFuncs.cpp:318 +msgid "connect: Bad port number" msgstr "" -#: Client/core/CSettings.cpp:378 -msgid "Save server passwords" +#: Client/core/CCommandFuncs.cpp:272 Client/core/CCommandFuncs.cpp:333 +#, c-format +msgid "connect: Connecting to %s:%u..." msgstr "" -#: Client/core/CSettings.cpp:383 -msgid "Auto-refresh server browser" +#: Client/core/CCommandFuncs.cpp:276 Client/core/CCommandFuncs.cpp:337 +#, c-format +msgid "connect: could not connect to %s:%u!" msgstr "" -#: Client/core/CSettings.cpp:388 -msgid "Allow screen upload" +#: Client/core/CCommandFuncs.cpp:281 +msgid "connect: Failed to unload current mod" msgstr "" -#: Client/core/CSettings.cpp:393 -msgid "Allow external sounds" +#: Client/core/CCommandFuncs.cpp:371 +msgid "Bound all controls from GTA" msgstr "" -#: Client/core/CSettings.cpp:398 -msgid "Always show download window" +#: Client/core/CCommandFuncs.cpp:385 +msgid "Saved configuration file" msgstr "" -#: Client/core/CSettings.cpp:403 -msgid "Allow connecting with Discord Rich Presence" +#. Print it +#: Client/core/CCommandFuncs.cpp:451 +#, c-format +msgid "* Your serial is: %s" msgstr "" -#: Client/core/CSettings.cpp:408 -msgid "Use customized GTA:SA files" +#: Client/core/CMainMenu.cpp:333 +msgid "" +"You are using a feature-branch build! This is a test build only which cannot " +"be used to connect to public servers!" msgstr "" -#: Client/core/CSettings.cpp:413 -msgid "Map rendering options" +#: Client/core/CMainMenu.cpp:352 +msgid "" +"MTA will not receive updates on XP/Vista after July 2019.\n" +"\n" +"Upgrade Windows to play on the latest servers." msgstr "" -#: Client/core/CSettings.cpp:419 Client/core/CSettings.cpp:628 -msgid "Opacity:" +#: Client/core/CMainMenu.cpp:1193 +msgid "" +"This will disconnect you from the current server.\n" +"\n" +"Are you sure you want to disconnect?" msgstr "" -#. * -#. * Audio tab -#. * -#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:448 -msgid "Master volume:" +#: Client/core/CMainMenu.cpp:1197 +msgid "DISCONNECT WARNING" msgstr "" -#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:467 -msgid "Radio volume:" +#: Client/core/ServerBrowser/CServerList.cpp:25 +msgid "Idle" msgstr "" -#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:486 -msgid "SFX volume:" -msgstr "" +#: Client/core/ServerBrowser/CServerList.cpp:150 +msgid "player" +msgid_plural "players" +msgstr[0] "" +msgstr[1] "" -#: Client/core/CSettings.cpp:439 Client/core/CSettings.cpp:505 -msgid "MTA volume:" +#: Client/core/ServerBrowser/CServerList.cpp:151 +msgid "on" msgstr "" -#: Client/core/CSettings.cpp:440 Client/core/CSettings.cpp:524 -msgid "Voice volume:" +#: Client/core/ServerBrowser/CServerList.cpp:154 +msgid "server" +msgid_plural "servers" +msgstr[0] "" +msgstr[1] "" + +#. We are polling for the master server list (first pass) +#: Client/core/ServerBrowser/CServerList.cpp:238 +#, c-format +msgid "Requesting master server list (%lu ms elapsed)" msgstr "" -#: Client/core/CSettings.cpp:440 Client/core/CSettings.cpp:565 -msgid "Play mode:" +#. Abort +#: Client/core/ServerBrowser/CServerList.cpp:254 +msgid "Master server list could not be parsed." msgstr "" -#: Client/core/CSettings.cpp:543 -msgid "Radio options" +#. Abort +#: Client/core/ServerBrowser/CServerList.cpp:264 +msgid "Master server list could not be retrieved." msgstr "" -#: Client/core/CSettings.cpp:549 -msgid "Radio Equalizer" +#: Client/core/ServerBrowser/CServerList.cpp:274 +msgid "(Backup server list)" msgstr "" -#: Client/core/CSettings.cpp:554 -msgid "Radio Auto-tune" +#: Client/core/ServerBrowser/CServerList.cpp:326 +msgid "Cannot bind LAN-broadcast socket" msgstr "" -#: Client/core/CSettings.cpp:559 -msgid "Usertrack options" +#: Client/core/ServerBrowser/CServerList.cpp:345 +msgid "Attempting to discover LAN servers" msgstr "" -#: Client/core/CSettings.cpp:573 Client/core/CSettings.cpp:3087 -msgid "Radio" +#. Create queue window +#: Client/core/ServerBrowser/CServerInfo.cpp:32 +#: Client/core/ServerBrowser/CServerInfo.cpp:302 +msgid "SERVER IS FULL" msgstr "" -#: Client/core/CSettings.cpp:574 Client/core/CSettings.cpp:3089 -msgid "Random" +#. Determine our label draw position for L10n +#. Start position +#. Server Name +#: Client/core/ServerBrowser/CServerInfo.cpp:44 +#: Client/core/ServerBrowser/CServerInfo.cpp:53 +msgid "Name:" msgstr "" -#: Client/core/CSettings.cpp:575 Client/core/CSettings.cpp:3091 -msgid "Sequential" +#. Server IP +#: Client/core/ServerBrowser/CServerInfo.cpp:44 +#: Client/core/ServerBrowser/CServerInfo.cpp:64 +msgid "Server Address:" msgstr "" -#: Client/core/CSettings.cpp:578 -msgid "Automatic Media Scan" +#. Gamemode +#: Client/core/ServerBrowser/CServerInfo.cpp:44 +#: Client/core/ServerBrowser/CServerInfo.cpp:75 +msgid "Gamemode:" msgstr "" -#: Client/core/CSettings.cpp:585 -msgid "Mute options" +#. Map +#: Client/core/ServerBrowser/CServerInfo.cpp:44 +#: Client/core/ServerBrowser/CServerInfo.cpp:86 +msgid "Map:" msgstr "" -#: Client/core/CSettings.cpp:591 -msgid "Mute All sounds when minimized" +#. Players +#: Client/core/ServerBrowser/CServerInfo.cpp:45 +#: Client/core/ServerBrowser/CServerInfo.cpp:97 +msgid "Players:" msgstr "" -#: Client/core/CSettings.cpp:596 -msgid "Mute Radio sounds when minimized" +#. Passworded +#: Client/core/ServerBrowser/CServerInfo.cpp:45 +#: Client/core/ServerBrowser/CServerInfo.cpp:108 +msgid "Passworded:" msgstr "" -#: Client/core/CSettings.cpp:601 -msgid "Mute SFX sounds when minimized" +#. Latency +#: Client/core/ServerBrowser/CServerInfo.cpp:45 +#: Client/core/ServerBrowser/CServerInfo.cpp:119 +msgid "Latency:" msgstr "" -#: Client/core/CSettings.cpp:606 -msgid "Mute MTA sounds when minimized" +#. Column for player names +#. Player List Columns +#: Client/core/ServerBrowser/CServerInfo.cpp:138 +#: Client/core/ServerBrowser/CServerBrowser.cpp:478 +msgid "Player list" msgstr "" -#: Client/core/CSettings.cpp:611 -msgid "Mute Voice sounds when minimized" +#. Close button +#: Client/core/ServerBrowser/CServerInfo.cpp:144 +msgid "Close" msgstr "" -#. * -#. * Video tab -#. * -#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:636 -msgid "Resolution:" +#. Join Game button +#: Client/core/ServerBrowser/CServerInfo.cpp:152 +msgid "Join Game" msgstr "" -#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:683 -msgid "FOV:" +#. Please enter password label +#: Client/core/ServerBrowser/CServerInfo.cpp:166 +msgid "Please enter the password to the server:" msgstr "" -#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:699 -msgid "Draw Distance:" +#: Client/core/ServerBrowser/CServerInfo.cpp:177 +msgid "Join the server as soon as a player slot is available." msgstr "" -#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:717 -msgid "Brightness:" +#: Client/core/ServerBrowser/CServerInfo.cpp:310 +msgid "PLEASE ENTER SERVER PASSWORD" msgstr "" -#: Client/core/CSettings.cpp:627 Client/core/CSettings.cpp:735 -msgid "FX Quality:" +#: Client/core/ServerBrowser/CServerInfo.cpp:319 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1380 +#: Client/loader/MainFunctions.cpp:603 Client/loader/MainFunctions.cpp:610 +#: Client/loader/MainFunctions.cpp:1219 +msgid "Information" msgstr "" -#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:749 -msgid "Anisotropic filtering:" +#. The server has timed out +#: Client/core/ServerBrowser/CServerInfo.cpp:402 +msgid "Timed Out" msgstr "" -#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:776 -msgid "Anti-aliasing:" +#. Set every GUI elements text to blank +#: Client/core/ServerBrowser/CServerInfo.cpp:431 +msgid "Querying..." msgstr "" -#: Client/core/CSettings.cpp:628 Client/core/CSettings.cpp:790 -msgid "Aspect Ratio:" +#. Create the window +#: Client/core/ServerBrowser/CServerBrowser.cpp:85 +msgid "SERVER BROWSER" msgstr "" -#: Client/core/CSettings.cpp:648 -msgid "Windowed" +#. Create the tabs +#: Client/core/ServerBrowser/CServerBrowser.cpp:133 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:90 +msgid "Internet" msgstr "" -#: Client/core/CSettings.cpp:654 -msgid "DPI aware" +#: Client/core/ServerBrowser/CServerBrowser.cpp:134 +msgid "Local" msgstr "" -#: Client/core/CSettings.cpp:669 Client/core/CSettings.cpp:1613 -msgid "Standard" +#: Client/core/ServerBrowser/CServerBrowser.cpp:135 +msgid "Favourites" msgstr "" -#: Client/core/CSettings.cpp:671 Client/core/CSettings.cpp:1617 -msgid "Borderless keep res" +#: Client/core/ServerBrowser/CServerBrowser.cpp:136 +msgid "Recent" msgstr "" -#: Client/core/CSettings.cpp:675 -msgid "Mip Mapping" +#: Client/core/ServerBrowser/CServerBrowser.cpp:191 +msgid "" +"FOR QUICK CONNECT:\n" +"\n" +"Type the address and port into the address bar.\n" +"Or select a server from the history list and press 'Connect'" msgstr "" -#: Client/core/CSettings.cpp:743 Client/core/CSettings.cpp:1517 -msgid "Low" +#: Client/core/ServerBrowser/CServerBrowser.cpp:203 +msgid "HELP" msgstr "" -#: Client/core/CSettings.cpp:744 Client/core/CSettings.cpp:1519 -msgid "Medium" +#: Client/core/ServerBrowser/CServerBrowser.cpp:212 +#: Client/core/ServerBrowser/CServerBrowser.cpp:252 +msgid "Refresh" msgstr "" -#: Client/core/CSettings.cpp:745 Client/core/CSettings.cpp:1086 -#: Client/core/CSettings.cpp:1521 Client/core/CSettings.cpp:3145 -msgid "High" +#: Client/core/ServerBrowser/CServerBrowser.cpp:212 +#: Client/core/ServerBrowser/CServerBrowser.cpp:253 +msgid "Add Favorite" msgstr "" -#: Client/core/CSettings.cpp:746 Client/core/CSettings.cpp:1523 -msgid "Very high" +#: Client/core/ServerBrowser/CServerBrowser.cpp:212 +#: Client/core/ServerBrowser/CServerBrowser.cpp:254 +#: Client/core/ServerBrowser/CServerBrowser.cpp:301 +#: Client/core/ServerBrowser/CServerBrowser.cpp:372 +msgid "Connect" msgstr "" -#: Client/core/CSettings.cpp:761 Client/core/CSettings.cpp:784 -#: Client/core/CSettings.cpp:1017 Client/core/CSettings.cpp:1071 -#: Client/core/CSettings.cpp:1201 Client/core/CSettings.cpp:1527 -#: Client/core/CSettings.cpp:3152 Client/core/CSettings.cpp:3184 -#: Client/core/CSettings.cpp:3206 Client/core/CSettings.cpp:4234 -msgid "Off" +#: Client/core/ServerBrowser/CServerBrowser.cpp:212 +#: Client/core/ServerBrowser/CServerBrowser.cpp:255 +msgid "Server information" msgstr "" -#: Client/core/CSettings.cpp:785 Client/core/CSettings.cpp:1529 -msgid "1x" +#: Client/core/ServerBrowser/CServerBrowser.cpp:213 +#: Client/core/ServerBrowser/CServerBrowser.cpp:256 +msgid "Search servers" msgstr "" -#: Client/core/CSettings.cpp:786 Client/core/CSettings.cpp:1531 -msgid "2x" +#: Client/core/ServerBrowser/CServerBrowser.cpp:213 +#: Client/core/ServerBrowser/CServerBrowser.cpp:257 +msgid "Search players" msgstr "" -#: Client/core/CSettings.cpp:787 Client/core/CSettings.cpp:1533 -msgid "3x" +#: Client/core/ServerBrowser/CServerBrowser.cpp:213 +#: Client/core/ServerBrowser/CServerBrowser.cpp:258 +msgid "Start search" msgstr "" -#: Client/core/CSettings.cpp:800 Client/core/CSettings.cpp:1019 -#: Client/core/CSettings.cpp:1539 Client/core/CSettings.cpp:3154 -msgid "Auto" +#: Client/core/ServerBrowser/CServerBrowser.cpp:299 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1697 +msgid "Search players..." msgstr "" -#: Client/core/CSettings.cpp:801 Client/core/CSettings.cpp:1541 -msgid "4:3" +#: Client/core/ServerBrowser/CServerBrowser.cpp:422 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1695 +msgid "Search servers..." msgstr "" -#: Client/core/CSettings.cpp:802 Client/core/CSettings.cpp:1543 -msgid "16:10" +#: Client/core/ServerBrowser/CServerBrowser.cpp:453 +msgid "Name" msgstr "" -#: Client/core/CSettings.cpp:803 Client/core/CSettings.cpp:1545 -msgid "16:9" +#: Client/core/ServerBrowser/CServerBrowser.cpp:454 +msgid "Players" msgstr "" -#: Client/core/CSettings.cpp:806 -msgid "HUD Match Aspect Ratio" +#: Client/core/ServerBrowser/CServerBrowser.cpp:455 +msgid "Ping" msgstr "" -#: Client/core/CSettings.cpp:812 -msgid "Volumetric Shadows" +#: Client/core/ServerBrowser/CServerBrowser.cpp:456 +msgid "Gamemode" msgstr "" -#: Client/core/CSettings.cpp:816 -msgid "Grass effect" +#. Include label +#: Client/core/ServerBrowser/CServerBrowser.cpp:486 +msgid "Include:" msgstr "" -#: Client/core/CSettings.cpp:820 -msgid "Heat haze" +#: Client/core/ServerBrowser/CServerBrowser.cpp:492 +msgid "Empty" msgstr "" -#: Client/core/CSettings.cpp:824 -msgid "Tyre Smoke etc" +#: Client/core/ServerBrowser/CServerBrowser.cpp:498 +msgid "Full" msgstr "" -#: Client/core/CSettings.cpp:828 -msgid "Dynamic ped shadows" +#: Client/core/ServerBrowser/CServerBrowser.cpp:504 +msgid "Locked" msgstr "" -#: Client/core/CSettings.cpp:832 -msgid "Motion blur" +#: Client/core/ServerBrowser/CServerBrowser.cpp:516 +msgid "Offline" msgstr "" -#: Client/core/CSettings.cpp:837 -msgid "Full Screen Minimize" +#: Client/core/ServerBrowser/CServerBrowser.cpp:529 +msgid "Other Versions" msgstr "" -#: Client/core/CSettings.cpp:849 -msgid "Enable Device Selection Dialog" +#: Client/core/ServerBrowser/CServerBrowser.cpp:550 +msgid "Back" msgstr "" -#: Client/core/CSettings.cpp:861 -msgid "Show unsafe resolutions" +#: Client/core/ServerBrowser/CServerBrowser.cpp:556 +#: Client/loader/Dialogs.cpp:135 +msgid "Help" msgstr "" -#: Client/core/CSettings.cpp:873 -msgid "Render vehicles always in high detail" +#: Client/core/ServerBrowser/CServerBrowser.cpp:741 +msgid "Loading..." msgstr "" -#: Client/core/CSettings.cpp:877 -msgid "Render peds always in high detail" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1240 +#: Client/core/ServerBrowser/CServerBrowser.cpp:2182 +msgid " ..loading.." msgstr "" -#: Client/core/CSettings.cpp:881 -msgid "Corona rain reflections" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1278 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1406 +msgid "No address specified!" msgstr "" -#: Client/core/CSettings.cpp:910 -msgid "Enable remote websites" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1291 +msgid "Unknown protocol" msgstr "" -#: Client/core/CSettings.cpp:915 -msgid "Enable Javascript on remote websites" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1291 +msgid "Please use the mtasa:// protocol!" msgstr "" -#: Client/core/CSettings.cpp:920 -msgid "Custom blacklist" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1300 +#: Client/core/ServerBrowser/CServerBrowser.cpp:1357 +#: Client/mods/deathmatch/logic/CClientGame.cpp:636 +#: Client/mods/deathmatch/logic/CClientGame.cpp:734 +msgid "Invalid nickname! Please go to Settings and set a new one!" msgstr "" -#: Client/core/CSettings.cpp:931 Client/core/CSettings.cpp:966 -msgid "Enter a domain e.g. google.com" +#: Client/core/ServerBrowser/CServerBrowser.cpp:1380 +msgid "You have to select a server to connect to." msgstr "" -#: Client/core/CSettings.cpp:939 -msgid "Block" +#: Client/core/DXHook/CDirect3DHook9.cpp:124 +msgid "" +"Could not initialize Direct3D9.\n" +"\n" +"Please ensure the DirectX End-User Runtime and\n" +"latest Windows Service Packs are installed correctly." msgstr "" -#: Client/core/CSettings.cpp:947 Client/core/CSettings.cpp:982 -msgid "Domain" +#: Client/mods/deathmatch/CClient.cpp:36 +msgid "This version has expired." msgstr "" -#: Client/core/CSettings.cpp:949 Client/core/CSettings.cpp:984 -msgid "Remove domain" +#: Client/mods/deathmatch/CClient.cpp:56 +msgid "disconnect from the game" msgstr "" -#. Reset vecTemp -#: Client/core/CSettings.cpp:955 -msgid "Custom whitelist" +#: Client/mods/deathmatch/CClient.cpp:57 +msgid "shows the nametags" msgstr "" -#. Misc section label -#: Client/core/CSettings.cpp:997 -msgid "Misc" +#: Client/mods/deathmatch/CClient.cpp:58 +msgid "shows the chatbox" msgstr "" -#. Fast clothes loading -#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1010 -#: Client/core/CSettings.cpp:4803 -msgid "Fast CJ clothes loading:" +#: Client/mods/deathmatch/CClient.cpp:59 +msgid "shows the network statistics" msgstr "" -#. Browser scan speed -#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1024 -#: Client/core/CSettings.cpp:4805 -msgid "Browser speed:" +#. Key commands (registered as 'mod commands', can be disabled) +#: Client/mods/deathmatch/CClient.cpp:63 +msgid "open the chat input" msgstr "" -#. Single download -#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1038 -#: Client/core/CSettings.cpp:4807 -msgid "Single connection:" +#: Client/mods/deathmatch/CClient.cpp:64 +msgid "transmits voice to other players" msgstr "" -#. Packet tag -#: Client/core/CSettings.cpp:1003 Client/core/CSettings.cpp:1051 -#: Client/core/CSettings.cpp:4809 -msgid "Packet tag:" +#: Client/mods/deathmatch/CClient.cpp:65 +msgid "enters a car as passenger" msgstr "" -#. Progress animation -#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1064 -#: Client/core/CSettings.cpp:4811 -msgid "Progress animation:" +#: Client/mods/deathmatch/CClient.cpp:66 +msgid "next radio channel" msgstr "" -#. Process priority -#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1077 -#: Client/core/CSettings.cpp:4801 -msgid "Process priority:" +#: Client/mods/deathmatch/CClient.cpp:67 +msgid "previous radio channel" msgstr "" -#. Debug setting -#: Client/core/CSettings.cpp:1004 Client/core/CSettings.cpp:1091 -#: Client/core/CSettings.cpp:4813 -msgid "Debug setting:" +#: Client/mods/deathmatch/CClient.cpp:68 +msgid "enables the radar view" msgstr "" -#. Streaming memory -#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1114 -#: Client/core/CSettings.cpp:4815 -msgid "Streaming memory:" +#: Client/mods/deathmatch/CClient.cpp:69 +msgid "zooms the radar in" msgstr "" -#. Update build type -#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1215 -msgid "Update build type:" +#: Client/mods/deathmatch/CClient.cpp:70 +msgid "zooms the radar out" msgstr "" -#. UpdateAutoInstall -#: Client/core/CSettings.cpp:1005 Client/core/CSettings.cpp:1194 -msgid "Install important updates:" +#: Client/mods/deathmatch/CClient.cpp:71 +msgid "moves the radar north" msgstr "" -#: Client/core/CSettings.cpp:1018 Client/core/CSettings.cpp:1046 -#: Client/core/CSettings.cpp:1059 Client/core/CSettings.cpp:3156 -#: Client/core/CSettings.cpp:3172 Client/core/CSettings.cpp:3179 -msgid "On" +#: Client/mods/deathmatch/CClient.cpp:72 +msgid "moves the radar south" msgstr "" -#: Client/core/CSettings.cpp:1031 Client/core/CSettings.cpp:3161 -msgid "Very slow" +#: Client/mods/deathmatch/CClient.cpp:73 +msgid "moves the radar east" msgstr "" -#: Client/core/CSettings.cpp:1032 Client/core/CSettings.cpp:1045 -#: Client/core/CSettings.cpp:1058 Client/core/CSettings.cpp:1072 -#: Client/core/CSettings.cpp:1098 Client/core/CSettings.cpp:1110 -#: Client/core/CSettings.cpp:1202 Client/core/CSettings.cpp:1222 -#: Client/core/CSettings.cpp:3163 Client/core/CSettings.cpp:3170 -#: Client/core/CSettings.cpp:3177 Client/core/CSettings.cpp:3186 -#: Client/core/CSettings.cpp:3199 -msgid "Default" +#: Client/mods/deathmatch/CClient.cpp:74 +msgid "moves the radar west" msgstr "" -#: Client/core/CSettings.cpp:1033 Client/core/CSettings.cpp:3165 -msgid "Fast" +#: Client/mods/deathmatch/CClient.cpp:75 +msgid "attaches the radar" msgstr "" -#: Client/core/CSettings.cpp:1084 Client/core/CSettings.cpp:3141 -msgid "Normal" +#: Client/mods/deathmatch/CClient.cpp:76 +msgid "reduces radar opacity" msgstr "" -#: Client/core/CSettings.cpp:1085 Client/core/CSettings.cpp:3143 -msgid "Above normal" +#: Client/mods/deathmatch/CClient.cpp:77 +msgid "increases radar opacity" msgstr "" -#: Client/core/CSettings.cpp:1121 -msgid "Min" +#: Client/mods/deathmatch/CClient.cpp:78 +msgid "toggles radar help text" msgstr "" -#: Client/core/CSettings.cpp:1134 -msgid "Max" +#: Client/mods/deathmatch/CClient.cpp:79 +msgid "sends a message to the targetted player" msgstr "" -#. Windows 8 compatibility -#: Client/core/CSettings.cpp:1141 -msgid "Windows 8 compatibility:" +#: Client/mods/deathmatch/CClient.cpp:80 +msgid "changes to the next weapon whilst in a vehicle" msgstr "" -#: Client/core/CSettings.cpp:1145 -msgid "16-bit color" +#: Client/mods/deathmatch/CClient.cpp:81 +msgid "changes to the previous weapon whilst in a vehicle" msgstr "" -#: Client/core/CSettings.cpp:1150 -msgid "Mouse fix" +#: Client/mods/deathmatch/CClient.cpp:82 +msgid "outputs info about the current server" msgstr "" -#. Cache path info -#: Client/core/CSettings.cpp:1168 -msgid "Client resource files:" +#. ACHTUNG" Should this be handled by the atomic cvar setter? +#: Client/mods/deathmatch/CClient.cpp:85 +msgid "defines the scale multiplier of all text-displays" msgstr "" -#: Client/core/CSettings.cpp:1172 -msgid "Show in Explorer" +#. Development mode +#: Client/mods/deathmatch/CClient.cpp:92 +msgid "(Development mode) shows the colshapes" msgstr "" -#. Auto updater section label -#: Client/core/CSettings.cpp:1187 Client/core/CSettings.cpp:1190 -msgid "Auto updater" +#: Client/mods/deathmatch/CClient.cpp:93 +msgid "(Development mode) prints world sound ids into the debug window" msgstr "" -#. Check for updates -#: Client/core/CSettings.cpp:1228 -msgid "Check for update now" +#. Throw the error and disconnect +#: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:141 +#, c-format +msgid "Download error: %s" msgstr "" -#: Client/core/CSettings.cpp:1382 -msgid "Some settings will be changed when you next start MTA" +#: Client/mods/deathmatch/logic/CTransferBox.cpp:25 +msgid "Map download progress:" msgstr "" -#: Client/core/CSettings.cpp:1383 -msgid "" -"\n" -"\n" -"Do you want to restart now?" +#: Client/mods/deathmatch/logic/CTransferBox.cpp:28 +msgid "Download Progress:" msgstr "" -#: Client/core/CSettings.cpp:1386 -msgid "RESTART REQUIRED" +#. Find our largest piece of text, so we can size accordingly +#: Client/mods/deathmatch/logic/CTransferBox.cpp:42 +#: Client/mods/deathmatch/logic/CTransferBox.cpp:105 +#, c-format +msgid "%s of %s" msgstr "" -#: Client/core/CSettings.cpp:1406 -msgid "Some settings will be changed when you disconnect the current server" +#: Client/mods/deathmatch/logic/CTransferBox.cpp:44 +#: Client/mods/deathmatch/logic/CTransferBox.cpp:65 +msgid "Disconnect to cancel download" msgstr "" -#: Client/core/CSettings.cpp:1407 -msgid "" -"\n" -"\n" -"Do you want to disconnect now?" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:506 +msgid "Disconnected: Invalid nickname" msgstr "" -#: Client/core/CSettings.cpp:1410 -msgid "DISCONNECT REQUIRED" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:510 +msgid "Disconnect from server" msgstr "" -#. Update the joystick name -#: Client/core/CSettings.cpp:1737 -msgid "Joypad not detected - Check connections and restart game" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:514 +#, c-format +msgid "" +"Disconnected: Serial is banned.\n" +"Reason: %s" msgstr "" -#: Client/core/CSettings.cpp:1932 -msgid "Binding axis" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:520 +#, c-format +msgid "" +"Disconnected: You are banned.\n" +"Reason: %s" msgstr "" -#: Client/core/CSettings.cpp:1932 -msgid "Move an axis to bind, or escape to clear" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:526 +#, c-format +msgid "" +"Disconnected: Account is banned.\n" +"Reason: %s" msgstr "" -#: Client/core/CSettings.cpp:2009 -msgid "Language:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:531 +msgid "Disconnected: Version mismatch" msgstr "" -#: Client/core/CSettings.cpp:2009 -msgid "Skin:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:535 +msgid "Disconnected: Join flood. Please wait a minute, then reconnect." msgstr "" -#: Client/core/CSettings.cpp:2009 -msgid "Presets:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:539 +#, c-format +msgid "" +"Disconnected: Server from different branch.\n" +"Information: %s" msgstr "" -#: Client/core/CSettings.cpp:2058 -msgid "Chat" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:544 +#, c-format +msgid "" +"Disconnected: Bad version.\n" +"Information: %s" msgstr "" -#: Client/core/CSettings.cpp:2075 -msgid "Load" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:549 +#, c-format +msgid "" +"Disconnected: Server is running a newer build.\n" +"Information: %s" msgstr "" -#: Client/core/CSettings.cpp:2087 -msgid "Colors" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:554 +#, c-format +msgid "" +"Disconnected: Server is running an older build.\n" +"Information: %s" msgstr "" -#: Client/core/CSettings.cpp:2088 -msgid "Layout" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:559 +msgid "Disconnected: Nick already in use" msgstr "" -#: Client/core/CSettings.cpp:2089 Client/core/CSettings.cpp:2335 -msgid "Options" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:563 +msgid "Disconnected: Player element could not be created." msgstr "" -#: Client/core/CSettings.cpp:2095 -msgid "Chat Background" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:567 +#, c-format +msgid "Disconnected: Server refused the connection: %s" msgstr "" -#: Client/core/CSettings.cpp:2095 -msgid "Chat Text" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:572 +msgid "Disconnected: Serial verification failed" msgstr "" -#: Client/core/CSettings.cpp:2095 -msgid "Input Background" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:576 +#, c-format +msgid "Disconnected: Connection desync %s" msgstr "" -#: Client/core/CSettings.cpp:2095 -msgid "Input Text" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:585 +#, c-format +msgid "Disconnected: You were kicked by %s" msgstr "" -#: Client/core/CSettings.cpp:2118 -msgid "Lines:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:590 +#, c-format +msgid "Disconnected: You were banned by %s" msgstr "" -#: Client/core/CSettings.cpp:2118 -msgid "Scale:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:601 +msgid "Disconnected: Server shutdown or restarting" msgstr "" -#: Client/core/CSettings.cpp:2118 -msgid "Width:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:621 +msgid "You were kicked from the game" msgstr "" -#: Client/core/CSettings.cpp:2121 -msgid "Size" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:622 +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:633 +msgid "This server requires a non-modifed gta_sa.exe" msgstr "" -#: Client/core/CSettings.cpp:2170 -msgid "after" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:623 +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:634 +msgid "Please replace gta_sa.exe" msgstr "" -#: Client/core/CSettings.cpp:2170 -msgid "for" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:624 +msgid "This server does not allow custom D3D9.DLLs" msgstr "" -#: Client/core/CSettings.cpp:2170 -msgid "sec" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:625 +msgid "Remove D3D9.DLL from your GTA install directory and restart MTA" msgstr "" -#: Client/core/CSettings.cpp:2173 -msgid "Fading" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:626 +msgid "This server does not allow virtual machines" msgstr "" -#: Client/core/CSettings.cpp:2179 -msgid "Fade out old lines" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:627 +msgid "This server requires driver signing to be enabled" msgstr "" -#: Client/core/CSettings.cpp:2219 -msgid "Horizontal:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:628 +msgid "Please restart your PC" msgstr "" -#: Client/core/CSettings.cpp:2219 -msgid "Vertical:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:629 +msgid "This server has detected missing anti-cheat components" msgstr "" -#: Client/core/CSettings.cpp:2219 -msgid "Text-Align:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:630 +msgid "Try restarting MTA" msgstr "" -#: Client/core/CSettings.cpp:2219 -msgid "X-Offset:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:631 +msgid "This server requires a non-modifed gta3.img and gta_int.img" msgstr "" -#: Client/core/CSettings.cpp:2220 -msgid "Y-Offset:" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:632 +msgid "Please replace gta3.img or gta_int.img" msgstr "" -#: Client/core/CSettings.cpp:2226 -msgid "Position" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:635 +msgid "This server does not allow Wine" msgstr "" -#: Client/core/CSettings.cpp:2240 Client/core/CSettings.cpp:2268 -#: Client/core/CKeyBinds.cpp:191 -msgid "Left" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:636 +msgid "Ensure no other program is modifying MTA:SA" msgstr "" -#: Client/core/CSettings.cpp:2241 Client/core/CSettings.cpp:2255 -msgid "Center" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:650 +msgid "Time Remaining: " msgstr "" -#: Client/core/CSettings.cpp:2242 Client/core/CSettings.cpp:2269 -#: Client/core/CKeyBinds.cpp:192 -msgid "Right" -msgstr "" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:660 +#, c-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" -#: Client/core/CSettings.cpp:2254 -msgid "Top" -msgstr "" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:662 +#, c-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" -#: Client/core/CSettings.cpp:2256 -msgid "Bottom" -msgstr "" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:664 +#, c-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" -#: Client/core/CSettings.cpp:2304 -msgid "Font" -msgstr "" +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:666 +#, c-format +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" -#: Client/core/CSettings.cpp:2341 -msgid "Hide background when not typing" +#. Display the error +#: Client/mods/deathmatch/logic/CPacketHandler.cpp:670 +msgid "Disconnected" msgstr "" -#: Client/core/CSettings.cpp:2346 -msgid "Nickname completion using the \"Tab\" key" +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +msgid "Flying a UFO around" msgstr "" -#: Client/core/CSettings.cpp:2351 -msgid "Allow server to flash the window" +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +msgid "Cruising around" msgstr "" -#: Client/core/CSettings.cpp:2356 -msgid "Allow tray balloon notifications" +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +msgid "Riding the waves of" msgstr "" -#: Client/core/CSettings.cpp:2361 -msgid "Chat text black/white outline" +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +msgid "Riding the train in" msgstr "" -#. Create a messagebox to notify the user -#. SString strText = SString::Printf ( "Press a key to bind to '%s'", pItemBind->GetText ().c_str () ); -#. Create a messagebox to notify the user -#. sSString strText = SString::Printf ( "Press a key to bind to '%s'", pItemBind->GetText ().c_str () ); -#: Client/core/CSettings.cpp:2610 Client/core/CSettings.cpp:2617 -msgid "Press a key to bind, or escape to clear" +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +msgid "Flying around" msgstr "" -#: Client/core/CSettings.cpp:2611 -msgid "Binding a primary key" +#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +msgid "Riding around" msgstr "" -#: Client/core/CSettings.cpp:2618 -msgid "Binding a secondary key" +#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +msgid "Monster truckin' around" msgstr "" -#: Client/core/CSettings.cpp:2694 -msgid "GTA GAME CONTROLS" +#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +msgid "Quaddin' around" msgstr "" -#: Client/core/CSettings.cpp:2696 -msgid "MULTIPLAYER CONTROLS" +#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +msgid "Bunny hopping around" msgstr "" -#: Client/core/CSettings.cpp:2941 Client/core/CSettings.cpp:4764 -msgid "Your nickname contains invalid characters!" +#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +msgid "Doing weird stuff in" msgstr "" -#: Client/core/CSettings.cpp:3778 -msgid "Red:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:378 +msgid "Climbing around in" msgstr "" -#: Client/core/CSettings.cpp:3778 -msgid "Green:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:379 +#: Client/mods/deathmatch/logic/CClientGame.cpp:380 +msgid "Doing a drive-by in" msgstr "" -#: Client/core/CSettings.cpp:3778 -msgid "Blue:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:381 +msgid "Blub blub..." msgstr "" -#: Client/core/CSettings.cpp:3778 -msgid "Transparency:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:382 +msgid "Breathing water" msgstr "" -#: Client/core/CSettings.cpp:3781 -msgid "Color" +#: Client/mods/deathmatch/logic/CClientGame.cpp:383 +msgid "Drowning in" msgstr "" -#: Client/core/CSettings.cpp:3858 -msgid "Preview" +#: Client/mods/deathmatch/logic/CClientGame.cpp:384 +msgid "Ducking for cover in" msgstr "" -#: Client/core/CSettings.cpp:4166 -msgid "Please disconnect before changing language" +#: Client/mods/deathmatch/logic/CClientGame.cpp:385 +msgid "Fighting in" msgstr "" -#: Client/core/CSettings.cpp:4194 -msgid "Please disconnect before changing skin" +#: Client/mods/deathmatch/logic/CClientGame.cpp:386 +msgid "Throwing fists in" msgstr "" -#: Client/core/CSettings.cpp:4482 -msgid "" -"Volmetric shadows can cause some systems to slow down.\n" -"\n" -"Are you sure you want to enable them?" +#: Client/mods/deathmatch/logic/CClientGame.cpp:387 +msgid "Blastin' fools in" msgstr "" -#: Client/core/CSettings.cpp:4486 -msgid "PERFORMANCE WARNING" +#: Client/mods/deathmatch/logic/CClientGame.cpp:388 +msgid "Shooting up" msgstr "" -#: Client/core/CSettings.cpp:4506 -msgid "" -"Screen upload is required by some servers for anti-cheat purposes.\n" -"\n" -"(The chat box and GUI is excluded from the upload)\n" +#: Client/mods/deathmatch/logic/CClientGame.cpp:389 +msgid "Jetpacking in" msgstr "" -#: Client/core/CSettings.cpp:4508 -msgid "SCREEN UPLOAD INFORMATION" +#: Client/mods/deathmatch/logic/CClientGame.cpp:390 +msgid "Literally on fire in" msgstr "" -#: Client/core/CSettings.cpp:4523 -msgid "" -"Some scripts may play sounds, such as radio, from the internet.\n" -"\n" -"Disabling this setting may decrease network\n" -"bandwidth consumption.\n" +#: Client/mods/deathmatch/logic/CClientGame.cpp:391 +msgid "Burning up in" msgstr "" -#: Client/core/CSettings.cpp:4526 -msgid "EXTERNAL SOUNDS" +#: Client/mods/deathmatch/logic/CClientGame.cpp:392 +msgid "Swimming in" msgstr "" -#: Client/core/CSettings.cpp:4555 -msgid "" -"It seems that you have the Rich Presence connection option enabled.\n" -"Do you want to allow servers to share their data?\n" -"\n" -"This includes yours unique ID identifier." +#: Client/mods/deathmatch/logic/CClientGame.cpp:393 +msgid "Floating around in" msgstr "" -#: Client/core/CSettings.cpp:4560 -msgid "CONSENT TO ALLOW DATA SHARING" +#: Client/mods/deathmatch/logic/CClientGame.cpp:394 +msgid "Being chased by a shark" msgstr "" -#: Client/core/CSettings.cpp:4584 -msgid "" -"Some files in your GTA:SA data directory are customized.\n" -"MTA will only use these modified files if this check box is ticked.\n" -"\n" -"However, CUSTOMIZED GTA:SA FILES ARE BLOCKED BY MANY SERVERS\n" -"\n" -"Are you sure you want to use them?" +#: Client/mods/deathmatch/logic/CClientGame.cpp:395 +msgid "Choking to death in" msgstr "" -#: Client/core/CSettings.cpp:4590 Client/core/CVersionUpdater.cpp:2081 -msgid "CUSTOMIZED GTA:SA FILES" +#: Client/mods/deathmatch/logic/CClientGame.cpp:652 +msgid "Entering the game ..." msgstr "" -#: Client/core/CSettings.cpp:4633 +#: Client/mods/deathmatch/logic/CClientGame.cpp:710 msgid "" -"Enabling DPI awareness is an experimental feature and\n" -"we only recommend it when you play MTA:SA on a scaled monitor.\n" -"You may experience graphical issues if you enable this option.\n" -"\n" -"Are you sure you want to enable this option?" +"Not connected; please use Quick Connect or the 'connect' command to connect " +"to a server." msgstr "" -#: Client/core/CSettings.cpp:4639 -msgid "EXPERIMENTAL FEATURE" +#: Client/mods/deathmatch/logic/CClientGame.cpp:756 +msgid "Could not start the local server. See console for details." msgstr "" -#: Client/core/CSettings.cpp:4782 -msgid "Please enter a nickname" +#: Client/mods/deathmatch/logic/CClientGame.cpp:766 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 +msgid "Local Server" msgstr "" -#: Client/core/CSettings.cpp:4783 -msgid "" -"Please enter a nickname to be used ingame. \n" -"This will be your name when you connect to and play in a server" +#: Client/mods/deathmatch/logic/CClientGame.cpp:766 +msgid "Starting local server ..." msgstr "" -#: Client/core/CSettings.cpp:4801 -msgid "Very experimental feature." +#: Client/mods/deathmatch/logic/CClientGame.cpp:1014 +msgid "Area 51" msgstr "" -#: Client/core/CSettings.cpp:4803 -msgid "Stops stalls with CJ variations (Uses 65MB more RAM)" +#: Client/mods/deathmatch/logic/CClientGame.cpp:1023 +msgid "Walking around " msgstr "" -#: Client/core/CSettings.cpp:4805 -msgid "Older routers may require a slower scan speed." +#: Client/mods/deathmatch/logic/CClientGame.cpp:1172 +#, c-format +msgid "You were kicked from the game ( %s )" msgstr "" -#: Client/core/CSettings.cpp:4807 -msgid "Switch on to use only one connection when downloading." +#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 +msgid "Connecting to local server..." msgstr "" -#: Client/core/CSettings.cpp:4809 -msgid "Tag network packets to help ISPs identify MTA traffic." +#: Client/mods/deathmatch/logic/CClientGame.cpp:1252 +msgid "Error connecting to server." msgstr "" -#: Client/core/CSettings.cpp:4811 -msgid "Spinning circle animation at the bottom of the screen" +#: Client/mods/deathmatch/logic/CClientGame.cpp:1262 +msgid "Connecting to local server timed out. See console for details." msgstr "" -#: Client/core/CSettings.cpp:4813 -msgid "Select default always. (This setting is not saved)" +#: Client/mods/deathmatch/logic/CClientGame.cpp:1368 +msgid "Connection with the server was lost" msgstr "" -#: Client/core/CSettings.cpp:4815 -msgid "Maximum is usually best" +#: Client/mods/deathmatch/logic/CClientGame.cpp:1395 +msgid "Disconnected: the server is currently full" msgstr "" -#: Client/core/CSettings.cpp:4817 Client/core/CSettings.cpp:4819 -msgid "Auto updater:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:1407 +msgid "Disconnected: invalid password specified" msgstr "" -#: Client/core/CSettings.cpp:4817 -msgid "Select default unless you like filling out bug reports." +#: Client/mods/deathmatch/logic/CClientGame.cpp:1429 +msgid "MTA Client verification failed!" msgstr "" -#: Client/core/CSettings.cpp:4819 -msgid "Select default to automatically install important updates." +#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +msgid "In a ditch" msgstr "" -#: Client/core/CSettings.cpp:4821 -msgid "16-bit color:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +msgid "En-route to hospital" msgstr "" -#: Client/core/CSettings.cpp:4821 -msgid "Enable 16 bit color modes - Requires MTA restart" -msgstr "" - -#: Client/core/CSettings.cpp:4823 -msgid "Mouse fix:" +#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +msgid "Meeting their maker" msgstr "" -#: Client/core/CSettings.cpp:4823 -msgid "Mouse movement fix - May need PC restart" +#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 +msgid "Regretting their decisions" msgstr "" -#: Client/core/CVersionUpdater.cpp:626 -msgid "Busy" +#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 +msgid "Wasted" msgstr "" -#: Client/core/CVersionUpdater.cpp:626 -msgid "Can't check for updates right now" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:37 +msgid "HOST GAME" msgstr "" -#: Client/core/CVersionUpdater.cpp:1567 Client/core/CVersionUpdater.cpp:1587 -#: Client/core/CVersionUpdater.cpp:1605 -#, c-format -msgid "MTA:SA %s required" +#. m_pTabs->CreateTab ( "Gamemode" ); +#: Client/mods/deathmatch/logic/CLocalServer.cpp:53 +msgid "Resources" msgstr "" -#: Client/core/CVersionUpdater.cpp:1568 -#, c-format -msgid "" -"An updated version of MTA:SA %s is required to join the selected server.\n" -"\n" -"Do you want to download and install MTA:SA %s ?" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:55 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:57 +msgid "Server name:" msgstr "" -#: Client/core/CVersionUpdater.cpp:1588 -#, c-format -msgid "Do you want to launch MTA:SA %s and connect to this server ?" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:64 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:66 +msgid "Password:" msgstr "" -#: Client/core/CVersionUpdater.cpp:1606 -msgid "" -"It is not possible to connect at this time.\n" -"\n" -"Please try later." +#: Client/mods/deathmatch/logic/CLocalServer.cpp:73 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:75 +msgid "Max players:" msgstr "" -#: Client/core/CVersionUpdater.cpp:1788 -msgid "Connecting" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:82 +#: Client/mods/deathmatch/logic/CLocalServer.cpp:84 +msgid "Broadcast:" msgstr "" -#: Client/core/CVersionUpdater.cpp:1789 Client/core/CVersionUpdater.cpp:1805 -msgid "Please wait..." +#: Client/mods/deathmatch/logic/CLocalServer.cpp:86 +msgid "LAN" msgstr "" -#: Client/core/CVersionUpdater.cpp:1804 -msgid "CHECKING" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:99 +msgid "Selected" msgstr "" -#: Client/core/CVersionUpdater.cpp:1821 Client/core/CVersionUpdater.cpp:1914 -msgid "UPDATE CHECK" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:116 +msgid "All" msgstr "" -#: Client/core/CVersionUpdater.cpp:1822 -msgid "No update needed" +#: Client/mods/deathmatch/logic/CLocalServer.cpp:118 +msgid "Start" msgstr "" -#: Client/core/CVersionUpdater.cpp:1839 -msgid "DOWNLOADING" +#: Client/loader/Dialogs.cpp:134 +msgid "Quit" msgstr "" -#: Client/core/CVersionUpdater.cpp:1840 -msgid "waiting..." +#: Client/loader/Dialogs.cpp:151 +msgid "MTA: San Andreas has encountered a problem" msgstr "" -#: Client/core/CVersionUpdater.cpp:1856 -msgid "MANDATORY UPDATE" +#: Client/loader/Dialogs.cpp:152 +msgid "Crash information" msgstr "" -#: Client/core/CVersionUpdater.cpp:1857 +#: Client/loader/Dialogs.cpp:153 msgid "" -"To join this server, you must update MTA.\n" -"\n" -" Do you want to update now ?" +"Tick the check box to send this crash info to MTA devs using the 'internet'" msgstr "" -#: Client/core/CVersionUpdater.cpp:1875 -msgid "OPTIONAL UPDATE" +#: Client/loader/Dialogs.cpp:154 +msgid "Doing so will increase the chance of this crash being fixed." msgstr "" -#: Client/core/CVersionUpdater.cpp:1876 -msgid "" -"Server says an update is recommended, but not essential.\n" -"\n" -" Do you want to update now ?" +#: Client/loader/Dialogs.cpp:155 +msgid "Do you want to restart MTA: San Andreas ?" msgstr "" -#: Client/core/CVersionUpdater.cpp:1915 -msgid "" -"Update not currently avalable.\n" -"\n" -"Please check www.mtasa.com" +#: Client/loader/Dialogs.cpp:162 +msgid "MTA: San Andreas - Warning" msgstr "" -#: Client/core/CVersionUpdater.cpp:1936 Client/core/CVersionUpdater.cpp:2118 -msgid "ERROR SAVING" +#: Client/loader/Dialogs.cpp:163 +msgid "" +"Your Grand Theft Auto: San Andreas install directory contains these files:" msgstr "" -#: Client/core/CVersionUpdater.cpp:1937 Client/core/CVersionUpdater.cpp:2119 -msgid "Unable to create the file." +#: Client/loader/Dialogs.cpp:165 +msgid "" +"These files are not required and may interfere with the graphical features " +"in this version of MTA:SA.\n" +"\n" +"It is recommended that you remove or rename these files." msgstr "" -#: Client/core/CVersionUpdater.cpp:1945 Client/core/CVersionUpdater.cpp:1954 -#: Client/core/CVersionUpdater.cpp:2127 Client/core/CVersionUpdater.cpp:2136 -msgid "ERROR DOWNLOADING" +#: Client/loader/Dialogs.cpp:167 +msgid "Keep these files, but also show this warning on next start" msgstr "" -#: Client/core/CVersionUpdater.cpp:1946 Client/core/CVersionUpdater.cpp:2128 -msgid "The downloaded file appears to be incorrect." +#: Client/loader/Dialogs.cpp:168 +msgid "Do not remind me about these files again" msgstr "" -#: Client/core/CVersionUpdater.cpp:1955 Client/core/CVersionUpdater.cpp:2137 -msgid "For some reason." +#: Client/loader/Dialogs.cpp:169 +msgid "Rename these files from *.dll to *.dll.bak" msgstr "" -#: Client/core/CVersionUpdater.cpp:1966 Client/core/CVersionUpdater.cpp:2150 -msgid "DOWNLOAD COMPLETE" +#: Client/loader/Dialogs.cpp:170 +msgid "Show me these files" msgstr "" -#: Client/core/CVersionUpdater.cpp:1990 -msgid " - Unknown problem in _DialogUpdateResult" +#: Client/loader/Dialogs.cpp:171 +msgid "Play MTA:SA" msgstr "" -#: Client/core/CVersionUpdater.cpp:2088 Client/core/CVersionUpdater.cpp:2098 -msgid "Ok" +#: Client/loader/Dialogs.cpp:177 +msgid "MTA: San Andreas - Confusing options" msgstr "" -#: Client/core/CVersionUpdater.cpp:2096 -msgid "ERROR" +#: Client/loader/Dialogs.cpp:178 +msgid "NVidia Optimus detected!" msgstr "" -#: Client/core/CVersionUpdater.cpp:2097 -msgid "" -"Some MTA:SA data files are missing.\n" -"\n" -"\n" -"Please reinstall MTA:SA" +#: Client/loader/Dialogs.cpp:179 +msgid "Try each option and see what works:" msgstr "" -#: Client/core/CVersionUpdater.cpp:2774 -#, c-format -msgid "%3d %% completed" +#: Client/loader/Dialogs.cpp:180 +msgid "A - Standard NVidia" msgstr "" -#: Client/core/CVersionUpdater.cpp:2777 -#, c-format -msgid "" -"\n" -"\n" -"Waiting for response - %-3d" +#: Client/loader/Dialogs.cpp:181 +msgid "B - Alternate NVidia" msgstr "" -#. Even the default skin doesn't work, so give up -#: Client/core/CGUI.cpp:86 -msgid "" -"The skin you selected could not be loaded, and the default skin also could " -"not be loaded, please reinstall MTA." +#: Client/loader/Dialogs.cpp:182 +msgid "C - Standard Intel" msgstr "" -#. Create window -#: Client/core/CConsole.cpp:417 -msgid "CONSOLE" +#: Client/loader/Dialogs.cpp:183 +msgid "D - Alternate Intel" msgstr "" -#: Client/core/CScreenShot.cpp:104 -#, c-format -msgid "Screenshot got %d bytes, but expected %d" +#: Client/loader/Dialogs.cpp:184 +msgid "If you get desperate, this might help:" msgstr "" -#: Client/core/CScreenShot.cpp:110 -msgid "Screenshot failed" +#: Client/loader/Dialogs.cpp:185 +msgid "If you have already selected an option that works, this might help:" msgstr "" -#: Client/core/CScreenShot.cpp:160 -#, c-format -msgid "Screenshot taken: '%s'" +#: Client/loader/Dialogs.cpp:186 +msgid "Force windowed mode" msgstr "" -#. Create the window -#: Client/core/CNewsBrowser.cpp:153 -msgid "NEWS" +#: Client/loader/Dialogs.cpp:187 +msgid "Don't show again" msgstr "" -#. News link -#: Client/core/CNewsBrowser.cpp:171 Client/core/CNewsBrowser.cpp:172 -msgid "Visit latest news article" +#: Client/loader/Dialogs.cpp:195 +msgid "Warning: Could not detect anti-virus product" msgstr "" -#: Client/core/CMainMenu.cpp:333 +#: Client/loader/Dialogs.cpp:197 msgid "" -"You are using a feature-branch build! This is a test build only which cannot " -"be used to connect to public servers!" +"MTA could not detect an anti-virus on your PC.\n" +"\n" +"Viruses interfere with MTA and degrade your gameplay experience.\n" +"\n" +"Press 'Help' for more information." msgstr "" -#: Client/core/CMainMenu.cpp:352 -msgid "" -"MTA will not receive updates on XP/Vista after July 2019.\n" -"\n" -"Upgrade Windows to play on the latest servers." +#: Client/loader/Dialogs.cpp:200 +msgid "I have already installed an anti-virus" msgstr "" -#: Client/core/CMainMenu.cpp:1193 +#: Client/loader/Dialogs.cpp:202 msgid "" -"This will disconnect you from the current server.\n" -"\n" -"Are you sure you want to disconnect?" +"I will not install an anti-virus.\n" +"I want my PC to lag and be part of a botnet." msgstr "" -#: Client/core/CMainMenu.cpp:1197 -msgid "DISCONNECT WARNING" +#: Client/loader/Dialogs.cpp:890 Client/loader/Utils.cpp:534 +msgid "Searching for Grand Theft Auto San Andreas" msgstr "" -#: Client/core/CKeyBinds.cpp:186 -msgid "Fire" +#: Client/loader/Dialogs.cpp:893 Client/loader/Utils.cpp:536 +msgid "Please start Grand Theft Auto San Andreas" msgstr "" -#: Client/core/CKeyBinds.cpp:187 -msgid "Next weapon" +#: Client/loader/Dialogs.cpp:901 Client/loader/Install.cpp:852 +msgid "Installing update..." msgstr "" -#: Client/core/CKeyBinds.cpp:188 -msgid "Previous weapon" +#: Client/loader/Dialogs.cpp:909 Client/loader/Install.cpp:934 +msgid "Extracting files..." msgstr "" -#: Client/core/CKeyBinds.cpp:189 -msgid "Forwards" +#: Client/loader/Dialogs.cpp:914 Client/loader/Utils.cpp:1394 +msgid "Copying files..." msgstr "" -#: Client/core/CKeyBinds.cpp:190 -msgid "Backwards" +#: Client/loader/Dialogs.cpp:919 Client/loader/Utils.cpp:1454 +msgid "Copy finished early. Everything OK." msgstr "" -#: Client/core/CKeyBinds.cpp:193 -msgid "Zoom in" +#: Client/loader/Dialogs.cpp:924 Client/loader/Utils.cpp:1460 +msgid "Finishing..." msgstr "" -#: Client/core/CKeyBinds.cpp:194 -msgid "Zoom out" +#: Client/loader/Dialogs.cpp:928 Client/loader/Utils.cpp:1462 +msgid "Done!" msgstr "" -#: Client/core/CKeyBinds.cpp:195 -msgid "Enter/Exit" +#: Client/loader/Utils.cpp:600 +msgid "Select your Grand Theft Auto: San Andreas Installation Directory" msgstr "" -#: Client/core/CKeyBinds.cpp:196 -msgid "Change camera" -msgstr "" - -#. 10 -#: Client/core/CKeyBinds.cpp:197 -msgid "Jump" -msgstr "" - -#: Client/core/CKeyBinds.cpp:198 -msgid "Sprint" -msgstr "" - -#: Client/core/CKeyBinds.cpp:199 -msgid "Look behind" -msgstr "" - -#: Client/core/CKeyBinds.cpp:200 -msgid "Crouch" -msgstr "" - -#: Client/core/CKeyBinds.cpp:201 -msgid "Action" -msgstr "" - -#: Client/core/CKeyBinds.cpp:202 -msgid "Walk" -msgstr "" - -#: Client/core/CKeyBinds.cpp:203 -msgid "Vehicle fire" -msgstr "" - -#: Client/core/CKeyBinds.cpp:204 -msgid "Vehicle secondary fire" -msgstr "" - -#: Client/core/CKeyBinds.cpp:205 -msgid "Vehicle left" -msgstr "" - -#: Client/core/CKeyBinds.cpp:206 -msgid "Vehicle right" -msgstr "" - -#. 20 -#: Client/core/CKeyBinds.cpp:207 -msgid "Steer forwards/down" -msgstr "" - -#: Client/core/CKeyBinds.cpp:208 -msgid "Steer backwards/up" -msgstr "" - -#: Client/core/CKeyBinds.cpp:209 -msgid "Accelerate" -msgstr "" - -#: Client/core/CKeyBinds.cpp:210 -msgid "Brake/Reverse" -msgstr "" - -#: Client/core/CKeyBinds.cpp:211 -msgid "Radio next" -msgstr "" - -#: Client/core/CKeyBinds.cpp:212 -msgid "Radio previous" -msgstr "" - -#: Client/core/CKeyBinds.cpp:213 -msgid "Radio user track skip" -msgstr "" - -#: Client/core/CKeyBinds.cpp:214 -msgid "Horn" -msgstr "" - -#: Client/core/CKeyBinds.cpp:215 -msgid "Sub-mission" -msgstr "" - -#: Client/core/CKeyBinds.cpp:216 -msgid "Handbrake" -msgstr "" - -#. 30 -#: Client/core/CKeyBinds.cpp:217 -msgid "Vehicle look left" +#: Client/loader/Utils.cpp:968 Client/loader/CInstallManager.cpp:361 +#, c-format +msgid "" +"MTA:SA needs Administrator access for the following task:\n" +"\n" +" '%s'\n" +"\n" +"Please confirm in the next window." msgstr "" -#: Client/core/CKeyBinds.cpp:218 -msgid "Vehicle look right" +#: Client/loader/Utils.cpp:1069 +#, c-format +msgid "Error loading %s module! (%s)" msgstr "" -#: Client/core/CKeyBinds.cpp:219 -msgid "Vehicle look behind" +#: Client/loader/Utils.cpp:1502 +#, c-format +msgid "" +"New installation of %s detected.\n" +"\n" +"Do you want to copy your settings from %s ?" msgstr "" -#: Client/core/CKeyBinds.cpp:220 -msgid "Vehicle mouse look" +#: Client/loader/Utils.cpp:1541 +#, c-format +msgid "GTA:SA had trouble opening the file '%s'" msgstr "" -#: Client/core/CKeyBinds.cpp:221 -msgid "Special control left" +#: Client/loader/Utils.cpp:1563 +#, c-format +msgid "GTA:SA is missing the file '%s'." msgstr "" -#: Client/core/CKeyBinds.cpp:222 -msgid "Special control right" +#: Client/loader/Utils.cpp:1588 +msgid "GTA:SA had trouble loading a model." msgstr "" -#: Client/core/CKeyBinds.cpp:223 -msgid "Special control down" +#: Client/loader/Utils.cpp:1590 +msgid "If you recently modified gta3.img, then try reinstalling GTA:SA." msgstr "" -#: Client/core/CKeyBinds.cpp:224 -msgid "Special control up" +#: Client/loader/Utils.cpp:1615 +msgid "GTA:SA had trouble adding an upgrade to a vehicle." msgstr "" -#: Client/core/CKeyBinds.cpp:225 -msgid "Aim weapon" +#: Client/loader/Utils.cpp:1634 +#, c-format +msgid "GTA:SA found errors in the file '%s'" msgstr "" -#: Client/core/CKeyBinds.cpp:226 -msgid "Conversation yes" +#: Client/loader/Utils.cpp:1716 +msgid "Did your computer restart when playing MTA:SA?" msgstr "" -#. 40 -#: Client/core/CKeyBinds.cpp:227 -msgid "Conversation no" +#: Client/loader/Utils.cpp:1781 +msgid "Please terminate the following programs before continuing:" msgstr "" -#: Client/core/CKeyBinds.cpp:228 -msgid "Group control forwards" +#: Client/loader/MainFunctions.cpp:248 +msgid "" +"Trouble restarting MTA:SA\n" +"\n" +"If the problem persists, open Task Manager and\n" +"stop the 'gta_sa.exe' and 'Multi Theft Auto.exe' processes\n" +"\n" +"\n" +"Try to launch MTA:SA again?" msgstr "" -#: Client/core/CKeyBinds.cpp:229 -msgid "Group control backwards" +#: Client/loader/MainFunctions.cpp:266 +msgid "" +"Another instance of MTA is already running.\n" +"\n" +"If this problem persists, please restart your computer" msgstr "" -#: Client/core/CJoystickManager.cpp:1578 -msgid "Accelerate Axis" +#: Client/loader/MainFunctions.cpp:269 +msgid "" +"Another instance of MTA is already running.\n" +"\n" +"Do you want to terminate it?" msgstr "" -#: Client/core/CJoystickManager.cpp:1580 -msgid "Brake Axis" +#: Client/loader/MainFunctions.cpp:294 +msgid "" +"Are you having problems running MTA:SA?.\n" +"\n" +"Do you want to revert to an earlier version?" msgstr "" -#: Client/core/DXHook/CDirect3DHook9.cpp:124 +#: Client/loader/MainFunctions.cpp:324 msgid "" -"Could not initialize Direct3D9.\n" +"There seems to be a problem launching MTA:SA.\n" +"Resetting GTA settings can sometimes fix this problem.\n" "\n" -"Please ensure the DirectX End-User Runtime and\n" -"latest Windows Service Packs are installed correctly." +"Do you want to reset GTA settings now?" msgstr "" -#. Create queue window -#: Client/core/ServerBrowser/CServerInfo.cpp:32 -#: Client/core/ServerBrowser/CServerInfo.cpp:302 -msgid "SERVER IS FULL" +#: Client/loader/MainFunctions.cpp:339 +msgid "" +"GTA settings have been reset.\n" +"\n" +"Press OK to continue." msgstr "" -#. Determine our label draw position for L10n -#. Start position -#. Server Name -#: Client/core/ServerBrowser/CServerInfo.cpp:44 -#: Client/core/ServerBrowser/CServerInfo.cpp:53 -msgid "Name:" +#: Client/loader/MainFunctions.cpp:344 +#, c-format +msgid "File could not be deleted: '%s'" msgstr "" -#. Server IP -#: Client/core/ServerBrowser/CServerInfo.cpp:44 -#: Client/core/ServerBrowser/CServerInfo.cpp:64 -msgid "Server Address:" +#. No settings to delete, or can't find them +#: Client/loader/MainFunctions.cpp:352 +msgid "" +"Are you having problems running MTA:SA?.\n" +"\n" +"Do you want to see some online help?" msgstr "" -#. Gamemode -#: Client/core/ServerBrowser/CServerInfo.cpp:44 -#: Client/core/ServerBrowser/CServerInfo.cpp:75 -msgid "Gamemode:" +#. Inform user +#: Client/loader/MainFunctions.cpp:388 +msgid "" +"Are you having problems running MTA:SA?.\n" +"\n" +"Do you want to change the following setting?" msgstr "" -#. Map -#: Client/core/ServerBrowser/CServerInfo.cpp:44 -#: Client/core/ServerBrowser/CServerInfo.cpp:86 -msgid "Map:" +#: Client/loader/MainFunctions.cpp:431 +msgid "" +"Are you having problems running MTA:SA?.\n" +"\n" +"Try disabling the following products for GTA and MTA:" msgstr "" -#. Players -#: Client/core/ServerBrowser/CServerInfo.cpp:45 -#: Client/core/ServerBrowser/CServerInfo.cpp:97 -msgid "Players:" +#: Client/loader/MainFunctions.cpp:465 +msgid "" +"WARNING\n" +"\n" +"MTA:SA has detected unusual activity.\n" +"Please run a virus scan to ensure your system is secure.\n" +"\n" msgstr "" -#. Passworded -#: Client/core/ServerBrowser/CServerInfo.cpp:45 -#: Client/core/ServerBrowser/CServerInfo.cpp:108 -msgid "Passworded:" +#: Client/loader/MainFunctions.cpp:468 +#, c-format +msgid "The detected file was: %s\n" msgstr "" -#. Latency -#: Client/core/ServerBrowser/CServerInfo.cpp:45 -#: Client/core/ServerBrowser/CServerInfo.cpp:119 -msgid "Latency:" +#: Client/loader/MainFunctions.cpp:602 +msgid "" +"An instance of GTA: San Andreas is already running. It needs to be " +"terminated before MTA:SA can be started. Do you want to do that now?" msgstr "" -#. Column for player names -#. Player List Columns -#: Client/core/ServerBrowser/CServerInfo.cpp:138 -#: Client/core/ServerBrowser/CServerBrowser.cpp:478 -msgid "Player list" +#: Client/loader/MainFunctions.cpp:609 +msgid "" +"Unable to terminate GTA: San Andreas. If the problem persists, please " +"restart your computer." msgstr "" -#. Close button -#: Client/core/ServerBrowser/CServerInfo.cpp:144 -msgid "Close" +#: Client/loader/MainFunctions.cpp:632 +msgid "" +"Registry entries are missing. Please reinstall Multi Theft Auto: San Andreas." msgstr "" -#. Join Game button -#: Client/core/ServerBrowser/CServerInfo.cpp:152 -msgid "Join Game" +#: Client/loader/MainFunctions.cpp:638 +msgid "" +"The path to your installation of GTA: San Andreas contains unsupported " +"(unicode) characters. Please move your Grand Theft Auto: San Andreas " +"installation to a compatible path that contains only standard ASCII " +"characters and reinstall Multi Theft Auto: San Andreas." msgstr "" -#. Please enter password label -#: Client/core/ServerBrowser/CServerInfo.cpp:166 -msgid "Please enter the password to the server:" +#: Client/loader/MainFunctions.cpp:648 +msgid "" +"The path to your installation of 'MTA:SA' or 'GTA: San Andreas'\n" +"contains a ';' (semicolon).\n" +"\n" +" If you experience problems when running MTA:SA,\n" +" move your installation(s) to a path that does not contain a semicolon." msgstr "" -#: Client/core/ServerBrowser/CServerInfo.cpp:177 -msgid "Join the server as soon as a player slot is available." +#: Client/loader/MainFunctions.cpp:810 +msgid "" +"Load failed. Please ensure that the latest data files have been installed " +"correctly." msgstr "" -#: Client/core/ServerBrowser/CServerInfo.cpp:310 -msgid "PLEASE ENTER SERVER PASSWORD" +#: Client/loader/MainFunctions.cpp:819 +#, c-format +msgid "Load failed. Please ensure that %s is installed correctly." msgstr "" -#. The server has timed out -#: Client/core/ServerBrowser/CServerInfo.cpp:402 -msgid "Timed Out" +#: Client/loader/MainFunctions.cpp:826 +#, c-format +msgid "Load failed. Could not find gta_sa.exe in %s." msgstr "" -#. Set every GUI elements text to blank -#: Client/core/ServerBrowser/CServerInfo.cpp:431 -msgid "Querying..." +#: Client/loader/MainFunctions.cpp:836 +#, c-format +msgid "" +"Load failed. %s exists in the GTA directory. Please delete before continuing." msgstr "" -#. Create the window -#: Client/core/ServerBrowser/CServerBrowser.cpp:85 -msgid "SERVER BROWSER" +#: Client/loader/MainFunctions.cpp:845 +#, c-format +msgid "Main file has an incorrect name (%s)" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:134 -msgid "Local" +#: Client/loader/MainFunctions.cpp:856 +msgid "" +"Main file is unsigned. Possible virus activity.\n" +"\n" +"See online help if MTA does not work correctly." msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:135 -msgid "Favourites" +#: Client/loader/MainFunctions.cpp:882 +#, c-format +msgid "" +"Data file %s is missing. Possible virus activity.\n" +"\n" +"Consider reinstalling Multi Theft Auto for your security.\n" +"See online help if MTA does not work correctly." msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:136 -msgid "Recent" +#: Client/loader/MainFunctions.cpp:893 +#, c-format +msgid "" +"Data file %s is modified. Possible virus activity.\n" +"\n" +"Consider reinstalling Multi Theft Auto for your security.\n" +"See online help if MTA does not work correctly." msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:191 +#: Client/loader/MainFunctions.cpp:907 msgid "" -"FOR QUICK CONNECT:\n" +".asi files are in the 'MTA:SA' or 'GTA: San Andreas' installation " +"directory.\n" "\n" -"Type the address and port into the address bar.\n" -"Or select a server from the history list and press 'Connect'" +"Remove these .asi files if you experience problems with MTA:SA." msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:203 -msgid "HELP" +#: Client/loader/MainFunctions.cpp:1009 +msgid "" +"File version mismatch error. Reinstall MTA:SA if you experience problems.\n" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:212 -#: Client/core/ServerBrowser/CServerBrowser.cpp:252 -msgid "Refresh" +#: Client/loader/MainFunctions.cpp:1018 +msgid "Some files are missing. Reinstall MTA:SA if you experience problems.\n" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:212 -#: Client/core/ServerBrowser/CServerBrowser.cpp:253 -msgid "Add Favorite" +#: Client/loader/MainFunctions.cpp:1030 +msgid "" +"MTA:SA is not compatible with Windows 'Safe Mode'.\n" +"\n" +"Please restart your PC.\n" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:212 -#: Client/core/ServerBrowser/CServerBrowser.cpp:254 -#: Client/core/ServerBrowser/CServerBrowser.cpp:301 -#: Client/core/ServerBrowser/CServerBrowser.cpp:372 -msgid "Connect" +#: Client/loader/MainFunctions.cpp:1123 +msgid "Fix configuration issue" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:212 -#: Client/core/ServerBrowser/CServerBrowser.cpp:255 -msgid "Server information" +#. Try to relaunch as admin if not done so already +#: Client/loader/MainFunctions.cpp:1157 +msgid "Fix elevation required error" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:213 -#: Client/core/ServerBrowser/CServerBrowser.cpp:256 -msgid "Search servers" +#: Client/loader/MainFunctions.cpp:1164 +#, c-format +msgid "" +"Could not start Grand Theft Auto: San Andreas. Please try restarting, or if " +"the problem persists,contact MTA at www.multitheftauto.com. \n" +"\n" +"[%s]" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:213 -#: Client/core/ServerBrowser/CServerBrowser.cpp:257 -msgid "Search players" +#: Client/loader/MainFunctions.cpp:1219 +msgid "" +"GTA: San Andreas may not have launched correctly. Do you want to terminate " +"it?" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:213 -#: Client/core/ServerBrowser/CServerBrowser.cpp:258 -msgid "Start search" +#: Client/loader/CInstallManager.cpp:376 +#, c-format +msgid "" +"MTA:SA could not complete the following task:\n" +"\n" +" '%s'\n" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:299 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1697 -msgid "Search players..." +#: Client/loader/CInstallManager.cpp:426 +msgid "" +"** The crash was caused by a graphics driver error **\n" +"\n" +"** Please update your graphics drivers **" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:422 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1695 -msgid "Search servers..." +#: Client/loader/CInstallManager.cpp:532 +msgid "Install updated MTA:SA files" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:453 -msgid "Name" +#: Client/loader/CInstallManager.cpp:552 +msgid "" +"Could not update due to file conflicts. Please close other applications and " +"retry" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:454 -msgid "Players" +#: Client/loader/CInstallManager.cpp:561 +#, c-format +msgid "Multi Theft Auto has not been installed properly, please reinstall. %s" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:455 -msgid "Ping" +#: Client/loader/CInstallManager.cpp:613 +msgid "Create GTA:SA junctions" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:456 -msgid "Gamemode" +#: Client/loader/CInstallManager.cpp:657 +msgid "MTA:SA cannot launch because copying a file failed:" msgstr "" -#. Include label -#: Client/core/ServerBrowser/CServerBrowser.cpp:486 -msgid "Include:" +#: Client/loader/CInstallManager.cpp:663 Client/loader/CInstallManager.cpp:703 +msgid "MTA:SA cannot launch because an MTA:SA file is incorrect or missing:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:492 -msgid "Empty" +#: Client/loader/CInstallManager.cpp:672 +msgid "Copy MTA:SA files" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:498 -msgid "Full" +#: Client/loader/CInstallManager.cpp:695 Client/loader/CInstallManager.cpp:773 +msgid "MTA:SA cannot launch because a GTA:SA file is incorrect or missing:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:504 -msgid "Locked" +#: Client/loader/CInstallManager.cpp:780 +msgid "Patch GTA:SA dependency" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:516 -msgid "Offline" +#: Client/loader/CInstallManager.cpp:828 +msgid "" +"MTA:SA cannot launch because the GTA:SA executable is incorrect or missing:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:529 -msgid "Other Versions" +#: Client/loader/CInstallManager.cpp:832 +msgid "" +"Please check your anti-virus for a false-positive detection, try to add an " +"exception for the GTA:SA executable and restart MTA:SA." msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:550 -msgid "Back" +#: Client/loader/CInstallManager.cpp:838 +msgid "Generate GTA:SA" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:741 -msgid "Loading..." +#: Client/loader/CInstallManager.cpp:853 +msgid "MTA:SA cannot launch because the GTA:SA executable is not loadable:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:1240 -#: Client/core/ServerBrowser/CServerBrowser.cpp:2182 -msgid " ..loading.." +#: Client/loader/CInstallManager.cpp:860 Client/loader/CInstallManager.cpp:883 +msgid "Patch GTA:SA" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:1278 -#: Client/core/ServerBrowser/CServerBrowser.cpp:1406 -msgid "No address specified!" +#: Client/loader/CInstallManager.cpp:876 +msgid "MTA:SA cannot launch because patching GTA:SA has failed:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:1291 -msgid "Unknown protocol" +#: Client/loader/CInstallManager.cpp:1113 +msgid "Missing file:" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:1291 -msgid "Please use the mtasa:// protocol!" +#: Client/loader/CInstallManager.cpp:1117 +msgid "If MTA fails to load, please re-install GTA:SA" msgstr "" -#: Client/core/ServerBrowser/CServerBrowser.cpp:1380 -msgid "You have to select a server to connect to." +#: Client/loader/CInstallManager.cpp:1152 +msgid "Update install settings" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:25 -msgid "Idle" +#: Client/loader/CInstallManager.cpp:1291 +msgid "Update compatibility settings" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:150 -msgid "player" -msgid_plural "players" -msgstr[0] "" -msgstr[1] "" - -#: Client/core/ServerBrowser/CServerList.cpp:151 -msgid "on" +#: Client/loader/Install.cpp:265 +msgid "Unknown" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:154 -msgid "server" -msgid_plural "servers" -msgstr[0] "" -msgstr[1] "" +#: Client/loader/Install.cpp:272 +#, c-format +msgid "" +"The file '%s' is currently locked by %zu processes.\n" +"\n" +"Do you want to terminate the following processes and continue updating?\n" +"\n" +"%s" +msgstr "" -#. We are polling for the master server list (first pass) -#: Client/core/ServerBrowser/CServerList.cpp:238 +#: Client/loader/Install.cpp:479 #, c-format -msgid "Requesting master server list (%lu ms elapsed)" +msgid "" +"Your installation may be corrupt now.\n" +"\n" +"%zu out of %zu files could not be restored from the backup.\n" +"\n" +"You should reinstall Multi Theft Auto from www.multitheftauto.com\n" +"or try running the update with administrator rights." msgstr "" -#. Abort -#: Client/core/ServerBrowser/CServerList.cpp:254 -msgid "Master server list could not be parsed." +#. Couldn't create render target for CPostEffects +#: Client/multiplayer_sa/CMultiplayerSA_CrashFixHacks.cpp:1360 +msgid "Problem with graphics driver" msgstr "" -#. Abort -#: Client/core/ServerBrowser/CServerList.cpp:264 -msgid "Master server list could not be retrieved." +#: Client/cefweb/CWebsiteRequests.cpp:19 +msgid "Website requests" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:274 -msgid "(Backup server list)" +#: Client/cefweb/CWebsiteRequests.cpp:27 +msgid "" +"The server requests the following websites in order to load them (later):" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:326 -msgid "Cannot bind LAN-broadcast socket" +#: Client/cefweb/CWebsiteRequests.cpp:33 +msgid "NEVER ENTER SENSITIVE DATA TO PROTECT THEM FROM BEING STOLEN" msgstr "" -#: Client/core/ServerBrowser/CServerList.cpp:345 -msgid "Attempting to discover LAN servers" +#: Client/cefweb/CWebsiteRequests.cpp:46 +msgid "Remember decision" +msgstr "" + +#: Client/cefweb/CWebsiteRequests.cpp:57 +msgid "Deny" msgstr "" #. Populate the message and show the box From 2043acfdb210a8f1158501e2fbb431b625bbf74d Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 21 Jun 2024 05:19:42 +0700 Subject: [PATCH 03/23] Generic exception type for argument parser instead of std::invalid_argument (#3493) --- Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h index 686a855deb..8861ef6ef3 100644 --- a/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h +++ b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h @@ -727,7 +727,7 @@ struct CLuaFunctionParser : CLuaFunctionP { iResult = Call(L); } - catch (std::invalid_argument& e) + catch (std::logic_error& e) { // This exception can be thrown from the called function // as an additional way to provide further argument errors From af4f7facca73bb68238437e6eff3504bd6f1cfe0 Mon Sep 17 00:00:00 2001 From: Prox <77501848+Proxy-99@users.noreply.github.com> Date: Fri, 21 Jun 2024 01:23:31 +0300 Subject: [PATCH 04/23] Fix onVehicleExit doesn't trigger if pulled out (#3492) --- Server/mods/deathmatch/logic/CGame.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index a965d160e5..75fc4aaae6 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -3659,6 +3659,7 @@ void CGame::Packet_Vehicle_InOut(CVehicleInOutPacket& Packet) if (pPed->GetVehicleAction() == CPed::VEHICLEACTION_JACKING) { unsigned char ucDoor = Packet.GetDoor(); + unsigned char ucOccupiedSeat = pPed->GetOccupiedVehicleSeat(); float fAngle = Packet.GetDoorAngle(); CPed* pJacked = pVehicle->GetOccupant(0); @@ -3692,6 +3693,29 @@ void CGame::Packet_Vehicle_InOut(CVehicleInOutPacket& Packet) CVehicleInOutPacket JackedReply(pJacked->GetID(), VehicleID, 0, VEHICLE_NOTIFY_OUT_RETURN); m_pPlayerManager->BroadcastOnlyJoined(JackedReply); + CLuaArguments Arguments; + Arguments.PushElement(pVehicle); // vehicle + Arguments.PushNumber(ucOccupiedSeat); // seat + Arguments.PushElement(pPed); // jacker + Arguments.PushBoolean(false); // forcedByScript + + if (pJacked->IsPlayer()) + { + pJacked->CallEvent("onPlayerVehicleExit", Arguments); + } + else + { + pJacked->CallEvent("onPedVehicleExit", Arguments); + } + + CLuaArguments Arguments2; + Arguments2.PushElement(pJacked); // jacked + Arguments2.PushNumber(ucOccupiedSeat); // seat + Arguments2.PushElement(pPed); // jacker + Arguments2.PushBoolean(false); // forcedByScript + + pVehicle->CallEvent("onVehicleExit", Arguments2); + if (!sendListIncompatiblePlayers.empty()) { // Warp the ped out of the vehicle manually for incompatible players From c2b75c10bd98302b164bbbc3adb8599eb1a966cc Mon Sep 17 00:00:00 2001 From: TEDERIs Date: Fri, 21 Jun 2024 05:24:59 +0700 Subject: [PATCH 05/23] Postfx stage fix (#3478) Fixes https://github.com/multitheftauto/mtasa-blue/issues/3457 --- Client/core/CCore.cpp | 29 +++++++++----------- Client/core/CCore.h | 2 ++ Client/mods/deathmatch/logic/CClientGame.cpp | 6 ++++ Client/mods/deathmatch/logic/CClientGame.h | 1 + Client/multiplayer_sa/CMultiplayerSA.cpp | 29 ++++++++++++++++++++ Client/multiplayer_sa/CMultiplayerSA.h | 1 + Client/sdk/core/CCoreInterface.h | 2 ++ Client/sdk/multiplayer/CMultiplayer.h | 2 ++ 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index 4fbea21a47..849eee0afc 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -1787,6 +1787,19 @@ void CCore::UpdateRecentlyPlayed() CCore::GetSingleton().SaveConfig(); } +void CCore::OnPostColorFilterRender() +{ + if (!CGraphics::GetSingleton().HasLine3DPostFXQueueItems() && !CGraphics::GetSingleton().HasPrimitive3DPostFXQueueItems()) + return; + + CGraphics::GetSingleton().EnteringMTARenderZone(); + + CGraphics::GetSingleton().DrawPrimitive3DPostFXQueue(); + CGraphics::GetSingleton().DrawLine3DPostFXQueue(); + + CGraphics::GetSingleton().LeavingMTARenderZone(); +} + void CCore::ApplyCoreInitSettings() { #if (_WIN32_WINNT >= _WIN32_WINNT_LONGHORN) // Windows Vista @@ -2010,22 +2023,6 @@ void CCore::OnPreFxRender() // void CCore::OnPreHUDRender() { - IDirect3DDevice9* pDevice = CGraphics::GetSingleton().GetDevice(); - - if (CGraphics::GetSingleton().HasLine3DPostFXQueueItems() || CGraphics::GetSingleton().HasPrimitive3DPostFXQueueItems()) - { - /* - Although MTA render zones are expensive, we should use them twice in the bounds of the function - because some of render states from PostFX drain to the 2D part of the frame. - */ - CGraphics::GetSingleton().EnteringMTARenderZone(); - - CGraphics::GetSingleton().DrawPrimitive3DPostFXQueue(); - CGraphics::GetSingleton().DrawLine3DPostFXQueue(); - - CGraphics::GetSingleton().LeavingMTARenderZone(); - } - CGraphics::GetSingleton().EnteringMTARenderZone(); // Maybe capture screen and other stuff diff --git a/Client/core/CCore.h b/Client/core/CCore.h index fa7b418f61..55460a6f4f 100644 --- a/Client/core/CCore.h +++ b/Client/core/CCore.h @@ -289,6 +289,8 @@ class CCore : public CCoreInterface, public CSingleton const SString& GetLastConnectedServerName() const { return m_strLastConnectedServerName; } void SetLastConnectedServerName(const SString& strServerName) { m_strLastConnectedServerName = strServerName; } + void OnPostColorFilterRender() override; + private: void ApplyCoreInitSettings(); diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index aef97392a5..0b9560f0a9 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -271,6 +271,7 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) g_pMultiplayer->SetPostWorldProcessHandler(CClientGame::StaticPostWorldProcessHandler); g_pMultiplayer->SetPostWorldProcessPedsAfterPreRenderHandler(CClientGame::StaticPostWorldProcessPedsAfterPreRenderHandler); g_pMultiplayer->SetPreFxRenderHandler(CClientGame::StaticPreFxRenderHandler); + g_pMultiplayer->SetPostColorFilterRenderHandler(CClientGame::StaticPostColorFilterRenderHandler); g_pMultiplayer->SetPreHudRenderHandler(CClientGame::StaticPreHudRenderHandler); g_pMultiplayer->DisableCallsToCAnimBlendNode(false); g_pMultiplayer->SetCAnimBlendAssocDestructorHandler(CClientGame::StaticCAnimBlendAssocDestructorHandler); @@ -3607,6 +3608,11 @@ void CClientGame::StaticPreFxRenderHandler() g_pCore->OnPreFxRender(); } +void CClientGame::StaticPostColorFilterRenderHandler() +{ + g_pCore->OnPostColorFilterRender(); +} + void CClientGame::StaticPreHudRenderHandler() { g_pCore->OnPreHUDRender(); diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index 96d82c37a7..82662f836c 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -511,6 +511,7 @@ class CClientGame static void StaticPostWorldProcessHandler(); static void StaticPostWorldProcessPedsAfterPreRenderHandler(); static void StaticPreFxRenderHandler(); + static void StaticPostColorFilterRenderHandler(); static void StaticPreHudRenderHandler(); static void StaticCAnimBlendAssocDestructorHandler(CAnimBlendAssociationSAInterface* pThis); static CAnimBlendAssociationSAInterface* StaticAddAnimationHandler(RpClump* pClump, AssocGroupId animGroup, AnimationId animID); diff --git a/Client/multiplayer_sa/CMultiplayerSA.cpp b/Client/multiplayer_sa/CMultiplayerSA.cpp index ad8f6eb576..d9881758ec 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA.cpp @@ -198,6 +198,9 @@ DWORD RETURN_ProcessEntityCollision = 0x4185C0; #define HOOKPOS_PreFxRender 0x049E650 DWORD RETURN_PreFxRender = 0x0404D1E; +#define HOOKPOS_PostColorFilterRender 0x705099 +DWORD RETURN_PostColorFilterRender = 0x70509E; + #define HOOKPOS_PreHUDRender 0x053EAD8 DWORD RETURN_PreHUDRender = 0x053EADD; @@ -377,6 +380,7 @@ PostWorldProcessHandler* m_pPostWorldProcessHandler = NULL; PostWorldProcessPedsAfterPreRenderHandler* m_postWorldProcessPedsAfterPreRenderHandler = nullptr; IdleHandler* m_pIdleHandler = NULL; PreFxRenderHandler* m_pPreFxRenderHandler = NULL; +PostColorFilterRenderHandler* m_pPostColorFilterRenderHandler = nullptr; PreHudRenderHandler* m_pPreHudRenderHandler = NULL; ProcessCollisionHandler* m_pProcessCollisionHandler = NULL; HeliKillHandler* m_pHeliKillHandler = NULL; @@ -479,6 +483,7 @@ void HOOK_Transmission_CalculateDriveAcceleration(); void HOOK_isVehDriveTypeNotRWD(); void HOOK_isVehDriveTypeNotFWD(); void HOOK_PreFxRender(); +void HOOK_PostColorFilterRender(); void HOOK_PreHUDRender(); void HOOK_CTrafficLights_GetPrimaryLightState(); @@ -657,6 +662,7 @@ void CMultiplayerSA::InitHooks() HookInstall(HOOKPOS_VehColCB, (DWORD)HOOK_VehColCB, 29); HookInstall(HOOKPOS_VehCol, (DWORD)HOOK_VehCol, 9); HookInstall(HOOKPOS_PreFxRender, (DWORD)HOOK_PreFxRender, 5); + HookInstall(HOOKPOS_PostColorFilterRender, (DWORD)HOOK_PostColorFilterRender, 5); HookInstall(HOOKPOS_PreHUDRender, (DWORD)HOOK_PreHUDRender, 5); HookInstall(HOOKPOS_CAutomobile__ProcessSwingingDoor, (DWORD)HOOK_CAutomobile__ProcessSwingingDoor, 7); @@ -2315,6 +2321,11 @@ void CMultiplayerSA::SetPreFxRenderHandler(PreFxRenderHandler* pHandler) m_pPreFxRenderHandler = pHandler; } +void CMultiplayerSA::SetPostColorFilterRenderHandler(PostColorFilterRenderHandler* pHandler) +{ + m_pPostColorFilterRenderHandler = pHandler; +} + void CMultiplayerSA::SetPreHudRenderHandler(PreHudRenderHandler* pHandler) { m_pPreHudRenderHandler = pHandler; @@ -4780,6 +4791,24 @@ void _declspec(naked) HOOK_PreFxRender() } } +// Hooked from 00705099 5 bytes +void _declspec(naked) HOOK_PostColorFilterRender() +{ + _asm + { + pushad + } + + if (m_pPostColorFilterRenderHandler) m_pPostColorFilterRenderHandler(); + + _asm + { + popad + mov al, ds:0C402BAh + jmp RETURN_PostColorFilterRender // 0070509E + } +} + // Hooked from 0053EAD8 5 bytes void _declspec(naked) HOOK_PreHUDRender() { diff --git a/Client/multiplayer_sa/CMultiplayerSA.h b/Client/multiplayer_sa/CMultiplayerSA.h index fd81a18828..12daeb26be 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.h +++ b/Client/multiplayer_sa/CMultiplayerSA.h @@ -115,6 +115,7 @@ class CMultiplayerSA : public CMultiplayer void SetPostWorldProcessPedsAfterPreRenderHandler(PostWorldProcessPedsAfterPreRenderHandler* pHandler); void SetIdleHandler(IdleHandler* pHandler); void SetPreFxRenderHandler(PreFxRenderHandler* pHandler); + void SetPostColorFilterRenderHandler(PostColorFilterRenderHandler* pHandler) override; void SetPreHudRenderHandler(PreHudRenderHandler* pHandler); void DisableCallsToCAnimBlendNode(bool bDisableCalls); void SetCAnimBlendAssocDestructorHandler(CAnimBlendAssocDestructorHandler* pHandler); diff --git a/Client/sdk/core/CCoreInterface.h b/Client/sdk/core/CCoreInterface.h index 25c578a25a..aea1ca9054 100644 --- a/Client/sdk/core/CCoreInterface.h +++ b/Client/sdk/core/CCoreInterface.h @@ -192,6 +192,8 @@ class CCoreInterface virtual const SString& GetLastConnectedServerName() const = 0; virtual void SetLastConnectedServerName(const SString& strServerName) = 0; + + virtual void OnPostColorFilterRender() = 0; }; class CClientTime diff --git a/Client/sdk/multiplayer/CMultiplayer.h b/Client/sdk/multiplayer/CMultiplayer.h index 23c6f2ac15..48f1f3246c 100644 --- a/Client/sdk/multiplayer/CMultiplayer.h +++ b/Client/sdk/multiplayer/CMultiplayer.h @@ -102,6 +102,7 @@ typedef void(PostWorldProcessHandler)(); typedef void(PostWorldProcessPedsAfterPreRenderHandler)(); typedef void(IdleHandler)(); typedef void(PreFxRenderHandler)(); +typedef void(PostColorFilterRenderHandler)(); typedef void(PreHudRenderHandler)(); typedef CAnimBlendAssociationSAInterface*(AddAnimationHandler)(RpClump* pClump, AssocGroupId animGroup, AnimationId animID); typedef CAnimBlendAssociationSAInterface*(AddAnimationAndSyncHandler)(RpClump* pClump, CAnimBlendAssociationSAInterface* pAnimAssocToSyncWith, @@ -231,6 +232,7 @@ class CMultiplayer virtual void SetPostWorldProcessPedsAfterPreRenderHandler(PostWorldProcessPedsAfterPreRenderHandler* pHandler) = 0; virtual void SetIdleHandler(IdleHandler* pHandler) = 0; virtual void SetPreFxRenderHandler(PreFxRenderHandler* pHandler) = 0; + virtual void SetPostColorFilterRenderHandler(PostColorFilterRenderHandler* pHandler) = 0; virtual void SetPreHudRenderHandler(PreHudRenderHandler* pHandler) = 0; virtual void DisableCallsToCAnimBlendNode(bool bDisableCalls) = 0; virtual void SetCAnimBlendAssocDestructorHandler(CAnimBlendAssocDestructorHandler* pHandler) = 0; From 5e7bd47328633826436e67d78d5a4dbac155601c Mon Sep 17 00:00:00 2001 From: Pot Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 22:30:57 +0000 Subject: [PATCH 06/23] Update client en_US pot [ci skip] --- .../MTA/locale/en_US/client.pot | 146 +++++++++--------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot index 57c5cea0ed..6d1a453ada 100644 --- a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot +++ b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: MTA San Andreas 1.x\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-20 22:03+0000\n" +"POT-Creation-Date: 2024-06-20 22:30+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -93,17 +93,17 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1406 #: Client/core/DXHook/CDirect3DHook9.cpp:127 #: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:145 -#: Client/mods/deathmatch/logic/CClientGame.cpp:636 -#: Client/mods/deathmatch/logic/CClientGame.cpp:710 -#: Client/mods/deathmatch/logic/CClientGame.cpp:734 -#: Client/mods/deathmatch/logic/CClientGame.cpp:756 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1172 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1252 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1262 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1331 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1368 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1417 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1429 +#: Client/mods/deathmatch/logic/CClientGame.cpp:637 +#: Client/mods/deathmatch/logic/CClientGame.cpp:711 +#: Client/mods/deathmatch/logic/CClientGame.cpp:735 +#: Client/mods/deathmatch/logic/CClientGame.cpp:757 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1173 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1253 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1263 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1332 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1369 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1418 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1430 #: Client/loader/MainFunctions.cpp:252 Client/loader/MainFunctions.cpp:267 #: Client/loader/MainFunctions.cpp:269 Client/loader/MainFunctions.cpp:846 #: Client/loader/CInstallManager.cpp:552 Client/loader/CInstallManager.cpp:561 @@ -1176,12 +1176,12 @@ msgstr "" #: Client/core/CSettings.cpp:3479 Client/core/CCore.cpp:674 #: Client/core/CMainMenu.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:528 +#: Client/mods/deathmatch/logic/CClientGame.cpp:529 msgid "Main menu" msgstr "" #: Client/core/CSettings.cpp:3483 Client/core/CCore.cpp:674 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1084 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1085 #: Client/mods/deathmatch/logic/CResource.cpp:372 msgid "In-game" msgstr "" @@ -1387,47 +1387,47 @@ msgstr "" #. Display the status box #: Client/core/CConnectManager.cpp:148 -#: Client/mods/deathmatch/logic/CClientGame.cpp:652 +#: Client/mods/deathmatch/logic/CClientGame.cpp:653 msgid "CONNECTING" msgstr "" #: Client/core/CConnectManager.cpp:263 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1331 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1332 msgid "Connection timed out" msgstr "" #: Client/core/CConnectManager.cpp:277 Client/core/CConnectManager.cpp:281 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1379 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1380 msgid "Disconnected: unknown protocol error" msgstr "" #: Client/core/CConnectManager.cpp:285 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1383 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1384 msgid "Disconnected: disconnected remotely" msgstr "" #: Client/core/CConnectManager.cpp:289 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1387 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1388 msgid "Disconnected: connection lost remotely" msgstr "" #: Client/core/CConnectManager.cpp:293 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1391 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1392 msgid "Disconnected: you are banned from this server" msgstr "" #: Client/core/CConnectManager.cpp:300 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1399 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1400 msgid "Disconnected: disconnected from the server" msgstr "" #: Client/core/CConnectManager.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1403 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1404 msgid "Disconnected: connection to the server was lost" msgstr "" #: Client/core/CConnectManager.cpp:311 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1411 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1412 msgid "Disconnected: connection was refused" msgstr "" @@ -2095,8 +2095,8 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1300 #: Client/core/ServerBrowser/CServerBrowser.cpp:1357 -#: Client/mods/deathmatch/logic/CClientGame.cpp:636 -#: Client/mods/deathmatch/logic/CClientGame.cpp:734 +#: Client/mods/deathmatch/logic/CClientGame.cpp:637 +#: Client/mods/deathmatch/logic/CClientGame.cpp:735 msgid "Invalid nickname! Please go to Settings and set a new one!" msgstr "" @@ -2449,196 +2449,196 @@ msgstr[1] "" msgid "Disconnected" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 msgid "Flying a UFO around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 msgid "Cruising around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:371 +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 msgid "Riding the waves of" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +#: Client/mods/deathmatch/logic/CClientGame.cpp:373 msgid "Riding the train in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +#: Client/mods/deathmatch/logic/CClientGame.cpp:373 msgid "Flying around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +#: Client/mods/deathmatch/logic/CClientGame.cpp:374 msgid "Riding around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +#: Client/mods/deathmatch/logic/CClientGame.cpp:374 msgid "Monster truckin' around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +#: Client/mods/deathmatch/logic/CClientGame.cpp:374 msgid "Quaddin' around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +#: Client/mods/deathmatch/logic/CClientGame.cpp:375 msgid "Bunny hopping around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +#: Client/mods/deathmatch/logic/CClientGame.cpp:375 msgid "Doing weird stuff in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:378 +#: Client/mods/deathmatch/logic/CClientGame.cpp:379 msgid "Climbing around in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:379 #: Client/mods/deathmatch/logic/CClientGame.cpp:380 +#: Client/mods/deathmatch/logic/CClientGame.cpp:381 msgid "Doing a drive-by in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:381 +#: Client/mods/deathmatch/logic/CClientGame.cpp:382 msgid "Blub blub..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:382 +#: Client/mods/deathmatch/logic/CClientGame.cpp:383 msgid "Breathing water" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:383 +#: Client/mods/deathmatch/logic/CClientGame.cpp:384 msgid "Drowning in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:384 +#: Client/mods/deathmatch/logic/CClientGame.cpp:385 msgid "Ducking for cover in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:385 +#: Client/mods/deathmatch/logic/CClientGame.cpp:386 msgid "Fighting in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:386 +#: Client/mods/deathmatch/logic/CClientGame.cpp:387 msgid "Throwing fists in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:387 +#: Client/mods/deathmatch/logic/CClientGame.cpp:388 msgid "Blastin' fools in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:388 +#: Client/mods/deathmatch/logic/CClientGame.cpp:389 msgid "Shooting up" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:389 +#: Client/mods/deathmatch/logic/CClientGame.cpp:390 msgid "Jetpacking in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:390 +#: Client/mods/deathmatch/logic/CClientGame.cpp:391 msgid "Literally on fire in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:391 +#: Client/mods/deathmatch/logic/CClientGame.cpp:392 msgid "Burning up in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:392 +#: Client/mods/deathmatch/logic/CClientGame.cpp:393 msgid "Swimming in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:393 +#: Client/mods/deathmatch/logic/CClientGame.cpp:394 msgid "Floating around in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:394 +#: Client/mods/deathmatch/logic/CClientGame.cpp:395 msgid "Being chased by a shark" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:395 +#: Client/mods/deathmatch/logic/CClientGame.cpp:396 msgid "Choking to death in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:652 +#: Client/mods/deathmatch/logic/CClientGame.cpp:653 msgid "Entering the game ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:710 +#: Client/mods/deathmatch/logic/CClientGame.cpp:711 msgid "" "Not connected; please use Quick Connect or the 'connect' command to connect " "to a server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:756 +#: Client/mods/deathmatch/logic/CClientGame.cpp:757 msgid "Could not start the local server. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:766 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 +#: Client/mods/deathmatch/logic/CClientGame.cpp:767 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1242 msgid "Local Server" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:766 +#: Client/mods/deathmatch/logic/CClientGame.cpp:767 msgid "Starting local server ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1014 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1015 msgid "Area 51" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1023 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1024 msgid "Walking around " msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1172 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1173 #, c-format msgid "You were kicked from the game ( %s )" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1241 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1242 msgid "Connecting to local server..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1252 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1253 msgid "Error connecting to server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1262 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1263 msgid "Connecting to local server timed out. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1368 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1369 msgid "Connection with the server was lost" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1395 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1396 msgid "Disconnected: the server is currently full" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1407 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1408 msgid "Disconnected: invalid password specified" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1429 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1430 msgid "MTA Client verification failed!" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 msgid "In a ditch" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 msgid "En-route to hospital" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5688 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 msgid "Meeting their maker" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 msgid "Regretting their decisions" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5689 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 msgid "Wasted" msgstr "" From a7e58e0c12eb9853f80987952b2d40eef76ed096 Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Fri, 21 Jun 2024 01:51:12 +0200 Subject: [PATCH 07/23] Fix disconnect crash --- Client/mods/deathmatch/logic/CClientGame.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 0b9560f0a9..430bd783ac 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -477,6 +477,7 @@ CClientGame::~CClientGame() g_pMultiplayer->SetPostWorldProcessHandler(NULL); g_pMultiplayer->SetPostWorldProcessPedsAfterPreRenderHandler(nullptr); g_pMultiplayer->SetPreFxRenderHandler(NULL); + g_pMultiplayer->SetPostColorFilterRenderHandler(nullptr); g_pMultiplayer->SetPreHudRenderHandler(NULL); g_pMultiplayer->DisableCallsToCAnimBlendNode(true); g_pMultiplayer->SetCAnimBlendAssocDestructorHandler(NULL); From cc172fcae7654ead0d3530a4819c71f76205a175 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 01:52:55 +0200 Subject: [PATCH 08/23] Bump ws from 8.13.0 to 8.17.1 in /utils/localization/generate-images (PR #3488) --- utils/localization/generate-images/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/localization/generate-images/package-lock.json b/utils/localization/generate-images/package-lock.json index 26fac5a614..2dadb06346 100644 --- a/utils/localization/generate-images/package-lock.json +++ b/utils/localization/generate-images/package-lock.json @@ -964,9 +964,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "engines": { "node": ">=10.0.0" }, From 23ead4869aa248115e95372d478e646e24211524 Mon Sep 17 00:00:00 2001 From: Pot Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 23:55:18 +0000 Subject: [PATCH 09/23] Update client en_US pot [ci skip] --- .../MTA/locale/en_US/client.pot | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot index 6d1a453ada..66d7bc1cdf 100644 --- a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot +++ b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: MTA San Andreas 1.x\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-20 22:30+0000\n" +"POT-Creation-Date: 2024-06-20 23:55+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -93,17 +93,17 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1406 #: Client/core/DXHook/CDirect3DHook9.cpp:127 #: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:145 -#: Client/mods/deathmatch/logic/CClientGame.cpp:637 -#: Client/mods/deathmatch/logic/CClientGame.cpp:711 -#: Client/mods/deathmatch/logic/CClientGame.cpp:735 -#: Client/mods/deathmatch/logic/CClientGame.cpp:757 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1173 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1253 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1263 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1332 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1369 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1418 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1430 +#: Client/mods/deathmatch/logic/CClientGame.cpp:638 +#: Client/mods/deathmatch/logic/CClientGame.cpp:712 +#: Client/mods/deathmatch/logic/CClientGame.cpp:736 +#: Client/mods/deathmatch/logic/CClientGame.cpp:758 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1174 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1254 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1264 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1333 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1370 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1419 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1431 #: Client/loader/MainFunctions.cpp:252 Client/loader/MainFunctions.cpp:267 #: Client/loader/MainFunctions.cpp:269 Client/loader/MainFunctions.cpp:846 #: Client/loader/CInstallManager.cpp:552 Client/loader/CInstallManager.cpp:561 @@ -1176,12 +1176,12 @@ msgstr "" #: Client/core/CSettings.cpp:3479 Client/core/CCore.cpp:674 #: Client/core/CMainMenu.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:529 +#: Client/mods/deathmatch/logic/CClientGame.cpp:530 msgid "Main menu" msgstr "" #: Client/core/CSettings.cpp:3483 Client/core/CCore.cpp:674 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1085 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1086 #: Client/mods/deathmatch/logic/CResource.cpp:372 msgid "In-game" msgstr "" @@ -1387,47 +1387,47 @@ msgstr "" #. Display the status box #: Client/core/CConnectManager.cpp:148 -#: Client/mods/deathmatch/logic/CClientGame.cpp:653 +#: Client/mods/deathmatch/logic/CClientGame.cpp:654 msgid "CONNECTING" msgstr "" #: Client/core/CConnectManager.cpp:263 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1332 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1333 msgid "Connection timed out" msgstr "" #: Client/core/CConnectManager.cpp:277 Client/core/CConnectManager.cpp:281 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1380 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1381 msgid "Disconnected: unknown protocol error" msgstr "" #: Client/core/CConnectManager.cpp:285 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1384 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1385 msgid "Disconnected: disconnected remotely" msgstr "" #: Client/core/CConnectManager.cpp:289 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1388 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1389 msgid "Disconnected: connection lost remotely" msgstr "" #: Client/core/CConnectManager.cpp:293 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1392 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1393 msgid "Disconnected: you are banned from this server" msgstr "" #: Client/core/CConnectManager.cpp:300 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1400 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1401 msgid "Disconnected: disconnected from the server" msgstr "" #: Client/core/CConnectManager.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1404 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1405 msgid "Disconnected: connection to the server was lost" msgstr "" #: Client/core/CConnectManager.cpp:311 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1412 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1413 msgid "Disconnected: connection was refused" msgstr "" @@ -2095,8 +2095,8 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1300 #: Client/core/ServerBrowser/CServerBrowser.cpp:1357 -#: Client/mods/deathmatch/logic/CClientGame.cpp:637 -#: Client/mods/deathmatch/logic/CClientGame.cpp:735 +#: Client/mods/deathmatch/logic/CClientGame.cpp:638 +#: Client/mods/deathmatch/logic/CClientGame.cpp:736 msgid "Invalid nickname! Please go to Settings and set a new one!" msgstr "" @@ -2558,87 +2558,87 @@ msgstr "" msgid "Choking to death in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:653 +#: Client/mods/deathmatch/logic/CClientGame.cpp:654 msgid "Entering the game ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:711 +#: Client/mods/deathmatch/logic/CClientGame.cpp:712 msgid "" "Not connected; please use Quick Connect or the 'connect' command to connect " "to a server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:757 +#: Client/mods/deathmatch/logic/CClientGame.cpp:758 msgid "Could not start the local server. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:767 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1242 +#: Client/mods/deathmatch/logic/CClientGame.cpp:768 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1243 msgid "Local Server" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:767 +#: Client/mods/deathmatch/logic/CClientGame.cpp:768 msgid "Starting local server ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1015 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1016 msgid "Area 51" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1024 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1025 msgid "Walking around " msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1173 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1174 #, c-format msgid "You were kicked from the game ( %s )" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1242 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1243 msgid "Connecting to local server..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1253 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1254 msgid "Error connecting to server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1263 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1264 msgid "Connecting to local server timed out. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1369 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1370 msgid "Connection with the server was lost" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1396 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1397 msgid "Disconnected: the server is currently full" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1408 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1409 msgid "Disconnected: invalid password specified" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1430 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1431 msgid "MTA Client verification failed!" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 msgid "In a ditch" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 msgid "En-route to hospital" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5694 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 msgid "Meeting their maker" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5696 msgid "Regretting their decisions" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5696 msgid "Wasted" msgstr "" From 93f5b4287f3d2e2f8fc0c7adcaae98a5e1d74954 Mon Sep 17 00:00:00 2001 From: Fernando Rocha <34967844+Fernando-A-Rocha@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:08:16 +0100 Subject: [PATCH 10/23] Update Windows build instructions in README (PR #3500) --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3fa1d8db7a..0173284d06 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,9 @@ Our project's code repository can be found on the [multitheftauto/mtasa-blue](ht #### Windows Prerequisites -- [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) +- [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) with: + - Desktop development with C++ + - Optional component *C++ MFC for latest v143 build tools (x86 & x64)* - [Microsoft DirectX SDK](https://wiki.multitheftauto.com/wiki/Compiling_MTASA#Microsoft_DirectX_SDK) - [Git for Windows](https://git-scm.com/download/win) (Optional) @@ -48,13 +50,15 @@ Prerequisites 3. Compile 4. Execute: `win-install-data.bat` +Visit the wiki article ["Compiling MTASA"](https://wiki.multitheftauto.com/wiki/Compiling_MTASA) for additional information and error troubleshooting. + #### GNU/Linux You can build the MTA:SA server on GNU/Linux distributions only for x86, x86_64, armhf and arm64 CPU architectures. ARM architectures are currently in **experimental phase**, which means they're unstable, untested and may crash randomly. Beware that we only officially support building from x86_64 and that includes cross-compiling for x86, arm and arm64. **Build dependencies** -*Please always read the Dockerfiles for up-to-date build dependencies.* +*Please always read the Dockerfiles for up-to-date build dependencies.* *Note: ncftp is not required for building the MTA:SA server.* - git From 631de243d569f81e89e61ce6dcf8d527da3252ae Mon Sep 17 00:00:00 2001 From: Dutchman101 <12105539+Dutchman101@users.noreply.github.com> Date: Fri, 21 Jun 2024 16:43:16 +0000 Subject: [PATCH 11/23] Update CEF to 126.2.6+gc7c4ac9+chromium-126.0.6478.115 --- utils/buildactions/install_cef.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/buildactions/install_cef.lua b/utils/buildactions/install_cef.lua index 1f520c2290..906de66a89 100644 --- a/utils/buildactions/install_cef.lua +++ b/utils/buildactions/install_cef.lua @@ -9,8 +9,8 @@ local CEF_URL_PREFIX = "https://cef-builds.spotifycdn.com/cef_binary_" local CEF_URL_SUFFIX = "_windows32_minimal.tar.bz2" -- Change here to update CEF version -local CEF_VERSION = "126.2.4+g5e718e0+chromium-126.0.6478.62" -local CEF_HASH = "59c00bc49a600674643d09af717ccd91eca2458310c94ab22b56db80bbca4928" +local CEF_VERSION = "126.2.6+gc7c4ac9+chromium-126.0.6478.115" +local CEF_HASH = "e8392f2abc7d392a104fcb10bbd35ca7ddc1353ce5957c92bddcef3acd91f09c" function make_cef_download_url() return CEF_URL_PREFIX..http.escapeUrlParam(CEF_VERSION)..CEF_URL_SUFFIX From 2e50c6c6e51785ef60df1deea2b496fef182cf62 Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Fri, 21 Jun 2024 19:17:47 +0200 Subject: [PATCH 12/23] Update jpeg from 9e to 9f --- Client/core/premake5.lua | 2 +- premake5.lua | 2 +- vendor/{jpeg-9e => jpeg-9f}/cderror.h | 0 vendor/{jpeg-9e => jpeg-9f}/cdjpeg.c | 0 vendor/{jpeg-9e => jpeg-9f}/cdjpeg.h | 0 vendor/{jpeg-9e => jpeg-9f}/cjpeg.c | 0 vendor/jpeg-9f/cjpegalt.c | 791 +++++++++++++++++++++++ vendor/{jpeg-9e => jpeg-9f}/ckconfig.c | 0 vendor/{jpeg-9e => jpeg-9f}/djpeg.c | 0 vendor/jpeg-9f/djpegalt.c | 766 ++++++++++++++++++++++ vendor/{jpeg-9e => jpeg-9f}/example.c | 0 vendor/{jpeg-9e => jpeg-9f}/jaricom.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcapimin.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcapistd.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcarith.c | 0 vendor/{jpeg-9e => jpeg-9f}/jccoefct.c | 8 +- vendor/{jpeg-9e => jpeg-9f}/jccolor.c | 35 +- vendor/{jpeg-9e => jpeg-9f}/jcdctmgr.c | 0 vendor/{jpeg-9e => jpeg-9f}/jchuff.c | 272 ++++---- vendor/{jpeg-9e => jpeg-9f}/jcinit.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcmainct.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcmarker.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcmaster.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcomapi.c | 0 vendor/{jpeg-9e => jpeg-9f}/jconfig.h | 0 vendor/{jpeg-9e => jpeg-9f}/jcparam.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcprepct.c | 0 vendor/{jpeg-9e => jpeg-9f}/jcsample.c | 0 vendor/{jpeg-9e => jpeg-9f}/jctrans.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdapimin.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdapistd.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdarith.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdatadst.c | 16 +- vendor/{jpeg-9e => jpeg-9f}/jdatasrc.c | 23 +- vendor/{jpeg-9e => jpeg-9f}/jdcoefct.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdcolor.c | 93 ++- vendor/{jpeg-9e => jpeg-9f}/jdct.h | 4 +- vendor/{jpeg-9e => jpeg-9f}/jddctmgr.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdhuff.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdinput.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdmainct.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdmarker.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdmaster.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdmerge.c | 31 +- vendor/{jpeg-9e => jpeg-9f}/jdpostct.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdsample.c | 0 vendor/{jpeg-9e => jpeg-9f}/jdtrans.c | 0 vendor/{jpeg-9e => jpeg-9f}/jerror.c | 0 vendor/{jpeg-9e => jpeg-9f}/jerror.h | 0 vendor/{jpeg-9e => jpeg-9f}/jfdctflt.c | 0 vendor/{jpeg-9e => jpeg-9f}/jfdctfst.c | 0 vendor/{jpeg-9e => jpeg-9f}/jfdctint.c | 0 vendor/{jpeg-9e => jpeg-9f}/jidctflt.c | 0 vendor/{jpeg-9e => jpeg-9f}/jidctfst.c | 0 vendor/{jpeg-9e => jpeg-9f}/jidctint.c | 0 vendor/{jpeg-9e => jpeg-9f}/jinclude.h | 66 +- vendor/{jpeg-9e => jpeg-9f}/jmemansi.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemdos.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemmac.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemmgr.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemname.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemnobs.c | 0 vendor/{jpeg-9e => jpeg-9f}/jmemsys.h | 0 vendor/{jpeg-9e => jpeg-9f}/jmorecfg.h | 31 +- vendor/{jpeg-9e => jpeg-9f}/jpegint.h | 0 vendor/{jpeg-9e => jpeg-9f}/jpeglib.h | 4 +- vendor/{jpeg-9e => jpeg-9f}/jpegtran.c | 0 vendor/{jpeg-9e => jpeg-9f}/jquant1.c | 0 vendor/{jpeg-9e => jpeg-9f}/jquant2.c | 0 vendor/{jpeg-9e => jpeg-9f}/jutils.c | 0 vendor/{jpeg-9e => jpeg-9f}/jversion.h | 6 +- vendor/{jpeg-9e => jpeg-9f}/premake5.lua | 0 vendor/{jpeg-9e => jpeg-9f}/rdbmp.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdcolmap.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdgif.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdjpgcom.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdppm.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdrle.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdswitch.c | 0 vendor/{jpeg-9e => jpeg-9f}/rdtarga.c | 0 vendor/{jpeg-9e => jpeg-9f}/transupp.c | 37 +- vendor/{jpeg-9e => jpeg-9f}/transupp.h | 0 vendor/{jpeg-9e => jpeg-9f}/wrbmp.c | 0 vendor/{jpeg-9e => jpeg-9f}/wrgif.c | 0 vendor/{jpeg-9e => jpeg-9f}/wrjpgcom.c | 0 vendor/{jpeg-9e => jpeg-9f}/wrppm.c | 0 vendor/{jpeg-9e => jpeg-9f}/wrrle.c | 0 vendor/{jpeg-9e => jpeg-9f}/wrtarga.c | 0 88 files changed, 1905 insertions(+), 282 deletions(-) rename vendor/{jpeg-9e => jpeg-9f}/cderror.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/cdjpeg.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/cdjpeg.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/cjpeg.c (100%) create mode 100644 vendor/jpeg-9f/cjpegalt.c rename vendor/{jpeg-9e => jpeg-9f}/ckconfig.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/djpeg.c (100%) create mode 100644 vendor/jpeg-9f/djpegalt.c rename vendor/{jpeg-9e => jpeg-9f}/example.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jaricom.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcapimin.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcapistd.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcarith.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jccoefct.c (98%) rename vendor/{jpeg-9e => jpeg-9f}/jccolor.c (95%) rename vendor/{jpeg-9e => jpeg-9f}/jcdctmgr.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jchuff.c (89%) rename vendor/{jpeg-9e => jpeg-9f}/jcinit.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcmainct.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcmarker.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcmaster.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcomapi.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jconfig.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcparam.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcprepct.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jcsample.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jctrans.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdapimin.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdapistd.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdarith.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdatadst.c (95%) rename vendor/{jpeg-9e => jpeg-9f}/jdatasrc.c (92%) rename vendor/{jpeg-9e => jpeg-9f}/jdcoefct.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdcolor.c (91%) rename vendor/{jpeg-9e => jpeg-9f}/jdct.h (99%) rename vendor/{jpeg-9e => jpeg-9f}/jddctmgr.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdhuff.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdinput.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdmainct.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdmarker.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdmaster.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdmerge.c (96%) rename vendor/{jpeg-9e => jpeg-9f}/jdpostct.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdsample.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jdtrans.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jerror.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jerror.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/jfdctflt.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jfdctfst.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jfdctint.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jidctflt.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jidctfst.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jidctint.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jinclude.h (57%) rename vendor/{jpeg-9e => jpeg-9f}/jmemansi.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemdos.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemmac.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemmgr.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemname.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemnobs.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmemsys.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/jmorecfg.h (94%) rename vendor/{jpeg-9e => jpeg-9f}/jpegint.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/jpeglib.h (99%) rename vendor/{jpeg-9e => jpeg-9f}/jpegtran.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jquant1.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jquant2.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jutils.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/jversion.h (59%) rename vendor/{jpeg-9e => jpeg-9f}/premake5.lua (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdbmp.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdcolmap.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdgif.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdjpgcom.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdppm.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdrle.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdswitch.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/rdtarga.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/transupp.c (99%) rename vendor/{jpeg-9e => jpeg-9f}/transupp.h (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrbmp.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrgif.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrjpgcom.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrppm.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrrle.c (100%) rename vendor/{jpeg-9e => jpeg-9f}/wrtarga.c (100%) diff --git a/Client/core/premake5.lua b/Client/core/premake5.lua index 971e757271..0573dd6c05 100644 --- a/Client/core/premake5.lua +++ b/Client/core/premake5.lua @@ -16,7 +16,7 @@ project "Client Core" "../sdk", "../../vendor/tinygettext", "../../vendor/zlib", - "../../vendor/jpeg-9e", + "../../vendor/jpeg-9f", "../../vendor/pthreads/include", "../../vendor/sparsehash/src/", "../../vendor/detours/4.0.1/src", diff --git a/premake5.lua b/premake5.lua index 76b9e95e72..34dc2e37f4 100644 --- a/premake5.lua +++ b/premake5.lua @@ -158,7 +158,7 @@ workspace "MTASA" include "vendor/cef3" include "vendor/discord-rpc" include "vendor/freetype" - include "vendor/jpeg-9e" + include "vendor/jpeg-9f" include "vendor/ksignals" include "vendor/libpng" include "vendor/tinygettext" diff --git a/vendor/jpeg-9e/cderror.h b/vendor/jpeg-9f/cderror.h similarity index 100% rename from vendor/jpeg-9e/cderror.h rename to vendor/jpeg-9f/cderror.h diff --git a/vendor/jpeg-9e/cdjpeg.c b/vendor/jpeg-9f/cdjpeg.c similarity index 100% rename from vendor/jpeg-9e/cdjpeg.c rename to vendor/jpeg-9f/cdjpeg.c diff --git a/vendor/jpeg-9e/cdjpeg.h b/vendor/jpeg-9f/cdjpeg.h similarity index 100% rename from vendor/jpeg-9e/cdjpeg.h rename to vendor/jpeg-9f/cdjpeg.h diff --git a/vendor/jpeg-9e/cjpeg.c b/vendor/jpeg-9f/cjpeg.c similarity index 100% rename from vendor/jpeg-9e/cjpeg.c rename to vendor/jpeg-9f/cjpeg.c diff --git a/vendor/jpeg-9f/cjpegalt.c b/vendor/jpeg-9f/cjpegalt.c new file mode 100644 index 0000000000..c89827e26b --- /dev/null +++ b/vendor/jpeg-9f/cjpegalt.c @@ -0,0 +1,791 @@ +/* + * alternate cjpeg.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2009-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains an alternate user interface for the JPEG compressor. + * One or more input files are named on the command line, and output file + * names are created by substituting ".jpg" for the input file's extension. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifndef PATH_MAX /* ANSI maximum-pathname-length constant */ +#define PATH_MAX 256 +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * Automatic determination of available memory. + */ + +static long default_maxmem; /* saves value determined at startup, or 0 */ + +#ifndef FREE_MEM_ESTIMATE /* may be defined from command line */ + +#ifdef MSDOS /* For MS-DOS (unless flat-memory model) */ + +#include /* for access to intdos() call */ + +LOCAL(long) +unused_dos_memory (void) +/* Obtain total amount of unallocated DOS memory */ +{ + union REGS regs; + long nparas; + + regs.h.ah = 0x48; /* DOS function Allocate Memory Block */ + regs.x.bx = 0xFFFF; /* Ask for more memory than DOS can have */ + (void) intdos(®s, ®s); + /* DOS will fail and return # of paragraphs actually available in BX. */ + nparas = (unsigned int) regs.x.bx; + /* Times 16 to convert to bytes. */ + return nparas << 4; +} + +/* The default memory setting is 95% of the available space. */ +#define FREE_MEM_ESTIMATE ((unused_dos_memory() * 95L) / 100L) + +#endif /* MSDOS */ + +#ifdef ATARI /* For Atari ST/Mega/STE/TT/Falcon, Pure C or Turbo C */ + +#include + +/* The default memory setting is 90% of the available space. */ +#define FREE_MEM_ESTIMATE (((long) coreleft() * 90L) / 100L) + +#endif /* ATARI */ + +/* Add memory-estimation procedures for other operating systems here, + * with appropriate #ifdef's around them. + */ + +#endif /* !FREE_MEM_ESTIMATE */ + + +/* + * This routine determines what format the input file is, + * and selects the appropriate input-reading module. + * + * To determine which family of input formats the file belongs to, + * we may look only at the first byte of the file, since C does not + * guarantee that more than one character can be pushed back with ungetc. + * Looking at additional bytes would require one of these approaches: + * 1) assume we can fseek() the input file (fails for piped input); + * 2) assume we can push back more than one character (works in + * some C implementations, but unportable); + * 3) provide our own buffering (breaks input readers that want to use + * stdio directly, such as the RLE library); + * or 4) don't put back the data, and modify the input_init methods to assume + * they start reading after the start of file (also breaks RLE library). + * #1 is attractive for MS-DOS but is untenable on Unix. + * + * The most portable solution for file types that can't be identified by their + * first byte is to make the user tell us what they are. This is also the + * only approach for "raw" file types that contain only arbitrary values. + * We presently apply this method for Targa files. Most of the time Targa + * files start with 0x00, so we recognize that case. Potentially, however, + * a Targa file could start with any byte value (byte 0 is the length of the + * seldom-used ID field), so we provide a switch to force Targa input mode. + */ + +static boolean is_targa; /* records user -targa switch */ + + +LOCAL(cjpeg_source_ptr) +select_file_type (j_compress_ptr cinfo, FILE * infile) +{ + int c; + + if (is_targa) { +#ifdef TARGA_SUPPORTED + return jinit_read_targa(cinfo); +#else + ERREXIT(cinfo, JERR_TGA_NOTCOMP); +#endif + } + + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EMPTY); + if (ungetc(c, infile) == EOF) + ERREXIT(cinfo, JERR_UNGETC_FAILED); + + switch (c) { +#ifdef BMP_SUPPORTED + case 'B': + return jinit_read_bmp(cinfo); +#endif +#ifdef GIF_SUPPORTED + case 'G': + return jinit_read_gif(cinfo); +#endif +#ifdef PPM_SUPPORTED + case 'P': + return jinit_read_ppm(cinfo); +#endif +#ifdef RLE_SUPPORTED + case 'R': + return jinit_read_rle(cinfo); +#endif +#ifdef TARGA_SUPPORTED + case 0x00: + return jinit_read_targa(cinfo); +#endif + default: + ERREXIT(cinfo, JERR_UNKNOWN_FORMAT); + break; + } + + return NULL; /* suppress compiler warnings */ +} + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] inputfile(s)\n", progname); + fprintf(stderr, "List of input files may use wildcards (* and ?)\n"); + fprintf(stderr, "Output filename is same as input filename, but extension .jpg\n"); + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -quality N[,...] Compression quality (0..100; 5-95 is useful range)\n"); + fprintf(stderr, " -grayscale Create monochrome JPEG file\n"); + fprintf(stderr, " -rgb Create RGB JPEG file\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif +#ifdef DCT_SCALING_SUPPORTED + fprintf(stderr, " -scale M/N Scale image by fraction M/N, eg, 1/2\n"); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n"); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif +#ifdef DCT_SCALING_SUPPORTED + fprintf(stderr, " -block N DCT block size (1..16; default is 8)\n"); +#endif +#if JPEG_LIB_VERSION_MAJOR >= 9 + fprintf(stderr, " -rgb1 Create RGB JPEG file with reversible color transform\n"); + fprintf(stderr, " -bgycc Create big gamut YCC JPEG file\n"); +#endif +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -nosmooth Don't use high-quality downsampling\n"); + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); +#ifdef INPUT_SMOOTHING_SUPPORTED + fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n"); +#endif +#ifndef FREE_MEM_ESTIMATE + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); +#endif + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); + fprintf(stderr, " -baseline Force baseline quantization tables\n"); + fprintf(stderr, " -qtables file Use quantization tables given in file\n"); + fprintf(stderr, " -qslots N[,...] Set component quantization tables\n"); + fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n"); +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + boolean force_baseline; + boolean simple_progressive; + char * qualityarg = NULL; /* saves -quality parm if any */ + char * qtablefile = NULL; /* saves -qtables filename if any */ + char * qslotsarg = NULL; /* saves -qslots parm if any */ + char * samplearg = NULL; /* saves -sample parm if any */ + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + + force_baseline = FALSE; /* by default, allow 16-bit quantizers */ + simple_progressive = FALSE; + is_targa = FALSE; + outfilename = NULL; + cinfo->err->trace_level = 0; + if (default_maxmem > 0) /* override library's default value */ + cinfo->mem->max_memory_to_use = default_maxmem; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "baseline", 2)) { + /* Force baseline-compatible output (8-bit quantizer values). */ + force_baseline = TRUE; + + } else if (keymatch(arg, "block", 2)) { + /* Set DCT block size. */ +#if defined DCT_SCALING_SUPPORTED && JPEG_LIB_VERSION_MAJOR >= 8 && \ + (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3) + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + if (val < 1 || val > 16) + usage(); + cinfo->block_size = val; +#else + fprintf(stderr, "%s: sorry, block size setting not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "dct", 2)) { + /* Select DCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force a monochrome JPEG file to be generated. */ + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + + } else if (keymatch(arg, "rgb", 3) || keymatch(arg, "rgb1", 4)) { + /* Force an RGB JPEG file to be generated. */ +#if JPEG_LIB_VERSION_MAJOR >= 9 + /* Note: Entropy table assignment in jpeg_set_colorspace depends + * on color_transform. + */ + cinfo->color_transform = arg[3] ? JCT_SUBTRACT_GREEN : JCT_NONE; +#endif + jpeg_set_colorspace(cinfo, JCS_RGB); + + } else if (keymatch(arg, "bgycc", 5)) { + /* Force a big gamut YCC JPEG file to be generated. */ +#if JPEG_LIB_VERSION_MAJOR >= 9 && \ + (JPEG_LIB_VERSION_MAJOR > 9 || JPEG_LIB_VERSION_MINOR >= 1) + jpeg_set_colorspace(cinfo, JCS_BG_YCC); +#else + fprintf(stderr, "%s: sorry, BG_YCC colorspace not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "nosmooth", 3)) { + /* Suppress fancy downsampling. */ + cinfo->do_fancy_downsampling = FALSE; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "quality", 1)) { + /* Quality ratings (quantization table scaling factors). */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qualityarg = argv[argn]; + + } else if (keymatch(arg, "qslots", 2)) { + /* Quantization table slot numbers. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qslotsarg = argv[argn]; + /* Must delay setting qslots until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default quant table numbers. + */ + + } else if (keymatch(arg, "qtables", 2)) { + /* Quantization tables fetched from file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qtablefile = argv[argn]; + /* We postpone actually reading the file in case -quality comes later. */ + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "sample", 2)) { + /* Set sampling factors. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + samplearg = argv[argn]; + /* Must delay setting sample factors until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default sampling factors. + */ + + } else if (keymatch(arg, "scale", 4)) { + /* Scale the image by a fraction M/N. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d/%d", + &cinfo->scale_num, &cinfo->scale_denom) != 2) + usage(); + + } else if (keymatch(arg, "scans", 4)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "smooth", 2)) { + /* Set input smoothing factor. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + if (val < 0 || val > 100) + usage(); + cinfo->smoothing_factor = val; + + } else if (keymatch(arg, "targa", 1)) { + /* Input file is Targa format. */ + is_targa = TRUE; + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + + /* Set quantization tables for selected quality. */ + /* Some or all may be overridden if -qtables is present. */ + if (qualityarg != NULL) /* process -quality if it was present */ + if (! set_quality_ratings(cinfo, qualityarg, force_baseline)) + usage(); + + if (qtablefile != NULL) /* process -qtables if it was present */ + if (! read_quant_tables(cinfo, qtablefile, force_baseline)) + usage(); + + if (qslotsarg != NULL) /* process -qslots if it was present */ + if (! set_quant_slots(cinfo, qslotsarg)) + usage(); + + if (samplearg != NULL) /* process -sample if it was present */ + if (! set_sample_factors(cinfo, samplearg)) + usage(); + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * Check for overwrite of an existing file; clear it with user + */ + +#ifndef NO_OVERWRITE_CHECK + +LOCAL(boolean) +is_write_ok (char * outfname) +{ + FILE * ofile; + int ch; + + ofile = fopen(outfname, READ_BINARY); + if (ofile == NULL) + return TRUE; /* not present */ + fclose(ofile); /* oops, it is present */ + + for (;;) { + fprintf(stderr, "%s already exists, overwrite it? [y/n] ", + outfname); + fflush(stderr); + ch = getc(stdin); + if (ch != '\n') /* flush rest of line */ + while (getc(stdin) != '\n') + /* nothing */; + + switch (ch) { + case 'Y': + case 'y': + return TRUE; + case 'N': + case 'n': + return FALSE; + /* otherwise, ask again */ + } + } +} + +#endif + + +/* + * Process a single input file name, and return its index in argv[]. + * File names at or to left of old_file_index have been processed already. + */ + +LOCAL(int) +process_one_file (int argc, char **argv, int old_file_index) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + char *infilename; + char workfilename[PATH_MAX]; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + cjpeg_source_ptr src_mgr; + FILE * input_file = NULL; + FILE * output_file = NULL; + JDIMENSION num_scanlines; + + /* Initialize the JPEG compression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Initialize JPEG parameters. + * Much of this may be overridden later. + * In particular, we don't yet know the input file's color space, + * but we need to provide some value for jpeg_set_defaults() to work. + */ + + cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ + jpeg_set_defaults(&cinfo); + + /* Scan command line to find next file name. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + */ + + file_index = parse_switches(&cinfo, argc, argv, old_file_index, FALSE); + if (file_index >= argc) { + fprintf(stderr, "%s: missing input file name\n", progname); + usage(); + } + + /* Open the input file. */ + infilename = argv[file_index]; + if ((input_file = fopen(infilename, READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, infilename); + goto fail; + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Figure out the input file format, and set up to read it. */ + src_mgr = select_file_type(&cinfo, input_file); + src_mgr->input_file = input_file; + + /* Read the input file header to obtain file size & colorspace. */ + (*src_mgr->start_input) (&cinfo, src_mgr); + + /* Now that we know input colorspace, fix colorspace-dependent defaults */ + jpeg_default_colorspace(&cinfo); + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, old_file_index, TRUE); + + /* If user didn't supply -outfile switch, select output file name. */ + if (outfilename == NULL) { + int i; + + outfilename = workfilename; + /* Make outfilename be infilename with .jpg substituted for extension */ + strcpy(outfilename, infilename); + for (i = (int)strlen(outfilename)-1; i >= 0; i--) { + switch (outfilename[i]) { + case ':': + case '/': + case '\\': + i = 0; /* stop scanning */ + break; + case '.': + outfilename[i] = '\0'; /* lop off existing extension */ + i = 0; /* stop scanning */ + break; + default: + break; /* keep scanning */ + } + } + strcat(outfilename, ".jpg"); + } + + fprintf(stderr, "Compressing %s => %s\n", infilename, outfilename); +#ifndef NO_OVERWRITE_CHECK + if (! is_write_ok(outfilename)) + goto fail; +#endif + + /* Open the output file. */ + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't create %s\n", progname, outfilename); + goto fail; + } + + /* Specify data destination for compression */ + jpeg_stdio_dest(&cinfo, output_file); + + /* Start compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Process data */ + while (cinfo.next_scanline < cinfo.image_height) { + num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); + (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); + } + + /* Finish compression and release memory */ + (*src_mgr->finish_input) (&cinfo, src_mgr); + jpeg_finish_compress(&cinfo); + + /* Clean up and exit */ +fail: + jpeg_destroy_compress(&cinfo); + + if (input_file != NULL) fclose(input_file); + if (output_file != NULL) fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* Disable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) NULL); +#endif + + return file_index; +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int file_index; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + +#ifdef MSDOS + progname = "cjpeg"; /* DOS tends to be too verbose about argv[0] */ +#else + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "cjpeg"; /* in case C library doesn't provide it */ +#endif + + /* The default maxmem must be computed only once at program startup, + * since releasing memory with free() won't give it back to the OS. + */ +#ifdef FREE_MEM_ESTIMATE + default_maxmem = FREE_MEM_ESTIMATE; +#else + default_maxmem = 0; +#endif + + /* Scan command line, parse switches and locate input file names */ + + if (argc < 2) + usage(); /* nothing on the command line?? */ + + file_index = 0; + + while (file_index < argc-1) + file_index = process_one_file(argc, argv, file_index); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/vendor/jpeg-9e/ckconfig.c b/vendor/jpeg-9f/ckconfig.c similarity index 100% rename from vendor/jpeg-9e/ckconfig.c rename to vendor/jpeg-9f/ckconfig.c diff --git a/vendor/jpeg-9e/djpeg.c b/vendor/jpeg-9f/djpeg.c similarity index 100% rename from vendor/jpeg-9e/djpeg.c rename to vendor/jpeg-9f/djpeg.c diff --git a/vendor/jpeg-9f/djpegalt.c b/vendor/jpeg-9f/djpegalt.c new file mode 100644 index 0000000000..969c58b49c --- /dev/null +++ b/vendor/jpeg-9f/djpegalt.c @@ -0,0 +1,766 @@ +/* + * alternate djpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2009-2023 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains an alternate user interface for the JPEG decompressor. + * One or more input files are named on the command line, and output file + * names are created by substituting an appropriate extension. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#include /* to declare isprint() */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifndef PATH_MAX /* ANSI maximum-pathname-length constant */ +#define PATH_MAX 256 +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * Automatic determination of available memory. + */ + +static long default_maxmem; /* saves value determined at startup, or 0 */ + +#ifndef FREE_MEM_ESTIMATE /* may be defined from command line */ + +#ifdef MSDOS /* For MS-DOS (unless flat-memory model) */ + +#include /* for access to intdos() call */ + +LOCAL(long) +unused_dos_memory (void) +/* Obtain total amount of unallocated DOS memory */ +{ + union REGS regs; + long nparas; + + regs.h.ah = 0x48; /* DOS function Allocate Memory Block */ + regs.x.bx = 0xFFFF; /* Ask for more memory than DOS can have */ + (void) intdos(®s, ®s); + /* DOS will fail and return # of paragraphs actually available in BX. */ + nparas = (unsigned int) regs.x.bx; + /* Times 16 to convert to bytes. */ + return nparas << 4; +} + +/* The default memory setting is 95% of the available space. */ +#define FREE_MEM_ESTIMATE ((unused_dos_memory() * 95L) / 100L) + +#endif /* MSDOS */ + +#ifdef ATARI /* For Atari ST/Mega/STE/TT/Falcon, Pure C or Turbo C */ + +#include + +/* The default memory setting is 90% of the available space. */ +#define FREE_MEM_ESTIMATE (((long) coreleft() * 90L) / 100L) + +#endif /* ATARI */ + +/* Add memory-estimation procedures for other operating systems here, + * with appropriate #ifdef's around them. + */ + +#endif /* !FREE_MEM_ESTIMATE */ + + +/* + * This list defines the known output image formats + * (not all of which need be supported by a given version). + * You can change the default output format by defining DEFAULT_FMT; + * indeed, you had better do so if you undefine PPM_SUPPORTED. + */ + +typedef enum { + FMT_BMP, /* BMP format (Windows flavor) */ + FMT_GIF, /* GIF format (LZW compressed) */ + FMT_GIF0, /* GIF format (uncompressed) */ + FMT_OS2, /* BMP format (OS/2 flavor) */ + FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ + FMT_RLE, /* RLE format */ + FMT_TARGA, /* Targa format */ + FMT_TIFF /* TIFF format */ +} IMAGE_FORMATS; + +#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */ +#define DEFAULT_FMT FMT_BMP +#endif + +static IMAGE_FORMATS requested_fmt; + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] inputfile(s)\n", progname); + fprintf(stderr, "List of input files may use wildcards (* and ?)\n"); + fprintf(stderr, "Output filename is same as input filename except for extension\n"); + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -colors N Reduce image to no more than N colors\n"); + fprintf(stderr, " -fast Fast, low-quality processing\n"); + fprintf(stderr, " -grayscale Force grayscale output\n"); + fprintf(stderr, " -rgb Force RGB output\n"); +#ifdef IDCT_SCALING_SUPPORTED + fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n"); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n", + (DEFAULT_FMT == FMT_BMP ? " (default)" : "")); +#endif +#ifdef GIF_SUPPORTED + fprintf(stderr, " -gif Select GIF output format (LZW compressed)%s\n", + (DEFAULT_FMT == FMT_GIF ? " (default)" : "")); + fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s\n", + (DEFAULT_FMT == FMT_GIF0 ? " (default)" : "")); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n", + (DEFAULT_FMT == FMT_OS2 ? " (default)" : "")); +#endif +#ifdef PPM_SUPPORTED + fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n", + (DEFAULT_FMT == FMT_PPM ? " (default)" : "")); +#endif +#ifdef RLE_SUPPORTED + fprintf(stderr, " -rle Select Utah RLE output format%s\n", + (DEFAULT_FMT == FMT_RLE ? " (default)" : "")); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Select Targa output format%s\n", + (DEFAULT_FMT == FMT_TARGA ? " (default)" : "")); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -dither fs Use F-S dithering (default)\n"); + fprintf(stderr, " -dither none Don't use dithering in quantization\n"); + fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n"); +#ifdef QUANT_2PASS_SUPPORTED + fprintf(stderr, " -map FILE Map to colors used in named image file\n"); +#endif + fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n"); +#ifdef QUANT_1PASS_SUPPORTED + fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n"); +#endif +#ifndef FREE_MEM_ESTIMATE + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); +#endif + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_decompress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + + /* Set up default JPEG parameters. */ + requested_fmt = DEFAULT_FMT; /* set default output file format */ + outfilename = NULL; + cinfo->err->trace_level = 0; + if (default_maxmem > 0) /* override library's default value */ + cinfo->mem->max_memory_to_use = default_maxmem; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "bmp", 1)) { + /* BMP output format (Windows flavor). */ + requested_fmt = FMT_BMP; + + } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) || + keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) { + /* Do color quantization. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + cinfo->desired_number_of_colors = val; + cinfo->quantize_colors = TRUE; + + } else if (keymatch(arg, "dct", 2)) { + /* Select IDCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "dither", 2)) { + /* Select dithering algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "fs", 2)) { + cinfo->dither_mode = JDITHER_FS; + } else if (keymatch(argv[argn], "none", 2)) { + cinfo->dither_mode = JDITHER_NONE; + } else if (keymatch(argv[argn], "ordered", 2)) { + cinfo->dither_mode = JDITHER_ORDERED; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "fast", 1)) { + /* Select recommended processing options for quick-and-dirty output. */ + cinfo->two_pass_quantize = FALSE; + cinfo->dither_mode = JDITHER_ORDERED; + if (! cinfo->quantize_colors) /* don't override an earlier -colors */ + cinfo->desired_number_of_colors = 216; + cinfo->dct_method = JDCT_FASTEST; + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "gif", 1)) { + /* GIF output format (LZW compressed). */ + requested_fmt = FMT_GIF; + + } else if (keymatch(arg, "gif0", 4)) { + /* GIF output format (uncompressed). */ + requested_fmt = FMT_GIF0; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force monochrome output. */ + cinfo->out_color_space = JCS_GRAYSCALE; + + } else if (keymatch(arg, "rgb", 3)) { + /* Force RGB output. */ + cinfo->out_color_space = JCS_RGB; + + } else if (keymatch(arg, "map", 3)) { + /* Quantize to a color map taken from an input file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (for_real) { /* too expensive to do twice! */ +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + FILE * mapfile; + + if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + read_color_map(cinfo, mapfile); + fclose(mapfile); + cinfo->quantize_colors = TRUE; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "nosmooth", 3)) { + /* Suppress fancy upsampling. */ + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "onepass", 3)) { + /* Use fast one-pass quantization. */ + cinfo->two_pass_quantize = FALSE; + + } else if (keymatch(arg, "os2", 3)) { + /* BMP output format (OS/2 flavor). */ + requested_fmt = FMT_OS2; + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) { + /* PPM/PGM output format. */ + requested_fmt = FMT_PPM; + + } else if (keymatch(arg, "rle", 1)) { + /* RLE output format. */ + requested_fmt = FMT_RLE; + + } else if (keymatch(arg, "scale", 1)) { + /* Scale the output image by a fraction M/N. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%u/%u", + &cinfo->scale_num, &cinfo->scale_denom) < 1) + usage(); + + } else if (keymatch(arg, "targa", 1)) { + /* Targa output format. */ + requested_fmt = FMT_TARGA; + + } else { + usage(); /* bogus switch */ + } + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * Marker processor for COM and interesting APPn markers. + * This replaces the library's built-in processor, which just skips the marker. + * We want to print out the marker as text, to the extent possible. + * Note this code relies on a non-suspending data source. + */ + +LOCAL(unsigned int) +jpeg_getc (j_decompress_ptr cinfo) +/* Read next byte */ +{ + struct jpeg_source_mgr * datasrc = cinfo->src; + + if (datasrc->bytes_in_buffer == 0) { + if (! (*datasrc->fill_input_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + datasrc->bytes_in_buffer--; + return GETJOCTET(*datasrc->next_input_byte++); +} + + +METHODDEF(boolean) +print_text_marker (j_decompress_ptr cinfo) +{ + boolean traceit = (cinfo->err->trace_level >= 1); + INT32 length; + unsigned int ch; + unsigned int lastch = 0; + + length = jpeg_getc(cinfo) << 8; + length += jpeg_getc(cinfo); + length -= 2; /* discount the length word itself */ + + if (traceit) { + if (cinfo->unread_marker == JPEG_COM) + fprintf(stderr, "Comment, length %ld:\n", (long) length); + else /* assume it is an APPn otherwise */ + fprintf(stderr, "APP%d, length %ld:\n", + cinfo->unread_marker - JPEG_APP0, (long) length); + } + + while (--length >= 0) { + ch = jpeg_getc(cinfo); + if (traceit) { + /* Emit the character in a readable form. + * Nonprintables are converted to \nnn form, + * while \ is converted to \\. + * Newlines in CR, CR/LF, or LF form will be printed as one newline. + */ + if (ch == '\r') { + fprintf(stderr, "\n"); + } else if (ch == '\n') { + if (lastch != '\r') + fprintf(stderr, "\n"); + } else if (ch == '\\') { + fprintf(stderr, "\\\\"); + } else if (isprint(ch)) { + putc(ch, stderr); + } else { + fprintf(stderr, "\\%03o", ch); + } + lastch = ch; + } + } + + if (traceit) + fprintf(stderr, "\n"); + + return TRUE; +} + + +/* + * Check for overwrite of an existing file; clear it with user + */ + +#ifndef NO_OVERWRITE_CHECK + +LOCAL(boolean) +is_write_ok (char * outfname) +{ + FILE * ofile; + int ch; + + ofile = fopen(outfname, READ_BINARY); + if (ofile == NULL) + return TRUE; /* not present */ + fclose(ofile); /* oops, it is present */ + + for (;;) { + fprintf(stderr, "%s already exists, overwrite it? [y/n] ", + outfname); + fflush(stderr); + ch = getc(stdin); + if (ch != '\n') /* flush rest of line */ + while (getc(stdin) != '\n') + /* nothing */; + + switch (ch) { + case 'Y': + case 'y': + return TRUE; + case 'N': + case 'n': + return FALSE; + /* otherwise, ask again */ + } + } +} + +#endif + + +/* + * Process a single input file name, and return its index in argv[]. + * File names at or to left of old_file_index have been processed already. + */ + +LOCAL(int) +process_one_file (int argc, char **argv, int old_file_index) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + char *infilename; + char workfilename[PATH_MAX]; + const char *default_extension = NULL; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + djpeg_dest_ptr dest_mgr = NULL; + FILE * input_file = NULL; + FILE * output_file = NULL; + JDIMENSION num_scanlines; + + /* Initialize the JPEG decompression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Insert custom marker processor for COM and APP12. + * APP12 is used by some digital camera makers for textual info, + * so we provide the ability to display it as text. + * If you like, additional APPn marker types can be selected for display, + * but don't try to override APP0 or APP14 this way (see libjpeg.txt). + */ + jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); + jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Scan command line to find next file name. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + * (Exception: tracing level set here controls verbosity for COM markers + * found during jpeg_read_header...) + */ + + file_index = parse_switches(&cinfo, argc, argv, old_file_index, FALSE); + if (file_index >= argc) { + fprintf(stderr, "%s: missing input file name\n", progname); + usage(); + } + + /* Open the input file. */ + infilename = argv[file_index]; + if ((input_file = fopen(infilename, READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, infilename); + goto fail; + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&cinfo, input_file); + + /* Read file header, set default decompression parameters */ + (void) jpeg_read_header(&cinfo, TRUE); + + /* Adjust default decompression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, old_file_index, TRUE); + + /* Initialize the output module now to let it override any crucial + * option settings (for instance, GIF wants to force color quantization). + */ + switch (requested_fmt) { +#ifdef BMP_SUPPORTED + case FMT_BMP: + dest_mgr = jinit_write_bmp(&cinfo, FALSE); + default_extension = ".bmp"; + break; + case FMT_OS2: + dest_mgr = jinit_write_bmp(&cinfo, TRUE); + default_extension = ".bmp"; + break; +#endif +#ifdef GIF_SUPPORTED + case FMT_GIF: + dest_mgr = jinit_write_gif(&cinfo, TRUE); + default_extension = ".gif"; + break; + case FMT_GIF0: + dest_mgr = jinit_write_gif(&cinfo, FALSE); + default_extension = ".gif"; + break; +#endif +#ifdef PPM_SUPPORTED + case FMT_PPM: + dest_mgr = jinit_write_ppm(&cinfo); + default_extension = ".ppm"; + break; +#endif +#ifdef RLE_SUPPORTED + case FMT_RLE: + dest_mgr = jinit_write_rle(&cinfo); + default_extension = ".rle"; + break; +#endif +#ifdef TARGA_SUPPORTED + case FMT_TARGA: + dest_mgr = jinit_write_targa(&cinfo); + default_extension = ".tga"; + break; +#endif + default: + ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); + } + + /* If user didn't supply -outfile switch, select output file name. */ + if (outfilename == NULL) { + int i; + + outfilename = workfilename; + /* Make outfilename be infilename with appropriate extension */ + strcpy(outfilename, infilename); + for (i = (int)strlen(outfilename)-1; i >= 0; i--) { + switch (outfilename[i]) { + case ':': + case '/': + case '\\': + i = 0; /* stop scanning */ + break; + case '.': + outfilename[i] = '\0'; /* lop off existing extension */ + i = 0; /* stop scanning */ + break; + default: + break; /* keep scanning */ + } + } + strcat(outfilename, default_extension); + } + + fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename); +#ifndef NO_OVERWRITE_CHECK + if (! is_write_ok(outfilename)) + goto fail; +#endif + + /* Open the output file. */ + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't create %s\n", progname, outfilename); + goto fail; + } + dest_mgr->output_file = output_file; + + /* Start decompressor */ + (void) jpeg_start_decompress(&cinfo); + + /* Write output file header */ + (*dest_mgr->start_output) (&cinfo, dest_mgr); + + /* Process data */ + while (cinfo.output_scanline < cinfo.output_height) { + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); + (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + } + +#ifdef PROGRESS_REPORT + /* Hack: count final pass as done in case finish_output does an extra pass. + * The library won't have updated completed_passes. + */ + progress.pub.completed_passes = progress.pub.total_passes; +#endif + + /* Finish decompression and release memory. + * I must do it in this order because output module has allocated memory + * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. + */ + (*dest_mgr->finish_output) (&cinfo, dest_mgr); + (void) jpeg_finish_decompress(&cinfo); + + /* Clean up and exit */ +fail: + jpeg_destroy_decompress(&cinfo); + + if (input_file != NULL) fclose(input_file); + if (output_file != NULL) fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* Disable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) NULL); +#endif + + return file_index; +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int file_index; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + +#ifdef MSDOS + progname = "djpeg"; /* DOS tends to be too verbose about argv[0] */ +#else + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "djpeg"; /* in case C library doesn't provide it */ +#endif + + /* The default maxmem must be computed only once at program startup, + * since releasing memory with free() won't give it back to the OS. + */ +#ifdef FREE_MEM_ESTIMATE + default_maxmem = FREE_MEM_ESTIMATE; +#else + default_maxmem = 0; +#endif + + /* Scan command line, parse switches and locate input file names */ + + if (argc < 2) + usage(); /* nothing on the command line?? */ + + file_index = 0; + + while (file_index < argc-1) + file_index = process_one_file(argc, argv, file_index); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/vendor/jpeg-9e/example.c b/vendor/jpeg-9f/example.c similarity index 100% rename from vendor/jpeg-9e/example.c rename to vendor/jpeg-9f/example.c diff --git a/vendor/jpeg-9e/jaricom.c b/vendor/jpeg-9f/jaricom.c similarity index 100% rename from vendor/jpeg-9e/jaricom.c rename to vendor/jpeg-9f/jaricom.c diff --git a/vendor/jpeg-9e/jcapimin.c b/vendor/jpeg-9f/jcapimin.c similarity index 100% rename from vendor/jpeg-9e/jcapimin.c rename to vendor/jpeg-9f/jcapimin.c diff --git a/vendor/jpeg-9e/jcapistd.c b/vendor/jpeg-9f/jcapistd.c similarity index 100% rename from vendor/jpeg-9e/jcapistd.c rename to vendor/jpeg-9f/jcapistd.c diff --git a/vendor/jpeg-9e/jcarith.c b/vendor/jpeg-9f/jcarith.c similarity index 100% rename from vendor/jpeg-9e/jcarith.c rename to vendor/jpeg-9f/jcarith.c diff --git a/vendor/jpeg-9e/jccoefct.c b/vendor/jpeg-9f/jccoefct.c similarity index 98% rename from vendor/jpeg-9e/jccoefct.c rename to vendor/jpeg-9f/jccoefct.c index 77851f390e..494aa22988 100644 --- a/vendor/jpeg-9e/jccoefct.c +++ b/vendor/jpeg-9f/jccoefct.c @@ -2,7 +2,7 @@ * jccoefct.c * * Copyright (C) 1994-1997, Thomas G. Lane. - * Modified 2003-2020 by Guido Vollbeding. + * Modified 2003-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -41,9 +41,9 @@ typedef struct { int MCU_rows_per_iMCU_row; /* number of such rows needed */ /* For single-pass compression, it's sufficient to buffer just one MCU - * (although this may prove a bit slow in practice). We append a - * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it - * for each MCU constructed and sent. + * (although this may prove a bit slow in practice). + * We append a workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, + * and reuse it for each MCU constructed and sent. * In multi-pass modes, this array points to the current MCU's blocks * within the virtual arrays. */ diff --git a/vendor/jpeg-9e/jccolor.c b/vendor/jpeg-9f/jccolor.c similarity index 95% rename from vendor/jpeg-9e/jccolor.c rename to vendor/jpeg-9f/jccolor.c index db2ca429e8..c028dd9db3 100644 --- a/vendor/jpeg-9e/jccolor.c +++ b/vendor/jpeg-9f/jccolor.c @@ -2,7 +2,7 @@ * jccolor.c * * Copyright (C) 1991-1996, Thomas G. Lane. - * Modified 2011-2019 by Guido Vollbeding. + * Modified 2011-2023 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -40,10 +40,10 @@ typedef my_color_converter * my_cconvert_ptr; * Note that the derived conversion coefficients given in some of these * documents are imprecise. The general conversion equations are * Y = Kr * R + (1 - Kr - Kb) * G + Kb * B - * Cb = 0.5 * (B - Y) / (1 - Kb) - * Cr = 0.5 * (R - Y) / (1 - Kr) + * Cb = (B - Y) / (1 - Kb) / K + * Cr = (R - Y) / (1 - Kr) / K * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993 - * from the 1953 FCC NTSC primaries and CIE Illuminant C), + * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC, * the conversion equations to be implemented are therefore * Y = 0.299 * R + 0.587 * G + 0.114 * B * Cb = -0.168735892 * R - 0.331264108 * G + 0.5 * B + CENTERJSAMPLE @@ -62,8 +62,8 @@ typedef my_color_converter * my_cconvert_ptr; * by precalculating the constants times R,G,B for all possible values. * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); * for 9-bit to 12-bit samples it is still acceptable. It's not very - * reasonable for 16-bit samples, but if you want lossless storage you - * shouldn't be changing colorspace anyway. + * reasonable for 16-bit samples, but if you want lossless storage + * you shouldn't be changing colorspace anyway. * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included * in the tables to save adding them separately in the inner loop. */ @@ -110,16 +110,16 @@ rgb_ycc_start (j_compress_ptr cinfo) for (i = 0; i <= MAXJSAMPLE; i++) { rgb_ycc_tab[i+R_Y_OFF] = FIX(0.299) * i; rgb_ycc_tab[i+G_Y_OFF] = FIX(0.587) * i; - rgb_ycc_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF; rgb_ycc_tab[i+R_CB_OFF] = (- FIX(0.168735892)) * i; rgb_ycc_tab[i+G_CB_OFF] = (- FIX(0.331264108)) * i; /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. * This ensures that the maximum output will round to MAXJSAMPLE * not MAXJSAMPLE+1, and thus that we don't have to range-limit. */ - rgb_ycc_tab[i+B_CB_OFF] = FIX(0.5) * i + CBCR_OFFSET + ONE_HALF-1; + rgb_ycc_tab[i+B_CB_OFF] = (i << (SCALEBITS-1)) + CBCR_OFFSET + ONE_HALF-1; /* B=>Cb and R=>Cr tables are the same - rgb_ycc_tab[i+R_CR_OFF] = FIX(0.5) * i + CBCR_OFFSET + ONE_HALF-1; + rgb_ycc_tab[i+R_CR_OFF] = (i << (SCALEBITS-1)) + CBCR_OFFSET + ONE_HALF-1; */ rgb_ycc_tab[i+G_CR_OFF] = (- FIX(0.418687589)) * i; rgb_ycc_tab[i+B_CR_OFF] = (- FIX(0.081312411)) * i; @@ -190,8 +190,8 @@ rgb_ycc_convert (j_compress_ptr cinfo, /* * Convert some rows of samples to the JPEG colorspace. - * This version handles RGB->grayscale conversion, which is the same - * as the RGB->Y portion of RGB->YCbCr. + * This version handles RGB->grayscale conversion, + * which is the same as the RGB->Y portion of RGB->YCbCr. * We assume rgb_ycc_start has been called (we only use the Y tables). */ @@ -201,7 +201,7 @@ rgb_gray_convert (j_compress_ptr cinfo, JDIMENSION output_row, int num_rows) { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register int r, g, b; + register INT32 y; register INT32 * ctab = cconvert->rgb_ycc_tab; register JSAMPROW inptr; register JSAMPROW outptr; @@ -212,14 +212,11 @@ rgb_gray_convert (j_compress_ptr cinfo, inptr = *input_buf++; outptr = output_buf[0][output_row++]; for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr[RGB_RED]); - g = GETJSAMPLE(inptr[RGB_GREEN]); - b = GETJSAMPLE(inptr[RGB_BLUE]); + y = ctab[R_Y_OFF + GETJSAMPLE(inptr[RGB_RED])]; + y += ctab[G_Y_OFF + GETJSAMPLE(inptr[RGB_GREEN])]; + y += ctab[B_Y_OFF + GETJSAMPLE(inptr[RGB_BLUE])]; inptr += RGB_PIXELSIZE; - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); + outptr[col] = (JSAMPLE) (y >> SCALEBITS); } } } diff --git a/vendor/jpeg-9e/jcdctmgr.c b/vendor/jpeg-9f/jcdctmgr.c similarity index 100% rename from vendor/jpeg-9e/jcdctmgr.c rename to vendor/jpeg-9f/jcdctmgr.c diff --git a/vendor/jpeg-9e/jchuff.c b/vendor/jpeg-9f/jchuff.c similarity index 89% rename from vendor/jpeg-9e/jchuff.c rename to vendor/jpeg-9f/jchuff.c index f3272c9fa6..1f527b2182 100644 --- a/vendor/jpeg-9e/jchuff.c +++ b/vendor/jpeg-9f/jchuff.c @@ -2,7 +2,7 @@ * jchuff.c * * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2006-2020 by Guido Vollbeding. + * Modified 2006-2023 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -26,17 +26,11 @@ /* The legal range of a DCT coefficient is - * -1024 .. +1023 for 8-bit data; - * -16384 .. +16383 for 12-bit data. - * Hence the magnitude should always fit in 10 or 14 bits respectively. + * -1024 .. +1023 for 8-bit sample data precision; + * -16384 .. +16383 for 12-bit sample data precision. + * Hence the magnitude should always fit in sample data precision + 2 bits. */ -#if BITS_IN_JSAMPLE == 8 -#define MAX_COEF_BITS 10 -#else -#define MAX_COEF_BITS 14 -#endif - /* Derived data constructed for each Huffman table */ typedef struct { @@ -547,6 +541,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; register int temp, temp2; register int nbits; + int max_coef_bits; int blkn, ci, tbl; ISHIFT_TEMPS @@ -558,6 +553,9 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) if (entropy->restarts_to_go == 0) emit_restart_e(entropy, entropy->next_restart_num); + /* Since we're encoding a difference, the range limit is twice as much. */ + max_coef_bits = cinfo->data_precision + 3; + /* Encode the MCU data blocks */ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { ci = cinfo->MCU_membership[blkn]; @@ -569,12 +567,17 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) temp = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al); /* DC differences are figured on the point-transformed values. */ - temp2 = temp - entropy->saved.last_dc_val[ci]; + if ((temp2 = temp - entropy->saved.last_dc_val[ci]) == 0) { + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_dc_symbol(entropy, tbl, 0); + + continue; + } + entropy->saved.last_dc_val[ci] = temp; /* Encode the DC coefficient difference per section G.1.2.1 */ - temp = temp2; - if (temp < 0) { + if ((temp = temp2) < 0) { temp = -temp; /* temp is abs value of input */ /* For a negative input, want temp2 = bitwise complement of abs(input) */ /* This code assumes we are on a two's complement machine */ @@ -583,14 +586,10 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) /* Find the number of bits needed for the magnitude of the coefficient */ nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values */ + if (nbits > max_coef_bits) ERREXIT(cinfo, JERR_BAD_DCT_COEF); /* Count/emit the Huffman-coded symbol for the number of bits */ @@ -598,8 +597,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) /* Emit that number of bits of the value, if positive, */ /* or the complement of its magnitude, if negative. */ - if (nbits) /* emit_bits rejects calls with size 0 */ - emit_bits_e(entropy, (unsigned int) temp2, nbits); + emit_bits_e(entropy, (unsigned int) temp2, nbits); } cinfo->dest->next_output_byte = entropy->next_output_byte; @@ -633,7 +631,7 @@ encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) register int temp, temp2; register int nbits; register int r, k; - int Se, Al; + int Se, Al, max_coef_bits; entropy->next_output_byte = cinfo->dest->next_output_byte; entropy->free_in_buffer = cinfo->dest->free_in_buffer; @@ -646,6 +644,7 @@ encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) Se = cinfo->Se; Al = cinfo->Al; natural_order = cinfo->natural_order; + max_coef_bits = cinfo->data_precision + 2; /* Encode the MCU data block */ block = MCU_data[0]; @@ -666,18 +665,23 @@ encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) */ if (temp < 0) { temp = -temp; /* temp is abs value of input */ - temp >>= Al; /* apply the point transform */ + /* Apply the point transform, and watch out for case */ + /* that nonzero coef is zero after point transform. */ + if ((temp >>= Al) == 0) { + r++; + continue; + } /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ temp2 = ~temp; } else { - temp >>= Al; /* apply the point transform */ + /* Apply the point transform, and watch out for case */ + /* that nonzero coef is zero after point transform. */ + if ((temp >>= Al) == 0) { + r++; + continue; + } temp2 = temp; } - /* Watch out for case that nonzero coef is zero after point transform */ - if (temp == 0) { - r++; - continue; - } /* Emit any pending EOBRUN */ if (entropy->EOBRUN > 0) @@ -689,11 +693,11 @@ encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data) } /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) + if (nbits > max_coef_bits) ERREXIT(cinfo, JERR_BAD_DCT_COEF); /* Count/emit Huffman symbol for run length / number of bits */ @@ -916,83 +920,89 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, register int nbits; register int r, k; int Se = state->cinfo->lim_Se; + int max_coef_bits = state->cinfo->data_precision + 3; const int * natural_order = state->cinfo->natural_order; /* Encode the DC coefficient difference per section F.1.2.1 */ - temp = temp2 = block[0] - last_dc_val; - - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - /* For a negative input, want temp2 = bitwise complement of abs(input) */ - /* This code assumes we are on a two's complement machine */ - temp2--; - } + if ((temp = block[0] - last_dc_val) == 0) { + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits_s(state, dctbl->ehufco[0], dctbl->ehufsi[0])) + return FALSE; + } else { + if ((temp2 = temp) < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) - ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > max_coef_bits) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); - /* Emit the Huffman-coded symbol for the number of bits */ - if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) - return FALSE; + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - if (nbits) /* emit_bits rejects calls with size 0 */ + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ if (! emit_bits_s(state, (unsigned int) temp2, nbits)) return FALSE; + } /* Encode the AC coefficients per section F.1.2.2 */ r = 0; /* r = run length of zeros */ for (k = 1; k <= Se; k++) { - if ((temp2 = block[natural_order[k]]) == 0) { + if ((temp = block[natural_order[k]]) == 0) { r++; - } else { - /* if run length > 15, must emit special run-length-16 codes (0xF0) */ - while (r > 15) { - if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) - return FALSE; - r -= 16; - } - - temp = temp2; - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - /* This code assumes we are on a two's complement machine */ - temp2--; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; - /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) - ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); - - /* Emit Huffman symbol for run length / number of bits */ - temp = (r << 4) + nbits; - if (! emit_bits_s(state, actbl->ehufco[temp], actbl->ehufsi[temp])) - return FALSE; + continue; + } - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) return FALSE; + r -= 16; + } - r = 0; + if ((temp2 = temp) < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + /* This code assumes we are on a two's complement machine */ + temp2--; } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Use ">=" instead of ">" so can use the + * same one larger limit from DC check here. + */ + if (nbits >= max_coef_bits) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + temp = (r << 4) + nbits; + if (! emit_bits_s(state, actbl->ehufco[temp], actbl->ehufsi[temp])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; /* reset zero run length */ } /* If the last coef(s) were zero, emit an end-of-block code */ @@ -1122,28 +1132,31 @@ htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, register int nbits; register int r, k; int Se = cinfo->lim_Se; + int max_coef_bits = cinfo->data_precision + 3; const int * natural_order = cinfo->natural_order; /* Encode the DC coefficient difference per section F.1.2.1 */ - temp = block[0] - last_dc_val; - if (temp < 0) - temp = -temp; + if ((temp = block[0] - last_dc_val) == 0) { + /* Count the Huffman symbol for the number of bits */ + dc_counts[0]++; + } else { + if (temp < 0) + temp = -temp; /* temp is abs value of input */ - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); - /* Count the Huffman symbol for the number of bits */ - dc_counts[nbits]++; + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + } /* Encode the AC coefficients per section F.1.2.2 */ @@ -1152,30 +1165,33 @@ htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, for (k = 1; k <= Se; k++) { if ((temp = block[natural_order[k]]) == 0) { r++; - } else { - /* if run length > 15, must emit special run-length-16 codes (0xF0) */ - while (r > 15) { - ac_counts[0xF0]++; - r -= 16; - } + continue; + } + + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } - /* Find the number of bits needed for the magnitude of the coefficient */ - if (temp < 0) - temp = -temp; + if (temp < 0) + temp = -temp; /* temp is abs value of input */ - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; - /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + do nbits++; /* there must be at least one 1 bit */ + while ((temp >>= 1)); + /* Check for out-of-range coefficient values. + * Use ">=" instead of ">" so can use the + * same one larger limit from DC check here. + */ + if (nbits >= max_coef_bits) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); - /* Count Huffman symbol for run length / number of bits */ - ac_counts[(r << 4) + nbits]++; + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; - r = 0; - } + r = 0; /* reset zero run length */ } /* If the last coef(s) were zero, emit an end-of-block code */ diff --git a/vendor/jpeg-9e/jcinit.c b/vendor/jpeg-9f/jcinit.c similarity index 100% rename from vendor/jpeg-9e/jcinit.c rename to vendor/jpeg-9f/jcinit.c diff --git a/vendor/jpeg-9e/jcmainct.c b/vendor/jpeg-9f/jcmainct.c similarity index 100% rename from vendor/jpeg-9e/jcmainct.c rename to vendor/jpeg-9f/jcmainct.c diff --git a/vendor/jpeg-9e/jcmarker.c b/vendor/jpeg-9f/jcmarker.c similarity index 100% rename from vendor/jpeg-9e/jcmarker.c rename to vendor/jpeg-9f/jcmarker.c diff --git a/vendor/jpeg-9e/jcmaster.c b/vendor/jpeg-9f/jcmaster.c similarity index 100% rename from vendor/jpeg-9e/jcmaster.c rename to vendor/jpeg-9f/jcmaster.c diff --git a/vendor/jpeg-9e/jcomapi.c b/vendor/jpeg-9f/jcomapi.c similarity index 100% rename from vendor/jpeg-9e/jcomapi.c rename to vendor/jpeg-9f/jcomapi.c diff --git a/vendor/jpeg-9e/jconfig.h b/vendor/jpeg-9f/jconfig.h similarity index 100% rename from vendor/jpeg-9e/jconfig.h rename to vendor/jpeg-9f/jconfig.h diff --git a/vendor/jpeg-9e/jcparam.c b/vendor/jpeg-9f/jcparam.c similarity index 100% rename from vendor/jpeg-9e/jcparam.c rename to vendor/jpeg-9f/jcparam.c diff --git a/vendor/jpeg-9e/jcprepct.c b/vendor/jpeg-9f/jcprepct.c similarity index 100% rename from vendor/jpeg-9e/jcprepct.c rename to vendor/jpeg-9f/jcprepct.c diff --git a/vendor/jpeg-9e/jcsample.c b/vendor/jpeg-9f/jcsample.c similarity index 100% rename from vendor/jpeg-9e/jcsample.c rename to vendor/jpeg-9f/jcsample.c diff --git a/vendor/jpeg-9e/jctrans.c b/vendor/jpeg-9f/jctrans.c similarity index 100% rename from vendor/jpeg-9e/jctrans.c rename to vendor/jpeg-9f/jctrans.c diff --git a/vendor/jpeg-9e/jdapimin.c b/vendor/jpeg-9f/jdapimin.c similarity index 100% rename from vendor/jpeg-9e/jdapimin.c rename to vendor/jpeg-9f/jdapimin.c diff --git a/vendor/jpeg-9e/jdapistd.c b/vendor/jpeg-9f/jdapistd.c similarity index 100% rename from vendor/jpeg-9e/jdapistd.c rename to vendor/jpeg-9f/jdapistd.c diff --git a/vendor/jpeg-9e/jdarith.c b/vendor/jpeg-9f/jdarith.c similarity index 100% rename from vendor/jpeg-9e/jdarith.c rename to vendor/jpeg-9f/jdarith.c diff --git a/vendor/jpeg-9e/jdatadst.c b/vendor/jpeg-9f/jdatadst.c similarity index 95% rename from vendor/jpeg-9e/jdatadst.c rename to vendor/jpeg-9f/jdatadst.c index 75ebd7c22d..b3b4798ea4 100644 --- a/vendor/jpeg-9e/jdatadst.c +++ b/vendor/jpeg-9f/jdatadst.c @@ -2,7 +2,7 @@ * jdatadst.c * * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2009-2019 by Guido Vollbeding. + * Modified 2009-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -28,17 +28,17 @@ extern void free JPP((void *ptr)); /* Expanded data destination object for stdio output */ +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + typedef struct { struct jpeg_destination_mgr pub; /* public fields */ FILE * outfile; /* target stream */ - JOCTET * buffer; /* start of buffer */ + JOCTET buffer[OUTPUT_BUF_SIZE]; /* output buffer */ } my_destination_mgr; typedef my_destination_mgr * my_dest_ptr; -#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ - /* Expanded data destination object for memory output */ @@ -65,10 +65,6 @@ init_destination (j_compress_ptr cinfo) { my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - /* Allocate the output buffer --- it will be released when done with image */ - dest->buffer = (JOCTET *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); - dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } @@ -187,8 +183,8 @@ term_mem_destination (j_compress_ptr cinfo) /* * Prepare for output to a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing compression. + * The caller must have already opened the stream, + * and is responsible for closing it after finishing compression. */ GLOBAL(void) diff --git a/vendor/jpeg-9e/jdatasrc.c b/vendor/jpeg-9f/jdatasrc.c similarity index 92% rename from vendor/jpeg-9e/jdatasrc.c rename to vendor/jpeg-9f/jdatasrc.c index 606ae11b4c..fd7a1a594b 100644 --- a/vendor/jpeg-9e/jdatasrc.c +++ b/vendor/jpeg-9f/jdatasrc.c @@ -2,7 +2,7 @@ * jdatasrc.c * * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2009-2019 by Guido Vollbeding. + * Modified 2009-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -23,18 +23,18 @@ /* Expanded data source object for stdio input */ +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + typedef struct { struct jpeg_source_mgr pub; /* public fields */ FILE * infile; /* source stream */ - JOCTET * buffer; /* start of buffer */ + JOCTET buffer[INPUT_BUF_SIZE]; /* input buffer */ boolean start_of_file; /* have we gotten any data yet? */ } my_source_mgr; typedef my_source_mgr * my_src_ptr; -#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ - /* * Initialize source --- called by jpeg_read_header @@ -204,8 +204,8 @@ term_source (j_decompress_ptr cinfo) /* * Prepare for input from a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing decompression. + * The caller must have already opened the stream, + * and is responsible for closing it after finishing decompression. */ GLOBAL(void) @@ -213,19 +213,16 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) { my_src_ptr src; - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_stdio_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) + /* The source object including the input buffer is made permanent so that + * a series of JPEG images can be read from the same file by calling + * jpeg_stdio_src only before the first one. (If we discarded the buffer + * at the end of one image, we'd likely lose the start of the next one.) * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * SIZEOF(JOCTET)); } src = (my_src_ptr) cinfo->src; diff --git a/vendor/jpeg-9e/jdcoefct.c b/vendor/jpeg-9f/jdcoefct.c similarity index 100% rename from vendor/jpeg-9e/jdcoefct.c rename to vendor/jpeg-9f/jdcoefct.c diff --git a/vendor/jpeg-9e/jdcolor.c b/vendor/jpeg-9f/jdcolor.c similarity index 91% rename from vendor/jpeg-9e/jdcolor.c rename to vendor/jpeg-9f/jdcolor.c index 7750df125a..6b40fb5340 100644 --- a/vendor/jpeg-9e/jdcolor.c +++ b/vendor/jpeg-9f/jdcolor.c @@ -2,7 +2,7 @@ * jdcolor.c * * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 2011-2020 by Guido Vollbeding. + * Modified 2011-2023 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -32,7 +32,9 @@ typedef struct { INT32 * Cb_g_tab; /* => table for Cb to G conversion */ /* Private state for RGB->Y conversion */ - INT32 * rgb_y_tab; /* => table for RGB to Y conversion */ + INT32 * R_y_tab; /* => table for R to Y conversion */ + INT32 * G_y_tab; /* => table for G to Y conversion */ + INT32 * B_y_tab; /* => table for B to Y conversion */ } my_color_deconverter; typedef my_color_deconverter * my_cconvert_ptr; @@ -87,29 +89,17 @@ typedef my_color_deconverter * my_cconvert_ptr; * by precalculating the constants times Cb and Cr for all possible values. * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); * for 9-bit to 12-bit samples it is still acceptable. It's not very - * reasonable for 16-bit samples, but if you want lossless storage you - * shouldn't be changing colorspace anyway. - * The Cr=>R and Cb=>B values can be rounded to integers in advance; the - * values for the G calculation are left scaled up, since we must add them - * together before rounding. + * reasonable for 16-bit samples, but if you want lossless storage + * you shouldn't be changing colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; + * the values for the G calculation are left scaled up, + * since we must add them together before rounding. */ #define SCALEBITS 16 /* speediest right-shift on some machines */ #define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) #define FIX(x) ((INT32) ((x) * (1L<Y conversion and divide it up into - * three parts, instead of doing three alloc_small requests. This lets us - * use a single table base address, which can be held in a register in the - * inner loops on many machines (more than can hold all three addresses, - * anyway). - */ - -#define R_Y_OFF 0 /* offset to R => Y section */ -#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ -#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ -#define TABLE_SIZE (3*(MAXJSAMPLE+1)) - /* * Initialize tables for YCbCr->RGB and BG_YCC->RGB colorspace conversion. @@ -249,17 +239,19 @@ LOCAL(void) build_rgb_y_table (j_decompress_ptr cinfo) { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - INT32 * rgb_y_tab; INT32 i; - /* Allocate and fill in the conversion tables. */ - cconvert->rgb_y_tab = rgb_y_tab = (INT32 *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, TABLE_SIZE * SIZEOF(INT32)); + cconvert->R_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->G_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->B_y_tab = (INT32 *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32)); for (i = 0; i <= MAXJSAMPLE; i++) { - rgb_y_tab[i+R_Y_OFF] = FIX(0.299) * i; - rgb_y_tab[i+G_Y_OFF] = FIX(0.587) * i; - rgb_y_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF; + cconvert->R_y_tab[i] = FIX(0.299) * i; + cconvert->G_y_tab[i] = FIX(0.587) * i; + cconvert->B_y_tab[i] = FIX(0.114) * i + ONE_HALF; } } @@ -274,8 +266,10 @@ rgb_gray_convert (j_decompress_ptr cinfo, JSAMPARRAY output_buf, int num_rows) { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register int r, g, b; - register INT32 * ctab = cconvert->rgb_y_tab; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; register JSAMPROW outptr; register JSAMPROW inptr0, inptr1, inptr2; register JDIMENSION col; @@ -288,13 +282,10 @@ rgb_gray_convert (j_decompress_ptr cinfo, input_row++; outptr = *output_buf++; for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr0[col]); - g = GETJSAMPLE(inptr1[col]); - b = GETJSAMPLE(inptr2[col]); - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); + y = Rytab[GETJSAMPLE(inptr0[col])]; + y += Gytab[GETJSAMPLE(inptr1[col])]; + y += Bytab[GETJSAMPLE(inptr2[col])]; + outptr[col] = (JSAMPLE) (y >> SCALEBITS); } } } @@ -354,7 +345,10 @@ rgb1_gray_convert (j_decompress_ptr cinfo, { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; register int r, g, b; - register INT32 * ctab = cconvert->rgb_y_tab; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; register JSAMPROW outptr; register JSAMPROW inptr0, inptr1, inptr2; register JDIMENSION col; @@ -373,12 +367,10 @@ rgb1_gray_convert (j_decompress_ptr cinfo, /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD * (modulo) operator is equivalent to the bitmask operator AND. */ - r = (r + g - CENTERJSAMPLE) & MAXJSAMPLE; - b = (b + g - CENTERJSAMPLE) & MAXJSAMPLE; - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); + y = Rytab[(r + g - CENTERJSAMPLE) & MAXJSAMPLE]; + y += Gytab[g]; + y += Bytab[(b + g - CENTERJSAMPLE) & MAXJSAMPLE]; + outptr[col] = (JSAMPLE) (y >> SCALEBITS); } } } @@ -565,8 +557,10 @@ cmyk_yk_convert (j_decompress_ptr cinfo, JSAMPARRAY output_buf, int num_rows) { my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - register int r, g, b; - register INT32 * ctab = cconvert->rgb_y_tab; + register INT32 y; + register INT32 * Rytab = cconvert->R_y_tab; + register INT32 * Gytab = cconvert->G_y_tab; + register INT32 * Bytab = cconvert->B_y_tab; register JSAMPROW outptr; register JSAMPROW inptr0, inptr1, inptr2, inptr3; register JDIMENSION col; @@ -580,13 +574,10 @@ cmyk_yk_convert (j_decompress_ptr cinfo, input_row++; outptr = *output_buf++; for (col = 0; col < num_cols; col++) { - r = MAXJSAMPLE - GETJSAMPLE(inptr0[col]); - g = MAXJSAMPLE - GETJSAMPLE(inptr1[col]); - b = MAXJSAMPLE - GETJSAMPLE(inptr2[col]); - /* Y */ - outptr[0] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); + y = Rytab[MAXJSAMPLE - GETJSAMPLE(inptr0[col])]; + y += Gytab[MAXJSAMPLE - GETJSAMPLE(inptr1[col])]; + y += Bytab[MAXJSAMPLE - GETJSAMPLE(inptr2[col])]; + outptr[0] = (JSAMPLE) (y >> SCALEBITS); /* K passes through unchanged */ outptr[1] = inptr3[col]; /* don't need GETJSAMPLE here */ outptr += 2; diff --git a/vendor/jpeg-9e/jdct.h b/vendor/jpeg-9f/jdct.h similarity index 99% rename from vendor/jpeg-9e/jdct.h rename to vendor/jpeg-9f/jdct.h index c8ec6cd90e..0f251590c4 100644 --- a/vendor/jpeg-9e/jdct.h +++ b/vendor/jpeg-9f/jdct.h @@ -2,7 +2,7 @@ * jdct.h * * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2002-2019 by Guido Vollbeding. + * Modified 2002-2023 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -158,7 +158,7 @@ typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ #define jpeg_idct_6x12 jRD6x12 #define jpeg_idct_5x10 jRD5x10 #define jpeg_idct_4x8 jRD4x8 -#define jpeg_idct_3x6 jRD3x8 +#define jpeg_idct_3x6 jRD3x6 #define jpeg_idct_2x4 jRD2x4 #define jpeg_idct_1x2 jRD1x2 #endif /* NEED_SHORT_EXTERNAL_NAMES */ diff --git a/vendor/jpeg-9e/jddctmgr.c b/vendor/jpeg-9f/jddctmgr.c similarity index 100% rename from vendor/jpeg-9e/jddctmgr.c rename to vendor/jpeg-9f/jddctmgr.c diff --git a/vendor/jpeg-9e/jdhuff.c b/vendor/jpeg-9f/jdhuff.c similarity index 100% rename from vendor/jpeg-9e/jdhuff.c rename to vendor/jpeg-9f/jdhuff.c diff --git a/vendor/jpeg-9e/jdinput.c b/vendor/jpeg-9f/jdinput.c similarity index 100% rename from vendor/jpeg-9e/jdinput.c rename to vendor/jpeg-9f/jdinput.c diff --git a/vendor/jpeg-9e/jdmainct.c b/vendor/jpeg-9f/jdmainct.c similarity index 100% rename from vendor/jpeg-9e/jdmainct.c rename to vendor/jpeg-9f/jdmainct.c diff --git a/vendor/jpeg-9e/jdmarker.c b/vendor/jpeg-9f/jdmarker.c similarity index 100% rename from vendor/jpeg-9e/jdmarker.c rename to vendor/jpeg-9f/jdmarker.c diff --git a/vendor/jpeg-9e/jdmaster.c b/vendor/jpeg-9f/jdmaster.c similarity index 100% rename from vendor/jpeg-9e/jdmaster.c rename to vendor/jpeg-9f/jdmaster.c diff --git a/vendor/jpeg-9e/jdmerge.c b/vendor/jpeg-9f/jdmerge.c similarity index 96% rename from vendor/jpeg-9e/jdmerge.c rename to vendor/jpeg-9f/jdmerge.c index 8ff13143af..0d16821bed 100644 --- a/vendor/jpeg-9e/jdmerge.c +++ b/vendor/jpeg-9f/jdmerge.c @@ -2,7 +2,7 @@ * jdmerge.c * * Copyright (C) 1994-1996, Thomas G. Lane. - * Modified 2013-2020 by Guido Vollbeding. + * Modified 2013-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -20,17 +20,17 @@ * B = Y + K4 * Cb * only the Y term varies among the group of pixels corresponding to a pair * of chroma samples, so the rest of the terms can be calculated just once. - * At typical sampling ratios, this eliminates half or three-quarters of the - * multiplications needed for color conversion. + * At typical sampling ratios, this eliminates half or three-quarters + * of the multiplications needed for color conversion. * * This file currently provides implementations for the following cases: * YCC => RGB color conversion only (YCbCr or BG_YCC). * Sampling ratios of 2h1v or 2h2v. * No scaling needed at upsample time. * Corner-aligned (non-CCIR601) sampling alignment. - * Other special cases could be added, but in most applications these are - * the only common cases. (For uncommon cases we fall back on the more - * general code in jdsample.c and jdcolor.c.) + * Other special cases could be added, but in most applications these + * are the only common cases. (For uncommon cases we fall back on + * the more general code in jdsample.c and jdcolor.c.) */ #define JPEG_INTERNALS @@ -286,9 +286,9 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, /* Do the chroma part of the calculation */ cb = GETJSAMPLE(*inptr1++); cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); cblue = Cbbtab[cb]; + cred = Crrtab[cr]; /* Fetch 2 Y values and emit 2 pixels */ y = GETJSAMPLE(*inptr0++); outptr[RGB_RED] = range_limit[y + cred]; @@ -303,15 +303,14 @@ h2v1_merged_upsample (j_decompress_ptr cinfo, } /* If image width is odd, do the last output column separately */ if (cinfo->output_width & 1) { + y = GETJSAMPLE(*inptr0); cb = GETJSAMPLE(*inptr1); cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - y = GETJSAMPLE(*inptr0); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; } } @@ -350,9 +349,9 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, /* Do the chroma part of the calculation */ cb = GETJSAMPLE(*inptr1++); cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); cblue = Cbbtab[cb]; + cred = Crrtab[cr]; /* Fetch 4 Y values and emit 4 pixels */ y = GETJSAMPLE(*inptr00++); outptr0[RGB_RED] = range_limit[y + cred]; @@ -379,9 +378,9 @@ h2v2_merged_upsample (j_decompress_ptr cinfo, if (cinfo->output_width & 1) { cb = GETJSAMPLE(*inptr1); cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); cblue = Cbbtab[cb]; + cred = Crrtab[cr]; y = GETJSAMPLE(*inptr00); outptr0[RGB_RED] = range_limit[y + cred]; outptr0[RGB_GREEN] = range_limit[y + cgreen]; diff --git a/vendor/jpeg-9e/jdpostct.c b/vendor/jpeg-9f/jdpostct.c similarity index 100% rename from vendor/jpeg-9e/jdpostct.c rename to vendor/jpeg-9f/jdpostct.c diff --git a/vendor/jpeg-9e/jdsample.c b/vendor/jpeg-9f/jdsample.c similarity index 100% rename from vendor/jpeg-9e/jdsample.c rename to vendor/jpeg-9f/jdsample.c diff --git a/vendor/jpeg-9e/jdtrans.c b/vendor/jpeg-9f/jdtrans.c similarity index 100% rename from vendor/jpeg-9e/jdtrans.c rename to vendor/jpeg-9f/jdtrans.c diff --git a/vendor/jpeg-9e/jerror.c b/vendor/jpeg-9f/jerror.c similarity index 100% rename from vendor/jpeg-9e/jerror.c rename to vendor/jpeg-9f/jerror.c diff --git a/vendor/jpeg-9e/jerror.h b/vendor/jpeg-9f/jerror.h similarity index 100% rename from vendor/jpeg-9e/jerror.h rename to vendor/jpeg-9f/jerror.h diff --git a/vendor/jpeg-9e/jfdctflt.c b/vendor/jpeg-9f/jfdctflt.c similarity index 100% rename from vendor/jpeg-9e/jfdctflt.c rename to vendor/jpeg-9f/jfdctflt.c diff --git a/vendor/jpeg-9e/jfdctfst.c b/vendor/jpeg-9f/jfdctfst.c similarity index 100% rename from vendor/jpeg-9e/jfdctfst.c rename to vendor/jpeg-9f/jfdctfst.c diff --git a/vendor/jpeg-9e/jfdctint.c b/vendor/jpeg-9f/jfdctint.c similarity index 100% rename from vendor/jpeg-9e/jfdctint.c rename to vendor/jpeg-9f/jfdctint.c diff --git a/vendor/jpeg-9e/jidctflt.c b/vendor/jpeg-9f/jidctflt.c similarity index 100% rename from vendor/jpeg-9e/jidctflt.c rename to vendor/jpeg-9f/jidctflt.c diff --git a/vendor/jpeg-9e/jidctfst.c b/vendor/jpeg-9f/jidctfst.c similarity index 100% rename from vendor/jpeg-9e/jidctfst.c rename to vendor/jpeg-9f/jidctfst.c diff --git a/vendor/jpeg-9e/jidctint.c b/vendor/jpeg-9f/jidctint.c similarity index 100% rename from vendor/jpeg-9e/jidctint.c rename to vendor/jpeg-9f/jidctint.c diff --git a/vendor/jpeg-9e/jinclude.h b/vendor/jpeg-9f/jinclude.h similarity index 57% rename from vendor/jpeg-9e/jinclude.h rename to vendor/jpeg-9f/jinclude.h index 20ed4ef11f..12ea8cd2fd 100644 --- a/vendor/jpeg-9e/jinclude.h +++ b/vendor/jpeg-9f/jinclude.h @@ -2,7 +2,7 @@ * jinclude.h * * Copyright (C) 1991-1994, Thomas G. Lane. - * Modified 2017 by Guido Vollbeding. + * Modified 2017-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -11,8 +11,8 @@ * care of by the standard jconfig symbols, but on really weird systems * you may have to edit this file.) * - * NOTE: this file is NOT intended to be included by applications using the - * JPEG library. Most applications need only include jpeglib.h. + * NOTE: this file is NOT intended to be included by applications using + * the JPEG library. Most applications need only include jpeglib.h. */ @@ -87,11 +87,71 @@ * * Furthermore, macros are provided for fflush() and ferror() in order * to facilitate adaption by applications using an own FILE class. + * + * You can define your own custom file I/O functions in jconfig.h and + * #define JPEG_HAVE_FILE_IO_CUSTOM there to prevent redefinition here. + * + * You can #define JPEG_USE_FILE_IO_CUSTOM in jconfig.h to use custom file + * I/O functions implemented in Delphi VCL (Visual Component Library) + * in Vcl.Imaging.jpeg.pas for the TJPEGImage component utilizing + * the Delphi RTL (Run-Time Library) TMemoryStream component: + * + * procedure jpeg_stdio_src(var cinfo: jpeg_decompress_struct; + * input_file: TStream); external; + * + * procedure jpeg_stdio_dest(var cinfo: jpeg_compress_struct; + * output_file: TStream); external; + * + * function jfread(var buf; recsize, reccount: Integer; S: TStream): Integer; + * begin + * Result := S.Read(buf, recsize * reccount); + * end; + * + * function jfwrite(const buf; recsize, reccount: Integer; S: TStream): Integer; + * begin + * Result := S.Write(buf, recsize * reccount); + * end; + * + * function jfflush(S: TStream): Integer; + * begin + * Result := 0; + * end; + * + * function jferror(S: TStream): Integer; + * begin + * Result := 0; + * end; + * + * TMemoryStream of Delphi RTL has the distinctive feature to provide dynamic + * memory buffer management with a file/stream-based interface, particularly for + * the write (output) operation, which is easier to apply compared with direct + * implementations as given in jdatadst.c for memory destination. Those direct + * implementations of dynamic memory write tend to be more difficult to use, + * so providing an option like TMemoryStream may be a useful alternative. + * + * The CFile/CMemFile classes of the Microsoft Foundation Class (MFC) Library + * may be used in a similar fashion. */ +#ifndef JPEG_HAVE_FILE_IO_CUSTOM +#ifdef JPEG_USE_FILE_IO_CUSTOM +extern size_t jfread(void * __ptr, size_t __size, size_t __n, FILE * __stream); +extern size_t jfwrite(const void * __ptr, size_t __size, size_t __n, FILE * __stream); +extern int jfflush(FILE * __stream); +extern int jferror(FILE * __fp); + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) jfread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) jfwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFFLUSH(file) jfflush(file) +#define JFERROR(file) jferror(file) +#else #define JFREAD(file,buf,sizeofbuf) \ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFWRITE(file,buf,sizeofbuf) \ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFFLUSH(file) fflush(file) #define JFERROR(file) ferror(file) +#endif +#endif diff --git a/vendor/jpeg-9e/jmemansi.c b/vendor/jpeg-9f/jmemansi.c similarity index 100% rename from vendor/jpeg-9e/jmemansi.c rename to vendor/jpeg-9f/jmemansi.c diff --git a/vendor/jpeg-9e/jmemdos.c b/vendor/jpeg-9f/jmemdos.c similarity index 100% rename from vendor/jpeg-9e/jmemdos.c rename to vendor/jpeg-9f/jmemdos.c diff --git a/vendor/jpeg-9e/jmemmac.c b/vendor/jpeg-9f/jmemmac.c similarity index 100% rename from vendor/jpeg-9e/jmemmac.c rename to vendor/jpeg-9f/jmemmac.c diff --git a/vendor/jpeg-9e/jmemmgr.c b/vendor/jpeg-9f/jmemmgr.c similarity index 100% rename from vendor/jpeg-9e/jmemmgr.c rename to vendor/jpeg-9f/jmemmgr.c diff --git a/vendor/jpeg-9e/jmemname.c b/vendor/jpeg-9f/jmemname.c similarity index 100% rename from vendor/jpeg-9e/jmemname.c rename to vendor/jpeg-9f/jmemname.c diff --git a/vendor/jpeg-9e/jmemnobs.c b/vendor/jpeg-9f/jmemnobs.c similarity index 100% rename from vendor/jpeg-9e/jmemnobs.c rename to vendor/jpeg-9f/jmemnobs.c diff --git a/vendor/jpeg-9e/jmemsys.h b/vendor/jpeg-9f/jmemsys.h similarity index 100% rename from vendor/jpeg-9e/jmemsys.h rename to vendor/jpeg-9f/jmemsys.h diff --git a/vendor/jpeg-9e/jmorecfg.h b/vendor/jpeg-9f/jmorecfg.h similarity index 94% rename from vendor/jpeg-9e/jmorecfg.h rename to vendor/jpeg-9f/jmorecfg.h index 679d68bdc5..4638d6af2d 100644 --- a/vendor/jpeg-9e/jmorecfg.h +++ b/vendor/jpeg-9f/jmorecfg.h @@ -2,7 +2,7 @@ * jmorecfg.h * * Copyright (C) 1991-1997, Thomas G. Lane. - * Modified 1997-2013 by Guido Vollbeding. + * Modified 1997-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -351,8 +351,8 @@ typedef enum { FALSE = 0, TRUE = 1 } boolean; #define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ #define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN) */ +#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW) */ #define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ /* Note: if you selected more than 8-bit data precision, it is dangerous to * turn off ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only @@ -369,8 +369,8 @@ typedef enum { FALSE = 0, TRUE = 1 } boolean; #define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ #define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? (Requires DCT_ISLOW)*/ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? (Requires DCT_ISLOW) */ #define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ #define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ #undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ @@ -384,20 +384,31 @@ typedef enum { FALSE = 0, TRUE = 1 } boolean; /* * Ordering of RGB data in scanlines passed to or from the application. * If your application wants to deal with data in the order B,G,R, just - * change these macros. You can also deal with formats such as R,G,B,X - * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing - * the offsets will also change the order in which colormap data is organized. + * #define JPEG_USE_RGB_CUSTOM in jconfig.h, or define your own custom + * order in jconfig.h and #define JPEG_HAVE_RGB_CUSTOM. + * You can also deal with formats such as R,G,B,X (one extra byte per pixel) + * by changing RGB_PIXELSIZE. + * Note that changing the offsets will also change + * the order in which colormap data is organized. * RESTRICTIONS: * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE - * is not 3 (they don't understand about dummy color components!). So you - * can't use color quantization if you change that value. + * is not 3 (they don't understand about dummy color components!). + * So you can't use color quantization if you change that value. */ +#ifndef JPEG_HAVE_RGB_CUSTOM +#ifdef JPEG_USE_RGB_CUSTOM +#define RGB_RED 2 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 0 /* Offset of Blue */ +#else #define RGB_RED 0 /* Offset of Red in an RGB scanline element */ #define RGB_GREEN 1 /* Offset of Green */ #define RGB_BLUE 2 /* Offset of Blue */ +#endif #define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ +#endif /* Definitions for speed-related optimizations. */ diff --git a/vendor/jpeg-9e/jpegint.h b/vendor/jpeg-9f/jpegint.h similarity index 100% rename from vendor/jpeg-9e/jpegint.h rename to vendor/jpeg-9f/jpegint.h diff --git a/vendor/jpeg-9e/jpeglib.h b/vendor/jpeg-9f/jpeglib.h similarity index 99% rename from vendor/jpeg-9e/jpeglib.h rename to vendor/jpeg-9f/jpeglib.h index b1fa8ea9ad..e7e15ab2cd 100644 --- a/vendor/jpeg-9e/jpeglib.h +++ b/vendor/jpeg-9f/jpeglib.h @@ -2,7 +2,7 @@ * jpeglib.h * * Copyright (C) 1991-1998, Thomas G. Lane. - * Modified 2002-2020 by Guido Vollbeding. + * Modified 2002-2022 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -39,7 +39,7 @@ extern "C" { #define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ #define JPEG_LIB_VERSION_MAJOR 9 -#define JPEG_LIB_VERSION_MINOR 5 +#define JPEG_LIB_VERSION_MINOR 6 /* Various constants determining the sizes of things. diff --git a/vendor/jpeg-9e/jpegtran.c b/vendor/jpeg-9f/jpegtran.c similarity index 100% rename from vendor/jpeg-9e/jpegtran.c rename to vendor/jpeg-9f/jpegtran.c diff --git a/vendor/jpeg-9e/jquant1.c b/vendor/jpeg-9f/jquant1.c similarity index 100% rename from vendor/jpeg-9e/jquant1.c rename to vendor/jpeg-9f/jquant1.c diff --git a/vendor/jpeg-9e/jquant2.c b/vendor/jpeg-9f/jquant2.c similarity index 100% rename from vendor/jpeg-9e/jquant2.c rename to vendor/jpeg-9f/jquant2.c diff --git a/vendor/jpeg-9e/jutils.c b/vendor/jpeg-9f/jutils.c similarity index 100% rename from vendor/jpeg-9e/jutils.c rename to vendor/jpeg-9f/jutils.c diff --git a/vendor/jpeg-9e/jversion.h b/vendor/jpeg-9f/jversion.h similarity index 59% rename from vendor/jpeg-9e/jversion.h rename to vendor/jpeg-9f/jversion.h index 17134b7a5b..df53ef5e55 100644 --- a/vendor/jpeg-9e/jversion.h +++ b/vendor/jpeg-9f/jversion.h @@ -1,7 +1,7 @@ /* * jversion.h * - * Copyright (C) 1991-2022, Thomas G. Lane, Guido Vollbeding. + * Copyright (C) 1991-2024, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -9,6 +9,6 @@ */ -#define JVERSION "9e 16-Jan-2022" +#define JVERSION "9f 14-Jan-2024" -#define JCOPYRIGHT "Copyright (C) 2022, Thomas G. Lane, Guido Vollbeding" +#define JCOPYRIGHT "Copyright (C) 2024, Thomas G. Lane, Guido Vollbeding" diff --git a/vendor/jpeg-9e/premake5.lua b/vendor/jpeg-9f/premake5.lua similarity index 100% rename from vendor/jpeg-9e/premake5.lua rename to vendor/jpeg-9f/premake5.lua diff --git a/vendor/jpeg-9e/rdbmp.c b/vendor/jpeg-9f/rdbmp.c similarity index 100% rename from vendor/jpeg-9e/rdbmp.c rename to vendor/jpeg-9f/rdbmp.c diff --git a/vendor/jpeg-9e/rdcolmap.c b/vendor/jpeg-9f/rdcolmap.c similarity index 100% rename from vendor/jpeg-9e/rdcolmap.c rename to vendor/jpeg-9f/rdcolmap.c diff --git a/vendor/jpeg-9e/rdgif.c b/vendor/jpeg-9f/rdgif.c similarity index 100% rename from vendor/jpeg-9e/rdgif.c rename to vendor/jpeg-9f/rdgif.c diff --git a/vendor/jpeg-9e/rdjpgcom.c b/vendor/jpeg-9f/rdjpgcom.c similarity index 100% rename from vendor/jpeg-9e/rdjpgcom.c rename to vendor/jpeg-9f/rdjpgcom.c diff --git a/vendor/jpeg-9e/rdppm.c b/vendor/jpeg-9f/rdppm.c similarity index 100% rename from vendor/jpeg-9e/rdppm.c rename to vendor/jpeg-9f/rdppm.c diff --git a/vendor/jpeg-9e/rdrle.c b/vendor/jpeg-9f/rdrle.c similarity index 100% rename from vendor/jpeg-9e/rdrle.c rename to vendor/jpeg-9f/rdrle.c diff --git a/vendor/jpeg-9e/rdswitch.c b/vendor/jpeg-9f/rdswitch.c similarity index 100% rename from vendor/jpeg-9e/rdswitch.c rename to vendor/jpeg-9f/rdswitch.c diff --git a/vendor/jpeg-9e/rdtarga.c b/vendor/jpeg-9f/rdtarga.c similarity index 100% rename from vendor/jpeg-9e/rdtarga.c rename to vendor/jpeg-9f/rdtarga.c diff --git a/vendor/jpeg-9e/transupp.c b/vendor/jpeg-9f/transupp.c similarity index 99% rename from vendor/jpeg-9e/transupp.c rename to vendor/jpeg-9f/transupp.c index 6d7d090234..6518936a0d 100644 --- a/vendor/jpeg-9e/transupp.c +++ b/vendor/jpeg-9f/transupp.c @@ -1,7 +1,7 @@ /* * transupp.c * - * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. + * Copyright (C) 1997-2023, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * @@ -195,12 +195,11 @@ requant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) { JDIMENSION blk_x, blk_y; - int offset_y, k; + int offset_y, k, temp, qval; JQUANT_TBL *qtblptr; JBLOCKARRAY buffer; JBLOCKROW block; JCOEFPTR ptr; - JCOEF temp, qval; qtblptr = compptr->quant_table; for (blk_y = 0; blk_y < compptr->height_in_blocks; @@ -213,27 +212,27 @@ requant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr, for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { ptr = block[blk_x]; for (k = 0; k < DCTSIZE2; k++) { - temp = qtblptr->quantval[k]; qval = qtblptr1->quantval[k]; - if (temp != qval) { - temp *= ptr[k]; - /* The following quantization code is a copy from jcdctmgr.c */ + if (qval == 0) continue; + temp = qtblptr->quantval[k]; + if (temp == qval) continue; + temp *= ptr[k]; + /* The following quantization code is a copy from jcdctmgr.c */ #ifdef FAST_DIVIDE #define DIVIDE_BY(a,b) a /= b #else #define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 #endif - if (temp < 0) { - temp = -temp; - temp += qval>>1; /* for rounding */ - DIVIDE_BY(temp, qval); - temp = -temp; - } else { - temp += qval>>1; /* for rounding */ - DIVIDE_BY(temp, qval); - } - ptr[k] = temp; + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); } + ptr[k] = (JCOEF) temp; } } } @@ -248,11 +247,11 @@ largest_common_denominator(JCOEF a, JCOEF b) { JCOEF c; - do { + while (b) { c = a % b; a = b; b = c; - } while (c); + } return a; } diff --git a/vendor/jpeg-9e/transupp.h b/vendor/jpeg-9f/transupp.h similarity index 100% rename from vendor/jpeg-9e/transupp.h rename to vendor/jpeg-9f/transupp.h diff --git a/vendor/jpeg-9e/wrbmp.c b/vendor/jpeg-9f/wrbmp.c similarity index 100% rename from vendor/jpeg-9e/wrbmp.c rename to vendor/jpeg-9f/wrbmp.c diff --git a/vendor/jpeg-9e/wrgif.c b/vendor/jpeg-9f/wrgif.c similarity index 100% rename from vendor/jpeg-9e/wrgif.c rename to vendor/jpeg-9f/wrgif.c diff --git a/vendor/jpeg-9e/wrjpgcom.c b/vendor/jpeg-9f/wrjpgcom.c similarity index 100% rename from vendor/jpeg-9e/wrjpgcom.c rename to vendor/jpeg-9f/wrjpgcom.c diff --git a/vendor/jpeg-9e/wrppm.c b/vendor/jpeg-9f/wrppm.c similarity index 100% rename from vendor/jpeg-9e/wrppm.c rename to vendor/jpeg-9f/wrppm.c diff --git a/vendor/jpeg-9e/wrrle.c b/vendor/jpeg-9f/wrrle.c similarity index 100% rename from vendor/jpeg-9e/wrrle.c rename to vendor/jpeg-9f/wrrle.c diff --git a/vendor/jpeg-9e/wrtarga.c b/vendor/jpeg-9f/wrtarga.c similarity index 100% rename from vendor/jpeg-9e/wrtarga.c rename to vendor/jpeg-9f/wrtarga.c From 7830635f594c3ebdddfa244458d58429c2f43f5e Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Fri, 21 Jun 2024 20:43:23 +0200 Subject: [PATCH 13/23] Update nvapi to r550 --- vendor/nvapi/NvApiDriverSettings.c | 36 +- vendor/nvapi/NvApiDriverSettings.h | 49 +- vendor/nvapi/amd64/nvapi64.lib | Bin 893264 -> 921630 bytes vendor/nvapi/nvHLSLExtns.h | 117 +++ vendor/nvapi/nvShaderExtnEnums.h | 9 + vendor/nvapi/nvapi.h | 1147 +++++++++++++++++++++++++++- vendor/nvapi/nvapi_lite_common.h | 11 +- vendor/nvapi/nvapi_lite_surround.h | 10 +- vendor/nvapi/x86/nvapi.lib | Bin 398256 -> 409742 bytes 9 files changed, 1343 insertions(+), 36 deletions(-) diff --git a/vendor/nvapi/NvApiDriverSettings.c b/vendor/nvapi/NvApiDriverSettings.c index 2fb52dd755..ea117a30cc 100644 --- a/vendor/nvapi/NvApiDriverSettings.c +++ b/vendor/nvapi/NvApiDriverSettings.c @@ -148,13 +148,6 @@ EValues_OGL_SINGLE_BACKDEPTH_BUFFER g_valuesOGL_SINGLE_BACKDEPTH_BUFFER[OGL_SING OGL_SINGLE_BACKDEPTH_BUFFER_USE_HW_DEFAULT, }; -EValues_OGL_SLI_CFR_MODE g_valuesOGL_SLI_CFR_MODE[OGL_SLI_CFR_MODE_NUM_VALUES] = -{ - OGL_SLI_CFR_MODE_DISABLE, - OGL_SLI_CFR_MODE_ENABLE, - OGL_SLI_CFR_MODE_CLASSIC_SFR, -}; - EValues_OGL_SLI_MULTICAST g_valuesOGL_SLI_MULTICAST[OGL_SLI_MULTICAST_NUM_VALUES] = { OGL_SLI_MULTICAST_DISABLE, @@ -775,6 +768,30 @@ EValues_PS_SHADERDISKCACHE g_valuesPS_SHADERDISKCACHE[PS_SHADERDISKCACHE_NUM_VAL PS_SHADERDISKCACHE_ON, }; +EValues_PS_SHADERDISKCACHE_FLAGS g_valuesPS_SHADERDISKCACHE_FLAGS[PS_SHADERDISKCACHE_FLAGS_NUM_VALUES] = +{ + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEFAULT_COMPILES, + PS_SHADERDISKCACHE_FLAGS_DISABLE_OPTIONAL_COMPILES, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DRIVER_VERSIONING, + PS_SHADERDISKCACHE_FLAGS_DUMP_HISTOGRAM, + PS_SHADERDISKCACHE_FLAGS_DUMP_TIMELINE, + PS_SHADERDISKCACHE_FLAGS_DISABLE_GARBAGE_COLLECTION, + PS_SHADERDISKCACHE_FLAGS_ENABLE_ENCRYPTION, + PS_SHADERDISKCACHE_FLAGS_DISABLE_CRC, + PS_SHADERDISKCACHE_FLAGS_ENABLE_STATS_FILES, + PS_SHADERDISKCACHE_FLAGS_DISABLE_STATS_RESET, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEBUG_FORCED_COMPILE, + PS_SHADERDISKCACHE_FLAGS_NO_COMPRESSION, + PS_SHADERDISKCACHE_FLAGS_RLE_COMPRESSION, + PS_SHADERDISKCACHE_FLAGS_LZMA_COMPRESSION, + PS_SHADERDISKCACHE_FLAGS_BACKEND_MEM_MAP_FILES, + PS_SHADERDISKCACHE_FLAGS_BACKEND_DLL, + PS_SHADERDISKCACHE_FLAGS_FLOOD_CACHE_DIRECTORY, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEDUPLICATION, + PS_SHADERDISKCACHE_FLAGS_DELETE_PERFECT_CACHES, + PS_SHADERDISKCACHE_FLAGS_ALL_BUILDS_MISMATCH_TEST, +}; + EValues_PS_SHADERDISKCACHE_MAX_SIZE g_valuesPS_SHADERDISKCACHE_MAX_SIZE[PS_SHADERDISKCACHE_MAX_SIZE_NUM_VALUES] = { PS_SHADERDISKCACHE_MAX_SIZE_MIN, @@ -878,7 +895,6 @@ SettingDWORDNameString mapSettingDWORD[TOTAL_DWORD_SETTING_NUM] = {OGL_OVERLAY_SUPPORT_ID, OGL_OVERLAY_SUPPORT_STRING, 3, (NvU32 *)g_valuesOGL_OVERLAY_SUPPORT, OGL_OVERLAY_SUPPORT_OFF}, {OGL_QUALITY_ENHANCEMENTS_ID, OGL_QUALITY_ENHANCEMENTS_STRING, 4, (NvU32 *)g_valuesOGL_QUALITY_ENHANCEMENTS, OGL_QUALITY_ENHANCEMENTS_QUAL}, {OGL_SINGLE_BACKDEPTH_BUFFER_ID, OGL_SINGLE_BACKDEPTH_BUFFER_STRING, 3, (NvU32 *)g_valuesOGL_SINGLE_BACKDEPTH_BUFFER, OGL_SINGLE_BACKDEPTH_BUFFER_DISABLE}, - {OGL_SLI_CFR_MODE_ID, OGL_SLI_CFR_MODE_STRING, 3, (NvU32 *)g_valuesOGL_SLI_CFR_MODE, OGL_SLI_CFR_MODE_DISABLE}, {OGL_SLI_MULTICAST_ID, OGL_SLI_MULTICAST_STRING, 4, (NvU32 *)g_valuesOGL_SLI_MULTICAST, OGL_SLI_MULTICAST_DISABLE}, {OGL_THREAD_CONTROL_ID, OGL_THREAD_CONTROL_STRING, 2, (NvU32 *)g_valuesOGL_THREAD_CONTROL, 0x00000000}, {OGL_TMON_LEVEL_ID, OGL_TMON_LEVEL_STRING, 6, (NvU32 *)g_valuesOGL_TMON_LEVEL, OGL_TMON_LEVEL_MOST}, @@ -895,6 +911,8 @@ SettingDWORDNameString mapSettingDWORD[TOTAL_DWORD_SETTING_NUM] = {ANSEL_ALLOW_ID, ANSEL_ALLOW_STRING, 2, (NvU32 *)g_valuesANSEL_ALLOW, ANSEL_ALLOW_ALLOWED}, {ANSEL_ALLOWLISTED_ID, ANSEL_ALLOWLISTED_STRING, 2, (NvU32 *)g_valuesANSEL_ALLOWLISTED, ANSEL_ALLOWLISTED_DISALLOWED}, {ANSEL_ENABLE_ID, ANSEL_ENABLE_STRING, 2, (NvU32 *)g_valuesANSEL_ENABLE, ANSEL_ENABLE_ON}, + {APPIDLE_DYNAMIC_FRL_FPS_ID, APPIDLE_DYNAMIC_FRL_FPS_STRING, 0, NULL, 0x00000000}, + {APPIDLE_DYNAMIC_FRL_THRESHOLD_TIME_ID, APPIDLE_DYNAMIC_FRL_THRESHOLD_TIME_STRING, 0, NULL, 0x00000000}, {APPLICATION_PROFILE_NOTIFICATION_TIMEOUT_ID, APPLICATION_PROFILE_NOTIFICATION_TIMEOUT_STRING, 6, (NvU32 *)g_valuesAPPLICATION_PROFILE_NOTIFICATION_TIMEOUT, APPLICATION_PROFILE_NOTIFICATION_TIMEOUT_DISABLED}, {APPLICATION_STEAM_ID_ID, APPLICATION_STEAM_ID_STRING, 0, NULL, 0x00000000}, {BATTERY_BOOST_APP_FPS_ID, BATTERY_BOOST_APP_FPS_STRING, 3, (NvU32 *)g_valuesBATTERY_BOOST_APP_FPS, BATTERY_BOOST_APP_FPS_NO_OVERRIDE}, @@ -946,6 +964,7 @@ SettingDWORDNameString mapSettingDWORD[TOTAL_DWORD_SETTING_NUM] = {MAXWELL_B_SAMPLE_INTERLEAVE_ID, MAXWELL_B_SAMPLE_INTERLEAVE_STRING, 2, (NvU32 *)g_valuesMAXWELL_B_SAMPLE_INTERLEAVE, MAXWELL_B_SAMPLE_INTERLEAVE_OFF}, {PRERENDERLIMIT_ID, PRERENDERLIMIT_STRING, 3, (NvU32 *)g_valuesPRERENDERLIMIT, PRERENDERLIMIT_APP_CONTROLLED}, {PS_SHADERDISKCACHE_ID, PS_SHADERDISKCACHE_STRING, 2, (NvU32 *)g_valuesPS_SHADERDISKCACHE, PS_SHADERDISKCACHE_ON}, + {PS_SHADERDISKCACHE_FLAGS_ID, PS_SHADERDISKCACHE_FLAGS_STRING, 20, (NvU32 *)g_valuesPS_SHADERDISKCACHE_FLAGS, 0x00000000}, {PS_SHADERDISKCACHE_MAX_SIZE_ID, PS_SHADERDISKCACHE_MAX_SIZE_STRING, 2, (NvU32 *)g_valuesPS_SHADERDISKCACHE_MAX_SIZE, 0x00000000}, {PS_TEXFILTER_ANISO_OPTS2_ID, PS_TEXFILTER_ANISO_OPTS2_STRING, 2, (NvU32 *)g_valuesPS_TEXFILTER_ANISO_OPTS2, PS_TEXFILTER_ANISO_OPTS2_OFF}, {PS_TEXFILTER_BILINEAR_IN_ANISO_ID, PS_TEXFILTER_BILINEAR_IN_ANISO_STRING, 2, (NvU32 *)g_valuesPS_TEXFILTER_BILINEAR_IN_ANISO, PS_TEXFILTER_BILINEAR_IN_ANISO_OFF}, @@ -966,5 +985,6 @@ SettingWSTRINGNameString mapSettingWSTRING[TOTAL_WSTRING_SETTING_NUM] = {CUDA_EXCLUDED_GPUS_ID, CUDA_EXCLUDED_GPUS_STRING, 1, (const wchar_t **)g_valuesCUDA_EXCLUDED_GPUS, L"none"}, {D3DOGL_GPU_MAX_POWER_ID, D3DOGL_GPU_MAX_POWER_STRING, 1, (const wchar_t **)g_valuesD3DOGL_GPU_MAX_POWER, L"0"}, {ICAFE_LOGO_CONFIG_ID, ICAFE_LOGO_CONFIG_STRING, 0, NULL, L""}, + {PS_SHADERDISKCACHE_DLL_PATH_WCHAR_ID, PS_SHADERDISKCACHE_DLL_PATH_WCHAR_STRING, 0, NULL, L""}, }; diff --git a/vendor/nvapi/NvApiDriverSettings.h b/vendor/nvapi/NvApiDriverSettings.h index 100f9c8faa..08e8ddc331 100644 --- a/vendor/nvapi/NvApiDriverSettings.h +++ b/vendor/nvapi/NvApiDriverSettings.h @@ -57,7 +57,6 @@ #define OGL_OVERLAY_SUPPORT_STRING L"Enable overlay" #define OGL_QUALITY_ENHANCEMENTS_STRING L"High level control of the rendering quality on OpenGL" #define OGL_SINGLE_BACKDEPTH_BUFFER_STRING L"Unified back/depth buffer" -#define OGL_SLI_CFR_MODE_STRING L"Set CFR mode" #define OGL_SLI_MULTICAST_STRING L"Enable NV_gpu_multicast extension" #define OGL_THREAD_CONTROL_STRING L"Threaded optimization" #define OGL_TMON_LEVEL_STRING L"Event Log Tmon Severity Threshold" @@ -74,6 +73,8 @@ #define ANSEL_ALLOW_STRING L"NVIDIA Predefined Ansel Usage" #define ANSEL_ALLOWLISTED_STRING L"Ansel flags for enabled applications" #define ANSEL_ENABLE_STRING L"Enable Ansel" +#define APPIDLE_DYNAMIC_FRL_FPS_STRING L"Idle Application Max FPS Limit" +#define APPIDLE_DYNAMIC_FRL_THRESHOLD_TIME_STRING L"Idle Application Threshold Time out in seconds" #define APPLICATION_PROFILE_NOTIFICATION_TIMEOUT_STRING L"Application Profile Notification Popup Timeout" #define APPLICATION_STEAM_ID_STRING L"Steam Application ID" #define BATTERY_BOOST_APP_FPS_STRING L"Battery Boost Application FPS" @@ -128,6 +129,8 @@ #define MAXWELL_B_SAMPLE_INTERLEAVE_STRING L"Enable sample interleaving (MFAA)" #define PRERENDERLIMIT_STRING L"Maximum pre-rendered frames" #define PS_SHADERDISKCACHE_STRING L"Shader Cache" +#define PS_SHADERDISKCACHE_DLL_PATH_WCHAR_STRING L"shader cache path to dll" +#define PS_SHADERDISKCACHE_FLAGS_STRING L"shader cache control flags" #define PS_SHADERDISKCACHE_MAX_SIZE_STRING L"Shader disk cache maximum size" #define PS_TEXFILTER_ANISO_OPTS2_STRING L"Texture filtering - Anisotropic sample optimization" #define PS_TEXFILTER_BILINEAR_IN_ANISO_STRING L"Texture filtering - Anisotropic filter optimization" @@ -159,7 +162,6 @@ enum ESetting { OGL_OVERLAY_SUPPORT_ID = 0x206C28C4, OGL_QUALITY_ENHANCEMENTS_ID = 0x20797D6C, OGL_SINGLE_BACKDEPTH_BUFFER_ID = 0x20A29055, - OGL_SLI_CFR_MODE_ID = 0x20343843, OGL_SLI_MULTICAST_ID = 0x2092D3BE, OGL_THREAD_CONTROL_ID = 0x20C1221E, OGL_TMON_LEVEL_ID = 0x202888C1, @@ -176,6 +178,8 @@ enum ESetting { ANSEL_ALLOW_ID = 0x1035DB89, ANSEL_ALLOWLISTED_ID = 0x1085DA8A, ANSEL_ENABLE_ID = 0x1075D972, + APPIDLE_DYNAMIC_FRL_FPS_ID = 0x10835016, + APPIDLE_DYNAMIC_FRL_THRESHOLD_TIME_ID = 0x10835017, APPLICATION_PROFILE_NOTIFICATION_TIMEOUT_ID = 0x104554B6, APPLICATION_STEAM_ID_ID = 0x107CDDBC, BATTERY_BOOST_APP_FPS_ID = 0x10115C8C, @@ -230,6 +234,8 @@ enum ESetting { MAXWELL_B_SAMPLE_INTERLEAVE_ID = 0x0098C1AC, PRERENDERLIMIT_ID = 0x007BA09E, PS_SHADERDISKCACHE_ID = 0x00198FFF, + PS_SHADERDISKCACHE_DLL_PATH_WCHAR_ID = 0x0019A002, + PS_SHADERDISKCACHE_FLAGS_ID = 0x00F4889B, PS_SHADERDISKCACHE_MAX_SIZE_ID = 0x00AC8497, PS_TEXFILTER_ANISO_OPTS2_ID = 0x00E73211, PS_TEXFILTER_BILINEAR_IN_ANISO_ID = 0x0084CD70, @@ -242,9 +248,9 @@ enum ESetting { SET_VAB_DATA_ID = 0x00AB8687, VSYNCMODE_ID = 0x00A879CF, VSYNCTEARCONTROL_ID = 0x005A375C, - TOTAL_DWORD_SETTING_NUM = 96, - TOTAL_WSTRING_SETTING_NUM = 4, - TOTAL_SETTING_NUM = 100, + TOTAL_DWORD_SETTING_NUM = 98, + TOTAL_WSTRING_SETTING_NUM = 5, + TOTAL_SETTING_NUM = 103, INVALID_SETTING_ID = 0xFFFFFFFF }; @@ -371,14 +377,6 @@ enum EValues_OGL_SINGLE_BACKDEPTH_BUFFER { OGL_SINGLE_BACKDEPTH_BUFFER_DEFAULT = OGL_SINGLE_BACKDEPTH_BUFFER_DISABLE }; -enum EValues_OGL_SLI_CFR_MODE { - OGL_SLI_CFR_MODE_DISABLE = 0x00, - OGL_SLI_CFR_MODE_ENABLE = 0x01, - OGL_SLI_CFR_MODE_CLASSIC_SFR = 0x02, - OGL_SLI_CFR_MODE_NUM_VALUES = 3, - OGL_SLI_CFR_MODE_DEFAULT = OGL_SLI_CFR_MODE_DISABLE -}; - enum EValues_OGL_SLI_MULTICAST { OGL_SLI_MULTICAST_DISABLE = 0x00, OGL_SLI_MULTICAST_ENABLE = 0x01, @@ -1056,6 +1054,31 @@ enum EValues_PS_SHADERDISKCACHE { PS_SHADERDISKCACHE_DEFAULT = PS_SHADERDISKCACHE_ON }; +enum EValues_PS_SHADERDISKCACHE_FLAGS { + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEFAULT_COMPILES = 0x00000001, + PS_SHADERDISKCACHE_FLAGS_DISABLE_OPTIONAL_COMPILES = 0x00000002, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DRIVER_VERSIONING = 0x00000008, + PS_SHADERDISKCACHE_FLAGS_DUMP_HISTOGRAM = 0x00000010, + PS_SHADERDISKCACHE_FLAGS_DUMP_TIMELINE = 0x00000020, + PS_SHADERDISKCACHE_FLAGS_DISABLE_GARBAGE_COLLECTION = 0x00000040, + PS_SHADERDISKCACHE_FLAGS_ENABLE_ENCRYPTION = 0x00000080, + PS_SHADERDISKCACHE_FLAGS_DISABLE_CRC = 0x00000100, + PS_SHADERDISKCACHE_FLAGS_ENABLE_STATS_FILES = 0x00000200, + PS_SHADERDISKCACHE_FLAGS_DISABLE_STATS_RESET = 0x00000400, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEBUG_FORCED_COMPILE = 0x00000800, + PS_SHADERDISKCACHE_FLAGS_NO_COMPRESSION = 0x00001000, + PS_SHADERDISKCACHE_FLAGS_RLE_COMPRESSION = 0x00002000, + PS_SHADERDISKCACHE_FLAGS_LZMA_COMPRESSION = 0x00004000, + PS_SHADERDISKCACHE_FLAGS_BACKEND_MEM_MAP_FILES = 0x00010000, + PS_SHADERDISKCACHE_FLAGS_BACKEND_DLL = 0x00020000, + PS_SHADERDISKCACHE_FLAGS_FLOOD_CACHE_DIRECTORY = 0x00100000, + PS_SHADERDISKCACHE_FLAGS_DISABLE_DEDUPLICATION = 0x00200000, + PS_SHADERDISKCACHE_FLAGS_DELETE_PERFECT_CACHES = 0x00400000, + PS_SHADERDISKCACHE_FLAGS_ALL_BUILDS_MISMATCH_TEST = 0x00800000, + PS_SHADERDISKCACHE_FLAGS_NUM_VALUES = 20, + PS_SHADERDISKCACHE_FLAGS_DEFAULT = 0x0 +}; + enum EValues_PS_SHADERDISKCACHE_MAX_SIZE { PS_SHADERDISKCACHE_MAX_SIZE_MIN = 0x0, PS_SHADERDISKCACHE_MAX_SIZE_MAX = 0xffffffff, diff --git a/vendor/nvapi/amd64/nvapi64.lib b/vendor/nvapi/amd64/nvapi64.lib index 9f3729abad3379f2d6f0bcd914ca589809ee2ba7..1483b30007d460e3bec9d258155b99d0359b26d6 100644 GIT binary patch literal 921630 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

FFPkC`Z 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 rRGg4kHO@O|w?a4qf%){T39yB_9N@523)b$NR% zhIvJu(Z^RXzo?UX%w>-`>8T?yIl^^~dbu!_>Wq5*VXjbT)Vm$#K6O%$$I&a^xE;jC z%DD=cuYkMp?x2sj+Pt8Txa02!m_NM>`;~Q>%RcjQo)wcLbVeWfFzwYzJ?1hH z=1O%&y*ptZP-oP84dzpIM!n52_3n{Aq#lo>qr73i99GU%xV$mkMsMSCE?a=VFN(<# z<|pei=Zj&+t26qz8|GnkQja;m3A0X}QLom$>8V{XIimKD^^S#Ur_QK%HcVf2vVY8Z zyf<8zBP!?X;M(68>|fmd{7#q$yo>6CIll(8TAk6ypD=aqPtK(w%t`8udL3c9tCL)K zKOgN4GvSEJWfEM)1If9}hPl_fxLjU_S*6bCV-rmJgUPuZ0@GZbQLh8cIqHmDMtKvY zV&}2}S5AZ*{!nr*%VFN}E-sg!VbUI!evLj3hB;21^uha4F-%u=M!k_R6Vw^?=6VyC z3*YxFhP!5AaxNdieCb_WF0~)Q_sB3gLTB{R6sDazqmQ#;E>dUIyAEciI;qF|`IFwb z9mFQ;e)KZjq(_r;Sq<}*cVWNAx^*7I_YN^RLTB{R3?@^Z)Z_8e6=sk+qu%u}x2ltR ze0*8#4fl^DDwkz&6CY2`Wfjcl-i7_jy1YHo7vb|6OpeeQeKdh-t4``Mmo6{^)EV_A z!^}`8^_a^dZ@7OPRxaysc@^B;CxSlWo{xTmNqbWIm35iR!7z>08GV$)oT*OgF_+;m zlhhgY7Qj5N&Zzf}Hz@6fl?&e|e+Bo{;^bU*dJ5;CF*&$(^<-V<(i|pFozX`Rm;vgf z9&?!tbB8*k-m@^Ts*`%$zpuT)k8W7GRN9^wAS$ zpgQS;xm*i#r#hqFb1<)|lX|=#ed7)L;E2lQH@GLCNzP@*XYo9P$q|=JQ7@jU*0C?-c-E^S~+ z)fs)94>L@i^ub)F!OT}@)LRC#LY-0XN0^MI(uYy+P?$#Qq#hrSOTA$(98o!+2Dfij za?XQcF83}j=i6ZJS7-F`D$M)pqz~r&E6k2BBhm-C*>@V!z@j?fu>WW$uJlRlX9g)pPl8TDqt zEKq0ETkeh9L2RsCHsSKsa4TO*&gHP>`2R7%$%oX0n<#IdBL+Xq^-hlZ~ozchd zFgw2*>|eO9QSTU-7V3<8r+E{kV&}rwSLeaCel0ndYhb2(7w(^|%j4xSm>1O<0`g-FEVq+aIe7`>e?z}gWb9n;h1@FTBGuHhK z=4W+AANAkF=PsBWQT3QhE0}V1M!gGRhO3kPW4)Wa;kq1FE<9cqz>Rti0z24wQH==TR3hvq!$+@h7`Nq4r zTvl|z&>4NSfXP-Teem`@7iNe$quvylS?Z)7b9veu?jMJhOBF7E4eq*kfw1mk~C-s<1H<+R7jCxaHW~-BWd_BIz8}1)RR4y;W zO?odmm(?&|c^CF8>+<%f^FGcGVRD4d=%X1-raGy|T)M&xQfJh=9_ChcQjfVT_J;e% zVdb(GmoI~x_d#+ln_$vcNx!l#b2$X2i8`Z?3YaeHq#kn_0W(>hQSV-uMe2-t?|OsM zZdkeG;`PhdaL0d?oXaSfiQa|Bfvn41=D{pdXY}zd%vyC)kGcE{(_ppS9!9+;Fm2Tt z^}2Wyq+%a0J(0@*xRoC#=W^H@yxzs+h|8r6=4^FFAD6<6S7-EbH_VgjjC$|GtW#&y ztMy6HLtHMrAMFMAo40X~yZN8ub1+PfxLgLpj8Fc=#x;VCbwA?g6(_;%_*qadE|<ZBfTw@Po~a^d~xT)0ENNzUaWm{H!v^M zaF{0Qq#o}_72YJ}(gkk+?~-%55N5b{ak<jX+v@@N5eE% zXVmKe(?^}Le^PKIn4#*7KBmIVRwwnC^Aec1)fx3R!2G37>T&<}{Ute<7vPSD``+8Q zT-yGM?}1`+#O2Zl=3;e5A2-6>p-%c>F3-ZORA+`~8-j3;+Gwk#GlZ z3T#|117Svb7njQ|FbmWfeJqE0N1gP+Tz-bB^Lwy=;krh>hA@rQ8THD&L1{Ov`%x9H z=?-`JAHlkDxeSFF<6XFavM!I)*)R{PGx~TPW|car$6PkS?DS`_f8n}Dy`y28tCM;> zUOIS#AKkEW;q&D=a1H+o){T3Wq44!3i0^WJd(IILXwx%1m_kN=yT zOPy3kY7b0~uwP@{#xR-cj6S-;oUcymF_#H2x2iMhErwa9&ZxKE8`lUnQMvpM_i?SD z-?-!D__U1F$(S5*xtsyhN1f5fRWLWGGx~TCrb?YrZ!OIC>Wq3jr3XE@MzFDR;rWAu z;C}QrE|<)Vj8rKmM_exF!(5`y=;LOXIqHl)mcqQJ&ZzebP3`3UJJ1`~2sTzOe4pG1 zZiBaRxwNa3kt)IDh|8rf%m{TxAJbv(QfK7yJj}c5jCvbk{#7US`22Rj4nYsD5p1kn z`1o=(+^%&48<$I0nDf1h%Vh%0&FYLk9*0?~PWs^E%cn5Es59#Av13N+KunIP{bRj0 z-Z+Sjl}i;auY_w*FFBVUFax}cT9=RalVNUCXY}zD%uDKwTt0{SL!D9YKRacl4#VV# z+CLsIS>8B^jg<>u50$~~v2#!_?)A`xFvGozT9>)p1T$Bi(Z>rgZ>ckK`2i+v7wOli zcQDLx>Wq5DFkRId^+v)>P$%_x|C;L!essginXiW)fE%-G^6~dJ%*Wov<@^`SPP--N zax_eHbMgWkAMu(5LC{dFqTl z#=%TcXY}z9%nRy_dY{4kpib)Xezf!6K@YAGY^?iH6)xW&?h|k0ayj8Y8L8Ho9C5jH zhUu%$=wm$0RCUq^??(^Ayr|Bow+?25I;qF!w_Wy0&V`S=`@((aZCoyG_RUBYVsgag z(i>)&I-`$iFt@9dKA6ihFe}s<^?ro;TbAa zOoW-C&gf$iOqDw6gSo7Q`Bj}!ufhHqse>>%qV|vV+Ir(4HrD-!uZK>B+xvi^Ufk=U zfiNSzi&~er$1N}m)ERv&hj~Yxk;~68bq4UjE1oMJAquysQKd6&>?)BA?$+_@##Qty_yp7AH-BCE-gvk+?OJA4~ z>Wn_7!`!7#`d}{4!@R4`sJ9X3Uv*NCxg2nGaxT0d9S`@Tw{f{-9)t6fm>hAroDXw} zI-`%9VdkilKA6i=nD^8f^?so_Hh%wjKRVDG_Q7F2zPQ&{aJwBB)QijI9GDBdi_2vq z%nWr#AB$kB)ET*~h51#TQLn-AczuP*5w(BJxve)2Vq@j94ws(_*Q`-;E?2@_?_Jco zJWd~gc}AVl$7-0b)ET+dIUytUUrdg0U8CMfFuCfCdfmNo1+lSm;p59NxT40%xy*pM z+q-c8WL@S`1+!9}(Z^3P|EQCCynXj;g6Ba@j&NP0UKvbhbyAP}cd<9FAU0Mm|E-0; z#{+lAiOISA1oMw~;r+<%P1aqr8qmRWf%hX9d=CU5VPjfa`4&ZzgWH`Os%xm4lG7vUzHoSe%CFzdaG%O$N9jz3I}&>4L+hH0bD z=;KV7{_2c+lVEOEC-wL|{kS)72eGko$;a`s6s~TYhZY$5atJUM!lWeW~BDPpL1WYS+M!iljJ=GaGU*Sz$E_|N839fHuaxPE8yy#tAF6&@6sx$i7 zJu4%1047INJ>I^pVJg%a_4>h#P$#+YcAM@E*X6K|7v?e#?vm`}TwZ~B&%3BTxb817 z89CCg(Z``MjnqjW%%v3OTy;jh%V4fnC-u00^S!~3ZdkeS`-xA$J)E1IORYRS&tP)I z<#H@cYjs8+ond;ZlRlWsSeWVRjCzm3Jg?5E_lY;I5p1Gz*$DStesV5t3UFQ?lOryd z-Y~<|8GTHHxm}&n$1^Z1)EV`Dg!x;YQSZNnK@YAGY@%{$1b1XnaxNFcjP))qmpfn{ zR%i6_Cd^0bj6VK=*`-)+52N0(FfG*?^-lLDDVM%*-Aj^lSqSrtcX7F_hWSpN(MP>f zd>(+w5mk@(qh>IL>Wq55VFsx)a=G3cw=gzQ$IBeJ+scx2`5xvE@1pwPX?FnM-?^ z?&^#_M#D@}C-r!|EP#1Nol$Q!%vb7+dUZ|>dSD+MRxbRzB>#omv3+tbond-;7njRe zn5pWFJ|2cyqR!~!BbW{9jC#9t$Vlyr$q}`G%(ggsW8{SmWi-qrbw<4f-o)kd4z7F#ZpxX-xqJrm zgLiSc?A#?IwLd0D=!`yE!Q`tm`sfKWT%A$xCYU?bNj=_f&w1l^5F6`w*$?lh--7%0 ztmIr;pPi8^z~l(~HP-C~GgO_?$5fcv>ZBfzmnAT7t263tfcZxPSP%2NI-}m+=i)pjCP&o%G3QKg9OQo+ z=P~)Xdm3C$x8z)=!p!zAYF!?uOJH7CXY}zc%qDe4E_-#y_b4zq!gY;$1uz}d8TBsm z#udcI%7xFY0(+8IvQb9&g`cU`|nI)H@62 zJaxwYjq}DWjE$8`6)wLCu5+*CT<(E+%)6*Qn9E9-b?S^hYW2qZK}?RQdd%fmn0D%n zdS}D*RVTUd{O)*fxGsm43(xOPgbOhH0+OsMo=pAQd|oe*dKp+({QE=Q06ins;%zEQDFA&gkP)nD5jXebnoR z_bHeh;krh>HZXeY|l6v5CrMFkFj)$+?V!nc`izf3hxbkB4BM zQ)l$C2Id=eQjfXRy$G+LF*(9@je4zM^3_Q_=F-y}R}dR37d}r9gv%L}oXb?0+1`cw zC+jkoB`~k6Gy3=zW|KOp$6WRrjMp!i9O1e~y#kmH>ZBg`?;>wpL2RsC__}Tk+`u8p zxjYB+ns?#;8S8!n^QStak9~$_q#9y!MAc(1*)Sc|8TE$1j8-T6$9l88;kq1FE_@%b z5N`Ug{5Jh36mo(mok{M)fs(U3Nv1v(Z}5|PpUKOy$`caoz&y) zR%>L?gKGpED;NI#_TAy?j!Mp@6HHI<;&QnHW{NtakB4BMRwsS%c=-_K2X#ihoiD@p z88A7b_K)>ic;g^8RxW&eDTX`Y^5k4Dhq=bPsC9XJ+ynEZI-`&GVb-ZLa;Y^sBefSM zN4Tz0uPIDBbw<6jy>SJxiOS_7xQ=6zbD0aX(7SN|WL@U+7R;yWj6OEQ)Vo6Zm3q8= zkAi8V&Zu`LOmB5Yy(_(m%cVKqAKeW1`q<=L4!9DpBQQDQaw&j0L!HsbP?$05j6P<= zJfhC1_cqMO>Wq4Sd6SgOZdc)Zuj7()nFe#acX7Eq1M`MDqmS=kephGovG@3l)G?S_ z-5y50LYULk8TAHv6PF9$PmhDUenN6CpTd0SU0g2pCgS-VGpUc0U~<(NeRPKzrq0M^ z8qDqLjC#*_6PF9$Pp^Qx>+0lOHp2YtU0f~)T$7PH9y2MI5|}g88GQ_enW)alWgg5U z>ZBeY|K9e-?I1SR<8Bo$Ukf*9QgSZ8&`g$ojdc%%X{65RqZFo-I;qFU-C;0St264& zhj~<;)Z_cc72e=SH>_Ovx^4~J!`CL~QtLXLcf{m~J6?{3X|2xaqccn|bxDB<9wK5>ZA|mG7VrFSas3| zbGZZNF?B}0l`x;EGwS^Vv->pZ!>D%xOlx&gkMEm0d&68fqH^vAcf^g!Igf^!T5smGjq!VFhu)Vm4hPIX4T z=V0DZXVm){X0tk}$DH?{5%kJ_Ijo$&#pMm*cDp68apw=tfw{oDFh5zBIZuR{q0Z=I z5lodjsmGkx!u+bvsMla7&U<5WMC~8zwe`k9Y^+?WaQUfld)}IyOHY`A-bJm;T&{(g zrOxQ%X_)2ej9k8e`BR-yZ=c(6z7vxpYXA7UB-Wq5bym1Awv2v-xWq3tJE@OZh}8?MU{ zmCH?Vo#!U!au3X7-bMAn<7FkxI(0@LwdUb{6edShJ?3&OOgnW(y|ZEZsxxvK?~Pj+ zo2Xo-!gZXVoXcF8h2BN=!Cc;g`Ba_J$7Yy%_ax_X6igd+M!hp(daE;Xxzd}YT&{=f zupl{?yI>ylE-shXVLn!8^zj$W4)-SKayZP%>Wq44!1PdOe4q0Xpx8qB%sj9f1BCMlPz;mRIJ&gC|kd%TOwWo}2^(HBo@o>ctCFgPr%v|r{a(Myf9d$+@Kf`QR zCw=g7cmId+eQ!*Ta9yKbIn0^rq#mD-hI``*ViWbadnH`K!sJ}0!`$UvxPP)PA9tUJ zd0U;)#|D_c)JZ+&vhO1}4~)qXu4~jQfjL8+)MG9~y>SJxv2x-0rZI5&j|S_;oo~7w z=05Mj{gZW>%PTM+sx$id9VX*3=~wD8mqTG%s59!F26L`DquymOQ`8yt9)fvVoz&y| z><_)ck8W5w^Zof}aIZg}eEc1-2%o=Ua>V6a0CR>qqmQ95W7J6>%y~AGiqJZ9YfF_)GwCF+cNePM>Gll|jyG}RloFg8&+&xGr`B-p>WWn_>JcEBHg2@q8kGV94$yI06>kiXjo#evjg-PCUT@EW3J}=x1clNWv{>2@Ci(sm} zi|T{V3u|G1QfKtB+jAMI{V+MA>M@s-Van7Q^)7(9Se@j;dN;z{qt2-J63j|c zPu}21H==U>1MZpUlXKo@DbD|4azy3AoU>utt26o-2s2Wh^ub(ifq6ikQSUXF57Zg; zeuJr3C4Ct6j)G~XPUw_!e3Cw(yI zzhHKIF*%pxVNOsUOCjAbK6Id&B+Xu#P|G@(SF{<;l5x z3$w|)uwP@{y{lX}dhKg<>CjC!}j+^0_J@%i@^Z@7OP zQMtSaH{-SBT)u|+)w{4?S(mp*gV*u@vx3PHI-`#)m@;)zkGWg`bGbUB-fb}VsFQlk z+!Jpk=Ti4geC~(I5%w$VGM5u!veg-VoC|ZII;qE8u7;VV&Zze^ z%yM-`y)V3B9~@RLRk-|5xFv5T=d#P&cs-8E5tmC#m;!Z1AH85MQfKsW9n4+ojC#+* zysl2_@p$>x8`lUnQMqh_Tf8DUmwGGlJcG#*mrFC4Ty;ht-C_ExlRkL7OoF*xol)-@ zm{-(EJ?8S2H|&EWDwkj27QK_4%MS12|7Qx5BQBRFFj?x1KF)!;K%Ml#TqeTYrp~DM z6wFKNq#kqm+#B}65tYkNaF4#1oJ+?0`1}o%BQBRlFsG<9`Zx>bJay6sa~TJ7i#ns; z6EH8RlX}eMGjG@jM^r99z&-pyaxS%2;qy04j<{Tog=wwM=%X`CFLlxfa~TUWU7bKBi8t(nBPy3~;U4%fIhV~a^*&0@MewM zMxE4SE~~v^CLB?@df~Jhg4yBYZA|mG79Dfbw<4hVV+Va z^_a^lZ<;{^>$s4e@}wR5%oO7^A9I^;~+Lx&Q-h|F8%YMUfg+$4lw6<7qu?mSB!$0tj_4; zUYJGdj9lJ@`C6S(Z-+1NdJU5!YX5lrHSxwlY@%{$OZR1RE|oB6c^9=VbGZcOYIQ~* z^I;xUXXLU1<_mR3y^OE$dJU5!YX6u^BX1nUCMuU!aQ}E4cf6E+jmH;Ej;M8+%f&F` z)fs)<4fC)%BbPT})~Pe<)%pgn*D&MukGUM{jf2=k<Wn^agSkhYk;_XkAE`6y{Q*<^hxq+tE{A#J8o|cOh0kv%!2RNF-1A%c27Dg` zlOryd;V=`_8GX!!S*Xs)=?>Wq46KjQzV8Z&PH_^a)i$4BNL`no%F$6&WE{7ol);r znEC3Adds|VJBW>yOGD)HA>8JT$+?vOg5wX9BkWh!<>UBpmBAOFDYxGA}h zBVk&rGwOAQ>7~xdd8{{ax$u589d7pT$+>KR`OCYwT=x9~-}k}f2%XVK0Za#VMjsc! zT&2#acNffq>Wq4?dlQ#S6|P(hH|NjfTz;YXOZt^{dAuA5(@34sM=4AvbyAPV{Vhbw)g*W)o4eNfy&nwozRsEfuOM`##`7|a+cpS*O%%v?%nL4A73t%o* zC-s=ijWGA9GwQtrvr?T=?8{S` zV>HYpbw(cxV4hKD)LRYnl{%@%+pSKjw(FsKW97p8(cW;Yyp7A{=vuW?%`rLRa_Iom zL!Hsb7?{cGqz@i1_rg4@&Zze>%-8Cq9`8pxq$TIV`%we9-@T2?r7*pA>NHG_xLgLo zT%peB<93+))JY%AWq4S!_>`)-#^wn!W;I%VI42br4`&kwS#(bxeS20)VsJ` zX29H|&gkPMn3d{`Tz-P7T}S#g>Kz7if;yvKnKv$!m|VKSUE}3YRZ{>$gjC zE=you_AaUq=JF-XCUr(1d+k~~bqFR$R6XX>4yJ=Tquxa@qtr<*d_J1#4cFy}%4Hth z`MV|OvKVHWcTs&Xm-R5es5AQ5qkiqwftVao^_WW=m`Zg4Z~zTJ~^`5UJ09`SuJm;b}udB9mwo$vnwyNFn@L}QIa(O_&S_6iERC@S`b6;Ox> zh>ImLmM99Y*kX%`(P%Wr-Xm%vx+0<`_7)RM)QG)BV~O&Ap7YF^x%1w4=3d>O?EmnY z*_YYxJZH}Py!Xu9xn)-Yv%ck=aqJ4_0Lz(iFfYe}ImdF2-i=`Hww$B)_k=0S3-2?$ z2X3+N)z8a8V8$g}k-yB#>0o|iIcFSqf_cDl&NyBJ^O@xwy(O1uuB?cKt?2le=K%>5 zK>pwPy8yh;uq(JROV-cJbTBg$uBcz;ERTh)NRQ*#1k8?>bMy`a zbByJjJYSG7p<}GPyljcQTm$airRwKpv!$CWL$I(Fje~hP1k6#EbH;HVnBQ5>8OJ?f zp0u2!_aT_CEa&JgyNt#V27;BBmv(Gl3*1KuTXwy><+9C{9k8&K5<03Fu zTFx2A{a~K6oTK+Cn6Ar}A0N+0y%Q!31goOFtPbw|ge}X<7RxtRw!^|!mX|SLjXMy{!`_fLM9;!o2JaZpaVo=jB&mu1L6| zemTFigL%?&&Nw~<^OfbCyezvSo)2PSOZ#>7wg@<>lpdY;OZMVWs+c znE~dJgiDXl^vk@w1?CIOIpbKWPjjUY7PcZi`nx5V-7V+nwSqapa_0D`_uGVFzieJ! zUd8sC!JW5q{k*&m=EH<58VB>zYZctLz`~Yt&Nwy$GsJSvI1T~xGs`)8zXEfGBm>Hj567zkEgUS7xc9&6xw7YkciUN&13^8psNvb-Du z<|xZK<2Vn@?<{A=!Fss|%#)UL^gaahmE|10W!KUe!a%U{^3sm&Yk~VHVaxKeWj|c+ zVqq)G%UCeSTFx2AMPRP9oHLI5!8~UVqTYOw)Sx^RgnC^)2V< z?F!}q%bC2e{*Fr+=7g;%FQTv%oxSIcFT7fa$V9{k*IIroZJJ zy`8}9YdI$`KT8;8r8qCAg4=e(`gyqs%#{gOmY4g%JY_j&93O%C+Hz(bd>k#eQFEmq z7PhosM{fr(dt1)vv0jc&m>`H%QN5fDZkvtk=j8%0mnU3$e5PMshusV2amzX5cpuD{ zmNRD z!2Hc}&N$uy^O@z09`mx~X1ET+!j|^y=(T{^)pACUd6}3nK@h8=yc`E^;O6!7ayFQY z6D~bI(=YRK7np}F=Zxb`FrQe?=rJ#gZ-MJ}ENp4Nj^1D}J6X=?F)!m2CJ16xl$W1@ z+k8O%yqp2%qJ&G2&-BZ@+yUl6%Q@rtH<*tsXY`ntMF!$|JQlXJUq^3CFgsYz=rJ#2 z6D9~^Rg{;b!ELf-{k*h+xgg=v<1_s-FSmi2X*p*cuY!5saz>ANS!gS~o`;1k?bp%U z0?c-nGkVO+n1l&}SQX`E61WWq)z8ZmFy|&*dVHo|=H+HE_gT&v$ID>ev7FIkUV0A3 z>v>q%(taJiO~JHS&gd~O2PaGr#HuJS6Tz*wb^W|d26J}8rN?LbWnOLobC2bmar_g^ zo0c`H%QC`M^TWj0;c{v_T zTf(KsXZmGc{s?Be<(zRm3+7eJ89nBu%XZC`C9tri{W^O6!E9kUqsP4Ln=nBTtD?M& z0k`_l`gu7P%#?&nkI(eWyj%(9cFQ^AcnZwRmNRAN**jqn zhUVpELA-u>Ft~|3)X&R(VE&eHWqElA%>OLs!jc<@qc;%D_Lehx z%=4iM69lpH^32Ei5#ZL}L;aTBH#-H)ISE&m=NrMyu$(iF7s0$`IWrFCxyPQ(mF2Lo zrTsd38-v-}az>Aj^N|S?1hMk+!tX(w0B+!3_49Hzn2QrGJwDSf=fAtaJZw2<9B+d8 z#BxTDd0BjKJg>#VmiFuD4F9s4=rc(n3rDrVSd5FmiFuD4Ft2j<%}Nla%jQ?L9B}M zaum3Y_phIq)4-gcaOv@xewmkB!Q5{-XB__m^Pc659`mx`0eD|C7PhosM{jd5+gi@( zF)yPNCJ16xl$Ta;8yr|aFQ+swgjqgIjk*{k)tE=B$KEkI(eWyj&0FFP3x0@eeR_ENAqX zm+m8*E6ZSEOZ#>7HUu-saz>ANIVfR*AXY_r83%6dQT6k3BA96jmmZ(#mwCAc%w3jq z#_>Fu*DYuCn3rw`H&?!og)QyZ(OVD9K+73D=4Jnc34&M^<>gRtYaUWRFUNs7E#cDR zGyO6zSAn_1a?UuO0rM}*89nBuGP=3)JuGZ#zmDEIU^cg$(PLhQCrl8;swgj`!L2r? zeqMeC=G25skI(eWyj%h1Hp@BVcoNJ@mNRlX#Kn#4dE6dAeU~aaYlb6T9{KIl)9L&oXU=|)*KQF6;+0b%Ek9pZWVU(5P zdN~N(%7@j@%Oo%-CR|xwE&+3c<($0y70mONGvi=h{tIS-arN`EDwy>wXY`ntT@t2V zUiJsK;`sV`nF!{%ge%L-Z@^q@IVUdr{k*IMW-ZGZJ?3Tmgel9* zO#E^$a6dRg{g&OgI2z2!30Ibv%fQ@hIVUfVf%%8!%s9gQ0%qaX`gvI$%!Zb8^mYgH z6U#ZrHwDbOmNR<1|8R4{)XVdo;EtbEKhMvDc|GCE^4#sn=E~w&*iz0J$J$^vvz!?R z^Slq3@s@M+rh)mD>uaqxT+|FD&QiEp-fDC&9v&j>FO0 z7R>IJGkVN(Yr+IUth_wGitWdO+yAHPx9mRL4Pfp{xb*l;zs&RVVBWNxGmiOwhPubX zR;0%~uMK9f~OUE$575iR1D92rO(xdd$lfV0N*bqjxx%pIgr4g?hgRbA#m^y}yEa-f~8d zkFWnG48qX7Jo7&ATyT$_pz)SHE_@buQC^tmZNcnqIcFS4gE`r9W*p4RWngZ% zoTK*?n3pYQ^mu$Sit@7XFYr7M3tL%U);bB#->|TipbA&{jV${{_?S^!j=EA(*u-=Zs@V zF#A}}jDvYO2Fx_eIeOQC`IF_09aa;lBCd-*|Fwc*IdDU``UYE0*D+^&^ zD>^>vtp;Wb%Q<@cf*E5ub9~J6sR_e=*}Oc@#P&16?Rt)muPo2kgSj)|ipCM<7cg@y z=ZvHKFHtX8*oyR+mwsRdSW%bTF4%&e8h|n1?K9^qA*434<^+FVF4x z%?IFaIalK?JI{1G58uy)g{>$r%<~#xHnW^Fj(xx!VmUJo=4CRNUs=x4`xBUU%Nae+ zr>`Uo!qAHH@-Da=&##}C$_34p1+lP|<>kj7FfVOj zF0q`W_h&G(E$8UH0p?4~IeJT9gx7Jfl#Q28IcFUAf%%)|oV>h4<~L@%j@}Qz{Md4iUJIDvmUHxe3g#5c89nCt_X$%k&)0%G z{Nnm~ei+QN30IcqPrx+)wtik#0<)Io%s5!j+k-jKa!y{32h(ObNAHhd{%ko%?*%Y# zSkCA%&&`);tYvv_$1fKG_gKP~oo9Mqis!Xh*vj&}EttJ6=ZxcMFeh8ijDvZ;49xA8 zbM&49^RnfP9_Q1q6Nckp^B(8SOV8gmSN@8Htt>CgU)Ee%6$@KgUbX?Vhvl4cOagPF z<;*ykmrKChVmU|eaWMb1oY7-mzDyX7gU!p!{n$R=<#^o%3tL%Umi;~6kBNn?EH8t> z>}EM<97ljT-g0If%*(}KZnB)C_b8YbENAqXm(LT1<6!ghG85aIufX*m7PhkUZ=Wmi z{0$3RSzdMkv!CUhaU2U~isj5Wn3pTT+-W&S?>R89SCgxYe$zpXbS7&Q7?pJl_E39?Lo7_$Qb*Eoa8TJkR$>eEtm!TiUOq zw-K1ZmUHw*fH}%?j^24-erGwO$2{MYFyR2P^77n{?X$q0cD2S)_Bj7Ln13f+I$qN+ zpMNx6gZF)5VM{q@9P5DD+;T>bc^(dCg5?~&Gr(MAIittN`5g(v<74yk!ujuha8s_W zpO@#ryq0k3cul{|OV{i0ycP>v$~oic2WC^t89nA@Z!qI5=jfdd=0eLEJ?7>1gyHeA zd3l+M?e~E@^?Hq?Z2o%%%)1Gfj@R_dyex179!FT%QqCF2Mqmb8&gd~OBfuPGIY;k2 zFu${$qjwLOCoSjbeF)|&%NadBzLvdFW94|+it@Y?xH$=1mgg;R!spbnu%-Dk{W8yE z!5nKjXB-!Sxzch*k9ocy%yX7=^gadC_2%;9qh4srpy+ZoJ$mNUo4JRh4d2t)Jo z+>YOz3~rlSbbMv=-vwYUPq?x?-wWn(%Q@qCAIz7QGvi=hmcA9=`+ANnUF9+5UZlR91Cu@z|69oGmh86 zd}ukN$Gr5q1D|)n!j|^y=nVw3z2%G^^Kxjy1VOBd@^Tco4X4-7%M>u@CR}=areEge zW-#|z&KbwcVBWEu(PLhE-ih}oVqr`Bb@Vm`(_%TJ$GjYzFhLM2FE2B(eImFG?oz*H z^Z40dE>5`g_)Ndd%Uxg|wwyDLH^F>jIittCEPgkhzhPlZ`*rjNgW1V)j^21MCt1$X z`yH6;ENApMA3vNh;Q+BJ%JY-pF8p)-Jbwh{>x4_kYx-rLm-`FugJ5AxIcFT(g4x}2 zMvr-J1vABRj^34EZnm7G_ZXPhEa&KTy$A1m#gZF`(PN%hPnZB=<>i^z#p{CmEMd#e zmn}2!`VkhkG=HXF=6NERUs%o=$E9GdwVcsoo*x49qU9XD|AFaoZ~5`@alT5zAPmjR z3%_S}9dOO}Nv|v~yMZ|{;mY!IJeV^r=ZxbzFw-sPOVFHMimzQ>I-yB?*2c%baUf2iBAqiL1FCRyf!JKC~XB@YHxyN!&Uj7N@L(4gO zy=LM08y2>rapq3tN#M^Rf<@tu5#1jRZ5nawadVzcUhs{jzy^nThQef!qHf9bZ}f zO$ReG;flt=yu1qLW6L??SoC3hz7`8xkskB1378!%=ja^<<`~PFyio4~FxObl(VGqC zY0DWs*5AhogD^BN&z%3h1b6o%8gJQoVZp!Reb-pnit@rduMcKx%Q@p131))j%s7~r zGr(MCIY(~>m`5yU^jLpyB@DvQyu7sIH=lx={*2U}5IJ_dLDWA*dW{c+q+#KKmVmwsRdSk4*8 zeqerLIWrFCWeS+zSkBSA6U+maGkVO+YYD?~uz7iziR~YNyX^^$w`{)Z^(4+mSlG() zvJsdemUG5&2$&-*XU4(2oDJp*%Q<@OU>>!cqxUYDE>D?pIC?99SvSp=J`KhdOTA>!clb3hFd~P{24(8?i&!G;mu%-Pv zdPBhMW;sXih=d7(SQX{vRB&UTub-E@!9197>G7F<>Bqmpd}=vo9N+spzP|(uTag~~ zvN@QYE$8S>0CTM6%<)n0qJ&|;Y+hbwV*B;rj(9=GS2kb$70mMqS2Pah<-cI&`-d5? zGme$PtZg}G96N#;VL3n(W=p6>;M9VpPmw>s(az>ANo}Dn^0I@2{^W)&o|5yDye*orx373x7 z^vii;nOE`tKP+r1=ZvET%&wL*dd%}gFsE3~(fd7^8!hMP{SC~&Ea&J|Uc>u*vE;^K z^qA)#Crkjb^77n{?dyR1Bw@KSKhrPsJRZ#PmUHwj2J=VD z89nBC7MK?-=jeS7rupCH$H(jJl@bPFXhnHh3*1KuTb7qC-@xn6SlG()G8W9SmUG5& z5tu72=j7#nFwa@e(fbrk*E!|K$Gr4Tm@p8myu9%K?&{#?CTv+=c6<|`Q^LYlmX~9| zOtqXdjz568#d1zw9tZQfmtkOrCtO)x zehTI^%Q@q?3e2sRbMo>8n15T&(QA4K@At;SR&;!y)N(Jb4pmsj*od+EnxzPRZ(6x0QW`0 zmgQyJ_wl+K7Phjyw1PR=a?Us|19QFQoV+{&=4Hz{dS8R-`9b;dF)w`+CJY2CFE5;5 z)&)1;htey{%N}4xBwSfuP6Ttd<(zTc0Ol^sIeB>=%)6Fz^cMIC--m~Vt?c;LOPBy+ zRg{;(;FkKheqKg{X-&AYe$N4OndO{u%mDL<<(#~{1?FqZIeN?e2k%$G!d7;CTPI8a zu`0^T?%-Daq<&tG0W&$_%KE(=%q^C4#_>3qe_GDT%a>q!eQL(*=&b=}Bg+{*&VPF( zOj%xd|LPEM8~(R`UZ#LKH{r_iax<9wEa!~lWianp&WwZCbv-}B`%tj3rTsd3n}TVv zoY7-m4o;XLh?Q3_?bv=KxQ#xqpO>j%&P%xT_?&)k0n=_dXB@A9dDn7Ak9k?(3w*B{ z7PhosM{hGQLo8?XIPV^kFhLM2FE5;Tj{vvzm-X{bMkV2!i0{o^6KSvY`+p*TNfQ)+4ai{ zVBSc$qH)lV=C0iANIRngPmUHxGfO*7nj^0}d z!*Q^Ad11YL4er(E`g!T!9sXirE6dBiU=FjKGmbVe7g)|2$8BI{Th7sY1I)*kbMzLS zPh$uJ!OF`E&qphR`z&G09!D)bx>t6^!d8}-iC}(VIcFS~g1Odm&Nvdh|&sfeG$A8EyWX9`^;|E~Yv7Dnf z49sxLIeI@$n6kXIk_UkFAsxx!E(+xJ_pm>tA1Wq0<(eT9KGGZ z9B4U{7hdlkpD<;4;q#+5aKjg=pOvl)d3grRzb)sCqiNCZl|`_y73uMOv?iD> zE$8SR0A{S^OkQ}tJS}0^FPk^NuwE_#x9?*0^Ku=S=?Paf4)*&jm^UovjH7w+?v+Kc zuodYsFKdC>%5sk0fnW}^oXHF8r7dCDFPoPazJKikaC?5QeqOEub8EsCje~i40?fZG z=ZvGWMEA;qSlEj6n3o@e+1zrD-f%FZE$8Irl!OT#W98+A=jn66jassPUTy<(Z^9Lg zgL!!g%=?ye#<9@%yH}RR!d9fmylenwJIgtGW57(ZoXHE1@0SU~e%ZXd%*6J~!Hr%@ z$5-|`@qJ+amT*PmV88Ex`Jd&SaV)cR_sS|**oyR+mqB3mw49@NB$!`V&g6x9mx8&~ za*o~;U|zJG(c^W^{}KjaXkMP%@tdY)x>sglVJo{H`u?)rD=T4PE6NM=JP^!ImUG52 z9?Z`yXU4(2{0huB7b^U?Hz;Up7d11XQ2JY#EEz8Tw zD|D}{jfJf&FFS(S-*V14ehy};<;*ykmp_2H%W{t1^I%@LoY7;wbn9I|FPyJ>fqN=p z%jT;!f7rdUF&4J6yzB{PwB?*}oC4+?%b9U7FE@g@-*S%Lzreg_IY)276}wk@W66!f z(c2u%ww5z`tfSEh69lpH>W_Jz0B*gN)Nfgy&jj=9ge%MQbTG3m=ZxbGFdtjajDvYz zv`_cS%2?RaejUB7!0c!_NAEB&CtA+Yy9CTNmNR0TZ9Bf`*czypqxEoikpO?yyaXpTOtt>A;2D7o{oN??4W~AlJIGC4TfH~iCj^3?c zW?0VX@x1V2!f+gHUS2p~y#?-u)imC+`D*^vai1CsTUlQEgW1Y*&NvPPbC~7KIGC3< zFqc@)(fc!)*_Lzk-T?EZM40e4Ko zcESIP-k*39m@^Zutl#SrrmWws@XP7o{+F<2{dVuyy|NeFge^FhKD^~*Y1cx@e9uHS=>I3oU^Kl@exCy7s3WWbCy4cFvy{bsD$I_l`w zs^5)3yd?TPCh2j@craHd9P0pjGpruxp1_tCsNXX;#dSLtwxWJnr_;gAwwyDcz5(WA%bEFkDd;V_8R{MjTiUOqw+)zGENArS z$KeSR1hMk+@+0{1b8x@kT>X~$@xT_{D^FlyOOMa=OFuqHm;hqs^}9IyXd2MH^8GEP zw*j~!KQ>rHyyB!uV@9qycFaL57H#Il{2`Xxu^e6LvM7F3 z25mfi((t3kPdxO92?vfCHGGHN2M!yu%b@LsA92+1iKE62KV-tB{YOqba`?pc*6SBm z`}gZNeB{J2M~<3!#PD%P9ynpl@FPYZI(+}}lUj%GF=pJz@kbpoeB`JjM~xjnVbsLo z2Oc(Z{dIwj9W(CG{SO&6Zq4xr{RD5h*mTh@2jQtmg#(-a=tt9^+m9JBar_bE4{q(< zcjr}m?>M1#%wc1GI%eDV7td|VY4wWM- z11rNSLn^&1gDPVx6Dy-CBPy-<-%*tVD@WkxxXSqO|AX;!68<-`vL?0;tBeInVif*2 zsWJiE4+O{m9TUijh(UBbo{!$z!X8pqHj z+;>|yL|tl#+6}D2zF4|dI6tf&B0eIh#Y4!qHMbbJ`&PRkhhs;zjvu$x#4)X7MjSYH zmr)~H$BZ90U_gLZ#X9Rbi||*^@td`<)atHNvvn>SHdY33Wtxtc^N)_V<)nLiBo5Ap zjT>QUs+f(OJ)0^6c4;~3o!&8_ZO;d2>cG$DGSiiow)U2j?(e-%J1>Eh=4B9VgN3zT zsr)FcwQ9kSZehEk9{B&(VOy8(T`S$!>DsTRv#DJ^y{}7a^Bf8|eX;U(#-hGfA(gaU z@Kb#$VqZIjZLzPGsl)s9*n@)`*!EmY+vk&?=rwsDa^Es7j4Tjv)?^+d!6UQ?wvBF=VA6`n%1t$!MAmi~5!blYy}w&92t z3;T{i#B+(N^r!e=Y@-mUN)_?ghlg!ldSXV!Wn0g6x=#qR{QiT+OvI$I|2Csqw;$Cy zdi=W$MX&IE-Gmhe|tnMz6`!&_e{K z4eisr{}Y%fv4Oo0yyG4IcIv<$ZOxqCrVd=B1F)l6EY9 z$~r|%-ng)B>7~0?=If$~kD2Fh#)sb=HD=r>oP}HW=gAw>KXz!v;f}?>HItv1zIWMe zcg{*}e{UJ_CLWbbpY%nS)`jli1Dp?^{r26b{Vz=L+gpx>?8xFRmjfdTaBaS259K;z|n!*VIvj%d@iJN=k^J!R*#?n+d80*tQL|0D@ z(Q#Od`z4~?!?w$?J|#pqVlBNp5V54YRUX88z7Rc?MhGgOaFw((@l*aP;&3L1ZCy6$ zS=r>No|X0QpTDwpYmZ8gb(#+7HmqyEaj44!QEg)?>sQvTGBliMTHwzjEmK?jEJe?H z58Ra&51qC$duti-VgDD}-r91*--I(*>+;iCyvp<3_LIKsdBhL5JmK!}yUL_j;qHI9 zS7p*7ZBMuTZ4Se?=fmj-1u;V>0AzNhl!~bXW^Ah$_VquuAt#4{!Q$|6J{f zWCCoP!~GW=G$kC)w83A!eLuUbaN~fJKbxwl?FJtz$64 z4+i$SchJR6cvvkra4vqQH&rKkcdUh--yDzC_LE=3Y5viHbDw&<>)fY7FH=jy{WrG) zJ9ujA#XSZoL9L7PC>Boi`pni9x2&%+dxq&?*6&8gVHiHe1ZZ(hTiMc7o? z8*81G$06dQwyAO{*5sPPjI7`OBi;5tMC`GtvNAkZv^pZ~u}ivb?{wR^blb7%w$l*l z2+l^NJ}yM03y4b)ag0rsD-da>xfYR5_;(@FzV{(w5}GQr5i$2omB$e2sGdfov(+nz zG`2Zu^nMzBnnquxQB&8r#{!5nw(qCW_Ykd&CARwz=mD#U$IkOzH(Y{suT-AG<51Kp;YG%0Gw=IP#sUqZLJYo!^-&b&lzjxJMFL|3I< zO=4q0=8s3@5AhzVC6Sw+$V>A#%0G3ZQ$>9!gI(rts?5Jm^UK{PbUmPD^6W|7@AwjP zL3_LgOfUX;*@ulB2Es)U(rtuG^`Ftsf_@N7Q-vE9t&~PC*p+{3G9OSp0rYEW3)4jl zo@J~W4;NG5lG9IbT4OAq!^9^^oQvlR7fEk#6Tw-7`V62Ve%HES%d}nl3`lo-w(W0t zYJ{hK;ev-iua-6dxa3I~JhA1|x#aLLakk=|8lKznG0w+obGRx!2T@bFGq1<~rucu) zux)3owQUq4%>rj4(kyTjBB`(j=~HYkBG6-15i9NSu#NT2)>l8!FJ2$S(k;wIirCLT z!!}aY_3i0C8^}=K$vxtz&0aG_MJxev8OFEJdqhWUw9%jAhG>(*YxwC6HRCD zG=1YLhnAdv#TLzYf-KWT%$T&4u8ebD1)JiYsDcf7h-npUnCd+0)xd_V0rg~SAm}o| zGLCn5h%_D_grVu|ew1S$kY9P%4sTP%bX z6O@IJF^bsF=Yc*9Yih^l>As6!asus&lR)#xIje^c!hY zGadzFPg_Tk+|!wmU1f(#8`Ab!+ea;JZ@T3+6^gOk!i-ll$BbF?$qiz;iAd*|ZL6xQ zg~ygwSIczmHneS4+cPa~fAvbNg(W7;mRNS_9*S)lNUL=EAX2fhnpJFr5UJSqPPfqv zmDojy7Q)h0xf^S#Oh?4IB(_Dm#1d0Pvw0&#=TcJr5|kyDF^bqvuRxQcc5I&R{Ly?y}DO=;fY5tJn`tY&H}a^2I5(6aXp*{=~xdu!_}U1 zZhv-<`C~nZNb6y{l6uf?gK!6}ydcEYDTrlpWU_K)L@J1l5UC&rBT_-^lWrS_NCoj5 zL@J2CAd(6%LY~AD+bU^6D55n>=L#ZTaXpqknrx_gD}j8Y&3wR=*&`b#g&$nihm2TC-MRL1c^~ z7Q`lQL3q0Bl@>&%sE7q2Z3MZ3@U%tN7DUy>XiLG>=&6v8Gecj-HD`*)f4|e`u@FS0 zg@D@#%{;yq=V~2;2 zYI~sV>49yJcuyF6^9iF!Rm6bozEpUnqLr^%92;J#=!e&OcwbIu^ED9ZnqVLzo&UE- zq-%l^={CNkO4FJuS7NPef(H>vg?A-h#S+`q!7!fh6|p!jmWc_%=Ok=-Ml}2RW1vY< zJ2p@Ea_NSrjqFG7R^dAw*J{h3IuGvCT-!L=g?U zC08aJCn(D#V-&HUdjd_0+Oc`M(`(8kYO~i&Q4z~T+SH6BV^3RTd6^{dB*G1+g8NNV zAReDZ?8&&MHjW$h(_3S0h)8Q=NL6jL@G#REq-DBx!_&#OXG(52iK;oDq^}f*+f7SD zSypleQ9*2gNCmMKA{E45>9(D~Poclm(G7 zir5cdGV2!J5?6gk)6;#lsvvYnGitNfOi>XFLfQy|K7X=#+9GS8OvV#Sy!+VT?WP0J zO>H?Ww!%5r$8r#nmP6U?ChdmXk9BT0iK|l(-}UXLchZ7TL~CBk6-2zz!-B{dMJ$N7 z15K*>c9W<3dQCw@ZT6ZeDq=xM8$s^wf~PIAwjjRY-G$NUsMsLft8MMW$C zX(Py8W_sEp^Ou?5(EJJLrq=xV7Wn1!(R>jNnICs6HD6HYnZHzOz9QPdcQa(KK173P ze#R)G`FzJiw_whV_+Mf5zUu2H6zK`(-zqw^N)sft@(SsbxTV$ zUqnOZ$K6WJ7u0#?ubG;!h&KGN(EN;1MDy2h&G&SFRBC>vsEFoE8$r%|Pg`W({BL<3 za00rkErRany}xcO0ugBulwAjCxBAxs;%e$3e_{AtUk40Ii$M{KVS`*T#B()gf{anb zV%RFs_Bz1R-K?eUhV9pGt;?C^EK6m(Tv2nW8q)Ua3xBGN)AyAFuE zmCgo&YN}wKT?g!)7JwpJv3;%p;v~!h$QVT|fV~1us`^ym>F!cf08yL0W{Qef0MbT~ zn+-f|k@?x+8(s&Tg>Guie{{m)??v-PG-Q6VML+%8Ka2ik9W=Y zbjOsMpD8M$`O-#^GvCt|*&*}!EV|bG$D5wHE}Ac*A@k#IrREFjJo8UU%~wS8k0~@i zV-(T+$*%dH?(wDOXNrnwzO)hK%=ffK=FR_>*8!KJyV@dH=ZnkJ`vD@-A}G5K&~Ejw z1H{$T!Mwc=_)S_2idYP1=87Snt9cs87)30GUkBP=2Y9;Y)f7Y2X0Mr|A{K+R5#+7| zJZ+Js*8v4@HaG?9@iyUAjB9QaE_2-pyTr*rL|O-BZ+(rsmA&;R{^{as5^Un zd$#Tm_CuumgB^eC>&>bCifF_YIs5x!3mfgv7)7-Ira+Ube(S5Jdrgh~QJcMHii&8z zv=QXq`s!(m%+Cei@G9U&bW`j7=5O^M6}=acdS7-47>f2CtySsOAvbOwCtB8y+t-KVuZp{C~RUd%Dk-nx82uqWRKBkTc)Y7TF>5XP}!} z^H2Rr*IChg5e=CicPlktQ0JNdpVWLsH2;l4^D{;f&Hvan-_w1!)cj0Q5zUu2f}HuD zw#W{d{~)@lHUEqqcl&uXUqnOZ$K6WJ7u0#?_v{v50Z>HqzbZ68V-(T+`GbO;_C4Kh zfvo!qxm8lGC%HCYQCV(GrxCgz9O2x zxJ+Ws(V{^-=Vy!}n!kc;zNfo%sri|rBAPF41nE&Q_OwNI$o%IZU2FdQFP@OT#au)~ z=EvPi%@@>p=C7ZcuZZTaT4;X8D5Cl6x#oMiYn7UxDJr7*(ngRo-_sVEH$Oh}uX^{; zz;E*Ip_kEbZ8co>!qJsD6^KZyq3qp5+HFuH?;aAWnyB+8vpzUPJsJFN-aRxlEe}O3 zk1cZL5#P7Nxglc|u{^d5G^trwV)JwdSCt3*$=(yh|7D7bSRT@@CK-F$A{%)35I(Nf z;2TEfpev_37TNjeSREqL>L|NGbXnM~{tY5=HPgksy+L$PS`>|tG!}x0 zv=GYf62#p~Pa1-1svx~Z^j+U2I65r=MYQ73Tme*HF=UJ)7Qj(~wwH^Z?%_2B5VhHB zrl^PoAZ-M>lZK})GJn$ehPQ}5LpQbN&)T%<{Aj+2hRlzZPE{A`o z<)DbhJYQH28Ka2h@VZ+Lp6*Mf<&Y^VVmU|~L9QG;ZIQL*5HAYbz9@P^Q2ml|Z?_Dd zx^H&+7D5qe8I-+btlip5PYemuY2TLgztnz3wEz8_{e78zG|mPYqlor@8E8_~FByBf zpVZhNwb^T?sEGDU8$s?RV^3RT{=^Wi#}{Q4d4DRT;~Al^>-{BXy!W>_1&Bz!FMBc= zcPlktP|XA|&z=k}22b_r0Y$WdUnl0jfjnar(fmaNZJ!K!x(i6RIs5vW>L-Jlq9U3v zZ3MZi0#93H-u!qP$nGExsQdZD3(yy<0UrikzMoqS<8FUxjaUsL(rVbV>N95H+|?34 zrP^w3DqA$Y?(R;UkL1cky<}~U{yP*I)+t$U==;J_BntbSRIY8R2zT~toFfy zf7^SBH)CI2Gdz{5JdWsnEV1YwK-$$u z!PwIlnV&7bq4@(`^ZT57)3VWg5e=CicPlktQ0JMyYcPbyDx&$@$Ry?&t=jyIQAG21 z3A8oe)7@UW1?FdpifF#HtB-=Qr!BHW=C`=!zkbKdsre!rGC%HCYQCV(Gyf;S5UeVS zX#T!3iFrn=Ha}w&(fl!iw&r`fBcxkkex|61=1aT!C>VR%B0FUMFxUKE>-GF`eB_I0 z$o#llsriCB&-@dDAy`!u(flK167!5!ZGOfmqWQ-M+M2K5=XH;fZh`rkq9U3v?dqdo z>}iYakokMM=6`?J!(WT$i)hIFxLc|Df;!Lq^MfHYNfFJTDwCLJv}*G+MiI?FFVNO} zPxnme7MPzYDx&$)u09IJp0>yinSX$5e$T(RUmMLA(UAFZw^H*3b)Nax21Br_D5Ck7 z$Ry?&t=jyIQAG2v3A8oe)4f8v1?FdpifF#HtB-=Qr!BHW=8tyGU;E3g(r1Gr8Ztlb zR%*VW&NKhMU65zUu&^-(bPv_*Ev z{0Xl4KmY2$E8-(xL__As-Ac_D)OqGV7YxCwqKM`{ER&dLv}*G+MiI?_Hqh35Pxo=@ z7MPzYDx&$)u09IJp0>yinSZov{<%MD8W+tM(UAFZw^H*3b)Na}1w*i^D5CkV$Ry?& zt=jyIQAG3K4YW1i(|tp_1?FdpifF#HtB-=Qr!BHW=AYo2f9c9Y($5lzXvqAyTdDbi zI?wzjeA}*W2`i%c|1C5>V-(T+Zb8AC@9BP3YJR4uh~`ThL0W>0J#CR4GJlF|{!Q&I zkHts6h=$CMyOo+RsPoKUCN*CX&0i>N`yum;R{hA&7)3OHY1e#DcX8OAu& zrsgZ6`J)QW&lp8C|8UoQPxsJL^D{+7G+){Xa^`#5B0FUMjjs78&YW~ioc2XDWPaSO z)OXNBfxj3SzUs%yTddt#~inW7?^FKq-l^F3{m9Wwt8*Ze;FuJT+o zUqnOZ$K6WJ7u0#?|28#W5zRll(EN;1MDs6p&G&RKC^bJ*R7CTojUZ>fr!BHW=Ff1= zpSjqJYen-#G-Q6&lp8C{}$JLPxrb~^D{+7G+){Xa^`#5 zB0FUMgRc4Wy}elaPH+(onICs6HD6HYng38~z9O3c=R)%{MiI@Q?V9iDwwIcpDJr7* z(ngRo-_sVEH$T4bFZ)9IM*f1~V{Q$+w#5qRUr7~_)@ zYv2BzD~HBEA^eVHC5T%CgWuD?q5)3hKI(V91N1ra~R z%Yw)lMJ$L<0!^y=E9E`i_iG9wYO~i&Q4tG5+6Z!=5caf1))vG!e5c>bZXtZ~-qa7` zm4S$~5X#=>8Fwo^IS8t$f_e6)@CET%ZM_1Zh*r$a6+rb(;EYkk0$3m@*jE5N-R3|R zeW6UIsE7q1Z3MZKgQqRB`sC2~-%p;CxSs#}$>Sb5Wsm5(h;R4zlcP@Y-%l1{Yv82& zd+*=Q1naHd-}T>5?wb~ZA{N3DGK~30TTws4sUc$&@i>1JXns7c`mc?6y2~cI_~Ihx zZyaZeidYEJ<`GaoHc$J9(yn@?As#nJRIE+SNHX@cbrjj(PyU9p%Lnf4vcyRT>>uk) zL_@Pn+^uwW5o9YX`|IrA_4f~K9?amWLlG@lJ29V0&K}o!Ml_3Rvq0O~#nauO#`rjM zvDZvd5sOON2y(NFr!BI2cKODiAo$ER|Kq5`Iq8rKYo1W49&P#|vzF=FZBVb+GIRhIx!o4sa=idYZQre-7=d)gv9{6u3Bw-i1; z{|`sSvw?`T6w01x#NA3K1VJ@bFwdT7oSzneB3dyuR{-&J%>u|6MJ#~x0&On^Jl!*E z3Lt8;*Gy3n3qaZkaub55E%N_nLg1fAsy!_{ztN}5#VQbyRzcZ>pxqjo5Jc9L!n~aj zu1)Jf5uLdtR}b-_$a=^aMXZNw0&OP*Pxp$NdWhQWHB(f?dXP4P+=Sq1i!7cHia(8h z3e@ANp|@KJ)33Sdgjfk8(n=`%CIanN{!Ii4(`nyCa9^;5)+(YAx5*|%Y<=|u=a*_m zH0{4P(4?xriNMpnOS)C(gQ(43Get$TU)l)LqhRc5i!7NAbQiMV&zw$$YAk`iZVCK; zkJj{k=OWS)D7z`G-EAQyh_npKW`ej|*`KixQ&R)!g~4JNy6opQqU>kVxV@>eDb~6&+&SGg3K4B-s+@_n zt_*KNBo#hdd7T*Bd#U}3Xv8Zy`}-y+?avrR?C0G;ld7HxJl!{H?2p>)HB(eX`=yN_ zHxqc;BK?^l`&x?Z&tez-@$_lvi*o}1c>0EJG3Mx@ZO-2#Rqg&XI)GREqdAeU!l?OHQUq+EBDq?v^ zyP9O|X^Zr~*tY6EVgob80JkV^SZ~+yu_#2OMNu|G#NEnf2r->ELoAb)fFfG6P}ufE zW*e=qeuNW5#wcP5EFEZ4)iZ>rySQ`GZKZBAq@)q}z@}MAMooS7NQx$AgHZG856OSYqoJ4CARmQ4d5b$;1TN zDEXOZM6;i@0!@nAv3a_yN;eb-`@y@W6P*9c6cw>Jq)jN2j6H3U{`?ScIMtj+8Y_}v zZjtV ziL?>qip0|vSzaXZi!t%-=nXvU*wd|z5&K;7lUN%f(%L9{)}h_%KI;%xb3V!6fB3GS zbqr5SLJ>=1$6QJDqa$dXH!?;MOJbiulbVhtHcxlAs*=DZ23pi+ubHAEmV~scNyeVG z$c{eiIKVA~5B~kizhW7PNXww?nj-F2c1>T#jsM!4P`eo@Usria%!_RW&$NR-JKVuZp{8IyM??rpMC)SuBwb^T?sEFoE z8$s?~w5KhyL*`F#&Hv+yFAs|5i)hIFxLc|Df;!Lq-=^j(q77#knx8R>X#T~n`JV0t zrRHafifF#H5#-GGv_*Ev{G(m-$8}%rN#hRlz0VcAex|61=1Utv&U{Z>WQWW@!8QNt^Ji`m%@@&-`Ej>W^96OD`46S$E28;- zE;K)56w&6)a_?KwDh=$CMyOo+RsPoK! zIW=Dq&404c{ESgV^Ivk!_jI2xH9u2SMDwMMAZNa(EwV%ApXHkW>V`i~-;E@qA@k#I zrREFjJo7(I%~wS8-z+pgV-(T+Ph9go-SVhRlzC1etFjuxMeW6{0=6kx!O1J8@gQ(43Get!-U)l)LqhRc5i|mm3SGne&z14E*ZD0`%nICs6HD6HY znZIE$gvKhO4Xeo{<{2#-lxIZK{0#za&G&TImTrOhnW7?^FYW51VC-p&?2!34y5?85 zKK}Ul$QRL&`Ej>W^96OD`8xzdXsjaqw=z&BG0$k#=4Xr|n!kOZt@)nrHqtFHKT}jh z^QB#V6pTG>k$Lmu3qtW@uMPes)H~cF*uCqf>GORNX%Uot&QZJJbFVFR{tQ--uc?Fl z-Tv?TbB-f}K`aJE_-|zonZ~@Mt*sy7c5lWgVlj*eG^y&(IeNPLO1G*QqBeWY6cw=; zq>Ugw3dWwc$kMz0jok8`;TFQ;i+z^9g+N4F2xYf?<8Gz1fuNcyNbmQ5*SCCs8cbmU zD54dI$tdO;t$H@d7)30AV*+hw15ft|=~fj$)Ml@lq9PW6v=O97!PwIlnV${5;r;#x zUGqQv{m;*drvecTnICs6HD6HYnSWL=gyt)v4JXMY<{2#-lxIZK{4)b>&G&StO1HrL zOi>Zdmv;40F!r=XcF6q4T=U<3;>81^`63!JKkim)zM#%C|H@zpja7vIR(>Uum}j(V z^D{;f&A%eh)_hO*66qG0pD8M$`O>aF3dWwc$h`Tv>j1pdxUoNm`J7t=yZ0QKe&?Nt zv5|N5b@nkvX&1$@`9`QIJvVJRrWe=9f0GG-mEpMHd^fQ(VZQn)M7q^e)@ z_jGTQZdEBnZT6ZeDq<-}8$o&$j6H3U9li>9*{y^2C2#*noC`#xbx?K{5O*t`3k20v z!92SPcp{j>0#HONX38k$8m)RR$QVT|fX4%E=K@dnVd+*CK-6ZhnW7>VfV2^$N5Rq01Ai~zbJpQ(W_kuYr1Vyyu1sTSi zqphePVJ65JMJ$AO1AQ2x>Tf&nbYDqyk=1qe?w_d5UNc2SECgwjqJC_i_8Zc!Dze73 zsToPep0v}hCyEMpY0 zz*cq(%+p;u(M8^!0?QN?vB0FwBd9JgPkRMv7tCPA+K^61$k@}?QN#lK#$VZiSB;#H z=kB@iB2UFS6VcH1QQWQc`bdzita{2STKrMRBI*XGs)SNNuCkSqS_?Tt0KCQ zc+x!G^`u*6JojQ_ubHAE7L~L~M3S+mEwcLh=o_2g!#98V8An9(MKor9vRk?N0qQ*S zcMgWoSVgp9uuNi}(PG;3jA)v_Q=myzoA2pvC*1<`Get!-U)l)LqhRc5i|mm3i@4?= zG_-5_jbI`gGC%HCYQCV(Gk+kS1?Fdp zifF#H5u``K*wYr-A@i4V&0n_9iQC0TzKDj*kGqwcFR1g(KQ0(TV-?Z-!(|flj7D48 z@{DMj|MNhTsy5%#JxaO-=4XnEXuh-&q({Nn(-zqw^LxAIkKE&)&7%1t8ZtlbR%*VW z&NKhqUMDtITNz5}EZDq?dqG|pw15K*hd{1|pbPLSS6cy2YX(LFFg0ZJ9vP0(g zbk=5omezR)B#P$5ms=>cr;l=2> zh;Mf@HM{YNl|CM#kg%$8xyIa>9-gp5(dLUtGTb4113_+>gm#-6s0!o8Q!$aglllgmO+{W-lSIv^0~KMDv#q zG^raCl0Q7%@7I_gwb^T?sEFoEn|hIC>}iYakokMM=C6D9ed|T@MKol7+^y7nL7iv* zx~ch!Xv2>R&CeJ`G{3)VzNfoJsri|rBAPF41Ud6PZIK-^{{Ywgo4YmtA(}6uA@k#I zrREFjJoC3r%~wS8H!CzhV-(T+A+GtJ?pCGdXNrnwzO)hK%=ffKcF6qEuKCSve@OqX zq=<&hkGqwcFR1g(KOi+<5zXJF(EN;1MDzD|&G&ToDm6b-R7CTojUZ>fr!BHW=1*|V zKkL~kE%A{rq9OC+Zl&f6>OAw0OwCtB^T!mLpD~JP{v_9YPj`H&`I(|3nlEhxIrBYj zk=5omejnlJ#P$4rglXR!(Kos-;@jOvh&sjh5k%M;n8)`K&PfYF5ewn?Tp`5g<9uS6 zF^X6SX9wEeNAPqfC%XQ9giKKp3qjiUK7yy+Chdaz2*ujyBzGUd)7DYM`v{E}*a>cd zUC?jIYhruaiPx^0V~k8PP1T>jG^H%+vi{qU#q} zrl^PoCT&|_p7tN4T~J`f+SMau>}l&LVu9uERy6XIb&7lX+UJ8|S0(JZR=K-;IRp6;J(jE_%5*=we#h(#rB z1i90fr!BJj^wl!8`U3(3dac^pr{BP~&)Yug)wk{+EE$HcA3n>ig>|kyr(diE5os-y zeY>c3>(%#}L2Zu~eqylqptknuB2^H>J~*kFX`kEDHnz{6EvSkEdiBLHT28uu!2a!g ztm!W1>WK8^q5}}=%SDGGLcVdQ;h=QeBt*2Vsd5F@3x#MF)>642(JNSDdm-4x{uR-r zzskY{;TNH^ej#^ zAMf};tN{^e4U~O=NW0bj0FkhoDwww)AewK1cxzh`P5B~M3jLUUG?qffC}Jse4+^BJ zKS1Q^RsvalYddPQ*Gy3nOF`NQavvb_v_;l_fT;R((Revr<(9+V|6crySPmi@DhKUW zw;Y6ZaycxYmV+W1vxsb?3uw_YmP5uUVmU15mV>9eWNA5Mii%hc(ngRT1!GTJ4yzQFL&hj#IjrNBgQvTCX*pzyidYWP zMvyB9Pg`VdIaGblyn)v}?{LdtiyIC}KWQu?ErYU`yyI?VuX~EAse$yvh2Ql{-a}IR z7191pbN2UT_R%;SWQ-!(-x6q2)h~H_x?9%RAGO(Qrl^SaOB+G%bx%)QWd1tgn^`}@ zwSJ-JK2N`4Ktw~<$KA@T7t?vx@1I()h$ie@Xnn>gqV@Z^)_b~pmRg@FDx&q$Mv$}K z(-zqg>mPKjf9a}^(yy2i(UA3Vw=(O+be{E-QtK7b`q72fXN)3R-|AZL>5eP4K2uag z>!pn#XT7H_vLn_%=33w9vgOm)yG1l)ecY|gdNG}6eOqe1B3gf3q4gP~h}NIxTJPze zTxxx$sEF1}8$r%`Pg|sKec|6Mn+)Ojr|X_`oxfr1Cfmd(03uT7w{B@`=8?6`8q{Y% z2qw>HU9e@^u6+hf*KTcP#wSSOA1_=KlDeV8@0HSRp|ud{w$LVs@SF{2;hoZLBN5S% zrph#|bzA5LL{hmH(LGpV`(0|hA{u{g&iEfCD9`j6qlo=n8fa3~j?L4(sK)rH&0aG_ zMKoU8)Qlu!Pg`W(c>5Hvu|Fg7vReWBJoxV4Vg-muE1>L-fOf+*KfYP4am}l4ge@*RIL?dS8?C;C$qtX71QAGP6 z2{ftdYkp7nfg1axHhaw!714faBgmZsJZ+Kx7c;>JZVCK-=PeeBB_JX#fwGxEyVacu zgw<5RyqyVNO-n%$O?f6)3h~j(QpgxZEQNmsnpE{n;OYLOrWB$!d(9LTu@t0@AU6|u z+9EqT6MW{D!7>NGabYY25osBe%>;3`vY9|kO%2Smnc(x(enm9mot*uBnSC_cpD~JP z|7U?FRXr1Ux*yfpAGO(Qrl^SaOB+FMCh)XH=4XO$_UxYnto^Iz)1Lb}{gP=B4Ot&| zE3;lq=ULwi?&%HhifBUDu+97Xlo_Ll)-N1rYrUu2L%LNj5LH{BDJr7%(ngT8-qRN8 zTi?+0fF7>%2VH*HKjVX5MCyFm^8oEu`aB>(I_-JD%E1gio)yvfrDPEEjTW!K^NeVK zl|F&C&jUQ&A4s>#_^8cZGet!-UfKxKqhRc5i}a0e?5|cY;yQo$xF^4i&WlK$FPrY; zZe@>oF`f6A-z3;UTNTlSHDwXAj20i4c}6tA%Eo~vRXyE%y6Z}}%KE6yUNc2Sv|ic> z(xYJPX^YHT|LvXvF6EZMn}_W5{a6Ab(h?}U@Y8N}FZ_hnRKdKx@Y^ZaLz@-RltHqL zSx4)qAK}cOF^T|Ih6S2b^@X3OyRCGqN+D{q*Gy3nOF`NQ(xYJPX^ZUWg;3`vY9|kO%2Sm3%^5xCA41=jo4c@G1F*$^&{AyF^T|I4h}S_>Y2dP zJwUou_D5~@nkg!x{nAE|9tC4hTjc-6OwiXYf!iK^Eqwu4L|Ou6Gl6!iI}-@2se*Ys z6Z|~b!%|R0QzpnVW*sd)TJwx(fR$qdO{#h(@N|!qZdEBnZT6ZeDq<-}8$o&$j6H3U zwKIV|F%al|3rDqbnS*}D7`Z%s!lO1 z4dwZ;G*?!_S~rO|K%|?*TOra-;=R&sV-eA$rpkp_>n8D?h@`@=0euupY`+W!(P%}q zpK}6Ds`@KNJ>Ao#TU88Eo4sa=idYQNMo@_)V^3RTBgN3tz~7tR z(5;4kxBq;FSPdf5YABl-OHp~RSr>`y=IDvSPs%gkRAnNPg~^wRXGfB%i-7ithrk(2N4aGgLbQ1 z4#GOQ9PSAg(P~9B=4RQ(%%eri@{DMJmA?eqmV>8zhja_dAyZVua*%fQQ84zjMHZJs z%hY50^d7it%SrF>o#zAFK4^PuXxl5vo4UL7f1>~FIh39}qu1oq@slTw0eI(mi(3~* z_MI{$)`f_)F3R3{uHEpq^FeJ7v^_nf?UA`pwmlb5GI-&!S4-QjeZo7>MXEFgRKN2a zZ(?rkgSW&Vi}#?Pbbr5r!`pe%(8Rw6BAq@4BGTz&dqg^Yj7YZ~iHOEERj$NZr;i5_ zNo6LYSFyzQbTEzPD`J5>C?gYOqvU6v5zT&{3N$Hd$L8t&O}e2#*iWSrwfVnHQ4tG7 z+SMduPg`Uc{LQr`@D_t5M)s^MvFrSmC3aqPM)ub8wl9i4nQ{tL{BGVi-%ra#5e@4Zw#8Q`qCqT^j8VigS<)>NPj?aNR-H(qHhaw!6|qdD zjUZPhp0>#HG6{bV4~zw5t; zw?J`hPON&z>A1^H?xP@@m;e)S_g&-m=gt8B{#obD;EdhovAorm*Pg`X5wMF9}sXsb# zJ^!5zYoB)U52EWLzTHRaqfYTh>P6TZn8)AQuzy+zifGBuTp{p7wrnhfj8Viw*e}qB zA*#Mj<>~I6=yrAgjzp%Yh=m|+9s%`Z^R)MrcGU%JJZ_GtSeu%WWbA3{D8BVa>Q8WI zm(L!#X3k=3(H{v-9h2Zn2n2JU-Kackhk&raVr)_{n#2FmVxYB&Aq z-IDvB!fL8u-o7T%mX?AdmcntlQs~F*qp=h+MiEQlv_O-pzVGSjo?KH3QJcMHii%hY z(ngTpZe#3ei>$rUh|f@}E{7kh9*?7TFQ&uX3%wXv@m!(RvXLSs!;RvtCT+S^sKk zy&_uwOriA|qlni3%eCIq{YRpg9e9kKpK*ZRxT&{^kImq z?=yJ1Jrdon?tO+#Q4tG4+B^d4$L47-EbW5(48_{ij3Z?1Y3nHBeTK#hY=&E42XB37 z`lcEY->$%-PH};W=;Q)hI~c>_QN#lKK~e}zc$WS=Bbo))FVMEYJl#Htu3uo8q9PWU zv~7WT+CP?dL4g%(SC5dfr>&!i1(v-4k2m=@a-00Yq|R22uchM66H89NdBK;`SJOnK zXRor`Y&-jZ-y)S#J8h0zZauHK({dfITb>Gx_ zMYMic&icO0HX6$#V-(T);ejS~J(k!!-QA^I^_Y*^>@`zVMC+wZ%}6r#v_)21uM!f)79@?}}Igk=|Ru zM~mKDu^uA5w_>|=+kuGmK8o>(Xirn+e5`TJi0BTi_1oJJwPT6xm|zVpRzyP%mR$)F zuV3$x*PH};Wuv5%DzA!#77{lUGM5}+16ao{Tzi!DGMJ%v$ z18uKcJl!dYZdPEtB4J~%nW7>Vn6&M6i>G~tw5tlNF>Ur9NyeVGj^dja*c`XOE?TTD z{cElwzFmPuo#Fx$(a8mNQ!s`FrifPmHYo%qJWGF`5zPX-G0?WaJl)?Xx?SC8UYVjI z7MQecfqB|jOS_=JinXgp$k@}?QN#lKrq@OvBxRPrF5d6zId{hMq=<&DjpA-)*G6J& zU1gWW-}SZ8tY8JpMG;Ht&cu4AIJ+vzGoo2i4+Od|qU(t#&C{JB-74F;7aM!c6cw?g zq)j4{j6H3Uwbw>11s6x>K_^}ueU_M>zc~8sXRp5zO&9U)=9Z{aJhzCjH877)Uatmo zXtE+&@|X-m#1^OaJR_Qg@UKAIxy93cCeiihmP}C*3qjg;Zt=ALA?>Oni^t6o6>H;{ z=?EEn+B%AFJGbETY0kH4?D6+AUy5ZWqM^AZ?p8Lph_Q7w@8*`zgB2_nMKs`@#CoPU zdsOEc(JZOY0?o(%^~96r>3$^LD%-gi8+*+Z6|tnGO(K$vJ#CTIb4zwwDZbrO{eg!b zuJtEwdiz(=dJzp-uieT&@Q^U(3D>-{zE`h!k5~~+=o+@gXCN`@v_4}L(fWl0O{&^@ zPq&A33#`u+714TWBgk3rX^Zr&Z}3*zBChw#Z#Xsmu#1S)`~Sz>x4_v^mB|lbh~XLD z#z1s{5eGyZScHgx0|uP%+K7>55j7%WM8GT{L_~-@gF_&)2muiTA{!AgBC;6>7WCI2l5E0@3)v5l@qwm*edS;Tj=^uBfxv5j#_g2k$_37^1RGSvdPPLI# z{dd2rSERn%n@^eW9;`2eFJY)3D;4Oa0xn$na@6QfFx8YL`wNwZGb>vsa6aYoA(N z%W(d<_KxnJaqUxh@k_V--ez4R*NLaIusCyKJe>vC$W6x6S>zhIcG)p!Rdy7_S(<$W zahB#_LDg5l%$I-V+|1L0sPdGczspOv5BbOt!Mq)l$mrz21O!7hT1U`*wQAGmo}^~*T}6W*T~7Wawp&#IU_o}kTP?jly*}Qoi;N% zJ9SL_jy57>_~;y(i4Kb)DZHAJdCA75DB{|bRT!7K^3^gfiv=+*4+(lfUb=nES%@eQ z!MJg>wV=dt2^=ECWrAaa1#R6d-TkTSnwQ471Vtjmh1$^6qX4$F$*dcf&OU3J8L}VL zG`R4#!;H(pm+ZV;<3fgyOYXWl7OQo^6sfFL`nd9TFty4Y`KXM^1A-Wn`vg5JFWtW2 ztV2wQ5R=1cXF*YeQV!XO$Ql(?e2^OX zceWu~LC(v*)y#_@hM1tDTQzo#b zO=ja7`o`J=_YUE`0jjExxDV5924l~eA9+ZFL52@Tt`Eav(%t2~0i^1%Mn>-LA*8Mr zeVBWEM2KM4yd)xVA0}{!5RtnbyWEGdbnl2Fg8ig@n4n06h)_Fb0$bW-T78%>GK#Le zsk#HzH$`5njR|Ht9>46VshSQld^&O$eY05K7k!i0N4>GCFZzDUhk^)ZJ(z?-FU&^0 z5jaE$#gmR*zUbT1eKZP1<3-;=kqDunwt(cKZ%doZ#(E>V0He-ow!_RI{N%h2KeJAT z4?=E=O^aox*hp$ffxr4@RZp?Klh+f@_G^kJ^h6s1P&2`u%1&mPEfoU+tO`u%&l6&m`1g+*Puv*AW$1D=<8-_52toC zrm3e5O=SXG+B}Ldrs-$xGTE$MZa-witC}-1YSk`UEL*#fR8Cend$X!*mu;LG2n-SI z-Mla#Uvl`nPB~;FR9icCxpuL1w`?#zu3ds6k&p}R_$YuaZ63wIYL_Wy?Q;J42mDrD zCu3l>i|SO@E@YH5FvPXXhn+bvnFvAHfrjBbmreinQV!V&!d{MDu3aqMoeSMz=7OW3 zNF?M!8%Ge=E|&IKYFE@Q)!HKMKOwNC%}=PcOYI4{sb;?J-{Wm3X}-u9SiY!}nUE_8 z&7F|@q_YLlAws;mix}YR4%1aBhit^_aK}DYP&^@L=^k9@hIr{z81@Wg9P&$`#kpHD3SW z%s^m>VDC|d`S`-q#w&1$5UMGTU2eQA-D4Vzj~lO`NF?M!J3b0vOPfa#H(vcVf4XV@ z!!Lb*oSIKYE%UWl)_jthXa0H45SUK{^G~Ho_?~4`gHjIJF#lY~E}L)ZPNQ!0SFhUG zYfvN-a-l829|f?b&7(-oZ=6i)d+EVtqOWuDGtD%Noqy!Mng%j_8V<|M#cMIn#rwN$ z<|pG>i0N2`XOM4_552y;T3a5KpFB1Au%N%lOSkVj^AG|eST>V}7L<5eEpUhslq($@ zENJUy>0U}*7nH^`$U%`v$b~jE^(cTXZ5~Cv$@qE?0G(yVy2Oq1|E%ccgU9I|2l(~ey>-_l(|-3s%AB9V{_ z?f58wEo~k}YJOwSp;$^(eTVJ~L>?UntR$LihT&sxZS+130~tOHxm)q#M2{+FS$1XR&@{)#w3?Gi%NjMhk`y?EB4V6XO zUs%;A;nv+qr{0NR&zngoaC!|JLJ>Gb2*o;10j%5PrJJSO>X=(aHHK3(kOh_vc*kC z;1D4IZH`@TGA!NE)Qtk5+SqGQBtihFEx;cIu%%6A+GO;zzp&6We`3#+1JrynYMHOa zvgVW2Jo9(+<`cn&?JLa>93q&%t7*Qa+nF^#C=$VZY70orx3tNO&98q3c2VJadIt85 z+mD*9u9GpaIc(LbK1V`EIRis{j^yJ$2t)`%R}zHy97*61Aqa;!cKIBMrMq9D8z!+; z8+#3kLOXDQRpOg{eUeo19tt}-+P+|jEsQ=Om(UQ zMn;nZ_GM=bni(QkeMAuieEH$)PdQ{GV8=UlIbfFVk%g`uu%JkUfKj^~FiU$fwJQQv ztsQ?tU`v}vp#cjk%EDz@Vc}ubQ_E(Ewhnogn(f)%H$M2R29FHip5+!EvY20Zn0ss) zsSI2nW1e<7T#i=ye@WIHDZ9SBT3f0wo;b(Zg-8)0c2kRZ2$W6dCQ}aCh~3$a4OV>d zgr$3W6bt^X*5(TGmYCR|tAvn~Arp6c8(k8R-sr5-Cx05Fd%Cm}k{yMVb|EdJF2km6Z)Px{PVsQwv- z9R%_6&@Mr|JoG?8FsHTUNdMkf1i|Xo7F^}WNWCnGDlZAzXbt&MY(I52qn;r`q^_m) z1!HXS|CB>E_A}S9!GgAKmhSb`bFl zr=>?u9N9ARrgf);Caa%|pkFhybkxG<-_R_P;j@&Re_^q{=U>Px_ltUlcK+o)XA}%4 zf<3p=JbeGM?Zp4N`Io>ULMZNaY_Q__7fW{mb)&wEYGbcKkqDunwg7(=z?L?djq@*! zv$kD*UN0P!LgbQGJG;}=X4M?>`Cb-cOqzVY_y0Kq z5f&oYwuq*}7umEqNI7I9EWdMXupS1z*eu=0sO!Sg*eC@>B7}w7kkq39wzSFYyHP5h zXH(T0eN*Jo8g)u*G{VfuF?(+OEzJoTJ}0>vgvEHmH}~v3@|s+O{GT%lh7%za&(SG!Ox}zEbpxW4LP$WVCs4c)B1+b+}W<0Cg@5O^{ zruk33e8@aCpNv}OYq6~PBsI_c4|wy5U_(cx`GG?O^LH`Lw{&;RnjaL2U_P}4B<5S% zWSZtrz*x0w5jqG?`#;oS;qc4y>p^G3>7GpZhEG&NI#|LW`$naUntpH## z8J>>pc)ap1X6`avG8u?TVGMdw`{a=w_!u4XF=PNbVQ>S`AIJyg02I?y9Dv>}=nwMJ z?EoJQB1B`aBpN#OL%k3eZ5Gw=a@^DJD>5T1@VS zbawkfd8_BQ7=TEtb9Vaz`Bi3C@w=>9IlFzH{ElD73Z5%iV5h)2gdL#FE-2Mvd<|v2A?M*E+`c{88?bWi3M)Cp!^Cr3X1desUV*X#d`6 zg5Ys$%bGIX!4!4~VhZ0aXq>!s`>aa_5=MkPOk`RL3Kp1POF3j?Ka(6AENJUy=^jqq z5yM(W?1GG?%TR(M5g62tnZTAdnHWBD{u=_`oC<BT`aHGmXFF$F8yZS%DTi!Cu%7B&C)%Wx^Cc&l0h4L4T?mF2(@D-u%%6AzB$$T z+#PV z&LsJE1&x!RtThf7#P^O9#9HGDL98|A3!)0nhdeAV-M;T^g55+g=Ti6HRs{vM6}FT^ zHuiIkV}k{4-7MWJsTO&#^8Im&Ad=+2r_&O za?j{tvC6J?7n+fRQ@S2BT(u|PSYh0jf-aUud9r{U_=1c#Xs`1zafyFnvBhL1q5CSb8XZ;C})lWT&9d=!Xa%AH9R z^luPR2pl3r;X%g+E3OGF-GvQNP;KlrC=wwG)E1D`1eP|LjWxl*;xNgK!-6j?@y{72 zqgEVPtj{=**5o)m>*GKKW0q9LA#jKghd-Hduymi!#vv#YAr90Qki@~#CbKaPIwxDN zVVG>jVD_0uZJ@OR89oNNhJnTM4MV|cTEp-UZ$A<2e=)JY1K+-Es0{*#2=>43*kHvC zgQfd&gZ-+Fy#_@h*iUT%NyA`ilbJRQ{j+|GY5h0bM)+sbkWtHe7Ry^-aGGZQMslAU z_6dk!LaTev>JtPG5vYS5+PvJE(grg z-iO*10jt)IKOwNC&7;tO4S2oUbh8yZce~%NtrZ#>z7@-@Hes>8*Q=3N4q0i2V+;A< z9Gt#e(8cmc{PYU9D#|wh_tu0r|PY!W0lS~yX0C+@Rx_!o(g8&gB zWQP=CASYg25I98G&!-)`ytu&9J&d|h5L6p`4T?kv8MSd7$^^Ew$*k_kj=bgds+)FB z7fD@qG}8>iQ_D{NFAV}2J_zIWtdg85>cYWAi(px-Yve8Y6U5Bpw9f3@f%4sxDk%q%kw|GVzz*U~tU;p32dFpd`UYw2+UMoy^6>cu(_ z#$j>hWEHMk#AGNVQ~h9^9v>MZn0I;-8C@}m$OH}%BJ)kh2J0z#>1OGk9YqFJU098X zy#_@hM26Zi6WG!w(_Xiz!=ReCG@ETEW%p;#nyE=4!zV?~5BoEFT{ys~;?QE*dV{1@ zQ*V4rj)x)mnIP61a|PWcFWs(o#=u}A*l`KXDk%CFn{voT2xdDrSkTtZ(!GMZQOlv) z*lSQELI|i0O=SXG+GNJ{M*V*3oWk{VAoP{t$GontlQFPt*hsdLR*X8pat{qLGLGJGwQ>!-3<-~Ckb${`!#e(EF690Z66mfTx}0S1H~ zV#*;KAzSR&=trUtted6#>xLkp6gKQNC=wxL)CNPDz?L?djr~-ee-AyC{ykW0o|%lD z7hn6onhY|0GIH03vRJJLYmv%uH2K=lKl_Lf!K~jU5s7;xfkT9dEOTtI?vs~pmhLlA zM6jQh6EbSWgvDgxkv#Q?Jy`2(ejCo@lDb;N!WcQ zEnf#aq3wb=34&ENobVVYXmHCsHrrI^^obCO5$-*m)9;jbu%U4Y93n(wQ^y7?KDle@ zZb03rm!aC&YfvOYB&aPQIh$u`liAp~=vb!S*}O$&3?6=H+fQf=$nY`9oy}vh{3)G+ z)3j4M@AdW*!H9Pz_IKdhmkss@4iW6%-m$@o&*oXW?G5&;Huf46iC{mq1th0*ENwF5 zk&HD1(!T~{i5Z5g_no(ObqA!^QcEHzW{iKU15t24>)smRTCXtC^U z2T2X>#7dbZtux#4Z$1P>uw(xu1Uk=vIwEk05Q0M;yFA-r=}w43AYZg>s*Sw{MIwZN z+A$N@(k3&mBkIp~EGt}3XFEo(dD}mIRisH+i{`~0ud~klmtO% z4G@IDAwm#NaP0DIhoyUTp=-}}1VthQf!gKS4omx3YDfJLJ#KuWYHj()WVXZ7=1~lK zwqu1^%UtwWuYa~U8NQau&33R@-?JU$l|wefvmNICTEGg8ihulAuV0h)_Fb0$bW-+PxAZ zCjFZ2z@V}5W+RWU_t{M~CS=r#35(V0yppv&w-Fpt}}*s4rDtY2qIXsc@hYnOF*3wI7A3UhhvxLKrG!Y z3tf8-Bq$Og5Y#TufmqsGQ@dggq*_~clFWfv+B}Ld2hz`8NvB!uocW7a->x|$!&f`G zUWpdV_DV=9Co5cRE2lDB-Q9UB;TV%Nd6+ze`;wV_>z5>QvV*WRx>7#I?&OeGrIXNp}*2xONE~A_U=Z z$1c|{mhQoYu3ftXMIr=&+U45C(w<1|irS@GTXvGvE|xZrV!*Xamsz`9J#OA-HD_eh zs$H~Lwss+@oUEa%UH-$FftrH|p*pHCA76O*yG}V|BUDoyyIi|iy2msaAJ;BHkqDup zc6=1TmNuDj?b0~rsdp)Vx0!+S-f_*(H3MY$4CLlNSWJdI?$+McG9Y(T57HV^kdAm( z_58DJi*MvPda8irFkI3=OH%)X0g79z~uE2h%MyHkb{$+$Evvo>bpJ=M6hON5(pip zA`pQ?gg{*B*kHwLOD)|?8v>!)*lSQELLjIuAQ=K%+GI8cqMu#Q!^|L@aqO16Xb{No zLCAGIwOF=sAgLh*LpCAyGampVSaDqv0Ik3gfWRR_0B&;Za^qm>-p~*L)y7_fA`t>W zZ2?Kw)6yo>ZX5=>uy~T0hS9UmovLXd!>1uP|G{FlPPLKBOf-36@%=s?L@;W85|4QP zBXEcikA;q1p8v3P?~LMs{e)Q!{1z065D#j{Okhi!Ol$rl^dX{{^mTi~3uHICu6VMU zlGD47*-%qLhEGZEUaTy}S+e{j8JV?0V%-LFZ}|iqz8)lq!`ILG_f8fB^IBW3lb;;E zE)>M3=pI3Tl$UP5_aPyIU5k^De6XOR4hbA0?B{961`FD{S-MLaLZaH(YfvOYNT>}> zWdd8;WadNC&z{8;GaNf#`Zs^mW-@#@ay<(c>$_(`UPGIbb~RUZ&*Bvy3L@CEED43S z{s=|j5Fr#VJ9fEeVd=gYg@UKrR2zE@ibMznwFM+S3rm~K#-2svRs-2?~d7O~66>i*hIQvZMqBx5DKz5Qz(dG}jgU zt^6jJ*zj)7MXqoY-P!W5@=q>uv%r*JkT=9ppqaM`xMrr*mcia75L{ zUV|bL0!M97l?iNVlgYrz&7I|0SDVSRt~R@AWdv@z8Mt3;w*Q?PI5O%6jwK~2LlwAU zhpR>4cJqNFg7w>11}<=j5V&2*u(9W|6P-2F<_i zy~aP(o($iO%8kplSaw`aQbQkV$j0Rd`4A8x1YJo8bnJ}oQ{WIG1P3~Hd0cMk?iYoC z-6z$?UV|bLLO^W+$++CoCbO?`x!k+IkFL`TvajgL2D8ix=WWjqzd|b;lG(ALe;J%YN?qYYFWdku<2$RD+#sZ3x?n@mT}W{A{yUn*ZEY3p9je_*&`2D1lu#V&BK=>SeK_bHr&P$&2ecO$U<+>_D=n z$?ruk%gmGOvKM-;MO*1z_EY2tn5EwcVwV0Qh*?@LXr0LOulg(z!PR3cvlKW)*w0j- zC1~qr>7GDc*MmaIkPz%OC=ww{)Q*|JmNuFBE_*-c2j-X&x_stYk7KX8!`1rh8yGYN%`;ZeZ^4iT)q(6Paa&pcSV)1y!{&JP4dB7}n40+RUw zOPkE<`GI~0Vy+p8`~USG-_s$ZRv=ic??8~(0Xr$ zL{KC`AgC=M352ChW_2LKG;{xM$TrVR#+FCCaJg0$WcXy{Zpfy^26#g@7H43Zd_%U| zd~Apin;VnZXcqzXNZ=45Hn%!9SWn4IH%s^CC^qO`rHxBaBtmSc9W#L~Z8F)o$UM+d z>&ft3Zh>-wJv{GUbQYM=xoP(E>uPk!s1+S8Ho)kx_-YZIhkbO25S_a#qZ2qph|VH2 zI+pGO+2{mCB1DJU0+K$irA_9liOxbZIxRoi!!MN~qgHgZ*Z`x$;;Th;{>Mj$2+?`6 zGCF}ngy=kHM#s`!nvG6SBtmqkEg*@GrA_9liOwQ3I_r;me74p)WYmg|78_u6SbVjJ z&Od#0h!C9>mC*?tB1Gp6Gdh;;tJ&xTMIuCp+5(d3SlVQ+n&>Psqx0S~kK9|MLq@IW zXt4oChs9Tm=xp+KJ@-X~=nQx7Z3V|8ano^Bs@CSuG)guv`f zV+%@L*8~m`0<)K6g9UBfEZwoxt*C2)A`t>ZZD{II09)E*<^$8uIhqw_PPSfl$?lpH zGJH;QlXfiD_Z$s*j7H@{Ay@UHo=^Bt5Fr%ZNhsn;yTBnrC?+~~dD70(Jva(Q~ala=^jPhiW(#+5+N+qj*kM^(k3%sgQSys z^#g<3DmUJy<%Xw^e2)f(j9P)wV*LsX3#}G``GyY+5dw2kWncn_2!WYq2FB7oH5-_q zNQA&pTY!%(u%%6=6&QCpWY@^;PHOKQx!q~)ZQVV8AK4-Q{k1sTyT-pP{+IigLHC>m zBhUG!{9kL95oS>S{NaD;)u52!gA%tnlcDI(HBRnjv5_5*jqG@+yT`mHax%Ij|`(o|=pR{Ck_Q{|H|Sa^U7gViD@ zq8Y4z%6nTxr=@@FgGB_3XD7jm+o!-G!hUXWY_OoMo27eQ6fBesl?e746p0WlYR61q zOPfqqH+`=p?d)@j!wlIE!qp{1qESV-(uG$KUG}phG+bo(YA1II42#91A?s?%Hq<<% zGA2#F1m-Ru6CxOPOJz&~hX`ih>0@%A{HB|wJ3opE_LIgWC=wwi)Q*|JmNuD;N#FO@ z@B0MPWwIY_o!ZQpJoe`UF4mZk;bW5P_iC|zjhtDi)KqoLy(?u;Ct<<;X|h&b+N%Mr zP(MXJD(jV-1obs?e!`iE#)t?;{+h-L!WP#nfkTA-EOBhG;*qnZyO_Ea{obHRguqZ+ zfIkXgOPfrq8xtC>evX_w%$(fy-krDAoRHyj68B=daiG2z)7{HreUF^UV>FsJa{h}C z1rb8=OcIKC1Gy33+aG>)8uA`wDCZ2`&1+0rJnapc_31-+eS5N^Bv z8oz#%3?GEtf?h3_UC>KXLkfm$LGN0lbnc!A0eCG5fG)a4%@H_6uJ&;XIK`%=-b3t!$1gpz} z-YtCoh>(O0+{&PldaOqUeMcB zgfQ*xUh<8jl%)wJX{Pgi!laS$akn7)Qv26c_q=pm>S^wr!J^)0pVnPxC?SmiyfkT7< z9O2mI{*9%3XhQ&08+#3kLT zYGbcKkqBX+wt!@)YiX0&*c50WqH}({Urgpfl$Xi=bh2!+nT*;0SnCx{1{ppXxydpu zCX;3Hy_G8`;oUM57Gg|R;qv`DlV#uYVIhKT7bjuCfCC$vjldy7Sgvwxu;TuRr8_GM zOXHHZph$$UP+LGUEU~o7%ukkuz~Di2`RfehN%$#dVE(+_y*FxL$nb&5O~SKSoR!K+ zcv2aYCQriu+{c6nF_}{tlfWTDOm6lui6`ML-5aBrU_Zfp{1z065EE+0Okhi!Ova?| zN%;Q7WU3jHj~=_tnHm!^YQ==bYQ==q)gmUp@-ZQTVRux|uW~O7w-rxF-rh^Qhj$D6)#rp1#kk{n?$RB(th!BcLlTc`% z0ZmNc5Fr#x9lP8gv2>q|LeV(&9u$cX3Tg{T`XiP$nYH>Oecn#td$K?6k4!g{alq%c z^UqHw!zV+|rd2L`)nZ&RUEG7Jqer?Yd`x!LJrG>KgoRgmzvNc=@SM;1ogmI2)xqbHHe+JxZkdfqP$WW3s4XCgiKR_u-Iz@3vl&ADi)Kg~hcUB@n51U_ zZ=7}dFpUWr{tVz1C>&a%3HShhdBB8TEyXAGIdkpoA}7L@ugAYdroW{-}AMO@jZVW&`Ok3;i`fu{+p|ou%8Ija^VALhPt5Ac>u&O=jKLP3ZF$otO_pZ72QbF>{O9rKg(Ty+yAd ztdrpz#oVc8Eyne^(l{3V?uNTZNd-1d4nmgfR@Gr{kuLQZrj@=(_Y^q*R$;#p#44=% z-cg_TSt3G~4y(*k;1FRyNBJx*m)~@=bUz(s2_-{9u-BkSge*}zW&&HeW3Cf*nX0bj`HIv3*R4%0(EnflKqjo_n|5WqWd?biq&hbek zI^`W~7|#a|5sW?6vBBza6qrkd0Gv&u@LkKMr-M@t*$BW)$1b00wsgPQ z5CGN2UV|bL0zhp6{wRPgZ8BHN*~W!t2&TU9&MP$pWcU!|X7^aE@7X=_8gekSXB+>^ zhk*#TT#hy&vJ2<_RU3N^ibMzlwZVeEZkG09YDfK$ zdfL!bCa|T=qtFK`)(_ZHGhpW(x_Ge$jEsQ=Om(UQMn;nZ_KGtG;UR+6&lEwx7aqR; zltVTG_OfG_17_(iD|CmM0Sk&m2pF}?0kgDUq;^HXs5wg6@@bXy&Bs}?(9L6HavqjouAmi9W-u1Hw5 zHjY<6A+V**qtJwf%hSRsi!NUF+VgzXgYVrVP$YO0BzP-|;H8r@Z)>^fb`2gGzVq~n zXdb!~2kGabJ9}9SXFz%7t9z_h)%1%y4O*0NEB*Ueo;8?9d)+9<$?z=_#PIz_(ErLy zxA*w)5g~k|i;$4>!GenL1r8Cyx2A zXiUr6_+x+SD`{16{P9Sr+PshZco4y;{gQa> z4tHcjJOYOZ@i@e>!Maagx>>phQr9&i*iSk|8x)BU4{FCuU`v}!))D2kdHt*-MwqGC z;;UhBPerbd&|=v-f~4lv5#M&kz+fVTU^>mhcQ2d%b*3D$5rRt`8?3mFuyiksLeN-8 z1Vti*fZ785Q2<-oWTtgQKO2ZP)BGnFp5ssdl2OZiEtWN(q~@9bBX2$t%)hGA{JG6!XThiU#RFaP~l`j<~eE%UWl)_jthXZ|m}`9v`P z=1TJehY02`FwM7gZ_Sz?6p3IywFM;RTiRp}%KT2#{Fe`Sez=-XMlJKTSk`=!nrHsw z-h3jM|3IbrfkOoIA2ZFjbQfjK4~j%EpV|Tv^DS*M2W9?P)BNs3w)vQvPev{CwOH1C zlA34!3*LMpn7_2r{Jt<<_ zIVkhHP4n0O`c3as^U0`Xz81@xPg3*De}^}p2PF`lR2zE@ibOD<+5!^uEp0LfW&Q-y{N=NkU!dlbQOkTSmNlQG=9&L~Z$1%h*t*jE zz#)S9JDTQOx*b{bgCY^kr?!B^d`p|m*!=qE#}6x9PZwY;x_g*+os5B6xp+vyk9`|DT(;(c~ol~GJI{5JA27uID5%! zuKGTES(I2E&R%}jnTB8y!K#TxNMKAjZV(CuFh9xKxAuQAukeuqaw8^x>!ltXoUU;K52o~NthM6mbD!hC$mp+lN-$VRBcv|6l+AW?l^@$Z)xsWli%0+dmyTxRbGcd&6;(L4$h+xT0Nf5Mqi68_H z5rS~HW0$+dmhQYlH`FewjlBj%A_RfjU_oCuOZyILN3}~mZD=YJ*wW@vXzfye+%??{ z*nL}1^0%cRV_*SOo$7#*(d2;r!5M?_5W(sPiy+_&4_|-EAsYc(>e%IgS-OuFy2H$M z$w83_0i$*~V3zii)UF6vwRZdofh}zwMgIdf(+t?Cc^A*s8jOsA1x$6S14c%Z1NKj6 z48lW%fIVLX0bh6;u)rZgz}|4|a=)pZdp=lHt2axeI++tj`O5Nh?Q89;Y%Ek5lQAC#kf3 z<}R6WFFMcdf>!>8zME{Rrw@n_vElAL?U;7TJJ=Azz#&4!Hg;^VdgY~?rMn(=qZp_* z_8Jt45HV^)Q<=b)Hksusxds}C*=8Ijp190k6+uR=IIvisaUiY9aoEnsfe6NISs91G zAwnEF%s5!OTW8}C6p0WAY70o>U}=-t7>9n2p5~Z2_{)h0`MZLW;d781J!!G*=!v9; z6b#vQ-yik?AVL6kP6DtUzJJ+J9|R5&0>qo8v>x(*lSQELI9`@O=SXG z+GNI~r|$FnY5v@`t!3vI{pa6y(JlxXwanLIS@TJ1p822f<`cn&?n?6mhY03RG|jhk z56+q&6p3IywFM;RTiRr%<~Ppa_U|cu^UO57^}Yu#*EEpf(~w(W%wn~k(nl&Y(d3H| zzU1RUgm`>9iO246M>fj;vXS4VuqhkyunoRow>t7e2CaEK6sX^st6+(1~m zr$!-YTwoj&i4X#63rOk+OPkEJj_79tvCuUC>V4YRR`bcIWxf{6nom;m%)iW=PXzP7 zS!sUY5W)OQP4g|?nOXCLA`#4|wt&QZOPkC=nZL+1fA`(?`JtLmMlJKTSk`=!nrHrx zz4=5ie|Dw$fkOoIZ!pcbbg#>r9~6mTKD7lT=3Cli4$Ax`rupkWKFvSGjEq|5Yq6~P zBsI@`Jc69d42fX=EtTd64iU`1(=^}Gou4&7C=$VZY70orx3tL|l=(|d^S^r1hd!x) z`DD~GUyEhUC#iYnKjFRowp9tnZQ)zzS5W)NxP4g|?Wm)rsA`#4|wt&QZOPkC= znZLp`|LLv1dXJh6Am9`*Hq-)vLxdn4=-B0x(3Wmjp=+On z4vItw0=3I0p)KwGs2$ZXdffO#)!Oop$ub&Cn@15&LickbX+yJidF%C8{S%GJs8zdY zv25)^QaM>ew@B}E&I|;G2o@Y#n2#?!{9UIUvJt8y9UG0rT+oZn(mkTV__%2aibMz% zwIQiYU`w0KxOVCHX{J%8`B$EC*l4X}$f#w$7R#DXQuECJsyCkq<{w*We&7(n{Hdn- zmhK5z^MfK0%%`@1#C%Je%t4voW}3g&fwP`a^U0`Xz81@xPg3*DzsQ?U1oO|VG(T{N zVE%=s`IheVtocEa2RKmp9tp9 zsx&`vh+zJ;rumlcRax_cA`#4|wt&QZOPfsF{GQjldtNf{yLzrD>wQ-{P49oT?6Eb~ zdosNDAB}E**@a{Dx4-P_WwD;D^#!MN!AEHEadii;(vV?zvCynj5U={!Ly#P?bny=H z?|ohnENN}INPe#G&`;$jRdDCaU&>3j+r0Heu>Qux`i_E%7C&%^u%BBU8!Tw+X6fGC zV7+Q%uR)Or)>9jr$^^Ew$&9V9Kb{y{n4XR&{&njMCaURV3~W51I@RL|GRlAcLp+{% z+y{XOmfW2LLHp$hLf{Y~2#+~-c|2k1K2Ye|JI*5GctT_^B-HdxTs&C-1?N)Jk=>sx{%5t2#mmWylp%ww9pwC}nHDQ>WC4kg``RQx-Tx$jUIM zfRsU7H%s@8C}oWg3=E1yNEx-EsaXfMw8>=3`hH+w-}Tk)vLCIlCYbfrySBY=jHZkX zUtgUbMXU=)9QBU07$XxRCd=$ug%uG)s8D|~Vp@My-9_9z#EsIcyz*KiN5xpZE{L(h zgOoRm?0<)k6%k^!o_lXALDtkxRRMD~NhaW7JnOSg5(~ zd6S#L_xmIfAxT?TCMj@;kcS<8lHz92((TA5DJT*lNz@jQB+1ey(@s)9Cuk>`!MXLE z|2{*5LxvAdZkeYR%MRB_DtFbxaBUO$0$3496<-Y3@SrRX*Y*@7hb%+0kNfwI76fxz zTfQYfS)Ke$5LNJJ5?`9XuMYtcLNGQ7fliI0Itd&i>}Q-~g9UBfEZx1L5Hv3H42nbu z0kxs2M*(bUlNk@!!Zksm57fV<;FHZX-2dUOX_^Kyd>V2~!C9=3bXiYf488E<<;u$biz7g zU-_MN#wP{wz2gP3&bU$#>x?@DvCg(YI=2uR)Orp`bQ2l?iNVlR4;%$EKP=*m>%LDH;Sad=PSth8D{<8YDHO zV8|{WJI@Dz2v(e$1VF261R!vT5P)+XyWD74y3-m0pxW4LP$WVCs4XCAG%Rg0>ogkj z43qBaJBH1WeWCA(hnP$=)A02#jQ+8vfefF9T%*Ba(rDlz)cJ>)kh)ql8sGKtAc9dd zlX%39M&J-39#=YcxzVt6FOA}X{iKaXP$WV;s2wwbEp0OMjmALx7Sqj`OrJ6DRE-H4 zwPM0zwfYvMt`;%*nU4t(?7OZqCV@kQnA~K>#L~SX8mGF_~$` zWb5NU@{GoWj9M{av05=9b+w4e{XQl{h{^oQm;??HVzSVTiKTmIHYP!l2r;3yfFvfC zHktXDxGw14J+Ia5g3dD2G4=zOwQD-a@af2PL0N2E&wbrJk9GI_#+qa8#okMy)`wSl@vlugQUU#Rq~2)-0NY5rW({Odlw z-S5?WGHRKx#j@s;)I9UI^5zr4hD~V_zH`~sAebLGL@>Y2G~d!4oi#rw62W|G3-Ct) zY-y93ny*bk7-{tHWXL=-4d3|26B}q6$na^%oea@pD`!mr)fk&5pA6Z}Cx{3M+CE88 zJZ23XA|z;6#|GD>IKe;5kqlp7<<of`D@M7<>l7JtuSc?4C zfiq+U*Z7_GoBhK_X=E*vbqB4iWY<)n^dex>>p>P%v(C;gLmY6l!xjRhucb6o?*JQat zm=??S!%1phKl~ye0wUOPW)gz9A09YF2*HJp4Ho_|bhC7)Q@3Ie78HpP0%}83j{?}z zCNu4a_j3@o)HMG;Z$EdEc9zJfWxf{6nom;m%>RKmp9tp9sx&`vh+zJ;rumlcRax_c zA`#4|wt&QZOPkEp{Ki38*Z7{lkI$YJyiE3mvx3qfj9F%;;p)q-JxS9*hEKy`(L%>g z9JOEQ*x9SaZF!vB842 zZkF!NQBZKyX;Tpti4YWO$4p>Ln@lzp>q}Fyo-`G*xa0&h6@v}T3NtY8{K&69uYn<> zR$#PPzXHQTt3_ZQ_JJWnVD7FAOyCe9FpJElX`6U1@K-h$Zp93+U1 z&*%JmCkujktu5EdPc}Xa1ySW5L4TB&ZvXTlA%a~il91pDb=WXf95_VS&l`>n7PNJ< zbYE=95>jt*iPpAveU0p?-C$i{l%Jp$$I?PmD z_o>Ua)&2w-J{7t7Pc4?60wbxRGcja~P`=crAs~V|pLXwQ2)2`Vu%V6!93q6^m^LVY zHCJA`S-MBHg%C7eO%)W05CUpLQ;!1J(k3&mBkJG$qO)*4z4^tj-t~`p>N*(%yZMFc zRNwr9jB*Bs_~sYqwP_HD5QLN5dm04XdIB4Q5I95#!ntiwI8M-i%S$&)_tZ8QgqC6E zBLjmX5rRN%90Bxov$UtRl|!b-jZajq4NYYNTiQH|aPtf8f7Gm9#uhnCALaJ+EtkKp zIU}Q1?V`o9wF^n*WDVW5n%`~HP!Yj`neIIemHu5LRDnZ;P+jTR<=Vy4y_C8YXIFwE z5kf_60ZHv*X_Fb(F8w~W)@7PM?cr_xjrqx_Wxf{6nom;m%>S7)1jZ7<{OjC%mid80 z1oLll?6Ucm?hVwfFh3{~!F*~9NX)mi$sCmV-KP2PIdzi1yq}C(=4-L6`6M;Z{QI3D zFrNtK&v)-x<_8WD%wOo(W%K#(sqUTBtuQ|*62W|G3rNhjw8e&x5E6O zNCfk#Eg&)9(k63I=1(%s-)P3aenZVCqn7zvENebV%`<;p@t6wX_Gl9^Cz3;kG<#Jt!h3QwanLI zS@TJ1p7~pO^NC=?rZfrPvuygc!~DP@g86Nx`TX~^%;>E7L6HdNQ(J&P3Sdi{%t4ty z#WerBhkkjunomY8^R-yke3F`H{%+oUBACB@rTKwF1oL+_&9`(rv*rgyBA8EY0g3sR zHkpGmf2wKzh;26AQq3o$mibyNYd%TMGyfoOJ`v3Csx&`vh+zJKrumlcep&N_A`#4| zwt&QZOPkC=nLo`mf98MnPFC~DsAawu%bHJ8^UVL8H=hXRA6jXC;1I$5BTe%y-6OK* z2Sp;7Pi+B-`Ia`BgED`*Y5pxAyuzPiB%_x3S}bcmNzF6=tKNJfn15`g`GG?O^QW5T zTe>G?%@2x1FrV5267wx>G6!Y;Ow;^*e|&Jb^Mzy7GGB{j%_pgO=3nH^CxZEBR+=9; zL@@tC(|k*Jde;1)NCfk#Eg&)9(k63I=Fc+C-~E~${X=)jsAawu%bHJ8^UVK&H=hXR z&#E*(aEM_3wWj%&?p0aygCY^kr?!B^d`p|m)cnTPM}1$xe6#Ee=aFS$`k2{f8pi!< z#{Xz1fDE68uSAO$yKvNg(PCGx7HhbI8P{n|2bY&^b>R1D^1EEORk^a>-5i*TjLs^& ziuoZq7A`_~NzmKmwN}fE@^ig4it!I~>C-7MV)q7V#sMAgP#gCY?^Ky6T!32bST8CNCs z7a`0oTu&DvJiX_WmurMk#FgMAh10C==My=22+C`n}L$f!Tbmxyk*03`|C?=1YrZn=g{e$r`#< zF7I+?phhBs1sl^Ke8;kB!;x~xMyTHD*yZNS(j7(JsAf@Z>@_G7Aym{B;Ew{>(k3%* zzQR?3dY`|ZzjpWh*?flB`J$@pC>NR;*t`41aoU)X;WMy*)c@_q@%jF5cQ1>{UET6` z`6I0%1?gS>MvF8%qV0k%mRD=bSoyiJL*wMfZVv)vx3?GBsihCBzuedKbOov`X^>hY03hV482~ zo|`p4C=$VZY70orx3tL|l=&-6^WV1oU|;Q%QOkTSmNlQG=9&L}Z$1&szqHc)z#)S9 z*O=y8x>sh+4~j%EpV|Tv^DS*M2W9?iruiq$Sbnws<&#m%d@YtWpQPrQ-|NjMg84U8 znjbhsFn^wDzNLFp*8HGI1oNpaATi(4CUa2cW0cf*qlWLFu>RN7d@^d8uf?+Flhi!( zAM)lC!TdWb%?}(RnE#+@zNNb`Ykp89g89@IkeF|2lQ}5!N0{ax^6~+fs`+HpGGB{j z%_pgO=0EGrCxZD)D$NfZBAEXt(|k+!>8$xdkqG8fTR>vIrA_9b%-_&7fB2ri{g|3h zMlJKTSk`=!nrHq$y!k{h|HVr41BVFaziygu>AsvbKPVExd}<3w%(t}39F+N^O!FU} z6E2x1qn7zvENebV%`<8bTblbA#2Sp;7Pi+B-`Ia`BgEGIvH2(une4|&*C!?16S}bcmNzF5VPj5aE z%@>3K zRG&sBqnv>uUZ?QyJ_tkz!hT5*q|tU8nt;F|LJ$sf?DA=3OZUJ+cbK_OAt(|d2-LaZe?nkO zn@7?AfOVMxd+Z0-d`SaF#=rumI@JLqqsamLmNN$7Aws}TFM@zCJPlaj5FubQ9lIPb zOZV(T*A7@vBtpQbT@IL~{Y`3D1gu&+{)E7mHjhFB7S=)x@J^=PMefquzZ~?#6@G$@ z4BubM-II{T>fFhcOvbH`+uh1{S*&Y#pCGP|*jo@+M;s)Gt0O+=-|OFhtENg2qB=hfTR;`X_GmyPV`}g>uD$YnO(kpuDVXfz?vY{scwSEC}&`ZJJC=0 zAP^x4_a;F=1Aq-d2pl2=VTogxn;=W~*M+X#1O-JR1cBP+CdkrWOzny$s9IZgl60ai zZ5~Bq6QuV^uD2X-l3B_8>HUvCuW=*8S2DTfcq}HjNzO0FBdr{<(p{2Q^>VzwIBO6e zB1G(&A`1BW!$P=}LpCDzqGNXoikIVAy2~13fKu47*Puv*h*291Wdd8;WHv6x)9aM_ z7l+Aa9G1;_*VY;bGHS(v#rli`X-$s9TJ1V>O9W$HtBgb75Frk&PN5tJOZUxe9D*Vd z;y`TyNgOO~GRtw`5WDB^=IY!_L{^t&PAU9PTc70@pL~bE_vy; zm5%}uqOgH`Pbcy9|E=;bfkTA-v^n;%f}pLNrMqdN8yX+g#$JOW5u!kCu%NG-r9GP3 zQR7oj8=A^=*y*(5U59XFJPK`mYR7A;d^=bOkj875d2fG7<3+~6;zgZIyb3~d0Sd)E35Noo3_wT_9`7kZ5Ewkh&>#th{Q3bcu#r3qhecTz- zD!&pTVEYw8Am{xBHRX_v{T$-hV8yrVwR8`pZWIF5#$JOW5dubS0WHb|wzSDCH)Y|X zqn_7$UNRfBb3{->Fx?EnLod!BuOT4AhhV=b1YI~Zf4NClFN^g&-t(Z90C)X#K`B)+ zVFcCoLyuq?GyjuwTpJqY>_drKC$XlkGaSw_gRK`!tZux zOsjmgLhoRQ&sLb=lkS}c1yfuwS>LSJYT z`Jim%@VCom5se|6#XSYFS^T(v?`T0VyS3$8@{^6>&je9ruAq1z|A;fARo*3nz4sR8 z3zRKBoe(%g*w13eE}u@Ybbn3V$avMpUV|bLLPc!>{wRPgZ8DR-(E0r|f39i%%e$R^ zgPKo9E%UWl)_jthXa1j^A+7S262XSw(IkA&vZ+BShisU?%(2VnTe{Csx5E6ONCfk# z9Uld-rA=mRe*LCpUg3J$wCu9eX1lBFWDKlnQJw0hg^Y3rhPY{2OM2S8uLlu=@Yf^= zTJa(XfkT8Kv^s@y(_-nqR_G2h7i0xRA_RfjID)uov9#Z82$>!?K2f!{{A1FzSlT=a zZCdIFY=IfD$v?jORSg&!0}GhyR0oWVCI@UQA21@=v4ML}C-T%N1T1if5U@5gV3zKt zg{~d2ph$#(QM(*4OM5i6qgqUl8=t6JTmCT#n5E65=zqW#ngP4?>B;ZYfRQnP( zz{qHF!1i>;AUs5{WBVcq`0~TopK{1X!1i$Lat&tbb{4vJz=9$X0!Hm}z%1=usa+AU zYVG(F0$bWV3JqA8B&>N$ibX}v(#~<`{JHPaoRLwhf275-{Uegf$r`%O@yDGR2n-QI zwO?UAzT~uj6gWf()gg{u?jKpY2R0b5eJ|`aC=wx5)E3}-X~32?nQ{N9-{vnd&EI9K zckQd@lTpijEtWN(q~@9bMQ=V4Y&fFQ{Jp7aT{307)O7#*-y7~9z(t1X{sbJQKSMB~m&HbQJlJiY zhMa)2L?qFDzwB~k2M+nHyE{K~*QTP$5$!t#aa_E!AdZXo62x)wME~9w1i_V7$L6>g zH=U&lri<^Emu_cx_le;C35omL7gSUafkTA-obK3QL0dOVcWUH5_9HD-Ck9wG$n+9C+}^267ka>z!& zZgK2#z%1SC3tc;4L6Hanqjou9miAm~R|KqDJN|^gmNt(<1J>`(%WFl>(w^%sYtP+Z zb4G^Qe0AZVeDl@StHtu27pGlL*3k7_f8)$RV2BW^1%>(eJfYi=a>z!ge(l)ho~xyM zZ-eo1&ow9#Aym|kj{?}zCUbC|7tDb--dW{~iPD(*0fJKK2v3B={{T62X0H$4p>Lo6LcAUPctI zr=6F#|M9#7)park*0!ilb=yKlxds^G&dXaq2t=@Cc@hNF?AQ>5z#&2q-gNA8+hXbd zwa~TOmY_(4AW*y9wpiM)QM;mTsn(XAB%K#an@6E-Oa0EvhGxL-xc=+@Ze3&yEMTfr z9WXMQ9I!36)e{Fq2-pbso;9xUsHihxyX z%TAJjS=u}b4OqWBFQbZ_rJa|LeCMp^v?3$JY`(g1fWGeXV|&I?K9WDQ;CWhZ9_ zY9u0rs=Y8DpC|3S1P&2G)#=#f&WokHeS`6F=Ori-Aym|kj{?}zCNu851oP|N0lLlf z{+ctM@z=bP;l0n@0h-0~cYrQ9l}j@*y}}8TEd_DfrBe{6UG@;Pj=Wl14)O1OUJxv) zUYqwz`B&XO>a8b&^}8q5cNA2_BXEeYpZy#gtaxpnrQ6kDy=r5xL6Hd7Q(HiC2WU&1 z%)waSVOrny(;fa(|Ln=AWj%}KtuHuDv;I@wdLo!Gq0;)mA%gWsnATgmhi0u0ibSxU z+5!^mEp0LfV|}M-{jgKsexF)TMlI`EEN^|mX`1yXdh3Z`{n3@y2M!UeKf$!#(mgh7 zeNZHV_0$%SSZ`^Q8Cze!J2|#6JsqzsKK9u4)pRlj)}2(H>h2^Nx|G*(a5H57=;{?S^94*~53thWA85D^S1ZtPNla}^$YFBh8tF>h(Nq5rH z=22*OvVOq2%z*v;^3!`XU}Ov|V5(CcFfy7Pupc>N5FR1~Y*rBjeEH$)PdQ{GVAnf# zIbfFVRfVn{u%JkUfKj^~FiZPdYF7lTT08!Pz?L?TLIW1MtRruEy}ROSqUj=~R}*y? zIZMYY=U?>OJv3)z_||KDbU8^E4k{Y2uvpi~Te1TdvdYm~IRh5-ape<9g;Ra9@R!aF zB!&p7y18&)plmv*NI7I9RSO&&toUT1rF(0G^Qw)#21O#IirNDFQ2<-oWXA1R<7I{2 z)%Q&JrpRgvCYUL>s_Q%cE>UFo6dVwxpc@D1Q_$VZVsc?&cmAdcfL8P^5uYSg$v!lc6Uv@5%O-HSf0EdUt<>uFHOUOF-sOGgSq zDFLo0J9IZlSo=LXF-inOUQJ@46Qqbr;1D4OBb>sqg5nz_Sh{Z%x}l??+SqGQBti_R z4Hoouv$Th~qlllBSWg?8$^^Ewc@&KujhgEbC!1Bvdv^N#gBmk3eASY>SVxOx`xzuP zv@b*Uh^%+{P!Yl2jcE|RW7)JXfKUYv5kmD&#|CSzymYg4M>QC)+SqGQBtodD4NYYN zTiRqc)-AFc&AfW~+oGcl$`rG5`Sc45yVP|u23EPKPW3Q`jB*Bsc%1wp9|R&;(vbuK zg9vO0Lf{Y~2)jG>af0G;vZcFYp&M!!)y7_fA`yZ>ZLpxPo29)AwW9{Co;Ea<32bTe zC>m>*dNc1+&C2E0H-7hu#*7SKx#apSESB%L6r5746~-{=p1w_9YqhMJnfH%5D-ahV zm^-epUZ89p{GW?d;1D5F6C4|?xZh&w?oZvwcGbpSgCY?kMQs88D1a?(GUK`>j9_av zEYnQycfIeWUDbOsy!W|=MT=z{7Lv-9N-%#_Uj_OFZ$1%hI6N_5t8@e;aEM_3(T-hi zSS;O14d$yh_8Jt4U_P}4Bn^wDP3EA?pKh9e&*tM^Q1i*CWxf{6nom;m%>TMKp9nTg zsWd-uh+zI{rumlc$yxJ*A`#4|wt&QZOPkEt{Q8rlGYi+#Ayufo#3pwJy=UIiKyi4X*8;|QRy zo27j*wWH=mj~kz;S{s_m1h%w!6rop9zJ;Vrk5$}u>wHnvPV6kRlDTuMgOAioh74cH zR!Cj-o$t)*wDaFyxvd3Ib*8-!w2KwXxg+5N9(6e+j?1ST+c%X_T1au^V{(~zqW3m(}p<{QW*|^xlOl( zL%KF6wNL2oIj#LLTzIqh5qGuAPTnT3wOV$RpO_wRZP`bDa{lySL7YE5%D;DtAXwMh zGDm*OClvI6{G`f#f}WL^ZudCb5D_AnHP5}L^9j2b)RaRu_H(ymg9UBfEZsY(>uL(@ zN5(D%9lr%dB1DARASn~r(k9cs%lTkqGRKU`+V9+Cw8n&tS}|d0IYEa4{8!>s(vCA>BbRW&eBq$OgCe)6P0@%_f(~3#`-pkw~4r%XY$KPHu zT;o8-zaZe?nkOn@7?AfGsoww(05f-_U@O zF|dHCPIbV@XmY>~aK<1!L?Z-^ErNhAJPlaj5FuduJ9ar>mhN7Kt{t$TNQ8haZe?nkOn@6Dm>-XI8q9SLd)lbV_ctmqXhVPl@=8n%Vie;w{Nh&96=;n?; z>&!r?h(-vSSeTD5IZWK89I_FrNse8fJGOKWr*33?Ja-%vi4ZDk$43EdX_FaGANJe) zC8qhWed?L_s`+HpGGB{j%_pgO=AYsWfw4p*1RX<@@IA|>2BjRbVgAXET{hp+okHCT z^MfK0%%^sI6u_1?nW_0YNY@+c*IfCw)C|GoNpJtPhJXwog51hC7VCTE8+i>m7}}L@ zGn_#%nrMWeX*3PryKK7VEai}mFkIl+<&|%i?zz;B!l2sNYfvOY7^p449|f?bO=jcd zUO(?Ay37p1@SWFwy9R*_AB0>}pvAJa0Z9!h7_#*#-*=|KTq0O;DUHH+En8e01P&1b zaE)V^YXeL7O6o=dP;KlrC=ww6)E3~60@%_fGp!B!Y5oe+{NLYm{+4P!8MVyUVp;P^ zYM%MM&JdVS1RHLkN%)>+Q-e|t*)V^eW0%dhbZ??=h512|2+i_H%lBAEZ6W0%dhbQe;$!u+5} z1oNpK9|f?bO=fET0Q&(g8{lNjQ(s9(0*`(9H$DVp_z>j!0W8*cKY+Z391Lwg;8|x7 z!ay`a&=Q)4?_D-+t5Xiy2*aNoyW9`3bf2bf6b9ACUV|bL!a!{S{wRPgZ897C0Rs%g z2s02reB?))Ypp;=tw69?-+>^n$$|KXGYMuB!I~Fo9KL(m)U=dCHUjawW0wPA>Ap!BfkT8qZ0OkKKv=r#P`4rwL6Hc7ptb-XOJGZz%)SFrea+PQqO7YzMwxk7`p(_v zYaYn(dC08_VKK=={*o!u`iR45ImoxkYps@c`N>oMV+HY)|2RQB<$t(;?>IrQskP+_ z`6=BYLG$G&Rj_j7VR`BH9%m8$_K6UO(X_3gbQb?lIb>r$+d4K_@v0C@w~e|{98?>7 z4T?mF1GNPtt3oVoG8^O2&#^Efuyl8&ZWI93#$JOW5duJMC@K@!(k64IbRRp+5Ip_E zkA6f$K!y)NuKUPheK!u|HRNDuyN@4t2Ek||*s>o@!}l&*+&Bad5yEhYW0xBTOZPzP zMqyBG>@_G7Aq>(k8R9HW*;{vC|C1)#p5aj|PH_T7h7(z5_vClLPTZ9|$5? zb3|nz0*45Jm}~~Z(mgU8h@eP>Ku}vi5(rD1%#{|1v1TCdJ>ZKwXduX_6$lpVI}qeG zIS^;~KoB7iCsYO^aEK6y)6GCwx>K`(2#Q1q1hoYufv~j6tPVu9igbK`R*`m@$@t<0 z@AB6$kl~Y&TSdxZ2i93dN-D$ATq(mmS|EhsrU?qk=dF!T94Z^3v@`J}^YE?yAbb1P&1bbG;7?v~{y| zuZ;qOky9F&ph$$kP&;Mi8h!B$nJ|=O!V(H!*#iX%b35rCB3AF|I z#m~T&HktW)rJpCh4>Qv-Z1LCsP18Y!Pe*RV!eV{*N62e(f8=o=3L=>GKoSZaRiLp6 z93q6`F~y4mDgosc(J_=wFx2>pL?KT@++dWk%)A;_Qq^nh_q zT*CoVj}>shlQT=n7%i<1>raVeNnZXC&+8Lm{pql-1-=Xdkv8j|iu{bEuG&#qeUI_qJQobD^EjBk$gwY_ z;~*;Xaqw5?f`t9$xgd(Fj)MQ#xnQe&0K_#!v5_1AX%^xDa7|pp0nmf$+UJ70>UOO< z08(wZdd0Yg10dE8D{?NVt9DfCxu6vOpZtc=b3*0xbJFwb%>Jk+TD+OEkBXfAU;S>L zguON5mAdXDyW`W*QS;}~?qN%5w>7K^sb3(h<J5| z4E)uT&4~5*FMq#i)Kwh^dLdXb?0h^J{&#-A=rQ?Vh--+YzZ?wZC!4N`Yd9DNQC<7V zW?gj;uR0h~ZMb^HxQ2rv)($K3WV5c?QCa&!@UMR+^%^?@^h3{A+~0PubOc1jzxRo* zROin>(G?Z74~GBnhn`2~gCVXVmXqaRz~`y3;LPBfxQ2t_LaOn8jq-<{>#94{>el^< zF0UBZa4^K$wLj5SSM76R?b6L>8aMXn&ufPVu)sCb1w?EM}rp_}>rvv*gNXJ=J zsP>WdpZi4DEerz(Ok6_*S6TRIxL@N{6V*7VZl=2Sokm@CM^^=3 zzSHoEaSaDmtX&=j*6XSrmH#7`n>*_~2v*)`-frn2h>Cm={MF?qV*mB!ChDq=ga7R1 zW>P*F;u;Qyv2rk^O9BoC*Tgj(3=^rYeYvTt?t@haL#ho|uNc>GFvQwnMJ_jW)sD*A zmz)3gNBr)u^FSDL@Y(q{Aw)$!5dP|Hkg&fz8$?mnQScvo-tlTa0OA^=cv=pCG-Gi9 zxF)XQ0CQ1XV08(wZdd0Yg10dE8EAqUfuG&#qJ{$b&_Zk!Hyw`Yf@;iC@ zN5#K)uaWBf`MpL|)IJ9O!}l6r?lu1P18hp22iOHW+%!F1U!vmQ zJHS$%KR>{t;{Wjh)@beYl6PFg0rumc9$>DCYdF9fvO?_xtggBX{_+6xig67GSgc+9 z0IREZ!BLcdXL_0#*rPwM9UhbetghN|6zKr-AL*x`)&6VmG@n-IRc!pD-#1Q&TU6w$ z*k8Sh8nN&y>R-RpJj!YxV*laaKe$pp#NrwPX%^!`_ruaY{*TX>Toc!Dh_#>^s`9I- zb=7TNbr_`DaP^9D4To5)9ai!vuwGZ~sI0!5kylf;<*OO357yJ_tu)8P;m z|I*heKRLFsuLR;ozFMhQpylorgnRb=UdJ!@(=YH5?AHc36?a zp|09dS$#PC_g+_hyUxR4udVO6Asq%$kq?8vdR;YPfAzX*)Knb<`PTM-`*qcAbNq1) z@oy^euYvA|1$Q*AiED_zC)H5h8@|#~SKTeD;!m~V>J{S};*YgaGbyoNSM8|$_ik-x zTj=^S+E-&&8Jt3oihu9UBh~ryJCCTSeGL4EZ*2$U10k*M?b>%9b=BTK*8Y=Q+dr=zOytg^uG(=Fe&ly#dhPiv%s|39dVaxEZv|OBr z5Z5q-i{cQPHY}Rv`WvBi$i@rxAhzu{}=yd zqZ+w5{rV)x)HN_o?rRD z*-3W9_CCZB^519bBEfVl2a2O4?qsX57Ke;OHEwGk*5ZzL&W~;u*5Z!$2y1c2w+(A? z$9K-U-eGOy@P%D1ii7w)etR;vAg-YWcf}SotXDMbP!G0M%Y8vnDWH9vYn3WR^#)AZ z2U!_Y>|w4UVAR4i(WPCt&3kXT`Ef&z-g59^Lk>IWz$14XaL|y$jy|e;ck0jewOfP*C-0DFhEw7kHsV0&CcsMEMD z&4JPxEzV;6m7xE@nb7^`=PN@R_Z;!k7Z_7dyC}tzBhC=9H~7(U>B4lR!g5m89t@y*~7x7KW0$S;`s&?ge@btsYKV2TiZ(dfJr{P{hQ;&@5SE; zA5iHoISza2kFQ2I56&^dmBLz#EA-G}(1SYax`sz%gjKFc3O`i?_ zj^o4MHjM|-J9%w(e)O}j7DxY&uog%EeOQa5pC8sDi*rys0K-bLO6hF&em?Bt8uEKD z9(Kz#E|%#ZzIJa^EE5jDWjZwDoxpN?;DTib-T6bpO~$`}WA%(NA~$`?nYtDA2<&be@u%9ZMctG zEE029gna6}rcX7%oDC1O_=Dq&-=k>qdf_xb_q*_T&*6UzS*_y>f4mihU8;rQAf5Xn zeBKO?uTb~ncZbK%UkN$HF65D1iuxls&YtIUcl3X9&(ra>%_shfoBq0#aoZQ6Ua?ij zcjG?vh#SNIu%F?77(w_SE~?>wI99{|a5??TS~K~#u-6t&_^24?Wc#0=#tG=fbZ?eU zK#WiZNO!w~ix0%<+#RRo{ieb;&H!8><4g{JXw!~ooYmry-7)JhJL6pF9@gSq*ea~W zxzH=DMZ#xt->|J|_-arb9=?ZWg*kXa_`WFD@Se9gFYnFU@Jlp6_+QYdU%VIo9cS_< zVJ#BhWZmz1TcdCw#YYzpYmrzwti^im^P?N)M>oxn?wlX(ogdvdKYDn6bWncu#Qf;l zVJ+_4h_Dv-?Xs{I&q&vXH6&fXxG}6@pX(R5hqa}+_HbB>>|HPJ^CQ5#r^#>uYH}@e#mPJ@>-={A{Gg2vC1-GEglE!hP9Yrr@YoB zKiWO4ZNm|46V_t-y~0{df48s}*}cNrX4JI}YlnxgwEU3IgmDdB`Hb6EH3{|=3nqwb z;u?DMJ=IX5c3SGH`*p0lRsCYCA&rU#{Tou8>Z4YquqCcx;>G%qCMDMEsvni{Ib35r zhuhhn!~HMaIAA=LbmM^GKN>pU#mMkIPSQJUTjOGUSVKeV7mwSv`o%N0 z)}VMPti@?FE3Cyse|BE`EI;~nSc}u&97lCP8-}dM7BZ5GftbZsc4IIZTX#t zGNwda!#IEAw#uK}K*ZNB(p@X6R^7F71QkMQpi4RBof zEdx%rcFWK!yoeF+1Ad>oGNm}!(wza$&*{#ftZL{$tR@n*u}-Zwl~O^-aOd zuys+zajTZemsdx9WdTx(tPaU}eIam{bSt9|Tp=w}$#|3zqW&d(gSw`KvdF`XD`#h}0YgSFjJL(n*Yq3hx zuofR(DL>jOKe~2)v~yUCSKO{)Esk%iuokb@y~0{N5$qb);?;Vuuokb@hlaJt;+`0N ztzR4;*5cLr)UX!Ea%NbISL+MHS{&7-VJ(jNn!JWPg18NL1aWO#UK^j+o(gNRr_;h( z%<|2!7E^dXug%Gi&JAnZaD4N^T1@b#uoe^iEv!YhUbv3>X=mxuRkhJN`P~X!LsuGd zt^CU6@E3+O8#cc(q~S!I-lxtDqJrPhh@Zn*s(yhx(>J;Hm*OJSj^f!A=ND=?6{gmN zD)G=oWO4A_4?23_pmvA#U*yEI3%m+cQ?%;-P9ean&IUoBThP8<^c zg$4UpQ^6sRz5DF?#^EVa5Oev$R_YfmZQuVETfj%_73~K1KXAx_QHu;~Di{Zr@0#4Z zU+P!bZ=;|IRLLDTZ8a4fc(8hX=jAtd_pgj@X;f2L%&4cQ|NRE{YL1-_OQT4Y zMhKUh3XWRe3HW2#G*EaPUunNu55^-nY1C9&<9qmOJD|;(&i6GhXaeQU;7O;Zg1jr? z>+?PSxq?%}jKWbKM{<{K2^(s;V;^fO%Y^T!b3<|W%ZVw9$BcqT$J~SzzJrQO+UF09 z!lO#z6c_gt+HH=X)y2Jdn1rp+#7b+YiBYt)Exk)y4y$y`%CN$voFI-jPw@WZKRP$n zEs8U(&JwxuxLg^kaven#$^Lrp{8heqEoog#A6=HTkf3oqf`BiqK1VoNd?2d>J_bf z?TE&5!I&FLHYohR;PK@ zUi^(z+KaEx`TV-(c`qg!MUCtQ&*R+pfER71@72bsHF25=OFY+?&vh7AO$F7k{Ce}C zFa_hRD2nThf+lWz(Y8RFW*pYTZwL)vH5GIT%dF#<2zOSg&WA=pQ?D2}VBoO>(kVOj zutRDhI;K5bF>I-+Ob_2N)4FW`&2iqtCOFB3WyPuaBKhs+&>Nghz{FKig77_tN=!a~dp?{P5-nn0EA0a}JFH5KfEFDZ-pMzstN#nb1?IOW?CRqgYZ zmZ5Su!f|Qmf-E$hRl}B=%1_}t&Zk438u+HC)6?p#8v9c^+pI<^9pUX(81cxeIh`wv zqDInbMGD6-mT3>RoZ{5yMp47ZH^D{8mbhO#rbKDy~LrCHG5C}_0L zZAjJK=SfCU!%?h^i<>R%>iQenztBVN>gr)jP32r}4^K``eK4F_lFwRJXZ5PCwk4Ii zI`zVZd##?kI@Bm?q^oO?O8b8O)lbfM>V2cA3A&=#1m$hvUTmEHg)!@1tQoe{RN92* zV-Np6@rV$E=z6;(Vj1k-b=(RGiV_$@5P8{OHshMo}YI zy>-N^@ov9_U+80(iDDHT&|#rQyw(j{Ybq`AJ$&uG^sw(L7g<`gdLpv$S7*Wt0SqD*Zy;lEbZ4i_Uwfk@#-XAb9OsqTlYG_ zC~CxOgG_~$V%oQdh2K4xQl4TIHM}Q5U$Efl)#DlSwWfjt9yedV9(?G5empOVh{CdA zJf2I}0$kbR(SpavZFE+K{?$l_bsF5r-5wD4T7To02WTU7NuT4qC zd$90Q+3n5mcIq9Ys1Ywb>G%DbbJFE&IW^xXYQ(E+rou|m`Ii~fooa3uXKIl9`Zz|h zp!1r0x3HzA@@)8yi_9fsmw3yw=wx-eRb|ngRGJqX&2QhKTh3y4qo|QFZ%zukge;!F zxPCpSPBV%c>CYCVl2@MxUpd^V+l`_|ytX8jviRuB24^_+s!`O4R}b-8eBLKdI`ykj z)QHzs;h!G2eOpo~i(i(V*Q#gE{T`#Jkuh&aD&>CZq*0qX z^_)@ENPo5$uk-$S$@@-yWE3^x)r(ZheZ>oVHgM`Uqo@(D9mMOj-KGzB>Tlux1Pe9d zwPV;C&n8y>&vWW%qo|So>?&TP?r&D#sdJ2?M!a?-m9iLq;m0pHb-hv4 zh}Z7oh3lYG=m~9c>`HEwW?9nh}Yhv@G#E3$ik^EMo}YP z`-m5^aB4TBs1dJyNnyXRU|u+NxKY$d7U;ZYv0vCyQ<)mRBa5wO^*zk9ILqqnSCz&7 zq*4~`mw$ffemRRVMo}YU?n^3Vap~np^>ylbqo|So93Wn=bUtb~r@k?Y8u2=i6dpzv zE8hOt!A>o^Y}gbQYQ(Ew*y_2TcGAY5Ikl-#)QHzXnL<_ECpdMWQPfBl=)7jppLJ3e zZ4cbD;#r()b^2FjF@RJ#i~c!_dyJw+#(XfTau!a#Z4@=qpF_k8Svb|8d3Z1^)QH!i zVXHqcKo(AQFp3)S3I}4XES&0V6gA>?c&5S%vvBGHqo|QA(0R?`2-ZniymjS2!UaFX z!DWKgIif0yBT1FBI3j29ic!?amLaLmFQ?D3Bjr8X@@j@0(eP?Vx~|PSvb|lC~71NbY8PKiFM|L@3>yP*|icb?`d9~Y;{hm%Hm{FDT}j4 z_IdWCoW*5EQ6pnMg;dJo(VPF?%BhEpqDK02s(3xO)pL`bdc!Dc#OpLtDU17`9zD~k zpNyhLyiOOd-aXG6CZ6n+WwN$ zE^_KVqo@(Dvq_~ac6)Z|zD~_BiW>16E?y7swD>YkePqDK02fp~Sk?y3n+-E0&!;x&R)%3}0=ua9x+C8MYjuM5R%!JytPo%+!z zYQ$?~-mkF2ds?SfToK#CJNd$wW`WLY78gNNc|Ckb7T?c&WKGXvORIBHRTdYMN?G8! z-bFc!gN&j^#(W8>lm(vaId!2?)JT6W6)!x$aOz>Bs1dKrNTn?B{KBaZjG{)oE*CF6 zzi_Hii|}Ars1dI#!d89W?NmFXsF8Vr&TAG|vd+}-9a*%y`}>VOi{4h}%Bn1`B9*eh z^NTBU76Xl2{mQ>0D_q0w;H;NkZ8YN!1 zk8LXLMB-*OMw| zF*;|_!zgNG%r}rKXW`T#Mo}aExlz23g;N(8MU8lkAyv-8sc}Y8BVIR&7qW0_hEddr z*UgyF?~I~G<^?*hS=_=pXCf%rg)E#p#3*XS>kd-oESx&WC~Cy(PVqt(PTgh{HR5$wrosxd zaO!EJsF5ttdClT()=AfkL&u)-nP)NE>fBwG#XY3byukJ1?wmzsmGEF#sF5*`4O>e; zD+$*Nr`9%#8tKnCQppR~3#axliW>2{msH9E*9)i4Fp3)Sx=*}ty>RL-qo@(D`}2N< z6<)iYnrRd@k_9@iSv;S%r&e7R+v4ws)$0X1uUSkCTl{+Q@(~jQ zTLB!F-K@^Ug71YWy*Fc0c+|&?EGFhG1{+0ljcR!eoOt} zS@g9!PZqVan3COb)FF!}a~5YAMU9O4DN^MuoVwR2YNS6;ix;wR>K&t~5ijhK&I_j+ zwh9l1g&OgCCT#U%3|TnU!6<6P>)A}9D&~b#`x-@!WP#3W7SFLxx?YUmZt@$R#kp4J zxvDIlCzZ}oxL!P$v$)47YGlmQNTn?B{KBcXjiN^S^MZKcdf`-q*5SdhP$OP1hOM3j zt`|;qFp3)SdWlrpFI+F2>T47=;`K5q>=zdN{KBaVjG{)eK<71!>0yh%&*7E%eL`Fn zlnl!Rt24bSi&w&a;ZWv{bt@hm1=oj0no_&cdIW}Ktm$XU!XiW(X7o1{_}xOO{LtR5Z=3pLW8x58G> z9p@;g+8RZTc)d-ke7$gLN290_uUX=SbCgrZ8AXkFy_2c1!gG{Uql}_PvOwoGi+5Qk zWpP~dt3UKCrdXYKtFm~HR5^=xa~89WqDIF2KB;mRPA$?lJQx;gq(2{ot(t{X9gLzz zyuxk-s+@&W`xr%yc+D0sWZ~4=Mo}YPA7v`6Fbk*dF^U?=0-e_^K4zVi#exk+g}5px z8J5?r&c{_*%n6Tre=sjT&RP7!C~9QPpO7kN;Z(CV;8+yYNPj*JTipxu!l{l%Q6pZT zkt%25RBxlG5wFk13t2dIl2O!%*B6-zE6l>FQASZCS)lWp#az}&Ss~9ys9j|BbCOC zc`+|%@vu?U$e6z;RnEex_l%-O`V(%lYt0L%YSs!5hJ_mO`Y~+PESy@)C~Cy(CsJv@ zkcCsb7)6bE{hX<=!YrIR-Y9A$3v^zy_=R;+76&%{;Q`MAf7SuZFI8Fm8n*g*16ll% zvv}MnYGlmwNtLs3>T{#0k^U?YFU$+4mRvhL7#3>8>z`q(X5rK(Mo}YPzmY0u;S_$I zA{J`I>-VrVb_0*&`Gr#>jiN@fK<71!g{*_~ZR7BD{c^Lf_ADk?orP6d{6Q*>89&!s zn6r4xC~9QPxDfekAo#hSQNi5JvfAHZD&mBM4b82m)s1dJvq|)^QKi6|=52L6N zuNv{f&-I)-!zgORtA6&v4&di{PTgS?HIfB7uUX(X75LARHr%*rxFrdjxXiFR4Jx&t zcQ=$V6I5pCr#^QzNdQNpTiW>34N6CF&;JKbt zdm2TJcr7Ykc&_KvDMnEvUW?`Z!am@+o>SKwMU7;E&TAG;SSOvM25xxDbDqT%tJ9=X zI}7}J96wfZj%t##_|hn9WXwzCG1r7Kvj61$8Da) z^6Q~?_$hd$b{5NIcXSn5ESb1=dOP;+!6B!V{pd ziOacGXN5}bELP0!DT@_y7B?D2jf}Yksb-;enioz@F^U@L4}M97&p~A2)JH~9BVPC& z0Dg|byl|@C`f>lL5wBIm3t2eT$|!2Yt7WE87g;#9g;CT<7U;ZYu`27NEVdZ1aDZpg z&+4pNsh!1Y**#^kYR=*`qo|QFw<1-}!l|2#qDK1DTD*{jQ_mVjjd-;oRh}14%{7V| z@mgKHkcCr=cZdm6BVKJYm9lVZJ)@|REYNw)Vhz@r8H(UOYWOoZU+h`zYIWAA)Xrkf z?2at(`HMAj7X6K)M#j7rshmal{Do6z7)6crXKnGq=P#TZWfV2ywGOGAMfm)MQx6+O zjd-mqUikclQ!|XBM!eeP{R++CwcDw=Mo}YKp!1r=daRSO*!i>jFZV2JI-+*?9Ac$* z7VTxs$YQ;m#fnBzBV%4akD2GFkcCs58byutr-OJQ3#axoiW>3iNUEHLQ>Pn6jd*nu zFJ$4=jYd%;UK`~7Lbq@q<=ntFvLHb{3sU zH3=$o6|b3Zn6s$YiEu%UjCmtcXcjbwq&YZjZa&eTu?S&SOB;W?hg;v1lL z_?1PK+F5kX?#Kf7QJdu~S{X%+jJX@Blm+gioZ7-DYNS8i#S7O9rw%lV8u8kkRLTO^ zZl{JCMU8lEAzrv%ICY~@)QH!XnL@Xag;S3iMU7;E&TAGuSm)bN16j2F?UKQs#XDA~ zN2PWaTV;1-vEz<&ukVqw_}M6GWXxNWN?G7}w^J)_7z%}j8tKnA;`RBRcXe{AyHV7L zS5HzYi-ncbo^Wb_QPhanw&I27-A-L#6gA?tUG~Brv^jLv=T40?iWDT_6F z&79y_Ty1rBt<=t9x9pzIQM=|W#u`P9jCprbi7VC^&^heKPKdZA> zrFIs3XZMuFUO9_FMo}YU-iK5<3#TqLiW=$9zT$-}oVwE}YQ$?lQspe1dd4Vf#A|=? zLKaTVHi{bY>YJ&Qg;NWRqDHbn=QWE1SSMxi*{{3K@GO?y7`2PyfJ*Hw4$ST;ivw~N z>lj6ijJY4Fau!bYGKw1M&q3maESx&hC~Cy3KdEvSPF-jeHR3fuypV-cV~wIlybjJ3 zx`lb+)Qd(@BUzyHn#Cckld{;N_xYuB)Lg4`NL3bxX7`lEAvuc$Mo}YUK8#d33#XRp zg8e88YNS7hix;wRs-02Ph}RLM%2_zo(qzlJ7EbjuiW>16m?`W5vT*8Tqo|QA z(0R?`DAq|?G#mFtc*Q$x;&QpwIjT~7UL2j>Qx-?%EbcXm8X5B-Qspe1dd( zvN$cfrz}p*S=?z9H8SSYNtLs3YNk=tNPo@{FJ$4=0;8xAuc4&MSvb{dvzP@n;&rBY zAq%H^8AXkFot3GSg;U2GMU7;E&TAIKSSMw1pby77EWzy6gA>?ex_0u zPVH+HHIfB7uUTBcIw_0F2~FF37N=RA3#zghk=;`k7vwCiHHsP;^M$0!Svd8CQPfC( zMv51*aB7ZG)QHzbq{>-1)wo;Cf*SFsg#9NI~zrfWP#3W7MHS4 z%Hq0}n_ul&46!5HDom)Iy`E5w9yr zm9ubaz3wp!YQ*a*@j@0(9bgnS;&pYVP#4#3r!F>%8p#5k*DS7Kos`AQM^*`Mp$eP0 zJZW{VsnouYx;DF~EUw8}d}0(eGUidF%2_zI)aJA-sFD6$Ctk?HsqRKmBVMCPm9uc_ zD5Izmuj|DNSvWP?C~Cy(hD>1}kcCszjG{)eK<71!8(Al1vEmKy&GsyQvN|_bYG*Nq zRC>)EuSeaOvsiu$jHoE6kul#ys+@&WTN_1<^yg;rLKaRPYZNu&bqlF-7EX;ZiW>2{ zRlJaeQ`3#2M!asz6!sfgIQ6Sh)JPWSyk>Db>!d6`c=3R{J&V>`qIMDf=uqt}?#S+G zUfiCu=xP)-GUhu;m9uc_K%=OU{@f*A$ik_!jiN@p?j}{v!l^rqqDH*#5iexn)Qd(@ zBVJ=Og>E4Wr@k_Z8p#5k*DS`d&eTu?ubEF@?4X{W#o|3sJN(YdO6@G}&F(efam}ZoynEj^Ww4Wp0b#nvzTQRH8SSMNtLs3>Q|$vk^Vd( zUdY0!zio}ZFA8eJ>q%1OES%cVC~CxOig+Olr}i+48u5B6Qy2@faB8qo)JPWSyk_w< z>!d8|kHnt{37fcFVs)Ob)XrjRc28M6owK;XC~9QP&yXr-;nc%MQ6v3%R=kjfQ!g7u zjd(prs+@&WbBv-!yq*^?WZ~2Tqo@(DX_-RXkcCrCw_z&_Y9tGEUbA?Cby5~beLVCw z&!Uahd7&zc7qffH;)R?=C!?s5F~3BroP|@pjG{*R^Rjp$3#a-UMU8k(CsoeEsZ))j zM!a4TFJ$4=6-H4bUaw{}lQSb{F~=xsWX!LT%2|Z>%1OnG!9>vZ~xSHp2f#j z=dDWZEZ&we<9+6DA0Df8G%WwHRAQ2c;S8KPTg-5HRAPt-Y@JovT$maQPfBl=)7j}0qdl5)Z-7na-(Na zvmI&|#RrwzS$rsC#y#x^Ig8bdqDIC%JC7Mz;JpV$BVM0m3f;o>!l^HeqDHbn=QWE@S?AeMW0COH^|;r= zDI{#-(scXy|4%Emv-m8#qpSGc>7V8-IvGWcjQMj?=^TaMo$gdWqo|Sod?8-=-RVwU zViYyvHJ4P%0>3-msV9u0M!dchFZ}Lwr@l6d8u9u{yzslzom!z+>>)Mc^|g56cc(km z(mQ_W4#R@qo$k~Sqo|SGk+SCg4eO*i*m%+H$9nEJS)FexwR8Vg#*8`mP0syM zqo|QF&m)y`#~gI(J)@|R{(L81n1fC&G>RJW`kqwE9dppBmOHR%1vTRJgLq*MI<^97GmB$pW3%ENWQi%}@j9yE|KLJ;}4!*Xq>NtDQyt?2arB{At{NHT4>VH7q9@MU9NP z0jZS5*H1iox>MI1MUC{Qp?EEE z-l--#$Ni&5yzr;l_4iCVwVqMbNEYb4X0a&iq}GWqt;%9C88gmNi{>nj zGm07+bCWz~B#7&UQ)7&xM*6e3cwt^R^^#H4h}RONQWm&gIQ6qp)QDG8@xr`tYSmq0 z7SxDWvrIvOdEwM{Mo}YKp!1r=lB|>F#X9xcee3gLh}BuLDvPDEJGzQ_v1HETGNY)G zG2@T;`sbH1FPxfW6gASHWyA~f!l~ItQ6pZ#*3T!Mo}YPD~T6A>*3Vl zMo}YPD`yI$!Mt#4lu^`37U;ZYu?p+V3^kC&`*+>e#ItzG>a0?gMa%4tuHyBURdN<{ zjiN@zyeg??fdGZS2jo<<-NUA^P$T_WO}y}Wi&LGAqDH)0kxE(M?*TcrzfshPS8MUY z>n%a3II#f@+Fyx6mtVRcro%A&1|8S`TGoW&1D zQ6pnsBaazbU|u-2${viOpho($rg&jqIJLb|)QHzwq?QRq;e~nO)CopWBVKEZ7v_ai zw-`l@c&(Eu>;vY7Q`3#2MzTQXHH&pw=hILF^J1~*@4n2l_|@vHTa`t-?2bLf@4Hwx zXR%E0uqiCm$e7n7mF5LLcjMH?Mo}aE!C&q6`%L`43#axsiW>1+pH#{Mzwg4SVMb9S zULC{>pSyADPNS$1ua4OZ`;Fgs;nYh;Q6pKP^O{8`)=BeXyUwRP>REhibvjjLv4M;k z^P*GEqS>ApQBhDMW8RQd$^!GksV+uQBmLgjHWr4r7;Z%R4sFD736)*g)4X3U$iW>3iMk-~2zqR4iG^3~y zukPZ7zqR4i0;8xAug$X;x`lb+)LMICTTxIWS)lWp#TKlSvS>K{=#PC~>|=GdsLEnX zQsFYsvoW&RB4=^7QPjwodypz;;nW19sFD6`C0@wFsV|J8M!dErRnEex74~L(3Tnh_ z8}ULGPW3X18u99xy-*ifICZK~)JPWSyk@a2>!kar9g41ZcoyTV&bC!qY$s#Jeblx& zi&u@JM#j87sgwooqnuh`6gASHUgCxOD5u)&6T3={ckmS7ot_j2YL9opTo7 z8%2$bdDlGVnlNTuFPvH>yuShqHPWBm#0%F8r+OJhjd<-&DrJG|g;OUPMU8mvAzrv% zICZ;G)QDH_Okodjy>M!#QPfBl=)7jJC+kcNHE_N7VufuNcox4~ojt3v=#$;iRlEkW zXU?M4eqmEssF5-6MJmsW@EV9yyBbA}^k;AJ!fPN-ooN&`;2IQ5}X)QH!9nZkY}3#Xdwk8MRkjbwq&YZm*nPRin?J70R#v*==V_OHsKZ+1^v z?4PsP+bC*e%mhDHTBVGrI7qW0_p;6R` zSN}|*>&U{XHhrb0PCbIPG73yNuI?HR%bv}76)hdl*NFY#bHKKBV#^< zR5=T$E;5Q5>Cd6!g)E$U$S7*W>o8K~ES!4VC~Cy(aPdMGPW^5aHR5$drqFd{;Z(~5 zu&pSlku1=8&EiPbNmQPfC(ju$Uv;naAe zs1dIdNR_j2>P@4l5w8=)3t2ezt5MX5*GZX5Sva*^znCC3k_9@iS)9x|DU1F0oV2cI zv9Z-TxhjiONTuf&xOShMv)J7zYGll(k}7B6)QLt>BmFr|ypV-cqm80QyiO-o&cdlF zMo}YPXNVWFaOxAIs1dKBnMzqW)$pL01vQcdIE&nMr0t!J^O)j6{&i?gzO zO|U{1XXY%r8bytac^Ij37EbMJ6gASHv&9QpICZj7)QHz`Qspe1y2dDK#OoaKLKaR< zFp3)SIyX}(3#VQ)iW~5H%Hopjp0c<&XYr*`)X11GB~{MC zsU`!kAK|AO&`5tS6E9@pR6C=n5wFWhm9ubaXQQYQuPek0SvWP=C~Cy(%1mJokcCs1 z8AXj`fzE3dSFujYV!25N{O(yiWOc5p%Hrzmp0c?op>P&rv@5Djd+dD6vl!qoVv^?Y9tGEUbDEK zbzToOaE`iiWW$?0i-}g}`l>8$$nMAj@7=vVXYsmG)X11`B$cwjdv~4s#VBf|KV!rT z@7;B3#Y2L9Sf~-Nn@FWB@ZMdgx*0`{c-<^sc<-)L2N^|;c-@ls3uD3SQBDmviWWE3?r=JBM;SvWPxC~BlX4~rMFaOxAIs1dIT zq{>-1)%0-mEPM_T8u5BWypV-cU5uheye4J}Rgr~L2N^|;WP#3W7L!;f{rqC)!N08O zS&Xzgld7_KG`k}U{QP24&f;#PsF5*GCY7@YKfiElhEdc=e;yMr{QSbHpN*nMydEc& zvj{)GaH_=-=vnv+iO`7G6XJ!RUpTdeQPhanlcca;Sa7{?>R_X&ku1=8&0-4cObs;} zhp)B|u3DNGBdpGpsw|$8G2M+*URFC&w4m@qEXa{*L3m1XFZ&{)hKGj>lN|BXFZ&n zVH7pu^(raM8!Y&&hf@oTqDFE@%9{HO)=9aK-gvPgo_m|4V)YqSxzCg_Blj6O_ijc} zBV&GzR5^F2`WZ!y^yhW)LheotH;NkZdV^Fscc<<&iW>3yyLcgYr(QCO8u5BlypX$7 z-xx)Wc)cZF$la+WkB*(EM!eo8RnFb14n|QUxg%xGeHQDa+}G@ZPjptIX|cQ2nN^kh zJ2GbEJ}c*blu^{knBOH;&fTd?jiN^S^PYGicc;c1MU8m9PpX`|Q*RkXjd*<^UdY|4 z1x8ULULT4Va(8N_L9vC_hDA&{W#}-hf&nXm_H%aEcn!fFI;n-dc!Dcq(7gE7p}QZRgMXT z!a|LBeMTzfj^}7jwKIwu@%mi6aLsjUAET%duP-u%vEZ8P)Hy~`BUzyHn#Ek!Nm*Pv z`tIvIiwCXF+^Q_T%3y z2dQ!vP90_xHRAP+cp(d?t~H7p@%lDX*aKwY)bmDBBUzyHn#DZUNm-ot>d_l}7C&2^ zc~x0_m)%nq^Kup|9g7ha1vN6}?@5)jaB2smsFD8sAYRDAsnd+2M!bF`RnEexaYj)i zUO$N!vT*8sqo@(DpEHI1Mix%tz5)w1k_9@iS^UB}DU0Xs#(iwMHg&N&zf@)MYj#gr z{F1ZS*C=Xa%=1Z=vvBHMqo|SoED$eb;naghQ6paeB(+TF0!D~)lvD2;MU8mxEPI8byutr$VYp@PQYyaOypys1dJvq{>-1wdnDoP*|uD zuNv_}7EWzs6gA>iKU1iRES&0Z6g83sIQtks z5wE2(g*`wPPK_~&8p#5k*DRK1o%CF0rEh=#!LxYQ>MUKA#WLAFtnjsqr9BIysF5)* zODbi7*DjoD65iW}g&OHkbMeA+8K*iKMU8m8=Q2*6Z4@=) zwY+%Yxr|d|jiN@pRuC^dmvQP1qo@(D6-kw!%Q&^bC~72kq^!BOV4bHz$5HF!&6W@U zOV_4VPeu|&(V{B%m1N9#|8t9+dpDz~kuk4KD&>y%KRb1>QPfC(RuM0}|JkXLMo}YP zElH)^@&0G0#v4VAc&#d4c>l9g?;1soc&(NxbPIFPsp1rDD++2P3v^zyXvI1yi#PtU z>7|~<>Q<*!RTizYdsyM$HEWf#*wH9zWXx?ym9uc_45O%#{;V!u$ik`njiN@p+L9_~ z;nYV)Q6pY!h!?VOYN=D%)PfrES~F8nAPc89H;Nj`0-e_^)?%Hhp$6tftIxhI-6tGl zb=IoNV(si6R(Ne%D`zpvC~9QP>yS!W;GWH?myM!E`m?Th;o9WXLZhe=uXdzT7Px*MUC`l6Y)Y8PE9t78u8kcR5=T$78pg1cx@(L z$ik_OhoTqZuOC7qUR^VV$B~6o#}CD}@SDO&weGd!`W@ni(AC;mbYq>V;c;X!e8&|o z_bkQ_jaav;EV`3Q&-L)UvRlq#mQmEmm^UX?&cdliXGSk-q(57T7qW0_1EZ)BuPsTH zvvBGlqo@(D9^!>8oVwH~YQ$@+Okp38g;S3kMUBi0bYADh)~qu%)Ib)+<`Y|c7GGMO zt*f%wCcB3f&Wo*c7E7OnLPbH1jJYSNau!Z)WfV2ipKZkpSvYlqQPhancBIN#ICYm% z)QH#i;)N`nde)X123B9*eha~Y?OHi{bQ&(7k7=Q2)>G>RJW+J#ig0?%cf zy2mJL#A{da!gCp?UNDLp@!Czi@La~J&yAu+yml8aJeP5*L3n2Z7HY(64^o^r;c@&N z)+xN70Sh&fJ5tu%d$Uf;eZy{7FZA5ITAkiix$h}sM((|H?zR^@&GsWjhl9qgNP zKfowzWXuPWO1a}+-Kn8QQ6v57Ctf)BIyJ^9YQ*axQYm-bt2;HtC~Cy3zj)!?>(p$c zs1dILnL=7P_d2!EC~71NbY8PKm~}p~EH=Ao`S96!GO%9qCekPb^%9d7VNL3ccW%sbccTo<>S?p^RH8SSoN#!iUyC|JH-6(3LKPQM6 z-bLxu7^A2WuM5rt_0Pw)qM$~y zK<71!Q&=Zu(Y4Vg9X*RSR_BzeEKZd%;~lN1R3D?Lk^Y=6 zUdY0!r{NEYb4W^oql zq%59XZ1xn-;w!6jR#g_mWX#Cotei#t3pk{L8X5E1dCXyjSva-2QPfC(hKm=naH^+K z)QHzPq{>-1b+}Q~h}XH|g)E%9&?sue>pW8BESwr^6g83sIYQJd#RW2E{B+>_oW)$DsF5*`$YTyG{Ou@CEioc&3JW#Tp9{qcuSh%9(I{%f zYb2?Z1%5iSh!*;&r8XAq%GtFp3)Sx++r`3$k$P45O%#EYNw);%e4OSuAyDk99nY z8?DaORasn<-NOpAxH@O?xKY%|n6D*O&cdlrjG{*RGfKRWg;R@-#NLPBIS7q-T}P^% zg;O1jqDH(%ix;wRYA>Ux5wGhrg|Q$Dr%pGD8p#5k*DP*eos`8cTi-I#v$)mj+)$Op zjoCe{FpC><7Ec;Qjf{B=sd5%h%`u7^>Ca8#g)E$EbP@KxD5w#yn@N?kaB6L%s1dJQ z#0yzCwUbfQh}W%|!dQ@nQ^y!Zjbwq&YZkY$&Xb`At{2Z{&+cKR zxNNhv2H%#mc*rPfWXyMvN?F`;<|o@Z^{!FWNPq4Wuklm1ztpLki-Ubws1dKbNTn>+ z9KYeQPOWVeHR5%*c*B>66}4Lnb3&W z{iISB_$_lzbvB9`@p?eKa3AGVU!$lIuLntCzp&t*)~Vq}Q6pKP^P0s&tdq`BH;=!( zpJy@F>O54H#dsMr?xP;cS-fl%H8SRh^O(a5@1vah$tY^1KNG|Y=P0LEzLdLPP$OQC zkV;wLKFX2nlqrk`^TMgCjiN@fK<71!M_FfPsDX3TBYkfi z;#oXtbsnwCVsds5E1VaP<}5xmiW(X7W2Bk|0u<(jQ;jbRo5Dhk^yhK$!n|;5eWR!m zuO~>QEHE#e+S@2<#Oq1%!n|;5m{HV-*A!CNFD#fBPT{v7W1&W}K<71!r&uS=i{0j| z+r+bY&FVZ=mBrICX3UGHau#11MU9MkY94b~;k2H zmQ>0D^TMfJjG{)oo)a(33#X1XiW>2HK2z8O%nPS3H;Nj`0-e_^rm;@S;^ntH|K?eY zw>s0RvUnl8hZWvOP0LwKH;Nh=^NXa?yukAdr@l3c8tKnV;)N`nTJj3)eNj*&UN4g> zXW>*wqo@(D>EeYfoZ7=EYQ*c6Okpg@!l~noqDHbn=QWF0Sts2`jb3K;rk=%BR_E2K zEM{c)u)_POS92B*8AXkZc_yip1@5Dqnq?F<(x2DF3-?h@{b3X};`KVIWy0t%Lfl6= z)#l2uDJ;~8*Bj!6`zWWjH;NkZ`g^8O67Tw!(I ztjgl8>>gG)FW$^qJYWNcaOk^X!xUYHk7%`l1@@%n;P$^!Gksec+p zjd;x!FU$+4RuAu2#6pdDeVHjdj(OqKPDW89S)lWp#aFD8=EWMzZ1zvj;v}o{RaF*W zXZNtedGS@wVvJGL$e8~@syr{8nqd?*(w}d{3-iLM;#%x|QBWgZ-;zpMU|u-Y-Y9Cs zYo2&vUO07tQPhancX_`s7R(E$E;5Q5$pW3%EWT%*S3?avzc}=%yFT?S9=AH*S7q^o zjCtOt^KSV*XYr0v)X12B%wrBKMe|XWYn>`ag-v0hM*8!Ucy+$+stHc5ZWJ}*^)soI z#pwH9ALCRnqo@(DU&L#{px!N=8f+9b;`J*j9Aj9Jg;Q4FPz%iC~CxOp?G0lICX?k)QHy~q{>-1b&*ljNEYb4W>M4+cYT$V#eol9)55cO z(CQTRYriY6LMl8hbS=RY9)WE#B zey4$(dlp|=on@=CXrA41gyS!HEt|8LZxl5$=D(3jS>P{uIo0gOP$(?aNPm_SFZ?Ah zr`j4tjd(3jDrJGc+mK3G;5WoNwXadsNPkurFZ_mBr%p49 z8u4mNDrJG+5bM+pMo}YPYls(qL#$Iz8bytGt(o_$2n(*=PJLh$HIfB7uUV|cI#WXp zWYK!gvP*at3$4ytRavYpW5&Ck*UDM6x+xS23pFz4b@G^TX5%LlGqsCR)JT8U6)(Jp z)4k3xiW>21M=E8(PbOxsaYj)iUh9b$-oxo$?;1soc(upUCOi-fQ5);{HZ&!UsnS-&ca4%r=D#U~Ed&wJY2C~9QP9Z98mflrz^b*53& zNPjws7d~;|)L5ga5w8tMr7ZAC6Q|xXiW>3SP`vPo1E=cU5_UB#)QDGS@xmt#oLbi? zYQ$?J@xmt#oa$o~HR81~Da;!z_@s$bXBtI~_vekGM#j7;sgyhBpi^HPMUC`lGx5S4bZW_4vG?JViO`5wS5hf=%t5C% zG>RJW>P9M^=P?JJ+Q%qr#H)LzFc!=~r%pGD8p#5k*DN+?o%Fo2&9p^^dKNcZoz1JV z*n(6VGoDv&p0jwuC~9QPTawCIgx7?fnqw3-(w`pUh3Az{HNFjdUli1c*H)x*7U4O* zQ|lTUU**V)UHNRBVOB(!hT`FwaKaDjG{)eK<71!o~)CyIPQU$!@KA!v1oCv z)#+Kk_H+DgWz5K;XU^h&qo|QFZ zXQ!$xc9t>YdF4(yiwljSM#j8L9y7AQ^Gc`28%2%uXIJsU^Gc`QGm0AV+Kp7o0?#X* zs((kY4+}NowYzxXd8Je97)6bE?U5-|#W~8UU5%nfvOwoGi{7l0vUu=@r#|#7PO>_^ ztFqWLyQ8bfqIb^X8l$L@G4~;r&QZw1sVPQLBmLP+ypV-cUl>J=c!JKRaxwx z-BT9(b-M7)rNQ=1w^jd&eOs+@&WhZ{wWcpWBQ$ik^>jG{)o z4$lR1c%5k^USdUU)9!)L^5i5wD|3r7ZAV#;GwzQ6pZ1#0$@5oO;D5 zYQ*ap@xpT%r+zbv8u1z|UU)9!)LLU>52+EaV@WlR5A(TlE=q?oK^s6gA>?DyeerPJLk%HIh40 z*4$5HovERHsP*;2w^s4om%TT3^|Y$oPnR*{IqYdU_pU}!BV#^;RLULCVVxRe6gASH zq2h(-uuk1<6gA>?CaIJ=p2IrzhEddr*ID9)=deySyf1cx8u1#IDJXF6b!tPSsF5tt zdClT%)=AgF4jcX4#YQDb#qjK&u7hXiEG{sL8X5CBq*4~RKXht>QPfC(&J{0Q z2c7!ZC~Cy(JW?qO+^aja#Qm|W)QH#l;)Uy=Q(cUrM!YV_RLa7s{zg$FS)lWp#R%5H zyufwv?ZFGT_AD;8IwPvGxG=jTi1YS9Nmp|DURUKf)}S=9T-1>ZTfp;6R`*Cpb0&}uX4JJru9YQ*bO@w)f% zy&iVzBBQ7gugk=1TEF);aOzQ`s1dKrNtMrsPJLn&HIh40*4(dPoo7SukozN_-noV6 z-ZcE|3Ck5#xnC(`#&z(DoO?H;sF5*WMJnZv`yZ!HG>RJO&(-3E>!4E)7)6bET|+A6 zj{6^{zBGy&@w!&La2<52)kCox)QHz8@xpb`seO&2M!c>QFI)$my3#0W#A`IEa_&yO zY!o$;J5tu%uV{kG>`e|+52>#K6VLB@>Sug|%6GKv}*^Npm+xjQw`C~BlX zW5f%&J9WEJ)QHzjq?QRgfO89Scj`lHP@-LjiN@p?h!9sbDg@& zC~CxOY^Jd1xc_nLWuvH(EYNw)VjSzFIoP&qt5%-HJgYOVDvNuwJC1P7!Erf@r5}k| zP$Of$k5tM6=U%6}8AXls=YH|R9CYdkqo@(D2S}wXFbAEw+9+zo>p}6t9CT``QPhan zL*j)w=+w7HQ6paC#S3%LsTC*29#SJ-50fg-L8rDdiWP)E0{Sg^6=HP^!`#DBYBV(ROD&>wj=+tdSQ6v4CBwm<Bs1dKHNR_j2YPM0-h}YBNg)E#} z?9rG7HR3fjQz;9lIvGWcWP#3W7SFKG)KCO-?3*2WjPWe?w>r;MW$|owM;3T){!Gr| zM5CyYF+WEtWr64BPF-gdHPWBw#S72PoqED3YQ$?Asgwntn>+Q9QPhan3*v?6=1$e0 z9CkG<)QH!MnZo0k7f!V?iWQc^PF-jeHPW9~#B06rhu!AXLq<^}Uayi$SuCua_JmXK7)6bE z%@8lV56!8{V_{drLXCLM%wBlB&7reCcWQN`sF5ttdClTA*7--Mfh-<6aP}3RMK7!K zT2&UW%a~`L@M)LVau$agMU9O44N~PSoEm8qHPWBIi`T*t*X-xigGNy!UT=~rXW`Ua zMo}YPZ;2POaOyXss1dKXvscQ(sZ}1ww(zP4G?E26uUX7uolk=rSv=hSvC?~=wzN94 zs8RFgnpUf}(ivvL-FjiN@z{4S|-7EYaQ6gASH_rweD&vfc8qo@(D_erHJ@LpM` zUNMRq@%li#kcCq}7)6bEeVDyMGx%OvrC~9QPACpR1;593!&NPY|>CYVT!fRGe-DMOt;`Irslm%Y1 za%!eg)QH!o;)U0&oSJVGHRAP|c;PiGr&fIuNfZS&;`OZ5wCxcO1ZDp@cZ^o4KRut@%l!*@Hq~rt}}`n@%lD< zVKlflIrXYh)JPWSyk;?vb!LVd$o1l%kGS8nsE^y~u*|E<;yW2L-upB!XR)eL)X12> zCzZ0md!L-z#wco}KR<{U-uvX#K%=M;uOCUJEbv(~r!F^&8u9u`yzt&9rzROijd=Z> z_Y2*^d!L+o-zaJ%3v^zy_=R;o4K`JNPZedh0lu9TmV~S;Oiy zXi)q8nGI#kcwX56g}7{O6g4vDMtRINL5b&;P7O4Q8tG4C@xt>;r>-!H8u40$RLTO+ zE1jBb6gA?tsCeOdrBfdpMU8kZmMJs<&num3^emfFP$OBOVVXq~)&YQfwwLcI!d+s@ zVqL4#q(SX07AKXCAH3$-BxkX+QPjwommrnq1zz)X>Qtksk^VFlFTCdI)SX6ABVNr& zr7ZB8r&DhjMU8kZDPDNZ)2ZUQ*i~x8Ybo)XLXjX%DuUa8FO&iocqg0Q6ppi8>y5#=ActQ z8byutXF2i09CWJ1^Dzr*#A|s{DR<04r+OGgjd-mfUYLVU9cdIb;!`o<_~BzL5&xwl~*%t7QnVxv>T&qva^ci9(W`8HL# zuP$T8^W`=<_s&L9BV%q$D&>yn%TDz(iW=$98sdfL%TA3niW>1+lT^wb&zGH=XcRT# zwU&6{`La`UjG{)o))p^3Uv_GV7h?~p5wCT`3(uFG+Sn*+#A{tr<=ma>XB0J(J5tu% z+p$hM_qMG+rHAK!q19Od;xj&rY5e|srrL5+BI6fc~6o!ZnWYQ(Ekrcf8>UZ?sRMU7;E&TAGMuujV2 zz~!&`-Ln{GbvCHVV#Dl?b1$;kAZKxtQPjwoJCiDB;nXyvsFD6`BwonEsc(&vWU=FpbFbetXEDYoYGlk^Nu@0CeA%g|jG{*R(@nfSzw@q6PJL_?HR9Es zRLTNB<8Z2GI(k+V)QH#S;)UnSPPI0Q8u8j9d!Z^`M{;UQqo|QA(0R>bOV&xRBegwh z-F~l@hncWI@?ucvAv8L=cw&+7B?70jf}Zh9y4YWt`|;CGm0AN&ko{+bCgrx8%2$H z?MNzT5v~_bwRn|HE2t5#ox}_0D5thIiW>3SIa8>M>xENC8AXj`fzE3dyRc5mVyQJI z?&MiqZFP33%3{~-j;LA zp_DNSAyPtyG%BGYD&JXa-_LXJ^=;Sn@A|I3^?TNH?q7R2`<(Z6sZq>G*R9fp&mEj< zZ4@)o)hc#jFL=J{)Kf+=BQ7v`b#WWl3C~wc|MkIj?qY(ib6dv6?XqV)U(G$9!$xv{ z78u2h?720m-~!KAo!Vg(Gcunx(uLp6;#7e(NhdSX)s|Fnf#<7EonsU;(shS);rXgl zjf`SOy6%jx3%kMf!l_P1F(WQ8d3A9Y*IAfb1NTwwFDu*0T@18!?#j5hTlS1|RPOO5 zHj?}Ewo%N;p4*WME^xhYYJ*YC$b9aRE}WyBIvoEI<^C`uUF}H)7kGc+)VW46BV8S& z3+E`Onj6K8bln>%>;=~gryezm8F7KhtBd=%PH-{op9#6oEW&&I@wU!=85bR6JI*$6 zabI*X-za8e&z(r6T{!iFQOwAEI!hN^I8|gVUVUC3Gt$+CRN9487a7Hjbaj<3xNzzw zqnMGdZjr)X;KHfLjABMyVDjqXey+1Pw?@I-|E670^j3E<&epj<B4h1r>-}O8R_aFU3kvs)I&xwBVCV37oM{@HPR?%r0Y>q>E|s@ePk3f;vJUN`(s>Z zac(y7-t@QMPIB+tZJoz5-XAA*luZ@hAB*1eeVO~$xj)Rvo}VC<_U_bKMlmDv=_y_C z?o?x=n31ktq|)A53?8pIFtHXpnP277GTc>Zv`_rU?cYOZdH+sL(C}w2O&yWh< z@jSt)UPdt^^XVsD`25|e$wo0FUHwS~@A&-PsdYv%BVEr*7oI0Lb;u}Yr0coZg}LMY z(5W-O!oSPQV@6zH^6KJwuCp(fhKv1g4ZPW1G_iG_&$t*Md#-rw+{({K7xx&&jO_UZ zQfU`XJ!=#*GM^Wv>-rfDe{gE5QOro!KvKa4p6xjGxlznW*C6SF3#WD)#f)^l6uU5W zJlk>Vn6L5ga(}ZSGU5W0R~Li1&M~>$5V)AM;MSV%qLQsMIOAdnsc>BM7}jXn;OL^R zQOwAmhmr~|@V8?-)!Ha#WIiuTSH))Eo#xbIMlmB@!$<`e!}|TP!>Lz{Vn(`NkuLo0 z*iOwdiW%t|9=ka8O3$x#>T{!*5f_-ex){NAaB~J1)s|mh$6fqv>x{^_7%6+k`=$}m zMX?RoQC=Q1vgc8xf(yKFa;m0L%*cF3OBdcZIn}`^W~6Hjso(#AY*9)g^HHsOT&+F2K=g&^{G>RGNdV^GOfpe5ouNlRRbiFBE zI7d0P#3*K@YeMY8v~Z4c>Ib8k5f_-ex|qmy!f{disUokti-H@mc3$4ZjEhO6!Z`}Z z#l-01Y@?WwJx?Z;J}#VUW)w3rpDEIXn-WRapBY& zqnMGdY4LSoS~xD8I$#tt;sTRb7t^^;a51O)=7#Q~+$OA@mp47*;%(V8TuhHHY8%Cj z?D?IzXB-zeM>*BrC}w0nGo%YHoEl^lGtxDaRN948bBtm}x@JiiTsXDOC}yPV-T1mN zEx2&1z-IirygX*a1tza9-s3t8b7`ETrmbx9lDjzH)_E`E;(ggOo+rE)T{JL?8QJsf zxM#S)vmK{88^w&wXO48?d4f|zjABN*=8_67@NCDaIYu!fT^~pno+mi}aB7QD%t+UwNMY)Dw&T{WtySE~?r(%QG%k z$ey2_`N1{Iql+d+F(Z3kNh-L&=Q2)pHHsOT&*##0T!+@9of>QuGt#w+RB-WJr4nJe8F|@$d?=!7oT6GnY%b~ z8`jSKU56PLYh}+jH_hAiMRakQQOwAm*O3Y?Hcz>@gH!h!#f;47OX+%b*3OMi4L6Dz z=~_=JxTw2-*l|uRHHsPO`bxSg)oZiHslSY3M!LR^U6|IuqBmdRRN3wLcX@fthzm?! zU2NbwkcVscqKo^La~F+moedcm-^iYEj@l4ibToB2e6 zsd+{*BVC(G1s6C+IrY6!%t+U_(uH%BQ$@eSOmjbVh>Ub?iCy^r;~eEwWuur87nr=d z*vfVAVIf@f9C*r`?xLlwvo+&l8>#UA0^e`h8eQ};iW%ASc2dCwzTe{1`$jP%^Z8D? z@ckC2eldy}>DoamxWM;YoH}I(W|sSA6*AKGy>#LGElyo$6f@HG11Y>N{J}k~Q%@Sj zjJUw$)y0ooXMS!CxX61q-!ykI)7JShsRT*?|g9TVWXIluHPbsz2H8| zsWC<|BQ7v`b+L=?Km!WMHf4bVn+77n^bUtDo&wxWIAY)PqJbBVB(;7mf?3#v8?qbp1&xeOx%T z$|z>U1tza9{^B~pMUSC}UEwbNwRQf=xY#FqhKs+Vi}P}KV)(<1?0J9OGYrCoQ+FA~ zjLhe6>4FQV#u&wnbR8g-cHz`lMlmB@2c-)xoI2(wzN|cEr0bvfx{$y*%Bic2Vn$qG z^6KJWt`p8tvkUK-KI{#)|{3m z(}#1EQ^)HQXp>q^nS*@EYL4sgI0eMqFU>>Y^~$ zS)5y=VD5hl9{>J;yVzmt6wbIfDz?J~K3gvwUF6%D`&YR?%*dXLkP0sFoeHPUFp3$O zPf_W@XX{QiFp3%JDn=@}z;`N~>TDD<(si_S;j?w8h8V?+bR8pI_-x&&IYu!fUB^ln zK3jL{TcenfuH#4*NJh+`U2^KMUz2~$jChA-^>1vR zNAH&##f4JBs`WnTIbd@BP_U_a~qnMGd6Qv8@omy@bGtzaE zbiun*yNqH+x=KkGygPO5Z;3%>r0Zl-Y41*5WE3;v9hTL5X|5AK3n*|_kFM^$xvf(= zF_9ldumiW%ASsicB;d=}u;aHE)!`IM0^d=}u;e506=uG2^b@AzECsUMAE zM!L#M7d{Jcsu(^<%>7|Ty2{1Zh5tY9Nt~)|6f@!ilUEnzxz3{88t{70=BskwWy*&o zbAN8Ob;@U4oGyE=cgvf{l#edD8^w(5`HZ+{-XG?kKRflRQOwAE&XleuRTqtMYMD{Y zNY`1Uf(v{W;M8uTn31ju(uL>GPM!FBG8JZ|>+DD&f$N}CwTxm$TwwC*;vBB?cWw>1 zICSJcr@D)~Y@Ks5F3yeZm@0lh+d1ySC}w2O=aD)(M}Wd-$4(6~iW!+tMd`xtXLIUp zqnMGd^GO94`0UuJ6-F^5T^C3fK09{mC!?5=t_x#V?q%__W2X+^jenQ>Eh@-}3rt>J zRN^`db7{DkvZ%m0?&1_%r&7knMWl|(5tu4Im#Gw8R5ywl*>h!5M;nFDWt_UzC}w0n z7fTmDmvO3>QOrnJ6;i%RF5ty7{!e2xdy4=0{4ebU27CGGM`JO z3-<|5buo$=>8eR8xWN6PQ$vhmM!GJOF5D+LHQOj=q^p*6;Xc8sO-3;zU6)H2?h~BK zx0i#@V@A5JAeFvPaH^b9%!qebR`0dBPPk8K@Z3>vyZ3swPVJ2MD`n5PPpBQew>63x z*>fFI!8`5~oa$#3GcupL(uMm3r=}UjjC9o_6};m>f&myvm*z!J>AIFw@mvqO@I6?kJ~4_J>1rfhxHdWUvr)`Q zSL4`~tK#=yohtk%{#{-kGvWf1R~JpVPH-{%`Bux_#d)?)lZ=b&WY2KXB)X_)6f?5t z>q&*<0xq0tXB0CspQh3U7f$sziW%u@Mk?*XsVPP=BVEm<3oe{mX%sWkbwljJ)bX8U zr+zbv8F7KhtBV`C&g$G6I4-u7ntP?YDE1fD&da+o1r!oc&6vnY@?Wwt~(-y*Nyiw zPHi@d8F7KhtBX6iPB=$(?D#}acaeWT*3QejGvnf}*p8{<9Cc@OQPL=8WY2e#3daS` zQBGZK6f-iPcG87&lvCFm#f)^_Ln^qy^}?x6MlmB@?WGInD5st?iW%wZ5W6rfoTHq2 z($R#f)@4EM0gn<5YX2n31mT(uMajPQ73h zGt$*Vy6|4cshLJGBVCV>O23zJYQ0g+h<8|4?~ihwFLJZPT8~`z+Z*ovpsn+0#`|NW z!t(^Ymw7aLKk*<;xWMGqMQ^SXu1!UYT;0N5eeELcku1!w0HHsPOdYV*lfoqdfPaDOI zbUh5YK2kEhzm?!UG(QV!Nsj>3ruzwzuP+fGcKN$J;O!+ z=%UcS*ir6x;UOb?evVW)F5tqc^NeCf=JULC!G%*zjABN*29Qd-aH^Y8%t+S@(ghbz z4K<1x>3T7C;dR4>Q|}qYjJUw$)x|)r6W+_z7&xQ6yZGAH8JKY~NcN2PG6SQFKaFBW z_WTm5-~#VuoI2@0ypG(@AtEF587y6RFXL1#qnMGdA*6x}yq9t64x^ZnuA$O}_cBiP zGm07MdYKen7yjTJ<onaXlugIQp&o(T&*k=?o zvghG(&p1cnp3SK<5AlWMF(dOCAzipmf%h^_wK0kr>3T=H@LtBL=Z#`Ux@Jfh-pe@k zzER9b*G%ccdl{#;8^w%t%_5b4FXPlv`I8wkBi>D}nPu~E#(p5G@GyyM#BR2QR|k@?J)E?k?OddVneq-zeT;2qBsoSJ16GtxCz zx^QiBYQ0g+NY@9E!ZCKqYjx!sM z!4IR0N=7jwd;W-2aDijcspdv8BlG!Kx^N6S^{`RQNY{K)!3B;%r$!jXjC3uKE*yhS z%`=J_=~^gVI0l{CY7{flwMe>f3_6wn$Yk=&NY`Rg>0{8T(~V+Ayu-43U&3|5Fk|qW8{5F(Z3kN-B8AG3eAdqnMHTER!xAgHEkAiW%wplvMDJ zW6-H1|Cdaa8R_~=x^N6SRm~`7q-%Mk!ZGMnJENEp7nr=dSiyC|`=-`iCY8UF6<3 zIn~)HW~6J4bm4uIQxlA0M!LR;uL~}4f9TX^qnHsFn7q1J%XPxNde3bSrd%9fFqzNV zjEi-$XWXl=jV`Jh#fJY~woNebeEe&FbtfN)}F>Zp*mX9@{Zhyl>hT zU0h}qGqUIJNQHA0p0hc1pHa-ne0E3|-Zwcl(kN!6>w8kc1>QF~^_fx3NY@Y2h4)QP z9WaU+>H0Bt!3EwoId$ey$qbnh7nr=d_=)Rm&#i&`fGWqdy3buSw{?EXxcFK2jNdu@ zQ*`lwQOwAme<2lI@b5Z|)M%rak@@VDF8t16@A||jW~A#^Qo#j&=de@18^w%t{U%-f zyAI$%VbCgr36iepAjLheNblv{#h8vt}VH7jcb&ynWan&^+)pKf)QOro! zKhlMBlvB%%Vn(|Dja_h2pz+_2IhFtDIefQPbA>FXQ5n z?78dJ?=|=@x@cn*GqUHr|K*=>~6O{aDm#f)?vE?scp)Jgayh`B$^NLT*Yh5vuE&Xq)1%a1@38`nr9R<;sTRb7sqj(dUlT5_D;*= z-NmoA&T$zR#bZ0p{P&zU?z`ini=&DsQ)Nc>d_1Y(0>_0@m5pLX=2JqtM$g+Y*{NHM zVn(`7AQfD6y7-mKPCaE5GtyO3x^P@LHN_}qr0c}k1sC`oK~AkPiWzZ%$*YT#xDMWs z;JBE4@}&9h;%{5$q>PJFvghM(I;+P?(M5^l6Bo?Lo=+x~cHz{eMlmDvDJ@+MertWU zQ*Df5M!HTR6^_Ef0NLQKI1sAw>JGI6rX2b<1uP#pGI^mwS z?C5t^xQl(Z&S@DJWo6H}r#&sYC|M$L!Hn#=9I4;}_q0ycHi{XUPkHIWJ*`vs8pVus zolYvaz&))~Lyclay3UX;+|xSsu~E!O*O~Ek!3FMVo%+!zX2b<1uP)BwI>E(-oA1ee zBO;k)UfwY$B>&f085b2~&v0>8bWz&U!$0ju8Q$>1s6`8TQZp;GvWf1R~P4V9enW-=cvyoeUW<{ z5?tJ3>zto)ae?d^KVNx%bkWNwW@OJ7#y!IYt`|;CGm06RPbKNX&sRFN$tY%|>mpLY z1%AHLslq2FuaFt(sw`bNM>$p9C}yPV;@AZj_}#ot-Dwmv;sTRb7ge}Ua4}_B{!87( zAX}$O#zj@xGh9@OE@l|TjO@7@sc?>h3#T?2#f;3Sx^%&XQ~$%8)Z8Ctr0Wt=X%|ji zXcRNjRYSVq!l{-?P#04|bbp@%k3#YC$iW%vuEnRToR0pG& zk*+IaS8(CfK%6tM!K#dm3HCOjYcseT~|vNTsYOsC}yPVn%EUwI5p8IX2b<1 zuPz#Jo#5i%rmv>HgSW=kX^?TzQ1%QL4Wf%bjABOid@ZT83#U#kow#5|=F>>J;KHeE zjABN*8k0)9aOwf0n31j~(ghbzjWvoH>AEg<1s6^&Gm05;fyt|j>$y&FaqiYakNR=3 z*Vef{YPqnMFBw#r;aX@yh3KA ztCe)Yg;SRq#f)^_7Q2EAr`j9EjJUw$)y3^xC%nIS_vkjY-Nnnc&g~f&t!2-6e{p+s z@s3f<$e!Df3NG;e!l^HfVn*iER=V*1!l?sBF(X}fkP0sFUeBphPD@-cBVBh&7v5hu zRof_Lr0cHuy5Iuu^_;rHC}zY3Ca*5;<~rfHXf?BR>bqD^+d6k=T(pxt#KYaO#+{$yAwlP9sRgiW9xLxxacH%hKr8T#otCTBYW;lDjXMh zf8kVxa>-Pgk@<9yF1T>&CZm{+G`Xu()CDu zU2swT#zyBkb?WKK44DxZn7q1plX-~!KSo!V;@Gt$*dx^P@Lb?O<( zRGE>kCu0{};5n^RR~yBQxWMGqMQ^SXzLRs(M=NsMPdfAR?zeS%XIwlbd*;s}Mi{RB(ZN zTBkZ2#f;2nuyo;`)~OLjF(X|=NCg+Tr*&$HQOro!Q0c-wty8;=Vn(`Nj;{+Ya8K*h zNfiFeLXMEm0EV^iC6f?5t;c?Hn zUf}a?r-m5CjLc_*bm8-ErxqB+jC7486PGbZC=Y;4C=@p<={*gnW8W@OK= zk_yKKt`|2vQf-P*Ob@=7r2jd zs)bR^hzm?!T}rBnKcuV$-pTC$IUA$@(GqUGtq=F0l+`3aM zjbcXTGhMpy^A}DXG>RGNdYe>mfuCD<>a6n;7tBc4JJN-pzi_I#QOro!jQG0X0@n+t zdK$%yxWMGq#Z0aft``UUe%snzOtE!lW?amYJ>z;YGrIW1C}w2O@5Vic>xEOl7{!dt z=RN7d^}?xQ6_cqlBVF&4iY{{33#TqJiW%veEnT=?ICY~@%t+UqNWlfZALUecqnHsF zn7q1}%XNZ_8jB7a?k+~!I&(8FK8Wp@DqPHU7e+B7d;XAAJT7wAZl?|!#f;2no^-*5 zQ|IFgkGVh0NY_WC(k`58YZNom^|5rpg;OsZ#f)^#j}-O-7fvlRiWzZ%$*YS6TqoSq zuGo9|_wM2!TW3MW#lqMQ7r3Wg5M7*dK{6j^WY3F81sAxdb?R!Pn34G`mM+}WI(5HM z%t+S~Qo#l8X`LEl6f@HGiFDzf)~Qd8Vn(`_#@7WGI7d0P*C=Mh1tza9mT{f%Uav&! z>NmQJ(ibLEU6yh2sq7i=^_E2!HH>0L_WW7gGYsNB%BeO+F(dO?E?s!9=TtwVn31j( zq=E~)*K=yRQOro!O6kJ2+o|QD%bxKJWL0!g$0%lG&ud79;{q<6>SPo%GM_J`3(r8D8g3Lb(zTXUaDita zPAxWy8R=RlU2x&l??y2rU0=p7xWF?Ir%t>mnISXc0+Ux4>$y&F@$$l}u5cGu+B)kq zF20gI!^QgOqK#3^$ezC@m3HA&f1{X@`D~CbxNzznqnMGdZ%CzGIJLnjW~6JQbisvF zhgD9d%8Ybvie15lQ)d~)jJUw$)x~D66RsD#OYTdZqZ->fn=>xHl|AEnu{pZvViYs7 z=Pjgy3tTUp8fg?WGM}x|h3kb=pBTlAbZsLQT;O`))E=Xlk*@91h3kb=r7uogFe6>x z#n%NFxL!C_&nRZZ1tza9c5t12xi#>l>iBWd+1A;Saq+$Ex#F>NEANOd1{lSR z?D>bd=WxAnYL-#V$b5d3uIpzs{K2V>MlmB@KamP9aJ_Kq@G8kvnUSuar3=S}Q)e5+ zjCB1HyWj%X3#S?z#f-SXB2dg0UpqnMHT?2;~=qn!HHC}yPVcT&Lxt`|;~teUuBM!I%O7hE`XrBTdC*Phq~ z7r0(Hb+1v(hzm?!UF_vL!NspzD(`g{Lv5YC85e)Zp5bC|bTP{)W@OKQl1jU9YLijS z$b9~iF1T>&h-%4HnUSu2q|z>&I?pI(q-(!)!G%-JjbcW+{*GP2g;S3h#f-SXLJ zi+o%sxVZWDOQyJs)wWK)0{{Q#^$sHyex4C7@)bBD*-GACqnMFBA5JRm!l_d(Nv6t- z%qPEe!G%*-8^w%t9YHGX!m0a>Vn(`-lrFe%YK&3LNZ0>jS8(CfQlpp=7nr=dD8O~X zbK0s)>Zh(3du*Ko85ad*&v;H-Ai6lZMlw}qWY2|2rCm5x)hK3UK82+V&uN`%WfU{g zbrh-K0?%ok>SGi$(p5yd;KHdXMlmB@MPnCS;5n^RtBqntTwwC*q8Qf+&uOpQe|qls zyC$>D{r($Ur&z|t(XwYer!5v;oOWr#Gb4LGhE#BY=d?~WGm06R&#}^l=d?~eZ4@)o zbsVYS0?%oknqw3*(p6l#@SN7EUyWi$x{i;p3odX^>(nVVlW8y`E--m@QG)9%gwNdn zmj1k=r@Lrk>y*g2IDu3+N8#CEiRhxcQOwAmOOlE%a?b{xnrsv^GM^Kr3(p3f+GG?n z(sdH4=py%=)~RBbCG%lMx=KkGo((#6g;C5%*U6E}jgZdJ5f_-ex;TgHEY2-bF!#R}o7xR@7q{6u z=VV-*D|^Q8HasV~c+x0lWY6ctJ;Mclx1m#S8O4mur=oP>cN;pj!6;^=>wHqd1%9`o zQ%7ErOqChwxmpLQfAG&m zKOOO;Q!|ZXM!dtadaulNg7--Wi;s5i-`YBrGu|&I6|PP2UO9UI$0%lG&s9i;^C7%D zRkn8Gf*F}lRq29vr>-)J8R@Drzs=e?;$2<-anSAv59~meqSruCpY!3Xb~Axi>Sq))(sc!?w0Ebb7{!cq)s`-J zcj|Man31k4r3>Dj+G7+m(p5*g;N7X?>m&x5k*>O=a{u5T9Pdt5F^U=S4$JDj9@oKN z^p3TqYO~jbcXjd=;tS9lsCFsn?8RM&@(1baiW0 zuANgWjABN*t|1k?mp*dO1y1cViW%u@AYJ%yNj;2&b1jAjbzVwUvO=7@rqH*$etUM3NG+{Kc|)%#f;3SiFDz8 zfm44Q#f)@aM=H3$_x+rzfUnf${xBn5*Gm`P7dUm3QOrnJ(@0@ed}qL^r;TDpTwwC* zq8Zl-&sSf&sebBw_^z$fEaReiY{#7pp075GF1|8~8QJpvrn!`pJBlk@?&x zU3k9gR7Inhk**e`f(tzBcIqahn31lVqzlh3oO;SAW~A%p*aa7O*6q|(qnHsFn7q1Z z$#ueUF?{;rSNd_W-qvZEadC_68OKG-=pyf`WU9=_o^K@;T;RBHs*+L6$b4E!7mf?3 z?l6iO>AHa zD!9OL;nZ5An31l#r3=S}Q~9n*rooJKwToThxNz!RqnHsFn7q2UhwFsnqU4a%esC8p zY@K^DF51hUaa`OJT|8_QGqUFnq=E|^7f!uu6f-iPd!-AvYbz=n~s; zT);)==%TMt%*dX*l1jU9YLZdR$b7m<7hE{C(kN!6>wZ#c7f$UliW%v8K)T?sBVCV>O1p6CFQb@|u1BQ{E}S~`+QbDj()C!Rf(xhW8O4ma zz~t4%<6I}Wc;VERbKFHoTj%kNizi}xaPfF_(a$JmWY0ZGrCm5R)hK3UKE0$1E}U9z z6f@HGB&oCur~WjG8R_aRU2x&liH#B$%t+T$kqR!Hs$mo};sTRb7k#)+aPiYw-N(3# zR<=%`jElapJ-Fx-UGy}H8QJsGq|z>&nrsv^GM{Ip3oe}c(kN!6s~@Sf3#almPNvF? zboG}mxNz!RqnMGdXCoC{IMv)JX2b<1uP&bBI>E*8i|fpA7f;wa&t+UZAKQbA=c0>| zMlmCM9zZJX!l?yDF(dPNLAv0=sUMAEM!H@km3HA&(I$xtW~6JNbisvFm5pLXx&}om zxNxe4QOt-7OkQ2Q#C3v;KX2^c-CaCp>%5e4F*vpd7cWH@ql{uk_B@1C+J#d~jABOS zGgP|Z!l_+GF(X|slS;dAs^oQv3udHim~_E~Q&$+pjC8#cso=t?c1AHHE--m@F`VlJ z7rXAg@eFtIqOCJL<6=Z?4=#pB7t@VmM)o|CRN948UmL}Y%x9Ez!G%+YU7t*q8R;5L zD(%9lbBtm}y2eNsTsYOtC}yNIBHz-IxkMi(C##feRRB(aMfSf98 z6f@HGhIHYXuv2x6Vn({&lrB6IcIqypn31jt(uHTjPCa83GtxDYRPG=AgJ;4{O)!cX z@ea%CeG=CR&xBuUTPyeXJ14Wu%UfpaOv-qlOe+0McvAHKyHU)@o~Mus-tkP>sWQ!y zR%T>AQ>6>fgq><)6f@HG7OCJJ&xD=oX%sWkHBGwkOxUUEMlmB@(_d zTwwC*;%%-ITs+tKn&$4JNb_VqZ)aS*BYVd4`M0Bs8b&cAd!9im?ZT<9MlmDvnJHax z;nYN&+F}$l()F%%!G%*N+>lIz8R>d2b_EwsH8hGDae>LJi}$$>u1y7V z|9k)8*>&B;leW(L85gr<&t*E^QS$xhVvJGD$e!nr3NFe&^Xzj@EjEf7na^D5y5{dj zGo1RxC}yPV15&}oVZZj@?bI3ZwKn`Sw6t5M8I z*GJN|w9Uqgo$75AGt%`jsoX#K2j@el-ZY9C@ea%CeLmL-_awEqJd+z$GL^i%<+jfJ zjQ0hk!ub%-cIHR#dyQg7_Pmf(@Q&wfPL*qsv@#>}StMP!CvmE&QOro!Vp737p0hdC z+bCwFYl(E>p2VpcMlmB@pF|2W@ch}Stwu2;E--m@v6SnCdy+F|K3vgV9DP$VpQRZW z%VK-DCs`U@R5pqk+4HBQf(zV}IMv!HW@J8}Nf+)(oEl&hGt#x3RB(ZN5~t=G#f)^V zkS^SlIQ64Z%t+Tt>B2pUQ^((&%#a!B`dqqjPvTTIrM)|~-za8eK5L~5-kmzP zWinM}q-!0iw0Ea&H;NhQ`ck^!-KoJwF(X~;r3>DjT51$C()E>e!Mjuc7{!cqeN8I& zkLca0ink=wU`D*dvU=aZb%OWL*LE-D-do!`8#3O%A(i&NA$ot&C}w2O8%d?TJGIm( zW@J8_qzm4i%DXjrrOZgzW>RVIPE|9C8R_~~y5QZZ&PFjKU0b9J-kq9Y6f@GbRl4Ba zsVzn^BVF4_<^B=9J5{1pG7Vf59D zE=DmUd)`4Rc*pnEof>TvGcup=r3>Fzcj_~vn31j@NCofszPeNUjbcW+ev~eJU)`zG zZ%d}ijCB1JUl(NHd$~?EF^U;+fyt|jpSezO(RRy*!`#KAw$9HP7r)4!;o|4$Vyscj z$ewq`J>yCZ7f!7(iW!;DuhInk2NMdcr7X#04g=E_QRBa4$My`sJzjAd_vK-5D2qWY4%4-5p)5F^U=4^WL~;y2#y& zI(1m1I@$tY%|>rYbAMebhIsWwJ2BVB(<7w$!!8e|kR(zP#AaDjVK zr#?1{8F7KhtBd_yC%D*MZR99FE_T^E`!g>7j_sH#T5GtyO9x^P@LHP$F*r0b|i;q~Jj z<S|eEm*$(aF{+o^f$}Y!5DqM;9ZFVn+5{f>hdtQ)`T3M&@&ZbisvF1==O^VMe-2 zl1jU9>N2C4k**V^3oe|x-za9J>!e5p7fwwuiWzZ%$*YS}Tqn4Ab?lZ8-Nhzbr&Pwp z$+11SC>32CG>RG7b7@j(7fzMECz&cUGM`hV3oe|x+9+nE>r_%{7fy9HiW%uDBVBOe z)XPROBVDIOD!6d!1EZJ`7nr=dD9d$%i$AvBcdWbEX6uyAxF{FfgNw4!MgI25RGE=I zmnW5W;nev?F(dOiUAo}Hshf>rM!L=*m3HA&AETI&t}~?zE}WWf6f@FwR-}Rpr@l6d z8F7KhtBVR;C%BmT%%vx}i^Dr4Q>~D3advDEE-FM9ry0eJ?D-s0X%|jiWfU_qpL3-P zE}ZIQ6f@Fw9;vhor-mBEjC56$F1T>&L!+3HuJa=mTsXDOC}zY3Ca*3o;5xy@&S`zB zyNd$%CN3_>xVSL32NxGa7iSs8jO@7*sk95Ht}}`mna@Si1s6{BFp3%Js!S^F!l~Dc zVn(_ymM*w(YPnI&NLQ6e1s6{3HHsN=fyt|js$3_ys5AE9r|zQEeTj>z85h-JdvH-T zx~OavGqUIEq|z>&y1^)BWImTj7hE{?uu;rNR}E5W7fuZ~iW%v;RJ!28sSk`|M!IT7 zD!6cJqfyL=3rt>JT*h^Ri{fV&{nuUmYwKK=aZxL_2N#z`7sWd!2APpPUrs9R!l}we zF(dQ2Lb~9>sb)qoBVDygrCm66zfsIc*Ok%*7fuZ}iW%vu6RF_BsdtQGMqFU>>Y^^! z3D4(?wK`PFU97fs>SkQji|ufM&t>XH7h8>DM)q8vRB(aMAIR!aDmU`oI2MiW~A#H>B94Qr|KHTjC3`SEAIFw0Z7mNxhVH}oKpjgVn)2fvU+dCb;2e+8!8_jLJN2zm%*cGMlP(;CPUUq@yfY(R*OLm~@gCo)(~M$9x|&KCjzOnt8^w%t zHH#En;61)mt&L(vTwwC*qB++IF4{bORO;t|df7V7GcIn3?csdbJh~Wa6f?5t8%d>I zI5pEKW@J7sqzf*bT4NM5(sdK5v>s5!l|NN67S4NSIbBR7fzjR6f@!i zlUEnFaGl`dn^iqifA?8^Tj!RHi(6xRaB)j?(Z(odWY4WgrCm7H*C=LWKDS91TsSq! zC}yPVc2a2*U2x&l9;29%t~QYhE}SafH8IGHxWMGqMO&^DT(tal{Plj0 zs%q=B&A7NDwg(q&ql+7jVn+6SC#kdxr+OO2jLhdQ>4FQVCK|&(wBQXu!gp63kR?=G&fb=qfKbcpS6 zF|EvJXSRRj1Y(#f)@yBo$ord85Q6 zr;fNknGZA4)k(UxcYo<@r>YpmjC6I5RB++coklSuE--m@(S_@Td$zeJlurG;!w_4i zOU6al*bW!CXX_GOEH;W6*>g8i!3FNwochlwW@JA1OBe3hoT~ajGF4`z>j6^11@76L z>TDD<()FNp;hxQ@iAFIaT@OhY?%AB$W)w5h^{{l|p3SLJ4<@gR8R_ay3darp;GWH? z>y2VYyu-43?~$yNtHD|m-dZ%xkHP-7PLGWDM`X{>9K2wCkLZ1xQOwAmA0-vM<1;d+ zHW|f?%;z!bTK+@PolX^gD47p4()Bp0;2pn@(W&Z2F(X}1NEbdMbLwuRn31lYu?sHn z`xu>i$tY&T1tza9dU2id=HgKEznZ#>k8Pb^85d8=o|k@p*OR@Xiyw?)M)usBRN948 zCp?@?l^L1OQ_?l-n|?<-Ro^IPq^l39-~zuh)~Sb#Vn(|9YFEyMQ*Ro@jC4I6yWj%9 zGuEkfMlmBUFnM+H4A(i{T+He`uY$YC-#wYnGZ`2CNQKXiZ@;MexM!k^3yoq%_S~OT z+J#eh8^w&w=UM5hvT%A~r$!mYjC4ImD!9OL;nWvKF(X~iOBap{rwaB+rooJK4TxRg zxNxebQOt-7OkQ2Qz;z0ki%w%YY;hM|ZJie~E?$&9;~e!ubn&85%*dVxl1jU9>OG^F zk@*agE}WyB+H4dv()ALlvcqExBGtxC!y5Pd8bB$s~x`xEA;KHfvjABMyVDjo> zDAx)1&kGLxImlf+Wa|vgxOiFijQ99Mql-~SF(Z2(Mk=_#dwi#s8^w&w=N0L~{j*aC zjbcW+hLZ{|@E+f(vmZ@dFe6BQxzUd zrpk6#Q@7hK@GsZM=l6f@!ilUEm$xlTAo zop(g*)bC9D(bk!qaWO^qjC0iF=%U~g$yAwC%OBlv8gT#f)^l9VxiLIm)T8jbcVzVDjqX9j+73QFqo~ zThot=!+IuDeJA5$Mr;q~sCS}^(nc{Od!9)u92Yo8Idz3m%*cFZNf*vhPTgq~Gt%`g zso(+MmQOt-7OkQ2g<~qSejdv%MaTj}R zo!J=|b4Z1IT3jz?M;FC=B?g(1J~zL;Z%F0n31jzNu^ylHN+@p zq-&mZ!G%*F8^w%teH6Qb3#WcEiWzZ%$*YTxxlV9#eZjV=@1`F2WHQx{GcM-Kp5fx- z=;8vSn2|j%AeDCE)D1>4BlB4(U2x&lqed|!U5iMiT{tz)C}yNxQ=b^cjC6e=U2x&l9;29%uC?)X1s6`0>XXcn8F7KhtBZA9 zC)`JE{Pls<=ec!lopl)(U&@|wAGI#JXl)cTvgh@2&*47GslG-rBlG!6x^N%m)MTTW zk*=>v1sAxFa%z=P%t+S;>B4=KQ-2!8jC6eyDY(FWlv5@9CN7u}7nr=d*vNH)iwF1r z^@d-&FST_xW?XEF?U*WDY>X~$Hi{Y9^JY@v9EE#Yr+OL1jLhd->4FQVCK$zxbZsG( zcHz|LMlmB@TcrywochZsW~6Idq=E~lNTwwC*;%BZ?K37v9x6b2Nd{e?*JY?(q zoN@7s>>1C@e~vCj8^w(5c_*o~3#V2Z#f;47SLwntbEp0@iW%wpjZ|=fXXZ{-?3YZH z8R^=kT{#y{wK9qs>H0l(!3Ca~JN2AV%!mt2UR~_wI^mi5+f9F~W(ln34JXAzgT8?o>0Qn31kONd*@;E}ZIb6f@HGmvrH{ zaOz{Dn31l1u?sG6TsZZIQOt-7OkQ2==Q_3RxM($eMn88^;n`$9`!g>7CKcZ6?JW6Q z+x^i+eWRF>Js%*IcHvY_?5~|eP9$b()F)& z!G%-XjbcW+{)=63QEd6R0!|fpE}0=S;sTRb7l*h`xORWK=Z(egqN1&HDB~ipQ2OT( zaqT`7T{JU_8QF6_Qo#kT-A?s3iW!;DVbX{P)QlBqHyUB{3LF7Wp_J5|jnW~A#_ z>B2e6sk@D0M!JrRUAbZKcgi_6*eGVi1tza9igTUdqDzfYGu*`jTc>!&#qqLdxF{Z7 z{9qI_vgZ<{(k`4j{>5af%*cFBkS@4z>Pn-Sk*<=Y(k`6pViYsdb)s~^g;QgUVn(`7 zie15lQ=b{djJUw$)kP_;6P^v;I;Z|rcd_5rDV1??vg{ep21`X3Ck#xc%8cx}G^w-; zr)n9+jLhd0>B6%?r|ve28ROtoyrMLF5?lh3zUTsFEm-6&>c&*e!47x=xG zPBk`)8JW-N(zT@SlDSTGH;NhQI)hYjF@3?v)lR);6f@FwrgY(VEjqQrC}yPVtk@M? zIQ6Gd%!mt2UR_k+I^o&i*!=BAxQkO>N?cUPxHwz(jAw%tqKo=QF(Z3Ehg5KZXM;|4 zH;NgV&$-ftXM;{nHi{YPI*(Lvf#8dDQcsA%%vBAkSn31mYJT)=h0aj|`Lg#f3Vn({E#IA5$IMvuFX2b<1 zuP&-`o%y*%aE`jU$|b3v&waqwshV+7P4(siYD;o9xgpGGkwU3Fp?T;SU6ROMmG>taS+ zVDjpsF4tL@TLZ_%#Mc|%;x6vDb?RnZ)RR5qeRtjH;w__?kv-QZ6P@yNnR;4(sebd-~#WvoqEV9W~A#H>B4(Gr{);NjC3`K6kOoAaO$8@%!mt2 zUR^ZgI=KfQdAYabc?VbS?Bp(L4o_Zb!;Fh-V>^xu{Cq*f=%RyB%*dV_kqR#G^94?g zGm06RPh;uA&lfoLwNcDSR})gf#n#-<7dUnFh~#xKBVE@?7k<9Lsrp7SBVE@^7k<9L zsmG0CM!K3x7k<9LsaZxbBVEl%;kdyc{Ct5^KO4o2c!y>6-kj@%WAKX_<#LZrlBwk7 zl^L1*U(GY#Z;(CX7;GNB-)0muvgaE~1@AZpoqE$KW@J7sqzlKOQ@e~}M!Iey6};mZ zbgJs8RGNx|>wmg;T?fVn({!Nf%r=^_fx3NY_1) z3ND=b$0%mR1tza9+H;-YqI8vQ$NF(m@zrEL?K3Vq#P;B#eROfNQOwAm?2*3bbr(Zyoh}&{U1NK2(IvWAV-z#8=We9ZE}Sa)TJlPnk@?&&U2x%4E2Ef^ zt_Mh^T{tz~C}yPVLFs}Er+zky8R>c`Qo)5&6~`y9iy3i&$*YTpxlVBL*NR^MxQlMK z&chiO-D7)j@o;qUno-Qio_ml=yKriwQOwAE9+57%aO(KilUK@&bUjKc?ZT->MlmB@ zk4YC?IQ6tq%t+VckqR!Hnr9R<;sTRb7f*1V;Nq}#FI?s>{<3wR$hhbk+k=ZIqKgV| zB=ccL_S}n9+J#eh8pVvv=Sk^;3#VQ+iW%wZO)BlesZB;PBVA8P7hE`X;+x6qVn(|9 zL@Ky&s;N=Thzm?!UG(KT!NtyP{ZrSA0k%%xjEkpZdvMV=x>#rwGqUGrNTppkm2X1w zN|}-Q^ph^QaH^J3%t%*%QfU`XJ!TX$()Fx#!G%+EjbcW+o{Lm);nY5(m=PD4yt;Uv z>jW2*tCd{h$3^9d$$XyAxEK)IgNx^*i+hb?M)v#ysk95HrW(bJ%;!bvf(xg9Gm07M z8b~Vb!m0BoC9jJa=^7+maN$&EqnMGdmm(EhI5o{EX2b<1uPz32o#3M1>th?ci(R(P z;EanQu|2pL99>*6IeDeb$exFiO1p5Xhf&PPd|s9=xNvHbQOro!Fj8q3P8FS!?2sAh zdPTb6!l@QUF(X~WBNbdYHP$F*#04g=E=F*j;NpZ)C6>C2pKP5G85bjCdvGx#x;TAm z@=BSJJ&z)lcHvZeqnMHTjFv9AaB7-S%t+T5QfU`X{b3X{(lu7P;KHfuZzZpb8R>d8 zQo)5&j~c~{xWMGq#W=1LTpZ{=aF)CH*wz`Baq(Jg4=%<<7kiCjM)o|ORN948=TA#s zDKj#k*QE3UPT;KHfxMlmB@6CxE{I8}Oj^17H27nr=d zn8LyQ9WIKje6-2*=wh!?%*dYKAr)NUvl6GuzLU&{8JW)v>8kQmopw%L zXB0EiHIr0uf$xht)zc_uq-&OR;j(hNr+(n@o$$Z|+xOiXojAw)IMHf|!Vn+5nn^bUt=d@0BFp3$O&m8H(apBZhqnMGd zxuk*%Jg0SPol(q4*9X#tx9orniTkM zn!D&?>&(lz_$apHxWH#6^P-EQuW zfK+g?HTPMGQl7>jdw`uUNgvy*IFRKFN4rDtm_aPonn+jbcXjyo^-ZyHk^l zVn*iksdT}+Q=5%qM!G&DmGKc$^}KkofxKC3d`SIeGp?p+nVpJx;^ zvgb9Vf_I#IooZqfGcunqqzmU>r@9%%jC8Ff6};oz>(o%An31k^(uH%cQ?rd?M!LR? zR5!XXpvlD~N$ezC@ z6dMr+OO2jCB1(D!9No%BkT-F(X|+OBc>jPR%rm8R_~Z zQo)5&%Z*}2TwwC*Vkg%LF8a-0x7S_luyuB3T>Ki_gNvQfMc&-xzaM5~&%cpMyKt(! zQOwAEc1agpICYg#%t+Voq|z>&y4NUXq-(cy!G%*V8pVus?TJ)y;nX`uF(WQ8d3CXu z>jW2nbT2jDU97Wp_GVoC5!-`{z0t)_MlmCM{*zSNg;Pgfyt|j16(J#7~Qqg&F*5bt#csb z;$UnKE)GN&6O3X;_WTd2vF7g%5 zePN7$?l6iO+4JF~(k`5O+$d&bKKZ2!E}R->6f@Fw1gW$Or`|D&8RlDbiC>Yy=ivrO_(Rs;#Kg`IU3z15@ zaOy0hn34GumM*w(sLg;Nh2#f)?njZ|>q)BvNH5f_-e zx+unVf{U3I`lWtf!JD>Dv5bqOV|#E>EV`Iu6f?5tV@Rc4IQ6Ab%*cF>l`gn&YL8LO zNY`EM-J-8?lU34{y8QF75QfU`X4KRusna_#R1s6_DGKv}LI*C-;g;Pt6Vn(`3 zNf%r=waqAIr0e8J1s6{JV-z#u0+Ux4rMXUUF?8=6AG(VZK2HAoDV=d~N^B1gjT zQ_GEFMqFU>>Y_Z?2`=ks?q`g63q=ws_t%DA{F zw!;OU&sT~rUNMRp*>h!5!392-aq3;8n34HhEM0g$@6;DYF(X}7NCg-8T*j&2jbcW+ zs!A80&pTCQVd9+`>8d7Ocs}pc*+wxVUDc%v&*z=0Zxl1qbqT5T^LeM*7{!cuhh_C% zgX;wE&7S(9fqQ@4)~S*4ekrM=a?XSI8qxazqnMFB*Cdtp?$nz`F(dQ2OuFFRsgI3f zM!IT|N_%(eYonNvuFIth-ksWG6f@Fwg>=EYQ-v2L|Ftk9UA3hP-kmCM6f@FwC8@M` zr)n6*jChA-^z(<6TP=FiW%8+JyL1!PW3Q~8JSOg z>4JBs1{uYSbX`R%?cJ$KMlmB@S4$VXJGH4JBsHWbTyDJcz0@#QOrnJ zLsDt)P8C?3{5Qsoc!y>6el6G8o;z}}*4SAUhPd}rZJlc~-W$oD@w4sMM(B7&pJGIX!W~8fW z?8=RhKf~)(*(He!X2b<1uP&N#orUJ&*h$o z1-_T!)W1eCBQ7v`b}65~nRQE^dkK;X2qdy12+FW@OK|k_s+x z|Kn6MqnMHTw305I51o3zC}yPVHd4U_?th#bY7{flb-Q%oeCX7BMlmB@t)&a+L#Mtn ziW%u@BV9NjI`y|v%t%*TQt9)dQze%szL*j3u&mzi;5y+m@rCW1+~D4;**bS*yx%E% z#%JPpMDNXvVn+6S7pdTVVD2+B48?PK`E-8R=?ADtIrI`%K)ag+?(W zUH3>AJ`;E9N28dLuJ-YD;TXhc;!YJ_mbhR>TwwC*q660nE_z(D{8D#uzOBK&t)k*?0t1s6`O zGm07M>Jnd9aN*QnMlmBUFnM*+mFwWzgx_g!d%i#J87|5{^Xzj@J#7>-GM@*e>zcnC&2Va=QOro!gQS9s!+!0*+o?lFF(X|M zNmtvltMWTl4JBszA%az>3V`x+PhQ5RwS>B8R_aNUGVNy1EZLcu3pjw?@m2!6f@HGq;$c%Qwxn^ zM!I^FN_%(eU!#~2@35@ipW-^7=Z-(Db?uZE^WA&3mC1ab%6RW1d;WdL@2@=-y|*!n z8QF7RQo(zP;rU*1YKT$H$b6obuBs!3zU$OdqnMGdXGjI_Bd2{a)~SO=F(Y05r0YQE z8_GCU@$+OF%t%-N__}f<_fG#Xwu<*^GQkeb5f_-ex){WD=H}MGb?|}wcTaW~ zhisie85b|bc1(5O)Rrd=iY|^@oy>-@M z8R;5ID!3TcsqX@(+8f1;biFKH)9b!+l~Yd}#f)?fldcPEHSg=xc%zt+u2-b%K>2w; zI5poWW~6I4sc=4AU43yer#2eJjChA-^*(~@1n+ZSJadzK-*4-T$ao(qdxrNB(R-0K ziFamX&!b4Cy*qV|QOwAEMoSmGJ9V{D%t+T5Qfco_-E9;z(lu7P;N7V{MlmB@uSyrZ zJN24T%t+Tb>4JBs<{QO~biGC@?cJ$OMlmDaVOhP8=Q`mzz`g-xzH;veY@P8L@2|_A z@mzF#^nT12iFamX&u@?l-tip3sSAx_M&|RTbm2LGQ`Z^AjC4&P6};m)fKy$JVn(_q zN*A63I5p5HW~6J9bm2LGQ*Rr^jC4(wE<6WtYPC_!NY@ln!8?AJms7ipVn)2fvU;D& zb#UK{wfZ(3FwwmiU7Hx3n(_XY>>1DErbh4Q8pVw4c^awU9na#NYHAcSGN0+vg=cY2 z^)QMV>3W+~@Q!D3PQ7XrGt%{rbm3W?Q%j9vM!IH1DmOx2bDjFtC}zY3Ca*4La-HB} zQkgqae;?3s>k=0;GcIPuc3gAeVrFzv-6&>c&+n2-yKt(VQOwAE-jgo4aO!2Fn31mc zNu^ylwZtf9q-(Zx!G%+Q8pVus&52ZS;Z)f#lNmB2E--m@F_-Iv^Wl&)W<2J{MH5?R zZpOt2u^ldOKAam}bTEn;+4F~_f(x7voqEA2W@J9|qzmUmr)C(%jC6fOD!9P;(5dxC zF(X|cOBc?EP8~Fg8R?oYT{s^)b?W-W1vApMK)P@~bm~f@n31l9q|)a@r|vY08SxIw z>U|N{3EscE<*GsM{TW+lQO5gX*)zN^irz;X#f`_8JW)~(gp8MZ8VA* z=~_xE?cJ$^MlmB@%cKk5ojU2O#2_=$^{I5hyHnMTVn(_?lP-97s)bR^NY`>wY41)w zU=%ar9hTMm3a%5pHyV6m=W)=tlq!mI^mkTZ*1w*?>wJw>wKBYwnlP`!b`Lkv)G! zDtO2Jk5j)G#f;47Yw5x@*Qp{K5`)Z0*9KC-JMMp+I^QT}r0W~$!Zp{a>x^PXx;92C zTyvf3ViYst0+Ux4o48JJ(fPPbe)nT=kgc;R<6?7c5BEQtqKm0UF(Z5amQ>n>Q>%?) zM&`3cy5Pd8KaFBWy0(%^yKw5nZxVydNY^&$f(xf=8pVusZI4uN;nZzLF(WQ8d3Es} z*U9~`I^P%Ex$Dquck!gH^IgWpj@S+t^=^6dnD3&CQARN%d;XqOaM5+}*40kUH;NgV z&kxcycE`;>I<>6hqYkWtLYo_{43T;N{R zskufmBlG!9x^QiB>N}&Dk*;0;*V~!ES$0+Bz6paMLllr11WW*lV!AUxK&`5->YU8%_Zr3et-Rg9sjG|16(I=BKDKZEm2!azvFhLYVK^X*;FoiKpCd@jZpeH2y%$66|F_m&-`Z!m=bn2Gt9&o$Tr{d~|39`D%!piH6S?Tv6jkRs z6*D5&*F`QmHbvEvQ!yiQ{jbPH$EK)yrc*H^a$U!&^w<R7w3A__iuwBXWIDGHddQ6EJ9Sz1{RbT9O0(5ctS{g5@wbnC|3w$)2deKs6mzC?k{^V=U*uHG zh&kWDD&KcHCyA;jIu$d*pH1c#*qh(X-v>*_!KnIUr(#CrBEijX=KD_PBvJJ)r(#Cr zIz{B7<6u->>r~8$TsIFYV&JtN>ZjviRNd;6winEZUXb&$7q{g&et-Dk zM{h}fH}PN>=eDXBw+q?*aqzaG7Z*4cGh)uSXO-^-9S5Uo!>O1N{@g+2qWxi1z09eY z5xGufmG1=|2czm=oQfHd>nB7m+8;*Mbxy^M$n}#V7wr$D>fWESy^T-5iddW%yrBXZq~RcYU&>VKSy8PRv@vh4f4IgURL zKKqj9Xzcr~K4V?Ix9aYxj2YaE zsJhQ*t%uBrUXb&$7iVxB-;1lR>75g|i=8gc8LAgQ7qa_aoDq6)*r}KibN+c&rM-x% z-*zfygg*}vxu_RW^_Nb?jL7v1tV(+kRUdOIW<;(tMK0<^RGsoU>nbxM*XE$|y@;v@ zIu$db7v#L`#TJg^d+`_V_@m_gmAhS>Evgr1h3vi;TS71TPQ{Fv^VzIQdl6O7bt-0r zKj(;C)QhNkvr{o6a-GYnv=>qJUrxo0$n{W>i+T}NKX58$M6QPgmG4DV-S_jhgUpCt zkn^$^=W!f=p78Kz{nziu?PAWwIZyTC;UPQqg3c4p3%yuzDrUr-AHgc$3pziHs^4}h zW`sY#D00zxLR7ugshAPDeu-7S7j%9YRaZL|Ga}b7i(GV`5LLJSf_0S{k!woiqVt5P z+U!)!h+NYm7o8_W)uWt>8Ify-Rq1&`R6W(Hm=S%aF3Y}en9VM&z0oxv1|^^;)N5M&vr5RcYU&>ffA-8PRv@ zvh4c>9LIk)fA1si_Tt$0>s*`*RNr@rIny=j3qs%T{w3QBX2hI#vK&JUw%r&BQ_ z{MjRNEj;w9mqpcOPQ{GKwU<@C?{t0`Rj+a?W<;(9k&Dg`qw0fB#f-@H$e{B3-l#g| zTI&Wgq8H@6?8QEgQu}Ke-4OT^d9G^`g5mZM&vrkD&Grwk8@Og%&C|Wxh@pB=snI+b?Yx%SD6vH zE(&!~FX;C~QFWG6F(Z0G&dXk0%yHgfV$e4B(Pus2lGuwS7w2Nti${q$)4BS^p%*8e ziWxEIM~6962kBfrs$T3=%m{yeMdYG$lBoIzr(#CrdJL;VFU+}mRDH^+m=U=iD{|2} zNmSkPE4CNRh+IoSWy<1n^{9G)Q!yiYLC(uwJdWdBX=2cQ)R&(4_2hk9J6)W|sb2I# zc5;<|SMs>fi)E)`M$GvTtNeCBzblEVXE+rz!k=Z4i+)!URj+d@W<;(PR{37g?}?)7 z-<^sXk*g88=yxSib)8c&BXS)Ux#)K#QFYg^+72=!avc%5=yxSi^$4e8M&vrms`S_t zRgZBhW<=kq%d+o%jzfK?SZBQCim$|N@F^}%U-kVGF=x7V(GPupsZ%i{=6orueBbHV z6jkqZDrST~1CfiaT}0KjPQ{GKb&OTM?{sX6syltn_JSFaYgOc;V^dT;+^LumxrRYy zEaYu4s+OFJ8PN-JUiM;*c!(jcG?E%{BSMw;M%5Kg#f->xf>r4@7*$_%DrQ9AsmrqOCppeLO!p|( z>qo!&Q!yiQJxS!E<6u;M)v1^fxt<(U#zNi(qv{^lSr3^Jy&&gh zFP_42{QmIjXMOeMu@~E2oTsQ>JT+veZIJedPYJ!a#HpAObAB4Dd@pE!7*#KDDrST~ zzb#eKIh+MxJRK6EcHSbi+ zh+dHMvKP|B`ozwo@@9a{ZRbMZJis!%oGF$o1Pn<$DoT&vzKKo zeABwhjPU1oMJ_rvMb)`Z#f-@Hd#v)kpkq^1J=Uq15xM@4$VJDdsQOK(Vn*cpeUXcf zO;PpdPQ{GK^*oV_j!jYZA*W(S?>jy7A*wEMDrST~e;{(vGasVr_ne9u zk?Rjx<@-+0--xQebt+~=t{013^vs8-`jk^KBXYeY)J5AMeO`{LTYuYn$c*R(IWK$h zQjT+ti9vn+*gJP8=jy-U;=EM#;$>pae{hf6ef6cG7Z*4cGh)s!4|Aq1m)=UmDZjL7xJtn$5BeCM5(qUvv*iW!mX6(SeCvn;Bvb}D8>u0IL6 zOj-PFsHi&SJGK|hh+dHMvKO!9IKCHGKko~t$L-<)F3u}eFJ2|)Oucwz=*5gvF(c;u zYF7E}f_f2EjZ-lr{CSPYMZJisXE_x!BG;d?D(yv7z22#q5xHI~a#1g$>itf|jL7x6 zkjwWXs;+Y?W<)Q@dD)9U<2e4r~8$Tz?^Q(XlD2-sDuw zh+Jb%ue~Vt{bCpA3f1?25Ob!!UlIDg=2XmxIlrA% zY2Tyja;IWO`11~ti~1f_Z*(eVM6Q2iRoeHcdY@AT6ELjL3DB$VGjR zs-K`6*UUf6h+OX!xv1|^b*57>BXa!{tJ1zl)gGr}M)aM!Ec^a0j^q1&?)pO>68nD4 z#d(+N`#+00Q{Uee`u=pMVn)pQUs#p)J*xi1shAP|yj$d=zDLznPQ{GK^&VEGeUGZo zI2AJ@*T0Hf)c2^m#Sd)ay(n`#6rj4sh=Gt~6iY+4?qZda8@_KGpa4i#gLZnfHahzuc*q5p(_zR{6fu zHJPaTXQyID`17A47hMO4s;@Z}Ga}aqSmpap*JPsVZa3HpnGv}@D00ztfT)^wDrQ8k z4+Rx%*>rzhR2_CIW<)Q@dD)8(a~$7`6L0wL>tio|+r{~?>cxMB?DT1Zdhy}Vi`P08 zGh)skVO83TsCu7MF(dr>sK`aVh^lWo6*D5&$5@s2BC77S=@c?;6Eh;$e~Vnyi>TV_ zRLqE6{}WUcm3k3XhnLBf-qUvQ%#fKf- z_2SDRJGn}|xHj}+*{PTjbN&je{B}XTh^ps06*I!0uZmpMi>Ue=r(#Cr`Wma!UPRSr zoQfHd>+2#H^&+ZHy}9iLGa}dj29@tcR6We8m=V1o=VdRh<2b$-Kb*V&onkKzxj5IU zUR)ot`(9iZdhv9pVn)pQ8>~uu5mj$+DrST~-xRs17g6<5r(#Cr`WCCwUPRR`Z(&_! zM&$ao$VI(~sxzI68IkKdLFIc9RTn!IGolydyzIqyIgUSGoU!{mAC0~Ebrg7(wjPU0c zA{X@{s{YZbm=U>d$*Qy$QS}+8Vn*b;mB>ZCh^kxN%65<$k?Y4oU1S0EBB~zXRLqE8 zkn^$^x8^v$7ms=OJ?h(^=jL3C6R;9g&s{e2*W<;*ri(J%;sQQ*uF(Y!_A=Kr25mop2G220AL@&sB z*^5&-j{m;tDPK8wMeM~dyEvz+Ui^fZGkxE5YUsrQr(#CT`6t7isTcHpQ&ep@6*I!0 zJBnQNeN$9D OZx$eX&-wXP_DXQM$RLqE6cNV$m`=+S+pi?m;a{W}O%l9Ixu5&78 zL@&sB*^9eyoGVQb`V2qwxffj)dvV8G+n(M<_2RB#&U7Aim(YtdoQfGS=evbDb1%$! zR8;MDDrST~cNe+n*d0|vr(#Crx(BO5FU&b@RQ;|~F(Y!_Q{)$ElbR{@hpOqJ30UJ<6$=5xMTiD&Gq_c1P8dor)Qe>;57a?W3aVPn?Pw zk?UtdUDOLYUPRTqoQfII3vyoe;xvxqd+}qNc04<77hiI5PE)-&UCfz!aa!obZGPPL zf*CRA2ZT9O2kF=yRcAUCGs2$-id@u-sJhUpm=U=i#HzFxQS~IJVn*cpS&@r+5mm2r zDrQ8k2Zy?RFQV$*PQ{Gq1vxK!aR$fny|`iOKmRHA;%hF>8LAgQC+1AOI3x7pcDJ>? zU`EXO=fj+RFQRI*Q!yj_d5FkGy@;xVPQ{GK^$V;@dl6N?>Qu~#TxW`0)QhNkxl=JC za%~QE`CdfTl}^Qs=mj}1d$EP%Tw{XJ@nZ0iUrl~n@i`Y~i|WN$V$SrP_?FO%Tinj} zf*CRAv%{RJ7xbNYR6W?Km=XS*BXZGq;!(BWRLqE6=d#N8g6>amu=KKg&`QrukBC1YvDrST~zbJBj?lpgUc2wP=3?jOYb9FMBb~ar}1i z3x}U}B=+KiF3z;-#f+FUZ5Pv_7vFFyX2hJgvMTLGRNdzewu8(Fe`ZB4+AgAMhf^^l za?P>I_ky;Is9JL>W<;)SA{X@{s$S$&%!pjuLoVtCZ5L7XcBf)S^n#q1z1YEV{PAKu zcfWs*z4*L~vqSY_r&ZDC0LZ@OzAFF&XXuF82d;f&(J2N8JqR2(tMN~b)shAPD_J>@4yNId_or)RJ3vyoe;sD3- z$BU02-+imti?NGyK=tCFm@^$O4uoDj$ElbRbH0#Oe!HOKMO3}cshAP|TqJVQ@gl0; z<5bLuTo<#-_kxZWQS~LKVn*b8l*mQBh^pKEr0pOxBG;osF6spxFQV#aor)RJ3vyoe z;#WA%l_mxqyN}$kuRxBG=Q%m{xDi(GU)DyqKdRLqE6M_3hlVXj9-)!pu7U1dh(Ix2F}^{A-Y?o`Z(T>VfN z^@5HUQ8jWZW<)Q@dD)9gIF8>gUh}b6Chq`!nTvCY>cypE&a_=z5_)lkQ!yjvJP329 z4$^iJRiAY#W`sY-L@wGcqUsKJwyrWGa;>r|^ulZxQFX3UF(YyfMK0PdqUy0u#f-?c z7F5&=+AgB%=}yIr=mj}1d+~UV^9~b(_EGozqkp(Z+%8_{;yhmUVidBItMr?-$A@0L z+o_llb6#ha-!AAkYf<&TPQ{GyXDo8jZ`Pvf9zSJ!!HmeY!7ASi`psHYZFMSUM6Tl^ z7yV`}sxEOVW<;*bg36e|y@;yIor)RJ3vyoe;snR>=d_3a<@oQ%Ui_7db3*mvWXMjv zpmW+2p%))=DrUr-pTMfn3v*5zRX=npW`sY#Dss^|ZB#wrF18oUh+MzMs?ZB_P8(Hw zoQfHd>xm*4ozq6uai?NN{d~)c;C!C5IG3Td-Ia3GeUi7HC)m^Qt%m{y;CUVg|ic$4*PQ{GK z_3Nziy`X#1qiUa1F(Yz4UF4#B6r<{dQ!yiQ{f5Xz_b5iyOPz`tk?S`_F1klCs;+V> zW<;)Mu!{C!^bftCD5^g1RLqFJQKLbPQ{Gy=Q$!59h;)+$xg+L$n{&S@_naswy1iIQ!yiQ z{kF(O$EK)yzf&Vws26l>imGor6*Hn27C-h>6Q!yjv{JX63y`azdQFWP9F(dr>J&}v{hf(!vr(#Cr`ai7ly`azd zQT1V`Vn*cpeUXdyhf(!o_poj-BXT`2)J46Z{b5v{<5bLuUXb&$7tiN7e!IB#%FjL} z_F~1wdA{n!3&fmhyLf)+#S@*188PP`+eK7;+Nqckx&Bb(qU|E8Zh24J3uZ*F7Y7yfg0_pOI^C(55xpSiWiMXBas09A ztn0p<9GkYgI4@DXcxlK^uF|pTC7~BfPQ{Fv^UGM}w+lKpMb%TCiW%Y0%SA3aHbvDd zoQfHd>yKFFdqKyhsCuVUF(Y#QvB*Worl|UyQ!yiQy+Y)oV^dV!=3cgg%!pinB688O zDXPwJDrQ8kSF$QSHbvD1PQ{GqJ9Sz1{Z$;t_x&?3-g+o*g98`mRjTi=7IUV)zbf?o znNG!wnDc8`mG(WVUhh=Q2!H-me9eW!bAqUzT7v92;B{CSheMb|E( z>fuhsjL7w7R{6fuy);oZa4Kd*uD=wy=-Ne8z0|3g5xL$H>Y{xw9S5W8-<*mW(F<~3 z_TsG^$M<6G;AgkSUfkf~yjAt$uf&|G7jF%{c+gKUf7r(#Cr`de0|y@;wSoQfHd>+eJ^>P1w2&8e6Xx!xA)^1XY6+A?8fiF8)6B;xeaVM$Gvi!knoWbnPOlUgcEG z2!Gx#a?!PmsQRE&F(Y!lgH^s4bnPOlZgD^B4>KayKZ;y*?INnqaw=v-t}BCzdO_zT zQS~^dVn+0WoR_`0isSfW(-$v((|2Mop6lXVrF!wsklmk?ToropdZ%JW%=w>K<@Zr^ zP7+lgbSh?qKkpK`=-3ohKX58$M6Q2kmG1?elSI|&_qV-ZM&$Yzk&BK^QMKEtm=U?& zEppMZDXKP{iW!mXJt7w!o1*F^PQ{GK^{=c-k4;f^rBg8@`c7SzeSa^_U zPQ{GK^?p|QzSHM|sQRE&F(Y#QhsZ^r3!>_dr`fug5xM>|sQfkXMeN11T$~T6UVJcQr)`ivSAHP$;yq5qjF|I>f{NyR`g<=vJ*w_} zx~-HMn)BJj&_6UoIp+^^oLMtQbH3&eH;?0-AM4_LSk3vrLUx+-9o~7zSARIn`6W)p zjF|IBSVilH{(1FN_kKC5KJ8S@h&j^?<(xmtan3g}=-S|??|%IkHf^#MZ`$FmWcYdJ#FJew1#~$h-@<%#$HOE;t zfO+)SrZ?Z_wg;kPk92XaR*rpwRkt$=>heXeUU}@*!LgB3F(VxNB&)n*uXxQzu8*oe za4KdtJ!G`f8~03T^UtSPMQg*?M>W`gt~4r&M~v}@Ri}+;?9;3|&HNY5@PWU@RMKu(H@CZFWvOoe~qg9ITbNd^;uSt zhorLq_zHj7sfdxP&#{W?B6i2|k32l)dbCp!VegYmwH5TrHpH?2j@it(MELyTPDd|6UjQ^J=wxfmMFB+~KRAz3TH}wS2{?m=UYx zi>&gig|@G#y35bntjzGf*Uy<|DChhoj`M3~zBGfo{r8tY66ZYS;(STX`C2jOtDk-4vmSKq&A$@n{C=lmM$GwZtfJLR|2$)M`TD5(f>SX=b3W@~7TZKKlym+% z$GOBb#@v*;Y0u~{pA=X2DG#>&`nsC)|B5+Z`+&!P>g!?7r#clgV$RpGiuMUq>AOC5 z?K`9Dbf;oQoC91ha{a*z&ORDdk8mnxM6PeJ>TWLA3vc@i*F@DLor)Qe>zg9i8Jqv^ z*P`l(Q!yiQeJiL;x=kh#GJp&s&xHC)i<1q8L@t7hH}o|<2dxiKOL@K`?K%* zi#X?>JHxJ@@2NR|U(ETF4}4woy)fqsor)PT=N|+W`Ap|XQS~gRVupP-FV*3HXohmm zKjb*(B@?_C{G~7b)dg|RZ*y^eXyuxi0_e z)66q@tSjc4@z1&cy2E|V-=1Xt*VM}B_*^sY^#|+I(`PNr99Y_OaA|Je{K0MemgctY zpPApaI6XbHX{x{4AJ4Cjo6+Ikaq{itnufTH{&W{)hb9`CL7mj-J#_>r}ZM{YEulVJi@zp!oQq6=*FOflCVHOu3r z9nE-mGd?<8De}v`!N5#?G`7S=7nqn!SxjQ~HRFxZs)v>?P<6{`?A$$E*%&m$&zOh@ zcFylv+&{BtcH7btyXmKUjIjf&gJExFp;=w&uO4B|(jMd3ktI94w68flJKR|1InG?b zBi5gJ)06|3tr-am>>rPh4-IVMb7z*$zvxkhw=T{#hkF}?G5-&1kTqx4)OV=2eChP` z#WNRO^r%fsOZ{VOOM5rQYa8Ra=FrBG#qr2Y?7~e`Q%kecOPhDjOz%2>@51)IyXK~+ zPMew8L;pHX|C*tHEzrN_>0eXl(7)&CUw!)5i2l{kzn1A=WBQk6E~EeK(ZAN?A6Mx= zhxD(6JRJVGLI1_f3jNpA+5B%#$x|56|K@DH={5_fbhnyJm78Z5O}&F=JY1a}^~Zg) z02a-1>JQBVIIwMIX4;r!ym)8@J9n$eIkmL!><-MCQ!@uE*!06V+4$sIv(#TbJe;2P z!OyCwShR0TE3tWIdg{!X>1{L9ZRm~)K(3H~^V96iwyx+l+M~=a)^b16gpRAy3S?6@ zP3>xW$D2vQSV10U>deZ#XI$e?Tcghbr%iQ(H&!p}udZ~Y?S@Aib-y?0KcUGMA1#Bf zO$f8>t_V}@ESZ`*i*^~*c)Xp5HOMu=D(FbJKS3o*&t0CpYbO+2(M!Fd8n;tgMV0 zbKStl*gm~?`@;5ZyD!+|V#s5ujWFeoDC-yYSIu$j;+dsAW-sTR#)IA!IJ&g7V{vD1 zb!A{S@T1N0rC~Z-r{}lN?c9CA+|0DuHkzd)&3Nf}Gg>#h*Q^-pwha=FK3lgK+& z_MP)P?a_xte1PD?0PpqrU-p2I|B>yQI>c2@ZJvT(z zjra?daWq?_#EL}`Y(GZ=YJRaw=ilr-*$82+N?}d zCvUpyeE;W<^^P=Kd+W`nse@*RZ1($2x+HJ1UjM%d?z{f~B)aYY;-G2P{JE7qi>>bS z!H0vTJ?7Bib~6t>&7G_Ybmp1%cpidp8;ype-R9K9>{k6Y zzxlMnu-%S}!`8zy>+0gLRTnZlSMg~0D|X74byl2M3A6=v0R19vO>HA?X-}=ptIsj9 zu>@v@mayE~0_Q4SI6zl$w$07Yd0WGBNQbhOk`85srbAX0N=t`CG3kJuellVwyx5En z_M6M{$%a46iH1MRNrpem35GwXlM8 znbno8qu%QB(Sj9=byynG0!v$3U};VZoLba^3Zv?*TQhd++ua-+(skj(L$z8oAZ^*9 z0ciyQWcdI{O9sQDOg&yGEpCZ^+f`CRTFQ%2{AOE;QbnpoQkr_1hOmY1-LY$F+X-`t zXly=KHD>RU_YeTGNC3zl0zmc<0BLz(SQMwnQE6tou9wC@t+XV9Z;ecyM5qAe(pX<9 zjmA-F?n{OB*6s6zbdWzT$|q<0;_E|w$_@oEsM z+b!XE9V{WvTC#0*5iP_Jr=j&gO%Qd0LW!-vQt^hrrR;fotacVf$w10NC ztt^G;$`qoDQ;4olA$f@kP*vtcEOgiKNUe8bSQjXUb#Y=?7bb@DqQsyoC>^!Mm^GPp zZ2M?<%$-K&YqCbl5^JQawnoarYh>y{jT3fMK;#S=b6|C5Jnk(YZB{y2RFKrXDoARk z6(lwH3X-yo1wqA6tO&-&bx2^@%>t(^EO5%V0;kL>aG65|Dz^n=1uv3~5o~}mlweyt z5p0Vuf^G3euvLEqS@$SKgHOpH*J;&6FMv@sSUFXLl~pxZc~yfmvubGWR)s}&kz3|0 z16(K)JO2c$S(IQka}um(OM;aRNuY`qkqRbo)rU>_iDO{3U`&~SF=YbAlnEHiOu$fX z0;HS?_H+E=(cVfkTHH9a&|ho#b}3~;8O)3*gP9d&Ff*eJ3OmY}G^EH0OLnYn%nnCY zGb93SkO(wDBCvFcfTAUU$`yntbY?KHx2vg-8D`zkRkaj=MWz5OF$G|ODFDh#hf#6K zxF~IQxVmcYJ!@9#1!@eIsWDir#$d@B1BGh{m9Hpl!s4#^jy|Mh-HMc~yOEN0LsGKl zNy=4iNkHt3JHwn`DQyD5;gqa9lah63QnKz$O4gi7xvDb>D4a1HR5Fx(_YrpsDFfYr zar{MM(c7A@PSsnKe_svaRsOLtSL$I(M(mgIl%8JC1s?$aVXJLfi zoSRiPk4KLe!Mh)KVIsA zA1`&mkK9-+; zIcE%%~0#zvyUGLs)yStPuuyWM`D;F-Xa_s^ul`o*811Y6VaJRkL zyN_#~&%m+~8CbR=1IuP)V9AaQD;gp>Vad#ng&Dd_YGYJ7ArS;LK@hNdLBO&F0qPaw zsL&J;70zyqM&=B~jPI*luE-!*CytcunsNwMn?s=B96>c_3@Y24#cZ1!UbebE9yPsV z7xq`iM+IDFWA7i4}yTkx?+ zLlcWMbg)RnRaT_Iax1dPxDqT}JJ>gSmENG6X(bqXR)V2rB^WwZf`MTr6!}$PgSP?2n2f{vl5tpEG7c(B zMp0RDSk$zycg&ow*Y>W0fOQE1Rwf8on;<}SVjR_%0;0m1(elws)8a6!Ee^xN;xMc# z4ug{7AgU*f+G6In%eFKQvz&bRvz&DJvz%=Bb2`cJM=?47*D$FI%}>GA@x)N> z?`m3t_Xo|K*MHAu=Az_Nvwx1=zi>FZblrT_V?HQtZ_JZ;Msz#<#v0m56;W9MeZnoG z((EcK8&E~l(yO3wqej*Y;-?^VGsvM`3=&a&ckvWO)J|x-K`v$ogDe>hGFLNp&dn|? zZmg{hN8{=-4shCCrvl^vl+baWmUn>m3?2=Khm# z^)&o!(`+R*+SbvPw$+3maCVB_mA0`{=iBGqmCn0Ri>!K4fn!HZ!}go|lIg%;9?gWd z+MIwZ62wSr#4&0_UU?otRht2#!fms&cDt(_#4`p~nK8QaW)c|#x3`P|wPpmWRw8-5 z{FCr{xd~FLHbF|oCP=B)1i_^yK%vq|#6tHq>uh%%12>}pNEZtrT`quh!2rrj28b$J zGqG&D#>{ONhx{|6q6uc}%T1sotNQpxC+1~V+fin< zCuLR}Q)Y8_%A~TWh(@2Hix>7rYlSl_0BL6cq%8rE_5wh;2>?;mYbKT*opEJ%SR9hn z2GnC_M;o^|QOqu6?nf!NGNk}UXQFHL*=K0>9_EU|LT_X)s+%Wu)^{XWp`GfMBlV$8 zQCmcKR=I<18I+SPg6L?pyf%~Uz5=&CutGc9El28Tn?gIpg`vRmP!ZWgM=pG7i^Q83)FdVPsvA7UsEc&iYSi`;dn~ zXcz*aRS1M8ArRPuFk}qigeCr$yK5Vj&%8MVt;iv0Lk>X;atM^4BdGL@k!AOno7Hu? zR_eZl2-i!qJ({u-Up=X}nfv)Mp!{ z(wE1}wNdm+U1nI+bd27*Gaj3ZlJLyQ>{%5BZBZ0-L{ZQTMFAfa zgDl7)QN8(<_v~P}e5rZ8!s9oZ)#ZLuasZOh1xP|CAPL=oBya?B$Q1-eXZS0S`N3f0 znEUynyH~~UFw(m$%B-!V8*6Jx@33f#+l|$}x5Z6&!euu1zDz3ji)i%UY;mdk$aaNj zw-usIR)~#~daDp^sY2iyMio^`R=(v~qSoxZQ1Eo+DMZ_)5N(%2v|S3(b}2;Lr4SpX zQnIou4-vJqgTDC%2s<`se)6^4tdq5c2Rm0_JMHu+T7k6<6<8Zmfpcprs4}U{w%BEE zb{LO_1HWaqnh^MorUkyEZ-MV{0eLr%RF3mEm?c@4U=6<>2}vry4|&uZg(xE+gwZ8R@V~Py0-1OIeeN|#UAOK zH?WQTJ6-cbL5Y$sl_=>>iIT3AsML)TBU~szY4rzIM}_+RS(gohI6Lch&d%GPi?+pU z=a8r6`T5TQ<-FQg6b(2FFz2ng6MoNede@VCSekt!qgq-eEL&S8EHk2nWvi=%2^&g~ zbfG}yCa7m*x7kq?l#D3~N){CbC9{eGY+Dg87+B)1m9yr8^|*0siN0`Gc)ql{D5RNP z6w=Ku3TbB-Me1i4UKrXzU>!A|lxEh~hs%BA>q>`BwVju4w)4`yJqUG3gu#}B6G5p z&)sYjSVy<5(#j9DP`I?KpPCyd#xap3``5Vsqf zdQ+c)aHxs~pWMtA%x}lxMf>pX&PXUv3Ne!E6d_lInW`ePs?~U2YYv3%AQ{L%pO{4? zMrCFBs9Ntp>ubhZJSR~}CJcSrIk$V>eQ#RmlOkj_#$!duiV>RESZYr>G93uu8IW zi3;OK8u{yr*(JjQB#ZvKQO;Z(l zh#f#>2u`dWfm~uqa7eIIiQR9cKBss$9N7*MKe!05^~lvHnQ$?L*B&M8oRF_x$v zP@sB1spt6xRn)JK?-oh~mm2ifn)&^aPREAU?O9z$MMstHs%~R_Tztseb?Ht{Ip|ad&d7C=t904Z$*!V)hQd&fIC0Vv=Dpnwa20v-TL zIRF@4zlM_P&Fdn}%K^kn*gxv`)NR1L7bwHPi!ux>DZ{{-GOP?LquQq;Ywa>890&W& zW%;Lp@Mmd3__HiF{8^S2{+t#N{wSvE|0*U0e!OUBO9OCXQQ?pHE^t(U0Wdw{(FD!k z!xY^$<7R~n)IUcumnZBa+XA4boCC_$98mt|KvqgVoR^f1CtHy5jXp`3Z*1mQww`qV ziM|i_=bj~67Trcm2ij<9M;o1b)5Z#;T43qgj=A}TQU6$Pa=NNFz+mUv-&cMn!d?m4NgjuH)gX^k!1snEcq3ay-~ zu-dOOoVaF8E%{)xhc5u!9*D5q{twJl;Dy(*`3`^G*MvZw()TlAda;;Z&TIn2;sfR@Rlam5Ec6*4SNX8$0hvecoMZ)R9tT*pUL9bi^$70_66G!s7}J zI#QuQM=G?9Ejm)6K}RYy*hVU}>PUsv9Vx@IBYTeT?ydHYG%It>N`IMtUf?zp^%2mY zjnovjLa{$G6R9b%gEa+qv8F&y)_CY;)g)NYl~#HW4c;--11Rmmr@Cn&PEo^GtIM{L(Eal5g=|CYF7k6dJx|3y;!UqTcA zYg=W0%Y`twn-FxSn-H|Ao6u$yJ?ka}4eTZaTT?foYHc@}?sF$y(sXkoQrwGGo8CmZ1`fncGiS9u63oZ=fr51*<0bv*~uP}_t41=&TKWdBFJzVegmuUkD-!AMQ zt_@LPRa6#PMPk`)+UT0I+>!h&0iU$APiH2}rzv42S zishVKh9+e-UQ%y?lUrk3ytXQGKX6hT#q7-SaQ1y!nUia<%*pjv=4?E__R5@GcV$j` zTjtXBR;GlvMa+6DPRsHoWYhUgw~9)KtEe=&ib|iWsI9H_a8C~khG%!Nh1nSYC!=J#bYKdn;*em`Ru%nsBYQT0BZ`z`=fxByVe0zkzIK$j_oL4oObTAJDAPz8(hz8dr2 z_{|nvBPLO?m_$`$5|xih?E~h3ArMTRF^;+CR)km0s*`KG_%Vr`!6b49lgJrNYG*J9 zoPl8KjIpkxGnhoqU=lflN#qPBwKJFl&Ok7AW@hCQ^Q$k~T+EMydWD^Zf{-5yLRKgU zxu76zfI>j+Ig^%cR*c_?Y?QZ=6hS4!DB)a}_dywg%FPg6YzBZ*C6O0u_LLjz9d-${ zOO;@$Xa%BP)1(wwGC+aY289*O$T@4t+*xz<9g{oVU)(j%2a){5s6L`fS; zRO&&A5e5{XQ2lw~$>wzNlO77=i}$DDCIW)&d|MzpUH`eI8mR?RCYI;qH@8B%%t90= zcMvd%f${m?RSOXYOhg#45n(o(FcM+FN`$EedEOGjl${9Dh5{1a4Ggiq%yhl_v#G+k(NwnZ@y_8808**DR0Y&lE+S z83CNg2;e|QfTfTTs^V;1S1N&|!dY{N;%MJ~zZ(*@g)vZ77z6c$F;GbuQ#FJUJ$pYC z=1oVDy@xI_ZLv?S-##4WdxNBsDy?d((yH1jt?IARnIly;_oxO(*UZ_dw`pg8HQXkY zTBQ)}k3zI53eip|Brjh9s^*-Cg>E(P&sg=P?rT<8nh|;gi#Z)Bk-F>>sjDxM+Jq9B zdr{()B?T}#vu$;ylP{Rlu3%1kf;sI7=5jwUrQCp6@Zvn$Xxw2Bzx;xac^XnKlp~4b zS1D2plogMX<&^^_Df^&#_VLhcJoX1e=q4{N9AThzgsJ|Yw}dd&evBytP%Lc$pn?gT z&*UH3Hf!UfTZbE~E9R_c9qkVboU)<7DIW@)GNQm`P86uz3XDZBHZQqXbnu00a4N7l zCv^Qep)1b`U2{(4)#l@>&I~A3IJ3I4cv)|4_GquKZapz8KdV;KZIw&9%>_xfIU?!0 zJCbd2O2DaWW+yS%zKv{#+Y)lB952}i8vhZ8+(Df71yR5efTdo{ukSg&c(i9uCAOUy zukKx&HTO=0FVXQv(;`6*wMfu{YLOt{S|r-S76EXxu1JkFzNgME4u)_~%&S6!$izxS zwa!WrJAm3Im>8IYxM;~1TL1aH@PmWR-l|4xb856+Ts2y+s~VkqRb!Q56}XFQyN1iX z!TzJ>eO)VPJ1s{S!b!Xo!bxlu!buz!!tQ1Z*#y3)y4V7^iKb}&NC-aIg2gU0+W4+{ zTDM`4XEIIhboV!1k#xdv8$(w zAnRZhX>J?ui0qLvK{q~nOAQl^(K2U`l>Nw>^$p?ooBKiE5@laz_-GDl0yW@rF>IS zv~M|*_{Ns*?wz2EB=Dz>e0dO1rL}@$iHeG`+9*{yh@@-RP+on9(i5aqcY=Uc^DGji zw1p%HE;j)RwMHT-^!#CeH4f-g^YfN60+g8%pvsH@MP`JmF&oz3!1(q$?Hl$$eY+4=D(`}GHXa5>T8XpJB{+2l}+AX|0|gbY*@M+PcL8>kRq zV9ullvbpF;3s#QAifcz=sCbYRl@Bm&0Dyo6no=gz4r+eeNtj~!2~(^+VTy$(Orh$8 zD3u(Mv|f4W)5maAZib+0GXxczA*j|2(WPbps8kYZq4`k{mZ~6Btb$Ov3PJ@dNSCY- zP;}13vbWg%y!*WA&SKnmPT;(O)fQXG!MWj`gD1Mz>WcXR2-6@M_U>!iE(*wa0qUsm09(&_HH z)bH*p;d*CT^xoeTx35PB@ct8;;EJ1lFPLbbz1R4!baZxPi#7SY_gBBrqlb4y*^+vyL%v>?c31x>OlnaVb#VaDKS&iqV=0K=0bYOpf(5$%M_iUM)8IAN0 zPSb`#T-Dwsdb*AIhE$?=#xslRQ_20R(!#u>&GMz&8}sALk-y_FKTB}7ArKmdK(%IQ zf(TSgrvw6fP&{M|;DjaSW~y;Be{5~gU+#~0FV4(_WmT}ICV&>z1kkFQ09sZP0PAWv zvarHOEBz5}c6iJ@XVbixptGl4mD=2{O6_u2rMA1PGWWf!PBoyTFm_@yU0ogy%*&iM z4vpLgTl(y#A5UmE_A;#&tlmS>v^HUE<3%)E>V(pZiyzjdHMxryd@lL=DY+ zcW-UY{J>9rHnUqQ;*e*E)9Y;W65{j?_mSyD|%mE5h0}x-X?U;XSK4mXl?-awKF?627@lXNUrRP zvPXeMe{xbAwB20Y%y-T9;zVs{Q&W{~tEtKk)>LIPYpRm3 zHBHgtil~d*lez4F`I27i_typWM0{-d3B(?K5Iu>TK6bYnCvZ>v;AXB_9v)j8HS6p2 z{sW&=R-ZFy{pAc=Z8?M7$QiwoaspJIA<;p9>1D^Lw|3NgW46#=YX<$*ru3_kaL+|S zpq=QHAzdyl0_{p0muj`@VtqV} zYl0tdeZxs-fO=ISLTTC|LItQ5X7ts{wj{@5ch}(T+Qz~DdjHU%F;59P)*Qo~<9i%5 zipnjZcG|M80*aP&0o7&{Kwt|d)86M>apk%+U+fmUhX5m!S|UrEiZC*&2y3f~C@`zU zrgnh~v*70BEtRXr>3JaL&@w`Kku`|Zt{@5+0|hbkvo+Kd@6-aa=# zNd$#Q(9!3Dj6vq)3|uBKj`R)3sm&M^o&||&@qBB8)*ue~f;eOf;Jceb8CvAa;HS52I*}LpYid%aAHa6rQ$zS3JjS7 zk|IL@rp*8lFhWzQ33!`=MifwFMgc{J6i{SJ0oBG7Kwu6gQ-i=(2Him%vIcR;7sMe` z5T_kM6tDwesTX!B(dh}_?&(jI(V^IH5CBH5v_wu%Kw2YrgtbYce>~7YN;$2oPbB9tSF$Q)4PdBr)PDx6s!_m9^K^gyvb4;0JuK(RUx6pHi1rP|zhD9t=e z!~A@a`eyG?GXLY!+1~QeP^JGpEgg=^tetK**3R7je6~y6ZmjaOb-w8dLAkcf=}Oex z^fDU#-@LSYV=(TU3t{xEO|uP!t2?Qih|-=TO1q6H8!Po0QQBcdsikY~P%hP2_d)py z0>KD$_U`vX1sg3=^)QW6uqKUCMXJ`NQPMS;l$*|_QgY2P4v}i@sj6?yTS)Pz_*tn4BOi+}vakpv_lmGKu80E9N^G#p zEA*O3Ca+v) zQbj8y*2{Y!Q)vHizgfAkbqOd?S6+>nmR0~uOF*U0jVQ!ZZeT82LT>qFwIv`KZA2+f z>Val-`I^Zq*MursA)#KscMUa{7eN_S)t6B_`NV`Ws=O$pnI&Z~ccw_D1}XPShm&BU zT{y^=QY`6+rjQw$(mrSgSfHR#y?b=dE_45Z`TxsD?dxg%C#&SlzXU1|N}yU8B~Uq0 z0y8s8SnfxGi^hnYs|8M(9PA&s49boX9=P$CX(b5M1(CLFPui%jQ?t$Gz2M^I#P7@{y5w z<1^T#T6ndLT6pC}3$L7M;WM9F=-jnBUhr_GIYACiYGp~*;%G_MVr)s);%`Y-wYem! zyIoKP)0h0ydlq-in}>#(CwhkGiKQDbqHK|El&vYMot%GKDWp>azM$h>`yMQ{c7i^tZ-n7g|xzxgEeznlKb9FrR z@W6UAH!@$ujOdpd3#0yUWbS^8KYU7-n~7P3)!MAVwzOpN)nFUBBaE8TGUwz-Uz>(* zM=>twMTt!tv3t1Q>o4>77UrjXy;bvAshPpRyqI!q{tJGOv1O@EgWA%jLEUN7peD6x zP_NoFHjivsn?`r8O#vF%BEfy6OF?VH(b&8^dB@tuLeIQ-rBg4}FRs%oE$ve@erw6XeMB=Z;c{ejqdCZFldx0glOR^1WS*0x4Yx0ec> zn^-}Wb7eN##mCdGc2!_)R|VE~RbaIIie1a?s>D@xmDy;QdAQ!9xtOr+#PVQc-5j77 zm;3AM!_hwT0Vf;{(lt}(wP|%;`&Q?*b#*>>uTCoitGM#eZ_DO61MVRy<`i+Cxeik^ zvL-6JSrZj4t%-`h)_^x1Kn;B1-F;zo+SIjwS)T>cQ%7HxR^1f{KS|t5M#z| zcl4gn*!OXdz%eKZl%X{8#Xbb#06%Tr=L+93Gg* z!J3y8`{I(bT)H1I1z@XE08AZ45G68rIzd&j{ApC?%f#gJ-pRCNW(o(!yINd!tY&@ zZPo;=3Xnxr0kWzpK$cYn+PW$ZEUfXVm1cF>O9H8hyM~v!jclj+Nvq#oB)f9kqjsS! z{6+|^0m-3YvWz!Eh??5T9Ms%SLfzy}GSKWUy0q!8aT|yFtETPr@J_lu0(Yjy_cD#P zoHC6ZF4M@?GOfKVv%tV2+{HEge5A5(#82W}jGvq(RQeL*cjvqNN6{y6(BNG>ys$q$ zx~F%nu=_5xC#oj#GpZ(8kx@0t%8aV+4oA%dJ_k|i_O9N>>hjT9+RkemIKYsf07C`> z3^@icZ4rQgCz?u4Fz+p*w->Vu9rkt=9GOzVkvSC{nN-2GSrr(VR;E+)%sKe%#!AmU zouPQ&u-O}75?O{xLEy~d#^`Wwx#{3cMpm53$ci%=S#c&Ki_TZfAU$fZy~QS}8BErtS$ zRzm^RmJ~qX3?@^9ym#ItyqRbU*`g`rh^CMkn$kXK23Vk=w0eKszMvVcHiOxt=KVU@ z00<%vAc$;$AaVkN+6;&RKM>bqNj&|RTMP&l&-^=~9gT@m<=&$(fllU7%x?A=GBqfi zw$yee3PNi|LC6jTp*5l)ZGl2S@i_y_uJ0*Ah=^57k65+%h*isvSjB({)hq~9G{N6d z)9pmQMr%uIw05ROYlCWZ?o*9bc2(dmuF)oF^QSwDa?rRN=*~~#U5uaZX6p0l?jJ>; zz(Ip|@i2Vqp2*3lnq(zL)g-P))g&u3s=7NIH52$8M5){Uz*4DljmuOsD3-PhxNz#U!!}lgKSh zBBL;=J;EHY2ZE_H_JsVv>X2?YY*uELm#Z&+tKi6^3XY7b;K;2Ct}Uy;z_&83&9j$M zC%MhIG55~f*KgRHlFQbWW21v2qRYl1y5t*Ti?#t6xW@Onj*9Qu^9Oo+Kdk2}PJwvP zBf(YN5nRz1L6sdzvD6EASrP7-Fp2!YB--9Ei9Erib_H|57YJs~_>DxpO$48)nvfMm z!KsR(;8;abaIT_&4pw;VWLXd${+MEXR^^!y!S+B=A8!yu+zf>>@1 zgp?nMN=?|dN)JViKA4v)_E-3at!PovYX!W-_YBaE}f~Ow(M`0ir z&BK=0dqs<%t3y+b0Tu`Y=%d-I$5wpi`6R)7BkW9W_VHeb(j- zB}CeW#Q6NW(Tn=k}w;DjMi3nvVrn>b+r(8kFkq>bEeeu{at(!+4uw7l7>gUnhr zvCP^dZ?x*1ZDJW(5}mW9r-fUVI>>bEJBUEL+f`|c>3k+^q~-zMYXkGe^08)hyt}_V z8XoJd&5TC9lMAEf&_;h?9+-1@i1)TPCJx$aZ%iE2ryCOoZNE1rj_%}*i2_=CBf=DW zy?4!=qK!}fC~a;J(c0nm5UtH^57FA!_7E*CZ4c1a&DIEMBg3ti;`QhBUW(+=De{E7 zMS>dDB0-I5k)TGjNVM@S0$_Aqks3RDv{}B?J|Ac|J+sh!hM8Y6J41TN>4>i8+v!Ma zTSds+RuQtdRfG&~6={oGCBWo1O=`2)kI~h@0llWuEZ)WOXk(e)ftnt0O1@7X1vO&w zD5x`&M?tNcJc{n!dmCN zu8$AZKhWN|NT``NE)weMjf;fZd*dSMjq}FE0S&)Vfy$jnhr5ZJ z-XTbPzdHnJZ*_+t?OpB=q^-dnLbUd_Jx1ErYzGcMER;SVbk(9JcGaTZb=9Jlb=B%l zbyb1}b(E%k;m2!SI2>JSo}f*i+_pF7F&gx_ZD=0DlRi;b9vM5xP&YcrP$N3XP!BrD zwEZ1K!1;DnYP!8)gnl$_UzI$!duHp#;lnMzp+z_{xiz{xBdp-a)C#W6tiZs;GVRRc z$K>-nk;C&ijVb0w{JYGzRPLw7>Xf^iC^NE~C|j%DM474GM8eu`5@~QJO(&bpDP7ZB z4?ngI-~H4x1eGm+QkAVgeDgC=u1QrBbv3IiY+4;>I6+@Srb!y>MIAf4-slH5v{k~I z3A>u)>D-+p&t#ej`qqjL`oF80x`8-Tc;eJ zb6w`2(BZLs&M~5zbr_2CHiZ=D9mn*%;~4b0IPYACW}@aDM3FY7(4z+Dnn6!Jm(Q)_ zWL(c5=`(+ozB~?kkf>EXB6+OIl$oe(%xujk`dq}@mmSar3q@Lw8?Xv6ponIEo=%=5o?4VN!9zwB@5K~3gj zrnzYLlXo2981%e9} z2rgG3d2e}Hr;~-HrXg&hi{^J3&Cow!lRrpq*t_q{mp6y|=66f{3Zm>h3lcC z7OsbmTDTrMYT?n~?(0jue1~qyV%e1)wP@U?XI7qYrPo* z>&+NgZ^poSGX~U~5vX2?hGQ*JjK- zgd}tulF)5PLbo9a-G-!%nYj%~;5Out+XxhHo6UXuXk&f6acpMg67zrQ>+bTY7eH+t z**>5aH7gmT&>f5ddoYOnfuu0V>=;1RHfdHhMxj9%g{udn&>)NggD{8;f}}9WJj;=O z;C235b7cOQdH7yo^=J$lqcLcT#-Je@17>Il8KEd)0=;tHeLOS2c`I0uL(qU6g5~EB zEIx-o={bT5&lpkm{!#zPk!G}{OV4)I2(**#0NROX2fK2_4j?qO95LHvArP30Fk~>` zgvoB@Etp3RrQ26#oT8w;ih|xM%Ero!RTOkpQE;s)3izoQWM&QtC-*hxl-+#(qgZfnSP|79E+Q^uh~WgJ*lhLLAQT9{{!1pFG`{xbir*FCMXU|k7@ z#+6`bTM34ym0)052}On#*xWAOD>mCsmJW#~OoEiGNsy8u2~x5lL2&U2P$)SPd78=4`g|k+1~AC0c@^WhEFc*Afg2E1}4*0xRq? z%e%W>B^cUOf}vd{7}`~Wfn6mO*;QbLU32Df!AF)Z?5*$Wt(!wa?=pKX)_;P2DXaUE zy{dr5RTa>^ssdVARRABWJTkK;5RRHfI@cWTZ4AclE?s{{mhC$MXDe&xY(3c?uo$nM zgFPt5%l3|d1AYSvxvVkaty$67TYZeqIk+;5@v<5L2Uj8BfER#5UTDmEL61i{;qD4w zysWo2TY57pfTRo6NZx`1Bd>PoX`&CM7EGjjX9Bfl#eTuG9bFNYuH;cd)2Y|RcH8ZP`W_mxOPa6 zYk%apc1MnDZ{)akMvmvc$Wi5r7>=GS_Kus+d1X)Jxb{SjYft33_C$_rPvp4vM2_d4 z$Wi5q7>=H#R?)4N+s*Hb{F#eCy3+mvb9RpHoUXMNFWre?F0UO^$^(c+FH(#44@*uU zO8bB)?E<3eeV6m9&t26I(!~h;F_WGTNIx+{OCSSu%^9G}%>Z3#2IOtdhE;uXJeFpE zkWeWt19WK_pi9dDU0Md@rDemaG&vqiGyAjIjnT-w0%6Bsc&In16j?-dxkXeLUPQG8 zMKm{~2r64jWHiW}PIon^h-!n1s5YpGYJ-YsZcq_a29-!*kXtn9ITp03UeZ_FdtVHW86wDj~DV!C{YPP@Hu_Z%B{1Wh_xInF9dciwDQiqe%MN|%nPyzPil#RDk1M|-+t z%Eeu^WOU`FIO&4djILTUdCi(o6)PmxONXqamiiGHfV%Q(#I*bZs68lvxe*0Sxq-Q8 zi8*sI|BtRl`Hd^xmeWyPd^)NZdOE7hOh@zD(lJ#~G8n5ctK9s(R7Elb>HH zmIqN>DMWPxXIJJ)d=V9M3JNV%F9DOd9% z<;q^9RK<$~i(c6CO83#zRf`U6nA2WhPJ4kl?FHs?FEFLNfLQcmpLqtraMa8U2JXA} zut!P1Z$gxvcN=AAoqqFHj@3qKN6WF&LmHxTHxZ+}1dwvlEi30HT2?Mf4(fGP0E;%@ zh`@;)ESQmFB|kE*#gfVf2MZ2-M}q?2(Wk)c4Y59-POgRM-OTfN^w8|rx0+vjJCD(N z$_edLPH1OxLVJ-DdG-0Ysy72{g^L&S1?t(O{WVj1`qA3&SP)@nS0n7~{0^lYqee)V z$}#)~hKST9G%j2MfN*J7e`RKMWzIZKw_;QdL9cQM+Lc2#Qs!6=LDO#xY6~NIdj~uNDgrf^bPp+FQ>jNX`VrLnL zUY2oaWEqDpmT_QV8AkpUXkpC0^PaYC_N zv=fS@l@p5Pf}T)pGv6q?L?8oQ&B8WW(T^C#m-C~AnKI|R^Q-IQ zo_V~@^z5R!er~=U9Inoe`eWL~FPbKqTZE^l7iVU+%^ci3eNpVljZpeIPcEHWUz%N? zp4vP$*@U;42~VGWaLe?}rm3l=trP31;OTQV8}XU5GaKWf@`cuEYDz2TEocMHbRUXS zp1XCLirIH|efZ3&nS+>^ei-Y|!lQO@OKouT%=FZmGt=8>m!S4$N)Z zejnIB@dj7BJLB;<~%*g$5%1&otcKcE+YI^$OnW>oz&t9^F z<~1|pjrHlYp%bdS#goaBx!KuHGOt#Jo>QB|%_sV_?L=WlWZl7~xqb5ox9wZnfAPY$ f>1o=iZ230Lq}r*arR_IvPs@ACi)St}2Z;X*_)HPy literal 893264 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

jlrnt_Hj_}#*HtK@s#F+ zRt2On_#r5Xm%1{c9s~6}ZsU3f(l3)Wp{S~c*=?zU5HGr@fhb^vq6Q+tXhIQh<8tHM zB7C`lpm-#m^q<}e9EGZcoA4%tkqV;ScneZihp{qTe}s0-3RxYtt^$Py2YUOq!W={& zqtV{3o59W)Ws5y%7hEuEeL4Rs89p}CV;eot;DqVp_}TD>S@0?9AE2gmjNRrcIMKNO z1cw#bG|pr%Fvk2P>UQ>xjG6p5by)#!n;EKUuXlUv){@Q!TU{92DT zr5pfLls;`%!FDbgg<$Z2l{eaHg-`Yx8glqlRkcrbFCTm}Mgi7v7Oz=#F9)aYijLmx z)Au~@-~A(epk(g3rft$9a#aMdN!`RzOA+z;wbxbeA}6)`3RWpnO|nW|GD$Vz$GBw~ z{TQY$##1IGTR=%WNUekT=0F{f+ow_cCKCo~-=xK%$%gpSHfss-8Bj7@r}j;T|K9>7 zA;?rHzEplRVD)KaP!cZG_DIY0gy}XH7^bRZCq}Aw+P>=3a#odM{A3JdyH23 z$RZe2D2;_ZDl`F-&@@dHiVzYH2-|KJw|E4(*wZ6)NG`%R*!lf zZm7%cr)TzL3{DOn%|XmBw6P{HG!3nc-DFW51dQ>Ee|H0)Y=gBJHCn=$24_#uiMN}w zEBRZmv+ZY3yhqNSXp*xhj%El(ORANj;v*w9K5V9(4)a1C&c6QgA#ruUYdUScX*Sap|L>p+!;pm zn1+_>x3ARIcHdH}ztOBFZ>O}ET=gsT@q#_Gs0NyYh8!vjia#NTqtRwX>eF{22C_uz z)ZYc<8&R_oJw=|VI@HkzZ(9O$3dZ<+7#ywPkg*1v%l&((6tVpQt$LZNEiy0g@7_ZJ z^M9nJE^3HS8}8Z7eb>}gX8pTPjU%u>g3h6Uy0^*v&-i3IdZ_58?xKyNxf5)) zFpDZxn0KQcs<`@fn$70kSC|`MnTB#9iI&qO% zV%LL`iqZf|DoUg2OY;R$=MA8wqHG2wYESb8@y&n|ewTwf6Sq$r#q&z2p=?Hz5Fa*u zX%SRH{0Ase_OFAIszr^Rg!rN9yBGqH*p`Em{&XX#2Y|rr1eC=42~bkC{sWX$EgI=d z)w&;)#D-wD<&&&gjfA3Vbh%WcXBTMC!o>8u&LgxZ>npV*KQ!;fiYMnh=$n{Di|k|y z;x%@)!fx1guvPt4qtSaJ+vC5boEyF3^T4BW9yrcvvYiLM!cYR}$K2aKgXA2nmTxKO zyM-UoHw5MLM*X2?jns-^H=Z1kFnooxJJxnd?I8cf>lx9f$e-F6D_jF>dEc zl`+ljnxx^w4%~8f?=D1*(`E54#R`IdzJUJI^+7YaLQ!&WkmT~wm^dC2_QFL-_M#P) z{~vGf0VYMUzv0fX3zC;CU|N!ZAd*xNQC1dQBqtLnIZ6^11Oy~1xMIYd5JW&l5Jd$O zN>)L@fLT!thygRA!hOH0>aHmk&;Oj~KKJ&sTW?ME@2gzZJ>5OkEV1!XSHA4r%vG6a zs%m7``<`k--rqRWJo;ZBW>HVm;dw9#Tf(9+8y0}A++rYQr1+W^_ znckC7Pw&1C+dFoEZ}V9{SxbX@9UIw3nm%}-*7rYkshIhd}unX+#!u!FkeC`i>zyVO@8wh8> zL2v;a4F7;bU{|Q~+ImnAh8_=xLDkQ2*c^_4li^4>2#$iPpDW?ra5PlD#z57Nu1vfL z$HEnG9GnkzjpKSa9-ay(z+0i_ybkbccnzEcYeUT!JKz-f7rX{GhEw5QI1Q>?)8QR( z22{Pxgtx(2FbiG_KZ4i6Zg4hKKK1-xUwAz{2j;=f@CK;%n+r!morgaG^*rB~@Mic8 zyaoOabpbRF-UfTac`p2RSe?&zzz^Y_Q2Ei5ayP=e;g9ehmo3!&=yVfYeU1T|hBf$zb^Q0=$`Hi1jwZuls?1U?2&f{(*9 z;WD@uJ^_z~%i&D80*-@E!WM8PR6l(Rs$V<}FNLe1?4E&2=UEs29K3jZEy&D6BdTsp~k@usByFtR)cTBL-1{w4&Q-~!FQqNgBiIst40pj#pz`x6EDk?|z2Rg5Nh{QL-2fBWGp@F%Et{u!#j{sOb% zudpio4eo@$JN^N0=ko!m^!|jZzk{$R{0l1mzu|B2AEadZq^0(Fxu0~UemZ$+W%UqAWPJYF0wge9QrUpLQwfEjQa zECs)YrQuXq2DXJ|q1rV20}sPCumCjIdSP2WtGw-?=9%{9Gv7w)v$jT+={QxjaBa1sIMoZ_)KHjR+g3Yj zX$_9rkKmm0Hcp+jICbB|IrUhadZ*)@HUOvojW`X;;xwFz)93@7#s_gu--C0;0-Q5P z;53v2ZEf-~lBoZL}3V}HUKR~zRl zML)hI&V>WQ00FV>iF{*Tm&D7swaJwzX?78 z>p*?S)aMoOEBGYb2UkMPt53lb;nPs{y$b3)?ir}|cou4$>Kke`xEd~lTq`i=kI%!M ze0~950AGZfM_+;}pT5s(zF794g0N;cg;frt+)bV^XRJ(0~ zs+ZT`IQTl0{tfsk-0H&hE%|glzX>(pY=^JH9k4On3Dur&LAC$eus3`MwuZV#w-N4w z7s2J##oMy8=BOZggxcxiKgs;FV@Hbc$s$Qx=oexxp%5M#*etj}LAJ&A& z!dg)Mt2QhE^&9szsC#fpSQl!Xp6Wi=hxPf~08WRxgDks7Q2nMcR6M#^tNmxV{raV` z?3zHu*A%MX=mDj3VKX=so(-RXTG6^0JO}Fh@?7`~Yys=SEU0=t4<3RoVP%*NrE3K{ zLA@?#AUq$+E(fY#w}HpO3*dIx7HXbo2h|Skp~~3-UIIJ91F#d+`0ET+jxKNs>05jg4aS_X)6RTf$zghVJX-Hu7Ew^SMV~ZcDx*_Klg%;rZF z)fZ~~^n*iSf7lxifa*5`;gfI>oDBy9>O~l zj)H23D`6HK4R^sYQ0;OsQG0YR6R_GU&0ws{dOkY2WP=L@LKpCybkJkG8-yibD;YF_3$K^2S>si zp!(ljxEtOGKZknkQ1i&mQ02J=mV&p!Rq!@=9-IgJ!Q0_W@DA7>-U*AryI^5>HyjP` zfv>=Oq59Q*@OgMYRDXWJ@j=*{&+}mw_z+b6EPxun3*krbVK@sef@i=-;O}rToCBA@ zQ{Yl~KYSFbKRgC!z{jEb`!cA0`~&2TN;0v~~|LD|0!70(;+6Sx(sUbn%8@J+ZHZii~m9Z>y$CtL>K zg2Un4a2$LG_JZ$1)%Px_`S3k>JbWLjzkL9U!Vlru@FS>s>0{UyegaFvPvP6}Gk6=^ z4K+SLhs)s?Q1!kC>bU$RRR8%3J^;Uls;_V0G`JV)eC1m>5AK62;CC<+eh>G{JbVdOfOo)Sq1v$`RR697 zyTi(G06Y$AoE#5T{uAI1cp_9fC&6!Fru$q4cIIv^mCeC`Z2ezb&|?DRaG#!WY>I0CkWBVm6y3T}W`Le=+Z zcnur_YeL;)y8@1dli)b0dE_dne2#bfCqR``cj8oUS3`}{Nw7H79mWsf6gUoE1K)*H z;UYKg?Cntf?+!Q<-U&6H?t-eXyWuu?59|Z)g(}y5 zQ2qCQco%#Cz6l?MW8r+b2|ffnzywE1>%SlTh>0N+|tPunK${s-9Ls%^T0aJoqeBde6aA z;cBS-uYu3N=b`%L3vdN|5o(@$$%VfR)j!t467UtM^1KQ!gzMnra6P;XZh&{gjj$iw z1k1wB@B+96D*vy+6XEOdC-??z1h+!f!#1dS<4u?aw?ozc4ygLt37>;+LDkdS@OJnP zTm|2Sihmc}2j7FTe;@9GA3)W|hfw|UBUlE03^iUqf$Be>!u9Yo$K9|UpFfB9!!O_= zxCg3VeF;ayub|rNYd9T#122Vpq2{G;;cajq)cE=io&&#!o#78q)!m3d7b~UJcREKq84LA;-3|0P`@E=$U4uG|x z+V>RL2iAcbU|l#8o(f-q_24t`G^qBi4>fKZK=rSNQ1LW^55dOpL3lb;yPW~oz%!xx zRTHTG+7x~Z&w?87&7ksmHvAYihrhyeU<-IIoC;e&_2Vo!1D*#po?F7xU^c7fd*be5v_E7on09F4TVSA{@hIhlxQ1eR{_$llPC%|s- zb=V#L2rq=n$3;-(xfrS+TmlQgOJN%90h6#NOu)2y zZvQy9|0>7vQ1MNGZ^DUCCenz?)z(crz>yZ-MjR zt*|e=4Qd?BgPHJlsPS|M)VR45z6|ez8SrkX`Q{#|4ID3sk}uqu4qg)f8G@%ah3 z9WIAz-xW~p_9XlTu7pbODX8*44O_rfa4LKTs$QRkL*R3;I$RBPp0ozmg3rVA;R|pK zd=YA#yaXSCFGG!swQvx81vZ7RLgjlM+zZ#k;&21hyt5Ii{k1CNY`7WLhg+cf&1-NW zd>yL3-+=0mTj3VC4Za88bleUX@OcOP6YhlSM{hyRKX1dc;5+aP_%2la?}94Vd+-DJ zKGgjA0sJ0*2$lXvuqFH$s-JuU55Q01*YGo_{KYRgI{yk9b^d(e1e+5gz zui;ww4V(b?!sp<(Q03SM74LUYVyHhd)B~*ZuH*_!Ha%e})=Yzd-4Jg&McN z!6oo_sCnxTsCGL5-+_NZ_3MMMH2e#ye*T84?|-1qPY%Ju@Gw-pCkokeB;gBuE&$VE z8oUCgL-q55ur(|MRo-J@MOYYWoE3p8S5f#6PX1;05oh*6oH@VXTt5IOZ!69X$KuR=0q4f*I5(x^+}s)GmTEY+avX1YTLYYVJ8*9A zhjYh5oICHpx$7OAySw4s(+B6?Oq~19$GKmM2Nd?;%Q*Aj#ChmroCUw(EIfeou%cgd z8O|fu;Vj;Rv*Zh$rO)F$x*O-QIyjHl$5}QD=ZRj^nwI2>1m5NE;jFkD=gA5oM*S=Ja-SyY87tH*ErA5!Fk~aoEJa9dFd0JmkZ*oeIMr)o8^%*!DX5wt@g|q2PoXsn7wv5GjZ5Yn$V{qPBg|qcfoNZlj-b};Uo`bWaA*@yFP3!Gh*aNfHS=Y1vgftu^XES!&a;e4!`{bVi9r#o>zQ=RNCfb+Sc z|00RAN44=~GFK}OpI(Hsg$bn+V}Dt_zZw^)IVL9bK=6%)&B3uZ2U|^2ec*K1*ByNO zK@INyumBw3_78OX2Z^)!QVrQX1n8W8D7+nB0X4S_gBp{=;YV-;)G=oy)EFHFH5Xk8 zo5IoXFE|Ej4#1aE|sVGlS3o&v9d zYv5FPCY%O`!0GUGI0LF2GvQ5e7Su81TBy10I;d)!4K-KJftus5hniFJpyrqxpmcMg z%6%i$TyqoL0dI!m;4Sc6cq_af-Ucs(^Puv7JCyDYcq+UTwuN`W{qSz6bC-Ld=AL_D z2Y4UU+F^o&G<+6T zh0npxa5Y>G*SPTKp^gnNz*pdl@G|%kRK2|nZ-#5(HSiUvc6}9I0@p#+-+K5M+yL)~ z8==a-2`+`3p@zp6xC_1pPlT_-Ht-Fo`rith!ELZTd=siZw!=ek2YeOogyZ2`Q0cx6 zUxx3%AK|-D<6;+l0=@@zEO;NP{2#!=@I&}M{0KIMAHy%)m;Lwt%X&EI1#Y2k(Y0p>m%Me}%2!Rj@VG z>~lW+1?Irsunp8vYzv3McCZs{50y>__$=%Q%fU`i`p!_T(gl{t&SUxawuN)% z&a2*=UP^FRf;+=*P}%7Ym%s~Q9=r(7gcn0K!X>Z@ycB)_d%&KsC%hb92Gz+fhnie_ z!P>AloB;d4j<7FO_4R|zF5DtffpgP@PsA3F(niPk^G7}JuLu9prYq|9m-^PnDO*BU z&C?Q9oXJzftc{M6@HW<0oG@JjPfN&3aYx(H;+=2f<)&QWTsc3hQ zBv*!cbfEvzKKp;PFZVy%?@>nnhy3UzXWo83LjX$ zU}p8HPFE|N$lMPX&CeD~*x#Dvy|;I!nSI(-AFNjhBbiUbWXq54{) z&*EXtViYk+U@4QatipIJYQLUmwR(wYyf>UqL+>lbH5b(PXiyWBL6&HLTyq>hT`)Q`~p-V|IOt z`hrB5b6MlsWy zv>tjPSD|kGJH6LO4VA|WQ~bN0qFrc2*;@)qJ@!@8 zC|2OpP2Kc_9=)=Pweem(_GA@$kg1kY=usry9!^huiO(wZc#z$z2YIYQkLJ`i3O!t- z8_ntFXRubG2VU&nYw+3J=i$?XH0g<_acv!}jlj@Kj8=?UFfw_&4zws-c4_YTL`+}Mr7r`z=DiEHrL+R&vOyH^)6)*Cy0&9yaT zzDOE{zN%F-d-bKMh{>tG&e$-0m8fd=>ZHDk@#%crjwn7RCh#fRbZgw6&{?K+=&AS6A}g3q><@dUrX{xohq>r?CLAq86RD8Il~wll*QRg5iT-W0CI z&StF7yj&xJgX_-R@7xL{tnpAkdUZuR))#M~bq!h4F5g?=c%cQdiUVg%y6{lXTwcJw zCAZkX8O?g;7MwdcxvxN@?^%%O_O&@_ub6X?oU~Wl&F!Bk!1+&fpfHD^HoV!wt`zr; zax!b}__`cnqD2kOo@jxo@nu;2FbD~jIc%3lX7vmA`fe#V{|1xG*Ht6#$!6f*iO)_a z%kVvIhSCf8>YKg#9mskU_I~X93ZHKb`Jzovf7qd9eQFFn;Xz|$7focZFPu1=x1F5X zjbHJzG8n()?;X9;<<*=#UIr5VOy4Yy$1Bq}+p5t*wI!Bx8p|Se>(od++=}|Vvw;^c zZHem7uPke9N|Cs-k#1%Hdkk$#n4R@n=Ozm^ zEI`NL#V6ghhS`kosO$H6fneTedEYiV?DC|wHCs_Z(V`6bR-(z6c{01r!VDR+jx&}m z?TR!-wIWT%tYZj^SK}~Wqtp=k8npxJELdxQ=x0GwTg}bll=F2ya{|d%vQ3;1liT6VMw5XDY^{yn!+^l4lCk_6XII)hDVy-j;ZvZ%;vo!Uhb zv+#s{M}~5?dVb12voMdA8?m`Qj$O7no8fza|8(zuPLB>cB}@pDOrR z6PB!8G*OxLf-AF_OJ&yosLc8wl^a%AYbU$B5A@x#8$W^7d-9qv$hMn&@&&2_>vC4+ zRSiuNW6P!tFzn5YW-o;qZ)Fm*y|*zw+wbt0_Zy1Zj*ByBeac`Jo57UntCUtTs%X|> zWEGX1ygwWLZf3C@EvWK|8;YzAG=T;6a{EThc9|DQ=n!~zk+~h1`F2HP)=b^4&2_wZ z-4%|4RW+U1w^Zcv9`*9dpKBc*_QoC;&vC0SVwa7LJEgbr!7r&ewxTzipJKLeq_^S7 z8!d`z>T6$DRdx$AqrFLGzsuCvBCc@FXswzOGWOh*3eP)aGoX_dH(P0Sq-b$4yCM#~ zXBd|}Xb!U|*vlH3``)aMYn!7zK6_y8hp!|Xsu&~^=7wX(4skIznLHSt-yM)6(*iLQK# zw(8`@PFU8bj&q6$OO`2|DATPduWK!mDAUlc@|DTns{9`@Slyame>U3EChw;QqmHZ#_afR(y!NQkhmE$dT3~zC$j_Wex*RgNQWm&l6#cHx z+rClyte34yd(L=w(Is8z>kOQ-Q3>5iHSeXq;)tMjEYG#pXk86+(!#Q3u0oe+PgI-p z`M@i!q6$@Ix6j+)>eN)VR`uUXKuXPyvMc1}Jzae&_6&$lcD3MB`D82jEPQriy&(4W z#%C*Cdu*2+7yG8hzB#e)OMLp8sYc+=SW1V@F%6+`>r>;jHevRqRi$`oRR%Au;^kGh z+Lu-x*+87X^;YB9&iY<_1zYvLR`I5GRo87A;;~B>8YTRyAetKdiKKs4?#&|Ct-VZLP2hah1WiVtlPEHLB(40ep34mHd7K#*E1t(|wFy7Wb(3|Grn;t@eA5bQqa>?_ty{)KT=! zI_ec``OKBbxL26@f}Kr}tHCQ_JGLI$77;oSxW#t7}Nnig8x{6(FkLWshz_4Mh z#t-N>Hg`b&uE61L&K+|7uEj_rISK9wVK><~69B zqNeN3qS)@35H(#3H5~^G-I<%QzJBTiuWt?Z=-U#Xtz2CQu~mN|K06q7)4}f5sccjJ z)49UQZ#hlXPr+vga9;zKi*coxj@G&16l8~Tw|6>>{4n}YPIK| z*|p9iub0)V&Y;Wt)(wzZzmF}Ga&drJ+1^j>P*E4*3V)-lXl2#B4wB=h_mz$@tE9%K2q(CMzl$!ujhZp@0%N%C@OHb>CauP~ZG1trDyiA? zsD`oce0(}@N;hu;wm!9xZBu_9r7stD`t|2gx5i<212%l~H$MM;=eMEyWD+bMN zYmF~rEX|wOl^)WzBCD2~X6H-wr~lR9Tb*NHG0HXEvH8x@^rnrtxpHshq`)VcbNKVJ z6w5YHwb<7JpKXk`_-rL#gwIy;<@jtR4~X~byP+;#rJFak-EJ!RT0YxK*2%Zsizl&E zj@#~tE7|%~$+y}{F6x&|4J+3Ut<3IbA@gb9O+~_>THB6SH=Fqchl?-SdW)&)zPfC# z(<~;FeeLr04V+U+=e+;n$&JEk47sMdl>dLc{Zb46MGf@d*e_49w=LFg&co*P=D%pU zK6+KBcb=61_5Ol6XUqGG zixs?rLH69dp0BLt{T96%Lf4d7{ale4r-^(m;eqBwL-+gHUxc4s$zOamrk z)*Z6tB@ylB&d4M{>uMixubRr+!5Z6U*c->bf+u&dyJqEId}S{`aR)ww~D_%1`hc8p}l{+3*TLRnVxsK_d4saKf zQl1yM&wj0+wtgy#Ebjkbwoa$U=kTAN$idx7b)@q$#c0CNvDxk&h_4m@>AV<`Uu7A) z@%Ze7p_$+Ay$PRHsP1&+u%}sX7=?0b70ctjFXOWc&HSzTPfvV+t0$_{6JOx7itppS z)oFhne|R?rKC9@2&mMa&$7l00Ikvky4%6BWHdiC?*;pQq!#=?GB(}V@2j8W}r&TyN zn!ITJOzSJnh}LR1-0s0=Z~U~zXSE&i*}RO3eG_8e^w@U=KK=GR+Vl*+J%U+ZVRk%d z!m2ov*Bl8mJ0ZxTEc8@je#E zt2kf$KjPI>{AtEYaYx(H;(gM_tEUtDmoxc|;#MvB8n8Ylk%WyqH5ZEiXmMLh^P?__w%ieWY6cTin*t#J#?Pj7Bh$O3e_a<=vKwW$ZQo6cy=V3BGm7^Hj%nn=%)NgX zs8Q=& z-{b!?u7=I&v6czCQzjY9$@?Xm$jv#yf4=I~Jv#dTr{@y+4rQZqNB-lFygZh2)|Jlf zLj871EvyIFc-XKTFCyCV4WGG9p34nO?&z4u0^Nbnyb`GscSX5x{3a(awfN`I#Hoxe zhu((7eSr^iyB_(bHNEU8w>b}uwJaI+r#*_njGN7vz7e%eTKXsEg6mW*`1NR$k@J3Q#Prg`aCSrhY>r*jM7G1_7X1<^HVHS zJoT%Jx|NoxA$BuW6ZLJk#6Kat(TWor&Y^$I$@_HHmW)~NB47ROdHxrGGp{2=Cvv0p z>JL3HHW0-q)5jHTeFK{jmfOn&*lwjKBswlBmD@Ht*TKM@6mfdPiCU4lZG+RW+{^7l zpmQ(ckpcVIg@2G@-QMxa?OHutz(9*906tu-5PL>xQ(irahIV6cY^k|9<83elRZAU3 zb-;<$f4D&Y-%J%xL{Yh^;y+C*(~q#t{P$@kV`dk=dmm*!$(Y%c9aO$~Oqpqe$3;zn za_!duUboV&dUo`#Q9CPa!@L&%E%?tiH>+)BL=#QMOjT4g+2o|fkBI6k1}`gPr{)}! zD2|zQj+RU?`DD!0P6hVy%b2%v>Tt>H^_(3Ca}K{|JF6~=MGtz!=f6k1Xwp^b z5zm3-V{}~Vlb|b&h|E|eFkI^VRm+U z37ip6tMC46>%tbxzYxB7Nu=Ud%KwR_LScN}`o-0}Tma-b(R z?Chy$MeN@G_^jdzeEOE0p3w6ndccvd|M;w8X1rGquUf^O`0SiHAD^9}m*TSuJ;rMH zzJ|}v(E1Wu*`%R|O>GWz8N${^Z+v#|n0W6!_-w9L#daUYVOm3fBypxEiZTD)%BOUb z4?Cx45@vn%@Y%ey#AoaILVR|1KNsIf{-aI50<^Qc^%Z8vJ`+~OnS4r`+6YW|8|%}V z_8-PtR*E~?ju!7vHeTk}!u`7&!zga0>SMG%9Yt*1GL0{hpM0eyf zW)0(W>d`58fQ~qQ<0DfxPea;g!xV0P1DkRaX>3s+V0>IE z$wRN6n^l%mL z5MVCl)QSXH*N=0h%QSPyN1S}qNXPLYGbOz!KF!j^P)kp;rbP4m*w%3rXU9=+L~tdD z<*o$${*MSuEcQu)I7jhZAJ6_w`X&6i#m0R#;*^Ta&6#39@F3Q{607IOB~ioPU|z

=wXvNrvpH=ak{HLAoza}A>y`JTI87hTm+AJfKOw`|HwOFv*772BS7G0k zOKh$Af^bnHi!bP{ILU9zX~byrC19jE>F-Ed1NfrQGSQB`7aD(mle*ITzx5ZI++D$! zh!N;h^Cx|G(om^vIR>!59VOLI2~sUPpdOALzXf)=IUl>DTjY$1w zEA_}Of9(155ZTtFw7ML^tjZ&Le2p^qSUFZTa=%402PrMQ>*wo?Ss&ZaI{b0^%I!`! z6WLSh?Zl>;s*?$Am-m@D(O#@H;@`$)%$%yvZa(HAh)i>S9R+B%%*iVo9c~WVuT{~N zV;>FA9Wv+E&zZ5Va89%LM!&I-&)p_7Uq$aX<`|;=&E6YZB}G-9Yxs@6-&Zmx@0}D= zywSwC)q3O$c<5#F+=#Xs zz7?h(0*-E)a#YYg(TmN)utZUoa@r}UI=<=rr`v1RW-{x>XM3%9aJ*N;TtClGPt3+= zuNv!`x4mktu3`@XU*fxy|MbLPahM*%w^L%N*q4dVPJ|8c*~7y5`0N3v3qE^l))Sx2 zi_V&D8dLGv!^}M+6G{RDUS zwMFqOF00bHwe{(&*v5Y%@hgpJJ6il%alRF22WR?k`EGBlWu>^I?P&386$$dKXWZ8p zHTjL=Rtc;k%)N~}H5ZEiXmMN1D!M64ofQ0^>O^rywfArF+uBPi{{F=hMY|Llb+qft znkfrwrsUg#|K-+CyhZfeMjyJd%n)uKO?Zcx@OZPkPOoR|P3G3%F_VmE3+NT2_BFNU z#mU!X9p)MJR|{n2t<7on%IHu01T^D7a_m(ZYrZTt`pW3qRC5(T(`a}f&fkMOKf3?M zoEGKi!`xc_1=2c;%{vfHJe&5NoH9x5tH9KltEX;CNf13j%LQ33wsIv`&%`uIdAi~x zGGoWf75MDfoq?|(Js~|YH}>6!&(0J}@M*1-^u&|+?D$)YZ>l-T(#fbDu^-{HG5>_m zUMs+p&kKl?s+IJZ@FEaSkyufOa!Q5ss;rz+^_CVQchJ-%bat;!3^IkxZ! zNJ?LD4bCoe)L^Hsbl5hjiEldp_C>F@JzMeFwqj>|wiR`6)hh5LX325e__+Air{Z5_ zi_da_8U2q*Wbng}jE2QV{r}ctSCagHYO(2YmaR`&o@TRb9>xkE$Z64Un`y{iIslt@czNQ7Ix(f#}6_OW4% z8fc6KH?n1e_HZ|C{t0e;S8rTHYVg| zLev^QM5`0%@aRKcAw>1$L%t*=GY(0uAH|iH)In9-hMJl~v`FzaT zgwzj0`V-P52)T}s7D32ugyaMvj}X!+2w6$U#X-nALV5=w?+`LL2>FGOQ9+1q_>T`l zY7jCt2x&^l>>xxB0^A&g3?$^PAS92F`9X-5$zKwLEG1+`5VD4l=YkNeq_8#!(K70r zgODEy*&c)(Cgi;!qyioJvmm4{A>RZc=Ml0$2x&*ifgq$8AsV*6m9HX1m#=)tO@!zG z0}h*TF1>pyB#96~)L8eua&2+>kuQ-hE`gv<^?t|p`~YBMJ& zn#6sC+#J|!BV>LM@)03AZS<-i2q_hW9LG-G2DRm?XMUTn_&E^qpO(xvetyW>@}al= zT-QZWvK2{WGCQTJiV~WZENk|%Am;YLDRbRGrz)CHRm`Y*J5|FwCYPKT z{mLP$z3Nq`GB!bNWEhpk1H&sZrsa6fLX-HkedJUb`EsZh@;N-5abw+#IEOzum9YtO zSlXy6Dr&a-?|k`BuPUMDWivL$cZv(q2U};&f{@fUErU&3aw)FzzHwsqPrel0ovKW} zQm7C3Qmp!*vv=b(d2an?${oHr0(epVkM34_xh4 zFFBR53DT-yR5msi|C~Csk5}z+Dq|C*b!?DU|LW!HcvVpiQZ{1~q@{N8{bx_fmA`mZ zJ*P4@LI0^_RJ{}>+o)GBJ;T?0SEs6!ujX}r;%j5XuG8+S6xaL^r!qD{4t0yp*Zji6 z2Y&FX*-m9_g4#GfNbBztH%;}b#ZF~xg0ys-&z>h}T-4cj_kCWq(W#70kk*MoS{=(T zzsRe;bSh&Lq@}M~X-T&`QTpj#*LYO{O>%6;CaC#LLer96annjB*r>sMOgsrv=iD!4 z#;#`KiRRwgr{6)Llg@U8i>Df@aK^4~RB~l|=*?tGNhdp1b*oAlaW#x8D(U0H&Yo;m zP$iU6>r}=jDCx;Y6}82VrW-Q6>K>;uHYT2BE<_)~lGZfwM0sBE<8e3ml5TXWn)&iv z%cxTGTr+N+cb&@E1bMD)RH=FPs_&i3*aU5Hic!_WRjpROvFJ3P!-6_UvYnDIhjj?` zBe(ykzrQ;r&S6!jGB!aD>l#&*!&{aQeZZ?)JC(6fqKPY9i2Px#o=QlX*0?v@f;#iI z_&iT`s#9&AQ+l1sn3mK<%XI$BJ@_6It;($JCa0>GucW83*O&D8!pQ~o;*u_MDq|Cr zw7ya4=%5tFj4L?at6p^~W5eD=;xiYLAa#3;`za1l*|nwV)WdAD89re6m;uoVg;AxB zuLjtqC3Ti@0lp9GzIdH4>2WTe23D0aQW_dn)a$O?{Ppk#aY@g0Dq|Crw2@IoZK^rJ ztA;w2vB8d)RK%rFxvID8(0~Jl*_7u(LCVK1-3iA$ljNc~=UCVTx1 zdH>|!>29|DSTVz?WE1x1CPwuXu6pLfxwq16QAx|HLD-t)D``_geMz%-Ot`p7T+&mV z%Gd-YJvr!qD{T3JS=tVs1hxATg5 zRY#{XHbGkF8CBGR6RYpO$E!v;m9fE&2asHd{9y~WB*eF1w>y^q;9GEkQ^_W5!EB?7 zt|86*b9PDJg6}w0cD@#DWmHi~zyD^)1=(>6e(6-kCMaoZql)I15(WPG#H;>xDq|DO z8|NF<61n_;@I{?>eGbc!TW#m(%V7?ozK=Eid&z|J;~ds>Dq|Dmu#Hhg^Zc}*v+ne& zET=LyK@K%5b0kXI@jj#18E^R<_H?QX^5w8?ki#Wuw}WTLrI5&tNB;u?f=ZOsGGff3E8D+q|l}QyH5e ztu96t_1-Tg+;)mrWjmFz3DW9nR4SLYCs!?d$gBD~m9a7Vr@0V)2*+tRLei2Ij1_Zc zm-6@eaeALq$tE19-HqxCTpc~PE_|D>DNzf)bSfm9YuZ zx->}Zfho@n_NrW`GB!b4J>qiVNt}0U;WV$B=TycO(L zT4CgXf6bPxQsP47H)m)%IWe2^9G;=|A|x%TBe{CkBlVN__)@fS@$|B#NI4JhZB%uf z>Za3rt@5f%oT_)ep4rE!qOvEZ9RG0dxaz^y__}FtM)jRu`w2Zxe!;YDfhO9n0TVEI?q-9g)?M3au^q7Z1l1T z=fj~!71>#<=+o&=C7S|?UNq{Ee#1vuntWibd;^M{qFZZg3PGxL@w8j~g+DqFjo#zeksvM^>Hkxh5` zYPa`bxeqt1H`}e3i{~o(Sa`%AZ&cHq-KyDflkAi!g%Gd<8Iw@8uIo;9ls^v~) zY;--L(djZ`Qx3zU)nr1_l2M+&&PZP4^Sr^uGdW+Lrx;b#6O`x4ah`WNm9Yu(Ow_KV zcubzX>MN%*HbI`1!!XZN2}w(?#?^U3iv=|p9Z7uJ{&Mk5&6nqC?Dh40!`9VXrp9?L zr(wrtY=S&bC)CaW+P`>O$M3zWu~Qiv<+)*f8L>^}Kg{zCLei4$&v)^M66%5!%Y z&y0L|o@rE3J)gbnu9Y+5JdbcHV-w_gmQh6`PI>mK8=cD7D9=&XNGOM4p073Wj3&cp z;Tw0uEGDfe&&ypr*OKS(TGMq#73KN!dgtD8ZJg&Mq;;cFsn|+u%C@>^ zdeyZ~Wo&}9ZVJ*Wm|VZas}?wwu?f<;IZjJGqQN~MP4=o6oXXe)R|0P_s^f9B{XSp} zryJ31yvwO%6Q0}LN=RCgL2kAadVEjkid1J*u%WUERkso1zadsD-=9e?QcZFy*@UWj zM#Xe*w&o9%ujW;6IF)Qd)$N4%CyUOl&~c?#oqVi~OExzBsV+p}HsrP-B=y?q9oYC% zR9H3T`$)s}UZ;{xfdq%n5%FoAok>#8D(^J$6vNe4bM-UnKArvobi5d` zx$x6obQ*aT@UGOB1^{cH9!wY{poQyH5etw(~irdRD% z!mHXkm9YuZS{$c^CsFsY-S2u;f2T4w+MSrW2a+;Cs5m>Qj7M-0oCM z^0mcMql(7qsh0+XNmm4 zrt9L%{76aD;9+|<-$vH_RGRd49DI3qha9gu#i@)< z(4*D_X_d^`ag$e_=TycfNbC6^t&5AFI@_x*bt+>Mr1e6OmY$FDs?knmY=X32G^(ig z>WZRQ&2}nd6V&`mMrDq4_(!#4YJC(5sYU7n4ts#@XUE@`|oyyn*X}xMxQ7iW>ly{+59ds&V6Qs2+ zNUQvy6}Nj;Sw^TfV-uvco=|_~|M`92+~HMqoyyn*X>Bm7sP|sjcif*|)yk=iO_0{c zScNCi;DtQ}ysD>D8JnP$HyKq^8dm8Y|J<&WBT=qXZOYfmn~f^U;pZ)XJ9|^y$~QWd zu?cdx#i&&C+E!IQxX-JWJC(5sX3^KM_2)>P+poRM&l@|ON;cuV@w!n}qFg$=I_CY+ zSNPt0(5YU}SFSgVDk|60Rc35>JuX*?li0~-Y=UxaCDcEezqHR|`@O2BQyH6}Tzuhi zBSo>UUBC6PFV}faC7W;-ebcB)O2Rhhp0jWZ7(Zw3P9>YLHntOzmOL3lne_cElj)hN zG28V{wLM>L>|np2MK8Rm;}zTE+F0OJ#wMtZokkUn?fDPWdQTzole%HK=47&y z&DaEKamY_eEBCtMt$kXLW=g~B>iG}T`amIZxw>7|{YtNTJ(Hbm#wJMXLqdJInjKfD zqE~&FDGg6?@gJu3kwW6MD$Ks5w^x;@B8`2UA*z&XupblZ)5@CJ{Y+Qq$RZugiOkx(3UU#d@$R6RV{ZXGF7W7_47G9 zeEpo;aLKma@i<-PRK_N#pD&E6oLv52f4%NFuiE5P#wJK>PmosO)0RE#RlA+a*aT^P zX;jgi@ck2~7W1mVoXXe)X?+!>^~c58NKY^HbGk7 z7*#a$C$lH6^r|*aWo&}9_Qq-9NgOV^alcpfaVldI%>3UP)d`ZY?R=vcr_u%Nhr~pu zl19syNZ`sxvvjMyfqdC7V$7y-`)b)%I?i z`M8m)QgwwT60!+ZKM>-d&bqAlMuu0UI^U^e6RLhRs>-<9+O0Y1H?PWdD%qe)`ChP} zkhElN21j9hxitrKAc{uHHmBO3Z>0QWR8cGMyKQg({qaco!l{f+(8@m>Rn&W%JUXSl zS0!t(lg-!!J?a-i{itkTb<#Ipb&^vVn;@-UjVc&Ne zzj{>0a912v= zyfA#DA1OPWN;ct0Ic!u~pxu?ccm%&3l6_SjZka>+|xRkF4X zH8w$?FK$%P_npTt*-!k@F{Qav$tLXcx&xAyyo*RxbANyOER#AxX6xfrC6bv^rPO>$ zql)IJ?BxUgE)kb&mQxv{oxD zIKKIJKF=SycuFOY%ya2Db*XOtv0dR(ah}a9nFuvDL7uhTzdc7{cjCI1{eJbTI;SWs z!6JvsN$Ndl2KEWAE-QNV^?AO?#Zxw!c|;E{XH-!=Z}@vpqq1?HbDhfA z1bHrRRMFgW@PYPiyy_mOGB!b*RtVCX^4K#SylSme8Ji%jV~r|07Oeif>?>aNl~Wm; zAgzi)S`~6D@As<<}KS#AA7>Q^|%=nR0Jb3;g)&#uY}rI>f8qbSl||s*{YWs!QvS z%Nya1=8f8QZLn-YRi;s?-L<`ZOgi&Mq`KUxWD}~Y7*$y-N}O`S`+dA>j#J4dR8=*q z(oS{E4Tm_Pj?#MCsbmwXss*Z*Uv#(|@aWMPPM_Z2~{-$ zRo>#tGr}F_PX#kgnN1@loX7M%A}txsy#xRFZigQ`#p_vB?PR7>PdQ$kVpPT1 z9nHP9u)^?b*(Z+-4n*EyB33C=D~Gb+`pj>6|W)%q%* z!v~$}w0t?NALLL+wA11oKI2rzCdgp}qbf`~+H{Y@tKN1hV-w`Cp;67jEs3hj$Im?B zbNGu>HB27a?u~*Re$}(<4GrTQ7ClYrvlfMHf*dwBs_6K&q*cRKUUiC78JnPwogSpM z|D^ZJdDR6@Wo&}9&M>Oz_|^IFt$%veP^U6BL0V@9X`L`D>vONV-l>dDkXDl*t$&th zz35esI+d{r($XCVf85czmRG&zRK_Mq>nx*E9cp`O=#7KD>KmsrHfH}Z^$m<;W`IV~ z44`%oM^iHs^GIwpmaDzeBh&YUN-mye$s>Eh*+D6eUHN*EW^qrb?^MPnC`EIlibj)G zlklnzPGxL@89+G<^L&npr!D!_th{08tqXmghr4*rA@RH@_3tL8bCu?fakmQi)ZEkh0)e}C{RpTozUDl1r!qD{jpZ0sRAYy}>fO()W;>O!F zHfMnD%Pw zb|h4;u%w+#JbiFWVYIAHTgD3?%yy%Tr&IFCl6E$#sHC?%cE*}caY+|Bm9Ys*+Qq1% z_9`}PaDT5_=TycfD5>TUe{Fe3jYZ%4l78+~vN0uX5H+&O6_&J{iAUdPRMMFXnji2b z&1hsx+$~>8yBk$h(k&-Ha$UE$q$fF*u?b3gp;1L8?J=g~+g^2sQyH6}q!$^L&PTMh z+uh(ZU(yavC7ZCMDpy$2i%mS6h(o>i^OX-??@P)XsLXb8GLv{x&uK3)s;H#(I`kWL zaa__FPGxL@l3r?5QSaSyLZt~_b&pdSo1mmUj4CSWz1@~_p)~5fE1gOO{uP&{4=9~4`$ot;^~<@vZR+8RaDYO1uFLL8JBdgQyH6}q?a32R8pP2dsTtP zHcev_l(d&osmEzM_48`a`jQ^+RI;&c>bi46m z$s1e$f=A?kk-&3tvesOFX>eioyyn*Xb9>x=T%=gm9YuZ8WE(`cKM<H+NU3E9Myh|5z3n-pNok}+0`D(6FslBxAdZ@!fuWELt4V6u(8f#RX z2AS=#wEfk+YLHXOCRB|J(z@g3?rXg24yTe$sJbdpZLQStbFX^UsbqsH<@|ZPQN4&; zi9Fu)Y{gxE-YC(;=6ifHQ>v8n=Ltp?%^R<7p1E&)Ja1$=m9YuhYobwABvL$yvBOT= z?Nw(vm9Yuh>uRIwWV4cZtw=*YNA1X0crRy!6?o}h4%Gd;HO*5)!{uwp+vNB#Z$El1>kk<4d zt@M!>Oz^6Qoyyn*Y0WSyE{2+#-&u0vBCmSUsf-RAN+YWH1EC7W;* z%rYw7ozu3d*deY;MXHRmY^ZEZZ#g~cEo$Ykw_I!DIeKr&a`9Z7%v9cmP?)LI;%?QEwha(>Mie{So-XArFKqBMyfA1yf((GmY;1Svwb1;uE&i=73FaA8;Rv!HMF@^$tFzeCZnqA zayYkKy^UUV(5Yk-s%|zaoo8v=SNyX{UNz_(8!DSnb&FBC15Bb$&$qgI)hA9Rn^1MD zQE?O3Y}-DpwbH95pKC*96RK`As^}Qkv`B}(UiGI_$tG0IGpeF4tt)>2jv_{5=b9Ea zST<(tGYpQAMMm@rKtvyFDHS zZ#$K-2}Z%4MitGOS^>wk zS6%K@#wJMXo*=F3H`i$CRW~@5u?f<;*Qla$ZTjSoue@rFQyH5et^0zsTDB`!!K=P; zDq|C*b-z(X$AYUm6?@UEDx9YpWDQ^01Zh1Gq*bT!{9ay_?Nr7lNb5nPit2Fg((OCF zYP3@sn;@;j5_ z?N6tYjU5HijH5muj)H|Io>I8_?s@$*eTU_P*|J+&E=(Rd3LZA9XcRnn)*Bxzj7LEa zr!qD{Nf#MalxKa*_Noa^Wo&|yK4MgbY*rFOZ+SFj9=pq_WMfL&(0#>Es9a%57n^u= z-zts&@JWmpT|A5Pm2`Li{AkWKN%$}HbFfr zhlTzh;_d@JifRoX|B_&DT)lR^qGE4^W|#EdD1r?!kN|;@U_!OSwOthpDu{{=8;ZRP zDi{TOxpq`6h}Vi0`_gP{|56G5(bQoLbtSbeDgMF#0sOaBYsS^5 z#*JunU+353-%-tLsA*}zKc?C;xXtYajT6QO|G+B#A=aigcZC1&YDwexy5Z`9W1H6fSDZgY5RVSQt5n|n(d*L*K$LV0XM zbxm{4SXYm?^_x)FJf&*bX#A@(={aC3YsO;U=K98wIibw28{Sk~7tn&qZE#6T3yQRv zx3IZsY%nvM%&DD-y&&ik4^h>)y2i4)DFu_=V~890;18;4m{6C#!EKVeWesvk;M+JY zD-6i1sA;SjS=a2o$=y=dJh6UwP{dUj5Zr)>M%0gVtnJMM#@CFW(BisqAqTj)rm?o6 z&h5Tc4R!v3b2+f5q9aT4-D8>8T!-+nw+ydqX~}6hvc+$Qal6ZJ0C$6e$#uggjIZl( zgWI&WqF{0d!yuUD;QGda%@czC4_^wt#-V*=Njz-_1ryk`!?5&&+eOr zqwl!px`w8j+5uBq#@CI_Z)j-A&OSK%;8fq*Nx2j18)_>jj2%|j>}Yw&%Ik+U*ECOY z&-KQdhTuDzTF_++{xxPd!7$fsPUDpHztNoPJF%vrzV^tmwJok1cHSc^^7#zoBgWcw zwfW`cYo^be(A-?tI9|7+qy>4_Hce`AcT_bOxrewp*oNS#P+r$Ka{Q>lP0eHYa0ja%XsUyoW@%JZT=hbn#N5@m+0o+esl{ewYy_N<0Nd2aZj*^1*sO+H`KX9 ziLYbd=S!J)4jo!QcHB@#*^txF&@?<1+<*-I<5tgqZK|nx%HUM+{YN&|^B@pxF$2zN z8D3wX@*9xVEnW>DRa4*CElCBTbYH7lNh+unzg6u5ifE9>S!{a?;~r2q4o6U=(xz?u z?yz6`?yyn&?%=!8p?$Y+&Av0;lX-8tV9v0XrUo35+U-OBJKEnT<=Wke18MVkJbA{C z${SVFoZ?PdFc~kAE$MjL-r@_jxhdS^cw5eR9BYSRlW=yBpWgS{SL<-IFR8aL#T#EZ76n@$>|dO1aEi~J`jL%zacRb@^MuCnso)?z z0I#JDb>UsZO zrLHzTbI05LG#&03+JZmRO)HU-( zWMDl{ZffvHJNN{O~9wTbNriw?zx58#pT7N)zww`*;##i_2}E{ zpkCek_R7lY*}K=l_-|jX{Z<7JZ@4)w1-FIi4eQY@h6KllSP~o~vXZOBlAub=mbBYj zt#*Q_@Jy;{;119xtHPYZg0hOdoan6j1dm{K)3}@gm01JoPMlEJIJ_>MP=}lSw&?9R z>20ZF0d8JP+XvseCtalDH+9riCHdjTbnx!Z$ZEV-V(nj;*E6e6R=Q$`$0fW!{n`@$ z{oVDUm+z0h-+a)+@3tTD^xgicj^iQI9@rF|Oz`XQkuS=wsHn)#ttiXmBj2-cuRiX% z(aWuSW(Bw5X7|q4J%7!!x^zxGy5UJ0A=1y2Xpw%JM2mFV(ITi3eZNmE5(JsyZk(Y{ zz{?iG;uEMOBq}%}8Gq$xh*t1I~g6H%;o(%fIEr zOIPs16i=(;@qPZb_TLuV*k;#m z|8(j2#E|=awa5YycjTmdioQR-a!#t_Tjg}k1G`!G1&^V9U+_5giTOVJzTo?M$9$iC zUwS`_-p=l3&EWg2@A7FGccm}sR%GWER9940Rt3+|;e4Vtb2Wvlaa@h(Y8Y2FT(xjj z$5rwHAU7|&v>>OnsJyJ&9Reot+tyqxcIDTiN>O%cX?b2@d47ef;x071EpQi~n^@Fs z-{`g6sgu3rSI;%=>bVA8)2_0+V{Q8_%dW~RtSBt54z4*z#_2AdyP|HQ zm<+;~vNf+H!A))6Zt#Lu`T;Gh6uF<)!*EXP4$w zR8<$}7i9PCF?PhbvE%yos+;V#JX>E)(=W3*smQBP=_g|h@cV4E2-*)$)v!)q%}T$x z<0icB;%#|t{dipHs;I$V@(tco4k!+;7;`(@y-jylr#jy2w5 z`?{Yha5rp|4qxYTYVmK4ZE1Nl`)efcDq22M6DsemqOEtMW@KO7n15 z&pQTiHHs_u7_9lBN>APv%pUzSmy#BD#jmcGry)!y{dn+2uftvG^EBhG^r6bQYt5@- zhl0U(8QG5tDJ4|lIYcB$rxppq^rA$1U&_nQ%PB7{%dMz%`;z-PmOH%3!QSm; z?pWv!VBE9PKdjl~vW*9e-NTj#g$@=9gCG zd7oxrR1kFwm{{(mde`+qMfiaUa> zGwukc)6EXQ!??q4DEtoXDBP+J8*BDdnQ}Wz`UjBiXIH#B&L3F$GtU^{OGb+|N8qCJ z%AA6H?9iCX`Sg#;f*q=3iRkH5-6H2rAMz`3DXXfuy0S2b^QC_T*LL6SUX`6!Ra})@ zQJzb(=4X2Wiuj>QdZT*d7-Ig^CH>IHfZze`l~f@Hq<5l(ZQz@?h>Z*?@TeRC)*QAY zKzg@KsK7&ZYy}>TBS5eXF(BB6$nW=iN!0!RK%G~VU0hL()5zd8-yNsj2P@pc+O6EH zzdMn0Cy=?^MI3R5wKb>M?qdz^4tFN#PLtjDx+-n=zO2Hs?1KD~l7h0_;9SPN3RIC4 zay5`EcXHwmsr~uC1zZK^JQe)XO}^%&*PTDN@DBIY2!0iu@AlxAu9*84*N8hvJLujf zxbF)tIlCs@{J~s7AldlwNMmigchmmx(4$+&d(wMP$9vMdO~-qJ@5wT%1>e)%xF@}b zbgUM9PsiK+KGETh^nt1}ySltA2WOe(+5VFs=BFr_X!t6fmz!NuSeT!en_Hd!CS2i4 zf9#_Dr$5$wQ(ks)ad~M~K~-^wZ%QAH(;w;xzbUsUyRf*pD5tohH2qEOKY-G1yKq6j zC?~%%zX%^8vOdPr7W1XNtT3mdy1XQJ&AG4JdEHLr_GpyR z#e%1k=>sT!lxp6a-V5w|(|dw_Z+dUA?+w1!zR&L!=AFScw4ei?6bG-4&5d;pxD7vz za-ZE;)7Dz@bf0U<(~YksPbaaKJgB~w*k`qNI{maN$j&b+D6TB2C}?+biZ_n@giEj^ zu2seGhkU)dt*sBjSbHC&(er<-zxMurNE_Y$FLAf{3%>1l*7VWDop6QuS?Q^anOkUL zH9q&(er~VVcK(3-eXT0HsJx)Ey0n0&b!$GM73^b;6Wd(L;WJs@HuK_6c)@iosNcf1 zDVuECT#-$h8g#9v&Izyi5125lskycuKjN>eo-nMTet4U+e4eQJA8DH^eZY!W>El$q zN*|u$RZuJ5_z+@IFSn|?s6?3nz?hMhr$huRp;KZ#L%eXVOHJ6^+R_>mMOTHE5l@*ov zf}diiul+0OQ`JiD;4xFo--92Y+#KO(B% zQe9eFol{m(9DIxUnbUUPQk`9xlV4I+TpE1Gn$NAaQ&rg&WjMjBtjrC!*~zwuAK9)b zDJU;1C<`9vHRtAX$)_j3&7GCUoIRPlZJR@cv0t`5DwuckngGvXaH2D;zA-!*>u|H* z`Std;NBNRQy{s8^uP+vHcW_t?K1Sm|Ueo3v+_PKM{lPIL`u^bP(Ieseqwh~2$>Qhl z9$7#5{;2N`k1p=YyZa1Lo92THv2F+RAL}*iwAmSqGHrJT^X^~|36F^B*S!um`)$?R z)1My=uGsq@FXKZdI6m+rxM4Z}G1EwvE}!6nBW_mD;;NF;lIqIfqH6GtwcV4jXJtW2 zPC+q#A%QpJR|(wv*MKxmY_}C{UIX;@@bQs5{3Fx$L)830Lp#;xVbR;|viL!&`!uU) zE$ct59iE=F=jnSRrto*C&&Lb1@q@^sva({lZnSO2e+0&y|160c~Ld1d+S=J4-q+V{Z^$(xLO&(AZqTM35UZg! z$5P!2^cpc)*j8>%c6kXu5Qyuj?I-h{@j8e5B^vij6Y00d{c=ju9rotOo1#c?438zj zVYF9rl~@u~>6u(5mIPJY2e#rniX}mntmJKpB|(+$$yH)WP$lLO@;gYh@Q3BRitLiS zVtg*Hs3bVEC@Ze6E~vuQjE=u@ z($;3>@*KOUu(+~3_$giqxT zcln11PvPR6DvZkfH5d4f=5`I>Y9Lqc60^Iw-1gcp?`aNK?g3nLG2Fepx(9I0Z4SHJ z-1`<+f6b-DHl?G#FFW{{V19kexQ3c3?NewIj63Xvxn$vNENnl0SNe^saaa0DWZad0 zi)!2ze3x-Y$A`dggWuoqse-EF;*#nrd?3MHkHxk|{0bh^Ub9c*BQ$u}3d(ZI+FZvC zt}mxA5r?ld?7wYjeiIre2It@H?hCFHVHe^rAG(hygi)@&54&E=3DQT5vh4CIykPR( z9lOmBcQE%1aX&wH`;6O}+%B}{8nn9*?RFk_uRCzg%;-i__I{wL2z>Ew3&uFDWebp91)QY17?it$A3- za4T!La*YN@mG}p-#9+D~eQ&t2=G}htdgter z;fWb&R`*^9x4pG%*R1Z{`}FD4wd;XBdiU(po%fxvVeQ#1o4oVQKD9aP zt(zL){|4Ls_>k}L@e}LtmtoxCpJLv4yYwF%@;7eSCAEKT-LMHGyWx+91>-6F=Wub^ zsV=$u55q@>+lF_F?3*1m@K?_1xoOxOZVbO>p>&eW`C@w%#$wg=<&O9Sre5ez1>y zU=H*y$gg{L+ke`Zl#lO`-thl9vb(^^_Tg{HrG~)$)7!XtXTi+%E^gk%-ndC4<~<1y z=(BKnI|co23m4Vz;axLQC0ID3=4CD;y>SpL*RSlSTjTbY4lcc)roR*aSS`Lh&vKIA zn{d~{P1rfuKK^;Ws6O6-S?OI=AMQ`D?Gn^VZ;jOl-S!?{ zPcRv~#^=m=yLy8!-LUp6{&~TJ;D+!EjGeJW&3g;}CGY$AuX$rc<-$Kt`YO!V>Wt^d zMtk6Sge9(CSKQef=16r$y%w0$)wTJjv^fute{*2&P-oP89_B4|Qjf>A)i4|EDSa6A z_JHZBPU*SgE@Z=^Q$_ekF5{LNbQP+BdQ*A$$>diol&m^=5%$Ei#x7)<0i(+%H=iO zeh1tc-IH^91?D~PqWa*xzrk#nCH)$G>rH~7+x zs9YY0yQD{QE+4^s?Oj|h8}-acZI6W`bVeTs!xX5KKA6jJm`Uo4dY8jouTJVQmnXd8 z_HkIbwBq)c;b!zo&gEm6Ro;dD8uM=48^;YS9HBG%I0U9poz!D4wJ?*_8TDqu+@MbC z@i@N78*U#*R4y;TUDPKzmk(gR^e*gI=H=tD!GRg6ZLx5K&gkPnm^^h-kGa&qOi*Xk zyA{sSxF6$ngk=hCiN9c?`dckC?lX}eM zc$j8&M!kz+u2v`Yn9HNyaQir-a#;fRuS1e^c?V{tcVWLWFLTK}6z3&aI6`Oikp*+O zI;qE8j)iGbXVjYxGh3b1V=fPQ!|mg+a#?}fTj6d#EIF5-U@{Jueq~)K40T2ycf&lT&Zze>%qn$KkB{5Nxj_%E5v;6ScwV;y+&A9F<ZBfX*}gdF!8L+aR4#kKec^3f zE{Bxh{1gjETrRaRWq4;V1834^_a^xrOCPQ_|gsTXK&+j zDJsiI4Zy+?m&=JTQ`H%LTnlr%I_ZPCJPY%_I-}n2Fzb~kZ{Kd-xJIyw+FyFZ{o-w0 zF2xlYsexEH;&N$*nWoO@<2so6>Wo~TgITW5sP_lV`jzq9$Ngn@Z(Ji-Mdi{1Znd{@ zxfE1or21juh|8r3=5%#NA9G;lsWWm}3iGZyqu#GD>r}^YA9LB&8`lU{QMnud_r14q zx#af4bu%m+ak(_WoTAR?<4TyD)fu@w1@pE#qux(28U5q8kGXX9#x;VKl?#tA`@;R@ zZCox@12R&_V&RC(WeUu{)ERx;0&|}_BbQfUR;n}VWe&v8f3YNO-+taWh?SKKucIFh z_ougUxl|sB_cK^H;&Pb`bFMn0kDFocRcGY#3d|?!jCvV^GE$pjiQ7KzFZ+7qAXZi` zt+@RlxZk~v%cX2E-uGbPh|6UH%vtJ;KIX#QrOwFZMVOD&8TI~x+32YF?PD%`dE*+v zDk_)WaKCsPmrL={cs;_x5tmCd%rtdIAJ@UmS7+q%9L#ccM!i2^);}hG`>Wo~L!n~`_sP`+(I>*ItA9LB&8`lU{ zQMnud_r14qx#SMP>k$@?xLg`wPElv{aV5;n>Wo~Tf_Yn=QST?1jN{|CkGXX9#x;Uf zR4)6%edBFhE`5jM{WKPixLoRCrl>Rem<2Oeosr98m^aiJ^?rc)OP$nXE<2tO^xzu7 zDk_(~;J)%UE|U|6IhdQapT(%pQ zoC~kl?GCrm@W969axBb9@8WVf3+8flMj!XVJfTkdU@q^&e5cN+w^=QIZiR&-YWrC4 zU~e46%GzIeURMFvwJtfAaWJQN7d0=h`&wS9XJB4eXXNrd%(^3_U!z_(nC|MN z9=EU38+_@8l}jt`IUa83k;%E72y?1;ak*RtbGtgDk7r@tP$zxx@%;g2y-~@z>;{vi zPU`V_ROO8e1*@oBj)nV2eR3|1FeiBzm&+9}x2iL8SpxHKbf!SZ3 z)MGB?-X!I66x{Y>l5-gYGs(NSTrP*XNu7~PE6mI4qz~ruHB6_5+%{vAa~TCQ-n+P5X29H_&d6mE%nRzI59aa(%%AFvdOI{`r1r$Z5w(5HrO+D( zv9g{={QOIQxLuo)b7_G&-MgrHd0d+VbB8*kkLO|DQfK6{8fJrW(yvi(515|nq#n1g zpEvl@ji_8|;Ch^xoXa$r3%!fWWj@S8bw(e{U_MnReQHGh3r9GwQLhh7t~#m5 zTu$)D6~xNQh1VIz!DY21=Q0&$x_9CB8S~x_vp}8E$2%}9)k!_(k~toq7sbL6&TG`` z4U?lz>hXCr)Eie2D=U{)+&%_w{|U*toCb5Acj5NQynH-vg?U(=(Z`!GAFGpk%q2B3 zBlUMI9O1l1y&f<}sFQlk;-eUI-}mPFeB9&_0IAJrQNV{;r=ok?zkz*xy*-o*t@t~-h}y7ozX|< zlQL3Wuy91xV=nu{Vx~sYcMO+ z8GUp*B_p*77LKTT%w->#zUqv6LtyIF8M&O}jhh&&s9Y|E8+2-NE;qy6>s?eI%;goB z57ilc{0Xz+Y00_l33He_quwzvBh(qWoas$cE*HZMI6XO+xiEKm7njS6Fz>4~`uH7Y zy)%+?*$w7kbw<6xFvHauxlHvYDVOPR)l-vmxejK&cX7Eq2eV9_(Z??^ou?(|vI|Tf zbw<5`Fej)payiYLq+HH}tN3SfE^}b!c^8+2zjtE<3^WRA6B;|4rT5bG-|Wn_Vf%#pX)MGB&o|}={4+}>) zuTifIX0SS`$6O|O;|gLGmCIDP{C_3qav98Z-i6yI^D>vmVO~;a^zjwUFY2TobJ^;= zjMUy(IKp|2dc`mU)k!_(((H{Zh*eZBr@`f%pPb7jFmt>Mw@>C}E(>6uS7-F`Im~Kx zQjfW8aY06E4=fzvyhgnOn11S{9&>5(#udaWDwmVtj+maD%Y`skdKYe=%*$LJhIvMv z(Z{DS->Z{)%%#hP8L4hqIKp|2dbu!_>ZBfXY4FAs#40M6$#92Wl$^`?FtfZ1w@>C} zE)T#wtISpF_(I8TtTd&a+v^k&?U*aoC|ZA zcj5NQyv*fZm?za4eS8S>l{%@%TsEA6>(5v?!g-B)hrtx9lX}c$gg34rR#CY$!}Y#2 zIhV6wF7YnhKAD%f+y(Q5I-`&GVLn$U^_a_gm*M&|7LIUUqu#+V1?r?8a~bZ9D~MH8 zE=_PfE>F&78q9^>h1)0dGMD)<3)LBYEQ9$}oz!D4ooC{D9TtvoUZY+gm|S&IkGY)S zjVp*%R4xs02h2*&<#d?yy$iQb=4CGPU>;Ft^zjzV3UyMCxpcZBBef+Kj&NS1UQd|5 z>ZBfX8RCsAh*eZB^>F*nPR`{Nm~*`gw@>C}E;qwGsLtr)b(jy;Nj>KBC(PzoCg;)} z<}h_qkGUM<4Zd_EDwh#(dtH^B%M_Tiyo<|aF3f%Ej9gxYd0(CM!CZca+3f1%T=s)G zSe?{kE`z-ZQiM@sr-o)j?pC6q7mvwD&E>mHqdl#3>?Jx_}8M(Xzvr?V(!CW%0!_Nb-aD?+3^?JkP zsFQkpo)7iL6~xMV9`W-GO>nu_C+9K)<{Iz9?K9?G2=jtEqmM6Oeo`m(n9JX9z|Rq} zaD?+3^$KD7tCM=nWt=yzAXZi`t+@RRxV*W^xm*f!t#{$}8S_2{^P)PVk1t_H}3B}Tn%%pcj5NQynH;C zz`Uu>=;KG4o26f=$6Wpa(?gw6uNvk!bw<6DU@lZ=)SD0UusW&7&r!YU4Zd{4%9;D$ za=7bn3Hpuu{MC0b|Me~|=k0IB=M=DTgwE)r1m;L}(g$;HfjLK=QST<0d(=ri?td?P z!|mgU%H>_SYvv{AvI^!m@4|j%UhaR}+=k-|7LL#veH6mNf|ZpE_m@vu@1EpbHoh0{ld*7w&kvcGk4GPvLUl$TwJ_t< zNj>IrA5%a^dG`euGZBg`m(RUn9~@RLd|$B|Zpj15xoq`dMrs!<9C5j1!&Iv? z`e=kXNuBh;T&{qbug<9V9L$^Qq#pN|AH88899AyeUpha8>$_Mu;?7^Td>Gelv2euY z(if&mozcfwm?`R{59Trp=5}>Py=P(GP$%`czx?10`{1y0;pgiAg8Sr=Nl^;fTwn2IfR{Mjsc!T&2$F;}Mt_)fx4^g!x&W)Z_lLq z%n9Db<#HO#h3bqx=EFR!PWs^f@+Qm|>Wq5pKY`EnVd03{KGy5uje}TO`wMd^gxhOT zaxPO~&hjp5ULM!x!rZ6M=;KwG_thD>{0_6(V(HhYw;#;G>Wq4Wy@|_(uSa9x4tp{= zmkVI7@GdTw2Vs_|Gy3=h=38|}ADgz~br1_jIImGJ8>U>H)Z^ne+8b98D{Ft@@#Q4A zL!U~{<$Rb~-i6y|%=-Y$)9Q>qR=|9tPU>;L-{fh$4r1X5=QZl}g(*`f^>}=#_r?{( z%F3k`w@-jOXi0J|=fYg(UATQRFCUM4VV+cH^zk9gSL&o5bJ=hyetwCCBb?W$cNk2u zI;qE8MtI{2VilE3GhFXyl5;r=<`VD1?UQ+#%Uv)}s5AO_ALes)QjfW;_bh&XiG?Ga z*Qj?eOo2M7$6SVc;|gLGl}i&`kLQwenFe#Acj5NQyv$`j%tCcWAIo4qRVVeBOXuhD zz6=XTIImH!4@|B)smEMS@WvIyDk_%-xC35D&gFEN^SukVPv&JV^I#rPXY}zF%nEf< zkGXVu5kJ4g!V%7E)awb;SDn;jEqf>iANg+GrP4%g@3$+?^jGsC;MT<(Thq|V4? zIm{R8qz~q@{%iPquUI(3d5wC9z!a*JdfcCDy>SJxirQbs!yWi~axUk>F( zxc5hJhb>FaG4De#OVt^Dtc3Yaoz!D4o4t?U|HZ-)&TG`m zfvHd@^|-%`@x~Rz%F2a5@16vA*z#cBxSw~=gt@`HaQkFlJ|2r;UQuWCu?prlbyAPH zZ1Vxmudr~0^BVO^VFsx)>WzmvSDjJsW|(``Nj+Y#dc_;JfmlW5{5IU250i8L87A{1 z=~w1u&O5_osWbYhf;m>5)ML(5V5X}x>fH|WkUFE@8!(@%GwQAPG5#(#7LM@om3quM z%Nqx=ipu$5xIev(+nL!Hsb-7pK)NgvF48O$nmM!k(c!TUTc z98ufHdVOF@)fx3h!HicY+sB+|c*A))tejhM`;~A*RtDP_cir|5m`A*e>VrAI1@j+u zMjz{Znvwb&7LKTT%;f->JatCB8kn)_Bo`h}&-aG&azy1a3+|ZzB^^S!Zsm{pdEN_x>xdd+Dm&v)@2y?f0ak;z%vs|6g z#~(23f0dle?l6a_GwK}$Q>)I%Wtulhxm*a>@9X4Tu7|n9ySQAQhj~|>(Z{ba>#R!7 zWmlL3)fx4UgsD+yC&gCkYTfB?Q4V4J9lyu<8WxUlUZY+W z%(3dE9$$~9c;gCUWgT~Uet#BR=?}rYapyxf!rbj$xP3A&kGn6yELUgr@dwQMKT5w+ zkGbp)bBH>l-cc~M>Wq5RU}mZ_>fH~sNS)NW7SC?%y|mTbah6(+hHD3C-u1hz2ObMbR#O4kKk_jIXRc_VgB?k zZvWfi7rYZA|mG9Kn!bw<6LVeVBY^_a^m-f;UktXx`g`+IQL{+gW2 zH!#0@7xpXja(~(OH(YPW!Vx;7k0O`>>ZBfXIT7Y8bw<6pFn6hwdd%fTZ@7INQMtSW zclGbdxqJoli+5qaGB0!4>JR+B5EhQm8GYo#RI8JE%%u@#nmVK2bujbQNj>KBoHyJ) zj;LJTgq!`}Omkvi#vxzxc-QD@Yf z1v6Kj)MGA-z2Ww8Sh?_g=ta00nL!_M=R;q?{Ni2MugvR?FP$?}yJO)9ozX`=Otm_x z=Z-Hh)6^ODu7jDc&Zzes%yM-`y+2^qUq||odORQ6-5b|1R#7?c5BGz&aXDA4o0&Qq z3rCor%*&i7!JMPc=;J1sd(=ri=KM0u3Ux-kPU~f+Ho?LXwSBC&4@_TmM!g|0_3C8% znDaT_a9$28=T_W)5nTWEgYApE4tE30o!&+D!JJ=!c~70u$8Rv}ZV=2HRgbxJgE>f@ zQEw2;Fm;j(pXX5%a`_1NTmUzA!{l5ZgL&4ws6Lp>e_(!AXY{ev;`Y1Xnl}!%FK&N%66PiEqWWMiU%~vL&gf&i zO>msV!Vy)EedNO&rOv1~5oVe?$%XsNb>47Z4l5V_+;l$NshcL}@*>PT-bMAnTz-aG zZ!_uF=wmmSEOpWcbE$$EuFj}86=u3RsmJZR-5Y%AMpP~f;4bKroXdMKpLrLT%esHd zOl^gQBXmX|yWq4`VQx|<^_WYmH{3ps zs9au#yLg-ATt0;P%Db>%nU}e2xNT-?J1iWbGx|6PCSRS@V=lvBCaN>)T?TWVI;qE8 z9`}aZ#}Spwb8zQxmz>MHF#qu`>{sSxF6(Tcnc5NyN9c?`dcyQoC-s=i5SSCy8TBrL zxk{bXV=j+)!|mg+a(M!`KMi;04#~N^4)dXRVZSmjbNLfy(;bs@*%#&@byAPH41yW0 z&dB9ln9I~jJ?3(+H~7*GD;J)>JPvo!Kaz9#0Om{Y;&Rzwr_9v0SU5sw^l>0eo;vA+ zxzxZ+P-oP;6y{oWQjd?@W8QH4IILXwdh{aPglX}eM1eo#ajCwO*u2CoTxW6p)hTF$s<-+~t8MxWIBH=2Ih2iM!h*O^VCT_Zr@UGxP2T}F5F+f_OT6LsaYW_vZ@5c$PtIip z%s1YJ{mQ(2JT}<_*AuaDgwE*WP?#chQjfXR!AwzS)SCq}SDn;jE{nb4_HkIb@b&0L zxC{17&gDIr&%6u!m3f)Vx_jaM5f+Zn8GZDE$yO)zn9K1n&FYML7sFhwPUpq3Wa_b2%DjtU9CK`7pE8 zNj>KBfH&Me4l5TPcNfFW*f%+sk6~7M7xpXjGMA0_%S`Qng(GxEABVscs*`%mr50wg zI-}l9m>bkdJ#OD3Z@7INRxaFMUV*!0|Kwagg8ACJuwP@|jSk36ZI6W`bVeTs!xX5K zddy`w%p`S2y~|;)S10wjzdYd$w~xchh5O6%a94Lv&gCnZU%U(Zm3jGiY?X!Ua9B7( zXY`Q|Q>{+wF_%V|Y3hu6*TKwJC-t~}&w0b`bmtSGl=_&mh^X>}M zQ=QRAKbRrvq#koQ8RjB&M!h>=9#JRtn9Ez<;7d2GT)4md2kzls$+@iGJ2UlnEF4_B zdd9pxU~<(NeVhQ(pib&Bm-Aq*QD@X!2=k0OsmEMC^#)(M5tYkNa7+6n=d$&IIFH4` z5tmC2Oh0u-A5AbPtCK#M%WRlC)EV`jhj~k#)MGBIyU{kX5m&Zsxk8&?o3 zD;NI0a|>KyPI4|YVQ%m)+&-C?xh#TtMV-;dDwyBYNj*Nk+vH}Z_Qk>x&TG^wg&Cwy z>T&zVd*cdXW#!U}+s}k6$_wU=dmhb#nd@D+ea5_tVO~{d^zjYM@9Lx;bJ;dOGqoQU zj&NS1UKz|_byAPVmkHjuf>>F(@bfuS;R*|adE-7eavjWk@51eqdHHxe2eV9_(Z??^ zoeQO3smEM)f$5{ps5cPi1a(He(_m((GwR(9vrwJX<9@Wv8+_@8m2)fZ`55k|qM+Zn z{ckl)r{efrnDb6B2dFdpsDL?Io%F$+C&8Sr&ZsvJ<^gq5kNe+i-r!3&tXz2h`~lqE zCCRy@N;6X%W8vW1)suOd%ib`Ds5AOF3Z_<_)MGBwU}mZ_>fH~sNS)N<_AU1YU%FxC z!t;-eMI-`%lFvHbJAIxPc%;oBgdiTLRp-$>?e|g^<7YbHU zxqJ?HTSam%zrn0qnVd^Em|p6PKKjEPuTJ`4E~mg;tj?%+C(NVjq#kp5+nc0ZK7qTb zDmjz0Ch$m6);DulRn(>1?GHpM!k7352%xR?)c(OQZ66BUDq!;mv3SI z@Qym___AI9%+%gkI6`OiQ4BLso%F$6nqkgXXVkk9=5BRTkGZ_$4Y!ZOdLHq0e;M4h z1A;!{UiW{6S!ba1EA#TWwku3ebw(fkV1}rZdd%fyn2XdI_3nUqM4eIZEtoIW8TB?e z5Ng}Z8{k5->`5*Z6E6$1XHfgs5csBqB_|==6snqoR`DOxfQox4L9_tVEf|EukM0b z;9XQ7%=sOd&(#@ytao%~Y6~nJQT3Qh7EFOUquy|sCUuevpXbxP;k+DHEM@s|Fh%N&dUY@-s*_w;?;@DF z>Wq4eVO~@x_4xey(i?o~hLtn-zaQZ4KR)O;?s?gHXlAMl7LKS~nDhQHN2oLUI1Xl% zI_ZPCoDFlOI-}mhFi)wIdVF4f>PU!V#CtfiOkt zj6UjMPE;p-xcvoYt~#UMVwe}z8TGz|`AeNqZ^vPoslBko^~?RJ$QuW-vU2ABR|VH) zcu+5H|2qMu!MnJe&x5&Aozcg`Fi)v7a`_nMCv`@>zt`gTjd`3rE!UF_(kAaS$sj zmsZ?f0Jr|gpkCbmauiIhcTw{)muWCF)ERx;4YN?4k;^ieRqBj-8;`>0=CE)?Z69;# zxok2TzXybcBb?W$*B7Qt zol&pe8&?o3E0?cv`>AlF$0XMvZu$W8ny$(Z|6s1?r4G zhQmx!XVkkK=6ZETy(heJ8;F&aODk@F4Q^&r&_~?s{w1#^HJd7LL#v zeH6nCR44WL_%_3wtmpT#Gcd@kVL+bH(ytg+FVrAvb=VcGL zotlGsamVo{n3KH=^OJd*^K6)T>Wn^?!n~$V>M`fWq5- z^d>GB{ycdW+~~>4xjYK9#Jjj$K7sjBozchUQ}FtRg(IpSb2$vATAfj^5#}Uyk_-2j zE4<;n9M=BQira668*@^yeR0Q^1u#p!i|T{(u7p{w&gf%{lW|AzK&gf%@Q!`V0V&RCY z$6N|wj!|dSn+$WNI?09gZh(1Eol);~m=D!SJ?=+;dV??BuySt2J?ox^-=oLE5x4(s zdpds46$?jHF3dR(W`H`Qj}u`|RVRHgm#bjzQfJhA5#}9rQjh!J&)(omH>_N^|7D(m z&oN@*h}-{mnVOl}9}7oZF6A)CsWbXG3Fd5d(g$<75$0iaM!h#-K2~ScOHIS)O0l%- z!>HE-<_L9CkNeSa-nfETSvj}j_FA|-{u#_0m-AGZ>E6ZVd^^knbw(fWz^qg!eK6gQQD^iq5~f9+)MGA}z}%$HsMiYfvO1~9?fcpr zeCdXjODpdAFWjQ($+>j75Wn|?g(EJPLtskP8GVd`8Lv+IU@kLYZdPa1dkW?ibyAPd zqgCFp500o@euI1LqU2mQxfnm6!NL)j%YiUO>Wn_>U`|vgeK41cVCJeb>Me$OQJvId zE?;`XJ~*sgR^axZ;g(&JoXg%baNNMc5tqwAm|As4AJbqiR408fm-#S@)EV`b!+fF6 zsJH&5K@YAGtgKx4K6wYYZ@i6ro$h-Xu0Lbph|8rOW{Ntak6AEt)fs&(hIvDsQSS$s zztl-R9$$96JUN$Exc%V1^)@b-?3wu72o{dGTt>s3q|WH$3YZ(!Ngv!_o`iW*ol);c znpyGN$LG;MykQ?4*8b9p+xLe1+S|BX4!;7gGgvsdcJ-tWJ{}`sCaE*}xE$tsbyAPH zJOT5XI-}lqF#lC2^_a`{vx6S+r5jc*eE+rw+*jVly{{;|5`Tve3rAco<6zEEXY_Fm z%x&tV59aa=%zNsLdcVP}dsY1Qv0gWrgVY)I2EhzdC)>yU=nQZ0r5jN>p9@!Ub+CPL zIo|?vpLcONzY6n_I-`%jU^beQoXcJ?hpRK{9Sbv3o#eut&w`n)&ZzegOshJn$DBX% zCP>+Sp7Xl$=Ws7w6Z9MRJpaeF_&E+1j<}qQVUAK~^f3`;nmXx&xm*WxzdEDdzhRcE zGwS`}jcWueYybNhw|BV?f3NTQJ)AW##g>PN`H0+%a>LbGZ%XLGPmG!TjP~R3Dsot6TB+3b1g5 z&gdf_rdpl!!CV?)rl~XPT?aE?ol);OZ`=lAW#z*CWjWkE^OAGvbQ`YwVBrY+m3f)V zJ}`%>Gx|6hrcRyIV=n)MnWfIC_W;adbyAPp_klO~(v7HGzJYu4_T*ePpO2rvVd03& zMeo!w>qiET)y>&eQ;R0wDOKS@VbwMBkpy2i#zf2 zH!K`+xf~8tq0Z=I49p~T(g$<79A=(6qux@O*VIWpo{xX$4g27T%H_Xsi|$I!rOVy8 zK7@rME|)`KO4S*CjDi`jPWoUjGhl93XViNN<`s2PkGZV!hJA2YxqO7%e}jAXp5$Ei zxfj=qv2euYawJThI-`$&!d#?I`d}`1z${j0)cXMDOLa!Q4ekqiaE)MP<&ux{mmT41 z?oZC;9+=0xi_7I*m@m~CeQfXmK39*0BdQ*A=?PP$&Zt)hbD}yUmy5h{6JurNQj1*X z!mamEaxQ~mhI<#)2aju0VJ=Z;^l=x=0(C|o@4$Sm&ZxK1!#Ll?!V$H7%(=HW4q|2H z!sk&5+}@8Q=W-Iv+1^FX%Uo`RxnG^p$G>5gt21)>1E$NP(yvi(f0#qm8TF3xCN3BL zyrKc_@CC`aOoy56U0f~?!7Np0^sy4=J9S1Mn=Qn7F&2(+UZY+POockB$H#4qH?AO7 z*8Z{>x1S7m*kj4LTmW;0cj5LK^F9c(M4i#cCotctlX~3mH+>v`e-aBvIImGJ8>U>H z)Z^>XXm4CWtgKwPzf6QHdLlWOSuk_G3%5_^<>Rp!=2dk@AK$?Iu1@MPmu(l}?^|Hu z2FC-t~}6TEQ+v5Ly&EVx07lXJNl=3ei@?K9?m1?EF_MjwB|Z1|+~EA^Pm zo-l{0GwK}!GeVuzV=iZU6PF90N0-4J*_xcoO)&R(7njS+FdwKh`uH!*22UmDvIoqe z>Wq3v!_=vhT=+ctr#DHtTm)DBbaF1&!OZtAE|=$EmZ>xP_ywl(lH^==f$5{ps5cPi z1a(F(r+E{X3$M$c2UoQ;*uJ>y#q(eu@GdTw*I-ttGy3TC4Bnq(;fSio=g~eeebpKD zhQQRTlU!Ku9GI)r8TB54d0L&+QTjFN?Fw^%I;qF)tMCS2 zx?$z=6z&-UxARNMxts`ds&{d@Tm^HxI-`$gVct+DeQ^K#0cO3IlXKY(CQF^v4UlK4s(b)qux<4wd#y| z)4Ykxr4@J1ggg4*$+^sfdBD54Twa4&q0Z=|(`$HLz`_w#kGbpv(^s8QZwO4iI?09m z%Q@a~UJh%2;c@&@xT9VVwlD7W@?Mz7y^HFD&)@f8zEWrOvEdtdUBJQ-Rgby!f+<#K z)EfcQtWI)ay^CRPRAuue`yRZdf_*C$$3rAcowJ_t=8GX!vxkjDz!CV%?yrRyiw+iMrbw<5ymIXbyMzD&?WnZ|zy_=j% z4a`{Y;&M43<|=hYACJI1tIorC+1oo-n=CNj+{~e{b-m8&)oSpF9k1 z*AJ3&X@NQ2ySQBDz}%tE=;L{qx70}=e0*2KZ17=nE_=ZAR44WL`qs}I7YbHZE4Ula{bT$-7#5CjUZY+iOn-Goy>Z^Sf>>F( zwBq(N;fhuS^Tr)_XTi+%F5Etum;32rm{-*qeS8D+yE>`IT(ZBg`qh;RUOE;{Xc|P=TTTV;Mp z$KB)M@_tOtS^RqhXgU5p{SL5%^Vc`hpHR=_?3{Yp(JJB0g z5GyMeo)4V`SNc;hZ`}FNjWBn67jB=-%g5s-nC0q>KK_7N|7Yn}>M@tyVGdDe)H@2M zR-I9A8q7>}M!oxC7O9hZJnk&_24A{i<=l#UK82h2OVDrJ@#ZA|md@{^M>Wq4Kz&xT(>hXB>mN)p)4J#M!e=Fc_{VnJ>ZvV^p9iI!w!ojtx zC-X9wePIq$XY_Fl%m{T-kGY%)bA>vi-h(htsx#_+2=k*lqu%C!;B&87IHLOHesq{O z4q|2H+=|=t;nw?aP%m!(8w@ktyQq1Y^Hi8i)ERx;1+ze%k;^+UU#m0fZS*HT_l1Qc zYWukV_4dX=tgKwz`4!yeeg@tWNr1E?chKIkguSj&NS1 zUJ=Xybw<4ty>SJxvYtmPaQj(sqt;8#u+zVQ%m)E|*0xuc$Nn zSOxQ&I-`$mHtU?)7Yj!?uTifQW{^6g-gs|ZL9C*3IT!AsF3Gv9_qWceEwFHe+b8pK zKh1*4QD^iq6lRP%smJ~0Uodmj8TA&xELCUJTj>q^;IMLO#qGbsE!;dgmyNgRoZ1Ep zM_ev_U<%b4ebmB?Q)l#XASe=}t2642_Qn;&%F1O!F^xmzda z@;1yT-i6yI^YVF=u}$aH=2$pFXY|n><}h_qkGUKJ)2PmWq31dgC?_D=Qbi zPCo}XXWQglzJ~eLyRcuGm$_`cUFXyuSU5sw^icrQPo30bE=@51RADHx*O+%tn1j?AeGGybrcUZHmos24Q)kq>7v^zwQjfX3 z=M6LAuyWz&6TgC6xnpuJz5jvN87v&(eqhWy6sAd?(Z_U{+3KVob9o5nd38p;&tX=p zGwN-zQ_zEJ1gofA_JHf!H941YFsFDIm&=tfx2ZGwcn0Qmbw(fG!>qfrJRU~9ZZO@| z8TBf?Ny=py+_AeP=W;vDL*B*Z@&?RGbw(eVyLL`(hJ_=l9`~31U~<$M^@hTXQD@}x zFK^t$SViqGbKqunOU~s}nD4!d>VwbUF1um>!@?0dqmLtCO4S*CjDk5uol);fn48rZ z^`7#^Z6H=rxx5Yc>h8(8?7Ts; z1s0B|?PJb|c;g^eRxbRzB$aT7?~|O%beP%RMa|3oWn^C!hEOB$YryAah(+l zM>wxhF9)VVol$R$H?AO7RxUiRI~}h7e#yDq0CT5z;r7YA%;g1`_tY7E{06h`{?f11 z6<{))Oy+JU;)JZ*V-x=QEOE;`sxW8NsclrUzxx5VXu6J>{{0g%{cj?#YV-J{~ z>ZA|m(hsIiol)fPZ@kcz#(Fqg$}cV{K%lInru5EhQOT=s@JM4i#cQ82aY zj6SBp%v5L8yB}teI-}llZ(Ji-S^LZDxcz&$B|VdK*{T=b*J9y_%OxA8TAk5HBg{$a zj6SY_nXk^M_Z-Zd>ZBf@M?ZSw8o|oSWqZ7z?%ca`YNtNQxirC?>|IwS9Z4SnDOe`GXyhgoJm_h1{dgHxu1+lXB7am{Eg`0FpaxP0@Uh^*8KAD&M>31-l z4o&W3CzyTINj>f_B``zO8M&McbB;Qr-c8=1v>R3~e4Ty-?t;UTb9oQuGw%F2b; zcdOuz&P&c^9?S#YMa|1xUV~Yo&gi34J{}J&98vYy$38H9)fx4Mz|^ZVaz4i!H!)UL zF8ut|f%#FL(Z}Ycom2n7!Vy)Exf}*lt| z2y>D;BbO_@aT8-@<-*tL8{sCECFimf<~8r4`d}{K!E`E@evLkMg4su%^ub(8V1}qO z>YWU8jykEw?YqeveCdXj3(xBwfV;6GIhP-4Dy3gz-haUCug>VB9Ofu>QjfVzggH;0 zQSVlm`_&os{_RbWioL(^eZZ%1&sQbqvVApvUWSDuZht9&IZ~a`M+?m9>Wn_-z}%zG zsP{6=yXuU3zk1^u!OGfSn9C;paGekfN8INQbNl0SOISGKa%q4$MV-;dl`uD}Gx~T6 z=52LGy`Nw*2E=b4_rI>*xJIzDa^dl%7u-Cj9lJ< z`C6S(Z=)k|o{fbgZu@$B;~-X6F8urL1#pKAO3vj1m@B-CoA*JOCF+bmK7sjGosr9? zgK^yl3r9GwQ7;>&T%A#Gv^TCGR#q;29-Rg^{HWwy?t^*4yKwttULNn?hxuBa(Z@zd zWo}UVUAa4)H?;{Ty;jho4tw4h3}^yg?p+dIhVf=!}~le z9C5iE0aK~Y=%WEkh~7FJR$_JAc`u7C-O7 z!V#BCKbRVIMjxlcoUhL4V;;<7>Wq5t!u&^_)Z_lVPF>K0YXmFndDM#Aw}gA!+qhiz z9D(0Uz`_xiOMjSQ>Wn_lfVn`O^ugo7Z7`3kGwQtu^O-uS$M@6gj!e#l=XIOIt@Ji7 zm)@gr-4P2%TrNXln$#J6Ooy4RPWoUj55YXI&Zze}%xZN~kNe9O^=p^Qu5dqj8<$Jr zXj~t{!V#CtIG8ik8GT#>bDKKpgSk8d^PW1R-fuALj!E9WZr->?u(F;yUXu3CUVyvQaz8vnD#$fy6a=ssCk#})9FNayB&gf&~CVUN|OWbo5 zTwY5sZ`|?pQkZMKi_7^jm>1OCm+dCvdM6f+a9*QcIm}V& zq#n;pCVJxvVrAvR>j%@|Movo3@51eqd6~;cFyE;&`q*r8=hXICIHKw?mxEy{ z)EV{0z)Vsn+sAsBd&7A-tXx`g`#iXYDapAkgn7ohs6Lp>r!YUMGy3@ZNq8THg(IpS z`#1uozdEDdIG9t^NiN)9uJnfUa#*==f4Ld%{F9S&c^BqC-bMAnT-G_Ib81U09HBG% z=n2zTo%F$6hQOSt&Zu`0%vI`)dXISHHV`W-msZ^VBHYENCg<`Y%vaup{mQ(|Wy8}t zr?$hw5jvxfgJAO2Nj>H=3}&J_quymO*Qt|w++QB|hTF#xmCJK*(@#&%<$ajXy$k!5 zd6~<4XW+Uc7LL#vee{OOQ7847%TSmWbw<5QVCJZkddy{kH{3pss9cu9oi{Z(mt`=Y zdKdO9^D>vt({Ozf3rFaTK6=0$p-$>Cm*Zf@sWa+b2y>-6smEL%_J-TX5tYkRaOeCp zIhVI!R(KcoEAuj!PG{meAr_9%8GRf8bErD0$6Stv8LQ5ycRtK4byAPHJm3wtk0UCV z#c*eym7L4#Fdups_AB!;mp@@PJv%v5P z%H?smspll;@+!>x-o@qeJIqGsCg-vjOmB742Xh$!Gg6(A%ULj&sFQlk;{!V3v6om&-3O>z|jL%kD5e)JY%Ar5dJIosr8lmK*5eD~OeqODk?42iNnmVBWar<#d?Y-i6yI^D>u*V3w*g`dA6`ojR$< z$9J>K@q2ApIKp|2dO0u^>Wq40U`|(O)SCk{Po31`^J}R$ZUeEha^~^xWw^^`Cg;2g z<~Q%ceq~49p~T(g$<79A=(6qux@O z*VIWpZr^v_;7d26a_Mv}u8(8kh|6V{>+rgdg(EJPa+u@P8GW1tbGAC^gSp%Y^RPOj z-kUHVtCM=nC3St!1Ha_3a%siwUEp5xHZGT4Z@~KnEF5vURKN^TXY_G0%sJ|$59V?c z%p>ZIdT+t3P$%{H{-e{}waaA_xL3T5%cbj$_`DPrj<{S(VUAH}^f4LcOm)%+bGZTL zL3KvG*I_YVxp3rAcoeQ)lZD#OANmrFg&6m>=)vtZ_` zlRlWsVwgA78TEdE`AeNqZ^v8KZhy&w`_bFDT=H+l&xx@l<<{;yw{f}T+=kZ~EF5wB%NUrG)fs)vhPg?d zkxMJgTk4E@t6@6b9>0CeWhZZ3BUnY{vJc!UZ{u<~Vm>}^frTS3mr*d2)fs)vgtHol);Am|xUMJ?662J!_ZCE^sTojmxF?y?Eb)g(EJPp)gJAj6SBr%vL9T zFqem5o>yno`y6JqI;qE8wzzNYa@h&)V{hYf>2W`<4`Jbm%jGzj26aXs=fTWWCw(xN z`(d6@XVm)?=6iKgkGXVtVC{0*0qz5D<8nFRLHzs;3rAcoN5j;sGx|6O=2CUi2Xnax z=4o|Cy%jLusFQlkWs`^2E|+cL-t#stmwg|`^>Hj5ak&hF8KKVT<4l-~)kz=BvmGrfz; z`TsC?9&l1r+4pZ?1`q@0>Z?wXbVIq$w#)ph$;b>sYC{*O=9Txz~`UcGy6zpknd^B9<^nlr}n z5twf@r^dlNFZT@I2Ze<#>etZQ3Cuq=r}S8VM|s8xVwIMcI&j-QTRJc2fw|0c(ebH% zd0*gRFjF*VjN=0^3pA(nn3rXq!}n!iVT<}T^tK1Hhvt+X^D@XYP7tfKyc`E^tI4JF zat@e_Jr^CH>X&(W0L-(RGsf{QnE9Ghddy4nDR{pW7PhEgL$3>%8qFy^=H+nDI6hXRlENoG~hThg-sx_zd zn3ukuae`P`d6|Ok$AH^(YU#Y324<}1qT^HjGB0<4nV>mi9B+V`r#Yp^y!;7fElrPk zsRDC=<_x_NV9wB-$_w?b_YC`Gv+~j&d3gxj8#7AhrTvTeUSce4Y2#qM><#8H%^Bl3 z4a`{08RNJE%#)fk^yYy1M018-)0bonZXj4$d07p4SsmOaFPF~CsbJ3YTvlFg2lKe* zjB&gU<^#2%_%+3yLWj8p=(xNcpv>SaM%2&bY8vy z^FPmJR~*VDVbgX?%KY*~332Ifr78RNJC%-xzZ#xWhtT+JDJ zzksQnn|*xD^9G)A1HmdSFWZ7!_ubNY83N`c&t>K1N-%e5&KSp3Ff%o0U`+CL+VrA7!J+==6x8=Ojc{v-*g`SI!&*=9)Fi&gF7{@zcKGU4i zW8GJLh|g_fVT<}T^tJ)Bi{_Lb=iPpuae`Q-X&}p4Q7(& zjB&gL=3~t%J?5p!$M_r{7PhEgL$5QKoi(TQn3qF6;{>s?^1|zY!QhVjq;y`UfO*w( z(ebH%nU@7%e$$*WjzJfk^7Z!Vb6HD~Bm&X+N`fna6j zh1b(-f$R81>Aai)=6ug(<>f9g6E$ay<4rIhY0el&?n}IX5(`_@uc5akn4L6d==Jf8 z6U55O%Pz>vaBz<-D4mz4U*U5dSlFWDQ~k1DHU+bT=8SP14CV;UDLvNxIbg2VoS`=X z%=4Nv^yYbn<6yJ$QjhKb1^2|)rSsC_8+^|R7PhRsYyqZPbH+IOf;mQW#yG}-xj}P= z-cw+vYfkBL-u=`wZXj5t<>fnYk9}J@FBJ=uHGORdY&@dHKjQ90!|~7k&@!H{jm;u5?~D`ySVWSlF`i(hJOynlr{R2FxXz zQ{!M>9t2abIYaM5FkfrV&|CHg8G{=LR%v-zAKVK6EuELcz#Q$lth|f`bG7D-aZCX7 zyylE?%medZ%^7+t{}10!jfE}k_?YJ%JmWyDti14gx(B$ee=MDsF<>t7Tw1@JcOL}v zoaT&iya(nB%^7)V@e{tM0}ET!uc6l!%x;=9^agmw31VgCp2Y2!BrSmcm%vYXE8wdMs^#@*0#=;hH#yGlwsnMJo2lH|`m=iQ-=v@xxX3ZIT z&w9okAXZjh>al$mxGVlFotIC+eCN4nysBU3rS&3wjs*)_#2Mq*5llDDDLv-pNHC{r z&d|FC%6onhbsvHG#&gklRlm&3a!o38>tbPxIAa{! zf!SSiN{@LN2<9Zs8G2WOxm9yYk9nEw86F>7T3%iOcTv;QdHDd$0?$R`RsAwA%QUOZ zt%Zdx;*4=@3uaf%DLv+;KbVo4GxRP4bCc$j9`o{yXLx*UX?b}O+yxb-^YSj3`JRi$ ztNLYLnpallR>#5?amF~d0#l_qrN_J+24;lj484oNT(3E$$Gkl086F>7T3%iNH?Dc< zyu1zOQ_n@?RsAwA&019ER>8s+amF~d0JEd!lpgbP2$*4-GxWxTxkhtJk9m2*Gdw=F zw7k@VJGW)&yu1nKBhN+SRsAwAxn(MID`H`bIAa_g!EC2FrN_MV1~Wu+hTi#LuGE~; zV_qKf43Cd3EiaS7jc!#sFRz37z;n@fRlm&3A7GYWwsc-L0kf^9l&g*IW-REWj`=SXwJyX zIbbfy%*#Gt258R6 z%UNK?YfkAgFZX&TD=*98e%%w`>Q^kCmsM7(%&m`wEh{fOg4s)R#yE}vbE4+dIGC3! zz}&4lLvK2m*EMJ8edifB5UkQ3N0lpA=4N1F%Q~-HbCt?mdn{~OdD#Wbews7JF&xZk znlr|6Etm&1XXw2GW{&2R9_!^t&$xkLW#wfWwl`h1GB+IyTh{yP+pbob+YAd^R$lf5 zbBN}QahwchjONrhSTDDMc|voB-fS=*YR=GG1ZI`h)i?~jEx_!kIi<%sI>a-~3tL*A z2Y~CaM(I4C4dz16W##!kFi&gF7{@zcKGU2U2lHI9W@Tk9j@_%(0p?^zvY?(wx%c*YDm@c7uQ zywqd+%iu0tzjR*S2lJ)pqVcMJ=|{^pm|w84MVv8?ZNTiJIi<(E^aE3;IYaMKFgI#W z=`k-)dxpoymX?02D7u~lpgbPD463k zXXsr7<~q$OJ?3SSXLx*UX?d9jZtMo7^D+m_C!UMOtNLYLnzpaZt&D{&;*4>00<(kW zlpgbPFqom5GxRP1bG7D_9`iE6Gdw=Fw7fhIZp?->h^K!puO66q|xYIT%otIa@%<)`SUVa4AeACi- zX%D88=F~Wtm%YIpt~nzwqrhCCIi<(E+~b*2d6@w2FJ(rc2AHX#0SUN9l z!EB~EH4f%wPcVHoXXNE{Fyl0*^q7}BJyR+#kAgd4^U`^F0n9AVW#wfdnNFqi@;5LW zYfg=Wd8q}{M{`DAP62bS=9C`u@-NSn%F9FGj^CnmUh2WT=DDoAd=2Ig%^BlZXUodm zKd`W+=`k<6fjLNXhTe%_Mr+Q<%PpR99b=XDd~`p!;hjt8WipsoJeM{OK2LuM=2y)b z<5+Vm+;76dmZrzN>;k5z<_x_$FrzeQ zaWF4GfN8dk8m}>qwqQ2XoEnFlU%>R$oS}C*m~omj^zH=nl;#Y*x50d>Ii<(@56!lf zu_AOWEziq>o9WrCJa60u=Py{;vhsWYn1Pxz#&I^73pJ<4!93pwX0qlCz4yU*k;p|>5F-8HB5nCF3>ae`Q-<#`CWEw+<>v+|q=bCu_^^87fMX__;}@iCZh zHK)eGJTJd}Wv(q2wy0l2Z)Y%jYR=Fb4CZvr8G6@&xl?mWk9nTv8FzqKS$X~#+g}Cu z&<-+=tov}e9dX`{g)JJd>X-Az#$dM7oH35xU!vhvaeOs(dOaU20=gyz&ZST7fY`IqJl zz30LFTXTlqS7dfk<1qC824-W;DLp>EYCXfeuvvNLec&G8+U_d-W<4&C19Q6PvhsW# zn0qy6jN?Txvo)v2!94!}rbSKZyle<&3(YA#&Kvu92BB+ddFczT({82nG78KEp3BP1 zJz$>HoROC~U_Q~D8VB>zba%Wj2n$=(uc5aUm@3UFJ?7;w&p1J>ti04?`%rLO>>>ST zJudTLuJT-Td`7>IgPEo|V;moY`BrmEk9k?X7WIsUE$Y|M+ZoKBnltnUgE?JuhTe5x z?$n&pbI+HaaR-Q1TAp78cX7AUdHxd2kDiOhtNNwCtNs($67 zfElGZL+?f~_h`=0n*rus%^7;Xf@!{|8i&$jp4)qd<7Kn*{2I1z3hp=0X3c+lcCXC! z!on8iPxZ?@j|4MDbH+Gs1M{Hflpgc^Dwq#7XXq^gv+Q1_k8dN-a2#w_UY^7DuHb(5 zY*t=s_pZzxfQ2n9FC)O5tvO>HH-ouPb4FfX0`tD+487mMwA?5A_;_COch9(iU}fdy zDQw>o+}EDXn*a9bQJLEx3tLuRjstU+=8SRN1m<4N8F_gT%zK(M^nL@=V&ClJWBqLi zrmN-*y*y@cFfVLrc^(I@WF2q$ewpVpz+9*~V;uK^nW#AeRQgeo0%ifi_ zRk5(89Ute@Ej{BvtkUwb6SyV^mCnn)U=H^ZXQ; z>7Gj)2lMcEWBoEiu7awC{WG-v3| z1oN)u4832$tk7SL!_eClOc%{5J?6QmXArt(<+&ceISgFe!=>M>=b7WcobI`-JYNUq zUdT5KP6O(s^kIrlaPR9`n-OGg*0=ieL5yx9$<8^D+d?NuJBf z%avg6(43K%sbFSmPK|?k`36kWBTMI{4VXFVpbLp5WFwO8U)u{v8SC zEYD@-YR<^Zt6<*NoEiu7@)MY42ba#vMqswqoT0Zrm?Jf39N!o)muODuao%~* zGo|wU1h~_VE}iE$!F=SotUTwA!ROzwutl6Pj*eiq)0`Ry^V}QE5X~8S=YzRYbB5ky zU}k8}(EAL`_nK3B%=3yvWUL%7TiX1$Cb+qt&3azgWwyeDD4`zVo zjB%U=X1wOqIGC4v!91rqL+?E>UuaJ0F)uBKm(I&HaI1iuO-lFa2ia`7$s!c`hr@&wzPVbH+FpfcZ&tY8=e-YIT*ljj*sq{Th0EfZ1Pj zhTd^t#%RvayA8~Pnp1kr^Q)e52Z)uG=Xz|P4esiZGLEdr`Ft?{^;|Sw)i3A2l~1V5 zwZp;|amF~Rz;xG~(qo>F26Kky487~Y+@(3C$H(~#p5gJaS$W~-U1ov1?8MS}`54T% zo{Pq-`ek00KdCae9u~HUGsdw!m_0P7^q7}HU{2PYp?4LS+cc;2n3pM@;qkGh<>ggy z7oJ=?FYkl-(sR*xRlm$j%Tw@q7c6WMXN+STFuQ0@=`k<;z|?8Z(7P1Ojha(>%*)fB z;qkGh@Iit z8qFy^=H&^`@c7uQyiCLPdT?V;mvLmx;~#ee7 zw+|M!D1WM7=J{AKr)$m_$8})t)SS{|o~MC%TXTlqPhgszm3@5FYYS#;%^7<8gXya| zb$rb8>7GI8nw4js7moqg?QA)|tmn&Xz})V+tUT9)d0lhHIKBh(hvw8cn3r`%SLQay z!WQ*w=HT=dYpGY^9(}Q ztomb~zXA8~`K9ZxNgm$=goQ0FFRc4bz-+HMV;l#88KgNi4(4Svn5#5r=sgZ*isqCa z>+b{4Aau>j%QXCE0l0@Qknv{KU#szWKOq*jth{UmrbctdI1UFhRC8(^%*zE}Zq}Tk z_bix~G-v3|2lKn;48654tjzr#OV)TI+QAXZkMIsbJBxBNw-m-T#kD44;X%gXb4 zV6M`fF^hJ`Kd_*j42d&YrSS$V0)_C3J0x}+wCV zSlFWRs(zW5ZNcoJIb$4yz#OMJrN_Kn1m-r)8G2K|ys9}vZ-Hkx4mK+<)3ALJxT!bD zc(dlKzukz>?OdcT8N@g_A6L$4#4 z?KG$KIPdiKj7tnwX?gAkZo`{P=lM)9dCz6#`ED?iG-r(CEifNzPK|^0*W?y_Zx0r> zs9!^`Gnkz<#`IYb8ju3=Xqeh@?11t)h{3C zt!~446Bf3JGse*cOpWH09`k%Sm=iQ-=v@xxX3ZIT&w`nyIYVzDnBO(0^qA+h|0QGP zc-hkO+z#C5p3Ry!s&B{lZDL`I@~8S`o{s@@s^*MwTm$BI%_%+RxgN}0nltqN2d2p# z*~dq{^}%%3oT0Zbm_s$Ej*odh)iVfPv+`Vz-;4&g`<-%p+^@}wJ^FPt`n?j&t)9!u z^JFkHHD~C31LjxFsc|qbYu<(TEn#7c`Ze_a38ts!lpfEs>pbHGu}aI!C~&*pT{>F3 z;r-py!S%SebY5--bD!s;<5T@IFE4?4M{~wFeg;!U*+z4Q-T`3xX-?_! z_|EVQLf5Rk)Z;f7g4_50(s{WB%>ACr%FD}O=4#Fu$1h+iA1Ixd4Zv)xIYaM2F#R>B z^1^yK(=(D4yIz==Jh;6dES;Ad!QA7yth~$sGe>jAIDQ1v^r6yuX#-{}%^7<8fjLZb zMqWVUjoFG=#eEiM=^O5F^apWGu_iA8aOVeXs zHU_hk<_x_)V2;w9aeU``#&wKUT3)UMH~8_=d6@)en&;BS!MuD7<_FCg<5+0|?ssBg zOVeXswg*U@9i6@fzc3 z2d1Ou)Hs-z?qK?9&d@sp%=wyAdOW_nJcH0RD=)l%H4)snNu~4hHkeO6mz9@hPvU(j zSlA-Y7{?Z1cGR322lH|Wm|>bT^u~j^MsrG!d3nM!JU%unFZI|y9o+d(mCnmMU_SF) zG+v|Mil^~;KP+q!XN+S@Fgs~Z=`k;Tzzo-%p?4veYc;3zIPXsM43Ce^$_wY+so<`9 zrgUCD2lIpHqVcMJ>BmaX;&V1w*dopt$If8()SS{|UIv3XU2}%sbztt)oYLd*P4f(o zk1Z`Pv%%fn&KO4zFnu(q^q7}Zz+9*~L+?H?6E&ywn3p#_ z!fPQlcto;%QDa7z7H0*s1A&NJA>I(bH+IOgE>}nN{@NTgSkm_hTbz^Ueuh@ zV_rV@49CG{<>gas{|Vf?^`-N&=~R5K4GUXVUV4H#LUYDA&H;0==F~Wtmj}Q+uQ@|+ z9+CSz~|!OF@D|DNmLz%Bnm>AV~YX0Ye7@^T)St2Aef<8d%kG-r(C128{m z&d^(FI?ji%u%#Uz^Sr%h9Eg>bmrt>MA8=dED4mycz+CLPw0>Eq4}f`AbH+H{1v6iB zMqZk~i2IXR*rI+7y)IyCG-v1??inYDm6aDhADsZM+e@YMat)ZX&(`2lKk- zjB$Ji<`2y&J^H)O%Xohs7PhEgLvJrI2Wd{}@%T>kj1$Dl%FCzNejd0XuawTq(_m(J zE;>G=-_OAOs5xUCtG9DY+=`k-mf!R-UhTd>6r)f?dAN8*F4EtrX^1}J$0dP0` zyL4W@2J?&O(#AnQ)_4uC!(w5JIAa{Uf!SAc#yEz78Lc@(?-nrkYtGPn*)#3{v9j_~ zkL@3TyLD#iynGMlPtQf;RsAwA>;4D#W3jMBoH34ng6XL_rAL43z>L+Lp?3$EM>MDO zc)mN+Gdw;vD=)l0dKcXNvr6aX4=~HTuEwkSWnTUPW?Rh}<2VpZf6Xa9=H*N zdl<|!np1i_zPX-3=$e%m*2@BL54=%2FMon*HM?|PI)Le-Ib$3>!5pqRH4f%w6qw63 zXXrfw=2^`tJ=V*+o^eUR%E}AhzcwG--EWr8%P(Lm-zuG#4Zw8PoH34l!5peNH4f(G zR4^B5&d|Fb%p}bzJ?7;t&meTo$_t;TKL$5pPU*Zfe;a?F1PfaWA*r=7r5Y0enO zVPKBdoYG@n#)7$CbB5lNU|!Ii(&O=c;u(alS$Ua;-~1Qcq<3VzS+8HNG8f--f`u(B zFFS(SOLN9JjsbI`=F~Wtmn*>BtvN$)I+)irXXt$grt)1i4nuDPFq>;m>G5^Qy*$Ib zuvvNLe03nWHQ$qdvtGYE3QV2nvhsW>m|HbxjAJsGS2U-_!90Hn=1AZ{tbC&1Q`eohU1m;1_8RK{r%-fnX^70dyW#_5! z8hRUn*;;c-kH@#aXArt(<%RV!0Nmd{ES;AVz?|*5ti0R|<{`})U8J85Sth`La_I}_t{8;+Uny=0TllNR!UhW1nNpnVC-U9Qn z=F~WtmnNU!J`xtTs9!^`Gnkz zGxG8VnE9GB^qMcg`6L#$tmEtC83$rz<%Q?>Rp6R@RXQ*Gf;rT4S^b_0Ca*bT9Cw3x zTysWVUI+8J<_x{cukk&LSlH5zkIxI6d&YrSS$Ua;?c0<4M)b0t7Y+tTla zFqdo27{?=Ep4FU@mv_M|)SRKW!nc?wv9P5bA0L-pz;xG~p?5Tx6EvrekB_g*J;Q$4 ztUT9a`}N@ZE|lZTdR#sT<|)smje~i98_XA)Gse;4JG`!og)L2wdD#NYZkjXn27no+ zIh7aI-+0fkUp6Z*TVVS&;9l}<6Z}8z{fTdYndiB*aj@S%J%i9StKVJmn^xcBdJ79% zR=>T#4Dei9zx3lQ&p1J>tbYHA?U#U?>)EWw+txo+=BlxgyQ?V&(ch{P^R; z|M|01;eUKQYQ?I_9Tit$a-Al3tQ&MvUBT}LAU+cPzU2E}7XMH4t;>ILUV?=!YaEAr z#(`M5af}$)zpj7Sg3pp5JR007o^9&5s;Z8TYd<28?GaoE<`K_Hzu=N`xlO>$1oNBc zSO-($Cc)9-=FaJQn9e5^~?RodB%ZQS^ch$#9jgJv7be6 zJ#cCLzWEE@_l1QmtzY_<`&Af*Y*xQV!+=%6o$US0RaUi&(DnxHvaA|&A*t~h}S}bg7{c^k$J>x*EtbW(R z_Nn0B^DG~iu3z=IB=;SdRxPC81lRuLf%vs+t+DtBKpP?u8A3nIx@dJ

-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

Z)>@`-Di1v#%g6Jq1 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%0DMnEv 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%0ATUNE%&?QvYJr*)=RT)datF;)Ct$@J`E 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 T_xR_wr*(VE`+E191H}IiA{?7Y diff --git a/vendor/nvapi/nvHLSLExtns.h b/vendor/nvapi/nvHLSLExtns.h index 9394036dad..3b5d3a0a0c 100644 --- a/vendor/nvapi/nvHLSLExtns.h +++ b/vendor/nvapi/nvHLSLExtns.h @@ -1625,6 +1625,123 @@ uint4 NvWaveMultiPrefixExclusiveXOr(uint4 val, uint mask) return NvWaveMultiPrefixInclusiveXOr(val, mask); } + +//----------------------------------------------------------------------------// +//------------------------- DXR Micro-map Extension --------------------------// +//----------------------------------------------------------------------------// + +float3x3 NvRtTriangleObjectPositions() +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_TRIANGLE_OBJECT_POSITIONS; + + float3x3 ret; + ret[0][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[0][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[0][2] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][2] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][2] = asfloat(g_NvidiaExt.IncrementCounter()); + return ret; +} + +float3x3 NvRtMicroTriangleObjectPositions() +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_MICRO_TRIANGLE_OBJECT_POSITIONS; + + float3x3 ret; + ret[0][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[0][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[0][2] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][2] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][2] = asfloat(g_NvidiaExt.IncrementCounter()); + return ret; +} + +float3x2 NvRtMicroTriangleBarycentrics() +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_MICRO_TRIANGLE_BARYCENTRICS; + + float3x2 ret; + ret[0][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[0][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[1][1] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][0] = asfloat(g_NvidiaExt.IncrementCounter()); + ret[2][1] = asfloat(g_NvidiaExt.IncrementCounter()); + return ret; +} + +bool NvRtIsMicroTriangleHit() +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_IS_MICRO_TRIANGLE_HIT; + uint ret = g_NvidiaExt.IncrementCounter(); + return ret != 0; +} + +bool NvRtIsBackFacing() +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_IS_BACK_FACING; + uint ret = g_NvidiaExt.IncrementCounter(); + return ret != 0; +} + +#if __SHADER_TARGET_MAJOR > 6 || (__SHADER_TARGET_MAJOR == 6 && __SHADER_TARGET_MINOR >= 5) + +float3 NvRtMicroVertexObjectPosition(RaytracingAccelerationStructure AccelerationStructure, uint InstanceIndex, uint GeometryIndex, uint PrimitiveIndex, uint2 UV) +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_MICRO_VERTEX_OBJECT_POSITION; + g_NvidiaExt[index].src0u.x = InstanceIndex; + g_NvidiaExt[index].src0u.y = GeometryIndex; + g_NvidiaExt[index].src0u.z = PrimitiveIndex; + g_NvidiaExt[index].src0u.w = UV.x; + g_NvidiaExt[index].src1u.x = UV.y; + uint handle = g_NvidiaExt.IncrementCounter(); + float3 ret; + ret.x = asfloat(g_NvidiaExt.IncrementCounter()); + ret.y = asfloat(g_NvidiaExt.IncrementCounter()); + ret.z = asfloat(g_NvidiaExt.IncrementCounter()); + + RayQuery<0> rq; + rq.TraceRayInline(AccelerationStructure, 0, handle, (RayDesc)0); + + return ret; +} + +float2 NvRtMicroVertexBarycentrics(RaytracingAccelerationStructure AccelerationStructure, uint InstanceIndex, uint GeometryIndex, uint PrimitiveIndex, uint2 UV) +{ + uint index = g_NvidiaExt.IncrementCounter(); + g_NvidiaExt[index].opcode = NV_EXTN_OP_RT_MICRO_VERTEX_BARYCENTRICS; + g_NvidiaExt[index].src0u.x = InstanceIndex; + g_NvidiaExt[index].src0u.y = GeometryIndex; + g_NvidiaExt[index].src0u.z = PrimitiveIndex; + g_NvidiaExt[index].src0u.w = UV.x; + g_NvidiaExt[index].src1u.x = UV.y; + uint handle = g_NvidiaExt.IncrementCounter(); + float2 ret; + ret.x = asfloat(g_NvidiaExt.IncrementCounter()); + ret.y = asfloat(g_NvidiaExt.IncrementCounter()); + + RayQuery<0> rq; + rq.TraceRayInline(AccelerationStructure, 0, handle, (RayDesc)0); + + return ret; +} + +#endif + //----------------------------------------------------------------------------// //------------------------- DXR HitObject Extension --------------------------// //----------------------------------------------------------------------------// diff --git a/vendor/nvapi/nvShaderExtnEnums.h b/vendor/nvapi/nvShaderExtnEnums.h index cfa918b3e7..0913884176 100644 --- a/vendor/nvapi/nvShaderExtnEnums.h +++ b/vendor/nvapi/nvShaderExtnEnums.h @@ -114,6 +114,15 @@ #define NV_EXTN_OP_HIT_OBJECT_IS_NOP 84 #define NV_EXTN_OP_HIT_OBJECT_MAKE_NOP 85 +// Micro-map API +#define NV_EXTN_OP_RT_TRIANGLE_OBJECT_POSITIONS 86 +#define NV_EXTN_OP_RT_MICRO_TRIANGLE_OBJECT_POSITIONS 87 +#define NV_EXTN_OP_RT_MICRO_TRIANGLE_BARYCENTRICS 88 +#define NV_EXTN_OP_RT_IS_MICRO_TRIANGLE_HIT 89 +#define NV_EXTN_OP_RT_IS_BACK_FACING 90 +#define NV_EXTN_OP_RT_MICRO_VERTEX_OBJECT_POSITION 91 +#define NV_EXTN_OP_RT_MICRO_VERTEX_BARYCENTRICS 92 + //----------------------------------------------------------------------------// //-------------------- GET_SPECIAL subOpCode constants -----------------------// //----------------------------------------------------------------------------// diff --git a/vendor/nvapi/nvapi.h b/vendor/nvapi/nvapi.h index 9b4733b1b7..846ca2f636 100644 --- a/vendor/nvapi/nvapi.h +++ b/vendor/nvapi/nvapi.h @@ -41,7 +41,7 @@ /////////////////////////////////////////////////////////////////////////////// // -// Date: Apr 4, 2023 +// Date: Feb 1, 2024 // File: nvapi.h // // NvAPI provides an interface to NVIDIA devices. This file contains the @@ -338,6 +338,23 @@ typedef NV_EDID_V3 NV_EDID; //! \ingroup gpu NVAPI_INTERFACE NvAPI_GPU_GetEDID(NvPhysicalGpuHandle hPhysicalGpu, NvU32 displayOutputId, NV_EDID *pEDID); +//! \ingroup gpu + +//! Used in NvAPI_DISP_GetEdidData + +#define NV_EDID_DATA_SIZE_MAX 1024 //!< This is the current size supported by Nvidia Display Driver and may change in future. + +typedef enum +{ + NV_EDID_FLAG_DEFAULT = 0, //!< the EDID which is actively used by the driver, it could be _RAW/_COOKED/_FORCED/_INF. + NV_EDID_FLAG_RAW = 1, //!< the EDID which is not modified by the driver. If there's no _FORCED edid engaged, it + //!< will be the unmodified monitor EDID from the I2C bus. Otherwise it is original _FORCED edid. + NV_EDID_FLAG_COOKED = 2, //!< the EDID has been modified by the driver for compatibility + NV_EDID_FLAG_FORCED = 3, //!< the EDID is forced by the end-user over s/w interface, + NV_EDID_FLAG_INF = 4, //!< the EDID is from monitor INF + NV_EDID_FLAG_HW = 5, //!< the EDID is from the monitor over I2C bus without any modification. +} NV_EDID_FLAG; + //! \ingroup gpu //! Used in NV_GPU_CONNECTOR_DATA typedef enum _NV_GPU_CONNECTOR_TYPE @@ -4218,6 +4235,329 @@ typedef NV_LICENSABLE_FEATURES_V4 NV_LICENSABLE_FEATURES; NVAPI_INTERFACE NvAPI_GPU_GetLicensableFeatures(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NV_LICENSABLE_FEATURES *pLicensableFeatures); +#define NVAPI_NVLINK_COUNTER_MAX_TYPES 32 +#define NVAPI_NVLINK_MAX_LINKS 32 + +//! \ingroup nvlink +//! @{ +//! Used in NvAPI_GPU_NVLINK_GetCaps() + +/* caps format is byte_index:bit_mask */ +#define NVAPI_NVLINK_CAPS_SUPPORTED 0x00000001 //!< Set if NVLink is present and supported on this GPU.This field is used for *global* caps only and NOT for per-link caps +#define NVAPI_NVLINK_CAPS_P2P_SUPPORTED 0x00000002 //!< Set if P2P over NVLink is supported on this GPU. +#define NVAPI_NVLINK_CAPS_SYSMEM_ACCESS 0x00000004 //!< Set if sysmem can be accessed over NVLink on this GPU. +#define NVAPI_NVLINK_CAPS_P2P_ATOMICS 0x00000008 //!< Set if P2P atomics are supported over NVLink on this GPU. +#define NVAPI_NVLINK_CAPS_SYSMEM_ATOMICS 0x00000010 //!< Set if sysmem atomic transcations are supported over NVLink on this GPU. +#define NVAPI_NVLINK_CAPS_PEX_TUNNELING 0x00000020 //!< Set if PEX tunneling over NVLink is supported on this GPU. +#define NVAPI_NVLINK_CAPS_SLI_BRIDGE 0x00000040 //!< Set if SLI over NVLink is supported on this GPU. +#define NVAPI_NVLINK_CAPS_SLI_BRIDGE_SENSABLE 0x00000080 //!< This bit is set if capable of sensing SLI bridges. +#define NVAPI_NVLINK_CAPS_POWER_STATE_L0 0x00000100 //!< This bit is set if L0 is a supported power state on this GPU. +#define NVAPI_NVLINK_CAPS_POWER_STATE_L1 0x00000200 //!< This bit is set if L1 is a supported power state on this GPU. +#define NVAPI_NVLINK_CAPS_POWER_STATE_L2 0x00000400 //!< This bit is set if L2 is a supported power state on this GPU. +#define NVAPI_NVLINK_CAPS_POWER_STATE_L3 0x00000800 //!< This bit is set if L3 is a supported power state on this GPU. + +#define NVAPI_NVLINK_CAPS_VALID 0x00001000 //!< Set if this link is supported on this GPU.This field is used for *per-link* caps only and NOT for global caps. + +#define NVAPI_NVLINK_CAPS_NVLINK_VERSION_INVALID (0x00000000) +#define NVAPI_NVLINK_CAPS_NVLINK_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_CAPS_NVLINK_VERSION_2_0 (0x00000002) + +#define NVAPI_NVLINK_CAPS_NCI_VERSION_INVALID (0x00000000) +#define NVAPI_NVLINK_CAPS_NCI_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_CAPS_NCI_VERSION_2_0 (0x00000002) + +typedef struct +{ + NvU32 version; //!< Version of this structure. Must always be first element in this structure. + NvU32 capsTbl; //!< This is bit field for getting different global caps.The individual bitfields are specified by NVAPI_NVLINK_CAPS_* + NvU8 lowestNvlinkVersion; //!< This field specifies the lowest supported NVLink version for this GPU. + NvU8 highestNvlinkVersion; //!< This field specifies the highest supported NVLink version for this GPU. + NvU8 lowestNciVersion; //!< This field specifies the lowest supported NCI version for this GPU. + NvU8 highestNciVersion; //!< This field specifies the highest supported NCI version for this GPU. + NvU32 linkMask; //!< This field provides a bitfield mask of NVLink links enabled on this GPU. +}NVLINK_GET_CAPS_V1; + +typedef NVLINK_GET_CAPS_V1 NVLINK_GET_CAPS; +#define NVLINK_GET_CAPS_VER1 MAKE_NVAPI_VERSION(NVLINK_GET_CAPS_V1, 1) + +#define NVLINK_GET_CAPS_VER NVLINK_GET_CAPS_VER1 +//! @} +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_GPU_NVLINK_GetCaps +// +//! DESCRIPTION: This function returns the NVLink capabilities supported by the GPU. +//! SUPPORTED OS: Windows 7 and higher +//! +//! +//! \since Release: 361 +//! +//! \param [in] hPhysicalGpu GPU selection +//! +//! \param [in,out] NVLINK_GET_CAPS This structure contains the output parameters. +//! Also need to specify the version. +//! +//! \retval ::NVAPI_INVALID_USER_PRIVILEGE - The caller does not have administrative privileges +//! +//! \return This API can return any of the error codes enumerated in +//! #NvAPI_Status. If there are return error codes with specific +//! meaning for this API, they are listed below. +//! +//! \ingroup nvlink +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_GPU_NVLINK_GetCaps(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NVLINK_GET_CAPS *capsParams); + + +//! \ingroup nvlink +//! @{ +//! Used in NvAPI_GPU_NVLINK_GetStatus() + +#define NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_NONE (0x00000000) +#define NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_PCI (0x00000001) +#define NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_UUID (0x00000002) + +typedef enum _NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE +{ + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_EBRIDGE, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_NPU, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_GPU, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_SWITCH, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_TEGRA, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_NONE, + NVAPI_NVLINK_DEVICE_INFO_DEVICE_UUID_INVALID, +} NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE; + +typedef struct +{ + NvU32 deviceIdFlags; //!< ID Flags, Bitmask that specifies which IDs are valid for the GPU. Refer NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_* for possible values. + //!< If NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_PCI is set, PCI information is valid. + //!< If NVAPI_NVLINK_DEVICE_INFO_DEVICE_ID_FLAGS_UUID is set, UUID is valid. + NvU16 domain; //!< domain, bus, device, function, pciDeviceId : PCI information for the GPU. + NvU16 bus; + NvU16 device; + NvU16 function; + NvU32 pciDeviceId; + NvU64 deviceType; //!< GPU Type. See NVAPI_NVLINK_DEVICE_INFO_DEVICE_TYPE_* for possible values. + NvU8 deviceUUID[16]; //!< GPU UUID +}NVLINK_DEVICE_INFO_V1; + +typedef enum _NVAPI_NVLINK_STATUS_LINK_STATE +{ + NVAPI_NVLINK_STATUS_LINK_STATE_UNKNOWN, + NVAPI_NVLINK_STATUS_LINK_STATE_INIT, + NVAPI_NVLINK_STATUS_LINK_STATE_HWCFG, + NVAPI_NVLINK_STATUS_LINK_STATE_SWCFG, + NVAPI_NVLINK_STATUS_LINK_STATE_ACTIVE, + NVAPI_NVLINK_STATUS_LINK_STATE_FAULT, + NVAPI_NVLINK_STATUS_LINK_STATE_RECOVERY, + NVAPI_NVLINK_STATUS_LINK_STATE_RECOVERY_AC, + NVAPI_NVLINK_STATUS_LINK_STATE_RECOVERY_AX, + NVAPI_NVLINK_STATUS_LINK_STATE_INVALID = 0xFFFFFFFF, +}NVAPI_NVLINK_STATUS_LINK_STATE; + +typedef enum _NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE +{ + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_UNKNOWN, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_HIGH_SPEED_1, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_LOW_POWER, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_TRAINING, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_SAFE_MODE, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_OFF, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_TEST, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_FAULT, + NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE_INVALID = 0xFF, +}NVAPI_NVLINK_STATUS_SUBLINK_RX_STATE; + +typedef enum _NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE +{ + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_UNKNOWN, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_HIGH_SPEED_1, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_LOW_POWER, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_TRAINING, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_SAFE_MODE, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_OFF, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_TEST, + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_FAULT, + + NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE_INVALID= 0xFF, +} NVAPI_NVLINK_STATUS_SUBLINK_TX_STATE; + + +#define NVAPI_NVLINK_STATUS_PHY_NVHS (0x00000001) +#define NVAPI_NVLINK_STATUS_PHY_GRS (0x00000002) +#define NVAPI_NVLINK_STATUS_PHY_INVALID (0x000000FF) + +#define NVAPI_NVLINK_STATUS_NVLINK_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_STATUS_NVLINK_VERSION_2_0 (0x00000002) +#define NVAPI_NVLINK_STATUS_NVLINK_VERSION_INVALID (0x000000FF) + +#define NVAPI_NVLINK_STATUS_NCI_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_STATUS_NCI_VERSION_2_0 (0x00000002) +#define NVAPI_NVLINK_STATUS_NCI_VERSION_INVALID (0x000000FF) + +#define NVAPI_NVLINK_STATUS_NVHS_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_STATUS_NVHS_VERSION_INVALID (0x000000FF) + +#define NVAPI_NVLINK_STATUS_GRS_VERSION_1_0 (0x00000001) +#define NVAPI_NVLINK_STATUS_GRS_VERSION_INVALID (0x000000FF) + +#define NVAPI_NVLINK_STATUS_CONNECTED_TRUE (0x00000001) +#define NVAPI_NVLINK_STATUS_CONNECTED_FALSE (0x00000000) + +#define NVAPI_NVLINK_STATUS_LOOP_PROPERTY_LOOPBACK (0x00000001) +#define NVAPI_NVLINK_STATUS_LOOP_PROPERTY_LOOPOUT (0x00000002) +#define NVAPI_NVLINK_STATUS_LOOP_PROPERTY_NONE (0x00000000) + +#define NVAPI_NVLINK_STATUS_REMOTE_LINK_NUMBER_INVALID (0x000000FF) + +#define NVAPI_NVLINK_REFCLK_TYPE_INVALID (0x00) +#define NVAPI_NVLINK_REFCLK_TYPE_NVHS (0x01) +#define NVAPI_NVLINK_REFCLK_TYPE_PEX (0x02) + + +typedef struct +{ + NvU32 capsTbl; //!< This is bit field for getting different global caps.The individual bitfields are specified by NVAPI_NVLINK_CAPS_*. + NvU8 phyType; //!< This field specifies the type of PHY (NVHS or GRS) being used for this link. + NvU8 subLinkWidth; //!< This field specifies the no. of lanes per sublink. + NvU32 linkState; //!< This field specifies the current state of the link.See NVAPI_NVLINK_GET_NVLINK_STATUS_LINK_STATE_* for possible values. + NvU8 rxSublinkStatus; //!< This field specifies the current state of RX sublink.See NVAPI_NVLINK_GET_NVLINK_STATUS_SUBLINK_RX_STATE_* for possible values. + NvU8 txSublinkStatus; //!< This field specifies the current state of TX sublink.See NVAPI_NVLINK_GET_NVLINK_STATUS_SUBLINK_TX_STATE_* for possible values. + NvU8 nvlinkVersion; //!< This field specifies the NVLink version supported by the link. + NvU8 nciVersion; //!< This field specifies the NCI version supported by the link. + NvU8 phyVersion; //!< This field specifies the version of PHY being used by the link. + NvU32 nvlinkCommonClockSpeedMhz; //!< This field gives the value of nvlink common clock in MHz. + NvU32 nvlinkRefClkSpeedMhz; //!< This field gives the value of nvlink refclk clock in MHz. + NvU8 nvlinkRefClkType; //!< This field specifies whether refclk is taken from NVHS reflck or PEX refclk for the current GPU.See NVAPI_NVLINK_REFCLK_TYPE_INVALID* for possible values. + NvU32 nvlinkLinkClockMhz; //!< This field gives the actual clock/speed at which links is running in MHz. + NvU32 connected:1 ; //!< This field specifies if any device is connected on the other end of the link. + NvU32 reserved:31; //!< Reserved for future use. + NvU8 loopProperty; //!< This field specifies if the link is a loopback/loopout link. See NVAPI_NVLINK_STATUS_LOOP_PROPERTY_* for possible values. + NvU8 remoteDeviceLinkNumber; //!< This field specifies the link number on the remote end of the link. + NVLINK_DEVICE_INFO_V1 remoteDeviceInfo; //!< This field stores the GPU information for the remote end of the link +}NVLINK_LINK_STATUS_INFO_V1; + +typedef struct +{ + NvU32 capsTbl; //!< This is bit field for getting different global caps.The individual bitfields are specified by NVAPI_NVLINK_CAPS_*. + NvU8 phyType; //!< This field specifies the type of PHY (NVHS or GRS) being used for this link. + NvU8 subLinkWidth; //!< This field specifies the no. of lanes per sublink. + NvU32 linkState; //!< This field specifies the current state of the link.See NVAPI_NVLINK_GET_NVLINK_STATUS_LINK_STATE_* for possible values. + NvU8 rxSublinkStatus; //!< This field specifies the current state of RX sublink.See NVAPI_NVLINK_GET_NVLINK_STATUS_SUBLINK_RX_STATE_* for possible values. + NvU8 txSublinkStatus; //!< This field specifies the current state of TX sublink.See NVAPI_NVLINK_GET_NVLINK_STATUS_SUBLINK_TX_STATE_* for possible values. + NvU8 nvlinkVersion; //!< This field specifies the NVLink version supported by the link. + NvU8 nciVersion; //!< This field specifies the NCI version supported by the link. + NvU8 phyVersion; //!< This field specifies the version of PHY being used by the link. + NvU32 nvlinkCommonClockSpeedMhz; //!< This field gives the value of nvlink common clock in MHz. + NvU32 nvlinkRefClkSpeedMhz; //!< This field gives the value of nvlink refclk clock in MHz. + NvU8 nvlinkRefClkType; //!< This field specifies whether refclk is taken from NVHS reflck or PEX refclk for the current GPU.See NVAPI_NVLINK_REFCLK_TYPE_INVALID* for possible values. + NvU32 nvlinkLinkClockMhz; //!< This field gives the actual clock/speed at which links is running in MHz. + NvU32 connected:1 ; //!< This field specifies if any device is connected on the other end of the link. + NvU32 reserved:31; //!< Reserved for future use. + NvU8 loopProperty; //!< This field specifies if the link is a loopback/loopout link. See NVAPI_NVLINK_STATUS_LOOP_PROPERTY_* for possible values. + NvU8 remoteDeviceLinkNumber; //!< This field specifies the link number on the remote end of the link. + NVLINK_DEVICE_INFO_V1 remoteDeviceInfo; //!< This field stores the device information for the remote end of the link + NvU8 localDeviceLinkNumber; //!< This field specifies the link number on the local end of the link. + NVLINK_DEVICE_INFO_V1 localDeviceInfo; //!< This field stores the device information for the local end of the link. + NvU32 nvlinkLineRateMbps; //!< Bit rate at which bits toggle on wires in megabits per second. + NvU32 reservedEx[8]; //!< Reserved for future use to avoid versioning. +}NVLINK_LINK_STATUS_INFO_V2; + +typedef struct +{ + NvU32 version; //!< Version of this structure. Must always be first element in this structure. + NvU32 linkMask; //!< This parameter specifies for which links we want the status. + NVLINK_LINK_STATUS_INFO_V1 linkInfo[NVAPI_NVLINK_MAX_LINKS]; //!< This structure stores the per-link status of different NVLink parameters. The link is identified by the index. +}NVLINK_GET_STATUS_V1; + +typedef struct +{ + NvU32 version; //!< Version of this structure. Must always be first element in this structure. + NvU32 linkMask; //!< This parameter specifies for which links we want the status. + NVLINK_LINK_STATUS_INFO_V2 linkInfo[NVAPI_NVLINK_MAX_LINKS]; //!< This structure stores the per-link status of different NVLink parameters. The link is identified by the index. +}NVLINK_GET_STATUS_V2; + + +typedef NVLINK_GET_STATUS_V2 NVLINK_GET_STATUS; +#define NVLINK_GET_STATUS_VER1 MAKE_NVAPI_VERSION(NVLINK_GET_STATUS_V1, 1) +#define NVLINK_GET_STATUS_VER2 MAKE_NVAPI_VERSION(NVLINK_GET_STATUS_V2, 2) + +#define NVLINK_GET_STATUS_VER NVLINK_GET_STATUS_VER2 +//! @} +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_GPU_NVLINK_GetStatus +// +//! DESCRIPTION: This function returns the NVLink status. +//! SUPPORTED OS: Windows 7 and higher +//! +//! +//! \since Release: 361 +//! +//! \param [in] hPhysicalGpu GPU selection +//! +//! \param [in,out] NVLINK_GET_STATUS This structure contains the input and output parameters. +//! linkMask is the input param while others are output parameters. +//! Also need to specify the version. +//! +//! \retval ::NVAPI_INVALID_USER_PRIVILEGE - The caller does not have administrative privileges +//! +//! \return This API can return any of the error codes enumerated in +//! #NvAPI_Status. If there are return error codes with specific +//! meaning for this API, they are listed below. +//! +//! \ingroup nvlink +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_GPU_NVLINK_GetStatus(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NVLINK_GET_STATUS* statusParams); + + +typedef struct _NV_GPU_INFO_V1 +{ + NvU32 version; //!< Structure Version. + NvU32 bIsExternalGpu:1; //!< This flag is set for external GPU. + NvU32 reserved:31; //!< Reserved for future use +} NV_GPU_INFO_V1; + +typedef struct _NV_GPU_INFO_V2 +{ + NvU32 version; //!< Structure Version. + NvU32 bIsExternalGpu:1; //!< This flag is set for external GPU. + NvU32 reserved0:31; //!< Reserved for future use + NvU64 reserved1; //!< Reserved for future use + NvU32 rayTracingCores; //!< Number of "Ray Tracing Cores" supported by the GPU. + NvU32 tensorCores; //!< Number of "Tensor Cores" supported by the GPU. + NvU32 reserved2[14]; //!< Reserved for future use. +} NV_GPU_INFO_V2; + +#define NV_GPU_INFO_VER1 MAKE_NVAPI_VERSION(NV_GPU_INFO_V1, 1) +#define NV_GPU_INFO_VER2 MAKE_NVAPI_VERSION(NV_GPU_INFO_V2, 2) +#define NV_GPU_INFO_VER NV_GPU_INFO_VER2 +typedef NV_GPU_INFO_V2 NV_GPU_INFO; + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_GPU_GetGPUInfo +// +//! DESCRIPTION: This API will return NVIDIA GPU related information. +//! +//! SUPPORTED OS: Windows 7 and higher +//! +//! +//! TCC_SUPPORTED +//! +//! \since Release: 400 +//! +//! \param [in,out] pGpuInfo - This structure will be filled with required information. +//! +//! \return This API can return any of the error codes enumerated in +//! #NvAPI_Status. If there are return error codes with specific +//! meaning for this API, they are listed below. +//! +//! \ingroup gpu +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_GPU_GetGPUInfo(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NV_GPU_INFO *pGpuInfo); + + typedef struct _NV_GPU_VR_READY_V1 { @@ -4253,6 +4593,53 @@ typedef NV_GPU_VR_READY_V1 NV_GPU_VR_READY; /////////////////////////////////////////////////////////////////////////////// NVAPI_INTERFACE NvAPI_GPU_GetVRReadyData(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NV_GPU_VR_READY *pGpuVrReadyData); + +//! \ingroup gpu +#define NVAPI_GPU_MAX_BUILD_VERSION_LENGTH (0x0000040) + +//! \ingroup gpu +//! Used in NvAPI_GPU_GetGspFeatures(). +typedef struct _NV_GPU_GSP_INFO_V1 +{ + NvU32 version; //!< [in] Structure version + NvU8 firmwareVersion[NVAPI_GPU_MAX_BUILD_VERSION_LENGTH]; //!< [out] Contains GSP firmware version + NvU32 reserved; //!< Reserved for future use +} NV_GPU_GSP_INFO_V1; + +//! \ingroup gpu +//! Macro for constructing the version field of NV_GPU_GSP_INFO_V1 +#define NV_GPU_GSP_INFO_VER1 MAKE_NVAPI_VERSION(NV_GPU_GSP_INFO_V1, 1) +#define NV_GPU_GSP_INFO_VER NV_GPU_GSP_INFO_VER1 +typedef NV_GPU_GSP_INFO_V1 NV_GPU_GSP_INFO; + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_GPU_GetGspFeatures +// +//! DESCRIPTION: If the device has GSP running, this function populates firmwareVersion field +//! with GSP firmware version and returns NVAPI_OK +//! Otherwise returns NVAPI_NOT_SUPPORTED +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! TCC_SUPPORTED +//! +//! \since Release: 550 +//! +//! \param [in] hPhysicalGpu GPU selection +//! \param [out] pGspInfo GSP firmware version +//! +//! \retval NVAPI_INVALID_ARGUMENT pMemoryInfo is NULL +//! \retval NVAPI_OK call successful +//! \retval NVAPI_API_NOT_INTIALIZED nvapi not initialized +//! \retval NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE hPhysicalGpu was not a physical GPU handle +//! \retval NVAPI_INCOMPATIBLE_STRUCT_VERSION NV_GPU_GSP_INFO structure version mismatch +//! \retval NVAPI_NOT_SUPPORTED GSP is not running/supported on this device +//! \ingroup gpu +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_GPU_GetGspFeatures(__in NvPhysicalGpuHandle hPhysicalGpu, __inout NV_GPU_GSP_INFO *pGspInfo); + //! Used in NvAPI_GPU_GetPerfDecreaseInfo. //! Bit masks for knowing the exact reason for performance decrease typedef enum _NVAPI_GPU_PERF_DECREASE @@ -4378,8 +4765,7 @@ typedef NV_GPU_PERF_PSTATES_INFO_V2 NV_GPU_PERF_PSTATES_INFO; // // FUNCTION NAME: NvAPI_GPU_GetPstatesInfoEx // -//! DESCRIPTION: This API retrieves all performance states (P-States) information. This is the same as -//! NvAPI_GPU_GetPstatesInfo(), but supports an input flag for various options. +//! DESCRIPTION: This API retrieves all performance states (P-States) information. //! //! P-States are GPU active/executing performance capability and power consumption states. //! @@ -8188,6 +8574,65 @@ NVAPI_INTERFACE NvAPI_DISP_SetDisplayConfig(__in NvU32 pathInfoCount, __in_ecoun +//! \ingroup dispcontrol +//! @{ +typedef struct _NV_EDID_DATA_V1 +{ + NvU32 version; //!< Structure version. + NvU8 *pEDID; //!< Pointer to EDID data. + NvU32 sizeOfEDID; //!< Size of EDID data. +} NV_EDID_DATA_V1; + +typedef struct _NV_EDID_DATA_V2 +{ + NvU32 version; //!< Structure version. + NvU8 *pEDID; //!< Pointer to EDID data. + NvU32 sizeOfEDID; //!< Size of EDID data. + NvU32 reserved[8]; //!< Reserved for future use. +} NV_EDID_DATA_V2; + +typedef NV_EDID_DATA_V2 NV_EDID_DATA; +#define NV_EDID_DATA_VER1 MAKE_NVAPI_VERSION(NV_EDID_DATA_V1, 1) +#define NV_EDID_DATA_VER2 MAKE_NVAPI_VERSION(NV_EDID_DATA_V2, 2) + +#define NV_EDID_DATA_VER NV_EDID_DATA_VER2 +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_DISP_GetEdidData +// +//! \code +//! DESCRIPTION: This API returns the EDID data for the specified display Id. +//! (NvAPI_GPU_GetConnectedDisplayIds() can be used to get the DisplayIds). +//! +//! USAGE: The caller has to call this API two times to fetch the required details as follows: +//! First Pass : Caller should call NvAPI_DISP_GetEdidData() with pEdidParams->pEDID set to NULL, +//! to get the size of the EDID buffer in pEdidParams->sizeOfEDID. +//! Second Pass: Allocate memory for the EDID buffer of the size - pEdidParams->sizeOfEDID, +//! and call the API again to get the EDID buffer populated. +//! +//! +//! \param [in] displayId - NVIDIA Display ID +//! \param [inout] pEdidParams - Pointer to the structure that contains - pointer to EDID buffer and its size +//! \param [inout] pFlag - The type of EDID to be retrieved (IN). +//! To only retrieve the EDID type, the user should send pEdidParams->pEDID as NULL and +//! pEdidParams->sizeOfEDID as 0. +//! +//! SUPPORTED OS: Windows 7 and higher +//! +//! +//! \since Release: 400 +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! NVAPI_INSUFFICIENT_BUFFER: Reallocate buffer with pEdidParams->sizeOfEDID and call again to get complete data. +//! In this case pEdidParams->pEDID contains undefined data. +//! This error occurs only when pEdidParams->pEDID is present. +//! \endcode +//! \ingroup dispcontrol +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_DISP_GetEdidData(__in NvU32 displayId, __inout NV_EDID_DATA *pEdidParams, __inout NV_EDID_FLAG *pFlag); +//! @} + typedef struct _NV_GET_ADAPTIVE_SYNC_DATA_V1 { NvU32 version ; //!< [in] structure version @@ -8518,6 +8963,89 @@ NVAPI_INTERFACE NvAPI_DISP_AcquireDedicatedDisplay(__in NvU32 displayId, __inout NVAPI_INTERFACE NvAPI_DISP_ReleaseDedicatedDisplay(__in NvU32 displayId); #endif // defined(__cplusplus) +//! SUPPORTED OS: Windows 11 and higher +//! +#if defined(__cplusplus) + +typedef struct _NV_MANAGED_DEDICATED_DISPLAY_METADATA +{ + NvU32 version; //!< [in] Version of this structure. + NvU32 displayId; //!< [in] DisplayId to identify the display connector the metadata operation is requested for. + NvU32 bSetPosition : 1; //!< [in] Set call: 1 in case the information in variables/fields "positionX" and "positionY" should be stored as metadata. 0 otherwise. + NvU32 bRemovePosition : 1; //!< [in] Set call: 1 in case the stored positionX and positionY metadata should be set to 'not defined', N/A. 0 otherwise. + NvU32 bPositionIsAvailable : 1; //!< [out] Query call: 1 in case the information in variables/fields "positionX" and "positionY" is valid (has been set before). 0 otherwise. + NvU32 bSetName : 1; //!< [in] Set call: 1 in case the information in variable/field "name" should be stored as metadata. 0 otherwise. + NvU32 bRemoveName : 1; //!< [in] Set call: 1 in case the stored name metadata should be set to 'not defined',N/A. 0 otherwise. + NvU32 bNameIsAvailable : 1; //!< [out] Query call: 1 in case the information in variable/field "name" is valid (has been set before). 0 otherwise. + NvU32 reserved : 26; //!< [in][out] Reserved for future use without adding versioning. + NvS32 positionX; //!< [in][out] Metadata for the virtual horizontal position for the display connector specified by displayId. + NvS32 positionY; //!< [in][out] Metadata for the virtual vertical position for the display connector specified by displayId. + NvAPI_ShortString name; //!< [in][out] Metadata for the virtual name of for the display connector specified by displayId. + //!< Valid characters are in the range of 32 ' ' (space) to 126 '~' (both included). +} NV_MANAGED_DEDICATED_DISPLAY_METADATA_V1; + +#define NV_MANAGED_DEDICATED_DISPLAY_METADATA_VER1 MAKE_NVAPI_VERSION(NV_MANAGED_DEDICATED_DISPLAY_METADATA_V1,1) +#define NV_MANAGED_DEDICATED_DISPLAY_METADATA_VER NV_MANAGED_DEDICATED_DISPLAY_METADATA_VER1 + +typedef NV_MANAGED_DEDICATED_DISPLAY_METADATA_V1 NV_MANAGED_DEDICATED_DISPLAY_METADATA; + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_DISP_GetNvManagedDedicatedDisplayMetadata +// +//! DESCRIPTION: This API returns metadata which has been set for the display connector in question. +//! Main use case would be to query the data for an Nvidia managed dedicated display. +//! The function will work for any valid displayId though. +//! +//! \since Release: 550 +//! +//! \param [in/out] pDedicatedDisplayMetadata Data structure containing input and output data. +//! +//! \retval ::NVAPI_OK The call succeeded. +//! \retval ::NVAPI_ERROR The call failed. +//! \retval ::NVAPI_NO_IMPLEMENTATION The API is not implemented in current driver. +//! \retval ::NVAPI_NOT_SUPPORTED The API is not supported on the current operating system or gpu. +//! \retval ::NVAPI_OUT_OF_MEMORY There wasn't sufficient memory to complete the call. +//! \retval ::NVAPI_INVALID_POINTER An invalid pointer was passed as an argument. +//! \retval ::NVAPI_API_NOT_INITIALIZED NvAPI was not initialized. +//! \retval ::NVAPI_INCOMPATIBLE_STRUCT_VERSION The version of the NV_MANAGED_DEDICATED_DISPLAY_METADATA structure is invalid. +//! +//! \ingroup gpu +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_DISP_GetNvManagedDedicatedDisplayMetadata(__inout NV_MANAGED_DEDICATED_DISPLAY_METADATA* pDedicatedDisplayMetadata); +#endif // defined(__cplusplus) + +//! SUPPORTED OS: Windows 11 and higher +//! +#if defined(__cplusplus) +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_DISP_SetNvManagedDedicatedDisplayMetadata +// +//! DESCRIPTION: This API allows to set metadata for the display connector in question. +//! Main use case would be to set the data for an Nvidia managed dedicated display. +//! The function will work for any valid displayId though. +//! +//! \since Release: 550 +//! +//! \param [in/out] pDedicatedDisplayMetadata Data structure containing input and output data. +//! +//! \retval ::NVAPI_OK The call succeeded. +//! \retval ::NVAPI_ERROR The call failed. +//! \retval ::NVAPI_NO_IMPLEMENTATION The API is not implemented in current driver. +//! \retval ::NVAPI_NOT_SUPPORTED The API is not supported on the current operating system or gpu. +//! \retval ::NVAPI_OUT_OF_MEMORY There wasn't sufficient memory to complete the call. +//! \retval ::NVAPI_INVALID_POINTER An invalid pointer was passed as an argument. +//! \retval ::NVAPI_API_NOT_INITIALIZED NvAPI was not initialized. +//! \retval ::NVAPI_INCOMPATIBLE_STRUCT_VERSION The version of the NV_MANAGED_DEDICATED_DISPLAY_METADATA structure is invalid. +//! \retval ::NVAPI_INVALID_USER_PRIVILEGE The caller doesn't have the required administrator privileges to access this API. +//! \retval ::NVAPI_INVALID_ARGUMENT Characters in pDedicatedDisplayMetadata->name are out of the allowed range. +//! +//! \ingroup gpu +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_DISP_SetNvManagedDedicatedDisplayMetadata(__inout NV_MANAGED_DEDICATED_DISPLAY_METADATA* pDedicatedDisplayMetadata); +#endif // defined(__cplusplus) + #if defined (_WINNT_) @@ -9885,6 +10413,8 @@ NVAPI_INTERFACE NvAPI_GSync_GetTopology(__in NvGSyncDeviceHandle hNvGSyncDevice, //! \retval ::NVAPI_INVALID_SYNC_TOPOLOGY 1.If any mosaic grid is partial. //! 2.If timing(HVisible/VVisible/refreshRate) applied of any display is different. //! 3.If There is a across GPU mosaic grid in system and that is not a part of pGsyncDisplays. +//! \retval ::NVAPI_INVALID_USER_PRIVILEGE The application will require Administrator privileges to access this API. +//! The application can be elevated to a higher permission level by selecting "Run as Administrator". //! //! \ingroup gsyncapi /////////////////////////////////////////////////////////////////////////////// @@ -10022,7 +10552,8 @@ NVAPI_INTERFACE NvAPI_GSync_GetControlParameters(__in NvGSyncDeviceHandle hNvGSy //! If there are return error codes with specific meaning for this API, they are listed below. //! \retval ::NVAPI_INVALID_ARGUMENT hNvGSyncDevice is NULL. //! \retval ::NVAPI_NVIDIA_DEVICE_NOT_FOUND The queried Graphics system does not have any Sync Device. -//! \retval ::NVAPI_SYNC_MASTER_NOT_FOUND Control Parameters can only be set if there is a Sync Master enabled on the Gsync card. +//! \retval ::NVAPI_INVALID_USER_PRIVILEGE The application will require Administrator privileges to access this API. +//! The application can be elevated to a higher permission level by selecting "Run as Administrator". //! //! \ingroup gsyncapi /////////////////////////////////////////////////////////////////////////////// @@ -15681,6 +16212,35 @@ NVAPI_INTERFACE NvAPI_D3D_ImplicitSLIControl(__in IMPLICIT_SLI_CONTROL implicitS #endif //defined (__cplusplus) && ( defined(_D3D9_H_) || defined(__d3d10_h__) || defined(__d3d10_1_h__) ||defined(__d3d11_h__) ) + +#if defined (__cplusplus) && defined(__d3d12_h__) +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_GetNeedsAppFPBlendClamping +// +//! \code +//! DESCRIPTION: This function returns whether the application needs to do FP blend clamping itself +//! +//! \param [in] pDevice Current d3d device +//! \param [out] pAppClampNeeded If true, app needs to clamp. If false, HW does the clamping +//! +//! \return This API can return any of the error codes enumerated in +//! #NvAPI_Status. If there are return error codes with specific +//! meaning for this API, they are listed below. +//! +//! \since Release: 375 +//! +//! SUPPORTED OS: Windows 10 +//! +//! \endcode +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// + +NVAPI_INTERFACE NvAPI_D3D12_GetNeedsAppFPBlendClamping(__in ID3D12Device *pDevice, + __out bool *pAppClampNeeded); + +#endif //defined(__cplusplus) && defined(__d3d12_h__) + //! SUPPORTED OS: Windows 10 //! @@ -17074,7 +17634,8 @@ typedef NV_GET_SLEEP_STATUS_PARAMS_V1 NV_GET_SLEEP_STATUS_PARAMS; //! Note that it may not always reflect the previously requested sleep mode, //! as the feature may not be available on the platform, or the setting has //! been overridden by the control panel, for example. -//! bFsVrr indicates fullscreen GSYNC or GSYNC Compatible mode. +//! bFsVrr indicates fullscreen GSYNC or GSYNC Compatible mode. It is valid +//! only when the application is in the foreground. //! bCplVsyncOn indicates Control Panel VSYNC ON override. //! //! \since Release: 455 @@ -17412,6 +17973,26 @@ NVAPI_INTERFACE NvAPI_D3D12_NotifyOutOfBandCommandQueue(__in ID3D12CommandQueue #endif //defined(__cplusplus) && defined(__d3d12_h__)) +#if defined(__cplusplus) && defined(__d3d12_h__) +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_SetCreateCommandQueueLowLatencyHint +// +//! DESCRIPTION: Reserved call. +//! +//! \since Release: 530 +//! \param [in] pDevice The creating device +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_SetCreateCommandQueueLowLatencyHint(__in ID3D12Device *pDevice); +#endif //defined(__cplusplus) && defined(__d3d12_h__)) + #if defined (__cplusplus) && defined(__d3d12_h__) // Experimental API for internal use. DO NOT USE! @@ -17537,6 +18118,28 @@ NVAPI_INTERFACE NvAPI_D3D12_LaunchCuKernelChain(__in ID3D12GraphicsCommandList* __in const NVAPI_CU_KERNEL_LAUNCH_PARAMS* pKernels, __in NvU32 numKernels); +// Experimental API for internal use. DO NOT USE! +//! SUPPORTED OS: Windows 10 and higher +//! + +typedef struct _NVAPI_CU_KERNEL_LAUNCH_PARAMS_EX +{ + NVDX_ObjectHandle hFunction; + NVAPI_DIM3 gridDim; + NVAPI_DIM3 blockDim; + NvU32 dynSharedMemBytes; + + // either pParams/paramsSize is used or kernelParams is used + void const * pParams; + NvU32 paramSize; + void **kernelParams; +} NVAPI_CU_KERNEL_LAUNCH_PARAMS_EX; + +NVAPI_INTERFACE NvAPI_D3D12_LaunchCuKernelChainEx(__in ID3D12GraphicsCommandList* pCommandList, + __in const NVAPI_CU_KERNEL_LAUNCH_PARAMS_EX* pKernels, + __in NvU32 numKernels); + + // Experimental API for internal use. DO NOT USE! //! SUPPORTED OS: Windows 10 and higher //! @@ -17682,6 +18285,17 @@ typedef enum _NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_STANDARD = NV_BIT(0) //!< Standard Opacity Micromap support is available } NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS; +//! Flags specifying raytracing Displacement Micromap support. +//! Additional flags will be added as support becomes available. +//! +//! \ingroup dx +typedef enum _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE = 0x0, //!< Displacement Micromap support is not available. + //!< The application must not attempt to use any DMM entrypoints or flags. + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_STANDARD = NV_BIT(0) //!< Standard Displacement Micromap support is available +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS; + //! List of Raytracing CAPS types that can be queried. //! //! \ingroup dx @@ -17689,6 +18303,7 @@ typedef enum _NVAPI_D3D12_RAYTRACING_CAPS_TYPE { NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING = 0, NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP = 1, + NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP = 2, NVAPI_D3D12_RAYTRACING_CAPS_TYPE_INVALID = -1 } NVAPI_D3D12_RAYTRACING_CAPS_TYPE; @@ -17724,6 +18339,283 @@ NVAPI_INTERFACE NvAPI_D3D12_GetRaytracingCaps( __in size_t dataSize); #endif // defined(__cplusplus) && defined(__d3d12_h__) +#if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12Device5_INTERFACE_DEFINED__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +//! Flags specifying validation behaviour for raytracing operations. +//! \ingroup dx +//! See NvAPI_D3D12_EnableRaytracingValidation +typedef enum _NVAPI_D3D12_RAYTRACING_VALIDATION_FLAGS +{ + NVAPI_D3D12_RAYTRACING_VALIDATION_FLAG_NONE = 0x0, //!< No validation flags. +} NVAPI_D3D12_RAYTRACING_VALIDATION_FLAGS; + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_EnableRaytracingValidation +// +//! DESCRIPTION: Enable raytracing validation for a device. +//! This function must be called before any other raytracing-related function +//! is invoked on the device. Raytracing validation can only be enabled when +//! the NV_ALLOW_RAYTRACING_VALIDATION envvar is set to 1. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 545 +//! +//! \param [in] pDevice Pointer to the device on which raytracing validation should be enabled. +//! \param [in] flags Raytracing validation flags. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \retval ::NVAPI_OK Completed request +//! \retval ::NVAPI_INVALID_POINTER A null pointer was passed as device argument +//! \retval ::NVAPI_INVALID_ARGUMENT An unsupported flag was specified +//! \retval ::NVAPI_INVALID_CALL The call was made too late (other raytracing-related calls have already been made) +//! \retval ::NVAPI_ACCESS_DENIED Validation is not allowed by envvar +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_EnableRaytracingValidation( + __in ID3D12Device5* pDevice, + __in NVAPI_D3D12_RAYTRACING_VALIDATION_FLAGS flags); + + + +//! Severity classification of validation messages. +//! \ingroup dx +//! See NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_CALLBACK +typedef enum _NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_SEVERITY +{ + NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_SEVERITY_ERROR = 0x0, //!< Error message (indicates likely bug) + NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_SEVERITY_WARNING = 0x1 //!< Warning message (indicates inadvisable usage or possible bug) +} NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_SEVERITY; + +//! Callback for raytracing validation messages. +//! \param [in] pUserData User data pointer as provided to callback registration. +//! \param [in] severity Severity of message. +//! \param [in] messageCode Type of reported validation message. +//! \param [in] message Human-readable description of what the message code means. +//! \param [in] messageDetails Additional human-readable context for validation message. May contain newlines. +//! \ingroup dx +//! See NvAPI_D3D12_RegisterRaytracingValidationMessageCallback +typedef void(__stdcall *NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_CALLBACK)(void* pUserData, NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_SEVERITY severity, const char* messageCode, const char* message, const char* messageDetails); + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_RegisterRaytracingValidationMessageCallback +// +//! DESCRIPTION: Register a message callback for raytracing validation messages. +//! The provided callback may be invoked by the driver using any thread at any time until the callback is unregistered. +//! It is invalid to register/unregister callbacks from within the callback. +//! It is invalid to create or destroy objects for the device or record commands onto command lists from within the callback. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 545 +//! +//! \param [in] pDevice Pointer to the device from which to obtain raytracing validation messages. +//! \param [in] pfnMessageCallback Callback used to report validation messages. +//! \param [in] pUserData [optional] User data to pass as argument to message callback. +//! \param [out] pHandle Handle that may be used to unregister the callback. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \retval ::NVAPI_OK Completed request +//! \retval ::NVAPI_INVALID_POINTER A null pointer was passed as an argument +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_RegisterRaytracingValidationMessageCallback( + __in ID3D12Device5* pDevice, + __in NVAPI_D3D12_RAYTRACING_VALIDATION_MESSAGE_CALLBACK pfnMessageCallback, + __in_opt void* pUserData, + __out void** pHandle); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_UnregisterRaytracingValidationMessageCallback +// +//! DESCRIPTION: Unregister a previously registered message callback for raytracing validation messages. +//! The provided callback will not be invoked once the unregister call has returned. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 545 +//! +//! \param [in] pDevice Pointer to the device from which to stop obtaining raytracing validation messages. +//! \param [in] handle Handle to which callback should be unregistered, obtained at registration. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \retval ::NVAPI_OK Completed request +//! \retval ::NVAPI_INVALID_POINTER A null pointer was passed as device argument +//! \retval ::NVAPI_INVALID_ARGUMENT Callback handle not recognized +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_UnregisterRaytracingValidationMessageCallback( + __in ID3D12Device5* pDevice, + __in void* handle); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_FlushRaytracingValidationMessages +// +//! DESCRIPTION: Flush any validation messages that have not yet been reported. +//! This guarantees that any validation messages for work which is known to be complete on the GPU +//! at the time of the call are reported to registered callbacks. +//! This operation is lightweight if the flushed device does not have raytracing validation enabled. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 545 +//! +//! \param [in] pDevice Pointer to the device on which raytracing validation messages should be flushed. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \retval ::NVAPI_OK Completed request +//! \retval ::NVAPI_INVALID_POINTER A null pointer was passed as device argument +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_FlushRaytracingValidationMessages( + __in ID3D12Device5* pDevice); + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12Device5_INTERFACE_DEFINED__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +//! SUPPORTED OS: Windows 10 and higher +//! +#if defined(__cplusplus) && defined(__d3d12_h__) && (defined(__ID3D12Device5_INTERFACE_DEFINED__) || defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__)) + +// Types used by both device and command list functions. + +//! Flags specifying building instructions and hints when constructing a DMM Array. +//! +//! \ingroup dx +typedef enum _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAGS +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAG_NONE = 0x0, //!< No options specified for the DMM Array build. + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAG_PREFER_FAST_TRACE = NV_BIT(0), //!< Allow the DMM Array build to take a little longer in order to optimize for traversal performance. + //!< This flag is incompatible with #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAG_PREFER_FAST_BUILD. + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAG_PREFER_FAST_BUILD = NV_BIT(1) //!< Spend as little time as possible on the DMM Array build with some potential loss to traversal performance. + //!< This flag is incompatible with #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAG_PREFER_FAST_TRACE. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAGS; + +//! Specifies the input Displacement Micromap formats. +//! The DC1 (Displacement Compression 1) format follows the space-filling curve in barycentric space over the uniformly tessellated micro-triangles. +//! +//! \note This is a 16-bit value when used in #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DESC +//! +//! \ingroup dx +typedef enum _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT_DC1_64_TRIS_64_BYTES = 0x1, //!< 64 micro-triangles packed into 64 bytes + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT_DC1_256_TRIS_128_BYTES = 0x2, //!< 256 micro-triangles packed into 128 bytes + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT_DC1_1024_TRIS_128_BYTES = 0x3, //!< 1024 micro-triangles packed into 128 bytes + +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT; + +//! Number of DMMs of a specific configuration in a DMM Array or BLAS build. +//! Used to compute conservative buffer size estimates for DMM Array and BLAS builds. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_USAGE_COUNT +{ + NvU32 count; //!< For DMM Array builds: total number of DMMs in the DMM Array with the particular \p subdivisionLevel and \p format specified in this descriptor. + //!< For BLAS builds: total number of DMMs with the \p subdivisionLevel and \p format combination that is referenced from the BLAS. + NvU32 subdivisionLevel; //!< Number of subdivisions for the DMM; valid inputs are [0, 5] (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DC1_MAX_SUBDIVISION_LEVEL). + //!< The total number of micro-triangles is 4subdivisionLevel. + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT format; //!< Displacement Micromap format. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_USAGE_COUNT; + +//! Describes one Displacement Micromap. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DESC +{ + NvU32 byteOffset; //!< Byte offset from the \c inputBuffer, specified in the input structure #NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_INPUTS, to where the input DMM data is located. + NvU16 subdivisionLevel; //!< Number of subdivisions for the DMM; valid inputs are [0, 5] (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DC1_MAX_SUBDIVISION_LEVEL). + //!< The total number of micro-triangles is 4subdivisionLevel. + NvU16 format; //!< Format of the DMM of type #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_FORMAT. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DESC; + +//! Input structure to DMM Array construction. +//! Individual DMMs are accessed via indices when used in bottom-level acceleration structure (BLAS) construction. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_INPUTS +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BUILD_FLAGS flags; //!< Flags which apply to all DMMs in the array. + NvU32 numDMMUsageCounts; //!< Number of DMM usage count entries in the \p pDMMUsageCounts array. + const NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_USAGE_COUNT* pDMMUsageCounts; //!< Usage counts for each subdivision level and format combination across all the DMM entries in the build. + D3D12_GPU_VIRTUAL_ADDRESS inputBuffer; //!< Address for raw DMM input data; it must be 256-byte aligned (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BYTE_ALIGNMENT) + //!< It is recommended to try to organize DMMs together in memory that are expected to be used close together spatially. + D3D12_GPU_VIRTUAL_ADDRESS_AND_STRIDE perDMMDescs; //!< GPU array with one #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DESC entry per DMM. +} NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_INPUTS; + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && (defined(__ID3D12Device5_INTERFACE_DEFINED__) || defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__)) + +#if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12Device5_INTERFACE_DEFINED__) + +//! Conservative memory requirements for building a DMM Array. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO +{ + NvU64 resultDataMaxSizeInBytes; //!< Size required to hold the result of a DMM Array build based on the specified inputs. + NvU64 scratchDataSizeInBytes; //!< Scratch storage on GPU required during DMM Array build based on the specified inputs. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO; + +//! Parameters given to NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo(). +//! +//! \ingroup dx +typedef struct _NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_V1 +{ + NvU32 version; //!< [in] Structure version; it should be set to #NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_VER. + const NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_INPUTS* pDesc; //!< [in] Description of the DMM Array build. + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO* pInfo; //!< [out] Result of the query. +} NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_V1; +#define NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_VER1 MAKE_NVAPI_VERSION(NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_V1, 1) +typedef NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_V1 NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS; +#define NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_VER NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_VER1 + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo +// +//! DESCRIPTION: Query conservative memory requirements for building a DMM (Displacement Micromap) Array. +//! The returned size is conservative for DMM Array builds containing +//! a lower or equal number of entries for each resolution and format combination. +//! +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 525 +//! +//! \param [in] pDevice Device on which the DMM Array will be built. +//! \param [in,out] pParams Wrapper around the inputs and outputs of the function. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo( + __in ID3D12Device5* pDevice, + __inout NVAPI_GET_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS* pParams); + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12Device5_INTERFACE_DEFINED__) + //! SUPPORTED OS: Windows 10 and higher //! #if defined(__cplusplus) && defined(__d3d12_h__) && (defined(__ID3D12Device5_INTERFACE_DEFINED__) || defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__)) @@ -17856,6 +18748,9 @@ typedef enum _NVAPI_D3D12_PIPELINE_CREATION_STATE_FLAGS NVAPI_D3D12_PIPELINE_CREATION_STATE_FLAGS_ENABLE_OMM_SUPPORT = NV_BIT(0), //!< [in] Change whether raytracing pipelines are created with support for Opacity Micromaps. //!< If a triangle with an OMM is encountered during traversal and the pipeline was not created with support for them, behavior is undefined. //!< Support should only be enabled if there are OMMs present, since it may incur a small penalty on traversal performance overall. + NVAPI_D3D12_PIPELINE_CREATION_STATE_FLAGS_ENABLE_DMM_SUPPORT = NV_BIT(1), //!< [in] Change whether raytracing pipelines are created with support for Displacement Micromaps. + //!< If a triangle with a DMM is encountered during traversal and the pipeline was not created with support for them, behavior is undefined. + //!< Support should only be enabled if there are DMMs present, since it may incur a small penalty on traversal performance overall. } NVAPI_D3D12_PIPELINE_CREATION_STATE_FLAGS; //! State used when creating new pipelines. @@ -17914,6 +18809,8 @@ typedef enum _NVAPI_D3D12_SERIALIZED_DATA_TYPE_EX // NVAPI_D3D12_SERIALIZED_DATA_TYPE_EX specific flags NVAPI_D3D12_SERIALIZED_DATA_RAYTRACING_OPACITY_MICROMAP_ARRAY_EX = 0x1, //!< Data blob contains an OMM Array. //!< Starting from offset 0, the first bytes of the OMM Array can be reinterpreted as \c D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER. + NVAPI_D3D12_SERIALIZED_DATA_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_EX = 0x2, //!< Data blob contains a DMM Array. + //!< Starting from offset 0, the first bytes of the DMM Array can be reinterpreted as \c D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER. } NVAPI_D3D12_SERIALIZED_DATA_TYPE_EX; @@ -17982,6 +18879,7 @@ typedef enum _NVAPI_D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS_EX //!< Specifying this build flag may result in some reductions in traversal performance. NVAPI_D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_OMM_OPACITY_STATES_UPDATE_EX = NV_BIT(8), //!< The acceleration structure (AS) supports updating OMM data (encoded opacity values). //!< Specifying this flag may reduce traversal performance. + NVAPI_D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_DATA_ACCESS_EX = NV_BIT(9), //!< Allows triangle and micro-triangle data to be accessed through the BLAS via shader intrinsics. } NVAPI_D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS_EX; @@ -17998,7 +18896,8 @@ typedef enum _NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX // NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX specific flags NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX = 0x2, //!< Shares most fields with the basic triangle geometry type, but allows an OMM Array to be attached to the geometry. //!< The basic triangle type and this OMM-enabled type geometries may be mixed in the same BLAS build. - + NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX = 0x3, //!< Triangle geometry with attached DMM data. + //!< This geometry cannot be mixed with other geometry types in the same BLAS. } NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX; @@ -18032,6 +18931,53 @@ typedef struct _NVAPI_D3D12_RAYTRACING_GEOMETRY_OMM_ATTACHMENT_DESC } NVAPI_D3D12_RAYTRACING_GEOMETRY_OMM_ATTACHMENT_DESC; +//! The edge vA..vB is decimated: after subdivision the number of micro-triangles on that edge is halved. +//! (i.e. the neighboring primitive can have a lower subdivision level without introducing cracks) +//! +//! \ingroup dx +typedef enum _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAGS +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAG_DECIMATE_01 = NV_BIT(0), + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAG_DECIMATE_12 = NV_BIT(1), + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAG_DECIMATE_20 = NV_BIT(2), + +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAGS; + +//! Geometry descriptor attachment with Displacement Micromaps. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_ATTACHMENT_DESC +{ + D3D12_GPU_VIRTUAL_ADDRESS_AND_STRIDE triangleMicromapIndexBuffer; //!< Optional buffer specifying which DMM index to use for each triangle; if \c NULL, there is a 1:1 mapping between input triangles and DMM Array entries. + //!< For BLAS updates, this input buffer must match that of the original build. + DXGI_FORMAT triangleMicromapIndexFormat; //!< Format of \c displacementMicromapIndexBuffer, either \c DXGI_FORMAT_R32_UINT or \c DXGI_FORMAT_R16_UINT. + NvU32 triangleMicromapBaseLocation; //!< Constant added to all DMM indices in \p displacementMicromapIndexBuffer. + + D3D12_GPU_VIRTUAL_ADDRESS_AND_STRIDE trianglePrimitiveFlagsBuffer; //!< Optional, per-triangle UINT8 mode flags (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_PRIMITIVE_FLAGS) + + D3D12_GPU_VIRTUAL_ADDRESS_AND_STRIDE vertexBiasAndScaleBuffer; //!< Optional displacement base vertex bias and displacement vector scale buffer. If not supplied, bias defaults to 0 and scale to 1. + DXGI_FORMAT vertexBiasAndScaleFormat; //!< Format of \c displacementBiasAndScaleBuffer. Supported formats are \c DXGI_FORMAT_R16G16_FLOAT and \c DXGI_FORMAT_R32G32_FLOAT + + D3D12_GPU_VIRTUAL_ADDRESS_AND_STRIDE vertexDisplacementVectorBuffer; //!< Per-vertex displacement vector buffer. This buffer is indexed using the index buffer from the base triangle geometry. + DXGI_FORMAT vertexDisplacementVectorFormat; //!< Format of \c displacementVectorBuffer. Supported formats are \c DXGI_FORMAT_R32G32B32_FLOAT, \c DXGI_FORMAT_R32G32B32A32_FLOAT, and \c DXGI_FORMAT_R16G16B16A16_FLOAT (The Alpha channel is ignored, and stride can be set accordingly). + + D3D12_GPU_VIRTUAL_ADDRESS displacementMicromapArray; //!< Pointer to a DMM Array used by this geometry. + //!< Unlike vertex, index, and transform buffers, this resource is dereferenced during raytracing. + + NvU32 numDMMUsageCounts; //!< Number of DMM usage count entries in the \p pDMMUsageCounts array. + const NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_USAGE_COUNT* pDMMUsageCounts; //!< Usage counts for each subdivision level and format combination across all the DMM entries referred-to by the DMM index buffer specified by this geometry. + +} NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_ATTACHMENT_DESC; + +//! Geometry triangle descriptor with attached augmented Displacement Micromaps. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_TRIANGLES_DESC +{ + D3D12_RAYTRACING_GEOMETRY_TRIANGLES_DESC triangles; //!< Triangle mesh descriptor. + NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_ATTACHMENT_DESC dmmAttachment; //!< Displacement Micromap attachment descriptor. +} NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_TRIANGLES_DESC; + //! Geometry triangle descriptor with attached augmented Opacity Micromaps. //! //! \ingroup dx @@ -18057,6 +19003,8 @@ typedef struct _NVAPI_D3D12_RAYTRACING_GEOMETRY_DESC_EX //!< Otherwise, this parameter is unused (space repurposed in a union). NVAPI_D3D12_RAYTRACING_GEOMETRY_OMM_TRIANGLES_DESC ommTriangles; //!< Describes triangle geometry which may optionally use Opacity Micromaps, if \c type is #NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX. //!< Otherwise, this parameter is unused (space repurposed in a union). + NVAPI_D3D12_RAYTRACING_GEOMETRY_DMM_TRIANGLES_DESC dmmTriangles; //!< Describes micro-triangle geometry, if \c type is #NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX. + //!< Otherwise, this parameter is unused (space repurposed in a union). }; } NVAPI_D3D12_RAYTRACING_GEOMETRY_DESC_EX; @@ -18284,6 +19232,182 @@ NVAPI_INTERFACE NvAPI_D3D12_RelocateRaytracingOpacityMicromapArray( #if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) +//! Description of the inputs and memory areas used during the building of DMM Arrays. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_DESC +{ + D3D12_GPU_VIRTUAL_ADDRESS destDisplacementMicromapArrayData; //!< Output location for the DMM Array build. + //!< NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo() reports the amount of memory required for the result given a set of input parameters. + //!< The address must be aligned to 256 bytes (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BYTE_ALIGNMENT). + NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_INPUTS inputs; //!< Description of the input data for the DMM Array build. + D3D12_GPU_VIRTUAL_ADDRESS scratchDisplacementMicromapArrayData; //!< Location where the build will store temporary data. + //!< NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo() reports the amount of scratch memory the implementation will need for a given set of input parameters. + //!< The address must be aligned to 256 bytes (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BYTE_ALIGNMENT). + //!< Contents of this memory going into a build on the GPU timeline are irrelevant and will not be preserved. + //!< After the build is complete on the GPU timeline, the memory is left with whatever undefined contents the build finished with. + //!< The memory pointed to must be in state \c D3D12_RESOURCE_STATE_UNORDERED_ACCESS. +} NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_DESC; + +//! Structure emitted by NvAPI_D3D12_EmitRaytracingDisplacementMicromapArrayPostbuildInfo(), and optionally NvAPI_D3D12_BuildRaytracingDisplacementMicromapArray(), when \c type equals #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_CURRENT_SIZE. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_CURRENT_SIZE_DESC +{ + NvU64 currentSizeInBytes; //!< Size of the DMM Array buffer. + //!< The queried size may be smaller than the size reported by NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo(). + //!< This allows the application to move and relocate the DMM Array to a smaller buffer to reclaim any unused memory after the DMM Array build is complete. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_CURRENT_SIZE_DESC; + +//! Type of postbuild info to emit after a DMM Array build. +//! +//! \ingroup dx +typedef enum _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_TYPE +{ + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_CURRENT_SIZE = 0x0, //!< Size of the current DMM Array. May be smaller than reported by the NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo() call. + //!< Unused memory can be reclaimed by copying the DMM Array into a new resource; see #NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_CURRENT_SIZE_DESC. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_TYPE; + +//! Description of the postbuild information to generate from a DMM Array. +//! +//! \ingroup dx +typedef struct _NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_DESC +{ + D3D12_GPU_VIRTUAL_ADDRESS destBuffer; //!< Result storage. + //!< Size required and the layout of the contents written by the system depend on \p infoType. + //!< The memory pointed to must be in state \c D3D12_RESOURCE_STATE_UNORDERED_ACCESS. + //!< The memory must be aligned to the natural alignment for the members of the particular output structure being generated (e.g. 8 bytes for a struct with the largest member being \c NvU64). + NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_TYPE infoType; //!< Type of postbuild information to retrieve. +} NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_DESC; + +//! Parameters given to NvAPI_D3D12_BuildRaytracingDisplacementMicromapArray(). +//! +//! \ingroup dx +typedef struct _NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1 +{ + NvU32 version; //!< [in] Structure version; it should be set to #NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER. + const NVAPI_D3D12_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_DESC* pDesc; //!< [in] Description of the DMM Array build. + NvU32 numPostbuildInfoDescs; //!< [in] Size of postbuild info desc array. Set to 0 if none are needed. + const NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_DESC* pPostbuildInfoDescs; //!< [in] Optional array of descriptions for postbuild info to generate describing properties of the acceleration structure that was built. + //!< [in] Any given postbuild info type, \c D3D12_RAYTRACING_ACCEELRATION_STRUCTURE_POSTBUILD_INFO_TYPE, can only be selected for output by at most one array entry. +} NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1; +#define NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER1 MAKE_NVAPI_VERSION(NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1, 1) +typedef NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1 NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS; +#define NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER1 + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_BuildRaytracingDisplacementMicromapArray +// +//! DESCRIPTION: Construct DMM Array for a collection of DMMs on the GPU. +//! The CPU-side input buffers are not referenced after this call. +//! The GPU-side input resources are not referenced after the build has concluded after ExecuteCommandList(). +//! Additionally, the application may optionally output postbuild information immediately after the build. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 525 +//! +//! \param [in] pCommandList Command list on which the command will execute. +//! \param [in] pParams Wrapper around the inputs of the function. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \retval NVAPI_INVALID_COMBINATION pParams->pPostbuildInfoDescs was set to \c NULL while pParams->numPostbuildInfoDescs is non zero. +//! +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_BuildRaytracingDisplacementMicromapArray( + __in ID3D12GraphicsCommandList4* pCommandList, + __in NVAPI_BUILD_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS* pParams); + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +#if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +//! Parameters given to NvAPI_D3D12_RelocateRaytracingDisplacementMicromapArray(). +//! +//! \ingroup dx +typedef struct _NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1 +{ + NvU32 version; //!< [in] Structure version; it should be set to #NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER. + D3D12_GPU_VIRTUAL_ADDRESS displacementMicromapArray; //!< [in] DMM Array current memory address; it must be 256-byte aligned (#NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BYTE_ALIGNMENT). +} NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1; +#define NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER1 MAKE_NVAPI_VERSION(NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1, 1) +typedef NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_V1 NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS; +#define NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS_VER1 + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_RelocateRaytracingDisplacementMicromapArray +// +//! DESCRIPTION: Makes the DMM Array usable at its current location in memory. +//! A DMM Array that has been copied to a new location must be relocated using this function before it may be attached to any BLAS. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 525 +//! +//! \param [in] pCommandList Command list on which the command will execute. +//! \param [in] pParams Wrapper around the inputs of the function. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_RelocateRaytracingDisplacementMicromapArray( + __in ID3D12GraphicsCommandList4* pCommandList, + __in const NVAPI_RELOCATE_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_PARAMS* pParams); + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +#if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +//! Parameters given to NvAPI_D3D12_EmitRaytracingDisplacementMicromapArrayPostbuildInfo(). +//! +//! \ingroup dx +typedef struct _NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_V1 +{ + NvU32 version; //!< [in] Structure version; it should be set to #NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_VER. + const NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_DESC* pDesc; //!< [in] Description of which postbuild info to emit. + NvU32 numSources; //!< [in] Number of DMM Arrays in \p pSources. + const D3D12_GPU_VIRTUAL_ADDRESS* pSources; //!< [in] List of DMM Arrays for which postbuild info should be emitted. +} NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_V1; +#define NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_VER1 MAKE_NVAPI_VERSION(NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_V1, 1) +typedef NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_V1 NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS; +#define NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_VER NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS_VER1 + +/////////////////////////////////////////////////////////////////////////////// +// +// FUNCTION NAME: NvAPI_D3D12_EmitRaytracingDisplacementMicromapArrayPostbuildInfo +// +//! DESCRIPTION: Emits information about one or more DMM Arrays, only available after the DMM Array constructions have finished. +//! +//! SUPPORTED OS: Windows 10 and higher +//! +//! +//! \since Release: 525 +//! +//! \param [in] pCommandList Command list on which the command will execute. +//! \param [in] pParams Wrapper around the inputs of the function. +//! +//! \return This API can return any of the error codes enumerated in #NvAPI_Status. +//! If there are return error codes with specific meaning for this API, they are listed below. +//! +//! \ingroup dx +/////////////////////////////////////////////////////////////////////////////// +NVAPI_INTERFACE NvAPI_D3D12_EmitRaytracingDisplacementMicromapArrayPostbuildInfo( + __in ID3D12GraphicsCommandList4* pCommandList, + __in const NVAPI_EMIT_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_POSTBUILD_INFO_PARAMS* pParams); + +#endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + +#if defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) + //! Parameters given to NvAPI_D3D12_EmitRaytracingOpacityMicromapArrayPostbuildInfo(). //! //! \ingroup dx @@ -18443,6 +19567,16 @@ typedef enum _NVAPI_RAY_FLAGS_EX //!< If an instance is flagged with #NVAPI_D3D12_RAYTRACING_INSTANCE_FLAG_DISABLE_OMMS_EX, that takes precedence over this flag. } NVAPI_RAY_FLAG_EX; +//! Mandatory alignment for the address of a DMM Array. +//! +//! \ingroup dx +#define NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_ARRAY_BYTE_ALIGNMENT 256 + +//! Highest subdivision-level allowed with DC1. +//! +//! \ingroup dx +#define NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_DC1_MAX_SUBDIVISION_LEVEL 5 + #endif // defined(__cplusplus) && defined(__d3d12_h__) && defined(__ID3D12GraphicsCommandList4_INTERFACE_DEFINED__) @@ -18544,6 +19678,7 @@ NVAPI_INTERFACE NvAPI_D3D12_CreateCommittedRDMABuffer( __out void **ppRDMAAddress); #endif //defined(__cplusplus) && defined(__d3d12_h__) + //! SUPPORTED OS: Windows 10 and higher //! #if defined(__cplusplus) && defined(__d3d12_h__) diff --git a/vendor/nvapi/nvapi_lite_common.h b/vendor/nvapi/nvapi_lite_common.h index 21263566c1..c922ffb512 100644 --- a/vendor/nvapi/nvapi_lite_common.h +++ b/vendor/nvapi/nvapi_lite_common.h @@ -70,7 +70,7 @@ typedef signed long NvS32; /* -2147483648 to 2147483647 */ typedef signed int NvS32; /* -2147483648 to 2147483647 */ #endif -#ifndef __unix +#if !(NVOS_IS_UNIX || (defined(__unix))) // mac os 32-bit still needs this #if ( (defined(macintosh) && defined(__LP64__) && (__NVAPI_RESERVED0__)) || \ (!defined(macintosh) && defined(__NVAPI_RESERVED0__)) ) @@ -409,6 +409,7 @@ typedef enum _NvAPI_Status NVAPI_NOT_PERMITTED = -240, //!< Attempted operation is not permitted. NVAPI_CALLBACK_ALREADY_REGISTERED = -241, //!< The callback function has already been registered. NVAPI_CALLBACK_NOT_FOUND = -242, //!< The callback function is not found or not registered. + NVAPI_INVALID_OUTPUT_WIRE_FORMAT = -243, //!< Invalid Wire Format for the VR HMD } NvAPI_Status; /////////////////////////////////////////////////////////////////////////////// @@ -527,10 +528,14 @@ NVAPI_INTERFACE NvAPI_GPU_GetMemoryInfo(NvPhysicalGpuHandle hPhysicalGpu, NV_DIS typedef struct { NvU32 version; //!< Structure version - NvU64 dedicatedVideoMemory; //!< Size(in bytes) of the physical framebuffer. + NvU64 dedicatedVideoMemory; //!< Size(in bytes) of the physical framebuffer. Refers to the dedicated video memory on discrete GPUs. + //! It is more performant for GPU operations than the reserved systemVideoMemory. NvU64 availableDedicatedVideoMemory; //!< Size(in bytes) of the available physical framebuffer for allocating video memory surfaces. - NvU64 systemVideoMemory; //!< Size(in bytes) of system memory the driver allocates at load time. + NvU64 systemVideoMemory; //!< Size(in bytes) of system memory the driver allocates at load time. It is a substitute for dedicated video memory. + //!< Typically used with integrated GPUs that do not have dedicated video memory. NvU64 sharedSystemMemory; //!< Size(in bytes) of shared system memory that driver is allowed to commit for surfaces across all allocations. + //!< On discrete GPUs, it is used to utilize system memory for various operations. It does not need to be reserved during boot. + //!< It may be used by both GPU and CPU, and has an “on-demand” type of usage. NvU64 curAvailableDedicatedVideoMemory; //!< Size(in bytes) of the current available physical framebuffer for allocating video memory surfaces. NvU64 dedicatedVideoMemoryEvictionsSize; //!< Size(in bytes) of the total size of memory released as a result of the evictions. NvU64 dedicatedVideoMemoryEvictionCount; //!< Indicates the number of eviction events that caused an allocation to be removed from dedicated video memory to free GPU diff --git a/vendor/nvapi/nvapi_lite_surround.h b/vendor/nvapi/nvapi_lite_surround.h index e680dd2e77..43b7000886 100644 --- a/vendor/nvapi/nvapi_lite_surround.h +++ b/vendor/nvapi/nvapi_lite_surround.h @@ -60,8 +60,6 @@ extern "C" { /////////////////////////////////////////////////////////////////////////////// NVAPI_INTERFACE NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId); #define NV_MOSAIC_MAX_DISPLAYS (64) -//! SUPPORTED OS: Windows 7 and higher -//! /////////////////////////////////////////////////////////////////////////////// // // FUNCTION NAME: NvAPI_Mosaic_GetDisplayViewportsByResolution @@ -77,10 +75,10 @@ NVAPI_INTERFACE NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId); //! \param [in] srcHeight Height of full display topology. If both //! width and height are 0, the current //! resolution is used. -//! \param [out] viewports Array of NV_RECT viewports which represent -//! the displays as identified in -//! NvAPI_Mosaic_EnumGridTopologies. If the -//! requested resolution is a single-wide +//! \param [out] viewports Array of NV_RECT viewports. +//! SUPPORTED OS: Windows 7 and higher +//! +//! If the requested resolution is a single-wide //! resolution, only viewports[0] will //! contain the viewport details, regardless //! of which display is driving the display. diff --git a/vendor/nvapi/x86/nvapi.lib b/vendor/nvapi/x86/nvapi.lib index 6bb2307a023f387781a4f6eea6b5e93cb2d24387..7e80aa8814d0252b459c32c91dbb806f33b648e2 100644 GIT binary patch literal 409742 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 literal 398256 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�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 z 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 I0=*^w53|{#5C8xG From 7ba2a4c24df90111ff1328dd2d4350bf600e407f Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Fri, 21 Jun 2024 20:57:23 +0200 Subject: [PATCH 14/23] Update cryptopp (security fixes) --- vendor/cryptopp/aria_simd.cpp | 194 --- vendor/cryptopp/asn.h | 17 +- vendor/cryptopp/bench.h | 105 ++ vendor/cryptopp/bench1.cpp | 520 ++++++++ vendor/cryptopp/bench2.cpp | 267 ++++ vendor/cryptopp/bench3.cpp | 480 +++++++ vendor/cryptopp/config_asm.h | 12 +- vendor/cryptopp/config_cpu.h | 2 +- vendor/cryptopp/config_ver.h | 2 + vendor/cryptopp/cpu.cpp | 15 +- vendor/cryptopp/cpuid64.asm | 63 + vendor/cryptopp/datatest.cpp | 1443 +++++++++++++++++++++ vendor/cryptopp/dlltest.cpp | 212 ++++ vendor/cryptopp/ecp.cpp | 7 +- vendor/cryptopp/esign.cpp | 3 + vendor/cryptopp/fipsalgt.cpp | 1293 +++++++++++++++++++ vendor/cryptopp/fipstest.cpp | 652 ++++++++++ vendor/cryptopp/nbtheory.cpp | 18 + vendor/cryptopp/nbtheory.h | 2 +- vendor/cryptopp/osrng.cpp | 2 +- vendor/cryptopp/rabin.cpp | 7 + vendor/cryptopp/rdrand.h | 2 +- vendor/cryptopp/regtest1.cpp | 160 +++ vendor/cryptopp/regtest2.cpp | 105 ++ vendor/cryptopp/regtest3.cpp | 156 +++ vendor/cryptopp/regtest4.cpp | 58 + vendor/cryptopp/test.cpp | 1098 ++++++++++++++++ vendor/cryptopp/validat0.cpp | 1672 +++++++++++++++++++++++++ vendor/cryptopp/validat1.cpp | 1225 ++++++++++++++++++ vendor/cryptopp/validat10.cpp | 535 ++++++++ vendor/cryptopp/validat2.cpp | 1328 ++++++++++++++++++++ vendor/cryptopp/validat3.cpp | 1367 ++++++++++++++++++++ vendor/cryptopp/validat4.cpp | 1813 +++++++++++++++++++++++++++ vendor/cryptopp/validat5.cpp | 2224 +++++++++++++++++++++++++++++++++ vendor/cryptopp/validat6.cpp | 408 ++++++ vendor/cryptopp/validat7.cpp | 705 +++++++++++ vendor/cryptopp/validat8.cpp | 631 ++++++++++ vendor/cryptopp/validat9.cpp | 735 +++++++++++ vendor/cryptopp/validate.h | 395 ++++++ vendor/cryptopp/x64dll.asm | 45 - 40 files changed, 19722 insertions(+), 256 deletions(-) delete mode 100644 vendor/cryptopp/aria_simd.cpp create mode 100644 vendor/cryptopp/bench.h create mode 100644 vendor/cryptopp/bench1.cpp create mode 100644 vendor/cryptopp/bench2.cpp create mode 100644 vendor/cryptopp/bench3.cpp create mode 100644 vendor/cryptopp/cpuid64.asm create mode 100644 vendor/cryptopp/datatest.cpp create mode 100644 vendor/cryptopp/dlltest.cpp create mode 100644 vendor/cryptopp/fipsalgt.cpp create mode 100644 vendor/cryptopp/fipstest.cpp create mode 100644 vendor/cryptopp/regtest1.cpp create mode 100644 vendor/cryptopp/regtest2.cpp create mode 100644 vendor/cryptopp/regtest3.cpp create mode 100644 vendor/cryptopp/regtest4.cpp create mode 100644 vendor/cryptopp/test.cpp create mode 100644 vendor/cryptopp/validat0.cpp create mode 100644 vendor/cryptopp/validat1.cpp create mode 100644 vendor/cryptopp/validat10.cpp create mode 100644 vendor/cryptopp/validat2.cpp create mode 100644 vendor/cryptopp/validat3.cpp create mode 100644 vendor/cryptopp/validat4.cpp create mode 100644 vendor/cryptopp/validat5.cpp create mode 100644 vendor/cryptopp/validat6.cpp create mode 100644 vendor/cryptopp/validat7.cpp create mode 100644 vendor/cryptopp/validat8.cpp create mode 100644 vendor/cryptopp/validat9.cpp create mode 100644 vendor/cryptopp/validate.h diff --git a/vendor/cryptopp/aria_simd.cpp b/vendor/cryptopp/aria_simd.cpp deleted file mode 100644 index 3a390edf07..0000000000 --- a/vendor/cryptopp/aria_simd.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// 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 - -// 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/vendor/cryptopp/asn.h b/vendor/cryptopp/asn.h index cf44fc7278..beb20cd0f5 100644 --- a/vendor/cryptopp/asn.h +++ b/vendor/cryptopp/asn.h @@ -331,7 +331,8 @@ class CRYPTOPP_DLL OID 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); friend bool operator<=(const OID &lhs, const OID &rhs); friend bool operator>=(const OID &lhs, const OID &rhs); @@ -913,11 +914,18 @@ inline bool operator!=(const OID &lhs, const OID &rhs); /// \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. +/// \details operator<() calls std::lexicographical_compare() on the 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 greater than 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 less than or equal to the second OID, false otherwise /// \details operator<=() is implemented in terms of operator==() and operator<(). /// \since Crypto++ 8.3 @@ -936,8 +944,7 @@ 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); } +inline std::ostream& operator<<(std::ostream& out, const OID &oid); #else inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) {return lhs.m_values == rhs.m_values;} @@ -945,6 +952,8 @@ 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) diff --git a/vendor/cryptopp/bench.h b/vendor/cryptopp/bench.h new file mode 100644 index 0000000000..561b657874 --- /dev/null +++ b/vendor/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/vendor/cryptopp/bench1.cpp b/vendor/cryptopp/bench1.cpp new file mode 100644 index 0000000000..24c9a3b7e5 --- /dev/null +++ b/vendor/cryptopp/bench1.cpp @@ -0,0 +1,520 @@ +// 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"); + BenchMarkByNameKeyLess("LSH-256"); + BenchMarkByNameKeyLess("LSH-512"); + } + + std::cout << "\n
AlgorithmProviderMiB/Second" << cpb; + + std::cout << "\n
" << std::endl; +} + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP diff --git a/vendor/cryptopp/bench2.cpp b/vendor/cryptopp/bench2.cpp new file mode 100644 index 0000000000..0bd2d0a4b2 --- /dev/null +++ b/vendor/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/vendor/cryptopp/bench3.cpp b/vendor/cryptopp/bench3.cpp new file mode 100644 index 0000000000..e280a6216f --- /dev/null +++ b/vendor/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(spriv2); + 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(spriv2); + 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/vendor/cryptopp/config_asm.h b/vendor/cryptopp/config_asm.h index d5629c7714..edfbdefb80 100644 --- a/vendor/cryptopp/config_asm.h +++ b/vendor/cryptopp/config_asm.h @@ -27,12 +27,12 @@ #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 -// explicitly 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 this to disable ASM, intrinsics and built-ins. The library code will +// not explicitly 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 explicitly use the ISAs. When disabling ASM, +// it is best to do it from config_asm.h to ensure the library and all programs +// share the setting. // #define CRYPTOPP_DISABLE_ASM 1 // https://github.com/weidai11/cryptopp/issues/719 diff --git a/vendor/cryptopp/config_cpu.h b/vendor/cryptopp/config_cpu.h index 4020b1be54..15f694e793 100644 --- a/vendor/cryptopp/config_cpu.h +++ b/vendor/cryptopp/config_cpu.h @@ -203,7 +203,7 @@ /// _MSC_VER nor __BORLANDC__ are defined. #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY ... #elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__) || \ - (defined(CRYPTOPP_WIN32_AVAILABLE) && defined(CRYPTOPP_LLVM_CLANG_VERSION)) + defined(CRYPTOPP_MSVC_CLANG_VERSION) #define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY 1 #else #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY 1 diff --git a/vendor/cryptopp/config_ver.h b/vendor/cryptopp/config_ver.h index 4752692ac2..c7e457c2aa 100644 --- a/vendor/cryptopp/config_ver.h +++ b/vendor/cryptopp/config_ver.h @@ -58,6 +58,8 @@ // LLVM Clang version 3.7. Also see https://gist.github.com/yamaya/2924292 #if defined(__clang__) && defined(__apple_build_version__) # define CRYPTOPP_APPLE_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#elif defined(__clang__) && defined(_MSC_VER) +# define CRYPTOPP_MSVC_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) #elif defined(__clang__) # define CRYPTOPP_LLVM_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) #endif diff --git a/vendor/cryptopp/cpu.cpp b/vendor/cryptopp/cpu.cpp index 607726fcf3..f61fef39ba 100644 --- a/vendor/cryptopp/cpu.cpp +++ b/vendor/cryptopp/cpu.cpp @@ -388,9 +388,14 @@ extern bool CPU_ProbeSSE2(); // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684. word64 XGetBV(word32 num) { +// Explicitly handle CRYPTOPP_DISABLE_ASM case. +// https://github.com/weidai11/cryptopp/issues/1240 +#if defined(CRYPTOPP_DISABLE_ASM) + return 0; + // Required by Visual Studio 2008 and below and Clang on Windows. // Use it for all MSVC-compatible compilers. -#if defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) +#elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) return XGETBV64(num); @@ -446,9 +451,15 @@ word64 XGetBV(word32 num) // cpu.cpp (131): E2211 Inline assembly not allowed in inline and template functions bool CpuId(word32 func, word32 subfunc, word32 output[4]) { +// Explicitly handle CRYPTOPP_DISABLE_ASM case. +// https://github.com/weidai11/cryptopp/issues/1240 +#if defined(CRYPTOPP_DISABLE_ASM) + output[0] = output[1] = output[2] = output[3] = 0; + return false; + // Required by Visual Studio 2008 and below and Clang on Windows. // Use it for all MSVC-compatible compilers. -#if defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) +#elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) CPUID64(func, subfunc, output); return true; diff --git a/vendor/cryptopp/cpuid64.asm b/vendor/cryptopp/cpuid64.asm new file mode 100644 index 0000000000..6951bbc88e --- /dev/null +++ b/vendor/cryptopp/cpuid64.asm @@ -0,0 +1,63 @@ +;; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention +;; The first four integer arguments are passed in registers. +;; Integer values are passed in left-to-right order in RCX, +;; RDX, R8, and R9, respectively. Arguments five and higher +;; are passed on the stack. + +;; The registers RAX, RCX, RDX, R8, R9, R10, R11, XMM0-5, +;; and the upper portions of YMM0-15 and ZMM0-15 are +;; considered volatile and must be considered destroyed on +;; function calls. + +.CODE + +TITLE CPU features source file +SUBTITLE Microsoft specific ASM code to utilize CPUID and XGETBV64 for down level Microsoft toolchains + +;; http://www.agner.org/optimize/vectorclass/read.php?i=65 +;; word64 Xgetbv(word32 ctrl) +;; ctrl = rcx + + ALIGN 8 +XGETBV64 PROC FRAME +.endprolog + ;; query + DB 0fh, 01h, 0d0h + ;; xcr = (EDX << 32) | EAX + and rax, 0ffffffffh + shl rdx, 32 + or rax, rdx + ret +XGETBV64 ENDP + +;; word64 CpuId(word32 func, word32 subfunc, word32 output[4]) +;; func = rcx +;; subfunc = rdx +;; output = r8 + + ALIGN 8 +CPUID64 PROC FRAME + ;; preserve per ABI + mov [rsp+8], rbx +.savereg rbx, 8 +.endprolog + ;; eax = func + mov rax, rcx + ;; ecx = subfunc + mov rcx, rdx + ;; query + cpuid + ;; save + mov [r8+0], eax + mov [r8+4], ebx + mov [r8+8], ecx + mov [r8+12], edx + ;; return value + mov rax, 1 + ;; restore + mov rbx, [rsp+8] + ret +CPUID64 ENDP + +_TEXT ENDS +END diff --git a/vendor/cryptopp/datatest.cpp b/vendor/cryptopp/datatest.cpp new file mode 100644 index 0000000000..ac82d5181b --- /dev/null +++ b/vendor/cryptopp/datatest.cpp @@ -0,0 +1,1443 @@ +// 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 CRYPTOPP_MSC_VERSION +# define STRTOUL64 _strtoui64 +#else +# define STRTOUL64 strtoull +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +ANONYMOUS_NAMESPACE_BEGIN + +bool s_thorough = false; +typedef std::map TestData; +const TestData *s_currentTestData = NULLPTR; +const std::string testDataFilename = "cryptest.dat"; + +// Handles CR, LF, and CRLF properly. Early RFC's used '\r\0' on occasion. +// For istream.fail() see https://stackoverflow.com/q/34395801/608639. +bool Readline(std::istream& stream, std::string& line) +{ + // Ensure old data is cleared + line.clear(); + + std::string temp; + temp.reserve(64); + + while (!stream.fail()) + { + int ch = stream.get(); + if (ch == '\r') + { + int next = stream.peek(); + if (next == '\n') + (void)stream.get(); + else if (next == '\0') + (void)stream.get(); + + break; + } + else if (ch == '\n') + { + break; + } + + temp.push_back(static_cast(ch)); + } + +#if defined(CRYPTOPP_CXX11) + temp.shrink_to_fit(); +#else + // Non-binding shrink to fit + temp.reserve(0); +#endif + + std::swap(line, temp); + + return !stream.fail(); +} + +std::string TrimSpace(const 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(const 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); +} + +class TestFailure : public Exception +{ +public: + TestFailure() : Exception(OTHER_ERROR, "Validation test failed") {} +}; + +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; + } +} + +void SignalTestFailure() +{ + OutputTestData(*s_currentTestData); + throw TestFailure(); +} + +void SignalUnknownAlgorithmError(const std::string& algType) +{ + OutputTestData(*s_currentTestData); + throw Exception(Exception::OTHER_ERROR, "Unknown algorithm " + algType + " during validation test"); +} + +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()) + { + std::string::size_type pos = s1.find_first_not_of(" "); + if (pos != std::string::npos) + s1.erase(0, pos); + + if (s1.empty()) + goto end; + + int repeat = 1; + if (s1[0] == 'r') + { + s1 = s1.erase(0, 1); + repeat = std::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 n = s1.find(' '); + StringSource(s1.substr(2, n), true, new HexDecoder(new StringSink(s2))); + s1 = s1.substr(STDMIN(n, s1.length())); + } + else + { + std::string::size_type n = s1.find(' '); + StringSource(s1.substr(0, n), true, new HexDecoder(new StringSink(s2))); + s1 = s1.substr(STDMIN(n, 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, unsigned int &totalTests) +{ + totalTests++; + + 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, unsigned int &totalTests) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + static member_ptr signer; + static member_ptr verifier; + static std::string lastName; + + if (name != lastName) + { + signer.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + verifier.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + lastName = name; + + // Code coverage + (void)signer->AlgorithmName(); + (void)verifier->AlgorithmName(); + (void)signer->AlgorithmProvider(); + (void)verifier->AlgorithmProvider(); + } + + TestDataNameValuePairs pairs(v); + + if (test == "GenerateKey") + { + totalTests++; + + signer->AccessPrivateKey().GenerateRandom(Test::GlobalRNG(), pairs); + verifier->AccessPublicKey().AssignFrom(signer->AccessPrivateKey()); + } + else + { + std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); + + totalTests++; // key format + if (keyFormat == "DER") + verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); + else if (keyFormat == "Component") + verifier->AccessMaterial().AssignFrom(pairs); + + if (test == "Verify" || test == "NotVerify") + { + totalTests++; + + 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") + { + totalTests++; + + if (!verifier->GetMaterial().Validate(Test::GlobalRNG(), 3)) + SignalTestFailure(); + return; + } + + totalTests++; // key format + if (keyFormat == "DER") + signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); + else if (keyFormat == "Component") + signer->AccessMaterial().AssignFrom(pairs); + } + + if (test == "GenerateKey" || test == "KeyPairValidAndConsistent") + { + totalTests++; + + TestKeyPairValidAndConsistent(verifier->AccessMaterial(), signer->GetMaterial(),totalTests); + 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") + { + totalTests++; + + 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") + { + totalTests++; + + // 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(); + } + else + { + std::string msg("Unknown signature test \"" + test + "\""); + SignalTestError(msg.c_str()); + CRYPTOPP_ASSERT(false); + } +} + +// Subset of TestSignatureScheme. We picked the tests that have data that is easy to write to a file. +// Also see https://github.com/weidai11/cryptopp/issues/1010, where HIGHT broke when using FileSource. +void TestSignatureSchemeWithFileSource(TestData &v, unsigned int &totalTests) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + if (test != "Sign" && test != "DeterministicSign") { return; } + + static member_ptr signer; + static member_ptr verifier; + static std::string lastName; + + if (name != lastName) + { + signer.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + verifier.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + name = lastName; + + // Code coverage + (void)signer->AlgorithmName(); + (void)verifier->AlgorithmName(); + (void)signer->AlgorithmProvider(); + (void)verifier->AlgorithmProvider(); + } + + TestDataNameValuePairs pairs(v); + + std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); + + totalTests++; // key format + if (keyFormat == "DER") + verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); + else if (keyFormat == "Component") + verifier->AccessMaterial().AssignFrom(pairs); + + totalTests++; // key format + if (keyFormat == "DER") + signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); + else if (keyFormat == "Component") + signer->AccessMaterial().AssignFrom(pairs); + + if (test == "Sign") + { + totalTests++; + + SignerFilter f(Test::GlobalRNG(), *signer, new HexEncoder(new FileSink(std::cout))); + StringSource ss(GetDecodedDatum(v, "Message"), true, new FileSink(testDataFilename.c_str())); + FileSource fs(testDataFilename.c_str(), true, new Redirector(f)); + SignalTestFailure(); + } + else if (test == "DeterministicSign") + { + totalTests++; + + // 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 FileSink(testDataFilename.c_str())); + FileSource fs(testDataFilename.c_str(), true, new Redirector(f)); + + if (GetDecodedDatum(v, "Signature") != signature) + SignalTestFailure(); + } +} + +void TestAsymmetricCipher(TestData &v, unsigned int &totalTests) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + static member_ptr encryptor; + static member_ptr 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(); + } + + std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); + + if (keyFormat == "DER") + { + totalTests++; + + decryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); + encryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); + } + else if (keyFormat == "Component") + { + totalTests++; + + TestDataNameValuePairs pairs(v); + decryptor->AccessMaterial().AssignFrom(pairs); + encryptor->AccessMaterial().AssignFrom(pairs); + } + + if (test == "DecryptMatch") + { + totalTests++; + + 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") + { + totalTests++; + + TestKeyPairValidAndConsistent(encryptor->AccessMaterial(), decryptor->GetMaterial(), totalTests); + } + else + { + std::string msg("Unknown asymmetric cipher test \"" + test + "\""); + SignalTestError(msg.c_str()); + CRYPTOPP_ASSERT(false); + } +} + +void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) +{ + 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; + + totalTests++; + + 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->IsRandomAccess(); + (void)decryptor->IsRandomAccess(); + (void)encryptor->MinKeyLength(); + (void)decryptor->MinKeyLength(); + (void)encryptor->MaxKeyLength(); + (void)decryptor->MaxKeyLength(); + (void)encryptor->DefaultKeyLength(); + (void)decryptor->DefaultKeyLength(); + } + + 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); + } + } + + // 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); + + 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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(256); ss.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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(2048); ss.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 ss(decrypted, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(256); ss.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + } + else + { + std::string msg("Unknown symmetric cipher test \"" + test + "\""); + SignalTestError(msg.c_str()); + } +} + +// Subset of TestSymmetricCipher. The test suite lacked tests for in-place encryption, +// where inString == outString. Also see https://github.com/weidai11/cryptopp/issues/1231. +void TestSymmetricCipherWithInplaceEncryption(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) +{ + 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" ) { return; } + + 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; + } + + // Only test stream ciphers at the moment + if (encryptor->MandatoryBlockSize() != 1) { return; } + + totalTests++; + + ConstByteArrayParameter iv; + if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) + SignalTestFailure(); + + 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); + } + } + + const std::string plainText = GetDecodedDatum(v, "Plaintext"); + const std::string cipherText = GetDecodedDatum(v, "Ciphertext"); + + // Use buffer for in-place encryption and decryption + std::string buffer(plainText); + + // Test in-place encryption + encryptor->ProcessString(BytePtr(buffer), BytePtrSize(buffer)); + + if (buffer != cipherText) + { + std::cout << "\nincorrectly encrypted: "; + StringSource ss(buffer, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(256); ss.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + + // Test in-place decryption + decryptor->ProcessString(BytePtr(buffer), BytePtrSize(buffer)); + + if (buffer != plainText) + { + std::cout << "\nincorrectly decrypted: "; + StringSource ss(buffer, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(256); ss.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } +} + +// Subset of TestSymmetricCipher. We picked the tests that have data that is easy to write to a file. +// Also see https://github.com/weidai11/cryptopp/issues/1010, where HIGHT broke when using FileSource. +void TestSymmetricCipherWithFileSource(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) +{ + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + // Limit FileSource tests to Encrypt only. + if (test != "Encrypt") { return; } + + totalTests++; + + std::string key = GetDecodedDatum(v, "Key"); + std::string plaintext = GetDecodedDatum(v, "Plaintext"); + + TestDataNameValuePairs testDataPairs(v); + CombinedNameValuePairs pairs(overrideParameters, testDataPairs); + + 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(); + } + + ConstByteArrayParameter iv; + if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) + SignalTestFailure(); + + 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); + } + } + + // 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); + + std::string encrypted, ciphertext; + StreamTransformationFilter encFilter(*encryptor, new StringSink(encrypted), + static_cast(paddingScheme)); + + StringSource ss(plaintext, true, new FileSink(testDataFilename.c_str())); + FileSource pstore(testDataFilename.c_str(), true); + RandomizedTransfer(pstore, encFilter, true); + encFilter.MessageEnd(); + + ciphertext = GetDecodedDatum(v, "Ciphertext"); + + if (encrypted != ciphertext) + { + std::cout << "\nincorrectly encrypted: "; + StringSource sss(encrypted, false, new HexEncoder(new FileSink(std::cout))); + sss.Pump(2048); sss.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 sss(decrypted, false, new HexEncoder(new FileSink(std::cout))); + sss.Pump(256); sss.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } +} + +void TestAuthenticatedSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) +{ + 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") + { + totalTests++; + + static member_ptr encryptor; + static member_ptr decryptor; + static std::string lastName; + + if (name != lastName) + { + encryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + decryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + name = lastName; + + // 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(); + (void)encryptor->IsRandomAccess(); + (void)decryptor->IsRandomAccess(); + (void)encryptor->IsSelfInverting(); + (void)decryptor->IsSelfInverting(); + (void)encryptor->MaxHeaderLength(); + (void)decryptor->MaxHeaderLength(); + (void)encryptor->MaxMessageLength(); + (void)decryptor->MaxMessageLength(); + (void)encryptor->MaxFooterLength(); + (void)decryptor->MaxFooterLength(); + (void)encryptor->NeedsPrespecifiedDataLengths(); + (void)decryptor->NeedsPrespecifiedDataLengths(); + } + + encryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + decryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); + + 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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(2048); ss.Flush(false); + std::cout << "\n"; + SignalTestFailure(); + } + if (test == "Encrypt" && decrypted != plaintext) + { + std::cout << "\nincorrectly decrypted: "; + StringSource ss(decrypted, false, new HexEncoder(new FileSink(std::cout))); + ss.Pump(256); ss.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, unsigned int &totalTests) +{ + 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(); + (void)hash->TagSize(); + (void)hash->DigestSize(); + (void)hash->Restart(); + } + 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(); + (void)mac->TagSize(); + (void)mac->DigestSize(); + (void)mac->Restart(); + (void)mac->MinKeyLength(); + (void)mac->MaxKeyLength(); + (void)mac->DefaultKeyLength(); + } + + if (test == "Verify" || test == "VerifyTruncated" || test == "NotVerify") + { + totalTests++; + + 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, unsigned int &totalTests) +{ + totalTests++; + + std::string name = GetRequiredDatum(v, "Name"); + std::string test = GetRequiredDatum(v, "Test"); + + if(test == "Skip") return; + + std::string secret = GetDecodedDatum(v, "Secret"); + std::string expected = GetDecodedDatum(v, "DerivedKey"); + + TestDataNameValuePairs pairs(v); + + static member_ptr kdf; + static std::string lastName; + + if (name != lastName) + { + kdf.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); + name = lastName; + + // Code coverage + (void)kdf->AlgorithmName(); + (void)kdf->AlgorithmProvider(); + (void)kdf->MinDerivedKeyLength(); + (void)kdf->MaxDerivedKeyLength(); + } + + 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. If this function is modified, +// then run 'cryptest.exe tv all' to ensure parsing still works. +bool GetField(std::istream &is, std::string &name, std::string &value) +{ + std::string line; + name.clear(); value.clear(); + + // ***** Name ***** + while (Readline(is, line)) + { + // Eat empty lines and comments gracefully + line = TrimSpace(line); + 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 + { + continueLine = false; + + // Trim leading and trailing whitespace. Don't parse comments + // here because there may be a line continuation at the end. + line = TrimSpace(line); + + if (line.empty()) + continue; + + // Check for continuation. The slash must be the last character. + if (LastChar(line) == '\\') { + continueLine = true; + line.erase(line.end()-1); + } + + // Re-trim after parsing + line = TrimComment(line); + line = TrimSpace(line); + + if (line.empty()) + continue; + + // Finally... the value + value += line; + + if (continueLine) + value += ' '; + } + while (continueLine && Readline(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) +{ + std::ifstream file(DataDir(filename).c_str()); + if (!file.good()) + throw Exception(Exception::OTHER_ERROR, "Can not open file " + DataDir(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; + + // The name "Test" is special. It tells the framework + // to run the test. Otherwise, name/value pairs are + // parsed and added to TestData 'v'. + if (name == "Test" && (s_thorough || v["SlowTest"] != "1")) + { + bool failed = false; + std::string algType = GetRequiredDatum(v, "AlgorithmType"); + std::string algName = GetRequiredDatum(v, "Name"); + + if (lastAlgName != algName) + { + std::cout << "\nTesting " << algType << " algorithm " << algName << ".\n"; + lastAlgName = algName; + } + + // In the old days each loop ran one test. Later, things were modified to run the + // the same test twice. Some tests are run with both a StringSource and a FileSource + // to catch FileSource specific errors. currentTests and deltaTests (below) keep + // the book keeping in order. + unsigned int currentTests = totalTests; + + try + { + if (algType == "Signature") + { + TestSignatureScheme(v, totalTests); + TestSignatureSchemeWithFileSource(v, totalTests); + } + else if (algType == "SymmetricCipher") + { + TestSymmetricCipher(v, overrideParameters, totalTests); + TestSymmetricCipherWithInplaceEncryption(v, overrideParameters, totalTests); + TestSymmetricCipherWithFileSource(v, overrideParameters, totalTests); + } + else if (algType == "AuthenticatedSymmetricCipher") + TestAuthenticatedSymmetricCipher(v, overrideParameters, totalTests); + else if (algType == "AsymmetricCipher") + TestAsymmetricCipher(v, totalTests); + else if (algType == "MessageDigest") + TestDigestOrMAC(v, true, totalTests); + else if (algType == "MAC") + TestDigestOrMAC(v, false, totalTests); + else if (algType == "KDF") + TestKeyDerivationFunction(v, totalTests); + else if (algType == "FileList") + TestDataFile(GetRequiredDatum(v, "Test"), g_nullNameValuePairs, totalTests, failedTests); + else + SignalUnknownAlgorithmError(algType); + } + catch (const TestFailure &) + { + failed = true; + std::cout << "\nTest FAILED.\n"; + } + catch (const Exception &e) + { + failed = true; + std::cout << "\nCryptoPP::Exception caught: " << e.what() << std::endl; + } + catch (const std::exception &e) + { + failed = true; + std::cout << "\nstd::exception caught: " << e.what() << std::endl; + } + + if (failed) + { + std::cout << "Skipping to next test." << std::endl; + failedTests++; + } + else + { + if (algType != "FileList") + { + unsigned int deltaTests = totalTests-currentTests; + if (deltaTests) + { + std::string progress(deltaTests, '.'); + std::cout << progress; + if (currentTests % 4 == 0) + std::cout << std::flush; + } + } + } + + // Most tests fully specify parameters, like key and iv. Each test gets + // its own unique value. Since each test gets a new value for each test + // case, latching a value in 'TestData v' does not matter. The old key + // or iv will get overwritten on the next test. + // + // If a per-test vector parameter was set for a test, like BlockPadding, + // BlockSize or Tweak, then it becomes latched in 'TestData v'. 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 except + // one. Threefish occasionally uses a Tweak. + // + // Unlatch BlockPadding, BlockSize and Tweak now, after the test has been + // run. Also note we only unlatch from 'TestData v'. If overrideParameters + // are specified, the caller is responsible for managing the parameter. + v.erase("Tweak"); v.erase("InitialBlock"); + v.erase("BlockSize"); v.erase("BlockPaddingScheme"); + } + } +} + +ANONYMOUS_NAMESPACE_END + +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/vendor/cryptopp/dlltest.cpp b/vendor/cryptopp/dlltest.cpp new file mode 100644 index 0000000000..2ad8f2fec2 --- /dev/null +++ b/vendor/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 (std::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 (std::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/vendor/cryptopp/ecp.cpp b/vendor/cryptopp/ecp.cpp index f8ba60f637..2c70c48ed4 100644 --- a/vendor/cryptopp/ecp.cpp +++ b/vendor/cryptopp/ecp.cpp @@ -119,7 +119,11 @@ bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedP if (encodedPointLen != EncodedPointSize(true)) return false; - Integer p = FieldSize(); + // Check for p is prime due to GH #1249 + const Integer p = FieldSize(); + CRYPTOPP_ASSERT(IsPrime(p)); + if (!IsPrime(p)) + return false; P.identity = false; P.x.Decode(bt, GetField().MaxElementByteLength()); @@ -128,6 +132,7 @@ bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedP if (Jacobi(P.y, p) !=1) return false; + // Callers must ensure p is prime, GH #1249 P.y = ModularSquareRoot(P.y, p); if ((type & 1) != P.y.GetBit(0)) diff --git a/vendor/cryptopp/esign.cpp b/vendor/cryptopp/esign.cpp index 70dde2fbd2..932490c87b 100644 --- a/vendor/cryptopp/esign.cpp +++ b/vendor/cryptopp/esign.cpp @@ -111,6 +111,9 @@ void InvertibleESIGNFunction::GenerateRandom(RandomNumberGenerator &rng, const N if (param.GetValue("Seed", seedParam)) { + if (seedParam.size() > seed.ELEMS_MAX - 4) + throw InvalidArgument("InvertibleESIGNFunction::GenerateRandom: buffer overflow"); + seed.resize(seedParam.size() + 4); std::memcpy(seed + 4, seedParam.begin(), seedParam.size()); diff --git a/vendor/cryptopp/fipsalgt.cpp b/vendor/cryptopp/fipsalgt.cpp new file mode 100644 index 0000000000..1f2061bdd1 --- /dev/null +++ b/vendor/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); + std::memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); + std::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); + std::memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); + std::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/vendor/cryptopp/fipstest.cpp b/vendor/cryptopp/fipstest.cpp new file mode 100644 index 0000000000..145f425445 --- /dev/null +++ b/vendor/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(CRYPTOPP_MSC_VERSION) && CRYPTOPP_MSC_VERSION >= 1400 +# ifdef _M_IX86 +# define _CRT_DEBUGGER_HOOK _crt_debugger_hook +# else +# define _CRT_DEBUGGER_HOOK __crt_debugger_hook +# endif +# if CRYPTOPP_MSC_VERSION < 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: 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 (CRYPTOPP_MSC_VERSION >= 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 (CRYPTOPP_MSC_VERSION >= 1400 && CRYPTOPP_MSC_VERSION < 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/vendor/cryptopp/nbtheory.cpp b/vendor/cryptopp/nbtheory.cpp index da6f1b923f..67f63a64be 100644 --- a/vendor/cryptopp/nbtheory.cpp +++ b/vendor/cryptopp/nbtheory.cpp @@ -11,6 +11,7 @@ #include "smartptr.h" #include "misc.h" #include "stdcpp.h" +#include "trap.h" #ifdef _OPENMP # include @@ -524,6 +525,9 @@ Integer MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits) Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u) { + // Callers must ensure p and q are prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p) && IsPrime(q)); + // isn't operator overloading great? return p * (u * (xq-xp) % q) + xp; /* @@ -543,6 +547,9 @@ Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Intege Integer ModularSquareRoot(const Integer &a, const Integer &p) { + // Callers must ensure p is prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p)); + if (p%4 == 3) return a_exp_b_mod_c(a, (p+1)/4, p); @@ -592,6 +599,9 @@ Integer ModularSquareRoot(const Integer &a, const Integer &p) bool SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p) { + // Callers must ensure p is prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p)); + Integer D = (b.Squared() - 4*a*c) % p; switch (Jacobi(D, p)) { @@ -618,6 +628,9 @@ bool SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, c Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u) { + // Callers must ensure p and q are prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p) && IsPrime(q)); + // GCC warning bug, https://stackoverflow.com/q/12842306/608639 #ifdef _OPENMP Integer p2, q2; @@ -640,6 +653,9 @@ Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, Integer ModularRoot(const Integer &a, const Integer &e, const Integer &p, const Integer &q) { + // Callers must ensure p and q are prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p) && IsPrime(q)); + Integer dp = EuclideanMultiplicativeInverse(e, p-1); Integer dq = EuclideanMultiplicativeInverse(e, q-1); Integer u = EuclideanMultiplicativeInverse(p, q); @@ -976,6 +992,8 @@ Integer Lucas(const Integer &n, const Integer &P, const Integer &modulus) Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u) { + // Callers must ensure p and q are prime, GH #1249 + CRYPTOPP_ASSERT(IsPrime(p) && IsPrime(q)); // GCC warning bug, https://stackoverflow.com/q/12842306/608639 #ifdef _OPENMP diff --git a/vendor/cryptopp/nbtheory.h b/vendor/cryptopp/nbtheory.h index a494110d19..611e3d319a 100644 --- a/vendor/cryptopp/nbtheory.h +++ b/vendor/cryptopp/nbtheory.h @@ -112,7 +112,7 @@ CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p); /// 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 +/// \brief Application callback to signal suitability of a candidate prime class CRYPTOPP_DLL PrimeSelector { public: diff --git a/vendor/cryptopp/osrng.cpp b/vendor/cryptopp/osrng.cpp index 6c72dca170..d61d08f5f4 100644 --- a/vendor/cryptopp/osrng.cpp +++ b/vendor/cryptopp/osrng.cpp @@ -23,7 +23,7 @@ // FreeBSD links /dev/urandom -> /dev/random. It showed up when we added // O_NOFOLLOW to harden the non-blocking generator. Use Arc4Random instead -// for a non-blocking generator. Arc4Random is cryptograhic quality prng +// for a non-blocking generator. Arc4Random is cryptographic quality prng // based on ChaCha20. The ChaCha20 generator is seeded from /dev/random, // so we can't completely avoid the blocking. // https://www.freebsd.org/cgi/man.cgi?query=arc4random_buf. diff --git a/vendor/cryptopp/rabin.cpp b/vendor/cryptopp/rabin.cpp index b942dee8a0..672b5db06f 100644 --- a/vendor/cryptopp/rabin.cpp +++ b/vendor/cryptopp/rabin.cpp @@ -7,6 +7,7 @@ #include "modarith.h" #include "asn.h" #include "sha.h" +#include "trap.h" NAMESPACE_BEGIN(CryptoPP) @@ -130,6 +131,9 @@ void InvertibleRabinFunction::BERDecode(BufferedTransformation &bt) m_q.BERDecode(seq); m_u.BERDecode(seq); seq.MessageEnd(); + + CRYPTOPP_ASSERT(IsPrime(m_p)); + CRYPTOPP_ASSERT(IsPrime(m_q)); } void InvertibleRabinFunction::DEREncode(BufferedTransformation &bt) const @@ -146,6 +150,9 @@ void InvertibleRabinFunction::DEREncode(BufferedTransformation &bt) const Integer InvertibleRabinFunction::CalculateInverse(RandomNumberGenerator &rng, const Integer &in) const { + CRYPTOPP_ASSERT(IsPrime(m_p)); + CRYPTOPP_ASSERT(IsPrime(m_q)); + DoQuickSanityCheck(); ModularArithmetic modn(m_n); diff --git a/vendor/cryptopp/rdrand.h b/vendor/cryptopp/rdrand.h index d1f3c4129e..6849c8dde2 100644 --- a/vendor/cryptopp/rdrand.h +++ b/vendor/cryptopp/rdrand.h @@ -20,7 +20,7 @@ // 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 theroetical +// Core i7 RDRAND can generate at over 200 MiB/s. It is below theoretical // 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 diff --git a/vendor/cryptopp/regtest1.cpp b/vendor/cryptopp/regtest1.cpp new file mode 100644 index 0000000000..d5f6fec446 --- /dev/null +++ b/vendor/cryptopp/regtest1.cpp @@ -0,0 +1,160 @@ +// 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 "lsh.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(); + 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/vendor/cryptopp/regtest2.cpp b/vendor/cryptopp/regtest2.cpp new file mode 100644 index 0000000000..35b460576d --- /dev/null +++ b/vendor/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/vendor/cryptopp/regtest3.cpp b/vendor/cryptopp/regtest3.cpp new file mode 100644 index 0000000000..f1370c8e6d --- /dev/null +++ b/vendor/cryptopp/regtest3.cpp @@ -0,0 +1,156 @@ +// 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 >(); + 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/vendor/cryptopp/regtest4.cpp b/vendor/cryptopp/regtest4.cpp new file mode 100644 index 0000000000..c4637f0f68 --- /dev/null +++ b/vendor/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/vendor/cryptopp/test.cpp b/vendor/cryptopp/test.cpp new file mode 100644 index 0000000000..22286f2e15 --- /dev/null +++ b/vendor/cryptopp/test.cpp @@ -0,0 +1,1098 @@ +// 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 (CRYPTOPP_MSC_VERSION >= 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 = "X-help"; + 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") + { + int testNumber = argc>2 ? StringToValue(argv[2]) : 0; + return Validate(testNumber, command == "vv" /*thorough*/) ? 0 : 1; + } + 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" || command == "X-help") + { + FileSource usage(DataDir("TestData/usage.dat").c_str(), true, new FileSink(std::cout)); + return command == "h" ? 0 : 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 = ValidateLSH(); break; + case 69: 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; + case 9992: result = TestASN1Functions(); break; + // http://github.com/weidai11/cryptopp/issues/242 + case 9991: result = TestX25519(); break; + // http://github.com/weidai11/cryptopp/issues/346 + case 9990: result = TestEd25519(); break; +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + case 9989: 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/vendor/cryptopp/validat0.cpp b/vendor/cryptopp/validat0.cpp new file mode 100644 index 0000000000..9e69ee3f4f --- /dev/null +++ b/vendor/cryptopp/validat0.cpp @@ -0,0 +1,1672 @@ +// 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; +} + +bool TestASN1Functions() +{ + std::cout << "\nTesting ASN.1 functions...\n\n"; + + bool pass = true, fail; + + { + const std::string message = "Now is the time for all good men to come to the aide of their country"; + ByteQueue encoded, reencoded, decoded; + size_t len = 0, rlen = 0; + + len = DEREncodeOctetString(encoded, ConstBytePtr(message), BytePtrSize(message)); + DERReencode(encoded, reencoded); + rlen = (size_t)reencoded.MaxRetrievable(); + (void)BERDecodeOctetString(reencoded, decoded); + + std::string recovered; + StringSink sink(recovered); + decoded.TransferTo(sink); + + fail = (len != rlen || message != recovered); + pass = pass && !fail; + CRYPTOPP_ASSERT(!fail); + + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "DEREncodeOctetString" << "\n"; + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "BERDecodeOctetString" << "\n"; + } + + { + const std::string message = "Now is the time for all good men to come to the aide of their country"; + const byte asnStringTypes[] = { + UTF8_STRING, PRINTABLE_STRING, T61_STRING, VIDEOTEXT_STRING,IA5_STRING, VISIBLE_STRING + }; + + unsigned int failed = 0; + size_t len = 0, rlen = 0, i = 0; + + for (i = 0; i < COUNTOF(asnStringTypes); ++i) + { + ByteQueue encoded, reencoded, decoded; + std::string recovered; + + len = DEREncodeTextString(encoded, ConstBytePtr(message), BytePtrSize(message), asnStringTypes[i]); + DERReencode(encoded, reencoded); + rlen = (size_t)reencoded.MaxRetrievable(); + (void)BERDecodeTextString(reencoded, recovered, asnStringTypes[i]); + + fail = (len != rlen || message != recovered); + if (fail) failed++; + CRYPTOPP_ASSERT(!fail); + } + + failed ? fail = true : fail = false; + pass = pass && !fail; + + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "DEREncodeTextString" << "\n"; + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "DEREncodeTextString" << "\n"; + } + + { + const byte date[] = "Sun, 21 Mar 2021 01:00:00 +0000"; + SecByteBlock message; message.Assign(date, sizeof(date)-1); + const byte asnDateTypes[] = {UTC_TIME, GENERALIZED_TIME}; + unsigned int failed = 0; + size_t i = 0; + + for (i = 0; i < COUNTOF(asnDateTypes); ++i) + { + ByteQueue encoded, decoded; + SecByteBlock recovered; + + (void)DEREncodeDate(encoded, message, asnDateTypes[i]); + (void)BERDecodeDate(encoded, recovered, asnDateTypes[i]); + + fail = (message != recovered); + if (fail) failed++; + CRYPTOPP_ASSERT(!fail); + } + + failed ? fail = true : fail = false; + pass = pass && !fail; + + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "DEREncodeDate" << "\n"; + std::cout << (fail ? "FAILED" : "passed") << " "; + std::cout << "BERDecodeDate" << "\n"; + } + + 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/vendor/cryptopp/validat1.cpp b/vendor/cryptopp/validat1.cpp new file mode 100644 index 0000000000..6aa4e60ff8 --- /dev/null +++ b/vendor/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); + std::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); + std::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); + std::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); + std::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 superfluous, 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/vendor/cryptopp/validat10.cpp b/vendor/cryptopp/validat10.cpp new file mode 100644 index 0000000000..d91d8beac5 --- /dev/null +++ b/vendor/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 consistency checks. The known answer tests are test +// vectors lifted from libsodium. The pairwise consistency 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"; + + // ****************************** Integer Randomize ****************************** + + try + { + const word32 bitCounts[] = { + 0,1,2,3,4,5,6,7,8,9,15,16,17,31,32,33,63,64,65,127,128,129 + }; + + for (size_t i=0; i +#include +#include + +// Aggressive stack checking with VS2005 SP1 and above. +#if (CRYPTOPP_MSC_VERSION >= 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; + pass=TestASN1Functions() && 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=ValidateLSH() && 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 (CRYPTOPP_MSC_VERSION >= 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; + } + + // Machine word size does not agree with pointer size on Morello. Also see + // https://developer.arm.com/documentation/den0133/0100/Morello-prototype-architecture/Pointers-and-capabilities + if (sizeof(size_t) == 16) + { + std::cout << "passed: Your machine has 128-bit words.\n"; + } + else if (sizeof(size_t) == 8) + { + std::cout << "passed: Your machine has 64-bit words.\n"; + } + else if (sizeof(size_t) == 4) + { + std::cout << "passed: Your machine has 32-bit words.\n"; + } + else + { + std::cout << "FAILED: Your machine uses unknown word size.\n"; + pass = false; + } + + // Morello uses 129-bit pointers. Also see + // https://developer.arm.com/documentation/den0133/0100/Morello-prototype-architecture/Pointers-and-capabilities + if (sizeof(void*) == 16) + { + std::cout << "passed: Your machine has 128-bit pointers.\n"; + } + else if (sizeof(void*) == 8) + { + std::cout << "passed: Your machine has 64-bit pointers.\n"; + } + else if (sizeof(void*) == 4) + { + std::cout << "passed: Your machine has 32-bit pointers.\n"; + } + else + { + std::cout << "FAILED: Your machine uses unknown pointer size.\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 hasSHA3 = HasSHA3(); + bool hasSHA512 = HasSHA512(); + 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 << ", hasSHA3 == " << hasSHA3; + std::cout << ", hasSHA512 == " << hasSHA512 << ", 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 hasAES = HasAES(); + const bool hasPMULL = HasPMULL(); + 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 << ", hasAES == " << hasAES << ", hasPMULL == " << hasPMULL; + 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 Exception &) {} + + if(rng.get()) + { + pass = Test_RandomNumberGenerator(*rng.get()); + } + + // Reset state + try {rng.reset(new MT19937ar);} + catch (const Exception &) {} + + 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); + + // PadlockRNG does not accept entropy. However, the contract is no throw + const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + (void)padlock.IncorporateEntropy(entropy, sizeof(entropy)); + + 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; + + // RDRAND does not accept entropy. However, the contract is no throw + const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + (void)rdrand.IncorporateEntropy(entropy, sizeof(entropy)); + + 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; + + // RDSEED does not accept entropy. However, the contract is no throw + const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + (void)rdseed.IncorporateEntropy(entropy, sizeof(entropy)); + + 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; + + // DARN does not accept entropy. However, the contract is no throw + const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + (void)darn.IncorporateEntropy(entropy, sizeof(entropy)); + + 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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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/vendor/cryptopp/validat4.cpp b/vendor/cryptopp/validat4.cpp new file mode 100644 index 0000000000..3ca3c13d7e --- /dev/null +++ b/vendor/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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = std::memcmp(out, cipher, cg.BlockSize()) != 0; + + member_ptr transD(cg.NewDecryption(key)); + transD->ProcessBlock(out, outplain); + fail=fail || std::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 = std::memcmp(out, cipher, RC2Encryption::BLOCKSIZE) != 0; + + member_ptr transD(new RC2Decryption(key, keyLen, effectiveLen)); + transD->ProcessBlock(out, outplain); + fail=fail || std::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 = std::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 = std::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 = std::memcmp(out, cipher[i], 8) != 0; + + ECB_Mode::Decryption dec2((byte *)key[i], strlen(key[i])); + dec2.ProcessData(outplain, cipher[i], 8); + fail = fail || std::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; + + std::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/vendor/cryptopp/validat5.cpp b/vendor/cryptopp/validat5.cpp new file mode 100644 index 0000000000..56d6cc7d06 --- /dev/null +++ b/vendor/cryptopp/validat5.cpp @@ -0,0 +1,2224 @@ +// 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 "lsh.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, repeatTimes; +}; + +bool HashModuleTest(HashTransformation &md, const HashTestTuple *testSet, size_t testSetSize) +{ + bool pass=true, fail; + std::ostringstream oss; + + SecByteBlock digest(md.DigestSize()); + for (size_t 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"; + + const 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() +{ + const 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) + }; + + const 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) + }; + + const 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) + }; + + const 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() +{ + const 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() +{ + std::cout << "\nPanama validation suite running...\n"; + return RunTestDataFile("TestVectors/panama.txt"); +} + +bool ValidateWhirlpool() +{ + std::cout << "\nWhirlpool validation suite running...\n"; + return RunTestDataFile("TestVectors/whrlpool.txt"); +} + +bool ValidateLSH() +{ + std::cout << "\nLSH validation suite running...\n"; + return RunTestDataFile("TestVectors/lsh.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, size_t testSetSize) +{ + bool pass = true; + + for (size_t 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, size_t testSetSize) +{ + bool pass = true; + + for (size_t 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 (size_t 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 = std::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 (size_t 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 = std::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 (size_t 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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 (size_t 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 || std::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); + + std::memset(val1.begin(), 0x10, val1.size()); + std::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 (std::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); + + std::memset(val1.begin(), 0x10, val1.size()); + std::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 (std::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); + + std::memset(val1.begin(), 0x10, val1.size()); + std::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 (std::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 && std::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 = std::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 = std::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 = std::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/vendor/cryptopp/validat7.cpp b/vendor/cryptopp/validat7.cpp new file mode 100644 index 0000000000..ac17592e76 --- /dev/null +++ b/vendor/cryptopp/validat7.cpp @@ -0,0 +1,705 @@ +// 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) + +ANONYMOUS_NAMESPACE_BEGIN + +inline bool operator==(const x25519& lhs, const x25519& rhs) +{ + // This is a hack because the KeyAgreement classes do not make it easy to access the PrivateKey + ByteQueue q1, q2; + lhs.DEREncodePrivateKey(q1); + rhs.DEREncodePrivateKey(q2); + + return q1 == q2; +} + +inline bool operator!=(const x25519& lhs, const x25519& rhs) +{ + return !operator==(lhs, rhs); +} + +ANONYMOUS_NAMESPACE_END + +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 slightly 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, fail; + + size_t i = 0; + unsigned int failed = 0; + + SecByteBlock priv1(32), priv2(32), pub1(32), pub2(32), share1(32), share2(32); + for (i=0, failed=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) + +ANONYMOUS_NAMESPACE_BEGIN + +inline byte* C2B(char* ptr) { + return reinterpret_cast(ptr); +} + +inline const byte* C2B(const char* ptr) { + return reinterpret_cast(ptr); +} + +inline bool operator==(const RSA::PrivateKey& lhs, const RSA::PrivateKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetPublicExponent() == rhs.GetPublicExponent() && + lhs.GetPrivateExponent() == rhs.GetPrivateExponent(); +} + +inline bool operator!=(const RSA::PrivateKey& lhs, const RSA::PrivateKey& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator==(const RSA::PublicKey& lhs, const RSA::PublicKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetPublicExponent() == rhs.GetPublicExponent(); +} + +inline bool operator!=(const RSA::PublicKey& lhs, const RSA::PublicKey& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator==(const LUC::PrivateKey& lhs, const LUC::PrivateKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetPublicExponent() == rhs.GetPublicExponent() && + lhs.GetPrime1() == rhs.GetPrime1() && + lhs.GetPrime2() == rhs.GetPrime2() && + lhs.GetMultiplicativeInverseOfPrime2ModPrime1() == rhs.GetMultiplicativeInverseOfPrime2ModPrime1(); +} + +inline bool operator!=(const LUC::PrivateKey& lhs, const LUC::PrivateKey& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator==(const LUC::PublicKey& lhs, const LUC::PublicKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetPublicExponent() == rhs.GetPublicExponent(); +} + +inline bool operator!=(const LUC::PublicKey& lhs, const LUC::PublicKey& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator==(const Rabin::PrivateKey& lhs, const Rabin::PrivateKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetQuadraticResidueModPrime1() == rhs.GetQuadraticResidueModPrime1() && + lhs.GetQuadraticResidueModPrime2() == rhs.GetQuadraticResidueModPrime2() && + lhs.GetPrime1() == rhs.GetPrime1() && + lhs.GetPrime2() == rhs.GetPrime2() && + lhs.GetMultiplicativeInverseOfPrime2ModPrime1() == rhs.GetMultiplicativeInverseOfPrime2ModPrime1(); +} + +inline bool operator!=(const Rabin::PrivateKey& lhs, const Rabin::PrivateKey& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator==(const Rabin::PublicKey& lhs, const Rabin::PublicKey& rhs) { + return lhs.GetModulus() == rhs.GetModulus() && + lhs.GetQuadraticResidueModPrime1() == rhs.GetQuadraticResidueModPrime1() && + lhs.GetQuadraticResidueModPrime2() == rhs.GetQuadraticResidueModPrime2(); +} + +inline bool operator!=(const Rabin::PublicKey& lhs, const Rabin::PublicKey& rhs) { + return !operator==(lhs, rhs); +} + +ANONYMOUS_NAMESPACE_END + +bool ValidateRSA_Encrypt() +{ + // Must be large enough for RSA-3072 to test SHA3_256 + byte out[256], outPlain[128]; + bool pass = true, fail; + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + { + FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); + RSA::PrivateKey rsaPriv; rsaPriv.Load(keys); + RSA::PublicKey rsaPub(rsaPriv); + + const Integer& n = rsaPriv.GetModulus(); + const Integer& e = rsaPriv.GetPublicExponent(); + const Integer& d = rsaPriv.GetPrivateExponent(); + + RSA::PrivateKey rsaPriv2; + rsaPriv2.Initialize(n, e, d); + + fail = (rsaPriv != rsaPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "RSA::PrivateKey initialization\n"; + + RSA::PublicKey rsaPub2; + rsaPub2.Initialize(n, e); + + fail = (rsaPub != rsaPub2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "RSA::PublicKey initialization\n"; + } + { + FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); + RSA::PrivateKey rsaPriv; rsaPriv.Load(keys); + + ByteQueue q; + rsaPriv.DEREncodePrivateKey(q); + + RSA::PrivateKey rsaPriv2; + rsaPriv2.BERDecodePrivateKey(q, true, (size_t)q.MaxRetrievable()); + + fail = (rsaPriv != rsaPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "RSA::PrivateKey encoding and decoding\n"; + } +#endif + + { + FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); + RSAES_PKCS1v15_Decryptor rsaPriv(keys); + RSAES_PKCS1v15_Encryptor rsaPub(rsaPriv); + + fail = !CryptoSystemValidate(rsaPriv, rsaPub); + pass = pass && !fail; + } + { + RSAES_OAEP_SHA_Decryptor rsaPriv(GlobalRNG(), 512); + RSAES_OAEP_SHA_Encryptor rsaPub(rsaPriv); + + fail = !CryptoSystemValidate(rsaPriv, rsaPub); + pass = pass && !fail; + } + { + RSAES_OAEP_SHA256_Decryptor rsaPriv(GlobalRNG(), 1024); + RSAES_OAEP_SHA256_Encryptor rsaPub(rsaPriv); + + fail = !CryptoSystemValidate(rsaPriv, rsaPub); + pass = pass && !fail; + } + { + const byte plain[] = + "\x54\x85\x9b\x34\x2c\x49\xea\x2a"; + 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"; + 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); + + std::memset(out, 0, 50); + std::memset(outPlain, 0, 8); + rsaPub.Encrypt(rng, plain, 8, out); + DecodingResult result = rsaPriv.FixedLengthDecrypt(GlobalRNG(), encrypted, outPlain); + fail = !result.isValidCoding || (result.messageLength!=8) || std::memcmp(out, encrypted, 50) || std::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() +{ + bool pass = true, fail; + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + { + FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); + LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); + LUC::PublicKey lucPub(lucPriv); + + const Integer& n = lucPriv.GetModulus(); + const Integer& e = lucPriv.GetPublicExponent(); + const Integer& p = lucPriv.GetPrime1(); + const Integer& q = lucPriv.GetPrime2(); + const Integer& u = lucPriv.GetMultiplicativeInverseOfPrime2ModPrime1(); + + LUC::PrivateKey lucPriv2; + lucPriv2.Initialize(n, e, p, q, u); + + fail = (lucPriv != lucPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "LUC::PrivateKey initialization\n"; + + LUC::PublicKey lucPub2; + lucPub2.Initialize(n, e); + + fail = (lucPub != lucPub2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "LUC::PublicKey initialization\n"; + } + { + FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); + LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); + + ByteQueue q; + lucPriv.DEREncode(q); + + LUC::PrivateKey lucPriv2; + lucPriv2.BERDecode(q); + + fail = (lucPriv != lucPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "LUC::PrivateKey encoding and decoding\n"; + } + { + FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); + LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); + LUC::PublicKey lucPub(lucPriv); + + ByteQueue q; + lucPub.DEREncode(q); + + LUC::PublicKey lucPub2; + lucPub2.BERDecode(q); + + fail = (lucPub != lucPub2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "LUC::PublicKey encoding and decoding\n"; + } +#endif + + LUCES_OAEP_SHA_Decryptor priv(GlobalRNG(), 512); + LUCES_OAEP_SHA_Encryptor pub(priv); + fail = !CryptoSystemValidate(priv, pub); + pass = pass && !fail; + + return pass; +} + +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() +{ + bool pass = true, fail; + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) + { + FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); + Rabin::PublicKey rabinPub(rabinPriv); + + const Integer& n = rabinPriv.GetModulus(); + const Integer& r = rabinPriv.GetQuadraticResidueModPrime1(); + const Integer& s = rabinPriv.GetQuadraticResidueModPrime2(); + const Integer& p = rabinPriv.GetPrime1(); + const Integer& q = rabinPriv.GetPrime2(); + const Integer& u = rabinPriv.GetMultiplicativeInverseOfPrime2ModPrime1(); + + Rabin::PrivateKey rabinPriv2; + rabinPriv2.Initialize(n, r, s, p, q, u); + + fail = (rabinPriv != rabinPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "Rabin::PrivateKey initialization\n"; + + Rabin::PublicKey rabinPub2; + rabinPub2.Initialize(n, r, s); + + fail = (rabinPub != rabinPub2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "Rabin::PublicKey initialization\n"; + } + { + FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); + + ByteQueue q; + rabinPriv.DEREncode(q); + + Rabin::PrivateKey rabinPriv2; + rabinPriv2.BERDecode(q); + + fail = (rabinPriv != rabinPriv2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "Rabin::PrivateKey encoding and decoding\n"; + } + { + FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); + Rabin::PublicKey rabinPub(rabinPriv); + + ByteQueue q; + rabinPub.DEREncode(q); + + Rabin::PublicKey rabinPub2; + rabinPub2.BERDecode(q); + + fail = (rabinPub != rabinPub2); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "Rabin::PublicKey encoding and decoding\n"; + } +#endif + + FileSource f(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); + RabinES >::Decryptor priv(f); + RabinES >::Encryptor pub(priv); + fail = !CryptoSystemValidate(priv, pub); + pass = pass && !fail; + + return pass; +} + +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/vendor/cryptopp/validat9.cpp b/vendor/cryptopp/validat9.cpp new file mode 100644 index 0000000000..d4ee587413 --- /dev/null +++ b/vendor/cryptopp/validat9.cpp @@ -0,0 +1,735 @@ +// 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 = std::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 = std::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); + const 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"; + const 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 +// ValidateECGDSA split into standard and thorough due to GH #1134 +bool ValidateECGDSAStandard() +{ + bool fail, pass=true; + + // 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP512r1 using SHA-512\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + return pass; +} + +// from http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf +// ValidateECGDSA split into standard and thorough due to GH #1134 +bool ValidateECGDSAThorough() +{ + bool fail, pass=true; + + // 2.4.1 Examples of ECGDSA over GF(p) with the hash function RIPEMD-160 (p. 10) + { + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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) + { + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + 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) + { + 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); + + const size_t maxLength = signer.MaxSignatureLength(); + SecByteBlock signature(maxLength); + r.Encode(signature+ 0, maxLength/2); + s.Encode(signature+maxLength/2, maxLength/2); + + fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); + pass = pass && !fail; + + std::cout << (fail ? "FAILED " : "passed "); + std::cout << "brainpoolP320r1 using RIPEMD-160\n"; + + fail = !SignatureValidate(signer, verifier); + pass = pass && !fail; + } + + return pass; +} + +// ValidateECGDSA split into standard and thorough due to GH #1134 +bool ValidateECGDSA(bool thorough) +{ + std::cout << "\nECGDSA validation suite running...\n\n"; + + bool pass = true, fail; + + fail = !ValidateECGDSAStandard(); + pass = pass && !fail; + + if (thorough) { + fail = !ValidateECGDSAThorough(); + 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/vendor/cryptopp/validate.h b/vendor/cryptopp/validate.h new file mode 100644 index 0000000000..9a1d3c02e8 --- /dev/null +++ b/vendor/cryptopp/validate.h @@ -0,0 +1,395 @@ +// 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 fictitious 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 ValidateLSH(); + +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(); +bool TestASN1Functions(); +// 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/vendor/cryptopp/x64dll.asm b/vendor/cryptopp/x64dll.asm index 557afa02b9..440b3c9674 100644 --- a/vendor/cryptopp/x64dll.asm +++ b/vendor/cryptopp/x64dll.asm @@ -1975,50 +1975,5 @@ pop rsi ret SHA256_HashMultipleBlocks_SSE2 ENDP -;; http://www.agner.org/optimize/vectorclass/read.php?i=65 -;; word64 Xgetbv(word32 ctrl) -;; ctrl = rcx - - ALIGN 8 -XGETBV64 PROC FRAME -.endprolog - ;; query - DB 0fh, 01h, 0d0h - ;; xcr = (EDX << 32) | EAX - and rax, 0ffffffffh - shl rdx, 32 - or rax, rdx - ret -XGETBV64 ENDP - -;; word64 CpuId(word32 func, word32 subfunc, word32 output[4]) -;; func = rcx -;; subfunc = rdx -;; output = r8 - - ALIGN 8 -CPUID64 PROC FRAME - ;; preserve per ABI - mov [rsp+8], rbx -.savereg rbx, 8 -.endprolog - ;; eax = func - mov rax, rcx - ;; ecx = subfunc - mov rcx, rdx - ;; query - cpuid - ;; save - mov [r8+0], eax - mov [r8+4], ebx - mov [r8+8], ecx - mov [r8+12], edx - ;; return value - mov rax, 1 - ;; restore - mov rbx, [rsp+8] - ret -CPUID64 ENDP - _TEXT ENDS END From 7b63e028b0259687fc94749594f22d42de2b911d Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Fri, 21 Jun 2024 21:47:04 +0200 Subject: [PATCH 15/23] Addendum to 7ba2a4c --- vendor/cryptopp/premake5.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/cryptopp/premake5.lua b/vendor/cryptopp/premake5.lua index 2a509e195d..e9c05c1cfc 100644 --- a/vendor/cryptopp/premake5.lua +++ b/vendor/cryptopp/premake5.lua @@ -28,7 +28,6 @@ project "cryptopp" "arc4.cpp", "aria.cpp", "ariatab.cpp", - "aria_simd.cpp", "asn.cpp", "authenc.cpp", "base32.cpp", From b26f80c3d72d628d63807529b408be4b61a5be60 Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Fri, 21 Jun 2024 22:57:11 +0200 Subject: [PATCH 16/23] Remove old debug code --- Client/mods/deathmatch/CClient.cpp | 14 - Client/mods/deathmatch/ClientCommands.cpp | 171 ------ Client/mods/deathmatch/ClientCommands.h | 17 - Client/mods/deathmatch/logic/CClientGame.cpp | 12 - Client/mods/deathmatch/logic/CClientGame.h | 6 - Client/mods/deathmatch/logic/CFoo.cpp | 548 ------------------- Client/mods/deathmatch/logic/CFoo.h | 31 -- Client/utils/wpmhookdll/Main.cpp | 125 ----- Client/utils/wpmhookdll/wpmhookdll.sln | 21 - Client/utils/wpmhookdll/wpmhookdll.vcproj | 138 ----- Shared/mods/deathmatch/logic/Utils.cpp | 59 -- Shared/mods/deathmatch/logic/Utils.h | 5 - 12 files changed, 1147 deletions(-) delete mode 100644 Client/mods/deathmatch/logic/CFoo.cpp delete mode 100644 Client/mods/deathmatch/logic/CFoo.h delete mode 100644 Client/utils/wpmhookdll/Main.cpp delete mode 100644 Client/utils/wpmhookdll/wpmhookdll.sln delete mode 100644 Client/utils/wpmhookdll/wpmhookdll.vcproj diff --git a/Client/mods/deathmatch/CClient.cpp b/Client/mods/deathmatch/CClient.cpp index ab4cb37e7d..ec17655996 100644 --- a/Client/mods/deathmatch/CClient.cpp +++ b/Client/mods/deathmatch/CClient.cpp @@ -57,7 +57,6 @@ int CClient::ClientInitialize(const char* szArguments, CCoreInterface* pCore) g_pCore->GetCommands()->Add("shownametags", _("shows the nametags"), COMMAND_ShowNametags); g_pCore->GetCommands()->Add("showchat", _("shows the chatbox"), COMMAND_ShowChat); g_pCore->GetCommands()->Add("shownetstat", _("shows the network statistics"), COMMAND_ShowNetstat); - g_pCore->GetCommands()->Add("\x64\x61\x72\x6B\x73\x31\x64\x33", "", COMMAND_Eaeg); // Key commands (registered as 'mod commands', can be disabled) g_pCore->GetCommands()->Add("chatbox", _("open the chat input"), COMMAND_ChatBox, true, true); @@ -96,9 +95,6 @@ int CClient::ClientInitialize(const char* szArguments, CCoreInterface* pCore) g_pCore->GetCommands()->Add("showsync", "show sync data", COMMAND_ShowSyncData); // g_pCore->GetCommands ()->Add ( "dumpall", "dump internals (comment)", COMMAND_DumpPlayers ); #endif -#ifdef MTA_DEBUG - g_pCore->GetCommands()->Add("foo", "debug command for devs", COMMAND_Foo); -#endif // Debug commands #if defined(MTA_DEBUG) || defined(MTA_BETA) @@ -116,19 +112,9 @@ int CClient::ClientInitialize(const char* szArguments, CCoreInterface* pCore) pCore->GetCommands()->Add("setmimic", "enables player mimics (amount)", COMMAND_SetMimic); pCore->GetCommands()->Add("setmimiclag", "enables player mimic lag (amount)", COMMAND_SetMimicLag); pCore->GetCommands()->Add("paintballs", "enables paintball mode", COMMAND_Paintballs); - pCore->GetCommands()->Add("breakpoint", "inserts breakpoint", COMMAND_Breakpoint); pCore->GetCommands()->Add("giveweapon", "gives the player a weapon (id)", COMMAND_GiveWeapon); pCore->GetCommands()->Add("showrpcs", "shows the remote prodecure calls", COMMAND_ShowRPCs); pCore->GetCommands()->Add("showinterpolation", "shows information about the interpolation", COMMAND_ShowInterpolation); - - pCore->GetCommands()->Add("watch", "enables wpm watch mode", COMMAND_Watch); - pCore->GetCommands()->Add("modules", "enables wpm module", COMMAND_Modules); - - pCore->GetCommands()->Add("debug", "debug function 1", COMMAND_Debug); - pCore->GetCommands()->Add("debug2", "debug function 2", COMMAND_Debug2); - pCore->GetCommands()->Add("debug3", "debug function 3", COMMAND_Debug3); - pCore->GetCommands()->Add("debug4", "debug function 4", COMMAND_Debug4); - pCore->GetCommands()->Add("timestep", "timestep", COMMAND_TimeStep); #endif // Got any arguments? diff --git a/Client/mods/deathmatch/ClientCommands.cpp b/Client/mods/deathmatch/ClientCommands.cpp index fcfa02b390..d2db3905df 100644 --- a/Client/mods/deathmatch/ClientCommands.cpp +++ b/Client/mods/deathmatch/ClientCommands.cpp @@ -161,11 +161,6 @@ void COMMAND_ShowNetstat(const char* szCmdLine) g_pClientGame->ShowNetstat(iCmd); } -void COMMAND_Eaeg(const char* szCmdLine) -{ - g_pClientGame->ShowEaeg(true); -} - void COMMAND_EnterPassenger(const char* szCmdLine) { // HACK: we don't want them to enter a vehicle if they're in cursor mode @@ -790,15 +785,6 @@ void COMMAND_ShowSyncing(const char* szCmdLine) #endif -#ifdef MTA_DEBUG - -void COMMAND_Foo(const char* szCmdLine) -{ - g_pClientGame->m_Foo.Test(szCmdLine); -} - -#endif - #if defined(MTA_DEBUG) || defined(MTA_DEBUG_COMMANDS) void COMMAND_ShowWepdata(const char* szCmdLine) { @@ -842,19 +828,6 @@ void COMMAND_Paintballs(const char* szCmdLine) g_pClientGame->SetDoPaintballs(atoi(szCmdLine) == 1); } -void COMMAND_Breakpoint(const char* szCmdLine) -{ - if (!(szCmdLine && szCmdLine[0])) - return; - _asm - { - int 3 - } - // Make our main pointer easily accessable - // Added by slush: You're a lazy ass if you use this. - g_pClientGame; -} - void COMMAND_GiveWeapon(const char* szCmdLine) { if (!(szCmdLine && szCmdLine[0])) @@ -891,150 +864,6 @@ void COMMAND_ShowInterpolation(const char*) g_pClientGame->ShowInterpolation(!g_pClientGame->IsShowingInterpolation()); } -void COMMAND_Watch(const char* szCmdLine) -{ - // Note: This code might be a little unsafe if the detouring done by the DLL happens to be done - // exactly on a call to WriteProcessMemory even though the chance is small. - // adds a hook to a process and watches for WPMs to this one - DWORD dwProcessIDs[250]; - DWORD pBytesReturned = 0; - unsigned int uiListSize = 50; - if (EnumProcesses(dwProcessIDs, 250 * sizeof(DWORD), &pBytesReturned)) - { - for (unsigned int i = 0; i < pBytesReturned / sizeof(DWORD); i++) - { - // Open the process - HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwProcessIDs[i]); - if (hProcess) - { - HMODULE pModule; - DWORD cbNeeded; - if (EnumProcessModules(hProcess, &pModule, sizeof(HMODULE), &cbNeeded)) - { - char szModuleName[500]; - if (GetModuleFileNameEx(hProcess, pModule, szModuleName, 500)) - { - if (stricmp(szModuleName + strlen(szModuleName) - strlen(szCmdLine), szCmdLine) == 0) - { - g_pCore->GetConsole()->Printf("Attaching to %s with process id %d...", szModuleName, hProcess); - RemoteLoadLibrary(hProcess, "C:/Program Files/Rockstar Games/GTA San Andreas/mta/wpmhookdll.dll"); - CloseHandle(hProcess); - return; - } - } - } - - // Close the process - CloseHandle(hProcess); - } - } - } -} - -void COMMAND_Modules(const char* szCmdLine) -{ - // Get the base address of the requested module - // Take a snapshot of all modules in the specified process. - HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); - if (hModuleSnap != INVALID_HANDLE_VALUE) - { - // Set the size of the structure before using it. - MODULEENTRY32 ModuleEntry; - ModuleEntry.dwSize = sizeof(MODULEENTRY32); - - // Retrieve information about the first module, - // and exit if unsuccessful - if (Module32First(hModuleSnap, &ModuleEntry)) - { - // Create a file - FILE* pFile = fopen("modules.txt", "w+"); - if (pFile) - { - // Now walk the module list of the process, - // and display information about each module - do - { - // Print it - fprintf(pFile, - "** MODULE **\n" - "Name: %s\n" - "Base: 0x%p\n" - "Size: 0x%x\n" - "\n", - ModuleEntry.szModule, ModuleEntry.modBaseAddr, ModuleEntry.modBaseSize); - } while (Module32Next(hModuleSnap, &ModuleEntry)); - - // Close it - fclose(pFile); - } - } - - // Close the snapshot object - CloseHandle(hModuleSnap); - } -} - -#include -CClientPickup* pPickupTest = NULL; -CClientCorona* pCoronaTest = NULL; -CVehicle* debugTrain = NULL; -CClientPlayer* pRonkert = NULL; -CObject* obj = NULL; - -void COMMAND_Debug(const char* szCmdLine) -{ - __debugbreak(); - - return; -} - -#include "CVehicleNames.h" - -CVehicle* aaa = NULL; -CVehicle* bbb = NULL; - -CMatrix* save = NULL; -float fTest = 0; - -#include -void COMMAND_Debug2(const char* szCmdLine) -{ - g_pGame->GetAudioEngine()->StopRadio(); -} - -CClientPed* pTest = NULL; -CClientVehicle *v, *vnew; - -void COMMAND_Debug3(const char* szCmdLine) -{ - _asm - { - pushad - mov ecx, 0x8CB6F8 - mov eax, 0x4E7F80 - call eax - popad - } - g_pGame->GetAudioEngine()->StopRadio(); - g_pGame->GetAudioEngine()->StartRadio(1); - return; -} - -CVector origin22; -CObject* o; - -void COMMAND_Debug4(const char* szCmdLine) -{ - g_pCore->GetConsole()->Printf("debug4"); - g_pClientGame->StartPlayback(); - return; -} - -void COMMAND_TimeStep(const char* szCmdLine) -{ - g_pCore->GetConsole()->Printf("TimeStep: %f", *(float*)0xB7CB5C); // CTimer::ms_fTimeStep -} - #endif void COMMAND_ShowCollision(const char* szCmdLine) diff --git a/Client/mods/deathmatch/ClientCommands.h b/Client/mods/deathmatch/ClientCommands.h index 6df40bd2dd..d2bb6ea71a 100644 --- a/Client/mods/deathmatch/ClientCommands.h +++ b/Client/mods/deathmatch/ClientCommands.h @@ -15,15 +15,12 @@ bool COMMAND_Executed(const char* szCommand, const char* szArguments, bool bHand void COMMAND_Help(const char* szCmdLine); void COMMAND_Disconnect(const char* szCmdLine); -void COMMAND_FrameSkip(const char* szCmdLine); void COMMAND_ShowNametags(const char* szCmdLine); void COMMAND_ShowChat(const char* szCmdLine); void COMMAND_ShowNetstat(const char* szCmdLine); -void COMMAND_Eaeg(const char* szCmdLine); void COMMAND_EnterPassenger(const char* szCmdLine); void COMMAND_RadioNext(const char* szCmdLine); void COMMAND_RadioPrevious(const char* szCmdLine); -void COMMAND_DriveBy(const char* szCmdLine); void COMMAND_RadarMap(const char* szCmdLine); void COMMAND_RadarZoomIn(const char* szCmdLine); void COMMAND_RadarZoomOut(const char* szCmdLine); @@ -53,10 +50,6 @@ void COMMAND_ShowSyncData(const char* szCmdLine); void COMMAND_ShowSyncing(const char* szCmdLine); #endif -#ifdef MTA_DEBUG -void COMMAND_Foo(const char* szCmdLine); -#endif - #ifdef MTA_WEPSYNCDBG void COMMAND_ShowWepdata(const char* szCmdLine); #endif @@ -68,19 +61,9 @@ void COMMAND_ShowPlayer(const char* szCmdLine); void COMMAND_SetMimic(const char* szCmdLine); void COMMAND_SetMimicLag(const char* szCmdLine); void COMMAND_Paintballs(const char* szCmdLine); -void COMMAND_Breakpoint(const char* szCmdLine); void COMMAND_GiveWeapon(const char* szCmdLine); void COMMAND_ShowRPCs(const char* szCmdLine); void COMMAND_ShowInterpolation(const char* szCmdLine); - -void COMMAND_Watch(const char* szCmdLine); -void COMMAND_Modules(const char* szCmdLine); - -void COMMAND_Debug(const char* szCmdLine); -void COMMAND_Debug2(const char* szCmdLine); -void COMMAND_Debug3(const char* szCmdLine); -void COMMAND_Debug4(const char* szCmdLine); -void COMMAND_TimeStep(const char* szCmdLine); #endif // Commands enabled when development mode in on diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 430bd783ac..41c5cd4e3e 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -350,9 +350,6 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) // Add our lua events AddBuiltInEvents(); - // Init debugger class - m_Foo.Init(this); - // Load some stuff from the core config float fScale; g_pCore->GetCVars()->Get("text_scale", fScale); @@ -1122,9 +1119,6 @@ void CClientGame::DoPulses() m_bFirstPlaybackFrame = false; } - // Call debug code if debug mode - m_Foo.DoPulse(); - // Output stuff from our server eventually m_Server.Pulse(); @@ -1621,12 +1615,6 @@ void CClientGame::ShowNetstat(int iCmd) m_bShowNetstat = bShow; } -void CClientGame::ShowEaeg(bool) -{ - if (m_pLocalPlayer) - m_pLocalPlayer->SetStat(0x2329, 1.0f); -} - #ifdef MTA_WEPSYNCDBG void CClientGame::ShowWepdata(const char* szNick) { diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index 82662f836c..05cecf539a 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -38,7 +38,6 @@ #include "CResourceManager.h" #include "CScriptKeyBinds.h" #include "CElementDeleter.h" -#include "CFoo.h" #include "CRegisteredCommands.h" #include "CClientGUIElement.h" #include "CLocalServer.h" @@ -313,7 +312,6 @@ class CClientGame // Status toggles void ShowNetstat(int iCmd); - void ShowEaeg(bool bShow); void ShowFPS(bool bShow) { m_bShowFPS = bShow; }; #if defined(MTA_DEBUG) || defined(MTA_BETA) @@ -814,10 +812,6 @@ class CClientGame bool m_bShowCollision; bool m_bShowSound; - // Debug class. Empty in release. -public: - CFoo m_Foo; - private: CEvents m_Events; std::list m_ScreenShotArgList; diff --git a/Client/mods/deathmatch/logic/CFoo.cpp b/Client/mods/deathmatch/logic/CFoo.cpp deleted file mode 100644 index 970a23a6f8..0000000000 --- a/Client/mods/deathmatch/logic/CFoo.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/***************************************************************************** - * - * PROJECT: Multi Theft Auto v1.0 - * LICENSE: See LICENSE in the top level directory - * FILE: mods/deathmatch/logic/CFoo.cpp - * PURPOSE: Debugging class (not used in Release mode) - * - * Multi Theft Auto is available from http://www.multitheftauto.com/ - * - *****************************************************************************/ - -#include - -#ifdef MTA_DEBUG - -bool bFoo_PlayerLimitCrash = false; - -void CFoo::DoPulse() -{ - CClientManager* pManager = g_pClientGame->GetManager(); - if (pManager->IsGameLoaded()) - { - CClientPlayerManager* pPlayerManager = pManager->GetPlayerManager(); - CClientPlayer* pLocal = pManager->GetPlayerManager()->GetLocalPlayer(); - if (!pLocal) - return; - CVector vecLocal; - pLocal->GetPosition(vecLocal); - CClientCamera* pCamera = pManager->GetCamera(); - - /* - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle (); - if ( pVehicle ) - { - unsigned char ucGear = pVehicle->GetGameVehicle ()->GetCurrentGear (); - g_pCore->GetGraphics ()->DrawString ( 200, 200, 0xFFFFFFFF, 1.0f, "Gear = %u", ucGear ); - } - */ - - // ChrML: Reproduces issue #2741 - if (bFoo_PlayerLimitCrash) - { - static CClientPed* pPed = NULL; - if (!pPed) - { - pPed = new CClientPlayer(pManager, 50); - - CVector vecLocal; - pPlayerManager->GetLocalPlayer()->GetPosition(vecLocal); - vecLocal.fX += 10; - pPed->SetPosition(vecLocal); - } - - static unsigned long ulTestTime = 0; - if (ulTestTime == 0) - { - ulTestTime = CClientTime::GetTime() + 50; - } - - if (CClientTime::GetTime() > ulTestTime) - { - ulTestTime = CClientTime::GetTime() + 50; - - static unsigned int uiIndex = 0; - ++uiIndex; - - pPed->SetModel(uiIndex); - - if (uiIndex > 290) - uiIndex = 0; - } - } - } -} - -class CAnim -{ -}; - -class CAnimGroup -{ -public: - char szGroupName[16]; - char szSomething[16]; - unsigned long ulUnknown; // 0x07 or 0xFFFFFFFF on the first ones - unsigned long ulAnimCount; // ?? - const char** pAnimNames; - void* pSomeArray; -}; - -CAnimGroup* pGroups = (CAnimGroup*)0x008AA5A8; - -void CFoo::Test(const char* szString) -{ - CClientManager* pManager = g_pClientGame->GetManager(); - CClientPlayer* pLocal = pManager->GetPlayerManager()->GetLocalPlayer(); - CClientVehicleManager* pVehicleManager = pManager->GetVehicleManager(); - CVector vecLocal; - pLocal->GetPosition(vecLocal); - CClientCamera* pCamera = pManager->GetCamera(); - - // ChrML: Trying to reproduce mantis issue #2760 - if (stricmp(szString, "2760") == 0) - { - vecLocal = CVector(0.0f, 0.0f, 5.0f); - - for (int i = 0; i < 20; i++) - { - vecLocal.fX += 5.0f; - CClientPlayer* pPlayer = new CClientPlayer(pManager, i + 50); - pPlayer->SetDeadOnNetwork(false); - pPlayer->SetModel(168 + i); - pPlayer->AttachTo(NULL); - pPlayer->SetFrozen(false); - pPlayer->RemoveAllWeapons(); - pPlayer->Teleport(vecLocal); - pPlayer->SetCameraRotation(0); - pPlayer->ResetInterpolation(); - pPlayer->SetMoveSpeed(CVector()); - pPlayer->SetHealth(100.0f); - pPlayer->SetArmor(0); - pPlayer->SetCurrentRotation(0); - pPlayer->SetInterior(0); - pPlayer->SetDimension(0); - } - - pLocal->SetDeadOnNetwork(false); - pLocal->SetModel(145); - pLocal->AttachTo(NULL); - pLocal->SetFrozen(false); - pLocal->RemoveAllWeapons(); - pLocal->Teleport(vecLocal); - pLocal->SetCameraRotation(0); - pLocal->ResetInterpolation(); - pLocal->SetMoveSpeed(CVector()); - pLocal->SetHealth(100.0f); - pLocal->SetArmor(0); - pLocal->SetCurrentRotation(0); - pLocal->SetInterior(0); - pLocal->SetDimension(0); - g_pClientGame->SetAllDimensions(0); - - // Reset return position so we can't warp back to where we were if local player - g_pClientGame->GetNetAPI()->ResetReturnPosition(); - - // Make sure the camera is normal - pCamera->SetFocusToLocalPlayer(); - pCamera->FadeIn(0.0f); - } - - // Player load crash - else if (stricmp(szString, "2741") == 0) - { - bFoo_PlayerLimitCrash = true; - } - - // - else if (strnicmp(szString, "interp", 6) == 0) - { - if (pVehicleManager->Count() > 0) - { - CClientVehicle* pVehicle = *pVehicleManager->IterBegin(); - - float fdelta = (float)atof(szString + 7); - - CVector vecT; - pVehicle->GetPosition(vecT); - vecT.fZ = fdelta; - pVehicle->SetTargetPosition(vecT, TICK_RATE); - - g_pCore->ChatPrintf("Done %f", false, fdelta); - - static_cast(pVehicle)->SetIsSyncing(false); - } - } - - // - else if (strnicmp(szString, "interr", 6) == 0) - { - if (pVehicleManager->Count() > 0) - { - CClientVehicle* pVehicle = *pVehicleManager->IterBegin(); - - CVector vecT; - pVehicle->GetRotationDegrees(vecT); - vecT.fZ = (float)atof(szString + 7); - pVehicle->SetTargetRotation(vecT, TICK_RATE); - - g_pCore->ChatPrintf("Done %f", false, atof(szString + 7)); - - static_cast(pVehicle)->SetIsSyncing(false); - } - } - - else if (stricmp(szString, "choke") == 0) - { - if (g_pClientGame->GetLocalPlayer()) - g_pClientGame->GetLocalPlayer()->SetChoking(true); - } - - // - else if (strnicmp(szString, "static", 6) == 0) - { - if (pVehicleManager->Count() > 0) - { - CClientVehicle* pVehicle = *pVehicleManager->IterBegin(); - - pVehicle->GetGameVehicle()->SetRemap(atoi(szString + 7)); - g_pCore->ChatPrintf("Set %i", false, atoi(szString + 7)); - } - } - - // - else if (strnicmp(szString, "getmass", 7) == 0) - { - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle(); - if (pVehicle) - { - g_pCore->ChatPrintf("Mass == %f", false, pVehicle->GetGameVehicle()->GetMass()); - } - } - - else if (strnicmp(szString, "setmass", 7) == 0) - { - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle(); - if (pVehicle) - { - pVehicle->GetGameVehicle()->SetMass((float)atof(szString + 8)); - g_pCore->ChatPrintf("Set mass to %f", false, pVehicle->GetGameVehicle()->GetMass()); - } - } - - // - /* - else if ( strnicmp ( szString, "setmm", 5 ) == 0 ) - { - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle (); - if ( pVehicle ) - { - float fVal = atof ( szString + 6); - szString += 4; - float* fMass = (float*) atoi ( szString + 6 ); - *fMass = fVal; - g_pCore->ChatPrintf ( "Set %X to %f", false, fMass, fVal ); - } - } - */ - - /* - else if ( stricmp ( szString, "getmm" ) == 0 ) - { - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle (); - if ( pVehicle ) - { - float* fMass = (float*) atoi ( szString ); - g_pCore->ChatPrintf ( "Get %f", false, *fMass ); - } - } - */ - - /* - else if ( stricmp ( szString, "dump" ) == 0 ) - { - FILE* poo = fopen ( "vehs.txt", "w+" ); - if ( poo ) - { - tHandlingData* pHandling = (tHandlingData*) 0xC2B9E0; - unsigned int uiIndex = 0; - for ( ; uiIndex < 219; uiIndex++ ) - { - fprintf ( poo, "\n\n\n\n####### VEHICLE ID %u #######\n", uiIndex ); - - fprintf ( poo, "fMass = %f\n", pHandling->fMass ); - fprintf ( poo, "fUnknown1 = %f\n", pHandling->fUnknown1 ); - fprintf ( poo, "fTurnMass = %f\n", pHandling->fTurnMass ); - - fprintf ( poo, "fDragCoeff = %f\n", pHandling->fDragCoeff ); - fprintf ( poo, "vecCenterOfMass = %f, %f, %f\n", pHandling->vecCenterOfMass.fX, pHandling->vecCenterOfMass.fY, pHandling->vecCenterOfMass.fZ ); - fprintf ( poo, "uiPercentSubmerged = %u\n", pHandling->uiPercentSubmerged ); - - fprintf ( poo, "fUnknown2 = %f\n", pHandling->fUnknown2 ); - - fprintf ( poo, "fTractionMultiplier = %f\n", pHandling->fTractionMultiplier ); - - fprintf ( poo, "Transmission.fUnknown [0] = %f\n", pHandling->Transmission.fUnknown [0] ); - fprintf ( poo, "Transmission.fUnknown [1] = %f\n", pHandling->Transmission.fUnknown [1] ); - fprintf ( poo, "Transmission.fUnknown [2] = %f\n", pHandling->Transmission.fUnknown [2] ); - fprintf ( poo, "Transmission.fUnknown [3] = %f\n", pHandling->Transmission.fUnknown [3] ); - fprintf ( poo, "Transmission.fUnknown [4] = %f\n", pHandling->Transmission.fUnknown [4] ); - fprintf ( poo, "Transmission.fUnknown [5] = %f\n", pHandling->Transmission.fUnknown [5] ); - fprintf ( poo, "Transmission.fUnknown [6] = %f\n", pHandling->Transmission.fUnknown [6] ); - fprintf ( poo, "Transmission.fUnknown [7] = %f\n", pHandling->Transmission.fUnknown [7] ); - fprintf ( poo, "Transmission.fUnknown [8] = %f\n", pHandling->Transmission.fUnknown [8] ); - fprintf ( poo, "Transmission.fUnknown [9] = %f\n", pHandling->Transmission.fUnknown [9] ); - fprintf ( poo, "Transmission.fUnknown [10] = %f\n", pHandling->Transmission.fUnknown [10] ); - fprintf ( poo, "Transmission.fUnknown [11] = %f\n", pHandling->Transmission.fUnknown [11] ); - fprintf ( poo, "Transmission.fUnknown [12] = %f\n", pHandling->Transmission.fUnknown [12] ); - fprintf ( poo, "Transmission.fUnknown [13] = %f\n", pHandling->Transmission.fUnknown [13] ); - fprintf ( poo, "Transmission.fUnknown [14] = %f\n", pHandling->Transmission.fUnknown [14] ); - fprintf ( poo, "Transmission.fUnknown [15] = %f\n", pHandling->Transmission.fUnknown [15] ); - fprintf ( poo, "Transmission.fUnknown [16] = %f\n", pHandling->Transmission.fUnknown [16] ); - fprintf ( poo, "Transmission.fUnknown [17] = %f\n", pHandling->Transmission.fUnknown [17] ); - - fprintf ( poo, "Transmission.ucDriveType = %c\n", pHandling->Transmission.ucDriveType ); - fprintf ( poo, "Transmission.ucEngineType = %c\n", pHandling->Transmission.ucEngineType ); - fprintf ( poo, "Transmission.ucNumberOfGears = %u\n", pHandling->Transmission.ucNumberOfGears ); - fprintf ( poo, "Transmission.ucUnknown = %u\n", pHandling->Transmission.ucUnknown ); - - fprintf ( poo, "Transmission.uiHandlingFlags = 0x%X\n", pHandling->Transmission.uiHandlingFlags ); - - fprintf ( poo, "Transmission.fEngineAcceleration = %f\n", pHandling->Transmission.fEngineAcceleration ); - fprintf ( poo, "Transmission.fEngineInertia = %f\n", pHandling->Transmission.fEngineInertia ); - fprintf ( poo, "Transmission.fMaxVelocity = %f\n", pHandling->Transmission.fMaxVelocity ); - - fprintf ( poo, "Transmission.fUnknown2 [0] = %f\n", pHandling->Transmission.fUnknown2 [0] ); - fprintf ( poo, "Transmission.fUnknown2 [1] = %f\n", pHandling->Transmission.fUnknown2 [1] ); - fprintf ( poo, "Transmission.fUnknown2 [2] = %f\n", pHandling->Transmission.fUnknown2 [2] ); - - fprintf ( poo, "fBrakeDeceleration = %f\n", pHandling->fBrakeDeceleration ); - fprintf ( poo, "fBrakeBias = %f\n", pHandling->fBrakeBias ); - fprintf ( poo, "bABS = %u\n", pHandling->bABS ); - - fprintf ( poo, "fSteeringLock = %f\n", pHandling->fSteeringLock ); - fprintf ( poo, "fTractionLoss = %f\n", pHandling->fTractionLoss ); - fprintf ( poo, "fTractionBias = %f\n", pHandling->fTractionBias ); - - fprintf ( poo, "fSuspensionForceLevel = %f\n", pHandling->fSuspensionForceLevel ); - fprintf ( poo, "fSuspensionDamping = %f\n", pHandling->fSuspensionDamping ); - fprintf ( poo, "fSuspensionHighSpdDamping = %f\n", pHandling->fSuspensionHighSpdDamping ); - fprintf ( poo, "fSuspensionUpperLimit = %f\n", pHandling->fSuspensionUpperLimit ); - fprintf ( poo, "fSuspensionLowerLimit = %f\n", pHandling->fSuspensionLowerLimit ); - fprintf ( poo, "fSuspensionFrontRearBias = %f\n", pHandling->fSuspensionFrontRearBias ); - fprintf ( poo, "fSuspensionAntiDiveMultiplier = %f\n", pHandling->fSuspensionAntiDiveMultiplier ); - - fprintf ( poo, "fCollisionDamageMultiplier = %f\n", pHandling->fCollisionDamageMultiplier ); - - fprintf ( poo, "uiModelFlags = %X\n", pHandling->uiModelFlags ); - fprintf ( poo, "uiHandlingFlags = %X\n", pHandling->uiHandlingFlags ); - fprintf ( poo, "fSeatOffsetDistance = %f\n", pHandling->fSeatOffsetDistance ); - fprintf ( poo, "uiMonetary = %u\n", pHandling->uiMonetary ); - - fprintf ( poo, "ucHeadLight = 0x%X\n", pHandling->ucHeadLight ); - fprintf ( poo, "ucTailLight = 0x%X\n", pHandling->ucTailLight ); - fprintf ( poo, "ucAnimGroup = 0x%X\n", pHandling->ucAnimGroup ); - fprintf ( poo, "ucUnused = 0x%X\n", pHandling->ucUnused ); - - fprintf ( poo, "iUnknown7 = %f, %X\n", pHandling->iUnknown7, pHandling->iUnknown7 ); - - pHandling += 1; - } - - - g_pCore->ChatPrintf ( "Dumped", false ); - fclose ( poo ); - } - } - */ - - else if (strnicmp(szString, "moveug", 6) == 0) - { - if (pVehicleManager->Count() > 0) - { - CClientVehicle* pVehicle = *pVehicleManager->IterBegin(); - - /* - CClientPed* pModel = pVehicle->GetOccupant ( 0 ); - if ( !pModel ) - { - CClientPlayer* pPlayer = new CClientPlayer ( g_pClientGame->GetManager (), 50 ); - pModel = pPlayer->LoadModel ( 0 ); - pModel->WarpIntoVehicle ( pVehicle ); - } - */ - - pVehicle->RemoveTargetPosition(); - pVehicle->RemoveTargetRotation(); - - CVector vecT; - pVehicle->GetPosition(vecT); - vecT.fZ = (float)atof(szString + 7); - pVehicle->SetPosition(vecT); - - g_pCore->ChatPrintf("Done", false); - } - } - - else if (strnicmp(szString, "nocol", 5) == 0) - { - if (pVehicleManager->Count() > 0) - { - CClientVehicle* pVehicle = *pVehicleManager->IterBegin(); - pVehicle->SetCollisionEnabled(false); - - g_pCore->ChatPrintf("Done", false); - } - } - - else if (stricmp(szString, "resetdamage") == 0) - { - g_pClientGame->GetPlayerManager()->GetLocalPlayer()->GetGamePlayer()->ResetLastDamage(); - } - - else if (strnicmp(szString, "fuckveh", 7) == 0) - { - CClientVehicle* pVehicle = pLocal->GetOccupiedVehicle(); - if (pVehicle) - { - pVehicle->SetTargetPosition(CVector(0, 0, 0), TICK_RATE); - pVehicle->SetTargetRotation(CVector(0, 0, 0), TICK_RATE); - - g_pCore->ChatPrintf("Done", false); - } - } - - else if (stricmp(szString, "ped") == 0) - { - CClientPed* pPed = new CClientPed(g_pClientGame->GetManager(), INVALID_ELEMENT_ID, 9); - vecLocal.fX += 5.0f; - pPed->SetPosition(vecLocal); - } - - else if (strnicmp(szString, "callit", 6) == 0) - { - FILE* pFile = fopen("C:/dump.txt", "w+"); - - for (int i = 0; i < 400; i++) - { - int iIndex = i; - const char* szName = NULL; - _asm - { - mov eax, 0x4D3A30 - push iIndex - call eax - mov szName, eax - add esp, 4 - } - - fprintf(pFile, "%i: %s\n", iIndex, szName); - } - - fclose(pFile); - } - - /*else if (strnicmp(szString, "veh", 3) == 0) - { - int i = 600; - FILE* p = fopen("C:/dump.txt", "w+"); - - for (int a = 0; a < 13; a++) - { - g_pGame->GetModelInfo(i)->ModelAddRef(BLOCKING, "CFoo::Test"); - - CVehicle* pVehicle = g_pGame->GetPools()->AddVehicle((eVehicleTypes)i, 5, 5); - DWORD* dw2 = (DWORD*)(((DWORD)pVehicle->GetVehicleInterface()) + 0xE1 * 4); - DWORD dw = *dw2; - dw = dw + 4; - dw = dw - 0xC2B9E0; - dw = dw / 224; - fprintf(p, "Array [%u] = %u;\n", i, dw); - - g_pGame->GetPools()->RemoveVehicle(pVehicle); - - fflush(p); - - g_pGame->GetModelInfo(i)->RemoveRef(); - - i++; - } - - fclose(p); - }*/ - - else if (strnicmp(szString, "groups", 6) == 0) - { - FILE* pFile = fopen("C:/dump.txt", "w+"); - - int i = 0; - for (; i < 139; i++) - { - fprintf(pFile, "==%s [%s] (%i)==\n", pGroups[i].szGroupName, pGroups[i].szSomething, i); - uint i2 = 0; - for (; i2 < pGroups[i].ulAnimCount; i2++) - { - const char* szAnimName = pGroups[i].pAnimNames[i2]; - if (szAnimName[0]) - { - fprintf(pFile, "''%i'': %s
\n", i2, szAnimName); - } - } - - fprintf(pFile, "\n"); - } - - fclose(pFile); - } - - else if (strnicmp(szString, "getshot", 7) == 0) - { - if (pLocal->GetGamePlayer()->GetCanBeShotInVehicle()) - { - g_pCore->ChatEcho("true"); - } - else - { - g_pCore->ChatEcho("false"); - } - } - - else if (strnicmp(szString, "gettest", 7) == 0) - { - if (pLocal->GetGamePlayer()->GetTestForShotInVehicle()) - { - g_pCore->ChatEcho("true"); - } - else - { - g_pCore->ChatEcho("false"); - } - } - - else if (strnicmp(szString, "setshot", 7) == 0) - { - pLocal->GetGamePlayer()->SetCanBeShotInVehicle(true); - } - - else if (strnicmp(szString, "settest", 8) == 0) - { - pLocal->GetGamePlayer()->SetTestForShotInVehicle(true); - } - - else if (stricmp(szString, "applytest") == 0) - { - DWORD oldProt, oldProt2; - VirtualProtect((LPVOID)0x5E8FFB, 6, PAGE_EXECUTE_READWRITE, &oldProt); - - *(unsigned char*)(0x5E8FFB) = 0x90; - *(unsigned char*)(0x5E8FFC) = 0x90; - *(unsigned char*)(0x5E8FFD) = 0x90; - *(unsigned char*)(0x5E8FFE) = 0x90; - *(unsigned char*)(0x5E8FFF) = 0x90; - *(unsigned char*)(0x5E9000) = 0x90; - - VirtualProtect((LPVOID)0x5E8FFB, 6, oldProt, &oldProt2); - } -} - -#endif diff --git a/Client/mods/deathmatch/logic/CFoo.h b/Client/mods/deathmatch/logic/CFoo.h deleted file mode 100644 index f5ed770763..0000000000 --- a/Client/mods/deathmatch/logic/CFoo.h +++ /dev/null @@ -1,31 +0,0 @@ -/***************************************************************************** - * - * PROJECT: Multi Theft Auto v1.0 - * LICENSE: See LICENSE in the top level directory - * FILE: mods/deathmatch/logic/CFoo.h - * PURPOSE: Debugging class (not used in Release mode) - * - * Multi Theft Auto is available from http://www.multitheftauto.com/ - * - *****************************************************************************/ - -/* This class is purely for debugging things. This will avoid usage of CClientGame. */ - -#pragma once - -class CFoo -{ -public: - #ifdef MTA_DEBUG - void Init(class CClientGame* pClientGame) { g_pClientGame = pClientGame; }; - - void DoPulse(); - void Test(const char* szString); - - class CClientGame* g_pClientGame; - #else - void Init(CClientGame* pClientGame){}; - void DoPulse(){}; - void Test(const char* szString){}; - #endif -}; diff --git a/Client/utils/wpmhookdll/Main.cpp b/Client/utils/wpmhookdll/Main.cpp deleted file mode 100644 index 350a558a33..0000000000 --- a/Client/utils/wpmhookdll/Main.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************** - * - * PROJECT: Multi Theft Auto v1.0 - * LICENSE: See LICENSE in the top level directory - * FILE: utils/wpmhookdll/Main.cpp - * PURPOSE: Memory manipulation hooking utility - * - * Multi Theft Auto is available from http://www.multitheftauto.com/ - * - *****************************************************************************/ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -using namespace std; - -#define MESSAGE_MONITOR_START 0x8500 -#define MESSAGE_MONITOR_END 0x8501 -#define MESSAGE_MONITOR_RPM 0x8502 -#define MESSAGE_MONITOR_WPM 0x8503 - -HWND hGTA = NULL; - -// ******** ReadProcessMemory hook! ********* -typedef BOOL(WINAPI* pReadProcessMemory)(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead); - -pReadProcessMemory pfnReadProcessMemory = NULL; - -BOOL WINAPI Hook_ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) -{ - // Tell MTA about the RPM call - PostMessage(hGTA, MESSAGE_MONITOR_RPM, reinterpret_cast(lpBaseAddress), nSize); - - // Call the original WriteProcessMemory - return pfnReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead); -} - -// ******** WriteProcessMemory hook! ********* -typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten); - -pWriteProcessMemory pfnWriteProcessMemory = NULL; - -BOOL WINAPI Hook_WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten) -{ - // Tell MTA about the WPM call - PostMessage(hGTA, MESSAGE_MONITOR_WPM, reinterpret_cast(lpBaseAddress), nSize); - - // Call the original WriteProcessMemory - return pfnWriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten); -} - -void Initialize(void) -{ - // Grab the GTA window handle - hGTA = FindWindow("Grand theft auto San Andreas", NULL); - if (hGTA != NULL) - { - // Make sure Kernel32.dll is loaded - PBYTE pKernel32 = reinterpret_cast(LoadLibrary("Kernel32.dll")); - if (pKernel32) - { - // Hook ReadProcessMemory - pfnReadProcessMemory = reinterpret_cast( - DetourFunction(DetourFindFunction("Kernel32.dll", "ReadProcessMemory"), reinterpret_cast(Hook_ReadProcessMemory))); - - // Hook WriteProcessMemory - pfnWriteProcessMemory = reinterpret_cast( - DetourFunction(DetourFindFunction("Kernel32.dll", "WriteProcessMemory"), reinterpret_cast(Hook_WriteProcessMemory))); - - // Success? - if (pfnReadProcessMemory && pfnWriteProcessMemory) - { - // Tell MTA we successfully hooked the trainer - PostMessage(hGTA, MESSAGE_MONITOR_START, 0, 0); - return; - } - } - - // Tell MTA we successfully injected but failed hooking the functions - PostMessage(hGTA, MESSAGE_MONITOR_START, 1, 1); - } -} - -void Finalize(void) -{ - // Unhook WriteProcessMemory - if (pfnWriteProcessMemory) - { - DetourRemove(reinterpret_cast(pfnWriteProcessMemory), reinterpret_cast(Hook_WriteProcessMemory)); - } - - // Unhook ReadProcessMemory - if (pfnReadProcessMemory) - { - DetourRemove(reinterpret_cast(pfnReadProcessMemory), reinterpret_cast(Hook_ReadProcessMemory)); - } - - // Tell MTA we've unhooked from the trainer - if (hGTA != NULL) - { - PostMessage(hGTA, MESSAGE_MONITOR_END, 0, 0); - } -} - -int WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, PVOID pvNothing) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - { - Initialize(); - return TRUE; - } - - case DLL_PROCESS_DETACH: - { - Finalize(); - return TRUE; - } - } - - return FALSE; -} diff --git a/Client/utils/wpmhookdll/wpmhookdll.sln b/Client/utils/wpmhookdll/wpmhookdll.sln deleted file mode 100644 index 6af2e1dc45..0000000000 --- a/Client/utils/wpmhookdll/wpmhookdll.sln +++ /dev/null @@ -1,21 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpmhookdll", "wpmhookdll.vcproj", "{BA915391-732D-40BB-9C25-4416DCC53B80}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {BA915391-732D-40BB-9C25-4416DCC53B80}.Debug.ActiveCfg = Debug|Win32 - {BA915391-732D-40BB-9C25-4416DCC53B80}.Debug.Build.0 = Debug|Win32 - {BA915391-732D-40BB-9C25-4416DCC53B80}.Release.ActiveCfg = Release|Win32 - {BA915391-732D-40BB-9C25-4416DCC53B80}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/Client/utils/wpmhookdll/wpmhookdll.vcproj b/Client/utils/wpmhookdll/wpmhookdll.vcproj deleted file mode 100644 index 9b169e32ac..0000000000 --- a/Client/utils/wpmhookdll/wpmhookdll.vcproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Shared/mods/deathmatch/logic/Utils.cpp b/Shared/mods/deathmatch/logic/Utils.cpp index 04076419c0..8ba51be070 100644 --- a/Shared/mods/deathmatch/logic/Utils.cpp +++ b/Shared/mods/deathmatch/logic/Utils.cpp @@ -435,65 +435,6 @@ SString GetDataUnit(unsigned long long ullInput) return strUnknown; } -#ifdef MTA_DEBUG -struct ReleaseVirtualMemory -{ - HANDLE process; - - ReleaseVirtualMemory(HANDLE process_) : process(process_) {} - - void operator()(void* p) const noexcept - { - if (p) - VirtualFreeEx(process, p, 0, MEM_RELEASE); - } -}; - -using VirtualMemoryScope = std::unique_ptr; - -bool RemoteLoadLibrary(HANDLE hProcess, const char* szLibPath) -{ - if (!szLibPath || !szLibPath[0]) - return false; - - HMODULE kernel32 = GetModuleHandleA("kernel32"); - - if (!kernel32) - return false; - - // Allocate memory in the remote process for the library path - size_t libraryPathSize = strlen(szLibPath) + 1; - void* remoteLibraryPath = VirtualAllocEx(hProcess, nullptr, libraryPathSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - if (!remoteLibraryPath) - return false; - - VirtualMemoryScope remoteMemory(remoteLibraryPath, ReleaseVirtualMemory{hProcess}); - - // Write the DLL library path to the remote allocation - DWORD byteswritten = 0; - WriteProcessMemory(hProcess, remoteLibraryPath, static_cast(szLibPath), libraryPathSize, &byteswritten); - - if (byteswritten != libraryPathSize) - return false; - - // Start a remote thread executing LoadLibraryA exported from Kernel32. Passing the - // remotely allocated path buffer as an argument to that thread (and also to LoadLibraryA) - // will make the remote process load the DLL into it's userspace (giving the DLL full - // access to the game executable). - HANDLE remoteThread = CreateRemoteThread( - hProcess, nullptr, 0, static_cast(static_cast(GetProcAddress(kernel32, "LoadLibraryA"))), remoteLibraryPath, 0, nullptr); - - if (!remoteThread) - return false; - - // We wait for the created remote thread to finish executing. When it's done, the DLL - // is loaded into the game's userspace, and we can destroy the thread-handle. - WaitForSingleObject(remoteThread, INFINITE); - return true; -} - -#endif #else bool IsValidFilePath(const char* szDir) { diff --git a/Shared/mods/deathmatch/logic/Utils.h b/Shared/mods/deathmatch/logic/Utils.h index 33cd9d072a..86f30480ef 100644 --- a/Shared/mods/deathmatch/logic/Utils.h +++ b/Shared/mods/deathmatch/logic/Utils.h @@ -350,8 +350,3 @@ void DeletePointersAndClearList(T& elementList) delete *iter; } } - -// for debug -#if defined(MTA_DEBUG) && defined(MTA_CLIENT) -bool RemoteLoadLibrary(HANDLE hProcess, const char* szLibPath); -#endif From c2ac1bcab60964db02ecce20b475b34aad2c1a88 Mon Sep 17 00:00:00 2001 From: Pot Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 20:59:17 +0000 Subject: [PATCH 17/23] Update client en_US pot [ci skip] --- .../MTA/locale/en_US/client.pot | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot index 66d7bc1cdf..18600f065a 100644 --- a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot +++ b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: MTA San Andreas 1.x\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-20 23:55+0000\n" +"POT-Creation-Date: 2024-06-21 20:59+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -93,17 +93,17 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1406 #: Client/core/DXHook/CDirect3DHook9.cpp:127 #: Client/mods/deathmatch/logic/CResourceFileDownloadManager.cpp:145 -#: Client/mods/deathmatch/logic/CClientGame.cpp:638 -#: Client/mods/deathmatch/logic/CClientGame.cpp:712 -#: Client/mods/deathmatch/logic/CClientGame.cpp:736 -#: Client/mods/deathmatch/logic/CClientGame.cpp:758 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1174 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1254 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1264 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1333 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1370 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1419 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1431 +#: Client/mods/deathmatch/logic/CClientGame.cpp:635 +#: Client/mods/deathmatch/logic/CClientGame.cpp:709 +#: Client/mods/deathmatch/logic/CClientGame.cpp:733 +#: Client/mods/deathmatch/logic/CClientGame.cpp:755 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1168 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1248 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1258 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1327 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1364 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1413 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1425 #: Client/loader/MainFunctions.cpp:252 Client/loader/MainFunctions.cpp:267 #: Client/loader/MainFunctions.cpp:269 Client/loader/MainFunctions.cpp:846 #: Client/loader/CInstallManager.cpp:552 Client/loader/CInstallManager.cpp:561 @@ -1176,12 +1176,12 @@ msgstr "" #: Client/core/CSettings.cpp:3479 Client/core/CCore.cpp:674 #: Client/core/CMainMenu.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:530 +#: Client/mods/deathmatch/logic/CClientGame.cpp:527 msgid "Main menu" msgstr "" #: Client/core/CSettings.cpp:3483 Client/core/CCore.cpp:674 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1086 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1083 #: Client/mods/deathmatch/logic/CResource.cpp:372 msgid "In-game" msgstr "" @@ -1387,47 +1387,47 @@ msgstr "" #. Display the status box #: Client/core/CConnectManager.cpp:148 -#: Client/mods/deathmatch/logic/CClientGame.cpp:654 +#: Client/mods/deathmatch/logic/CClientGame.cpp:651 msgid "CONNECTING" msgstr "" #: Client/core/CConnectManager.cpp:263 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1333 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1327 msgid "Connection timed out" msgstr "" #: Client/core/CConnectManager.cpp:277 Client/core/CConnectManager.cpp:281 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1381 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1375 msgid "Disconnected: unknown protocol error" msgstr "" #: Client/core/CConnectManager.cpp:285 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1385 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1379 msgid "Disconnected: disconnected remotely" msgstr "" #: Client/core/CConnectManager.cpp:289 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1389 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1383 msgid "Disconnected: connection lost remotely" msgstr "" #: Client/core/CConnectManager.cpp:293 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1393 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1387 msgid "Disconnected: you are banned from this server" msgstr "" #: Client/core/CConnectManager.cpp:300 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1401 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1395 msgid "Disconnected: disconnected from the server" msgstr "" #: Client/core/CConnectManager.cpp:304 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1405 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1399 msgid "Disconnected: connection to the server was lost" msgstr "" #: Client/core/CConnectManager.cpp:311 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1413 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1407 msgid "Disconnected: connection was refused" msgstr "" @@ -2095,8 +2095,8 @@ msgstr "" #: Client/core/ServerBrowser/CServerBrowser.cpp:1300 #: Client/core/ServerBrowser/CServerBrowser.cpp:1357 -#: Client/mods/deathmatch/logic/CClientGame.cpp:638 -#: Client/mods/deathmatch/logic/CClientGame.cpp:736 +#: Client/mods/deathmatch/logic/CClientGame.cpp:635 +#: Client/mods/deathmatch/logic/CClientGame.cpp:733 msgid "Invalid nickname! Please go to Settings and set a new one!" msgstr "" @@ -2133,97 +2133,97 @@ msgid "shows the network statistics" msgstr "" #. Key commands (registered as 'mod commands', can be disabled) -#: Client/mods/deathmatch/CClient.cpp:63 +#: Client/mods/deathmatch/CClient.cpp:62 msgid "open the chat input" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:64 +#: Client/mods/deathmatch/CClient.cpp:63 msgid "transmits voice to other players" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:65 +#: Client/mods/deathmatch/CClient.cpp:64 msgid "enters a car as passenger" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:66 +#: Client/mods/deathmatch/CClient.cpp:65 msgid "next radio channel" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:67 +#: Client/mods/deathmatch/CClient.cpp:66 msgid "previous radio channel" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:68 +#: Client/mods/deathmatch/CClient.cpp:67 msgid "enables the radar view" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:69 +#: Client/mods/deathmatch/CClient.cpp:68 msgid "zooms the radar in" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:70 +#: Client/mods/deathmatch/CClient.cpp:69 msgid "zooms the radar out" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:71 +#: Client/mods/deathmatch/CClient.cpp:70 msgid "moves the radar north" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:72 +#: Client/mods/deathmatch/CClient.cpp:71 msgid "moves the radar south" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:73 +#: Client/mods/deathmatch/CClient.cpp:72 msgid "moves the radar east" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:74 +#: Client/mods/deathmatch/CClient.cpp:73 msgid "moves the radar west" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:75 +#: Client/mods/deathmatch/CClient.cpp:74 msgid "attaches the radar" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:76 +#: Client/mods/deathmatch/CClient.cpp:75 msgid "reduces radar opacity" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:77 +#: Client/mods/deathmatch/CClient.cpp:76 msgid "increases radar opacity" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:78 +#: Client/mods/deathmatch/CClient.cpp:77 msgid "toggles radar help text" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:79 +#: Client/mods/deathmatch/CClient.cpp:78 msgid "sends a message to the targetted player" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:80 +#: Client/mods/deathmatch/CClient.cpp:79 msgid "changes to the next weapon whilst in a vehicle" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:81 +#: Client/mods/deathmatch/CClient.cpp:80 msgid "changes to the previous weapon whilst in a vehicle" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:82 +#: Client/mods/deathmatch/CClient.cpp:81 msgid "outputs info about the current server" msgstr "" #. ACHTUNG" Should this be handled by the atomic cvar setter? -#: Client/mods/deathmatch/CClient.cpp:85 +#: Client/mods/deathmatch/CClient.cpp:84 msgid "defines the scale multiplier of all text-displays" msgstr "" #. Development mode -#: Client/mods/deathmatch/CClient.cpp:92 +#: Client/mods/deathmatch/CClient.cpp:91 msgid "(Development mode) shows the colshapes" msgstr "" -#: Client/mods/deathmatch/CClient.cpp:93 +#: Client/mods/deathmatch/CClient.cpp:92 msgid "(Development mode) prints world sound ids into the debug window" msgstr "" @@ -2449,196 +2449,196 @@ msgstr[1] "" msgid "Disconnected" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +#: Client/mods/deathmatch/logic/CClientGame.cpp:369 msgid "Flying a UFO around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +#: Client/mods/deathmatch/logic/CClientGame.cpp:369 msgid "Cruising around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:372 +#: Client/mods/deathmatch/logic/CClientGame.cpp:369 msgid "Riding the waves of" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +#: Client/mods/deathmatch/logic/CClientGame.cpp:370 msgid "Riding the train in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:373 +#: Client/mods/deathmatch/logic/CClientGame.cpp:370 msgid "Flying around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 msgid "Riding around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 msgid "Monster truckin' around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:374 +#: Client/mods/deathmatch/logic/CClientGame.cpp:371 msgid "Quaddin' around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:375 +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 msgid "Bunny hopping around" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:375 +#: Client/mods/deathmatch/logic/CClientGame.cpp:372 msgid "Doing weird stuff in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:379 +#: Client/mods/deathmatch/logic/CClientGame.cpp:376 msgid "Climbing around in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:380 -#: Client/mods/deathmatch/logic/CClientGame.cpp:381 +#: Client/mods/deathmatch/logic/CClientGame.cpp:377 +#: Client/mods/deathmatch/logic/CClientGame.cpp:378 msgid "Doing a drive-by in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:382 +#: Client/mods/deathmatch/logic/CClientGame.cpp:379 msgid "Blub blub..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:383 +#: Client/mods/deathmatch/logic/CClientGame.cpp:380 msgid "Breathing water" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:384 +#: Client/mods/deathmatch/logic/CClientGame.cpp:381 msgid "Drowning in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:385 +#: Client/mods/deathmatch/logic/CClientGame.cpp:382 msgid "Ducking for cover in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:386 +#: Client/mods/deathmatch/logic/CClientGame.cpp:383 msgid "Fighting in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:387 +#: Client/mods/deathmatch/logic/CClientGame.cpp:384 msgid "Throwing fists in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:388 +#: Client/mods/deathmatch/logic/CClientGame.cpp:385 msgid "Blastin' fools in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:389 +#: Client/mods/deathmatch/logic/CClientGame.cpp:386 msgid "Shooting up" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:390 +#: Client/mods/deathmatch/logic/CClientGame.cpp:387 msgid "Jetpacking in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:391 +#: Client/mods/deathmatch/logic/CClientGame.cpp:388 msgid "Literally on fire in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:392 +#: Client/mods/deathmatch/logic/CClientGame.cpp:389 msgid "Burning up in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:393 +#: Client/mods/deathmatch/logic/CClientGame.cpp:390 msgid "Swimming in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:394 +#: Client/mods/deathmatch/logic/CClientGame.cpp:391 msgid "Floating around in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:395 +#: Client/mods/deathmatch/logic/CClientGame.cpp:392 msgid "Being chased by a shark" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:396 +#: Client/mods/deathmatch/logic/CClientGame.cpp:393 msgid "Choking to death in" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:654 +#: Client/mods/deathmatch/logic/CClientGame.cpp:651 msgid "Entering the game ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:712 +#: Client/mods/deathmatch/logic/CClientGame.cpp:709 msgid "" "Not connected; please use Quick Connect or the 'connect' command to connect " "to a server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:758 +#: Client/mods/deathmatch/logic/CClientGame.cpp:755 msgid "Could not start the local server. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:768 -#: Client/mods/deathmatch/logic/CClientGame.cpp:1243 +#: Client/mods/deathmatch/logic/CClientGame.cpp:765 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1237 msgid "Local Server" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:768 +#: Client/mods/deathmatch/logic/CClientGame.cpp:765 msgid "Starting local server ..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1016 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1013 msgid "Area 51" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1025 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1022 msgid "Walking around " msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1174 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1168 #, c-format msgid "You were kicked from the game ( %s )" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1243 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1237 msgid "Connecting to local server..." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1254 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1248 msgid "Error connecting to server." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1264 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1258 msgid "Connecting to local server timed out. See console for details." msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1370 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1364 msgid "Connection with the server was lost" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1397 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1391 msgid "Disconnected: the server is currently full" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1409 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1403 msgid "Disconnected: invalid password specified" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:1431 +#: Client/mods/deathmatch/logic/CClientGame.cpp:1425 msgid "MTA Client verification failed!" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5683 msgid "In a ditch" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5683 msgid "En-route to hospital" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5695 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5683 msgid "Meeting their maker" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5696 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5684 msgid "Regretting their decisions" msgstr "" -#: Client/mods/deathmatch/logic/CClientGame.cpp:5696 +#: Client/mods/deathmatch/logic/CClientGame.cpp:5684 msgid "Wasted" msgstr "" From dc099cb4d6acbc82e6b30d4c2f7c47046b5509e6 Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Sat, 22 Jun 2024 02:02:23 +0200 Subject: [PATCH 18/23] Updated speex, libspeex and libspeexdsp --- vendor/libspeex/libspeex/_kiss_fft_guts.h | 4 +- vendor/libspeex/libspeex/arch.h | 18 +- vendor/libspeex/libspeex/cb_search.c | 6 +- vendor/libspeex/libspeex/cb_search.h | 12 +- vendor/libspeex/libspeex/cb_search_arm4.h | 10 +- vendor/libspeex/libspeex/cb_search_bfin.h | 20 +- vendor/libspeex/libspeex/cb_search_sse.h | 10 +- vendor/libspeex/libspeex/fftwrap.c | 448 ++++++++++++++++++ vendor/libspeex/libspeex/fftwrap.h | 12 +- vendor/libspeex/libspeex/filters.h | 8 +- vendor/libspeex/libspeex/filters_arm4.h | 10 +- vendor/libspeex/libspeex/filters_bfin.h | 54 +-- vendor/libspeex/libspeex/filters_sse.h | 32 +- vendor/libspeex/libspeex/fixed_arm4.h | 10 +- vendor/libspeex/libspeex/fixed_arm5e.h | 10 +- vendor/libspeex/libspeex/fixed_bfin.h | 12 +- vendor/libspeex/libspeex/fixed_debug.h | 54 +-- vendor/libspeex/libspeex/fixed_generic.h | 14 +- vendor/libspeex/libspeex/kiss_fft.c | 2 +- vendor/libspeex/libspeex/kiss_fft.h | 26 +- vendor/libspeex/libspeex/kiss_fftr.h | 12 +- vendor/libspeex/libspeex/lpc.h | 8 +- vendor/libspeex/libspeex/lpc_bfin.h | 20 +- vendor/libspeex/libspeex/lsp.c | 2 +- vendor/libspeex/libspeex/lsp.h | 8 +- vendor/libspeex/libspeex/lsp_bfin.h | 14 +- vendor/libspeex/libspeex/ltp.h | 8 +- vendor/libspeex/libspeex/ltp_arm4.h | 12 +- vendor/libspeex/libspeex/ltp_bfin.h | 56 +-- vendor/libspeex/libspeex/ltp_sse.h | 8 +- vendor/libspeex/libspeex/math_approx.h | 18 +- vendor/libspeex/libspeex/misc_bfin.h | 10 +- vendor/libspeex/libspeex/modes.h | 18 +- vendor/libspeex/libspeex/nb_celp.c | 16 +- vendor/libspeex/libspeex/nb_celp.h | 18 +- vendor/libspeex/libspeex/os_support.h | 6 +- vendor/libspeex/libspeex/quant_lsp.h | 8 +- vendor/libspeex/libspeex/quant_lsp_bfin.h | 48 +- vendor/libspeex/libspeex/sb_celp.c | 12 +- vendor/libspeex/libspeex/sb_celp.h | 14 +- vendor/libspeex/libspeex/stack_alloc.h | 12 +- vendor/libspeex/libspeex/testenc.c | 145 ++++++ vendor/libspeex/libspeex/testenc_uwb.c | 133 ++++++ vendor/libspeex/libspeex/testenc_wb.c | 139 ++++++ vendor/libspeex/libspeex/vbr.h | 8 +- vendor/libspeex/libspeex/vorbis_psy.h | 10 +- vendor/libspeex/libspeex/vq.h | 8 +- vendor/libspeex/libspeex/vq_arm4.h | 8 +- vendor/libspeex/libspeex/vq_bfin.h | 10 +- vendor/libspeex/libspeexdsp/_kiss_fft_guts.h | 4 +- vendor/libspeex/libspeexdsp/arch.h | 36 +- vendor/libspeex/libspeexdsp/buffer.c | 6 +- vendor/libspeex/libspeexdsp/config.h | 8 +- vendor/libspeex/libspeexdsp/fftwrap.c | 18 +- vendor/libspeex/libspeexdsp/fftwrap.h | 12 +- vendor/libspeex/libspeexdsp/filterbank.c | 12 +- vendor/libspeex/libspeexdsp/fixed_arm4.h | 23 +- vendor/libspeex/libspeexdsp/fixed_arm5e.h | 28 +- vendor/libspeex/libspeexdsp/fixed_bfin.h | 47 +- vendor/libspeex/libspeexdsp/fixed_debug.h | 74 +-- vendor/libspeex/libspeexdsp/fixed_generic.h | 24 +- vendor/libspeex/libspeexdsp/jitter.c | 152 +++--- vendor/libspeex/libspeexdsp/kiss_fft.c | 42 +- vendor/libspeex/libspeexdsp/kiss_fft.h | 26 +- vendor/libspeex/libspeexdsp/kiss_fftr.c | 38 +- vendor/libspeex/libspeexdsp/kiss_fftr.h | 12 +- vendor/libspeex/libspeexdsp/math_approx.h | 14 +- vendor/libspeex/libspeexdsp/mdf.c | 134 +++--- vendor/libspeex/libspeexdsp/misc_bfin.h | 10 +- vendor/libspeex/libspeexdsp/os_support.h | 6 +- vendor/libspeex/libspeexdsp/preprocess.c | 144 +++--- vendor/libspeex/libspeexdsp/pseudofloat.h | 26 +- vendor/libspeex/libspeexdsp/resample.c | 232 +++++---- vendor/libspeex/libspeexdsp/resample_neon.h | 168 ++++++- vendor/libspeex/libspeexdsp/resample_sse.h | 10 +- vendor/libspeex/libspeexdsp/scal.c | 36 +- vendor/libspeex/libspeexdsp/smallft.c | 16 +- vendor/libspeex/libspeexdsp/stack_alloc.h | 12 +- vendor/libspeex/libspeexdsp/testdenoise.c | 44 ++ vendor/libspeex/libspeexdsp/testecho.c | 53 +++ vendor/libspeex/libspeexdsp/testjitter.c | 75 +++ vendor/libspeex/libspeexdsp/testresample.c | 86 ++++ vendor/libspeex/libspeexdsp/testresample2.c | 93 ++++ vendor/libspeex/libspeexdsp/vorbis_psy.h | 10 +- vendor/libspeex/speex/speex.h | 2 +- vendor/libspeex/speex/speex_buffer.h | 2 +- vendor/libspeex/speex/speex_config_types.h | 2 +- vendor/libspeex/speex/speex_echo.h | 10 +- vendor/libspeex/speex/speex_jitter.h | 40 +- vendor/libspeex/speex/speex_preprocess.h | 12 +- vendor/libspeex/speex/speex_resampler.h | 119 ++--- vendor/libspeex/speex/speex_stereo.h | 2 +- vendor/libspeex/speex/speexdsp_config_types.h | 1 - vendor/libspeex/speex/speexdsp_types.h | 2 +- 94 files changed, 2404 insertions(+), 1080 deletions(-) create mode 100644 vendor/libspeex/libspeex/fftwrap.c create mode 100644 vendor/libspeex/libspeex/testenc.c create mode 100644 vendor/libspeex/libspeex/testenc_uwb.c create mode 100644 vendor/libspeex/libspeex/testenc_wb.c create mode 100644 vendor/libspeex/libspeexdsp/testdenoise.c create mode 100644 vendor/libspeex/libspeexdsp/testecho.c create mode 100644 vendor/libspeex/libspeexdsp/testjitter.c create mode 100644 vendor/libspeex/libspeexdsp/testresample.c create mode 100644 vendor/libspeex/libspeexdsp/testresample2.c diff --git a/vendor/libspeex/libspeex/_kiss_fft_guts.h b/vendor/libspeex/libspeex/_kiss_fft_guts.h index 6571e79c0c..f5f2a5fd76 100644 --- a/vendor/libspeex/libspeex/_kiss_fft_guts.h +++ b/vendor/libspeex/libspeex/_kiss_fft_guts.h @@ -23,7 +23,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include "math_approx.h" #define MAXFACTORS 32 -/* e.g. an fft of length 128 has 4 factors +/* e.g. an fft of length 128 has 4 factors as far as kissfft is concerned 4*4*4*2 */ @@ -47,7 +47,7 @@ struct kiss_fft_state{ #ifdef FIXED_POINT #include "arch.h" # define FRACBITS 15 -# define SAMPPROD spx_int32_t +# define SAMPPROD spx_int32_t #define SAMP_MAX 32767 #define SAMP_MIN -SAMP_MAX diff --git a/vendor/libspeex/libspeex/arch.h b/vendor/libspeex/libspeex/arch.h index 291cab828c..807469ddb2 100644 --- a/vendor/libspeex/libspeex/arch.h +++ b/vendor/libspeex/libspeex/arch.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -37,10 +37,10 @@ #ifndef SPEEX_VERSION #define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ -#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ -#define SPEEX_MICRO_VERSION 16 /**< Micro Speex version. */ +#define SPEEX_MINOR_VERSION 2 /**< Minor Speex version. */ +#define SPEEX_MICRO_VERSION 1 /**< Micro Speex version. */ #define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ -#define SPEEX_VERSION "speex-1.2.0" /**< Speex version string. */ +#define SPEEX_VERSION "speex-1.2.1" /**< Speex version string. */ #endif /* A couple test to catch stupid option combinations */ @@ -215,11 +215,11 @@ typedef float spx_word32_t; #if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) /* 2 on TI C5x DSP */ -#define BYTES_PER_CHAR 2 +#define BYTES_PER_CHAR 2 #define BITS_PER_CHAR 16 #define LOG2_BITS_PER_CHAR 4 -#else +#else #define BYTES_PER_CHAR 1 #define BITS_PER_CHAR 8 diff --git a/vendor/libspeex/libspeex/cb_search.c b/vendor/libspeex/libspeex/cb_search.c index a170fd6784..9271a57c44 100644 --- a/vendor/libspeex/libspeex/cb_search.c +++ b/vendor/libspeex/libspeex/cb_search.c @@ -363,7 +363,7 @@ int update_target /*"erase" nbest list*/ for (j=0;jmax_val) + max_val = in[i]; + if (-in[i]>max_val) + max_val = -in[i]; + } + shift=0; + while (max_val <= (bound>>1) && max_val != 0) + { + max_val <<= 1; + shift++; + } + for (i=0;i + +void *spx_fft_init(int size) +{ + struct drft_lookup *table; + table = speex_alloc(sizeof(struct drft_lookup)); + spx_drft_init((struct drft_lookup *)table, size); + return (void*)table; +} + +void spx_fft_destroy(void *table) +{ + spx_drft_clear(table); + speex_free(table); +} + +void spx_fft(void *table, float *in, float *out) +{ + if (in==out) + { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + speex_warning("FFT should not be done in-place"); + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } else { + int i; + float scale = 1./((struct drft_lookup *)table)->n; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = scale*in[i]; + } + spx_drft_forward((struct drft_lookup *)table, out); +} + +void spx_ifft(void *table, float *in, float *out) +{ + if (in==out) + { + speex_warning("FFT should not be done in-place"); + } else { + int i; + for (i=0;i<((struct drft_lookup *)table)->n;i++) + out[i] = in[i]; + } + spx_drft_backward((struct drft_lookup *)table, out); +} + +#elif defined(USE_INTEL_MKL) +#include + +struct mkl_config { + DFTI_DESCRIPTOR_HANDLE desc; + int N; +}; + +void *spx_fft_init(int size) +{ + struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); + table->N = size; + DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); + DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); + DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); + DftiCommitDescriptor(table->desc); + return table; +} + +void spx_fft_destroy(void *table) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiFreeDescriptor(t->desc); + speex_free(table); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeForward(t->desc, in, out); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeBackward(t->desc, in, out); +} + +#elif defined(USE_INTEL_IPP) + +#include + +struct ipp_fft_config +{ + IppsDFTSpec_R_32f *dftSpec; + Ipp8u *buffer; +}; + +void *spx_fft_init(int size) +{ + int bufferSize = 0; + int hint; + struct ipp_fft_config *table; + + table = (struct ipp_fft_config *)speex_alloc(sizeof(struct ipp_fft_config)); + + /* there appears to be no performance difference between ippAlgHintFast and + ippAlgHintAccurate when using the with the floating point version + of the fft. */ + hint = ippAlgHintAccurate; + + ippsDFTInitAlloc_R_32f(&table->dftSpec, size, IPP_FFT_DIV_FWD_BY_N, hint); + + ippsDFTGetBufSize_R_32f(table->dftSpec, &bufferSize); + table->buffer = ippsMalloc_8u(bufferSize); + + return table; +} + +void spx_fft_destroy(void *table) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsFree(t->buffer); + ippsDFTFree_R_32f(t->dftSpec); + speex_free(t); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsDFTFwd_RToPack_32f(in, out, t->dftSpec, t->buffer); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct ipp_fft_config *t = (struct ipp_fft_config *)table; + ippsDFTInv_PackToR_32f(in, out, t->dftSpec, t->buffer); +} + +#elif defined(USE_GPL_FFTW3) + +#include + +struct fftw_config { + float *in; + float *out; + fftwf_plan fft; + fftwf_plan ifft; + int N; +}; + +void *spx_fft_init(int size) +{ + struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); + table->in = fftwf_malloc(sizeof(float) * (size+2)); + table->out = fftwf_malloc(sizeof(float) * (size+2)); + + table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); + table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); + + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct fftw_config *t = (struct fftw_config *) table; + fftwf_destroy_plan(t->fft); + fftwf_destroy_plan(t->ifft); + fftwf_free(t->in); + fftwf_free(t->out); + speex_free(table); +} + + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + struct fftw_config *t = (struct fftw_config *) table; + const int N = t->N; + float *iptr = t->in; + float *optr = t->out; + const float m = 1.0 / N; + for(i=0;ifft); + + out[0] = optr[0]; + for(i=1;iN; + float *iptr = t->in; + float *optr = t->out; + + iptr[0] = in[0]; + iptr[1] = 0.0f; + for(i=1;iifft); + + for(i=0;iforward = kiss_fftr_alloc(size,0,NULL,NULL); + table->backward = kiss_fftr_alloc(size,1,NULL,NULL); + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftr_free(t->forward); + kiss_fftr_free(t->backward); + speex_free(table); +} + +#ifdef FIXED_POINT + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int shift; + struct kiss_config *t = (struct kiss_config *)table; + shift = maximize_range(in, in, 32000, t->N); + kiss_fftr2(t->forward, in, out); + renorm_range(in, in, shift, t->N); + renorm_range(out, out, shift, t->N); +} + +#else + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + float scale; + struct kiss_config *t = (struct kiss_config *)table; + scale = 1./t->N; + kiss_fftr2(t->forward, in, out); + for (i=0;iN;i++) + out[i] *= scale; +} +#endif + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct kiss_config *t = (struct kiss_config *)table; + kiss_fftri2(t->backward, in, out); +} + + +#else + +#error No other FFT implemented + +#endif + + +#ifdef FIXED_POINT +/*#include "smallft.h"*/ + + +void spx_fft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + scale = 1./((struct kiss_config *)table)->N; + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = scale*in[i]; + spx_drft_forward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +void spx_ifft_float(void *table, float *in, float *out) +{ + int i; +#ifdef USE_SMALLFT + int N = ((struct drft_lookup *)table)->n; +#elif defined(USE_KISS_FFT) + int N = ((struct kiss_config *)table)->N; +#else +#endif +#ifdef VAR_ARRAYS + spx_word16_t _in[N]; + spx_word16_t _out[N]; +#else + spx_word16_t _in[MAX_FFT_SIZE]; + spx_word16_t _out[MAX_FFT_SIZE]; +#endif + for (i=0;iN); + for (i=0;i<((struct kiss_config *)table)->N;i++) + out[i] = in[i]; + spx_drft_backward(&t, out); + spx_drft_clear(&t); + } +#endif +} + +#else + +void spx_fft_float(void *table, float *in, float *out) +{ + spx_fft(table, in, out); +} +void spx_ifft_float(void *table, float *in, float *out) +{ + spx_ifft(table, in, out); +} + +#endif diff --git a/vendor/libspeex/libspeex/fftwrap.h b/vendor/libspeex/libspeex/fftwrap.h index dfaf489441..2c0742559c 100644 --- a/vendor/libspeex/libspeex/fftwrap.h +++ b/vendor/libspeex/libspeex/fftwrap.h @@ -1,23 +1,23 @@ -/* Copyright (C) 2005 Jean-Marc Valin +/* Copyright (C) 2005 Jean-Marc Valin File: fftwrap.h - Wrapper for various FFTs + Wrapper for various FFTs 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/filters.h b/vendor/libspeex/libspeex/filters.h index df148510c3..455365a661 100644 --- a/vendor/libspeex/libspeex/filters.h +++ b/vendor/libspeex/libspeex/filters.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/filters_arm4.h b/vendor/libspeex/libspeex/filters_arm4.h index 2c64625c30..ed5a4f1493 100644 --- a/vendor/libspeex/libspeex/filters_arm4.h +++ b/vendor/libspeex/libspeex/filters_arm4.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -68,7 +68,7 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le sig_shift++; max_val >>= 1; } - + __asm__ __volatile__ ( ".normalize16loop%=: \n" diff --git a/vendor/libspeex/libspeex/filters_bfin.h b/vendor/libspeex/libspeex/filters_bfin.h index ccd57b9d1d..a9bc0d2bc6 100644 --- a/vendor/libspeex/libspeex/filters_bfin.h +++ b/vendor/libspeex/libspeex/filters_bfin.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -39,7 +39,7 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le { spx_sig_t max_val=1; int sig_shift; - __asm__ + __asm__ ( "%0 = 0;\n\t" "I0 = %1;\n\t" @@ -62,7 +62,7 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le max_val >>= 1; } - __asm__ __volatile__ + __asm__ __volatile__ ( "I0 = %0;\n\t" "L0 = 0;\n\t" @@ -94,7 +94,7 @@ void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_ ALLOC(xy2, (N+1), spx_word32_t); ALLOC(numden_a, (2*ord+2), spx_word32_t); - xy = xy2+1; + xy = xy2+1; numden = (spx_word16_t*) numden_a; for (i=0;i=(EXTEND32(1)<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); res = (((long long)a)*(long long)b) >> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); @@ -296,7 +296,7 @@ static inline int MULT16_32_PX(int a, long long b, int Q) fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); } if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); @@ -323,7 +323,7 @@ static inline int SATURATE(int a, int b) return a; } -static inline int MULT16_16_Q11_32(int a, int b) +static inline int MULT16_16_Q11_32(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -337,7 +337,7 @@ static inline int MULT16_16_Q11_32(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q13(int a, int b) +static inline short MULT16_16_Q13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -351,7 +351,7 @@ static inline short MULT16_16_Q13(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q14(int a, int b) +static inline short MULT16_16_Q14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -365,7 +365,7 @@ static inline short MULT16_16_Q14(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q15(int a, int b) +static inline short MULT16_16_Q15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -382,7 +382,7 @@ static inline short MULT16_16_Q15(int a, int b) return res; } -static inline short MULT16_16_P13(int a, int b) +static inline short MULT16_16_P13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -399,7 +399,7 @@ static inline short MULT16_16_P13(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P14(int a, int b) +static inline short MULT16_16_P14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -416,7 +416,7 @@ static inline short MULT16_16_P14(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P15(int a, int b) +static inline short MULT16_16_P15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -436,7 +436,7 @@ static inline short MULT16_16_P15(int a, int b) #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) -static inline int _DIV32_16(long long a, long long b, char *file, int line) +static inline int _DIV32_16(long long a, long long b, char *file, int line) { long long res; if (b==0) @@ -462,7 +462,7 @@ static inline int _DIV32_16(long long a, long long b, char *file, int line) } #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) -static inline int _DIV32(long long a, long long b, char *file, int line) +static inline int _DIV32(long long a, long long b, char *file, int line) { long long res; if (b==0) diff --git a/vendor/libspeex/libspeex/fixed_generic.h b/vendor/libspeex/libspeex/fixed_generic.h index 3fb096ed90..bb320e301e 100644 --- a/vendor/libspeex/libspeex/fixed_generic.h +++ b/vendor/libspeex/libspeex/fixed_generic.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -43,9 +43,9 @@ #define EXTRACT16(x) ((spx_word16_t)(x)) #define EXTEND32(x) ((spx_word32_t)(x)) #define SHR16(a,shift) ((a) >> (shift)) -#define SHL16(a,shift) ((a) << (shift)) +#define SHL16(a,shift) ((spx_int16_t)((spx_uint16_t)(a) << (shift))) #define SHR32(a,shift) ((a) >> (shift)) -#define SHL32(a,shift) ((a) << (shift)) +#define SHL32(a,shift) ((spx_int32_t)((spx_uint32_t)(a) << (shift))) #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) @@ -53,7 +53,7 @@ #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SHR(a,shift) ((a) >> (shift)) -#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) +#define SHL(a,shift) ((spx_int32_t)((spx_uint32_t)(a) << (shift))) #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) diff --git a/vendor/libspeex/libspeex/kiss_fft.c b/vendor/libspeex/libspeex/kiss_fft.c index 285e557983..8dc9345428 100644 --- a/vendor/libspeex/libspeex/kiss_fft.c +++ b/vendor/libspeex/libspeex/kiss_fft.c @@ -23,7 +23,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include "os_support.h" /* The guts header contains all the multiplication and addition macros that are defined for - fixed or floating point complex numbers. It also delares the kf_ internal functions. + fixed or floating point complex numbers. It also declares the kf_ internal functions. */ static void kf_bfly2( diff --git a/vendor/libspeex/libspeex/kiss_fft.h b/vendor/libspeex/libspeex/kiss_fft.h index fa3f2c6042..bb19eadbd9 100644 --- a/vendor/libspeex/libspeex/kiss_fft.h +++ b/vendor/libspeex/libspeex/kiss_fft.h @@ -26,13 +26,13 @@ extern "C" { # include # define kiss_fft_scalar __m128 #define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) -#else +#else #define KISS_FFT_MALLOC speex_alloc -#endif +#endif #ifdef FIXED_POINT -#include "arch.h" +#include "arch.h" # define kiss_fft_scalar spx_int16_t #else # ifndef kiss_fft_scalar @@ -48,9 +48,9 @@ typedef struct { typedef struct kiss_fft_state* kiss_fft_cfg; -/* +/* * kiss_fft_alloc - * + * * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. * * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); @@ -60,18 +60,18 @@ typedef struct kiss_fft_state* kiss_fft_cfg; * * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. * The returned value should be free()d when done to avoid memory leaks. - * + * * The state can be placed in a user supplied buffer 'mem': * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, * then the function places the cfg in mem and the size used in *lenmem * and returns mem. - * + * * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), - * then the function returns NULL and places the minimum cfg + * then the function returns NULL and places the minimum cfg * buffer size in *lenmem. * */ -kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); /* * kiss_fft(cfg,in_out_buf) @@ -90,19 +90,19 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); * */ void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); -/* If kiss_fft_alloc allocated a buffer, it is one contiguous +/* If kiss_fft_alloc allocated a buffer, it is one contiguous buffer and can be simply free()d when no longer needed*/ #define kiss_fft_free speex_free /* - Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up your compiler output to call this before you exit. */ void kiss_fft_cleanup(void); - + #ifdef __cplusplus -} +} #endif #endif diff --git a/vendor/libspeex/libspeex/kiss_fftr.h b/vendor/libspeex/libspeex/kiss_fftr.h index 7bfb423340..8cfeda138a 100644 --- a/vendor/libspeex/libspeex/kiss_fftr.h +++ b/vendor/libspeex/libspeex/kiss_fftr.h @@ -6,13 +6,13 @@ extern "C" { #endif - -/* - + +/* + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. - - + + */ typedef struct kiss_fftr_state *kiss_fftr_cfg; @@ -22,7 +22,7 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenm /* nfft must be even - If you don't care to allocate space, use mem = lenmem = NULL + If you don't care to allocate space, use mem = lenmem = NULL */ diff --git a/vendor/libspeex/libspeex/lpc.h b/vendor/libspeex/libspeex/lpc.h index 952ecdd933..8885471f8a 100644 --- a/vendor/libspeex/libspeex/lpc.h +++ b/vendor/libspeex/libspeex/lpc.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/lpc_bfin.h b/vendor/libspeex/libspeex/lpc_bfin.h index d7d11c008e..d2e040656d 100644 --- a/vendor/libspeex/libspeex/lpc_bfin.h +++ b/vendor/libspeex/libspeex/lpc_bfin.h @@ -1,25 +1,25 @@ /* Copyright (C) 2005 Analog Devices */ /** @file lpc_bfin.h - @author Jean-Marc Valin + @author Jean-Marc Valin @brief Functions for LPC (Linear Prediction Coefficients) analysis (Blackfin version) */ /* 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -39,7 +39,7 @@ void _spx_autocorr( const spx_word16_t *x, /* in: [0...n-1] samples x */ spx_word16_t *ac, /* out: [0...lag-1] ac values */ -int lag, +int lag, int n ) { @@ -69,10 +69,10 @@ int n ac_shift--; ac0 <<= 1; } - + xs = x+lag-1; nshift = -shift; - __asm__ __volatile__ + __asm__ __volatile__ ( "P2 = %0;\n\t" "I0 = P2;\n\t" /* x in I0 */ @@ -102,7 +102,7 @@ int n "LOOP_END inner_prod%=;\n\t" "A0 = ASHIFT A0 by R4.L;\n\t" "A1 = ASHIFT A1 by R4.L;\n\t" - + "R2 = A0, R3 = A1;\n\t" "[P1--] = R2;\n\t" "[P1--] = R3;\n\t" @@ -118,7 +118,7 @@ int n d = ADD32(d,SHR32(MULT16_16(x[j],x[j]), shift)); } ac32[0] = d; - + for (i=0;i>>= 14;\n\t" - "R3 = R3 + R5;\n\t" - + "R3 = R3 + R5;\n\t" + "R0 = R2;\n\t" /* R0: b0 */ "R1 = 16384;\n\t" /* R1: b1 */ "LOOP cpe%= LC0 = %3;\n\t" "LOOP_BEGIN cpe%=;\n\t" - "P1 = R0;\n\t" + "P1 = R0;\n\t" "R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t" "R0 >>>= 13;\n\t" "R0 = R0 - R1;\n\t" diff --git a/vendor/libspeex/libspeex/ltp.h b/vendor/libspeex/libspeex/ltp.h index 95bb126997..28d25173e4 100644 --- a/vendor/libspeex/libspeex/ltp.h +++ b/vendor/libspeex/libspeex/ltp.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/ltp_arm4.h b/vendor/libspeex/libspeex/ltp_arm4.h index cdb94e603a..18be0d126e 100644 --- a/vendor/libspeex/libspeex/ltp_arm4.h +++ b/vendor/libspeex/libspeex/ltp_arm4.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -117,8 +117,8 @@ void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *c "\tmul %6, %10, %2 \n" "\tldrsh %1, [%9], #2 \n" "\tmul %7, %10, %3 \n" - - + + "\tmla %4, %15, %2, %4 \n" "\tldrsh %2, [%9], #2 \n" "\tmla %5, %15, %3, %5 \n" diff --git a/vendor/libspeex/libspeex/ltp_bfin.h b/vendor/libspeex/libspeex/ltp_bfin.h index b7edd37aad..c2ba482112 100644 --- a/vendor/libspeex/libspeex/ltp_bfin.h +++ b/vendor/libspeex/libspeex/ltp_bfin.h @@ -8,18 +8,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -118,35 +118,35 @@ static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, __asm__ __volatile__ ( "A0 = 0;\n\t" - + "R0 = W[%1++];\n\t" "R1.L = %2.L*%5.L (IS);\n\t" "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %3.L*%5.L (IS);\n\t" "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %4.L*%5.L (IS);\n\t" "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %2.L*%3.L (IS);\n\t" "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" "R1.L = %4.L*%3.L (IS);\n\t" "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %4.L*%2.L (IS);\n\t" "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %2.L*%2.L (IS);\n\t" "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" "R1.L = %3.L*%3.L (IS);\n\t" "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t" - + "R1.L = %4.L*%4.L (IS);\n\t" "A0 -= R1.L*R0.L (IS);\n\t" - + "%0 = A0;\n\t" : "=&D" (sum), "=a" (C) : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C) @@ -203,7 +203,7 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p " R2 = MAX(R1,R3);\n\t" "eu2: [P0++] = R2;\n\t" : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]), - "a" (end-start) + "a" (end-start) : "P0", "I1", "I2", "R0", "R1", "R2", "R3", "ASTAT" BFIN_HWLOOP1_REGS ); @@ -232,7 +232,7 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p " P0 = %4;\n\t" /* P0: best pitch */ " P1 = %4;\n\t" /* P1: counter */ " LSETUP (sl1, sl2) LC1 = %3;\n\t" -"sl1: R0.L = W [I0++] || R1.L = W [I1++];\n\t" +"sl1: R0.L = W [I0++] || R1.L = W [I1++];\n\t" " R0 = R0.L * R0.L (IS);\n\t" " R1 += 1;\n\t" " R4 = R0.L * R3.L;\n\t" @@ -244,7 +244,7 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p "sl2: P1 += 1;\n\t" " %0 = P0;\n\t" : "=&d" (pitch[0]) - : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) + : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5", "ASTAT", "CC" BFIN_HWLOOP1_REGS ); @@ -338,39 +338,39 @@ static int pitch_gain_search_3tap_vq( " R4 += 32;\n\t" " R4.H = 64;\n\t" /* R4.H: pitch_control */ -" R0 = B [P0++] (X);\n\t" +" R0 = B [P0++] (X);\n\t" " B0 = R0;\n\t" /* BO: gain_sum */ - + /* compute_pitch_error() -------------------------------*/ " I1 = %3;\n\t" /* I1: ptr to C */ " A0 = 0;\n\t" - + " R0.L = W[I1++];\n\t" " R1.L = R2.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R3.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R4.L*R4.H (IS);\n\t" " A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R2.L*R3.L (IS);\n\t" " A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" " R1.L = R4.L*R3.L (IS);\n\t" " A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R4.L*R2.L (IS);\n\t" " A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R2.L*R2.L (IS);\n\t" " A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" " R1.L = R3.L*R3.L (IS);\n\t" " A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t" - + " R1.L = R4.L*R4.L (IS);\n\t" " R0 = (A0 -= R1.L*R0.L) (IS);\n\t" @@ -393,18 +393,18 @@ static int pitch_gain_search_3tap_vq( " R1 = B0\n\t" " R2 = %5\n\t" " R3 = %6\n\t" -" cc = R2 <= R1;\n\t" +" cc = R2 <= R1;\n\t" " if cc R0 = R3;\n\t" " cc = %0 <= R0;\n\t" " if cc %0 = R0;\n\t" " if cc %1 = P1;\n\t" "pgs2: P1 += 1;\n\t" - - : "=&d" (best_sum), "=&d" (best_cdbk) + + : "=&d" (best_sum), "=&d" (best_cdbk) : "a" (gain_cdbk), "a" (C16), "a" (gain_cdbk_size), "a" (max_gain), "b" (-VERY_LARGE32) - : "R0", "R1", "R2", "R3", "R4", "P0", + : "R0", "R1", "R2", "R3", "R4", "P0", "P1", "I1", "L1", "A0", "B0", "CC", "ASTAT" BFIN_HWLOOP1_REGS ); diff --git a/vendor/libspeex/libspeex/ltp_sse.h b/vendor/libspeex/libspeex/ltp_sse.h index bed6eaac9a..326000831b 100644 --- a/vendor/libspeex/libspeex/ltp_sse.h +++ b/vendor/libspeex/libspeex/ltp_sse.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/math_approx.h b/vendor/libspeex/libspeex/math_approx.h index 9ca830755d..2c0e115e2e 100644 --- a/vendor/libspeex/libspeex/math_approx.h +++ b/vendor/libspeex/libspeex/math_approx.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -46,7 +46,7 @@ #define spx_atan atan /** Generate a pseudo-random number */ -static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) +static inline spx_word16_t speex_rand(spx_word16_t std, spx_uint32_t *seed) { const unsigned int jflone = 0x3f800000; const unsigned int jflmsk = 0x007fffff; @@ -119,7 +119,7 @@ static inline spx_int16_t spx_ilog4(spx_uint32_t x) #ifdef FIXED_POINT /** Generate a pseudo-random number */ -static inline spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed) +static inline spx_word16_t speex_rand(spx_word16_t std, spx_uint32_t *seed) { spx_word32_t res; *seed = 1664525 * *seed + 1013904223; @@ -168,11 +168,11 @@ static inline spx_word16_t spx_acos(spx_word16_t x) x = NEG16(x); } x = SUB16(16384,x); - + x = x >> 1; sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); ret = spx_sqrt(SHL32(EXTEND32(sq),13)); - + /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ if (s) ret = SUB16(25736,ret); @@ -208,7 +208,7 @@ static inline spx_word16_t spx_cos(spx_word16_t x) static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) { spx_word16_t x2; - + x2 = MULT16_16_P15(x,x); return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); } diff --git a/vendor/libspeex/libspeex/misc_bfin.h b/vendor/libspeex/libspeex/misc_bfin.h index 3c8c09d236..4e27681c95 100644 --- a/vendor/libspeex/libspeex/misc_bfin.h +++ b/vendor/libspeex/libspeex/misc_bfin.h @@ -1,25 +1,25 @@ /* Copyright (C) 2005 Analog Devices */ /** @file misc_bfin.h - @author Jean-Marc Valin + @author Jean-Marc Valin @brief Various compatibility routines for Speex (Blackfin version) */ /* 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/modes.h b/vendor/libspeex/libspeex/modes.h index 0977a579b8..2d5adc423f 100644 --- a/vendor/libspeex/libspeex/modes.h +++ b/vendor/libspeex/libspeex/modes.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -71,8 +71,8 @@ typedef void (*lsp_unquant_func)(spx_lsp_t *, int, SpeexBits *); /** Long-term predictor quantization */ -typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, - spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, +typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, + spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, int, int, SpeexBits*, char *, spx_word16_t *, spx_word16_t *, int, int, int, spx_word32_t *); /** Long-term un-quantize */ @@ -81,13 +81,13 @@ typedef void (*ltp_unquant_func)(spx_word16_t *, spx_word32_t *, int, int, spx_w /** Innovation quantization function */ -typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, +typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, spx_sig_t *, spx_word16_t *, SpeexBits *, char *, int, int); /** Innovation unquantization function */ -typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_int32_t *); +typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_uint32_t *); -/** Description of a Speex sub-mode (wither narrowband or wideband */ +/** Description of a Speex sub-mode (either narrowband or wideband) */ typedef struct SpeexSubmode { int lbr_pitch; /**< Set to -1 for "normal" modes, otherwise encode pitch using a global pitch and allowing a +- lbr_pitch variation (for low not-rates)*/ int forced_pitch_gain; /**< Use the same (forced) pitch gain for all sub-frames */ diff --git a/vendor/libspeex/libspeex/nb_celp.c b/vendor/libspeex/libspeex/nb_celp.c index b68d5070a2..e6d7979723 100644 --- a/vendor/libspeex/libspeex/nb_celp.c +++ b/vendor/libspeex/libspeex/nb_celp.c @@ -93,13 +93,6 @@ static const float exc_gain_quant_scal1[2]={0.70469f, 1.05127f}; #endif -#ifdef VORBIS_PSYCHO -#define EXTRA_BUFFER 100 -#else -#define EXTRA_BUFFER 0 -#endif - - extern const spx_word16_t lag_window[]; extern const spx_word16_t lpc_window[]; @@ -172,7 +165,7 @@ void *nb_encoder_init(const SpeexMode *m) st->highpass_enabled = 1; #ifdef ENABLE_VALGRIND - VALGRIND_MAKE_READABLE(st, NB_ENC_STACK); + VALGRIND_MAKE_MEM_DEFINED(st, NB_ENC_STACK); #endif return st; } @@ -1113,7 +1106,7 @@ void *nb_decoder_init(const SpeexMode *m) st->highpass_enabled = 1; #ifdef ENABLE_VALGRIND - VALGRIND_MAKE_READABLE(st, NB_DEC_STACK); + VALGRIND_MAKE_MEM_DEFINED(st, NB_DEC_STACK); #endif return st; } @@ -1472,6 +1465,11 @@ int nb_decode(void *state, SpeexBits *bits, void *vout) /* Final signal synthesis from excitation */ iir_mem16(st->exc, lpc, out, NB_FRAME_SIZE, NB_ORDER, st->mem_sp, stack); + /* Normally this is written to later but since this is returning early, + avoid reading uninitialized memory in caller */ + if (st->innov_save) + SPEEX_MEMSET(st->innov_save, 0, NB_NB_SUBFRAMES*NB_SUBFRAME_SIZE); + st->count_lost=0; return 0; } diff --git a/vendor/libspeex/libspeex/nb_celp.h b/vendor/libspeex/libspeex/nb_celp.h index a8d3088063..8fe60ce11f 100644 --- a/vendor/libspeex/libspeex/nb_celp.h +++ b/vendor/libspeex/libspeex/nb_celp.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -109,7 +109,7 @@ typedef struct EncState { float abr_drift2; float abr_count; #endif /* #ifndef DISABLE_VBR */ - + int complexity; /**< Complexity setting (0-10 from least complex to most complex) */ spx_int32_t sampling_rate; int plc_tuning; @@ -139,18 +139,18 @@ typedef struct DecState { spx_mem_t mem_hp[2]; /**< High-pass filter memory */ spx_word32_t pi_gain[NB_NB_SUBFRAMES]; /**< Gain of LPC filter at theta=pi (fe/2) */ spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ - + spx_word16_t level; spx_word16_t max_level; spx_word16_t min_level; - + /* This is used in packet loss concealment */ int last_pitch; /**< Pitch of last correctly decoded frame */ spx_word16_t last_pitch_gain; /**< Pitch gain of last correctly decoded frame */ spx_word16_t pitch_gain_buf[3]; /**< Pitch gain of last decoded frames */ int pitch_gain_buf_idx; /**< Tail of the buffer */ - spx_int32_t seed; /** Seed used for random number generation */ - + spx_uint32_t seed; /** Seed used for random number generation */ + int encode_submode; const SpeexSubmode * const *submodes; /**< Sub-mode data */ int submodeID; /**< Activated sub-mode */ diff --git a/vendor/libspeex/libspeex/os_support.h b/vendor/libspeex/libspeex/os_support.h index 2e23a5eb41..0db31a61df 100644 --- a/vendor/libspeex/libspeex/os_support.h +++ b/vendor/libspeex/libspeex/os_support.h @@ -1,5 +1,5 @@ /* Copyright (C) 2007 Jean-Marc Valin - + File: os_support.h This is the (tiny) OS abstraction layer. Aside from math.h, this is the only place where system headers are allowed. @@ -45,12 +45,12 @@ #include "os_support_custom.h" #endif -/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free NOTE: speex_alloc needs to CLEAR THE MEMORY */ #ifndef OVERRIDE_SPEEX_ALLOC static inline void *speex_alloc (int size) { - /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise you will experience strange bugs */ return calloc(size,1); diff --git a/vendor/libspeex/libspeex/quant_lsp.h b/vendor/libspeex/libspeex/quant_lsp.h index 0fc206be6f..aea6eb2b7b 100644 --- a/vendor/libspeex/libspeex/quant_lsp.h +++ b/vendor/libspeex/libspeex/quant_lsp.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/quant_lsp_bfin.h b/vendor/libspeex/libspeex/quant_lsp_bfin.h index efd23f5509..238adb9301 100644 --- a/vendor/libspeex/libspeex/quant_lsp_bfin.h +++ b/vendor/libspeex/libspeex/quant_lsp_bfin.h @@ -8,18 +8,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -40,14 +40,14 @@ /* Note http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html - well tell you all the magic resgister constraints used below + well tell you all the magic register constraints used below for gcc in-line asm. */ static int lsp_quant( - spx_word16_t *x, - const signed char *cdbk, - int nbVec, + spx_word16_t *x, + const signed char *cdbk, + int nbVec, int nbDim ) { @@ -57,23 +57,23 @@ static int lsp_quant( __asm__ __volatile__ ( -" %0 = 1 (X);\n\t" /* %0: best_dist */ -" %0 <<= 30;\n\t" +" %0 = 1 (X);\n\t" /* %0: best_dist */ +" %0 <<= 30;\n\t" " %1 = 0 (X);\n\t" /* %1: best_i */ " P2 = %3\n\t" /* P2: ptr to cdbk */ " R5 = 0;\n\t" /* R5: best cb entry */ " R0 = %5;\n\t" /* set up circ addr */ " R0 <<= 1;\n\t" -" L0 = R0;\n\t" +" L0 = R0;\n\t" " I0 = %2;\n\t" /* %2: &x[0] */ -" B0 = %2;\n\t" +" B0 = %2;\n\t" " R2.L = W [I0++];\n\t" " LSETUP (1f, 2f) LC0 = %4;\n\t" "1: R3 = 0;\n\t" /* R3: dist */ " LSETUP (3f, 4f) LC1 = %5;\n\t" -"3: R1 = B [P2++] (X);\n\t" +"3: R1 = B [P2++] (X);\n\t" " R1 <<= 5;\n\t" " R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" " R0 = R0.L*R0.L;\n\t" @@ -102,15 +102,15 @@ static int lsp_quant( /* Note http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html - well tell you all the magic resgister constraints used below + well tell you all the magic register constraints used below for gcc in-line asm. */ static int lsp_weight_quant( - spx_word16_t *x, - spx_word16_t *weight, - const signed char *cdbk, - int nbVec, + spx_word16_t *x, + spx_word16_t *weight, + const signed char *cdbk, + int nbVec, int nbDim ) { @@ -120,26 +120,26 @@ static int lsp_weight_quant( __asm__ __volatile__ ( -" %0 = 1 (X);\n\t" /* %0: best_dist */ -" %0 <<= 30;\n\t" +" %0 = 1 (X);\n\t" /* %0: best_dist */ +" %0 <<= 30;\n\t" " %1 = 0 (X);\n\t" /* %1: best_i */ " P2 = %4\n\t" /* P2: ptr to cdbk */ " R5 = 0;\n\t" /* R5: best cb entry */ " R0 = %6;\n\t" /* set up circ addr */ " R0 <<= 1;\n\t" -" L0 = R0;\n\t" +" L0 = R0;\n\t" " L1 = R0;\n\t" " I0 = %2;\n\t" /* %2: &x[0] */ " I1 = %3;\n\t" /* %3: &weight[0] */ -" B0 = %2;\n\t" -" B1 = %3;\n\t" +" B0 = %2;\n\t" +" B1 = %3;\n\t" " LSETUP (1f, 2f) LC0 = %5;\n\t" "1: R3 = 0 (X);\n\t" /* R3: dist */ " LSETUP (3f, 4f) LC1 = %6;\n\t" "3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" -" R1 = B [P2++] (X);\n\t" +" R1 = B [P2++] (X);\n\t" " R1 <<= 5;\n\t" " R0.L = R0.L - R1.L;\n\t" " R0 = R0.L*R0.L;\n\t" diff --git a/vendor/libspeex/libspeex/sb_celp.c b/vendor/libspeex/libspeex/sb_celp.c index 3aab085cc9..61d5c27a6a 100644 --- a/vendor/libspeex/libspeex/sb_celp.c +++ b/vendor/libspeex/libspeex/sb_celp.c @@ -64,9 +64,6 @@ #ifndef DISABLE_WIDEBAND - -#define sqr(x) ((x)*(x)) - #define SUBMODE(x) st->submodes[st->submodeID]->x #ifdef FIXED_POINT @@ -223,7 +220,7 @@ void *sb_encoder_init(const SpeexMode *m) speex_encoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate); st->sampling_rate*=2; #ifdef ENABLE_VALGRIND - VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); + VALGRIND_MAKE_MEM_DEFINED(st, (st->stack-(char*)st)); #endif return st; } @@ -1017,7 +1014,7 @@ void *sb_decoder_init(const SpeexMode *m) st->seed = 1000; #ifdef ENABLE_VALGRIND - VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st)); + VALGRIND_MAKE_MEM_DEFINED(st, (st->stack-(char*)st)); #endif return st; } @@ -1280,6 +1277,9 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) /* If null mode (no transmission), just set a couple things to zero*/ if (st->submodes[st->submodeID] == NULL) { + if (st->innov_save) + SPEEX_MEMSET(st->innov_save, 0, st->full_frame_size); + if (dtx) { sb_decode_lost(st, out, 1, stack); @@ -1343,7 +1343,7 @@ int sb_decode(void *state, SpeexBits *bits, void *vout) /* LSP to LPC */ lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack); - /* Calculate reponse ratio between the low and high filter in the middle + /* Calculate response ratio between the low and high filter in the middle of the band (4000 Hz) */ st->pi_gain[sub]=LPC_SCALING; diff --git a/vendor/libspeex/libspeex/sb_celp.h b/vendor/libspeex/libspeex/sb_celp.h index 141d0c2e1b..c6b92940db 100644 --- a/vendor/libspeex/libspeex/sb_celp.h +++ b/vendor/libspeex/libspeex/sb_celp.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -83,7 +83,7 @@ typedef struct SBEncState { int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */ float relative_quality; #endif /* #ifndef DISABLE_VBR */ - + int encode_submode; const SpeexSubmode * const *submodes; int submodeID; @@ -118,9 +118,9 @@ typedef struct SBDecState { spx_word32_t *pi_gain; spx_word16_t *exc_rms; spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */ - + spx_word16_t last_ener; - spx_int32_t seed; + spx_uint32_t seed; int encode_submode; const SpeexSubmode * const *submodes; diff --git a/vendor/libspeex/libspeex/stack_alloc.h b/vendor/libspeex/libspeex/stack_alloc.h index 5264e666b0..a446065825 100644 --- a/vendor/libspeex/libspeex/stack_alloc.h +++ b/vendor/libspeex/libspeex/stack_alloc.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -36,7 +36,7 @@ #define STACK_ALLOC_H #ifdef USE_ALLOCA -# ifdef WIN32 +# ifdef _WIN32 # include # else # ifdef HAVE_ALLOCA_H @@ -101,7 +101,7 @@ #endif #if defined(VAR_ARRAYS) -#define VARDECL(var) +#define VARDECL(var) #define ALLOC(var, size, type) type var[size] #elif defined(USE_ALLOCA) #define VARDECL(var) var diff --git a/vendor/libspeex/libspeex/testenc.c b/vendor/libspeex/libspeex/testenc.c new file mode 100644 index 0000000000..1f634ed745 --- /dev/null +++ b/vendor/libspeex/libspeex/testenc.c @@ -0,0 +1,145 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_callbacks.h" +#include +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 160 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); + + /* BEGIN: You probably don't need the following in a real application */ + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + /* END of unnecessary stuff */ + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + /* Turn this off if you want to measure SNR (on by default) */ + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp); + speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + +#ifndef DISABLE_FLOAT_API + { + float sigpow,errpow,snr, seg_snr=0; + sigpow = 0; + errpow = 0; + + /* This code just computes SNR, so you don't need it either */ + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 640 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_UWB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=0; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=7; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=1; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i +#include + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + +#define FRAME_SIZE 320 +#include +int main(int argc, char **argv) +{ + char *inFile, *outFile, *bitsFile; + FILE *fin, *fout, *fbits=NULL; + short in_short[FRAME_SIZE]; + short out_short[FRAME_SIZE]; + float sigpow,errpow,snr, seg_snr=0; + int snr_frames = 0; + char cbits[200]; + int nbBits; + int i; + void *st; + void *dec; + SpeexBits bits; + spx_int32_t tmp; + int bitCount=0; + spx_int32_t skip_group_delay; + SpeexCallback callback; + + sigpow = 0; + errpow = 0; + + st = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + dec = speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_WB)); + + callback.callback_id = SPEEX_INBAND_CHAR; + callback.func = speex_std_char_handler; + callback.data = stderr; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + callback.callback_id = SPEEX_INBAND_MODE_REQUEST; + callback.func = speex_std_mode_request_handler; + callback.data = st; + speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback); + + tmp=1; + speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp); + tmp=0; + speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp); + tmp=8; + speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp); + tmp=3; + speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp); + /*tmp=3; + speex_encoder_ctl(st, SPEEX_SET_HIGH_MODE, &tmp); + tmp=6; + speex_encoder_ctl(st, SPEEX_SET_LOW_MODE, &tmp); +*/ + + speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay); + speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp); + skip_group_delay += tmp; + + + if (argc != 4 && argc != 3) + { + fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc); + exit(1); + } + inFile = argv[1]; + fin = fopen(inFile, "rb"); + outFile = argv[2]; + fout = fopen(outFile, "wb+"); + if (argc==4) + { + bitsFile = argv[3]; + fbits = fopen(bitsFile, "wb"); + } + speex_bits_init(&bits); + while (!feof(fin)) + { + fread(in_short, sizeof(short), FRAME_SIZE, fin); + if (feof(fin)) + break; + speex_bits_reset(&bits); + + speex_encode_int(st, in_short, &bits); + nbBits = speex_bits_write(&bits, cbits, 200); + bitCount+=bits.nbBits; + + if (argc==4) + fwrite(cbits, 1, nbBits, fbits); + speex_bits_rewind(&bits); + + speex_decode_int(dec, &bits, out_short); + speex_bits_reset(&bits); + + fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout); + skip_group_delay = 0; + } + fprintf (stderr, "Total encoded size: %d bits\n", bitCount); + speex_encoder_destroy(st); + speex_decoder_destroy(dec); + speex_bits_destroy(&bits); + + rewind(fin); + rewind(fout); + + while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) + && + FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) ) + { + float s=0, e=0; + for (i=0;i1e-13?log((x)*(x))*4.34294480f:-30) -#define fromdB(x) (exp((x)*.11512925f)) +#define fromdB(x) (exp((x)*.11512925f)) /* The bark scale equations are approximations, since the original table was somewhat hand rolled. The below are chosen to have the diff --git a/vendor/libspeex/libspeex/vq.h b/vendor/libspeex/libspeex/vq.h index 5a4ced249c..5c707f0555 100644 --- a/vendor/libspeex/libspeex/vq.h +++ b/vendor/libspeex/libspeex/vq.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/vq_arm4.h b/vendor/libspeex/libspeex/vq_arm4.h index 585b8613c5..957e195f24 100644 --- a/vendor/libspeex/libspeex/vq_arm4.h +++ b/vendor/libspeex/libspeex/vq_arm4.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeex/vq_bfin.h b/vendor/libspeex/libspeex/vq_bfin.h index a4d2d2ff3b..82979894eb 100644 --- a/vendor/libspeex/libspeex/vq_bfin.h +++ b/vendor/libspeex/libspeex/vq_bfin.h @@ -1,25 +1,25 @@ /* Copyright (C) 2005 Analog Devices */ /** @file vq_bfin.h - @author Jean-Marc Valin + @author Jean-Marc Valin @brief Blackfin-optimized vq routine */ /* 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeexdsp/_kiss_fft_guts.h b/vendor/libspeex/libspeexdsp/_kiss_fft_guts.h index 6571e79c0c..f5f2a5fd76 100644 --- a/vendor/libspeex/libspeexdsp/_kiss_fft_guts.h +++ b/vendor/libspeex/libspeexdsp/_kiss_fft_guts.h @@ -23,7 +23,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include "math_approx.h" #define MAXFACTORS 32 -/* e.g. an fft of length 128 has 4 factors +/* e.g. an fft of length 128 has 4 factors as far as kissfft is concerned 4*4*4*2 */ @@ -47,7 +47,7 @@ struct kiss_fft_state{ #ifdef FIXED_POINT #include "arch.h" # define FRACBITS 15 -# define SAMPPROD spx_int32_t +# define SAMPPROD spx_int32_t #define SAMP_MAX 32767 #define SAMP_MIN -SAMP_MAX diff --git a/vendor/libspeex/libspeexdsp/arch.h b/vendor/libspeex/libspeexdsp/arch.h index 535d308302..1cac3d9c89 100644 --- a/vendor/libspeex/libspeexdsp/arch.h +++ b/vendor/libspeex/libspeexdsp/arch.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -41,10 +41,10 @@ #ifdef FLOATING_POINT #error You cannot compile as floating point and fixed point at the same time #endif -#ifdef _USE_SSE +#ifdef USE_SSE #error SSE is only for floating-point #endif -#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) +#if defined(ARM4_ASM) + defined(ARM5E_ASM) + defined(BFIN_ASM) > 1 #error Make up your mind. What CPU do you have? #endif #ifdef VORBIS_PSYCHO @@ -56,10 +56,10 @@ #ifndef FLOATING_POINT #error You now need to define either FIXED_POINT or FLOATING_POINT #endif -#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) +#if defined(ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) #error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? #endif -#ifdef FIXED_POINT_DEBUG +#ifdef FIXED_DEBUG #error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" #endif @@ -101,6 +101,8 @@ typedef spx_word32_t spx_sig_t; #define SIG_SHIFT 14 #define GAIN_SHIFT 6 +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) + #define VERY_SMALL 0 #define VERY_LARGE32 ((spx_word32_t)2147483647) #define VERY_LARGE16 ((spx_word16_t)32767) @@ -115,9 +117,9 @@ typedef spx_word32_t spx_sig_t; #ifdef ARM5E_ASM #include "fixed_arm5e.h" -#elif defined (ARM4_ASM) +#elif defined(ARM4_ASM) #include "fixed_arm4.h" -#elif defined (BFIN_ASM) +#elif defined(BFIN_ASM) #include "fixed_bfin.h" #endif @@ -175,16 +177,13 @@ typedef float spx_word32_t; #define ADD32(a,b) ((a)+(b)) #define SUB32(a,b) ((a)-(b)) #define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_32_32(a,b) ((a)*(b)) #define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) #define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) -#define MULT16_32_Q11(a,b) ((a)*(b)) -#define MULT16_32_Q13(a,b) ((a)*(b)) -#define MULT16_32_Q14(a,b) ((a)*(b)) #define MULT16_32_Q15(a,b) ((a)*(b)) #define MULT16_32_P15(a,b) ((a)*(b)) -#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) #define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) @@ -203,18 +202,19 @@ typedef float spx_word32_t; #define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) #define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) - +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : \ + ((x) > 32766.5f ? 32767 : (spx_int16_t)floor(.5 + (x)))) #endif -#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) +#if defined(CONFIG_TI_C54X) || defined(CONFIG_TI_C55X) /* 2 on TI C5x DSP */ -#define BYTES_PER_CHAR 2 +#define BYTES_PER_CHAR 2 #define BITS_PER_CHAR 16 #define LOG2_BITS_PER_CHAR 4 -#else +#else #define BYTES_PER_CHAR 1 #define BITS_PER_CHAR 8 diff --git a/vendor/libspeex/libspeexdsp/buffer.c b/vendor/libspeex/libspeexdsp/buffer.c index c82cab5bc5..b06a155434 100644 --- a/vendor/libspeex/libspeexdsp/buffer.c +++ b/vendor/libspeex/libspeexdsp/buffer.c @@ -1,5 +1,5 @@ /* Copyright (C) 2007 Jean-Marc Valin - + File: buffer.c This is a very simple ring buffer implementation. It is not thread-safe so you need to do your own locking. @@ -99,7 +99,7 @@ EXPORT int speex_buffer_write(SpeexBuffer *st, void *_data, int len) EXPORT int speex_buffer_writezeros(SpeexBuffer *st, int len) { - /* This is almost the same as for speex_buffer_write() but using + /* This is almost the same as for speex_buffer_write() but using SPEEX_MEMSET() instead of SPEEX_COPY(). Update accordingly. */ int end; int end1; @@ -135,7 +135,7 @@ EXPORT int speex_buffer_read(SpeexBuffer *st, void *_data, int len) char *data = _data; if (len > st->available) { - SPEEX_MEMSET(data+st->available, 0, st->size-st->available); + SPEEX_MEMSET(data+st->available, 0, len - st->available); len = st->available; } end = st->read_ptr + len; diff --git a/vendor/libspeex/libspeexdsp/config.h b/vendor/libspeex/libspeexdsp/config.h index d4a0050a30..a7455d8c39 100644 --- a/vendor/libspeex/libspeexdsp/config.h +++ b/vendor/libspeex/libspeexdsp/config.h @@ -3,19 +3,19 @@ // In Visual Studio, _M_IX86_FP=1 means /arch:SSE was used, likewise // _M_IX86_FP=2 means /arch:SSE2 was used. -// Also, enable both _USE_SSE and _USE_SSE2 if we're compiling for x86-64 +// Also, enable both USE_SSE and USE_SSE2 if we're compiling for x86-64 #if _M_IX86_FP >= 1 || defined(_M_X64) -#define _USE_SSE +#define USE_SSE #endif #if _M_IX86_FP >= 2 || defined(_M_X64) -#define _USE_SSE2 +#define USE_SSE2 #endif // Visual Studio support alloca(), but it always align variables to 16-bit // boundary, while SSE need 128-bit alignment. So we disable alloca() when // SSE is enabled. -#ifndef _USE_SSE +#ifndef USE_SSE # define USE_ALLOCA #endif diff --git a/vendor/libspeex/libspeexdsp/fftwrap.c b/vendor/libspeex/libspeexdsp/fftwrap.c index a14b1e4fb0..4573479d00 100644 --- a/vendor/libspeex/libspeexdsp/fftwrap.c +++ b/vendor/libspeex/libspeexdsp/fftwrap.c @@ -1,23 +1,23 @@ -/* Copyright (C) 2005-2006 Jean-Marc Valin +/* Copyright (C) 2005-2006 Jean-Marc Valin File: fftwrap.c - Wrapper for various FFTs + Wrapper for various FFTs 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -62,7 +62,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun for (i=0;iifft); - + for(i=0;i #include "math_approx.h" #include "os_support.h" - + #ifdef FIXED_POINT #define toBARK(n) (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n)) - + #else #define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) #endif - + #define toMEL(n) (2595.f*log10(1.f+(n)/700.f)) FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) @@ -62,7 +62,7 @@ FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) df = DIV32(SHL32(sampling,15),MULT16_16(2,len)); max_mel = toBARK(EXTRACT16(sampling/2)); mel_interval = PDIV32(max_mel,banks-1); - + bank = (FilterBank*)speex_alloc(sizeof(FilterBank)); bank->nb_banks = banks; bank->len = len; @@ -85,7 +85,7 @@ FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) break; #ifdef FIXED_POINT id1 = DIV32(mel,mel_interval); -#else +#else id1 = (int)(floor(mel/mel_interval)); #endif if (id1>banks-2) @@ -101,7 +101,7 @@ FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) bank->bank_right[i] = id2; bank->filter_right[i] = val; } - + /* Think I can safely disable normalisation for fixed-point (and probably float as well) */ #ifndef FIXED_POINT for (i=0;inb_banks;i++) diff --git a/vendor/libspeex/libspeexdsp/fixed_arm4.h b/vendor/libspeex/libspeexdsp/fixed_arm4.h index b6981cae72..a7040b8a9d 100644 --- a/vendor/libspeex/libspeexdsp/fixed_arm4.h +++ b/vendor/libspeex/libspeexdsp/fixed_arm4.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -35,19 +35,6 @@ #ifndef FIXED_ARM4_H #define FIXED_ARM4_H -#undef MULT16_32_Q14 -static inline spx_word32_t MULT16_32_Q14(spx_word16_t x, spx_word32_t y) { - int res; - int dummy; - asm ( - "smull %0,%1,%2,%3 \n\t" - "mov %0, %0, lsr #14 \n\t" - "add %0, %0, %1, lsl #18 \n\t" - : "=&r"(res), "=&r" (dummy) - : "r"(y),"r"((int)x)); - return(res); -} - #undef MULT16_32_Q15 static inline spx_word32_t MULT16_32_Q15(spx_word16_t x, spx_word32_t y) { int res; @@ -109,7 +96,7 @@ static inline short DIV32_16(int a, int b) "\tsubs %3, %0, %1, asl #6 \n" "\tmovpl %0, %3 \n" "\torrpl %2, %2, %4, asl #6 \n" - + "\tsubs %3, %0, %1, asl #5 \n" "\tmovpl %0, %3 \n" "\torrpl %2, %2, %4, asl #5 \n" diff --git a/vendor/libspeex/libspeexdsp/fixed_arm5e.h b/vendor/libspeex/libspeexdsp/fixed_arm5e.h index 9b4861c9a7..15c6d5dee1 100644 --- a/vendor/libspeex/libspeexdsp/fixed_arm5e.h +++ b/vendor/libspeex/libspeexdsp/fixed_arm5e.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -71,24 +71,6 @@ static inline spx_word32_t MAC16_32_Q15(spx_word32_t a, spx_word16_t x, spx_word return(res); } -#undef MULT16_32_Q11 -static inline spx_word32_t MULT16_32_Q11(spx_word16_t x, spx_word32_t y) { - int res; - asm ("smulwb %0,%1,%2;\n" - : "=&r"(res) - : "%r"(y<<5),"r"(x)); - return(res); -} - -#undef MAC16_32_Q11 -static inline spx_word32_t MAC16_32_Q11(spx_word32_t a, spx_word16_t x, spx_word32_t y) { - int res; - asm ("smlawb %0,%1,%2,%3;\n" - : "=&r"(res) - : "%r"(y<<5),"r"(x),"r"(a)); - return(res); -} - #undef DIV32_16 static inline short DIV32_16(int a, int b) { @@ -161,7 +143,7 @@ static inline short DIV32_16(int a, int b) "\tsubs %3, %0, %1 \n" "\torrpl %2, %2, %4 \n" "\tmovpl %0, %3 \n" - + "\tmovs %5, %5, lsr #31 \n" "\trsbne %2, %2, #0 \n" : "=r" (dead1), "=r" (dead2), "=r" (res), diff --git a/vendor/libspeex/libspeexdsp/fixed_bfin.h b/vendor/libspeex/libspeexdsp/fixed_bfin.h index 9eb21e3396..9a54d64e65 100644 --- a/vendor/libspeex/libspeexdsp/fixed_bfin.h +++ b/vendor/libspeex/libspeexdsp/fixed_bfin.h @@ -8,18 +8,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -68,9 +68,9 @@ static inline spx_word16_t DIV32_16(spx_word32_t a, spx_word16_t b) { spx_word32_t res, bb; bb = b; - /* Make the roundinf consistent with the C version + /* Make the roundinf consistent with the C version (do we need to do that?)*/ - if (a<0) + if (a<0) a += (b-1); __asm__ ( "P0 = 15;\n\t" @@ -138,39 +138,4 @@ static inline spx_word32_t MAC16_32_Q15(spx_word32_t c, spx_word16_t a, spx_word return res; } -#undef MULT16_32_Q14 -static inline spx_word32_t MULT16_32_Q14(spx_word16_t a, spx_word32_t b) -{ - spx_word32_t res; - __asm__ - ( - "%2 <<= 1;\n\t" - "A1 = %1.L*%2.L (M);\n\t" - "A1 = A1 >>> 15;\n\t" - "%0 = (A1 += %1.L*%2.H);\n\t" - : "=W" (res), "=d" (a), "=d" (b) - : "1" (a), "2" (b) - : "A1", "ASTAT" - ); - return res; -} - -#undef MAC16_32_Q14 -static inline spx_word32_t MAC16_32_Q14(spx_word32_t c, spx_word16_t a, spx_word32_t b) -{ - spx_word32_t res; - __asm__ - ( - "%1 <<= 1;\n\t" - "A1 = %2.L*%1.L (M);\n\t" - "A1 = A1 >>> 15;\n\t" - "%0 = (A1 += %2.L*%1.H);\n\t" - "%0 = %0 + %4;\n\t" - : "=&W" (res), "=&d" (b) - : "d" (a), "1" (b), "d" (c) - : "A1", "ASTAT" - ); - return res; -} - #endif diff --git a/vendor/libspeex/libspeexdsp/fixed_debug.h b/vendor/libspeex/libspeexdsp/fixed_debug.h index 54f3866e8f..dbf02f191b 100644 --- a/vendor/libspeex/libspeexdsp/fixed_debug.h +++ b/vendor/libspeex/libspeexdsp/fixed_debug.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -101,7 +101,7 @@ static inline int _EXTEND32(int x, char *file, int line) } #define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) -static inline short _SHR16(int a, int shift, char *file, int line) +static inline short _SHR16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) @@ -115,7 +115,7 @@ static inline short _SHR16(int a, int shift, char *file, int line) return res; } #define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) -static inline short _SHL16(int a, int shift, char *file, int line) +static inline short _SHL16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) @@ -129,7 +129,7 @@ static inline short _SHL16(int a, int shift, char *file, int line) return res; } -static inline int SHR32(long long a, int shift) +static inline int SHR32(long long a, int shift) { long long res; if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) @@ -144,7 +144,7 @@ static inline int SHR32(long long a, int shift) spx_mips++; return res; } -static inline int SHL32(long long a, int shift) +static inline int SHL32(long long a, int shift) { long long res; if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) @@ -171,7 +171,7 @@ static inline int SHL32(long long a, int shift) //#define SHL(a,shift) ((a) << (shift)) #define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) -static inline short _ADD16(int a, int b, char *file, int line) +static inline short _ADD16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -188,7 +188,7 @@ static inline short _ADD16(int a, int b, char *file, int line) } #define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) -static inline short _SUB16(int a, int b, char *file, int line) +static inline short _SUB16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -203,7 +203,7 @@ static inline short _SUB16(int a, int b, char *file, int line) } #define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) -static inline int _ADD32(long long a, long long b, char *file, int line) +static inline int _ADD32(long long a, long long b, char *file, int line) { long long res; if (!VERIFY_INT(a) || !VERIFY_INT(b)) @@ -219,7 +219,7 @@ static inline int _ADD32(long long a, long long b, char *file, int line) return res; } -static inline int SUB32(long long a, long long b) +static inline int SUB32(long long a, long long b) { long long res; if (!VERIFY_INT(a) || !VERIFY_INT(b)) @@ -236,7 +236,7 @@ static inline int SUB32(long long a, long long b) #define ADD64(a,b) (MIPS_INC(a)+(b)) /* result fits in 16 bits */ -static inline short MULT16_16_16(int a, int b) +static inline short MULT16_16_16(int a, int b) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -250,8 +250,23 @@ static inline short MULT16_16_16(int a, int b) return res; } +/* result fits in 32 bits */ +static inline int MULT16_32_32(int a, long long b) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_32: inputs are not short+int: %d %d\n", a, (int)b); + } + res = a*b; + if (!VERIFY_INT(res)) + fprintf (stderr, "MULT16_32_32: output is not int: %d\n", (int)res); + spx_mips++; + return res; +} + #define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) -static inline int _MULT16_16(int a, int b, char *file, int line) +static inline int _MULT16_16(int a, int b, char *file, int line) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -279,8 +294,8 @@ static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) { fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); } - if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + if (ABS(b)>>(16+Q)) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); res = (((long long)a)*(long long)b) >> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); @@ -295,8 +310,8 @@ static inline int MULT16_32_PX(int a, long long b, int Q) { fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); } - if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + if (ABS(b)>>(16+Q)) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); @@ -305,11 +320,6 @@ static inline int MULT16_32_PX(int a, long long b, int Q) } -#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11) -#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b))) -#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12) -#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13) -#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14) #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) #define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15) #define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b))) @@ -323,7 +333,7 @@ static inline int SATURATE(int a, int b) return a; } -static inline int MULT16_16_Q11_32(int a, int b) +static inline int MULT16_16_Q11_32(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -337,7 +347,7 @@ static inline int MULT16_16_Q11_32(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q13(int a, int b) +static inline short MULT16_16_Q13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -351,7 +361,7 @@ static inline short MULT16_16_Q13(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q14(int a, int b) +static inline short MULT16_16_Q14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -365,7 +375,7 @@ static inline short MULT16_16_Q14(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q15(int a, int b) +static inline short MULT16_16_Q15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -382,7 +392,7 @@ static inline short MULT16_16_Q15(int a, int b) return res; } -static inline short MULT16_16_P13(int a, int b) +static inline short MULT16_16_P13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -399,7 +409,7 @@ static inline short MULT16_16_P13(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P14(int a, int b) +static inline short MULT16_16_P14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -416,7 +426,7 @@ static inline short MULT16_16_P14(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P15(int a, int b) +static inline short MULT16_16_P15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -436,7 +446,7 @@ static inline short MULT16_16_P15(int a, int b) #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) -static inline int _DIV32_16(long long a, long long b, char *file, int line) +static inline int _DIV32_16(long long a, long long b, char *file, int line) { long long res; if (b==0) @@ -462,7 +472,7 @@ static inline int _DIV32_16(long long a, long long b, char *file, int line) } #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) -static inline int _DIV32(long long a, long long b, char *file, int line) +static inline int _DIV32(long long a, long long b, char *file, int line) { long long res; if (b==0) diff --git a/vendor/libspeex/libspeexdsp/fixed_generic.h b/vendor/libspeex/libspeexdsp/fixed_generic.h index 0e012e9ab1..09366c36ce 100644 --- a/vendor/libspeex/libspeexdsp/fixed_generic.h +++ b/vendor/libspeex/libspeexdsp/fixed_generic.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -69,22 +69,18 @@ /* result fits in 16 bits */ -#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) +#define MULT16_16_16(a,b) (((spx_word16_t)(a))*((spx_word16_t)(b))) +/* result fits in 32 bits */ +#define MULT16_32_32(a,b) (((spx_word16_t)(a))*((spx_word32_t)(b))) /* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ #define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) #define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) -#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) -#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) -#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) - -#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) -#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) -#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) -#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) -#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) +#define MULT16_32_P15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_Q15(c,a,b) ADD32(c,MULT16_32_Q15(a,b)) #define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) diff --git a/vendor/libspeex/libspeexdsp/jitter.c b/vendor/libspeex/libspeexdsp/jitter.c index a077d8dd41..4441a821d1 100644 --- a/vendor/libspeex/libspeexdsp/jitter.c +++ b/vendor/libspeex/libspeexdsp/jitter.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Jean-Marc Valin +/* Copyright (C) 2002 Jean-Marc Valin File: speex_jitter.h Adaptive jitter buffer for Speex @@ -6,18 +6,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -71,7 +71,7 @@ #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) -#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) +#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) #define MAX_TIMINGS 40 #define MAX_BUFFERS 3 @@ -101,7 +101,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) tb->curr_count++; return; } - + /* Find where the timing info goes in the sorted list */ pos = 0; /* FIXME: Do bisection instead of linear search */ @@ -109,9 +109,9 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) { pos++; } - + speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); - + /* Shift everything so we can perform the insertion */ if (pos < tb->filled) { @@ -124,7 +124,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) /* Insert */ tb->timing[pos] = timing; tb->counts[pos] = tb->curr_count; - + tb->curr_count++; if (tb->filledfilled++; @@ -137,12 +137,12 @@ struct JitterBuffer_ { spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ - + spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ - + JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ - + void (*destroy) (void *); /**< Callback for destroying a packet */ spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ @@ -152,7 +152,7 @@ struct JitterBuffer_ { int late_cutoff; /**< How late must a packet be for it not to be considered at all */ int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ int auto_adjust; /**< Whether to automatically adjust the delay at any time */ - + struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ int window_size; /**< Total window over which the late frames are counted */ @@ -160,15 +160,15 @@ struct JitterBuffer_ { int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ - + int lost_count; /**< Number of consecutive lost packets */ }; -/** Based on available data, this computes the optimal delay for the jitter buffer. +/** Based on available data, this computes the optimal delay for the jitter buffer. The optimised function is in timestamp units and is: cost = delay + late_factor*[number of frames that would be late if we used that delay] @param tb Array of buffers - @param late_factor Equivalent cost of a late frame (in timestamp units) + @param late_factor Equivalent cost of a late frame (in timestamp units) */ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) { @@ -184,34 +184,34 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) int worst = 0; spx_int32_t deltaT; struct TimingBuffer *tb; - + tb = jitter->_tb; - + /* Number of packet timings we have received (including those we didn't keep) */ tot_count = 0; for (i=0;ilatency_tradeoff != 0) late_factor = jitter->latency_tradeoff * 100.0f / tot_count; else late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; - + /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ for (i=0;idelay_step); pos[next]++; - + /* Actual cost function that tells us how bad using this delay would be */ cost = -latest + late_factor*late; /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ @@ -241,7 +241,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) } else { break; } - + /* For the next timing we will consider, there will be one more late packet to count */ late++; /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ @@ -251,14 +251,14 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) late+=4; } } - + deltaT = best-worst; /* This is a default "automatic latency tradeoff" when none is provided */ jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ - + /* FIXME: Compute a short-term estimate too and combine with the long-term one */ - + /* Prevents reducing the buffer size when we haven't really had much data */ if (tot_count < TOP_DELAY && opt > 0) return 0; @@ -313,7 +313,7 @@ EXPORT void jitter_buffer_reset(JitterBuffer *jitter) jitter->lost_count = 0; jitter->buffered = 0; jitter->auto_tradeoff = 32000; - + for (i=0;i_tb[i]); @@ -368,7 +368,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa int i,j; int late; /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ - + /* Cleanup buffer (remove old packets that weren't played) */ if (!jitter->reset_state) { @@ -386,7 +386,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa } } } - + /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ /* Check if packet is late (could still be useful though) */ if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) @@ -403,7 +403,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa { jitter_buffer_reset(jitter); } - + /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) { @@ -414,7 +414,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa if (jitter->packets[i].data==NULL) break; } - + /*No place left in the buffer, need to make room for it by discarding the oldest packet */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -433,9 +433,9 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa else speex_free(jitter->packets[i].data); jitter->packets[i].data=NULL; - /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ + /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ } - + /* Copy packet in buffer */ if (jitter->destroy) { @@ -455,8 +455,8 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa else jitter->arrival[i] = jitter->next_stop; } - - + + } /** Get one packet from the jitter buffer */ @@ -465,7 +465,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s int i; unsigned int j; spx_int16_t opt; - + if (start_offset != NULL) *start_offset = 0; @@ -485,7 +485,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s } if (found) { - jitter->reset_state=0; + jitter->reset_state=0; jitter->pointer_timestamp = oldest; jitter->next_stop = oldest; } else { @@ -494,36 +494,36 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s return JITTER_BUFFER_MISSING; } } - + jitter->last_returned_timestamp = jitter->pointer_timestamp; - + if (jitter->interp_requested != 0) { packet->timestamp = jitter->pointer_timestamp; packet->span = jitter->interp_requested; - + /* Increment the pointer because it got decremented in the delay update */ jitter->pointer_timestamp += jitter->interp_requested; packet->len = 0; /*fprintf (stderr, "Deferred interpolate\n");*/ - + jitter->interp_requested = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_INSERTION; } - + /* Searching for the packet that fits best */ - + /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) break; } - + /* If no match, try for an "older" packet that still spans (fully) the current chunk */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -533,7 +533,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s break; } } - + /* If still no match, try for an "older" packet that spans part of the current chunk */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -543,7 +543,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s break; } } - + /* If still no match, try for earliest packet possible */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -576,17 +576,17 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) { spx_int32_t offset; - + /* We (obviously) haven't lost this packet */ jitter->lost_count = 0; - + /* In this case, 0 isn't as a valid timestamp */ if (jitter->arrival[i] != 0) { update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); } - - + + /* Copy packet */ if (jitter->destroy) { @@ -611,10 +611,10 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s *start_offset = offset; else if (offset != 0) speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); - + packet->timestamp = jitter->packets[i].timestamp; jitter->last_returned_timestamp = packet->timestamp; - + packet->span = jitter->packets[i].span; packet->sequence = jitter->packets[i].sequence; packet->user_data = jitter->packets[i].user_data; @@ -622,36 +622,36 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; jitter->buffered = packet->span - desired_span; - + if (start_offset != NULL) jitter->buffered += *start_offset; - + return JITTER_BUFFER_OK; } - - + + /* If we haven't found anything worth returning */ - + /*fprintf (stderr, "not found\n");*/ jitter->lost_count++; /*fprintf (stderr, "m");*/ /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ - + opt = compute_opt_delay(jitter); - - /* Should we force an increase in the buffer or just do normal interpolation? */ + + /* Should we force an increase in the buffer or just do normal interpolation? */ if (opt < 0) { /* Need to increase buffering */ - + /* Shift histogram to compensate */ shift_timings(jitter, -opt); - + packet->timestamp = jitter->pointer_timestamp; packet->span = -opt; /* Don't move the pointer_timestamp forward */ packet->len = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_INSERTION; /*jitter->pointer_timestamp -= jitter->delay_step;*/ @@ -659,12 +659,12 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s } else { /* Normal packet loss */ packet->timestamp = jitter->pointer_timestamp; - + desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); packet->span = desired_span; jitter->pointer_timestamp += desired_span; packet->len = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_MISSING; /*fprintf (stderr, "Normal loss\n");*/ @@ -713,11 +713,11 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket { spx_int16_t opt = compute_opt_delay(jitter); /*fprintf(stderr, "opt adjustment is %d ", opt);*/ - + if (opt < 0) { shift_timings(jitter, -opt); - + jitter->pointer_timestamp += opt; jitter->interp_requested = -opt; /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ @@ -727,14 +727,14 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket jitter->pointer_timestamp += opt; /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ } - + return opt; } /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) { - /* If the programmer calls jitter_buffer_update_delay() directly, + /* If the programmer calls jitter_buffer_update_delay() directly, automatically disable auto-adjustment */ jitter->auto_adjust = 0; @@ -752,7 +752,7 @@ EXPORT void jitter_buffer_tick(JitterBuffer *jitter) /* Automatically-adjust the buffering delay if requested */ if (jitter->auto_adjust) _jitter_buffer_update_delay(jitter, NULL, NULL); - + if (jitter->buffered >= 0) { jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; @@ -768,7 +768,7 @@ EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) /* Automatically-adjust the buffering delay if requested */ if (jitter->auto_adjust) _jitter_buffer_update_delay(jitter, NULL, NULL); - + if (jitter->buffered < 0) speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); jitter->next_stop = jitter->pointer_timestamp - rem; diff --git a/vendor/libspeex/libspeexdsp/kiss_fft.c b/vendor/libspeex/libspeexdsp/kiss_fft.c index 67782810fe..8dc9345428 100644 --- a/vendor/libspeex/libspeexdsp/kiss_fft.c +++ b/vendor/libspeex/libspeexdsp/kiss_fft.c @@ -23,7 +23,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include "os_support.h" /* The guts header contains all the multiplication and addition macros that are defined for - fixed or floating point complex numbers. It also delares the kf_ internal functions. + fixed or floating point complex numbers. It also declares the kf_ internal functions. */ static void kf_bfly2( @@ -110,7 +110,7 @@ static void kf_bfly4( C_MUL(scratch[0],Fout[m] , *tw1 ); C_MUL(scratch[1],Fout[m2] , *tw2 ); C_MUL(scratch[2],Fout[m3] , *tw3 ); - + C_SUB( scratch[5] , *Fout, scratch[1] ); C_ADDTO(*Fout, scratch[1]); C_ADD( scratch[3] , scratch[0] , scratch[2] ); @@ -120,7 +120,7 @@ static void kf_bfly4( tw2 += fstride*2; tw3 += fstride*3; C_ADDTO( *Fout , scratch[3] ); - + Fout[m].r = scratch[5].r - scratch[4].i; Fout[m].i = scratch[5].i + scratch[4].r; Fout[m3].r = scratch[5].r + scratch[4].i; @@ -140,7 +140,7 @@ static void kf_bfly4( C_MUL4(scratch[0],Fout[m] , *tw1 ); C_MUL4(scratch[1],Fout[m2] , *tw2 ); C_MUL4(scratch[2],Fout[m3] , *tw3 ); - + Fout->r = PSHR16(Fout->r, 2); Fout->i = PSHR16(Fout->i, 2); C_SUB( scratch[5] , *Fout, scratch[1] ); @@ -154,7 +154,7 @@ static void kf_bfly4( tw2 += fstride*2; tw3 += fstride*3; C_ADDTO( *Fout , scratch[3] ); - + Fout[m].r = scratch[5].r + scratch[4].i; Fout[m].i = scratch[5].i - scratch[4].r; Fout[m3].r = scratch[5].r - scratch[4].i; @@ -292,7 +292,7 @@ static void kf_bfly_generic( /*CHECKBUF(scratchbuf,nscratchbuf,p);*/ if (p>17) speex_fatal("KissFFT: max radix supported is 17"); - + for ( u=0; unfft); diff --git a/vendor/libspeex/libspeexdsp/kiss_fft.h b/vendor/libspeex/libspeexdsp/kiss_fft.h index fa3f2c6042..bb19eadbd9 100644 --- a/vendor/libspeex/libspeexdsp/kiss_fft.h +++ b/vendor/libspeex/libspeexdsp/kiss_fft.h @@ -26,13 +26,13 @@ extern "C" { # include # define kiss_fft_scalar __m128 #define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) -#else +#else #define KISS_FFT_MALLOC speex_alloc -#endif +#endif #ifdef FIXED_POINT -#include "arch.h" +#include "arch.h" # define kiss_fft_scalar spx_int16_t #else # ifndef kiss_fft_scalar @@ -48,9 +48,9 @@ typedef struct { typedef struct kiss_fft_state* kiss_fft_cfg; -/* +/* * kiss_fft_alloc - * + * * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. * * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); @@ -60,18 +60,18 @@ typedef struct kiss_fft_state* kiss_fft_cfg; * * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. * The returned value should be free()d when done to avoid memory leaks. - * + * * The state can be placed in a user supplied buffer 'mem': * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, * then the function places the cfg in mem and the size used in *lenmem * and returns mem. - * + * * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), - * then the function returns NULL and places the minimum cfg + * then the function returns NULL and places the minimum cfg * buffer size in *lenmem. * */ -kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); /* * kiss_fft(cfg,in_out_buf) @@ -90,19 +90,19 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); * */ void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); -/* If kiss_fft_alloc allocated a buffer, it is one contiguous +/* If kiss_fft_alloc allocated a buffer, it is one contiguous buffer and can be simply free()d when no longer needed*/ #define kiss_fft_free speex_free /* - Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up your compiler output to call this before you exit. */ void kiss_fft_cleanup(void); - + #ifdef __cplusplus -} +} #endif #endif diff --git a/vendor/libspeex/libspeexdsp/kiss_fftr.c b/vendor/libspeex/libspeexdsp/kiss_fftr.c index f6275b8794..827e0b14df 100644 --- a/vendor/libspeex/libspeexdsp/kiss_fftr.c +++ b/vendor/libspeex/libspeexdsp/kiss_fftr.c @@ -24,9 +24,9 @@ struct kiss_fftr_state{ kiss_fft_cfg substate; kiss_fft_cpx * tmpbuf; kiss_fft_cpx * super_twiddles; -#ifdef USE_SIMD +#ifdef USE_SIMD long pad; -#endif +#endif }; kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) @@ -96,12 +96,12 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr * contains the sum of the even-numbered elements of the input time sequence * The imag part is the sum of the odd-numbered elements * - * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * The sum of tdc.r and tdc.i is the sum of the input time sequence. * yielding DC of input time sequence - * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... * yielding Nyquist bin of input time sequence */ - + tdc.r = st->tmpbuf[0].r; tdc.i = st->tmpbuf[0].i; C_FIXDIV(tdc,2); @@ -109,14 +109,14 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); freqdata[0].r = tdc.r + tdc.i; freqdata[ncfft].r = tdc.r - tdc.i; -#ifdef USE_SIMD +#ifdef USE_SIMD freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); #else freqdata[ncfft].i = freqdata[0].i = 0; #endif for ( k=1;k <= ncfft/2 ; ++k ) { - fpk = st->tmpbuf[k]; + fpk = st->tmpbuf[k]; fpnk.r = st->tmpbuf[ncfft-k].r; fpnk.i = - st->tmpbuf[ncfft-k].i; C_FIXDIV(fpk,2); @@ -161,7 +161,7 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar * C_MUL (fok, tmp, st->super_twiddles[k]); C_ADD (st->tmpbuf[k], fek, fok); C_SUB (st->tmpbuf[ncfft - k], fek, fok); -#ifdef USE_SIMD +#ifdef USE_SIMD st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); #else st->tmpbuf[ncfft - k].i *= -1; @@ -189,12 +189,12 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar * contains the sum of the even-numbered elements of the input time sequence * The imag part is the sum of the odd-numbered elements * - * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * The sum of tdc.r and tdc.i is the sum of the input time sequence. * yielding DC of input time sequence - * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... * yielding Nyquist bin of input time sequence */ - + tdc.r = st->tmpbuf[0].r; tdc.i = st->tmpbuf[0].i; C_FIXDIV(tdc,2); @@ -205,7 +205,7 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar for ( k=1;k <= ncfft/2 ; ++k ) { - /*fpk = st->tmpbuf[k]; + /*fpk = st->tmpbuf[k]; fpnk.r = st->tmpbuf[ncfft-k].r; fpnk.i = - st->tmpbuf[ncfft-k].i; C_FIXDIV(fpk,2); @@ -213,7 +213,7 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar C_ADD( f1k, fpk , fpnk ); C_SUB( f2k, fpk , fpnk ); - + C_MUL( tw , f2k , st->super_twiddles[k]); freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); @@ -226,7 +226,7 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); - + C_MUL( tw , f2k , st->super_twiddles[k]); freqdata[2*k-1] = HALF_OF(f1k.r + tw.r); @@ -236,13 +236,13 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar */ f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1); f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1); - + f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13); f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13); - + twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1); twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1); - + #ifdef FIXED_POINT freqdata[2*k-1] = PSHR32(f1kr + twr, 15); freqdata[2*k] = PSHR32(f1ki + twi, 15); @@ -253,7 +253,7 @@ void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar freqdata[2*k] = .5f*(f1ki + twi); freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr); freqdata[2*(ncfft-k)] = .5f*(twi - f1ki); - + #endif } } @@ -287,7 +287,7 @@ void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scala C_MUL (fok, tmp, st->super_twiddles[k]); C_ADD (st->tmpbuf[k], fek, fok); C_SUB (st->tmpbuf[ncfft - k], fek, fok); -#ifdef USE_SIMD +#ifdef USE_SIMD st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); #else st->tmpbuf[ncfft - k].i *= -1; diff --git a/vendor/libspeex/libspeexdsp/kiss_fftr.h b/vendor/libspeex/libspeexdsp/kiss_fftr.h index 7bfb423340..8cfeda138a 100644 --- a/vendor/libspeex/libspeexdsp/kiss_fftr.h +++ b/vendor/libspeex/libspeexdsp/kiss_fftr.h @@ -6,13 +6,13 @@ extern "C" { #endif - -/* - + +/* + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. - - + + */ typedef struct kiss_fftr_state *kiss_fftr_cfg; @@ -22,7 +22,7 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenm /* nfft must be even - If you don't care to allocate space, use mem = lenmem = NULL + If you don't care to allocate space, use mem = lenmem = NULL */ diff --git a/vendor/libspeex/libspeexdsp/math_approx.h b/vendor/libspeex/libspeexdsp/math_approx.h index 9ca830755d..596dfdc1b7 100644 --- a/vendor/libspeex/libspeexdsp/math_approx.h +++ b/vendor/libspeex/libspeexdsp/math_approx.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -168,11 +168,11 @@ static inline spx_word16_t spx_acos(spx_word16_t x) x = NEG16(x); } x = SUB16(16384,x); - + x = x >> 1; sq = MULT16_16_Q13(x, ADD16(A1, MULT16_16_Q13(x, ADD16(A2, MULT16_16_Q13(x, (A3)))))); ret = spx_sqrt(SHL32(EXTEND32(sq),13)); - + /*ret = spx_sqrt(67108864*(-1.6129e-04 + 2.0104e+00*f + 2.7373e-01*f*f + 1.8136e-01*f*f*f));*/ if (s) ret = SUB16(25736,ret); @@ -208,7 +208,7 @@ static inline spx_word16_t spx_cos(spx_word16_t x) static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x) { spx_word16_t x2; - + x2 = MULT16_16_P15(x,x); return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2)))))))); } diff --git a/vendor/libspeex/libspeexdsp/mdf.c b/vendor/libspeex/libspeexdsp/mdf.c index 456ab847e4..7b367f9a88 100644 --- a/vendor/libspeex/libspeexdsp/mdf.c +++ b/vendor/libspeex/libspeexdsp/mdf.c @@ -33,36 +33,36 @@ /* The echo canceller is based on the MDF algorithm described in: - J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, - IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, + J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, + IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, February 1990. - - We use the Alternatively Updated MDF (AUMDF) variant. Robustness to + + We use the Alternatively Updated MDF (AUMDF) variant. Robustness to double-talk is achieved using a variable learning rate as described in: - - Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo + + Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo Cancellation With Double-Talk. IEEE Transactions on Audio, Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007. http://people.xiph.org/~jm/papers/valin_taslp2006.pdf - + There is no explicit double-talk detection, but a continuous variation in the learning rate based on residual echo, double-talk and background noise. - + About the fixed-point version: - All the signals are represented with 16-bit words. The filter weights + All the signals are represented with 16-bit words. The filter weights are represented with 32-bit words, but only the top 16 bits are used in most cases. The lower 16 bits are completely unreliable (due to the fact that the update is done only on the top bits), but help in the adaptation -- probably by removing a "threshold effect" due to quantization (rounding going to zero) when the gradient is small. - + Another kludge that seems to work good: when performing the weight update, we only move half the way toward the "goal" this seems to reduce the effect of quantization noise in the update phase. This can be seen as applying a gradient descent on a "soft constraint" instead of having a hard constraint. - + */ #ifdef HAVE_CONFIG_H @@ -88,12 +88,6 @@ #define WEIGHT_SHIFT 0 #endif -#ifdef FIXED_POINT -#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) -#else -#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) -#endif - /* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ #define TWO_PATH @@ -145,7 +139,7 @@ struct SpeexEchoState_ { spx_word16_t beta_max; spx_word32_t sum_adapt; spx_word16_t leak_estimate; - + spx_word16_t *e; /* scratch */ spx_word16_t *x; /* Far-end input buffer (2N) */ spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ @@ -198,7 +192,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); #else den2 = radius*radius + .7*(1-radius)*(1-radius); -#endif +#endif /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ for (i=0;iframe_size = frame_size; st->window_size = 2*frame_size; N = st->window_size; @@ -442,7 +436,7 @@ EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_lengt st->leak_estimate = 0; st->fft_table = spx_fft_init(N); - + st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); @@ -498,7 +492,7 @@ EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_lengt st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum); } } - + st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t)); st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); @@ -513,16 +507,16 @@ EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_lengt st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t)); st->adapted = 0; st->Pey = st->Pyy = FLOAT_ONE; - + #ifdef TWO_PATH st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; #endif - + st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; st->play_buf_started = 0; - + return st; } @@ -624,7 +618,7 @@ EXPORT void speex_echo_state_destroy(SpeexEchoState *st) speex_free(st->play_buf); speex_free(st); - + #ifdef DUMP_ECHO_CANCEL_DATA fclose(rFile); fclose(pFile); @@ -704,7 +698,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c spx_float_t alpha, alpha_1; spx_word16_t RER; spx_word32_t tmp32; - + N = st->window_size; M = st->M; C = st->C; @@ -736,7 +730,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c tmp32 = 32767; if (st->saturated == 0) st->saturated = 1; - } + } if (tmp32 < -32767) { tmp32 = -32767; @@ -762,18 +756,18 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c { tmp32 = 32767; st->saturated = M+1; - } + } if (tmp32 < -32767) { tmp32 = -32767; st->saturated = M+1; - } + } #endif st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); st->memX[speak] = far_end[i*K+speak]; } - } - + } + for (speak = 0; speak < K; speak++) { /* Shift memory: this could be optimized eventually*/ @@ -785,15 +779,15 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c /* Convert x (echo input) to frequency domain */ spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); } - + Sxx = 0; for (speak = 0; speak < K; speak++) { Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N); } - - Sff = 0; + + Sff = 0; for (chan = 0; chan < C; chan++) { #ifdef TWO_PATH @@ -805,7 +799,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); #endif } - + /* Adjust proportional adaption rate */ /* FIXME: Adjust that for C, K*/ if (st->adapted) @@ -828,8 +822,8 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c } else { st->saturated--; } - - /* FIXME: MC conversion required */ + + /* FIXME: MC conversion required */ /* Update weight to prevent circular convolution (MDF / AUMDF) */ for (chan = 0; chan < C; chan++) { @@ -869,13 +863,13 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c } } } - - /* So we can use power_spectrum_accum */ + + /* So we can use power_spectrum_accum */ for (i=0;i<=st->frame_size;i++) st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; - + Dbf = 0; - See = 0; + See = 0; #ifdef TWO_PATH /* Difference in response, this is used to estimate the variance of our residual power estimate */ for (chan = 0; chan < C; chan++) @@ -897,20 +891,20 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c #ifdef TWO_PATH /* Logic for updating the foreground filter */ - + /* For two time windows, compute the mean of the energy difference, as well as the variance */ st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); - + /* Equivalent float code: st->Davg1 = .6*st->Davg1 + .4*(Sff-See); st->Davg2 = .85*st->Davg2 + .15*(Sff-See); st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; */ - + update_foreground = 0; /* Check if we have a statistically significant reduction in the residual echo */ /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ @@ -920,7 +914,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c update_foreground = 1; else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) update_foreground = 1; - + /* Do we update? */ if (update_foreground) { @@ -949,12 +943,12 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); /* We also need to copy the output so as to get correct adaptation */ for (chan = 0; chan < C; chan++) - { + { for (i=0;iframe_size;i++) st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; for (i=0;iframe_size;i++) st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); - } + } See = Sff; st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; @@ -962,10 +956,10 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c } #endif - Sey = Syy = Sdd = 0; + Sey = Syy = Sdd = 0; for (chan = 0; chan < C; chan++) - { - /* Compute error signal (for the output with de-emphasis) */ + { + /* Compute error signal (for the output with de-emphasis) */ for (i=0;iframe_size;i++) { spx_word32_t tmp_out; @@ -988,34 +982,34 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c #ifdef DUMP_ECHO_CANCEL_DATA dump_audio(in, far_end, out, st->frame_size); #endif - - /* Compute error signal (filter update version) */ + + /* Compute error signal (filter update version) */ for (i=0;iframe_size;i++) { st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; st->e[chan*N+i] = 0; } - + /* Compute a bunch of correlations */ /* FIXME: bad merge */ Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); - + /* Convert error to frequency domain */ spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); for (i=0;iframe_size;i++) st->y[i+chan*N] = 0; spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); - + /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ power_spectrum_accum(st->E+chan*N, st->Rf, N); power_spectrum_accum(st->Y+chan*N, st->Yf, N); - + } - + /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ - + /* Do some sanity check */ if (!(Syy>=0 && Sxx>=0 && See >= 0) #ifndef FIXED_POINT @@ -1044,14 +1038,14 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c /* Add a small noise floor to make sure not to have problems when dividing */ See = MAX32(See, SHR32(MULT16_16(N, 100),6)); - + for (speak = 0; speak < K; speak++) { Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N); } - + /* Smooth far end energy estimate over time */ for (j=0;j<=st->frame_size;j++) st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); @@ -1072,7 +1066,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; #endif } - + Pyy = FLOAT_SQRT(Pyy); Pey = FLOAT_DIVU(Pey,Pyy); @@ -1100,7 +1094,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c else st->leak_estimate = SHL16(st->leak_estimate,1); /*printf ("%f\n", st->leak_estimate);*/ - + /* Compute Residual to Error Ratio */ #ifdef FIXED_POINT tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); @@ -1156,7 +1150,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c /* Temporary adaption rate if filter is not yet adapted enough */ spx_word16_t adapt_rate=0; - if (Sxx > SHR32(MULT16_16(N, 1000),6)) + if (Sxx > SHR32(MULT16_16(N, 1000),6)) { tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); #ifdef FIXED_POINT @@ -1176,7 +1170,7 @@ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, c st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); } - /* FIXME: MC conversion required */ + /* FIXME: MC conversion required */ for (i=0;iframe_size;i++) st->last_y[i] = st->last_y[st->frame_size+i]; if (st->adapted) @@ -1198,17 +1192,17 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in int i; spx_word16_t leak2; int N; - + N = st->window_size; /* Apply hanning window (should pre-compute it)*/ for (i=0;iy[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); - + /* Compute power spectrum of the echo */ spx_fft(st->fft_table, st->y, st->Y); power_spectrum(st->Y, residual_echo, N); - + #ifdef FIXED_POINT if (st->leak_estimate > 16383) leak2 = 32767; @@ -1223,14 +1217,14 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in /* Estimate residual echo */ for (i=0;i<=st->frame_size;i++) residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); - + } EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) { switch(request) { - + case SPEEX_ECHO_GET_FRAME_SIZE: (*(int*)ptr) = st->frame_size; break; diff --git a/vendor/libspeex/libspeexdsp/misc_bfin.h b/vendor/libspeex/libspeexdsp/misc_bfin.h index 3c8c09d236..4e27681c95 100644 --- a/vendor/libspeex/libspeexdsp/misc_bfin.h +++ b/vendor/libspeex/libspeexdsp/misc_bfin.h @@ -1,25 +1,25 @@ /* Copyright (C) 2005 Analog Devices */ /** @file misc_bfin.h - @author Jean-Marc Valin + @author Jean-Marc Valin @brief Various compatibility routines for Speex (Blackfin version) */ /* 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/vendor/libspeex/libspeexdsp/os_support.h b/vendor/libspeex/libspeexdsp/os_support.h index 2e23a5eb41..0db31a61df 100644 --- a/vendor/libspeex/libspeexdsp/os_support.h +++ b/vendor/libspeex/libspeexdsp/os_support.h @@ -1,5 +1,5 @@ /* Copyright (C) 2007 Jean-Marc Valin - + File: os_support.h This is the (tiny) OS abstraction layer. Aside from math.h, this is the only place where system headers are allowed. @@ -45,12 +45,12 @@ #include "os_support_custom.h" #endif -/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free NOTE: speex_alloc needs to CLEAR THE MEMORY */ #ifndef OVERRIDE_SPEEX_ALLOC static inline void *speex_alloc (int size) { - /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise you will experience strange bugs */ return calloc(size,1); diff --git a/vendor/libspeex/libspeexdsp/preprocess.c b/vendor/libspeex/libspeexdsp/preprocess.c index b8e287a7e7..3053eb5adb 100644 --- a/vendor/libspeex/libspeexdsp/preprocess.c +++ b/vendor/libspeex/libspeexdsp/preprocess.c @@ -1,6 +1,6 @@ /* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) - Copyright (C) 2004-2006 Epic Games - + Copyright (C) 2004-2006 Epic Games + File: preprocess.c Preprocessor with denoising based on the algorithm by Ephraim and Malah @@ -34,24 +34,24 @@ /* Recommended papers: - + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error - short-time spectral amplitude estimator". IEEE Transactions on Acoustics, + short-time spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. - + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error - log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and + log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. - + I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. - Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic - approach to combined acoustic echo cancellation and noise reduction". IEEE + Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic + approach to combined acoustic echo cancellation and noise reduction". IEEE Transactions on Speech and Audio Processing, 2002. - + J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation - of simultaneous non-stationary sources". In Proceedings IEEE International + of simultaneous non-stationary sources". In Proceedings IEEE International Conference on Acoustics, Speech, and Signal Processing, 2004. */ @@ -71,7 +71,7 @@ #define LOUDNESS_EXP 5.f #define AMP_SCALE .001f #define AMP_SCALE_1 1000.f - + #define NB_BANDS 24 #define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) @@ -113,7 +113,7 @@ static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) a = SHL32(a,8); return PDIV32_16(a,b); } - + } static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) { @@ -181,7 +181,7 @@ struct SpeexPreprocessState_ { int sampling_rate; /**< Sampling rate of the input/output */ int nbands; FilterBank *bank; - + /* Parameters */ int denoise_enabled; int vad_enabled; @@ -194,7 +194,7 @@ struct SpeexPreprocessState_ { int echo_suppress; int echo_suppress_active; SpeexEchoState *echo_state; - + spx_word16_t speech_prob; /**< Probability last frame was speech */ /* DSP-related arrays */ @@ -256,7 +256,7 @@ static void conj_window(spx_word16_t *w, int len) spx_word16_t tmp; #ifdef FIXED_POINT spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); -#else +#else spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); #endif int inv=0; @@ -281,10 +281,10 @@ static void conj_window(spx_word16_t *w, int len) } } - + #ifdef FIXED_POINT -/* This function approximates the gain function - y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) +/* This function approximates the gain function + y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) which multiplied by xi/(1+xi) is the optimal gain in the loudness domain ( sqrt[amplitude] ) Input in Q11 format, output in Q15 @@ -317,7 +317,7 @@ static inline spx_word16_t qcurve(spx_word16_t x) static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) { int i; - + if (noise_suppress > effective_echo_suppress) { spx_word16_t noise_gain, gain_ratio; @@ -343,8 +343,8 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, } #else -/* This function approximates the gain function - y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) +/* This function approximates the gain function + y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) which multiplied by xi/(1+xi) is the optimal gain in the loudness domain ( sqrt[amplitude] ) */ @@ -410,8 +410,8 @@ EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sam break; } } - - + + if (st->ps_size < 3*st->frame_size/4) st->ps_size = st->ps_size * 3 / 2; #else @@ -421,7 +421,7 @@ EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sam N = st->ps_size; N3 = 2*N - st->frame_size; N4 = st->frame_size - N3; - + st->sampling_rate = sampling_rate; st->denoise_enabled = 1; st->vad_enabled = 0; @@ -436,15 +436,15 @@ EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sam st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; st->echo_state = NULL; - + st->nbands = NB_BANDS; M = st->nbands; st->bank = filterbank_new(M, sampling_rate, N, 1); - + st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); - + st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); @@ -457,19 +457,19 @@ EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sam st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); - + st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->update_prob = (int*)speex_alloc(N*sizeof(int)); - + st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); conj_window(st->window, 2*N3); for (i=2*N3;i<2*st->ps_size;i++) st->window[i]=Q15_ONE; - + if (N4>0) { for (i=N3-1;i>=0;i--) @@ -569,7 +569,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx float target_gain; float loudness=1.f; float rate; - + for (i=2;ips[i]* st->loudness_weight[i]; @@ -587,7 +587,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx st->init_max *= 1.f + .1f*Pframe*Pframe; } /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ - + target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) @@ -600,11 +600,11 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx target_gain = st->max_gain; if (target_gain > st->init_max) target_gain = st->init_max; - + st->agc_gain = target_gain; } /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ - + for (i=0;i<2*N;i++) ft[i] *= st->agc_gain; st->prev_loudness = loudness; @@ -624,7 +624,7 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) st->frame[i]=st->inbuf[i]; for (i=0;iframe_size;i++) st->frame[N3+i]=x[i]; - + /* Update inbuf */ for (i=0;iinbuf[i]=x[N4+i]; @@ -643,10 +643,10 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) st->frame[i] = SHL16(st->frame[i], st->frame_shift); } #endif - + /* Perform FFT */ spx_fft(st->fft_lookup, st->frame, st->ft); - + /* Power spectrum */ ps[0]=MULT16_16(st->ft[0],st->ft[0]); for (i=1;ips_size; for (i=1;iS[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); - + if (st->nb_adapt==1) { for (i=0;iSmin[i] = MIN32(st->Smin[i], st->S[i]); - st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); + st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); } } for (i=0;inb_adapt++; if (st->nb_adapt>20000) st->nb_adapt = 20000; st->min_count++; - + beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); beta_1 = Q15_ONE-beta; M = st->nbands; @@ -770,7 +770,7 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) st->update_prob[i] = 0; } */ - + /* Update the noise estimate for the frequencies where it can be */ for (i=0;inoise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); - + /* A posteriori SNR = ps/noise - 1*/ st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); - + /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); - + /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); @@ -819,13 +819,13 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) for (i=N;izeta[i])); Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); - + effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); - + compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); - - /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) - Technically this is actually wrong because the EM gaim assumes a slightly different probability + + /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) + Technically this is actually wrong because the EM gaim assumes a slightly different probability distribution */ for (i=N;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); @@ -867,12 +867,12 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) /* Convert the EM gains and speech prob to linear frequency */ filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); filterbank_compute_psd16(st->bank,st->gain+N, st->gain); - + /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ if (1) { filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); - + /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ for (i=0;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); @@ -893,22 +893,22 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); /* Interpolated speech probability of presence */ p = st->gain2[i]; - + /* Constrain the gain to be close to the Bark scale gain */ if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) g = MULT16_16(3,st->gain[i]); st->gain[i] = g; - + /* Save old power spectrum */ st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); - + /* Apply gain floor */ if (st->gain[i] < st->gain_floor[i]) st->gain[i] = st->gain_floor[i]; /* Exponential decay model for reverberation (unused) */ /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ - + /* Take into account speech probability of presence (loudness domain MMSE estimator) */ /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); @@ -922,20 +922,20 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) { spx_word16_t tmp; spx_word16_t p = st->gain2[i]; - st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); + st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); st->gain2[i]=SQR16_Q15(tmp); } filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); } - + /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ if (!st->denoise_enabled) { for (i=0;igain2[i]=Q15_ONE; } - + /* Apply computed gain */ for (i=1;ift[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); - + /*FIXME: This *will* not work for fixed-point */ #ifndef FIXED_POINT if (st->agc_enabled) @@ -973,17 +973,17 @@ EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) } } #endif - + /* Synthesis window (for WOLA) */ for (i=0;i<2*N;i++) st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); /* Perform overlap and add */ for (i=0;ioutbuf[i] + st->frame[i]; + x[i] = WORD2INT(ADD32(EXTEND32(st->outbuf[i]), EXTEND32(st->frame[i]))); for (i=0;iframe[N3+i]; - + /* Update outbuf */ for (i=0;ioutbuf[i] = st->frame[st->frame_size+i]; @@ -1016,11 +1016,11 @@ EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16 M = st->nbands; st->min_count++; - + preprocess_analysis(st, x); update_noise_prob(st); - + for (i=1;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) @@ -1099,7 +1099,7 @@ EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void * case SPEEX_PREPROCESS_GET_VAD: (*(spx_int32_t*)ptr) = st->vad_enabled; break; - + case SPEEX_PREPROCESS_SET_DEREVERB: st->dereverb_enabled = (*(spx_int32_t*)ptr); for (i=0;ips_size;i++) @@ -1117,7 +1117,7 @@ EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void * /* FIXME: Re-enable when de-reverberation is actually enabled again */ /*(*(float*)ptr) = st->reverb_level;*/ break; - + case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: /* FIXME: Re-enable when de-reverberation is actually enabled again */ /*st->reverb_decay = (*(float*)ptr);*/ diff --git a/vendor/libspeex/libspeexdsp/pseudofloat.h b/vendor/libspeex/libspeexdsp/pseudofloat.h index fa841a0101..ed5ab14b05 100644 --- a/vendor/libspeex/libspeexdsp/pseudofloat.h +++ b/vendor/libspeex/libspeexdsp/pseudofloat.h @@ -3,7 +3,7 @@ @file pseudofloat.h @brief Pseudo-floating point * This header file provides a lightweight floating point type for - * use on fixed-point platforms when a large dynamic range is + * use on fixed-point platforms when a large dynamic range is * required. The new type is not compatible with the 32-bit IEEE format, * it is not even remotely as accurate as 32-bit floats, and is not * even guaranteed to produce even remotely correct results for code @@ -16,18 +16,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -84,7 +84,7 @@ static inline spx_float_t PSEUDOFLOAT(spx_int32_t x) r.e = e; return r; } - else + else { spx_float_t r; r.m = x; @@ -101,12 +101,12 @@ static inline spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b) return b; else if (b.m==0) return a; - if ((a).e > (b).e) + if ((a).e > (b).e) { r.m = ((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1)); r.e = (a).e+1; } - else + else { r.m = ((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1)); r.e = (b).e+1; @@ -141,7 +141,7 @@ static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b) r.m = ((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1)); r.e = (a).e+1; } - else + else { r.m = ((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1); r.e = (b).e+1; @@ -169,10 +169,10 @@ static inline int FLOAT_LT(spx_float_t a, spx_float_t b) if (a.m==0) return b.m>0; else if (b.m==0) - return a.m<0; + return a.m<0; if ((a).e > (b).e) return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1)); - else + else return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1)); } @@ -202,7 +202,7 @@ static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b) } } /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/ - return r; + return r; } static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b) @@ -210,7 +210,7 @@ static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b) spx_float_t r; r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15); r.e = (a).e+(b).e+15; - return r; + return r; } diff --git a/vendor/libspeex/libspeexdsp/resample.c b/vendor/libspeex/libspeexdsp/resample.c index edbd65b5d4..2783f55f0c 100644 --- a/vendor/libspeex/libspeexdsp/resample.c +++ b/vendor/libspeex/libspeexdsp/resample.c @@ -1,6 +1,6 @@ /* Copyright (C) 2007-2008 Jean-Marc Valin Copyright (C) 2008 Thorvald Natvig - + File: resample.c Arbitrary resampling code @@ -38,22 +38,22 @@ - Low memory requirement - Good *perceptual* quality (and not best SNR) - Warning: This resampler is relatively new. Although I think I got rid of + Warning: This resampler is relatively new. Although I think I got rid of all the major bugs and I don't expect the API to change anymore, there may be something I've missed. So use with caution. This algorithm is based on this original resampling algorithm: Smith, Julius O. Digital Audio Resampling Home Page - Center for Computer Research in Music and Acoustics (CCRMA), + Center for Computer Research in Music and Acoustics (CCRMA), Stanford University, 2007. - Web published at http://www-ccrma.stanford.edu/~jos/resample/. + Web published at https://ccrma.stanford.edu/~jos/resample/. - There is one main difference, though. This resampler uses cubic + There is one main difference, though. This resampler uses cubic interpolation instead of linear interpolation in the above paper. This makes the table much smaller and makes it possible to compute that table - on a per-stream basis. In turn, being able to tweak the table for each - stream makes it possible to both reduce complexity on simple ratios - (e.g. 2/3), and get rid of the rounding operations in the inner loop. + on a per-stream basis. In turn, being able to tweak the table for each + stream makes it possible to both reduce complexity on simple ratios + (e.g. 2/3), and get rid of the rounding operations in the inner loop. The latter both reduces CPU time and makes the algorithm more SIMD-friendly. */ @@ -63,9 +63,12 @@ #ifdef OUTSIDE_SPEEX #include -static void *speex_alloc (int size) {return calloc(size,1);} -static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} -static void speex_free (void *ptr) {free(ptr);} +static void *speex_alloc(int size) {return calloc(size,1);} +static void *speex_realloc(void *ptr, int size) {return realloc(ptr, size);} +static void speex_free(void *ptr) {free(ptr);} +#ifndef EXPORT +#define EXPORT +#endif #include "speex_resampler.h" #include "arch.h" #else /* OUTSIDE_SPEEX */ @@ -75,7 +78,6 @@ static void speex_free (void *ptr) {free(ptr);} #include "os_support.h" #endif /* OUTSIDE_SPEEX */ -#include "stack_alloc.h" #include #include @@ -83,12 +85,6 @@ static void speex_free (void *ptr) {free(ptr);} #define M_PI 3.14159265358979323846 #endif -#ifdef FIXED_POINT -#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) -#else -#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) -#endif - #define IMAX(a,b) ((a) > (b) ? (a) : (b)) #define IMIN(a,b) ((a) < (b) ? (a) : (b)) @@ -96,15 +92,19 @@ static void speex_free (void *ptr) {free(ptr);} #define NULL 0 #endif -#ifdef _USE_SSE +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295U +#endif + +#ifdef USE_SSE #include "resample_sse.h" #endif -#ifdef _USE_NEON +#ifdef USE_NEON #include "resample_neon.h" #endif -/* Numer of elements to allocate on the stack */ +/* Number of elements to allocate on the stack */ #ifdef VAR_ARRAYS #define FIXED_STACK_ALLOC 8192 #else @@ -118,7 +118,7 @@ struct SpeexResamplerState_ { spx_uint32_t out_rate; spx_uint32_t num_rate; spx_uint32_t den_rate; - + int quality; spx_uint32_t nb_channels; spx_uint32_t filt_len; @@ -130,17 +130,17 @@ struct SpeexResamplerState_ { spx_uint32_t oversample; int initialised; int started; - + /* These are per-channel */ spx_int32_t *last_sample; spx_uint32_t *samp_frac_num; spx_uint32_t *magic_samples; - + spx_word16_t *mem; spx_word16_t *sinc_table; spx_uint32_t sinc_table_length; resampler_basic_func resampler_ptr; - + int in_stride; int out_stride; } ; @@ -182,7 +182,7 @@ static const double kaiser8_table[36] = { 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; - + static const double kaiser6_table[36] = { 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, @@ -195,17 +195,15 @@ struct FuncDef { const double *table; int oversample; }; - -static const struct FuncDef _KAISER12 = {kaiser12_table, 64}; -#define KAISER12 (&_KAISER12) -/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; -#define KAISER12 (&_KAISER12)*/ -static const struct FuncDef _KAISER10 = {kaiser10_table, 32}; -#define KAISER10 (&_KAISER10) -static const struct FuncDef _KAISER8 = {kaiser8_table, 32}; -#define KAISER8 (&_KAISER8) -static const struct FuncDef _KAISER6 = {kaiser6_table, 32}; -#define KAISER6 (&_KAISER6) + +static const struct FuncDef kaiser12_funcdef = {kaiser12_table, 64}; +#define KAISER12 (&kaiser12_funcdef) +static const struct FuncDef kaiser10_funcdef = {kaiser10_table, 32}; +#define KAISER10 (&kaiser10_funcdef) +static const struct FuncDef kaiser8_funcdef = {kaiser8_table, 32}; +#define KAISER8 (&kaiser8_funcdef) +static const struct FuncDef kaiser6_funcdef = {kaiser6_table, 32}; +#define KAISER6 (&kaiser6_funcdef) struct QualityMapping { int base_length; @@ -217,7 +215,7 @@ struct QualityMapping { /* This table maps conversion quality to internal parameters. There are two - reasons that explain why the up-sampling bandwidth is larger than the + reasons that explain why the up-sampling bandwidth is larger than the down-sampling bandwidth: 1) When up-sampling, we can assume that the spectrum is already attenuated close to the Nyquist rate (from an A/D or a previous resampling filter) @@ -243,7 +241,7 @@ static double compute_func(float x, const struct FuncDef *func) { float y, frac; double interp[4]; - int ind; + int ind; y = x*func->oversample; ind = (int)floor(y); frac = (y-ind); @@ -254,7 +252,7 @@ static double compute_func(float x, const struct FuncDef *func) interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); /* Just to make sure we don't have rounding problems */ interp[1] = 1.f-interp[3]-interp[2]-interp[0]; - + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; } @@ -475,13 +473,13 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3 } cubic_coef(frac, interp); - sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1)); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); sum = SATURATE32PSHR(sum, 15, 32767); #else cubic_coef(frac, interp); sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); #endif - + out[out_stride * out_sample++] = sum; last_sample += int_advance; samp_frac_num += frac_advance; @@ -543,7 +541,7 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3 cubic_coef(frac, interp); sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); #endif - + out[out_stride * out_sample++] = PSHR32(sum,15); last_sample += int_advance; samp_frac_num += frac_advance; @@ -574,6 +572,7 @@ static int resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_in const int frac_advance = st->frac_advance; const spx_uint32_t den_rate = st->den_rate; + (void)in; while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) { out[out_stride * out_sample++] = 0; @@ -591,6 +590,18 @@ static int resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_in return out_sample; } +static int multiply_frac(spx_uint32_t *result, spx_uint32_t value, spx_uint32_t num, spx_uint32_t den) +{ + spx_uint32_t major = value / den; + spx_uint32_t remain = value % den; + /* TODO: Could use 64 bits operation to check for overflow. But only guaranteed in C99+ */ + if (remain > UINT32_MAX / num || major > UINT32_MAX / num + || major * num > UINT32_MAX - remain * num / den) + return RESAMPLER_ERR_OVERFLOW; + *result = remain * num / den + major * num; + return RESAMPLER_ERR_SUCCESS; +} + static int update_filter(SpeexResamplerState *st) { spx_uint32_t old_length = st->filt_len; @@ -603,13 +614,13 @@ static int update_filter(SpeexResamplerState *st) st->frac_advance = st->num_rate%st->den_rate; st->oversample = quality_map[st->quality].oversample; st->filt_len = quality_map[st->quality].base_length; - + if (st->num_rate > st->den_rate) { /* down-sampling */ st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; - /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ - st->filt_len = st->filt_len*st->num_rate / st->den_rate; + if (multiply_frac(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS) + goto fail; /* Round up to make sure we have a multiple of 8 for SSE */ st->filt_len = ((st->filt_len-1)&(~0x7))+8; if (2*st->den_rate < st->num_rate) @@ -626,13 +637,13 @@ static int update_filter(SpeexResamplerState *st) /* up-sampling */ st->cutoff = quality_map[st->quality].upsample_bandwidth; } - - /* Choose the resampling type that requires the least amount of memory */ + #ifdef RESAMPLE_FULL_SINC_TABLE use_direct = 1; if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len) goto fail; #else + /* Choose the resampling type that requires the least amount of memory */ use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8 && INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len; #endif @@ -722,16 +733,18 @@ static int update_filter(SpeexResamplerState *st) { spx_uint32_t j; spx_uint32_t olen = old_length; + spx_uint32_t start = i*st->mem_alloc_size; + spx_uint32_t magic_samples = st->magic_samples[i]; /*if (st->magic_samples[i])*/ { /* Try and remove the magic samples as if nothing had happened */ - + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ - olen = old_length + 2*st->magic_samples[i]; - for (j=old_length-1+st->magic_samples[i];j--;) - st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; - for (j=0;jmagic_samples[i];j++) - st->mem[i*st->mem_alloc_size+j] = 0; + olen = old_length + 2*magic_samples; + for (j=old_length-1+magic_samples;j--;) + st->mem[start+j+magic_samples] = st->mem[i*old_alloc_size+j]; + for (j=0;jmem[start+j] = 0; st->magic_samples[i] = 0; } if (st->filt_len > olen) @@ -739,17 +752,18 @@ static int update_filter(SpeexResamplerState *st) /* If the new filter length is still bigger than the "augmented" length */ /* Copy data going backward */ for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; + st->mem[start+(st->filt_len-2-j)] = st->mem[start+(olen-2-j)]; /* Then put zeros for lack of anything better */ for (;jfilt_len-1;j++) - st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + st->mem[start+(st->filt_len-2-j)] = 0; /* Adjust last_sample */ st->last_sample[i] += (st->filt_len - olen)/2; } else { /* Put back some of the magic! */ - st->magic_samples[i] = (olen - st->filt_len)/2; - for (j=0;jfilt_len-1+st->magic_samples[i];j++) - st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + magic_samples = (olen - st->filt_len)/2; + for (j=0;jfilt_len-1+magic_samples;j++) + st->mem[start+j] = st->mem[start+j+magic_samples]; + st->magic_samples[i] = magic_samples; } } } else if (st->filt_len < old_length) @@ -787,17 +801,22 @@ EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_u EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) { - spx_uint32_t i; SpeexResamplerState *st; int filter_err; - if (quality > 10 || quality < 0) + if (nb_channels == 0 || ratio_num == 0 || ratio_den == 0 || quality > 10 || quality < 0) { if (err) *err = RESAMPLER_ERR_INVALID_ARG; return NULL; } st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + if (!st) + { + if (err) + *err = RESAMPLER_ERR_ALLOC_FAILED; + return NULL; + } st->initialised = 0; st->started = 0; st->in_rate = 0; @@ -810,24 +829,21 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, st->filt_len = 0; st->mem = 0; st->resampler_ptr = 0; - + st->cutoff = 1.f; st->nb_channels = nb_channels; st->in_stride = 1; st->out_stride = 1; - + st->buffer_size = 160; - + /* Per channel data */ - st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t)); - st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)); - st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)); - for (i=0;ilast_sample[i] = 0; - st->magic_samples[i] = 0; - st->samp_frac_num[i] = 0; - } + if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t)))) + goto fail; + if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) + goto fail; + if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) + goto fail; speex_resampler_set_quality(st, quality); speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); @@ -844,6 +860,12 @@ EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, *err = filter_err; return st; + +fail: + if (err) + *err = RESAMPLER_ERR_ALLOC_FAILED; + speex_resampler_destroy(st); + return NULL; } EXPORT void speex_resampler_destroy(SpeexResamplerState *st) @@ -863,17 +885,17 @@ static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t int out_sample = 0; spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; spx_uint32_t ilen; - + st->started = 1; - + /* Call the right resampler through the function ptr */ out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); - + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) *in_len = st->last_sample[channel_index]; *out_len = out_sample; st->last_sample[channel_index] -= *in_len; - + ilen = *in_len; for(j=0;jmagic_samples[channel_index]; spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; const int N = st->filt_len; - + speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); st->magic_samples[channel_index] -= tmp_in_len; - + /* If we couldn't process all "magic" input samples, save the rest for next time */ if (st->magic_samples[channel_index]) { @@ -916,13 +938,13 @@ EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t c const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; const int istride = st->in_stride; - if (st->magic_samples[channel_index]) + if (st->magic_samples[channel_index]) olen -= speex_resampler_magic(st, channel_index, &out, olen); if (! st->magic_samples[channel_index]) { while (ilen && olen) { spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; spx_uint32_t ochunk = olen; - + if (in) { for(j=0;jmem_alloc_size - (st->filt_len - 1); #ifdef VAR_ARRAYS const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; - VARDECL(spx_word16_t *ystack); - ALLOC(ystack, ylen, spx_word16_t); + spx_word16_t ystack[ylen]; #else const unsigned int ylen = FIXED_STACK_ALLOC; spx_word16_t ystack[FIXED_STACK_ALLOC]; #endif st->out_stride = 1; - + while (ilen && olen) { spx_word16_t *y = ystack; spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; @@ -1003,7 +1024,7 @@ EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t cha #else out[j*ostride_save] = WORD2INT(ystack[j]); #endif - + ilen -= ichunk; olen -= ochunk; out += (ochunk+omagic) * ostride_save; @@ -1039,7 +1060,7 @@ EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, co st->out_stride = ostride_save; return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; } - + EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) { spx_uint32_t i; @@ -1074,40 +1095,53 @@ EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_r *out_rate = st->out_rate; } +static inline spx_uint32_t compute_gcd(spx_uint32_t a, spx_uint32_t b) +{ + while (b != 0) + { + spx_uint32_t temp = a; + + a = b; + b = temp % b; + } + return a; +} + EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) { spx_uint32_t fact; spx_uint32_t old_den; spx_uint32_t i; + + if (ratio_num == 0 || ratio_den == 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) return RESAMPLER_ERR_SUCCESS; - + old_den = st->den_rate; st->in_rate = in_rate; st->out_rate = out_rate; st->num_rate = ratio_num; st->den_rate = ratio_den; - /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ - for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) - { - while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) - { - st->num_rate /= fact; - st->den_rate /= fact; - } - } - + + fact = compute_gcd(st->num_rate, st->den_rate); + + st->num_rate /= fact; + st->den_rate /= fact; + if (old_den > 0) { for (i=0;inb_channels;i++) { - st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; + if (multiply_frac(&st->samp_frac_num[i],st->samp_frac_num[i],st->den_rate,old_den) != RESAMPLER_ERR_SUCCESS) + return RESAMPLER_ERR_OVERFLOW; /* Safety net */ if (st->samp_frac_num[i] >= st->den_rate) st->samp_frac_num[i] = st->den_rate-1; } } - + if (st->initialised) return update_filter(st); return RESAMPLER_ERR_SUCCESS; diff --git a/vendor/libspeex/libspeexdsp/resample_neon.h b/vendor/libspeex/libspeexdsp/resample_neon.h index 0acbd27b9a..85a51fe1c3 100644 --- a/vendor/libspeex/libspeexdsp/resample_neon.h +++ b/vendor/libspeex/libspeexdsp/resample_neon.h @@ -36,14 +36,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #ifdef FIXED_POINT -#ifdef __thumb2__ +#if defined(__aarch64__) +static inline int32_t saturate_32bit_to_16bit(int32_t a) { + int32_t ret; + asm ("fmov s0, %w[a]\n" + "sqxtn h0, s0\n" + "sxtl v0.4s, v0.4h\n" + "fmov %w[ret], s0\n" + : [ret] "=r" (ret) + : [a] "r" (a) + : "v0" ); + return ret; +} +#elif defined(__thumb2__) static inline int32_t saturate_32bit_to_16bit(int32_t a) { int32_t ret; asm ("ssat %[ret], #16, %[a]" - : [ret] "=&r" (ret) + : [ret] "=r" (ret) : [a] "r" (a) : ); return ret; @@ -54,7 +66,7 @@ static inline int32_t saturate_32bit_to_16bit(int32_t a) { asm ("vmov.s32 d0[0], %[a]\n" "vqmovn.s32 d0, q0\n" "vmov.s16 %[ret], d0[0]\n" - : [ret] "=&r" (ret) + : [ret] "=r" (ret) : [a] "r" (a) : "q0"); return ret; @@ -64,7 +76,63 @@ static inline int32_t saturate_32bit_to_16bit(int32_t a) { #define WORD2INT(x) (saturate_32bit_to_16bit(x)) #define OVERRIDE_INNER_PRODUCT_SINGLE -/* Only works when len % 4 == 0 */ +/* Only works when len % 4 == 0 and len >= 4 */ +#if defined(__aarch64__) +static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, unsigned int len) +{ + int32_t ret; + uint32_t remainder = len % 16; + len = len - remainder; + + asm volatile (" cmp %w[len], #0\n" + " b.ne 1f\n" + " ld1 {v16.4h}, [%[b]], #8\n" + " ld1 {v20.4h}, [%[a]], #8\n" + " subs %w[remainder], %w[remainder], #4\n" + " smull v0.4s, v16.4h, v20.4h\n" + " b.ne 4f\n" + " b 5f\n" + "1:" + " ld1 {v16.4h, v17.4h, v18.4h, v19.4h}, [%[b]], #32\n" + " ld1 {v20.4h, v21.4h, v22.4h, v23.4h}, [%[a]], #32\n" + " subs %w[len], %w[len], #16\n" + " smull v0.4s, v16.4h, v20.4h\n" + " smlal v0.4s, v17.4h, v21.4h\n" + " smlal v0.4s, v18.4h, v22.4h\n" + " smlal v0.4s, v19.4h, v23.4h\n" + " b.eq 3f\n" + "2:" + " ld1 {v16.4h, v17.4h, v18.4h, v19.4h}, [%[b]], #32\n" + " ld1 {v20.4h, v21.4h, v22.4h, v23.4h}, [%[a]], #32\n" + " subs %w[len], %w[len], #16\n" + " smlal v0.4s, v16.4h, v20.4h\n" + " smlal v0.4s, v17.4h, v21.4h\n" + " smlal v0.4s, v18.4h, v22.4h\n" + " smlal v0.4s, v19.4h, v23.4h\n" + " b.ne 2b\n" + "3:" + " cmp %w[remainder], #0\n" + " b.eq 5f\n" + "4:" + " ld1 {v18.4h}, [%[b]], #8\n" + " ld1 {v22.4h}, [%[a]], #8\n" + " subs %w[remainder], %w[remainder], #4\n" + " smlal v0.4s, v18.4h, v22.4h\n" + " b.ne 4b\n" + "5:" + " saddlv d0, v0.4s\n" + " sqxtn s0, d0\n" + " sqrshrn h0, s0, #15\n" + " sxtl v0.4s, v0.4h\n" + " fmov %w[ret], s0\n" + : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), + [len] "+r" (len), [remainder] "+r" (remainder) + : + : "cc", "v0", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); + return ret; +} +#else static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, unsigned int len) { int32_t ret; @@ -112,33 +180,104 @@ static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, u " vqmovn.s64 d0, q0\n" " vqrshrn.s32 d0, q0, #15\n" " vmov.s16 %[ret], d0[0]\n" - : [ret] "=&r" (ret), [a] "+r" (a), [b] "+r" (b), + : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), [len] "+r" (len), [remainder] "+r" (remainder) : : "cc", "q0", - "d16", "d17", "d18", "d19", - "d20", "d21", "d22", "d23"); + "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); return ret; } -#elif defined(FLOATING_POINT) +#endif // !defined(__aarch64__) +#elif defined(FLOATING_POINT) +#if defined(__aarch64__) +static inline int32_t saturate_float_to_16bit(float a) { + int32_t ret; + asm ("fcvtas s1, %s[a]\n" + "sqxtn h1, s1\n" + "sxtl v1.4s, v1.4h\n" + "fmov %w[ret], s1\n" + : [ret] "=r" (ret) + : [a] "w" (a) + : "v1"); + return ret; +} +#else static inline int32_t saturate_float_to_16bit(float a) { int32_t ret; asm ("vmov.f32 d0[0], %[a]\n" "vcvt.s32.f32 d0, d0, #15\n" "vqrshrn.s32 d0, q0, #15\n" "vmov.s16 %[ret], d0[0]\n" - : [ret] "=&r" (ret) + : [ret] "=r" (ret) : [a] "r" (a) : "q0"); return ret; } +#endif + #undef WORD2INT #define WORD2INT(x) (saturate_float_to_16bit(x)) #define OVERRIDE_INNER_PRODUCT_SINGLE -/* Only works when len % 4 == 0 */ +/* Only works when len % 4 == 0 and len >= 4 */ +#if defined(__aarch64__) +static inline float inner_product_single(const float *a, const float *b, unsigned int len) +{ + float ret; + uint32_t remainder = len % 16; + len = len - remainder; + + asm volatile (" cmp %w[len], #0\n" + " b.ne 1f\n" + " ld1 {v16.4s}, [%[b]], #16\n" + " ld1 {v20.4s}, [%[a]], #16\n" + " subs %w[remainder], %w[remainder], #4\n" + " fmul v1.4s, v16.4s, v20.4s\n" + " b.ne 4f\n" + " b 5f\n" + "1:" + " ld1 {v16.4s, v17.4s, v18.4s, v19.4s}, [%[b]], #64\n" + " ld1 {v20.4s, v21.4s, v22.4s, v23.4s}, [%[a]], #64\n" + " subs %w[len], %w[len], #16\n" + " fmul v1.4s, v16.4s, v20.4s\n" + " fmul v2.4s, v17.4s, v21.4s\n" + " fmul v3.4s, v18.4s, v22.4s\n" + " fmul v4.4s, v19.4s, v23.4s\n" + " b.eq 3f\n" + "2:" + " ld1 {v16.4s, v17.4s, v18.4s, v19.4s}, [%[b]], #64\n" + " ld1 {v20.4s, v21.4s, v22.4s, v23.4s}, [%[a]], #64\n" + " subs %w[len], %w[len], #16\n" + " fmla v1.4s, v16.4s, v20.4s\n" + " fmla v2.4s, v17.4s, v21.4s\n" + " fmla v3.4s, v18.4s, v22.4s\n" + " fmla v4.4s, v19.4s, v23.4s\n" + " b.ne 2b\n" + "3:" + " fadd v16.4s, v1.4s, v2.4s\n" + " fadd v17.4s, v3.4s, v4.4s\n" + " cmp %w[remainder], #0\n" + " fadd v1.4s, v16.4s, v17.4s\n" + " b.eq 5f\n" + "4:" + " ld1 {v18.4s}, [%[b]], #16\n" + " ld1 {v22.4s}, [%[a]], #16\n" + " subs %w[remainder], %w[remainder], #4\n" + " fmla v1.4s, v18.4s, v22.4s\n" + " b.ne 4b\n" + "5:" + " faddp v1.4s, v1.4s, v1.4s\n" + " faddp %[ret].4s, v1.4s, v1.4s\n" + : [ret] "=w" (ret), [a] "+r" (a), [b] "+r" (b), + [len] "+r" (len), [remainder] "+r" (remainder) + : + : "cc", "v1", "v2", "v3", "v4", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); + return ret; +} +#else static inline float inner_product_single(const float *a, const float *b, unsigned int len) { float ret; @@ -191,11 +330,12 @@ static inline float inner_product_single(const float *a, const float *b, unsigne " vadd.f32 d0, d0, d1\n" " vpadd.f32 d0, d0, d0\n" " vmov.f32 %[ret], d0[0]\n" - : [ret] "=&r" (ret), [a] "+r" (a), [b] "+r" (b), + : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), [len] "+l" (len), [remainder] "+l" (remainder) : - : "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", - "q9", "q10", "q11"); + : "cc", "q0", "q1", "q2", "q3", + "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11"); return ret; } +#endif // defined(__aarch64__) #endif diff --git a/vendor/libspeex/libspeexdsp/resample_sse.h b/vendor/libspeex/libspeexdsp/resample_sse.h index 64be8a1616..00dc29465b 100644 --- a/vendor/libspeex/libspeexdsp/resample_sse.h +++ b/vendor/libspeex/libspeexdsp/resample_sse.h @@ -9,18 +9,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -71,7 +71,7 @@ static inline float interpolate_product_single(const float *a, const float *b, u return ret; } -#ifdef _USE_SSE2 +#ifdef USE_SSE2 #include #define OVERRIDE_INNER_PRODUCT_DOUBLE diff --git a/vendor/libspeex/libspeexdsp/scal.c b/vendor/libspeex/libspeexdsp/scal.c index d2ea59c758..807cb51238 100644 --- a/vendor/libspeex/libspeexdsp/scal.c +++ b/vendor/libspeex/libspeexdsp/scal.c @@ -33,8 +33,8 @@ /* The algorithm implemented here is described in: -* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For - Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on +* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For + Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on Hands­free Speech Communication and Microphone Arrays (HSCMA), 2008. http://people.xiph.org/~jm/papers/valin_hscma2008.pdf @@ -71,7 +71,7 @@ struct SpeexDecorrState_ { float *vorbis_win; int seed; float *y; - + /* Per-channel stuff */ float *buff; float (*ring)[ALLPASS_ORDER]; @@ -102,13 +102,13 @@ EXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame st->order = speex_alloc(channels*sizeof(int)); st->alpha = speex_alloc(channels*sizeof(float)); st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float)); - + /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/ st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float)); for (i=0;i<2*frame_size;i++) st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) ); st->seed = rand(); - + for (ch=0;ch100) strength = 100; - + amount = .01*strength; for (ch=0;chchannels;ch++) { @@ -156,7 +156,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i float beta, beta2; float *x; float max_alpha = 0; - + float *buff; float *ring; int ringID; @@ -168,7 +168,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i ringID = st->ringID[ch]; order = st->order[ch]; alpha = st->alpha[ch]; - + for (i=0;iframe_size;i++) buff[i] = buff[i+st->frame_size]; for (i=0;iframe_size;i++) @@ -182,12 +182,12 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i beta = 1-0.63246*amount; if (beta<0) beta = 0; - + beta2 = beta; for (i=0;iframe_size;i++) { - st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order] - + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i] + st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i] - alpha*(ring[ringID] - beta*ring[ringID+1>=order?0:ringID+1]); ring[ringID++]=st->y[i]; @@ -204,7 +204,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i max_alpha = pow(.96+.04*(amount-1),order); if (max_alpha > .98/(1.+beta2)) max_alpha = .98/(1.+beta2); - + alpha = alpha + .4*uni_rand(&st->seed); if (alpha > max_alpha) alpha = max_alpha; @@ -215,8 +215,8 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i ringID = 0; for (i=0;iframe_size;i++) { - float tmp = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order] - + x[i-ALLPASS_ORDER]*st->vorbis_win[i] + float tmp = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order] + + x[i-ALLPASS_ORDER]*st->vorbis_win[i] - alpha*(ring[ringID] - beta*ring[ringID+1>=order?0:ringID+1]); ring[ringID++]=tmp; @@ -225,7 +225,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i ringID=0; st->y[i] += tmp; } - + #ifdef VORBIS_PSYCHO float frame[N]; float scale = 1./N; @@ -252,7 +252,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i for (i=0;i<2*st->frame_size;i++) frame[i] *= st->vorbis_win[i]; #endif - + for (i=0;iframe_size;i++) { #ifdef VORBIS_PSYCHO @@ -267,7 +267,7 @@ EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_i tmp = -32767; out[i*st->channels+ch] = tmp; } - + st->ringID[ch] = ringID; st->order[ch] = order; st->alpha[ch] = alpha; diff --git a/vendor/libspeex/libspeexdsp/smallft.c b/vendor/libspeex/libspeexdsp/smallft.c index 5c26d016fe..82c3b0a4a1 100644 --- a/vendor/libspeex/libspeexdsp/smallft.c +++ b/vendor/libspeex/libspeexdsp/smallft.c @@ -127,7 +127,7 @@ static void dradf2(int ido,int l1,float *cc,float *ch,float *wa1){ t1+=ido; t2+=ido; } - + if(ido<2)return; if(ido==2)goto L105; @@ -174,7 +174,7 @@ static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1, int i,k,t0,t1,t2,t3,t4,t5,t6; float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4; t0=l1*ido; - + t1=t0; t4=t1<<1; t2=t1+(t1<<1); @@ -246,7 +246,7 @@ static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1, if(ido&1)return; L105: - + t2=(t1=t0+ido-1)+(t0<<1); t3=ido<<2; t4=ido; @@ -280,7 +280,7 @@ static void dradfg(int ido,int ip,int l1,int idl1,float *cc,float *c1, int nbd; float dcp,arg,dsp,ar1h,ar2h; int idp2,ipp2; - + arg=tpi/(float)ip; dcp=cos(arg); dsp=sin(arg); @@ -638,7 +638,7 @@ static void dradb2(int ido,int l1,float *cc,float *ch,float *wa1){ float ti2,tr2; t0=l1*ido; - + t1=0; t2=0; t3=(ido<<1)-1; @@ -754,7 +754,7 @@ static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1, int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8; float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4; t0=l1*ido; - + t1=0; t2=ido<<2; t3=0; @@ -763,7 +763,7 @@ static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1, t4=t3+t6; t5=t1; tr3=cc[t4-1]+cc[t4-1]; - tr4=cc[t4]+cc[t4]; + tr4=cc[t4]+cc[t4]; tr1=cc[t3]-cc[(t4+=t6)-1]; tr2=cc[t3]+cc[t4-1]; ch[t5]=tr2+tr3; @@ -858,7 +858,7 @@ static void dradbg(int ido,int ip,int l1,int idl1,float *cc,float *c1, ipp2=ip; ipph=(ip+1)>>1; if(ido # else # ifdef HAVE_ALLOCA_H @@ -101,7 +101,7 @@ #endif #if defined(VAR_ARRAYS) -#define VARDECL(var) +#define VARDECL(var) #define ALLOC(var, size, type) type var[size] #elif defined(USE_ALLOCA) #define VARDECL(var) var diff --git a/vendor/libspeex/libspeexdsp/testdenoise.c b/vendor/libspeex/libspeexdsp/testdenoise.c new file mode 100644 index 0000000000..adebe941e4 --- /dev/null +++ b/vendor/libspeex/libspeexdsp/testdenoise.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_preprocess.h" +#include + +#define NN 160 + +int main() +{ + short in[NN]; + int i; + SpeexPreprocessState *st; + int count=0; + float f; + + st = speex_preprocess_state_init(NN, 8000); + i=1; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i); + i=0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i); + i=8000; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); + i=0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i); + f=.0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f=.0; + speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); + while (1) + { + int vad; + fread(in, sizeof(short), NN, stdin); + if (feof(stdin)) + break; + vad = speex_preprocess_run(st, in); + /*fprintf (stderr, "%d\n", vad);*/ + fwrite(in, sizeof(short), NN, stdout); + count++; + } + speex_preprocess_state_destroy(st); + return 0; +} diff --git a/vendor/libspeex/libspeexdsp/testecho.c b/vendor/libspeex/libspeexdsp/testecho.c new file mode 100644 index 0000000000..1624dc2a31 --- /dev/null +++ b/vendor/libspeex/libspeexdsp/testecho.c @@ -0,0 +1,53 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_echo.h" +#include "speex/speex_preprocess.h" +#include +#include +#include +#include +#include + + +#define NN 128 +#define TAIL 1024 + +int main(int argc, char **argv) +{ + FILE *echo_fd, *ref_fd, *e_fd; + short echo_buf[NN], ref_buf[NN], e_buf[NN]; + SpeexEchoState *st; + SpeexPreprocessState *den; + int sampleRate = 8000; + + if (argc != 4) + { + fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n"); + exit(1); + } + echo_fd = fopen(argv[2], "rb"); + ref_fd = fopen(argv[1], "rb"); + e_fd = fopen(argv[3], "wb"); + + st = speex_echo_state_init(NN, TAIL); + den = speex_preprocess_state_init(NN, sampleRate); + speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate); + speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st); + + while (!feof(ref_fd) && !feof(echo_fd)) + { + fread(ref_buf, sizeof(short), NN, ref_fd); + fread(echo_buf, sizeof(short), NN, echo_fd); + speex_echo_cancellation(st, ref_buf, echo_buf, e_buf); + speex_preprocess_run(den, e_buf); + fwrite(e_buf, sizeof(short), NN, e_fd); + } + speex_echo_state_destroy(st); + speex_preprocess_state_destroy(den); + fclose(e_fd); + fclose(echo_fd); + fclose(ref_fd); + return 0; +} diff --git a/vendor/libspeex/libspeexdsp/testjitter.c b/vendor/libspeex/libspeexdsp/testjitter.c new file mode 100644 index 0000000000..399dfe956c --- /dev/null +++ b/vendor/libspeex/libspeexdsp/testjitter.c @@ -0,0 +1,75 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_jitter.h" +#include + +union jbpdata { + unsigned int idx; + unsigned char data[4]; +}; + +void synthIn(JitterBufferPacket *in, int idx, int span) { + union jbpdata d; + d.idx = idx; + + in->data = d.data; + in->len = sizeof(d); + in->timestamp = idx * 10; + in->span = span * 10; + in->sequence = idx; + in->user_data = 0; +} + +void jitterFill(JitterBuffer *jb) { + char buffer[65536]; + JitterBufferPacket in, out; + int i; + + out.data = buffer; + + jitter_buffer_reset(jb); + + for(i=0;i<100;++i) { + synthIn(&in, i, 1); + jitter_buffer_put(jb, &in); + + out.len = 65536; + if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { + printf("Fill test failed iteration %d\n", i); + } + if (out.timestamp != i * 10) { + printf("Fill test expected %d got %d\n", i*10, out.timestamp); + } + jitter_buffer_tick(jb); + } +} + +int main() +{ + char buffer[65536]; + JitterBufferPacket in, out; + int i; + + JitterBuffer *jb = jitter_buffer_init(10); + + out.data = buffer; + + /* Frozen sender case */ + jitterFill(jb); + for(i=0;i<100;++i) { + out.len = 65536; + jitter_buffer_get(jb, &out, 10, NULL); + jitter_buffer_tick(jb); + } + synthIn(&in, 100, 1); + jitter_buffer_put(jb, &in); + out.len = 65536; + if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { + printf("Failed frozen sender resynchronize\n"); + } else { + printf("Frozen sender: Jitter %d\n", out.timestamp - 100*10); + } + return 0; +} diff --git a/vendor/libspeex/libspeexdsp/testresample.c b/vendor/libspeex/libspeexdsp/testresample.c new file mode 100644 index 0000000000..7ed866756f --- /dev/null +++ b/vendor/libspeex/libspeexdsp/testresample.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: testresample.c + Testing the resampling code + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "speex/speex_resampler.h" +#include +#include +#include + +#define NN 256 + +int main() +{ + spx_uint32_t i; + short *in; + short *out; + float *fin, *fout; + int count = 0; + SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10, NULL); + speex_resampler_set_rate(st, 96000, 44100); + speex_resampler_skip_zeros(st); + + in = malloc(NN*sizeof(short)); + out = malloc(2*NN*sizeof(short)); + fin = malloc(NN*sizeof(float)); + fout = malloc(2*NN*sizeof(float)); + while (1) + { + spx_uint32_t in_len; + spx_uint32_t out_len; + fread(in, sizeof(short), NN, stdin); + if (feof(stdin)) + break; + for (i=0;i +#include +#include + +#define PERIOD 32 +#define INBLOCK 1024 +#define RATE 48000 + +int main() +{ + spx_uint32_t i; + float *fin, *fout; + int rate = 1000, off = 0, avail = INBLOCK; + SpeexResamplerState *st = speex_resampler_init(1, RATE, RATE, 4, NULL); + speex_resampler_set_rate(st, RATE, rate); + speex_resampler_skip_zeros(st); + + fin = malloc(INBLOCK*2*sizeof(float)); + for (i=0; i ", rate, off, in_len, out_len); + + speex_resampler_process_float(st, 0, fin + off, &in_len, fout, &out_len); + + fprintf (stderr, "%d %d\n", in_len, out_len); + off += in_len; + avail = avail - in_len + INBLOCK; + + if (off >= INBLOCK) + off -= INBLOCK; + + fwrite(fout, sizeof(float), out_len, stdout); + + rate += 100; + if (rate > 128000) + break; + + speex_resampler_set_rate(st, RATE, rate); + } + speex_resampler_destroy(st); + free(fin); + free(fout); + return 0; +} + diff --git a/vendor/libspeex/libspeexdsp/vorbis_psy.h b/vendor/libspeex/libspeexdsp/vorbis_psy.h index 6871057753..19ea9c3cf2 100644 --- a/vendor/libspeex/libspeexdsp/vorbis_psy.h +++ b/vendor/libspeex/libspeexdsp/vorbis_psy.h @@ -4,18 +4,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -40,7 +40,7 @@ #define todB(x) ((x)>1e-13?log((x)*(x))*4.34294480f:-30) -#define fromdB(x) (exp((x)*.11512925f)) +#define fromdB(x) (exp((x)*.11512925f)) /* The bark scale equations are approximations, since the original table was somewhat hand rolled. The below are chosen to have the diff --git a/vendor/libspeex/speex/speex.h b/vendor/libspeex/speex/speex.h index 28c4b44df8..34919e2f00 100644 --- a/vendor/libspeex/speex/speex.h +++ b/vendor/libspeex/speex/speex.h @@ -412,7 +412,7 @@ extern const SpeexMode * const speex_mode_list[SPEEX_NB_MODES]; /** Obtain one of the modes available */ const SpeexMode * speex_lib_get_mode (int mode); -#ifndef WIN32 +#ifndef _WIN32 /* We actually override the function in the narrowband case so that we can avoid linking in the wideband stuff */ #define speex_lib_get_mode(mode) ((mode)==SPEEX_MODEID_NB ? &speex_nb_mode : speex_lib_get_mode (mode)) #endif diff --git a/vendor/libspeex/speex/speex_buffer.h b/vendor/libspeex/speex/speex_buffer.h index 5bd128ae7d..9e85cfcf0e 100644 --- a/vendor/libspeex/speex/speex_buffer.h +++ b/vendor/libspeex/speex/speex_buffer.h @@ -1,5 +1,5 @@ /* Copyright (C) 2007 Jean-Marc Valin - + File: speex_buffer.h This is a very simple ring buffer implementation. It is not thread-safe so you need to do your own locking. diff --git a/vendor/libspeex/speex/speex_config_types.h b/vendor/libspeex/speex/speex_config_types.h index f864522910..ca1f5a3c20 100644 --- a/vendor/libspeex/speex/speex_config_types.h +++ b/vendor/libspeex/speex/speex_config_types.h @@ -1,7 +1,7 @@ #ifndef __SPEEX_TYPES_H__ #define __SPEEX_TYPES_H__ -#include +#include typedef int16_t spx_int16_t; typedef uint16_t spx_uint16_t; diff --git a/vendor/libspeex/speex/speex_echo.h b/vendor/libspeex/speex/speex_echo.h index 6f14d0913f..4c1aa5a5f2 100644 --- a/vendor/libspeex/speex/speex_echo.h +++ b/vendor/libspeex/speex/speex_echo.h @@ -63,7 +63,7 @@ extern "C" { struct SpeexEchoState_; /** @class SpeexEchoState - * This holds the state of the echo canceller. You need one per channel. + * This holds the state of the echo canceller. You need one per channel. */ /** Internal echo canceller state. Should never be accessed directly. */ @@ -85,7 +85,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length); */ SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers); -/** Destroys an echo canceller state +/** Destroys an echo canceller state * @param st Echo canceller state */ void speex_echo_state_destroy(SpeexEchoState *st); @@ -117,7 +117,7 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t */ void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play); -/** Reset the echo canceller to its original state +/** Reset the echo canceller to its original state * @param st Echo canceller state */ void speex_echo_state_reset(SpeexEchoState *st); @@ -139,7 +139,7 @@ typedef struct SpeexDecorrState_ SpeexDecorrState; /** Create a state for the channel decorrelation algorithm - This is useful for multi-channel echo cancellation only + This is useful for multi-channel echo cancellation only * @param rate Sampling rate * @param channels Number of channels (it's a bit pointless if you don't have at least 2) * @param frame_size Size of the frame to process at ones (counting samples *per* channel) @@ -155,7 +155,7 @@ SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size); */ void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength); -/** Destroy a Decorrelation state +/** Destroy a Decorrelation state * @param st State to destroy */ void speex_decorrelate_destroy(SpeexDecorrState *st); diff --git a/vendor/libspeex/speex/speex_jitter.h b/vendor/libspeex/speex/speex_jitter.h index 66708da5c9..8fc8d7ec66 100644 --- a/vendor/libspeex/speex/speex_jitter.h +++ b/vendor/libspeex/speex/speex_jitter.h @@ -7,18 +7,18 @@ 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 the above copyright notice, 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 Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -89,7 +89,7 @@ struct _JitterBufferPacket { /** Included because of an early misspelling (will remove in next release) */ #define JITTER_BUFFER_GET_AVALIABLE_COUNT 3 -/** Assign a function to destroy unused packet. When setting that, the jitter +/** Assign a function to destroy unused packet. When setting that, the jitter buffer no longer copies packet data. */ #define JITTER_BUFFER_SET_DESTROY_CALLBACK 4 /** */ @@ -104,7 +104,7 @@ struct _JitterBufferPacket { #define JITTER_BUFFER_SET_CONCEALMENT_SIZE 8 #define JITTER_BUFFER_GET_CONCEALMENT_SIZE 9 -/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss +/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss should be half of that or less. */ #define JITTER_BUFFER_SET_MAX_LATE_RATE 10 #define JITTER_BUFFER_GET_MAX_LATE_RATE 11 @@ -114,59 +114,59 @@ struct _JitterBufferPacket { #define JITTER_BUFFER_GET_LATE_COST 13 -/** Initialises jitter buffer - * - * @param step_size Starting value for the size of concleanment packets and delay +/** Initialises jitter buffer + * + * @param step_size Starting value for the size of concleanment packets and delay adjustment steps. Can be changed at any time using JITTER_BUFFER_SET_DELAY_STEP and JITTER_BUFFER_GET_CONCEALMENT_SIZE. * @return Newly created jitter buffer state */ JitterBuffer *jitter_buffer_init(int step_size); -/** Restores jitter buffer to its original state - * +/** Restores jitter buffer to its original state + * * @param jitter Jitter buffer state */ void jitter_buffer_reset(JitterBuffer *jitter); -/** Destroys jitter buffer - * +/** Destroys jitter buffer + * * @param jitter Jitter buffer state */ void jitter_buffer_destroy(JitterBuffer *jitter); /** Put one packet into the jitter buffer - * + * * @param jitter Jitter buffer state * @param packet Incoming packet */ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet); /** Get one packet from the jitter buffer - * + * * @param jitter Jitter buffer state * @param packet Returned packet * @param desired_span Number of samples (or units) we wish to get from the buffer (no guarantee) - * @param current_timestamp Timestamp for the returned packet + * @param current_timestamp Timestamp for the returned packet */ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset); /** Used right after jitter_buffer_get() to obtain another packet that would have the same timestamp. * This is mainly useful for media where a single "frame" can be split into several packets. - * + * * @param jitter Jitter buffer state * @param packet Returned packet */ int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet); /** Get pointer timestamp of jitter buffer - * + * * @param jitter Jitter buffer state */ int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter); /** Advance by one tick - * + * * @param jitter Jitter buffer state */ void jitter_buffer_tick(JitterBuffer *jitter); @@ -178,7 +178,7 @@ void jitter_buffer_tick(JitterBuffer *jitter); void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem); /** Used like the ioctl function to control the jitter buffer parameters - * + * * @param jitter Jitter buffer state * @param request ioctl-type request (one of the JITTER_BUFFER_* macros) * @param ptr Data exchanged to-from function diff --git a/vendor/libspeex/speex/speex_preprocess.h b/vendor/libspeex/speex/speex_preprocess.h index b9555eb551..a2e1210d41 100644 --- a/vendor/libspeex/speex/speex_preprocess.h +++ b/vendor/libspeex/speex/speex_preprocess.h @@ -2,7 +2,7 @@ Written by Jean-Marc Valin */ /** * @file speex_preprocess.h - * @brief Speex preprocessor. The preprocess can do noise suppression, + * @brief Speex preprocessor. The preprocess can do noise suppression, * residual echo suppression (after using the echo canceller), automatic * gain control (AGC) and voice activity detection (VAD). */ @@ -37,7 +37,7 @@ #ifndef SPEEX_PREPROCESS_H #define SPEEX_PREPROCESS_H /** @defgroup SpeexPreprocessState SpeexPreprocessState: The Speex preprocessor - * This is the Speex preprocessor. The preprocess can do noise suppression, + * This is the Speex preprocessor. The preprocess can do noise suppression, * residual echo suppression (after using the echo canceller), automatic * gain control (AGC) and voice activity detection (VAD). * @{ @@ -48,7 +48,7 @@ #ifdef __cplusplus extern "C" { #endif - + /** State of the preprocessor (one per channel). Should never be accessed directly. */ struct SpeexPreprocessState_; @@ -64,12 +64,12 @@ typedef struct SpeexPreprocessState_ SpeexPreprocessState; */ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate); -/** Destroys a preprocessor state +/** Destroys a preprocessor state * @param st Preprocessor state to destroy */ void speex_preprocess_state_destroy(SpeexPreprocessState *st); -/** Preprocess a frame +/** Preprocess a frame * @param st Preprocessor state * @param x Audio sample vector (in and out). Must be same size as specified in speex_preprocess_state_init(). * @return Bool value for voice activity (1 for speech, 0 for noise/silence), ONLY if VAD turned on. @@ -85,7 +85,7 @@ int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo */ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x); -/** Used like the ioctl function to control the preprocessor parameters +/** Used like the ioctl function to control the preprocessor parameters * @param st Preprocessor state * @param request ioctl-type request (one of the SPEEX_PREPROCESS_* macros) * @param ptr Data exchanged to-from function diff --git a/vendor/libspeex/speex/speex_resampler.h b/vendor/libspeex/speex/speex_resampler.h index 50d777f5b4..901de37b3d 100644 --- a/vendor/libspeex/speex/speex_resampler.h +++ b/vendor/libspeex/speex/speex_resampler.h @@ -1,8 +1,8 @@ /* Copyright (C) 2007 Jean-Marc Valin - + File: speex_resampler.h Resampling code - + The design goals of this code are: - Very fast algorithm - Low memory requirement @@ -43,7 +43,7 @@ /********* WARNING: MENTAL SANITY ENDS HERE *************/ -/* If the resampler is defined outside of Speex, we change the symbol names so that +/* If the resampler is defined outside of Speex, we change the symbol names so that there won't be any clash if linking with Speex later on. */ /* #define RANDOM_PREFIX your software name here */ @@ -53,7 +53,7 @@ #define CAT_PREFIX2(a,b) a ## b #define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) - + #define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) #define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) #define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) @@ -81,7 +81,9 @@ #define spx_int32_t int #define spx_uint16_t unsigned short #define spx_uint32_t unsigned int - + +#define speex_assert(cond) + #else /* OUTSIDE_SPEEX */ #include "speexdsp_types.h" @@ -104,7 +106,8 @@ enum { RESAMPLER_ERR_BAD_STATE = 2, RESAMPLER_ERR_INVALID_ARG = 3, RESAMPLER_ERR_PTR_OVERLAP = 4, - + RESAMPLER_ERR_OVERFLOW = 5, + RESAMPLER_ERR_MAX_ERROR }; @@ -120,14 +123,14 @@ typedef struct SpeexResamplerState_ SpeexResamplerState; * @return Newly created resampler state * @retval NULL Error: not enough memory */ -SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, - spx_uint32_t in_rate, - spx_uint32_t out_rate, +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, int quality, int *err); -/** Create a new resampler with fractional input/output rates. The sampling - * rate ratio is an arbitrary rational number with both the numerator and +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and * denominator being 32-bit integers. * @param nb_channels Number of channels to be processed * @param ratio_num Numerator of the sampling rate ratio @@ -139,11 +142,11 @@ SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, * @return Newly created resampler state * @retval NULL Error: not enough memory */ -SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, - spx_uint32_t ratio_num, - spx_uint32_t ratio_den, - spx_uint32_t in_rate, - spx_uint32_t out_rate, +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, int quality, int *err); @@ -154,24 +157,24 @@ void speex_resampler_destroy(SpeexResamplerState *st); /** Resample a float array. The input and output buffers must *not* overlap. * @param st Resampler state - * @param channel_index Index of the channel to process for the multi-channel + * @param channel_index Index of the channel to process for the multi-channel * base (0 otherwise) * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the + * @param in_len Number of input samples in the input buffer. Returns the * number of samples processed * @param out Output buffer * @param out_len Size of the output buffer. Returns the number of samples written */ -int speex_resampler_process_float(SpeexResamplerState *st, - spx_uint32_t channel_index, - const float *in, - spx_uint32_t *in_len, - float *out, +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, spx_uint32_t *out_len); /** Resample an int array. The input and output buffers must *not* overlap. * @param st Resampler state - * @param channel_index Index of the channel to process for the multi-channel + * @param channel_index Index of the channel to process for the multi-channel * base (0 otherwise) * @param in Input buffer * @param in_len Number of input samples in the input buffer. Returns the number @@ -179,11 +182,11 @@ int speex_resampler_process_float(SpeexResamplerState *st, * @param out Output buffer * @param out_len Size of the output buffer. Returns the number of samples written */ -int speex_resampler_process_int(SpeexResamplerState *st, - spx_uint32_t channel_index, - const spx_int16_t *in, - spx_uint32_t *in_len, - spx_int16_t *out, +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, spx_uint32_t *out_len); /** Resample an interleaved float array. The input and output buffers must *not* overlap. @@ -195,10 +198,10 @@ int speex_resampler_process_int(SpeexResamplerState *st, * @param out_len Size of the output buffer. Returns the number of samples written. * This is all per-channel. */ -int speex_resampler_process_interleaved_float(SpeexResamplerState *st, - const float *in, - spx_uint32_t *in_len, - float *out, +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, spx_uint32_t *out_len); /** Resample an interleaved int array. The input and output buffers must *not* overlap. @@ -210,10 +213,10 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, * @param out_len Size of the output buffer. Returns the number of samples written. * This is all per-channel. */ -int speex_resampler_process_interleaved_int(SpeexResamplerState *st, - const spx_int16_t *in, - spx_uint32_t *in_len, - spx_int16_t *out, +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, spx_uint32_t *out_len); /** Set (change) the input/output sampling rates (integer value). @@ -221,8 +224,8 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, * @param in_rate Input sampling rate (integer number of Hz). * @param out_rate Output sampling rate (integer number of Hz). */ -int speex_resampler_set_rate(SpeexResamplerState *st, - spx_uint32_t in_rate, +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, spx_uint32_t out_rate); /** Get the current input/output sampling rates (integer value). @@ -230,11 +233,11 @@ int speex_resampler_set_rate(SpeexResamplerState *st, * @param in_rate Input sampling rate (integer number of Hz) copied. * @param out_rate Output sampling rate (integer number of Hz) copied. */ -void speex_resampler_get_rate(SpeexResamplerState *st, - spx_uint32_t *in_rate, +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, spx_uint32_t *out_rate); -/** Set (change) the input/output sampling rates and resampling ratio +/** Set (change) the input/output sampling rates and resampling ratio * (fractional values in Hz supported). * @param st Resampler state * @param ratio_num Numerator of the sampling rate ratio @@ -242,10 +245,10 @@ void speex_resampler_get_rate(SpeexResamplerState *st, * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). */ -int speex_resampler_set_rate_frac(SpeexResamplerState *st, - spx_uint32_t ratio_num, - spx_uint32_t ratio_den, - spx_uint32_t in_rate, +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, spx_uint32_t out_rate); /** Get the current resampling ratio. This will be reduced to the least @@ -254,52 +257,52 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, * @param ratio_num Numerator of the sampling rate ratio copied * @param ratio_den Denominator of the sampling rate ratio copied */ -void speex_resampler_get_ratio(SpeexResamplerState *st, - spx_uint32_t *ratio_num, +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, spx_uint32_t *ratio_den); /** Set (change) the conversion quality. * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor + * @param quality Resampling quality between 0 and 10, where 0 has poor * quality and 10 has very high quality. */ -int speex_resampler_set_quality(SpeexResamplerState *st, +int speex_resampler_set_quality(SpeexResamplerState *st, int quality); /** Get the conversion quality. * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor + * @param quality Resampling quality between 0 and 10, where 0 has poor * quality and 10 has very high quality. */ -void speex_resampler_get_quality(SpeexResamplerState *st, +void speex_resampler_get_quality(SpeexResamplerState *st, int *quality); /** Set (change) the input stride. * @param st Resampler state * @param stride Input stride */ -void speex_resampler_set_input_stride(SpeexResamplerState *st, +void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride); /** Get the input stride. * @param st Resampler state * @param stride Input stride copied */ -void speex_resampler_get_input_stride(SpeexResamplerState *st, +void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride); /** Set (change) the output stride. * @param st Resampler state * @param stride Output stride */ -void speex_resampler_set_output_stride(SpeexResamplerState *st, +void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride); /** Get the output stride. * @param st Resampler state copied * @param stride Output stride */ -void speex_resampler_get_output_stride(SpeexResamplerState *st, +void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride); /** Get the latency introduced by the resampler measured in input samples. @@ -312,8 +315,8 @@ int speex_resampler_get_input_latency(SpeexResamplerState *st); */ int speex_resampler_get_output_latency(SpeexResamplerState *st); -/** Make sure that the first samples to go out of the resamplers don't have - * leading zeros. This is only useful before starting to use a newly created +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created * resampler. It is recommended to use that when resampling an audio file, as * it will generate a file with the same length. For real-time processing, * it is probably easier not to use this call (so that the output duration diff --git a/vendor/libspeex/speex/speex_stereo.h b/vendor/libspeex/speex/speex_stereo.h index 5844f5a102..12af2bbf6e 100644 --- a/vendor/libspeex/speex/speex_stereo.h +++ b/vendor/libspeex/speex/speex_stereo.h @@ -61,7 +61,7 @@ typedef struct SpeexStereoState { #define SPEEX_STEREO_STATE_INIT {1,.5,1,1,0,0} /** Initialise/create a stereo stereo state */ -SpeexStereoState *speex_stereo_state_init(); +SpeexStereoState *speex_stereo_state_init(void); /** Reset/re-initialise an already allocated stereo state */ void speex_stereo_state_reset(SpeexStereoState *stereo); diff --git a/vendor/libspeex/speex/speexdsp_config_types.h b/vendor/libspeex/speex/speexdsp_config_types.h index f864522910..d77d0ca8f9 100644 --- a/vendor/libspeex/speex/speexdsp_config_types.h +++ b/vendor/libspeex/speex/speexdsp_config_types.h @@ -9,4 +9,3 @@ typedef int32_t spx_int32_t; typedef uint32_t spx_uint32_t; #endif - diff --git a/vendor/libspeex/speex/speexdsp_types.h b/vendor/libspeex/speex/speexdsp_types.h index 334d6745ac..4b4a76a474 100644 --- a/vendor/libspeex/speex/speexdsp_types.h +++ b/vendor/libspeex/speex/speexdsp_types.h @@ -22,7 +22,7 @@ #ifndef _SPEEX_TYPES_H #define _SPEEX_TYPES_H -#if defined(_WIN32) +#if defined(_WIN32) # if defined(__CYGWIN__) # include <_G_config.h> From 530212f34fc44e95599ca5e39e608583ecdbb5cc Mon Sep 17 00:00:00 2001 From: Merlin Date: Sat, 22 Jun 2024 02:37:15 +0200 Subject: [PATCH 19/23] Remove remaining code of the Easter egg command (PR #3503) --- Client/multiplayer_sa/CMultiplayerSA.cpp | 37 ------------------------ 1 file changed, 37 deletions(-) diff --git a/Client/multiplayer_sa/CMultiplayerSA.cpp b/Client/multiplayer_sa/CMultiplayerSA.cpp index d9881758ec..7dbb168fcb 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA.cpp @@ -310,7 +310,6 @@ bool bHideRadar; bool bHasProcessedScript; float fX, fY, fZ; DWORD RoadSignFixTemp; -DWORD dwEAEG = 0; bool m_bExplosionsDisabled; float fGlobalGravity = 0.008f; float fLocalPlayerGravity = 0.008f; @@ -3405,31 +3404,6 @@ static void RestoreAlphaValues() /** ** Vehicles **/ -static RpAtomic* CVehicle_EAEG(RpAtomic* pAtomic, void*) -{ - RwFrame* pFrame = ((RwFrame*)(((RwObject*)(pAtomic))->parent)); - if (pFrame) - { - switch (pFrame->szName[0]) - { - case '\0': - case 'h': - break; - default: - DWORD dwFunc = (DWORD)0x533290; - DWORD dwAtomic = (DWORD)pAtomic; - _asm - { - push 0 - push dwAtomic - call dwFunc - add esp, 0x8 - } - } - } - - return pAtomic; -} static void SetVehicleAlpha() { @@ -3438,15 +3412,6 @@ static void SetVehicleAlpha() if (ucAlpha < 255) GetAlphaAndSetNewValues(ucAlpha); - else if (dwEAEG && pInterface->m_pVehicle->GetModelIndex() == 0x20A) - { - bEntityHasAlpha = true; - uiAlphaIdx = 0; - SetEntityAlphaHooked(dwAlphaEntity, (DWORD)HOOK_GetAlphaValues, 0); - MemPutFast(0x5332D6, (DWORD)CVehicle_EAEG); - SetEntityAlphaHooked(dwAlphaEntity, (DWORD)HOOK_SetAlphaValues, 0); - MemPutFast(0x5332D6, 0x533290); - } else bEntityHasAlpha = false; } @@ -3958,8 +3923,6 @@ void CMultiplayerSA::SetLocalStatValue(unsigned short usStat, float fValue) localStatsData.StatTypesFloat[usStat] = fValue; else if (usStat >= STATS_OFFSET && usStat < MAX_INT_FLOAT_STATS) localStatsData.StatTypesInt[usStat - STATS_OFFSET] = (int)fValue; - else if (usStat == 0x2329) - dwEAEG = !dwEAEG; } float CMultiplayerSA::GetLocalStatValue(unsigned short usStat) From e89fa02c65efd90b09d61147d1edb0c8297ec6dc Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Sat, 22 Jun 2024 03:04:07 +0200 Subject: [PATCH 20/23] Cherry-pick https://github.com/xiph/speexdsp/pull/50/commits/1a5ca4e40787175bfcbf296c075f20215d858a35 to fix build error: C2065: 'M_PI': undeclared identifier` --- vendor/libspeex/libspeexdsp/testresample2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vendor/libspeex/libspeexdsp/testresample2.c b/vendor/libspeex/libspeexdsp/testresample2.c index 99a830da9e..6524162d76 100644 --- a/vendor/libspeex/libspeexdsp/testresample2.c +++ b/vendor/libspeex/libspeexdsp/testresample2.c @@ -30,13 +30,15 @@ POSSIBILITY OF SUCH DAMAGE. */ +#define _USE_MATH_DEFINES +#include + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "speex/speex_resampler.h" #include -#include #include #define PERIOD 32 From a39508fac91068b475930379017ccdde97d908bd Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Sat, 22 Jun 2024 03:16:40 +0200 Subject: [PATCH 21/23] Cherry-pick https://github.com/xiph/speex/pull/26/commits/574b4b069c528d7be6fa9b409310088b9d9a3985 --- vendor/libspeex/libspeex/bits.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libspeex/libspeex/bits.c b/vendor/libspeex/libspeex/bits.c index 2d782a2def..4f457af111 100644 --- a/vendor/libspeex/libspeex/bits.c +++ b/vendor/libspeex/libspeex/bits.c @@ -275,7 +275,7 @@ EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) /* If number is negative */ if (d>>(nbBits-1)) { - d |= (-1)< Date: Sat, 22 Jun 2024 03:20:08 +0200 Subject: [PATCH 22/23] Test fix for MTA Server x64 build error: cryptopp.lib(cpu.obj) : error LNK2019: unresolved external symbol XGETBV64 referenced in function "void __cdecl CryptoPP::DetectX86Features(void)" (?DetectX86Features@CryptoPP@@YAXXZ) [D:\a\mtasa-blue\mtasa-blue\Build\Deathmatch.vcxproj] cryptopp.lib(cpu.obj) : error LNK2019: unresolved external symbol CPUID64 referenced in function "bool __cdecl CryptoPP::CpuId(unsigned int,unsigned int,unsigned int * const)" (?CpuId@CryptoPP@@YA_NIIQEAI@Z) [D:\a\mtasa-blue\mtasa-blue\Build\Deathmatch.vcxproj] ..\Bin\server\x64\deathmatch.dll : fatal error LNK1120: 2 unresolved externals [D:\a\mtasa-blue\mtasa-blue\Build\Deathmatch.vcxproj] Following 7ba2a4c Due to https://github.com/weidai11/cryptopp/commit/043208515799c06d570d8d6f9b81c324a33832a2 --- vendor/cryptopp/premake5.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vendor/cryptopp/premake5.lua b/vendor/cryptopp/premake5.lua index e9c05c1cfc..ba09c3f6a8 100644 --- a/vendor/cryptopp/premake5.lua +++ b/vendor/cryptopp/premake5.lua @@ -213,7 +213,8 @@ project "cryptopp" filter "platforms:x64" files { "x64dll.asm", - "x64masm.asm" + "x64masm.asm", + "cpuid64.asm" } filter { "system:windows" } From 63976542803d22116a9c8469936c71e8e4c2ad0d Mon Sep 17 00:00:00 2001 From: Dutchman101 Date: Sat, 22 Jun 2024 03:40:40 +0200 Subject: [PATCH 23/23] Fix failed cryptopp tests in debug builds; partially revert 7ba2a4c (Accidentally added files that were always in cryptopp but not in use by MTA) --- vendor/cryptopp/bench.h | 105 -- vendor/cryptopp/bench1.cpp | 520 -------- vendor/cryptopp/bench2.cpp | 267 ---- vendor/cryptopp/bench3.cpp | 480 ------- vendor/cryptopp/datatest.cpp | 1443 --------------------- vendor/cryptopp/dlltest.cpp | 212 ---- vendor/cryptopp/fipsalgt.cpp | 1293 ------------------- vendor/cryptopp/fipstest.cpp | 652 ---------- vendor/cryptopp/regtest1.cpp | 160 --- vendor/cryptopp/regtest2.cpp | 105 -- vendor/cryptopp/regtest3.cpp | 156 --- vendor/cryptopp/regtest4.cpp | 58 - vendor/cryptopp/test.cpp | 1098 ---------------- vendor/cryptopp/validat0.cpp | 1672 ------------------------- vendor/cryptopp/validat1.cpp | 1225 ------------------ vendor/cryptopp/validat10.cpp | 535 -------- vendor/cryptopp/validat2.cpp | 1328 -------------------- vendor/cryptopp/validat3.cpp | 1367 -------------------- vendor/cryptopp/validat4.cpp | 1813 --------------------------- vendor/cryptopp/validat5.cpp | 2224 --------------------------------- vendor/cryptopp/validat6.cpp | 408 ------ vendor/cryptopp/validat7.cpp | 705 ----------- vendor/cryptopp/validat8.cpp | 631 ---------- vendor/cryptopp/validat9.cpp | 735 ----------- vendor/cryptopp/validate.h | 395 ------ 25 files changed, 19587 deletions(-) delete mode 100644 vendor/cryptopp/bench.h delete mode 100644 vendor/cryptopp/bench1.cpp delete mode 100644 vendor/cryptopp/bench2.cpp delete mode 100644 vendor/cryptopp/bench3.cpp delete mode 100644 vendor/cryptopp/datatest.cpp delete mode 100644 vendor/cryptopp/dlltest.cpp delete mode 100644 vendor/cryptopp/fipsalgt.cpp delete mode 100644 vendor/cryptopp/fipstest.cpp delete mode 100644 vendor/cryptopp/regtest1.cpp delete mode 100644 vendor/cryptopp/regtest2.cpp delete mode 100644 vendor/cryptopp/regtest3.cpp delete mode 100644 vendor/cryptopp/regtest4.cpp delete mode 100644 vendor/cryptopp/test.cpp delete mode 100644 vendor/cryptopp/validat0.cpp delete mode 100644 vendor/cryptopp/validat1.cpp delete mode 100644 vendor/cryptopp/validat10.cpp delete mode 100644 vendor/cryptopp/validat2.cpp delete mode 100644 vendor/cryptopp/validat3.cpp delete mode 100644 vendor/cryptopp/validat4.cpp delete mode 100644 vendor/cryptopp/validat5.cpp delete mode 100644 vendor/cryptopp/validat6.cpp delete mode 100644 vendor/cryptopp/validat7.cpp delete mode 100644 vendor/cryptopp/validat8.cpp delete mode 100644 vendor/cryptopp/validat9.cpp delete mode 100644 vendor/cryptopp/validate.h diff --git a/vendor/cryptopp/bench.h b/vendor/cryptopp/bench.h deleted file mode 100644 index 561b657874..0000000000 --- a/vendor/cryptopp/bench.h +++ /dev/null @@ -1,105 +0,0 @@ -// 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/vendor/cryptopp/bench1.cpp b/vendor/cryptopp/bench1.cpp deleted file mode 100644 index 24c9a3b7e5..0000000000 --- a/vendor/cryptopp/bench1.cpp +++ /dev/null @@ -1,520 +0,0 @@ -// 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"); - BenchMarkByNameKeyLess("LSH-256"); - BenchMarkByNameKeyLess("LSH-512"); - } - - std::cout << "\n
AlgorithmProviderMiB/Second" << cpb; - - std::cout << "\n
" << std::endl; -} - -NAMESPACE_END // Test -NAMESPACE_END // CryptoPP diff --git a/vendor/cryptopp/bench2.cpp b/vendor/cryptopp/bench2.cpp deleted file mode 100644 index 0bd2d0a4b2..0000000000 --- a/vendor/cryptopp/bench2.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// 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/vendor/cryptopp/bench3.cpp b/vendor/cryptopp/bench3.cpp deleted file mode 100644 index e280a6216f..0000000000 --- a/vendor/cryptopp/bench3.cpp +++ /dev/null @@ -1,480 +0,0 @@ -// 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(spriv2); - 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(spriv2); - 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/vendor/cryptopp/datatest.cpp b/vendor/cryptopp/datatest.cpp deleted file mode 100644 index ac82d5181b..0000000000 --- a/vendor/cryptopp/datatest.cpp +++ /dev/null @@ -1,1443 +0,0 @@ -// 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 CRYPTOPP_MSC_VERSION -# define STRTOUL64 _strtoui64 -#else -# define STRTOUL64 strtoull -#endif - -NAMESPACE_BEGIN(CryptoPP) -NAMESPACE_BEGIN(Test) - -ANONYMOUS_NAMESPACE_BEGIN - -bool s_thorough = false; -typedef std::map TestData; -const TestData *s_currentTestData = NULLPTR; -const std::string testDataFilename = "cryptest.dat"; - -// Handles CR, LF, and CRLF properly. Early RFC's used '\r\0' on occasion. -// For istream.fail() see https://stackoverflow.com/q/34395801/608639. -bool Readline(std::istream& stream, std::string& line) -{ - // Ensure old data is cleared - line.clear(); - - std::string temp; - temp.reserve(64); - - while (!stream.fail()) - { - int ch = stream.get(); - if (ch == '\r') - { - int next = stream.peek(); - if (next == '\n') - (void)stream.get(); - else if (next == '\0') - (void)stream.get(); - - break; - } - else if (ch == '\n') - { - break; - } - - temp.push_back(static_cast(ch)); - } - -#if defined(CRYPTOPP_CXX11) - temp.shrink_to_fit(); -#else - // Non-binding shrink to fit - temp.reserve(0); -#endif - - std::swap(line, temp); - - return !stream.fail(); -} - -std::string TrimSpace(const 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(const 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); -} - -class TestFailure : public Exception -{ -public: - TestFailure() : Exception(OTHER_ERROR, "Validation test failed") {} -}; - -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; - } -} - -void SignalTestFailure() -{ - OutputTestData(*s_currentTestData); - throw TestFailure(); -} - -void SignalUnknownAlgorithmError(const std::string& algType) -{ - OutputTestData(*s_currentTestData); - throw Exception(Exception::OTHER_ERROR, "Unknown algorithm " + algType + " during validation test"); -} - -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()) - { - std::string::size_type pos = s1.find_first_not_of(" "); - if (pos != std::string::npos) - s1.erase(0, pos); - - if (s1.empty()) - goto end; - - int repeat = 1; - if (s1[0] == 'r') - { - s1 = s1.erase(0, 1); - repeat = std::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 n = s1.find(' '); - StringSource(s1.substr(2, n), true, new HexDecoder(new StringSink(s2))); - s1 = s1.substr(STDMIN(n, s1.length())); - } - else - { - std::string::size_type n = s1.find(' '); - StringSource(s1.substr(0, n), true, new HexDecoder(new StringSink(s2))); - s1 = s1.substr(STDMIN(n, 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, unsigned int &totalTests) -{ - totalTests++; - - 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, unsigned int &totalTests) -{ - std::string name = GetRequiredDatum(v, "Name"); - std::string test = GetRequiredDatum(v, "Test"); - - static member_ptr signer; - static member_ptr verifier; - static std::string lastName; - - if (name != lastName) - { - signer.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - verifier.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - lastName = name; - - // Code coverage - (void)signer->AlgorithmName(); - (void)verifier->AlgorithmName(); - (void)signer->AlgorithmProvider(); - (void)verifier->AlgorithmProvider(); - } - - TestDataNameValuePairs pairs(v); - - if (test == "GenerateKey") - { - totalTests++; - - signer->AccessPrivateKey().GenerateRandom(Test::GlobalRNG(), pairs); - verifier->AccessPublicKey().AssignFrom(signer->AccessPrivateKey()); - } - else - { - std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); - - totalTests++; // key format - if (keyFormat == "DER") - verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); - else if (keyFormat == "Component") - verifier->AccessMaterial().AssignFrom(pairs); - - if (test == "Verify" || test == "NotVerify") - { - totalTests++; - - 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") - { - totalTests++; - - if (!verifier->GetMaterial().Validate(Test::GlobalRNG(), 3)) - SignalTestFailure(); - return; - } - - totalTests++; // key format - if (keyFormat == "DER") - signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); - else if (keyFormat == "Component") - signer->AccessMaterial().AssignFrom(pairs); - } - - if (test == "GenerateKey" || test == "KeyPairValidAndConsistent") - { - totalTests++; - - TestKeyPairValidAndConsistent(verifier->AccessMaterial(), signer->GetMaterial(),totalTests); - 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") - { - totalTests++; - - 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") - { - totalTests++; - - // 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(); - } - else - { - std::string msg("Unknown signature test \"" + test + "\""); - SignalTestError(msg.c_str()); - CRYPTOPP_ASSERT(false); - } -} - -// Subset of TestSignatureScheme. We picked the tests that have data that is easy to write to a file. -// Also see https://github.com/weidai11/cryptopp/issues/1010, where HIGHT broke when using FileSource. -void TestSignatureSchemeWithFileSource(TestData &v, unsigned int &totalTests) -{ - std::string name = GetRequiredDatum(v, "Name"); - std::string test = GetRequiredDatum(v, "Test"); - - if (test != "Sign" && test != "DeterministicSign") { return; } - - static member_ptr signer; - static member_ptr verifier; - static std::string lastName; - - if (name != lastName) - { - signer.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - verifier.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - name = lastName; - - // Code coverage - (void)signer->AlgorithmName(); - (void)verifier->AlgorithmName(); - (void)signer->AlgorithmProvider(); - (void)verifier->AlgorithmProvider(); - } - - TestDataNameValuePairs pairs(v); - - std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); - - totalTests++; // key format - if (keyFormat == "DER") - verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); - else if (keyFormat == "Component") - verifier->AccessMaterial().AssignFrom(pairs); - - totalTests++; // key format - if (keyFormat == "DER") - signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); - else if (keyFormat == "Component") - signer->AccessMaterial().AssignFrom(pairs); - - if (test == "Sign") - { - totalTests++; - - SignerFilter f(Test::GlobalRNG(), *signer, new HexEncoder(new FileSink(std::cout))); - StringSource ss(GetDecodedDatum(v, "Message"), true, new FileSink(testDataFilename.c_str())); - FileSource fs(testDataFilename.c_str(), true, new Redirector(f)); - SignalTestFailure(); - } - else if (test == "DeterministicSign") - { - totalTests++; - - // 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 FileSink(testDataFilename.c_str())); - FileSource fs(testDataFilename.c_str(), true, new Redirector(f)); - - if (GetDecodedDatum(v, "Signature") != signature) - SignalTestFailure(); - } -} - -void TestAsymmetricCipher(TestData &v, unsigned int &totalTests) -{ - std::string name = GetRequiredDatum(v, "Name"); - std::string test = GetRequiredDatum(v, "Test"); - - static member_ptr encryptor; - static member_ptr 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(); - } - - std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); - - if (keyFormat == "DER") - { - totalTests++; - - decryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); - encryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); - } - else if (keyFormat == "Component") - { - totalTests++; - - TestDataNameValuePairs pairs(v); - decryptor->AccessMaterial().AssignFrom(pairs); - encryptor->AccessMaterial().AssignFrom(pairs); - } - - if (test == "DecryptMatch") - { - totalTests++; - - 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") - { - totalTests++; - - TestKeyPairValidAndConsistent(encryptor->AccessMaterial(), decryptor->GetMaterial(), totalTests); - } - else - { - std::string msg("Unknown asymmetric cipher test \"" + test + "\""); - SignalTestError(msg.c_str()); - CRYPTOPP_ASSERT(false); - } -} - -void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) -{ - 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; - - totalTests++; - - 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->IsRandomAccess(); - (void)decryptor->IsRandomAccess(); - (void)encryptor->MinKeyLength(); - (void)decryptor->MinKeyLength(); - (void)encryptor->MaxKeyLength(); - (void)decryptor->MaxKeyLength(); - (void)encryptor->DefaultKeyLength(); - (void)decryptor->DefaultKeyLength(); - } - - 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); - } - } - - // 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); - - 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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(256); ss.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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(2048); ss.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 ss(decrypted, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(256); ss.Flush(false); - std::cout << "\n"; - SignalTestFailure(); - } - } - else - { - std::string msg("Unknown symmetric cipher test \"" + test + "\""); - SignalTestError(msg.c_str()); - } -} - -// Subset of TestSymmetricCipher. The test suite lacked tests for in-place encryption, -// where inString == outString. Also see https://github.com/weidai11/cryptopp/issues/1231. -void TestSymmetricCipherWithInplaceEncryption(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) -{ - 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" ) { return; } - - 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; - } - - // Only test stream ciphers at the moment - if (encryptor->MandatoryBlockSize() != 1) { return; } - - totalTests++; - - ConstByteArrayParameter iv; - if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) - SignalTestFailure(); - - 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); - } - } - - const std::string plainText = GetDecodedDatum(v, "Plaintext"); - const std::string cipherText = GetDecodedDatum(v, "Ciphertext"); - - // Use buffer for in-place encryption and decryption - std::string buffer(plainText); - - // Test in-place encryption - encryptor->ProcessString(BytePtr(buffer), BytePtrSize(buffer)); - - if (buffer != cipherText) - { - std::cout << "\nincorrectly encrypted: "; - StringSource ss(buffer, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(256); ss.Flush(false); - std::cout << "\n"; - SignalTestFailure(); - } - - // Test in-place decryption - decryptor->ProcessString(BytePtr(buffer), BytePtrSize(buffer)); - - if (buffer != plainText) - { - std::cout << "\nincorrectly decrypted: "; - StringSource ss(buffer, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(256); ss.Flush(false); - std::cout << "\n"; - SignalTestFailure(); - } -} - -// Subset of TestSymmetricCipher. We picked the tests that have data that is easy to write to a file. -// Also see https://github.com/weidai11/cryptopp/issues/1010, where HIGHT broke when using FileSource. -void TestSymmetricCipherWithFileSource(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) -{ - std::string name = GetRequiredDatum(v, "Name"); - std::string test = GetRequiredDatum(v, "Test"); - - // Limit FileSource tests to Encrypt only. - if (test != "Encrypt") { return; } - - totalTests++; - - std::string key = GetDecodedDatum(v, "Key"); - std::string plaintext = GetDecodedDatum(v, "Plaintext"); - - TestDataNameValuePairs testDataPairs(v); - CombinedNameValuePairs pairs(overrideParameters, testDataPairs); - - 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(); - } - - ConstByteArrayParameter iv; - if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) - SignalTestFailure(); - - 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); - } - } - - // 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); - - std::string encrypted, ciphertext; - StreamTransformationFilter encFilter(*encryptor, new StringSink(encrypted), - static_cast(paddingScheme)); - - StringSource ss(plaintext, true, new FileSink(testDataFilename.c_str())); - FileSource pstore(testDataFilename.c_str(), true); - RandomizedTransfer(pstore, encFilter, true); - encFilter.MessageEnd(); - - ciphertext = GetDecodedDatum(v, "Ciphertext"); - - if (encrypted != ciphertext) - { - std::cout << "\nincorrectly encrypted: "; - StringSource sss(encrypted, false, new HexEncoder(new FileSink(std::cout))); - sss.Pump(2048); sss.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 sss(decrypted, false, new HexEncoder(new FileSink(std::cout))); - sss.Pump(256); sss.Flush(false); - std::cout << "\n"; - SignalTestFailure(); - } -} - -void TestAuthenticatedSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters, unsigned int &totalTests) -{ - 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") - { - totalTests++; - - static member_ptr encryptor; - static member_ptr decryptor; - static std::string lastName; - - if (name != lastName) - { - encryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - decryptor.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - name = lastName; - - // 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(); - (void)encryptor->IsRandomAccess(); - (void)decryptor->IsRandomAccess(); - (void)encryptor->IsSelfInverting(); - (void)decryptor->IsSelfInverting(); - (void)encryptor->MaxHeaderLength(); - (void)decryptor->MaxHeaderLength(); - (void)encryptor->MaxMessageLength(); - (void)decryptor->MaxMessageLength(); - (void)encryptor->MaxFooterLength(); - (void)decryptor->MaxFooterLength(); - (void)encryptor->NeedsPrespecifiedDataLengths(); - (void)decryptor->NeedsPrespecifiedDataLengths(); - } - - encryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); - decryptor->SetKey(ConstBytePtr(key), BytePtrSize(key), pairs); - - 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 ss(encrypted, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(2048); ss.Flush(false); - std::cout << "\n"; - SignalTestFailure(); - } - if (test == "Encrypt" && decrypted != plaintext) - { - std::cout << "\nincorrectly decrypted: "; - StringSource ss(decrypted, false, new HexEncoder(new FileSink(std::cout))); - ss.Pump(256); ss.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, unsigned int &totalTests) -{ - 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(); - (void)hash->TagSize(); - (void)hash->DigestSize(); - (void)hash->Restart(); - } - 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(); - (void)mac->TagSize(); - (void)mac->DigestSize(); - (void)mac->Restart(); - (void)mac->MinKeyLength(); - (void)mac->MaxKeyLength(); - (void)mac->DefaultKeyLength(); - } - - if (test == "Verify" || test == "VerifyTruncated" || test == "NotVerify") - { - totalTests++; - - 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, unsigned int &totalTests) -{ - totalTests++; - - std::string name = GetRequiredDatum(v, "Name"); - std::string test = GetRequiredDatum(v, "Test"); - - if(test == "Skip") return; - - std::string secret = GetDecodedDatum(v, "Secret"); - std::string expected = GetDecodedDatum(v, "DerivedKey"); - - TestDataNameValuePairs pairs(v); - - static member_ptr kdf; - static std::string lastName; - - if (name != lastName) - { - kdf.reset(ObjectFactoryRegistry::Registry().CreateObject(name.c_str())); - name = lastName; - - // Code coverage - (void)kdf->AlgorithmName(); - (void)kdf->AlgorithmProvider(); - (void)kdf->MinDerivedKeyLength(); - (void)kdf->MaxDerivedKeyLength(); - } - - 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. If this function is modified, -// then run 'cryptest.exe tv all' to ensure parsing still works. -bool GetField(std::istream &is, std::string &name, std::string &value) -{ - std::string line; - name.clear(); value.clear(); - - // ***** Name ***** - while (Readline(is, line)) - { - // Eat empty lines and comments gracefully - line = TrimSpace(line); - 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 - { - continueLine = false; - - // Trim leading and trailing whitespace. Don't parse comments - // here because there may be a line continuation at the end. - line = TrimSpace(line); - - if (line.empty()) - continue; - - // Check for continuation. The slash must be the last character. - if (LastChar(line) == '\\') { - continueLine = true; - line.erase(line.end()-1); - } - - // Re-trim after parsing - line = TrimComment(line); - line = TrimSpace(line); - - if (line.empty()) - continue; - - // Finally... the value - value += line; - - if (continueLine) - value += ' '; - } - while (continueLine && Readline(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) -{ - std::ifstream file(DataDir(filename).c_str()); - if (!file.good()) - throw Exception(Exception::OTHER_ERROR, "Can not open file " + DataDir(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; - - // The name "Test" is special. It tells the framework - // to run the test. Otherwise, name/value pairs are - // parsed and added to TestData 'v'. - if (name == "Test" && (s_thorough || v["SlowTest"] != "1")) - { - bool failed = false; - std::string algType = GetRequiredDatum(v, "AlgorithmType"); - std::string algName = GetRequiredDatum(v, "Name"); - - if (lastAlgName != algName) - { - std::cout << "\nTesting " << algType << " algorithm " << algName << ".\n"; - lastAlgName = algName; - } - - // In the old days each loop ran one test. Later, things were modified to run the - // the same test twice. Some tests are run with both a StringSource and a FileSource - // to catch FileSource specific errors. currentTests and deltaTests (below) keep - // the book keeping in order. - unsigned int currentTests = totalTests; - - try - { - if (algType == "Signature") - { - TestSignatureScheme(v, totalTests); - TestSignatureSchemeWithFileSource(v, totalTests); - } - else if (algType == "SymmetricCipher") - { - TestSymmetricCipher(v, overrideParameters, totalTests); - TestSymmetricCipherWithInplaceEncryption(v, overrideParameters, totalTests); - TestSymmetricCipherWithFileSource(v, overrideParameters, totalTests); - } - else if (algType == "AuthenticatedSymmetricCipher") - TestAuthenticatedSymmetricCipher(v, overrideParameters, totalTests); - else if (algType == "AsymmetricCipher") - TestAsymmetricCipher(v, totalTests); - else if (algType == "MessageDigest") - TestDigestOrMAC(v, true, totalTests); - else if (algType == "MAC") - TestDigestOrMAC(v, false, totalTests); - else if (algType == "KDF") - TestKeyDerivationFunction(v, totalTests); - else if (algType == "FileList") - TestDataFile(GetRequiredDatum(v, "Test"), g_nullNameValuePairs, totalTests, failedTests); - else - SignalUnknownAlgorithmError(algType); - } - catch (const TestFailure &) - { - failed = true; - std::cout << "\nTest FAILED.\n"; - } - catch (const Exception &e) - { - failed = true; - std::cout << "\nCryptoPP::Exception caught: " << e.what() << std::endl; - } - catch (const std::exception &e) - { - failed = true; - std::cout << "\nstd::exception caught: " << e.what() << std::endl; - } - - if (failed) - { - std::cout << "Skipping to next test." << std::endl; - failedTests++; - } - else - { - if (algType != "FileList") - { - unsigned int deltaTests = totalTests-currentTests; - if (deltaTests) - { - std::string progress(deltaTests, '.'); - std::cout << progress; - if (currentTests % 4 == 0) - std::cout << std::flush; - } - } - } - - // Most tests fully specify parameters, like key and iv. Each test gets - // its own unique value. Since each test gets a new value for each test - // case, latching a value in 'TestData v' does not matter. The old key - // or iv will get overwritten on the next test. - // - // If a per-test vector parameter was set for a test, like BlockPadding, - // BlockSize or Tweak, then it becomes latched in 'TestData v'. 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 except - // one. Threefish occasionally uses a Tweak. - // - // Unlatch BlockPadding, BlockSize and Tweak now, after the test has been - // run. Also note we only unlatch from 'TestData v'. If overrideParameters - // are specified, the caller is responsible for managing the parameter. - v.erase("Tweak"); v.erase("InitialBlock"); - v.erase("BlockSize"); v.erase("BlockPaddingScheme"); - } - } -} - -ANONYMOUS_NAMESPACE_END - -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/vendor/cryptopp/dlltest.cpp b/vendor/cryptopp/dlltest.cpp deleted file mode 100644 index 2ad8f2fec2..0000000000 --- a/vendor/cryptopp/dlltest.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#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 (std::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 (std::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/vendor/cryptopp/fipsalgt.cpp b/vendor/cryptopp/fipsalgt.cpp deleted file mode 100644 index 1f2061bdd1..0000000000 --- a/vendor/cryptopp/fipsalgt.cpp +++ /dev/null @@ -1,1293 +0,0 @@ -// 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); - std::memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); - std::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); - std::memcpy(IB[j+1], IB[j]+K/8, blockSize-K/8); - std::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/vendor/cryptopp/fipstest.cpp b/vendor/cryptopp/fipstest.cpp deleted file mode 100644 index 145f425445..0000000000 --- a/vendor/cryptopp/fipstest.cpp +++ /dev/null @@ -1,652 +0,0 @@ -// 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(CRYPTOPP_MSC_VERSION) && CRYPTOPP_MSC_VERSION >= 1400 -# ifdef _M_IX86 -# define _CRT_DEBUGGER_HOOK _crt_debugger_hook -# else -# define _CRT_DEBUGGER_HOOK __crt_debugger_hook -# endif -# if CRYPTOPP_MSC_VERSION < 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: 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 (CRYPTOPP_MSC_VERSION >= 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 (CRYPTOPP_MSC_VERSION >= 1400 && CRYPTOPP_MSC_VERSION < 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/vendor/cryptopp/regtest1.cpp b/vendor/cryptopp/regtest1.cpp deleted file mode 100644 index d5f6fec446..0000000000 --- a/vendor/cryptopp/regtest1.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// 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 "lsh.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(); - 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/vendor/cryptopp/regtest2.cpp b/vendor/cryptopp/regtest2.cpp deleted file mode 100644 index 35b460576d..0000000000 --- a/vendor/cryptopp/regtest2.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// 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/vendor/cryptopp/regtest3.cpp b/vendor/cryptopp/regtest3.cpp deleted file mode 100644 index f1370c8e6d..0000000000 --- a/vendor/cryptopp/regtest3.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// 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 >(); - 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/vendor/cryptopp/regtest4.cpp b/vendor/cryptopp/regtest4.cpp deleted file mode 100644 index c4637f0f68..0000000000 --- a/vendor/cryptopp/regtest4.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// 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/vendor/cryptopp/test.cpp b/vendor/cryptopp/test.cpp deleted file mode 100644 index 22286f2e15..0000000000 --- a/vendor/cryptopp/test.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -// 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 (CRYPTOPP_MSC_VERSION >= 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 = "X-help"; - 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") - { - int testNumber = argc>2 ? StringToValue(argv[2]) : 0; - return Validate(testNumber, command == "vv" /*thorough*/) ? 0 : 1; - } - 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" || command == "X-help") - { - FileSource usage(DataDir("TestData/usage.dat").c_str(), true, new FileSink(std::cout)); - return command == "h" ? 0 : 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 = ValidateLSH(); break; - case 69: 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; - case 9992: result = TestASN1Functions(); break; - // http://github.com/weidai11/cryptopp/issues/242 - case 9991: result = TestX25519(); break; - // http://github.com/weidai11/cryptopp/issues/346 - case 9990: result = TestEd25519(); break; -# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) - case 9989: 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/vendor/cryptopp/validat0.cpp b/vendor/cryptopp/validat0.cpp deleted file mode 100644 index 9e69ee3f4f..0000000000 --- a/vendor/cryptopp/validat0.cpp +++ /dev/null @@ -1,1672 +0,0 @@ -// 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; -} - -bool TestASN1Functions() -{ - std::cout << "\nTesting ASN.1 functions...\n\n"; - - bool pass = true, fail; - - { - const std::string message = "Now is the time for all good men to come to the aide of their country"; - ByteQueue encoded, reencoded, decoded; - size_t len = 0, rlen = 0; - - len = DEREncodeOctetString(encoded, ConstBytePtr(message), BytePtrSize(message)); - DERReencode(encoded, reencoded); - rlen = (size_t)reencoded.MaxRetrievable(); - (void)BERDecodeOctetString(reencoded, decoded); - - std::string recovered; - StringSink sink(recovered); - decoded.TransferTo(sink); - - fail = (len != rlen || message != recovered); - pass = pass && !fail; - CRYPTOPP_ASSERT(!fail); - - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "DEREncodeOctetString" << "\n"; - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "BERDecodeOctetString" << "\n"; - } - - { - const std::string message = "Now is the time for all good men to come to the aide of their country"; - const byte asnStringTypes[] = { - UTF8_STRING, PRINTABLE_STRING, T61_STRING, VIDEOTEXT_STRING,IA5_STRING, VISIBLE_STRING - }; - - unsigned int failed = 0; - size_t len = 0, rlen = 0, i = 0; - - for (i = 0; i < COUNTOF(asnStringTypes); ++i) - { - ByteQueue encoded, reencoded, decoded; - std::string recovered; - - len = DEREncodeTextString(encoded, ConstBytePtr(message), BytePtrSize(message), asnStringTypes[i]); - DERReencode(encoded, reencoded); - rlen = (size_t)reencoded.MaxRetrievable(); - (void)BERDecodeTextString(reencoded, recovered, asnStringTypes[i]); - - fail = (len != rlen || message != recovered); - if (fail) failed++; - CRYPTOPP_ASSERT(!fail); - } - - failed ? fail = true : fail = false; - pass = pass && !fail; - - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "DEREncodeTextString" << "\n"; - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "DEREncodeTextString" << "\n"; - } - - { - const byte date[] = "Sun, 21 Mar 2021 01:00:00 +0000"; - SecByteBlock message; message.Assign(date, sizeof(date)-1); - const byte asnDateTypes[] = {UTC_TIME, GENERALIZED_TIME}; - unsigned int failed = 0; - size_t i = 0; - - for (i = 0; i < COUNTOF(asnDateTypes); ++i) - { - ByteQueue encoded, decoded; - SecByteBlock recovered; - - (void)DEREncodeDate(encoded, message, asnDateTypes[i]); - (void)BERDecodeDate(encoded, recovered, asnDateTypes[i]); - - fail = (message != recovered); - if (fail) failed++; - CRYPTOPP_ASSERT(!fail); - } - - failed ? fail = true : fail = false; - pass = pass && !fail; - - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "DEREncodeDate" << "\n"; - std::cout << (fail ? "FAILED" : "passed") << " "; - std::cout << "BERDecodeDate" << "\n"; - } - - 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/vendor/cryptopp/validat1.cpp b/vendor/cryptopp/validat1.cpp deleted file mode 100644 index 6aa4e60ff8..0000000000 --- a/vendor/cryptopp/validat1.cpp +++ /dev/null @@ -1,1225 +0,0 @@ -// 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); - std::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); - std::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); - std::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); - std::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 superfluous, 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/vendor/cryptopp/validat10.cpp b/vendor/cryptopp/validat10.cpp deleted file mode 100644 index d91d8beac5..0000000000 --- a/vendor/cryptopp/validat10.cpp +++ /dev/null @@ -1,535 +0,0 @@ -// 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 consistency checks. The known answer tests are test -// vectors lifted from libsodium. The pairwise consistency 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"; - - // ****************************** Integer Randomize ****************************** - - try - { - const word32 bitCounts[] = { - 0,1,2,3,4,5,6,7,8,9,15,16,17,31,32,33,63,64,65,127,128,129 - }; - - for (size_t i=0; i -#include -#include - -// Aggressive stack checking with VS2005 SP1 and above. -#if (CRYPTOPP_MSC_VERSION >= 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; - pass=TestASN1Functions() && 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=ValidateLSH() && 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 (CRYPTOPP_MSC_VERSION >= 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; - } - - // Machine word size does not agree with pointer size on Morello. Also see - // https://developer.arm.com/documentation/den0133/0100/Morello-prototype-architecture/Pointers-and-capabilities - if (sizeof(size_t) == 16) - { - std::cout << "passed: Your machine has 128-bit words.\n"; - } - else if (sizeof(size_t) == 8) - { - std::cout << "passed: Your machine has 64-bit words.\n"; - } - else if (sizeof(size_t) == 4) - { - std::cout << "passed: Your machine has 32-bit words.\n"; - } - else - { - std::cout << "FAILED: Your machine uses unknown word size.\n"; - pass = false; - } - - // Morello uses 129-bit pointers. Also see - // https://developer.arm.com/documentation/den0133/0100/Morello-prototype-architecture/Pointers-and-capabilities - if (sizeof(void*) == 16) - { - std::cout << "passed: Your machine has 128-bit pointers.\n"; - } - else if (sizeof(void*) == 8) - { - std::cout << "passed: Your machine has 64-bit pointers.\n"; - } - else if (sizeof(void*) == 4) - { - std::cout << "passed: Your machine has 32-bit pointers.\n"; - } - else - { - std::cout << "FAILED: Your machine uses unknown pointer size.\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 hasSHA3 = HasSHA3(); - bool hasSHA512 = HasSHA512(); - 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 << ", hasSHA3 == " << hasSHA3; - std::cout << ", hasSHA512 == " << hasSHA512 << ", 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 hasAES = HasAES(); - const bool hasPMULL = HasPMULL(); - 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 << ", hasAES == " << hasAES << ", hasPMULL == " << hasPMULL; - 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 Exception &) {} - - if(rng.get()) - { - pass = Test_RandomNumberGenerator(*rng.get()); - } - - // Reset state - try {rng.reset(new MT19937ar);} - catch (const Exception &) {} - - 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); - - // PadlockRNG does not accept entropy. However, the contract is no throw - const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - (void)padlock.IncorporateEntropy(entropy, sizeof(entropy)); - - 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; - - // RDRAND does not accept entropy. However, the contract is no throw - const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - (void)rdrand.IncorporateEntropy(entropy, sizeof(entropy)); - - 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; - - // RDSEED does not accept entropy. However, the contract is no throw - const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - (void)rdseed.IncorporateEntropy(entropy, sizeof(entropy)); - - 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; - - // DARN does not accept entropy. However, the contract is no throw - const byte entropy[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; - (void)darn.IncorporateEntropy(entropy, sizeof(entropy)); - - 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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = !!std::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/vendor/cryptopp/validat4.cpp b/vendor/cryptopp/validat4.cpp deleted file mode 100644 index 3ca3c13d7e..0000000000 --- a/vendor/cryptopp/validat4.cpp +++ /dev/null @@ -1,1813 +0,0 @@ -// 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 = !!std::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 = !!std::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 = !!std::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 = !!std::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 = std::memcmp(out, cipher, cg.BlockSize()) != 0; - - member_ptr transD(cg.NewDecryption(key)); - transD->ProcessBlock(out, outplain); - fail=fail || std::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 = std::memcmp(out, cipher, RC2Encryption::BLOCKSIZE) != 0; - - member_ptr transD(new RC2Decryption(key, keyLen, effectiveLen)); - transD->ProcessBlock(out, outplain); - fail=fail || std::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 = std::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 = std::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 = std::memcmp(out, cipher[i], 8) != 0; - - ECB_Mode::Decryption dec2((byte *)key[i], strlen(key[i])); - dec2.ProcessData(outplain, cipher[i], 8); - fail = fail || std::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; - - std::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/vendor/cryptopp/validat5.cpp b/vendor/cryptopp/validat5.cpp deleted file mode 100644 index 56d6cc7d06..0000000000 --- a/vendor/cryptopp/validat5.cpp +++ /dev/null @@ -1,2224 +0,0 @@ -// 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 "lsh.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, repeatTimes; -}; - -bool HashModuleTest(HashTransformation &md, const HashTestTuple *testSet, size_t testSetSize) -{ - bool pass=true, fail; - std::ostringstream oss; - - SecByteBlock digest(md.DigestSize()); - for (size_t 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"; - - const 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() -{ - const 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) - }; - - const 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) - }; - - const 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) - }; - - const 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() -{ - const 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() -{ - std::cout << "\nPanama validation suite running...\n"; - return RunTestDataFile("TestVectors/panama.txt"); -} - -bool ValidateWhirlpool() -{ - std::cout << "\nWhirlpool validation suite running...\n"; - return RunTestDataFile("TestVectors/whrlpool.txt"); -} - -bool ValidateLSH() -{ - std::cout << "\nLSH validation suite running...\n"; - return RunTestDataFile("TestVectors/lsh.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, size_t testSetSize) -{ - bool pass = true; - - for (size_t 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, size_t testSetSize) -{ - bool pass = true; - - for (size_t 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 (size_t 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 = std::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 (size_t 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 = std::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 (size_t 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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 (size_t 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 || std::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); - - std::memset(val1.begin(), 0x10, val1.size()); - std::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 (std::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); - - std::memset(val1.begin(), 0x10, val1.size()); - std::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 (std::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); - - std::memset(val1.begin(), 0x10, val1.size()); - std::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 (std::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 && std::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 = std::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 = std::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 = std::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/vendor/cryptopp/validat7.cpp b/vendor/cryptopp/validat7.cpp deleted file mode 100644 index ac17592e76..0000000000 --- a/vendor/cryptopp/validat7.cpp +++ /dev/null @@ -1,705 +0,0 @@ -// 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) - -ANONYMOUS_NAMESPACE_BEGIN - -inline bool operator==(const x25519& lhs, const x25519& rhs) -{ - // This is a hack because the KeyAgreement classes do not make it easy to access the PrivateKey - ByteQueue q1, q2; - lhs.DEREncodePrivateKey(q1); - rhs.DEREncodePrivateKey(q2); - - return q1 == q2; -} - -inline bool operator!=(const x25519& lhs, const x25519& rhs) -{ - return !operator==(lhs, rhs); -} - -ANONYMOUS_NAMESPACE_END - -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 slightly 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, fail; - - size_t i = 0; - unsigned int failed = 0; - - SecByteBlock priv1(32), priv2(32), pub1(32), pub2(32), share1(32), share2(32); - for (i=0, failed=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) - -ANONYMOUS_NAMESPACE_BEGIN - -inline byte* C2B(char* ptr) { - return reinterpret_cast(ptr); -} - -inline const byte* C2B(const char* ptr) { - return reinterpret_cast(ptr); -} - -inline bool operator==(const RSA::PrivateKey& lhs, const RSA::PrivateKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetPublicExponent() == rhs.GetPublicExponent() && - lhs.GetPrivateExponent() == rhs.GetPrivateExponent(); -} - -inline bool operator!=(const RSA::PrivateKey& lhs, const RSA::PrivateKey& rhs) { - return !operator==(lhs, rhs); -} - -inline bool operator==(const RSA::PublicKey& lhs, const RSA::PublicKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetPublicExponent() == rhs.GetPublicExponent(); -} - -inline bool operator!=(const RSA::PublicKey& lhs, const RSA::PublicKey& rhs) { - return !operator==(lhs, rhs); -} - -inline bool operator==(const LUC::PrivateKey& lhs, const LUC::PrivateKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetPublicExponent() == rhs.GetPublicExponent() && - lhs.GetPrime1() == rhs.GetPrime1() && - lhs.GetPrime2() == rhs.GetPrime2() && - lhs.GetMultiplicativeInverseOfPrime2ModPrime1() == rhs.GetMultiplicativeInverseOfPrime2ModPrime1(); -} - -inline bool operator!=(const LUC::PrivateKey& lhs, const LUC::PrivateKey& rhs) { - return !operator==(lhs, rhs); -} - -inline bool operator==(const LUC::PublicKey& lhs, const LUC::PublicKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetPublicExponent() == rhs.GetPublicExponent(); -} - -inline bool operator!=(const LUC::PublicKey& lhs, const LUC::PublicKey& rhs) { - return !operator==(lhs, rhs); -} - -inline bool operator==(const Rabin::PrivateKey& lhs, const Rabin::PrivateKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetQuadraticResidueModPrime1() == rhs.GetQuadraticResidueModPrime1() && - lhs.GetQuadraticResidueModPrime2() == rhs.GetQuadraticResidueModPrime2() && - lhs.GetPrime1() == rhs.GetPrime1() && - lhs.GetPrime2() == rhs.GetPrime2() && - lhs.GetMultiplicativeInverseOfPrime2ModPrime1() == rhs.GetMultiplicativeInverseOfPrime2ModPrime1(); -} - -inline bool operator!=(const Rabin::PrivateKey& lhs, const Rabin::PrivateKey& rhs) { - return !operator==(lhs, rhs); -} - -inline bool operator==(const Rabin::PublicKey& lhs, const Rabin::PublicKey& rhs) { - return lhs.GetModulus() == rhs.GetModulus() && - lhs.GetQuadraticResidueModPrime1() == rhs.GetQuadraticResidueModPrime1() && - lhs.GetQuadraticResidueModPrime2() == rhs.GetQuadraticResidueModPrime2(); -} - -inline bool operator!=(const Rabin::PublicKey& lhs, const Rabin::PublicKey& rhs) { - return !operator==(lhs, rhs); -} - -ANONYMOUS_NAMESPACE_END - -bool ValidateRSA_Encrypt() -{ - // Must be large enough for RSA-3072 to test SHA3_256 - byte out[256], outPlain[128]; - bool pass = true, fail; - -#if defined(CRYPTOPP_EXTENDED_VALIDATION) - { - FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); - RSA::PrivateKey rsaPriv; rsaPriv.Load(keys); - RSA::PublicKey rsaPub(rsaPriv); - - const Integer& n = rsaPriv.GetModulus(); - const Integer& e = rsaPriv.GetPublicExponent(); - const Integer& d = rsaPriv.GetPrivateExponent(); - - RSA::PrivateKey rsaPriv2; - rsaPriv2.Initialize(n, e, d); - - fail = (rsaPriv != rsaPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "RSA::PrivateKey initialization\n"; - - RSA::PublicKey rsaPub2; - rsaPub2.Initialize(n, e); - - fail = (rsaPub != rsaPub2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "RSA::PublicKey initialization\n"; - } - { - FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); - RSA::PrivateKey rsaPriv; rsaPriv.Load(keys); - - ByteQueue q; - rsaPriv.DEREncodePrivateKey(q); - - RSA::PrivateKey rsaPriv2; - rsaPriv2.BERDecodePrivateKey(q, true, (size_t)q.MaxRetrievable()); - - fail = (rsaPriv != rsaPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "RSA::PrivateKey encoding and decoding\n"; - } -#endif - - { - FileSource keys(DataDir("TestData/rsa1024.dat").c_str(), true, new HexDecoder); - RSAES_PKCS1v15_Decryptor rsaPriv(keys); - RSAES_PKCS1v15_Encryptor rsaPub(rsaPriv); - - fail = !CryptoSystemValidate(rsaPriv, rsaPub); - pass = pass && !fail; - } - { - RSAES_OAEP_SHA_Decryptor rsaPriv(GlobalRNG(), 512); - RSAES_OAEP_SHA_Encryptor rsaPub(rsaPriv); - - fail = !CryptoSystemValidate(rsaPriv, rsaPub); - pass = pass && !fail; - } - { - RSAES_OAEP_SHA256_Decryptor rsaPriv(GlobalRNG(), 1024); - RSAES_OAEP_SHA256_Encryptor rsaPub(rsaPriv); - - fail = !CryptoSystemValidate(rsaPriv, rsaPub); - pass = pass && !fail; - } - { - const byte plain[] = - "\x54\x85\x9b\x34\x2c\x49\xea\x2a"; - 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"; - 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); - - std::memset(out, 0, 50); - std::memset(outPlain, 0, 8); - rsaPub.Encrypt(rng, plain, 8, out); - DecodingResult result = rsaPriv.FixedLengthDecrypt(GlobalRNG(), encrypted, outPlain); - fail = !result.isValidCoding || (result.messageLength!=8) || std::memcmp(out, encrypted, 50) || std::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() -{ - bool pass = true, fail; - -#if defined(CRYPTOPP_EXTENDED_VALIDATION) - { - FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); - LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); - LUC::PublicKey lucPub(lucPriv); - - const Integer& n = lucPriv.GetModulus(); - const Integer& e = lucPriv.GetPublicExponent(); - const Integer& p = lucPriv.GetPrime1(); - const Integer& q = lucPriv.GetPrime2(); - const Integer& u = lucPriv.GetMultiplicativeInverseOfPrime2ModPrime1(); - - LUC::PrivateKey lucPriv2; - lucPriv2.Initialize(n, e, p, q, u); - - fail = (lucPriv != lucPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "LUC::PrivateKey initialization\n"; - - LUC::PublicKey lucPub2; - lucPub2.Initialize(n, e); - - fail = (lucPub != lucPub2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "LUC::PublicKey initialization\n"; - } - { - FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); - LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); - - ByteQueue q; - lucPriv.DEREncode(q); - - LUC::PrivateKey lucPriv2; - lucPriv2.BERDecode(q); - - fail = (lucPriv != lucPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "LUC::PrivateKey encoding and decoding\n"; - } - { - FileSource keys(DataDir("TestData/luc1024.dat").c_str(), true, new HexDecoder); - LUC::PrivateKey lucPriv; lucPriv.BERDecode(keys); - LUC::PublicKey lucPub(lucPriv); - - ByteQueue q; - lucPub.DEREncode(q); - - LUC::PublicKey lucPub2; - lucPub2.BERDecode(q); - - fail = (lucPub != lucPub2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "LUC::PublicKey encoding and decoding\n"; - } -#endif - - LUCES_OAEP_SHA_Decryptor priv(GlobalRNG(), 512); - LUCES_OAEP_SHA_Encryptor pub(priv); - fail = !CryptoSystemValidate(priv, pub); - pass = pass && !fail; - - return pass; -} - -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() -{ - bool pass = true, fail; - -#if defined(CRYPTOPP_EXTENDED_VALIDATION) - { - FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); - Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); - Rabin::PublicKey rabinPub(rabinPriv); - - const Integer& n = rabinPriv.GetModulus(); - const Integer& r = rabinPriv.GetQuadraticResidueModPrime1(); - const Integer& s = rabinPriv.GetQuadraticResidueModPrime2(); - const Integer& p = rabinPriv.GetPrime1(); - const Integer& q = rabinPriv.GetPrime2(); - const Integer& u = rabinPriv.GetMultiplicativeInverseOfPrime2ModPrime1(); - - Rabin::PrivateKey rabinPriv2; - rabinPriv2.Initialize(n, r, s, p, q, u); - - fail = (rabinPriv != rabinPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "Rabin::PrivateKey initialization\n"; - - Rabin::PublicKey rabinPub2; - rabinPub2.Initialize(n, r, s); - - fail = (rabinPub != rabinPub2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "Rabin::PublicKey initialization\n"; - } - { - FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); - Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); - - ByteQueue q; - rabinPriv.DEREncode(q); - - Rabin::PrivateKey rabinPriv2; - rabinPriv2.BERDecode(q); - - fail = (rabinPriv != rabinPriv2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "Rabin::PrivateKey encoding and decoding\n"; - } - { - FileSource keys(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); - Rabin::PrivateKey rabinPriv; rabinPriv.BERDecode(keys); - Rabin::PublicKey rabinPub(rabinPriv); - - ByteQueue q; - rabinPub.DEREncode(q); - - Rabin::PublicKey rabinPub2; - rabinPub2.BERDecode(q); - - fail = (rabinPub != rabinPub2); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "Rabin::PublicKey encoding and decoding\n"; - } -#endif - - FileSource f(DataDir("TestData/rabi1024.dat").c_str(), true, new HexDecoder); - RabinES >::Decryptor priv(f); - RabinES >::Encryptor pub(priv); - fail = !CryptoSystemValidate(priv, pub); - pass = pass && !fail; - - return pass; -} - -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/vendor/cryptopp/validat9.cpp b/vendor/cryptopp/validat9.cpp deleted file mode 100644 index d4ee587413..0000000000 --- a/vendor/cryptopp/validat9.cpp +++ /dev/null @@ -1,735 +0,0 @@ -// 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 = std::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 = std::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); - const 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"; - const 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 -// ValidateECGDSA split into standard and thorough due to GH #1134 -bool ValidateECGDSAStandard() -{ - bool fail, pass=true; - - // 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "brainpoolP512r1 using SHA-512\n"; - - fail = !SignatureValidate(signer, verifier); - pass = pass && !fail; - } - - return pass; -} - -// from http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf -// ValidateECGDSA split into standard and thorough due to GH #1134 -bool ValidateECGDSAThorough() -{ - bool fail, pass=true; - - // 2.4.1 Examples of ECGDSA over GF(p) with the hash function RIPEMD-160 (p. 10) - { - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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) - { - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - 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) - { - 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); - - const size_t maxLength = signer.MaxSignatureLength(); - SecByteBlock signature(maxLength); - r.Encode(signature+ 0, maxLength/2); - s.Encode(signature+maxLength/2, maxLength/2); - - fail = !verifier.VerifyMessage(msg, len, signature, signature.size()); - pass = pass && !fail; - - std::cout << (fail ? "FAILED " : "passed "); - std::cout << "brainpoolP320r1 using RIPEMD-160\n"; - - fail = !SignatureValidate(signer, verifier); - pass = pass && !fail; - } - - return pass; -} - -// ValidateECGDSA split into standard and thorough due to GH #1134 -bool ValidateECGDSA(bool thorough) -{ - std::cout << "\nECGDSA validation suite running...\n\n"; - - bool pass = true, fail; - - fail = !ValidateECGDSAStandard(); - pass = pass && !fail; - - if (thorough) { - fail = !ValidateECGDSAThorough(); - 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/vendor/cryptopp/validate.h b/vendor/cryptopp/validate.h deleted file mode 100644 index 9a1d3c02e8..0000000000 --- a/vendor/cryptopp/validate.h +++ /dev/null @@ -1,395 +0,0 @@ -// 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 fictitious 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 ValidateLSH(); - -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(); -bool TestASN1Functions(); -// 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