diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..92a2674 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,46 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- +**Alternative, faster ways to get help** +If you have just started using ZeroTier, here are some places to get help: +- my.zerotier.com has a _Community_ tab. It's a live chat with other users and the developers. +- [ZeroTier Knowledge Base](https://zerotier.atlassian.net/wiki/spaces/SD/overview) +- www.zerotier.com has a Contact Us button +- email contact@zerotier.com + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Create a Network '...' +2. Install zerotier-one '....' +3. '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots or console output to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Mac, Linux, Windows, BSD] + - OS/Distribution Version + - ZeroTier Version [e.g. 1.2.4] + - Hardware [e.g. raspberry pi 3] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Version [e.g. 1.2.4] + +**Additional context** +Add any other context about the problem here. +- ZeroTier Network Configuration +- Router Config +- Firewall Config (try turning the firewall off) +- General Network Environment: [ e.g Home, University Campus, Corporate LAN ] + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index bd884dc..44b5eb5 100755 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,17 @@ -<<<<<<< HEAD # Main binaries created in *nix builds /zerotier-one /zerotier-idtool /zerotier-cli /zerotier-selftest /zerotier +/nltest # OS-created garbage files from various platforms .DS_Store .Apple* Thumbs.db @eaDir +._* # Windows build droppings /windows/ZeroTierOne.sdf @@ -27,6 +28,7 @@ Thumbs.db /windows/Release /windows/WebUIWrapper/bin /windows/WebUIWrapper/obj +/windows/lib /ext/installfiles/windows/ZeroTier One-SetupFiles /ext/installfiles/windows/Prerequisites /ext/installfiles/windows/*-cache @@ -49,6 +51,7 @@ enc_temp_folder /world/mkworld /world/*.c25519 zt1-src.tar.gz +/MacEthernetTapAgent # Miscellaneous temporaries, build files, etc. *.log @@ -111,3 +114,9 @@ build/ !default.perspectivev3 *.xccheckout xcuserdata/ +ext/librethinkdbxx/build +.vscode +__pycache__ +*~ +attic/world/*.c25519 +attic/world/mkworld diff --git a/AUTHORS.md b/AUTHORS.md index 043ff00..c4c0c73 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,6 +2,7 @@ * ZeroTier Core and ZeroTier One virtual networking service
Adam Ierymenko / adam.ierymenko@zerotier.com + Joseph Henry / joseph.henry@zerotier.com (QoS and multipath) * Java JNI Interface to enable Android application development, and Android app itself (code for that is elsewhere)
Grant Limberg / glimberg@gmail.com @@ -45,13 +46,6 @@ ZeroTier includes the following third party code, either in ext/ or incorporated * Home page: https://github.com/nlohmann/json * License grant: MIT - * TunTapOSX by Mattias Nissler - - * Files: ext/tap-mac/tuntap/* - * Home page: http://tuntaposx.sourceforge.net/ - * License grant: BSD attribution no-endorsement - * ZeroTier Modifications: change interface name to zt#, increase max MTU, increase max devices - * tap-windows6 by the OpenVPN project * Files: windows/TapDriver6/* @@ -71,3 +65,9 @@ ZeroTier includes the following third party code, either in ext/ or incorporated * Files: ext/libnatpmp/* ext/miniupnpc/* * Home page: http://miniupnp.free.fr/ * License grant: BSD attribution no-endorsement + + * cpp-httplib by yhirose + + * Files: ext/cpp-httplib/* + * Home page: https://github.com/yhirose/cpp-httplib + * License grant: MIT diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fff7808 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +# CMake build script for libzerotiercore.a + +cmake_minimum_required (VERSION 2.8) +project (zerotiercore) + +set (PROJ_DIR ${PROJECT_SOURCE_DIR}) +set (ZT_DEFS -std=c++11) + +file(GLOB core_src_glob ${PROJ_DIR}/node/*.cpp) +add_library(zerotiercore STATIC ${core_src_glob}) + +target_compile_options(zerotiercore PRIVATE ${ZT_DEFS}) diff --git a/COPYING b/COPYING index 23d42df..c43e8e7 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ ZeroTier One, an endpoint server for the ZeroTier virtual network layer. -Copyright © 2011–2016 ZeroTier, Inc. +Copyright © 2011–2019 ZeroTier, Inc. ZeroTier One is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/Jenkinsfile b/Jenkinsfile index 74c8624..8898932 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,11 @@ #!/usr/bin/env groovy node('master') { + checkout scm + def changelog = getChangeLog currentBuild - slackSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}" + mattermostSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}" } parallel 'centos7': { @@ -17,66 +19,66 @@ parallel 'centos7': { } catch (err) { currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)" + mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)" throw err } } -}, 'android-ndk': { - node('android-ndk') { - try { - checkout scm +// }, 'android-ndk': { +// node('android-ndk') { +// try { +// checkout scm - stage('Build Android NDK') { - sh "/android/android-ndk-r13b/ndk-build -C $WORKSPACE/java ZT1=${WORKSPACE}" - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Android NDK (<${env.BUILD_URL}|Open>)" +// stage('Build Android NDK') { +// sh "/android/android-ndk-r15b/ndk-build -C $WORKSPACE/java ZT1=${WORKSPACE}" +// } +// } +// catch (err) { +// currentBuild.result = "FAILURE" +// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Android NDK (<${env.BUILD_URL}|Open>)" - throw err - } - } -}, 'macOS': { - node('macOS') { - try { - checkout scm +// throw err +// } +// } +// }, 'macOS': { +// node('macOS') { +// try { +// checkout scm - stage('Build macOS') { - sh 'make -f make-mac.mk' - } +// stage('Build macOS') { +// sh 'make -f make-mac.mk' +// } - stage('Build macOS UI') { - sh 'cd macui && xcodebuild -target "ZeroTier One" -configuration Debug' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" +// stage('Build macOS UI') { +// sh 'cd macui && xcodebuild -target "ZeroTier One" -configuration Debug' +// } +// } +// catch (err) { +// currentBuild.result = "FAILURE" +// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - throw err - } - } -}, 'windows': { - node('windows') { - try { - checkout scm +// throw err +// } +// } +// }, 'windows': { +// node('windows') { +// try { +// checkout scm - stage('Build Windows') { - bat '''CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64 -git clean -dfx -msbuild windows\\ZeroTierOne.sln -''' - } - } - catch (err) { - currentBuild.result = "FAILURE" - slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Windows (<${env.BUILD_URL}|Open>)" +// stage('Build Windows') { +// bat '''CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64 +// git clean -dfx +// msbuild windows\\ZeroTierOne.sln +// ''' +// } +// } +// catch (err) { +// currentBuild.result = "FAILURE" +// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Windows (<${env.BUILD_URL}|Open>)" - throw err - } - } +// throw err +// } +// } } -slackSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)" +mattermostSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3807fea --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,37 @@ +ZeroTier One - Network Virtualization Everywhere +Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +See LICENSE.GPL-3 for the full GNU GPL v3 license. + +-- + +You can be released from the requirements of the license by purchasing +a commercial license. Buying such a license is mandatory as soon as you +develop commercial closed-source software that incorporates or links +directly against ZeroTier software without disclosing the source code +of your own application. + +-- + +The above license does not apply to third party code included with or +linked against by ZeroTier software. See the third party code section +of the AUTHORS.md for an index of third party software included in +this software repository. + +Licenses for third party code are all relatively permissive: MIT, +BSD, and public domain. The only exception is the tap-windows driver +which is under the GPLv2, but this is only needed to produce the +binary tap device driver used by the ZeroTier service on Windows. diff --git a/Makefile b/Makefile index 9511862..144225f 100644 --- a/Makefile +++ b/Makefile @@ -22,3 +22,7 @@ ifeq ($(OSTYPE),OpenBSD) ZT_BUILD_PLATFORM=9 include make-bsd.mk endif + +ifeq ($(OSTYPE),NetBSD) + include make-netbsd.mk +endif diff --git a/OFFICIAL-RELEASE-STEPS.md b/OFFICIAL-RELEASE-STEPS.md index d0f42e3..6de3526 100644 --- a/OFFICIAL-RELEASE-STEPS.md +++ b/OFFICIAL-RELEASE-STEPS.md @@ -13,7 +13,6 @@ The version must be incremented in all of the following files: /zerotier-one.spec /debian/changelog /ext/installfiles/mac/ZeroTier One.pkgproj - /ext/installfiles/windows/chocolatey/zerotier-one.nuspec /ext/installfiles/windows/ZeroTier One.aip /windows/WinUI/AboutView.xaml @@ -29,36 +28,6 @@ Mac's easy. Just type: You will need [Packages](http://s.sudre.free.fr/Software/Packages/about.html) and our release signing key in the keychain. -## Linux - -Mount the GPG key for *contact@zerotier.com* and then on an x86_64 box with a recent version of Docker and an Internet connection run: - - make distclean - cd linux-build-farm - ./build.sh - -This will build i386 and x86_64 packages. Now ssh into our build Raspberry Pi and type `make debian` there to build the Raspbian armhf package. Copy it to `debian-jessie/` inside `linux-build-farm` so that it will be included in the repositories we generate. Now generate the YUM and APT repos: - - rm -rf ~/.aptly* - rm -rf /tmp/zt-rpm-repo - ./make-apt-repos.sh - ./make-rpm-repos.sh - -This will require the passphrase for *contact@zerotier.com*. - -The contents of ~/.aptly/public must be published as `debian/` on `download.zerotier.com`. The contents of /tmp/zt-rpm-repo are published as `redhat/` on same. - ## Windows First load the Visual Studio solution and rebuild the UI and ZeroTier One in both x64 and i386 `Release` mode. Then load [Advanced Installer Enterprise](http://www.advancedinstaller.com/), check that the version is correct, and build. The build will fail if any build artifacts are missing, and Windows must have our product singing key (from DigiCert) available to sign the resulting MSI file. The MSI must then be tested on at least a few different CLEAN Windows VMs to ensure that the installer is valid and properly signed. - -*After the MSI is published to download.zerotier.com in the proper RELEASE/#.#.#/dist subfolder for its version* the Chocolatey package must be rebuilt and published. Open a command prompt, change to `ext/installfiles/windows/chocolatey`, and type `choco pack`. Then use `choco push` to push it to Chocolatey (API key required). - - choco pack - choco push zerotier-one.#.#.#.nupkg -s https://chocolatey.org/ - -Note that this does not cover rebuilding the drivers or their containing MSI projects, as this is typically not necessary and they are shipped in binary form in the repository for convenience. - -## iOS, Android - -... no docs here yet since this is done entirely out of band with regular installs. diff --git a/README.md b/README.md index 47bfc87..6fecf2f 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,57 @@ -ZeroTier - A Planetary Ethernet Switch +ZeroTier - Global Area Networking ====== -ZeroTier is an enterprise Ethernet switch for planet Earth. +ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows networked devices and applications to be managed as if the entire world is one data center or cloud region. -It erases the LAN/WAN distinction and makes VPNs, tunnels, proxies, and other kludges arising from the inflexible nature of physical networks obsolete. Everything is encrypted end-to-end and traffic takes the most direct (peer to peer) path available. +It replaces the physical LAN/WAN boundary with a virtual one, allowing devices of any type at any location to be managed as if they all reside in the same cloud region or data center. All traffic is encrypted end-to-end and takes the most direct path available for minimum latency and maximum performance. The goals and design of ZeroTier are inspired by among other things the original [Google BeyondCorp](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/43231.pdf) paper and the [Jericho Forum](https://en.wikipedia.org/wiki/Jericho_Forum). -Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download.shtml). Apps for Android and iOS are available for free in the Google Play and Apple app stores. +Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download/). Apps for Android and iOS are available for free in the Google Play and Apple app stores. ### Getting Started -ZeroTier's basic operation is easy to understand. Devices have 10-digit *ZeroTier addresses* like `89e92ceee5` and networks have 16-digit network IDs like `8056c2e21c000001`. All it takes for a device to join a network is its 16-digit ID, and all it takes for a network to authorize a device is its 10-digit address. Everything else is automatic. +Everything in the ZeroTier world is controlled by two types of identifier: 40-bit/10-digit *ZeroTier addresses* and 64-bit/16-digit *network IDs*. A ZeroTier address identifies a node or "device" (laptop, phone, server, VM, app, etc.) while a network ID identifies a virtual Ethernet network that can be joined by devices. -A "device" in our terminology is any "unit of compute" capable of talking to a network: desktops, laptops, phones, servers, VMs/VPSes, containers, and even user-space applications via our [SDK](https://github.com/zerotier/ZeroTierSDK). +Another way of thinking about it is that ZeroTier addresses are port numbers on a giant planetary-sized smart switch while network IDs are VLANs to which these ports can be assigned. For more details read about VL1 and VL2 in [the ZeroTier manual](https://www.zerotier.com/manual/). -For testing purposes we provide a public virtual network called *Earth* with network ID `8056c2e21c000001`. You can join it with: - - sudo zerotier-cli join 8056c2e21c000001 - -Now wait about 30 seconds and check your system with `ip addr list` or `ifconfig`. You'll see a new interface whose name starts with *zt* and it should quickly get an IPv4 and an IPv6 address. Once you see it get an IP, try pinging `earth.zerotier.net` at `29.209.112.93`. If you've joined Earth from more than one system, try pinging your other machine. If you don't want to belong to a giant Ethernet party line anymore, just type: - - sudo zerotier-cli leave 8056c2e21c000001 - -The *zt* interface will disappear. You're no longer on the network. - -To create networks of your own, you'll need a network controller. ZeroTier One (for desktops and servers) includes controller functionality in its default build that can be configured via its JSON API (see [README.md in controller/](controller/)). ZeroTier provides a hosted solution with a nice web UI and SaaS add-ons at [my.zerotier.com](https://my.zerotier.com/). Basic controller functionality is free for up to 100 devices. +*Network controllers* are ZeroTier nodes that act as access control certificate authorities and configuration managers for virtual networks. The first 40 bits (or 10 digits) of a network ID is the ZeroTier address of its controller. You can create networks with our [hosted controllers](https://my.zerotier.com/) and web UI/API or [host your own](controller/) if you don't mind posting some JSON configuration info or writing a script to do so. ### Project Layout +The base path contains the ZeroTier One service main entry point (`one.cpp`), self test code, makefiles, etc. + - `artwork/`: icons, logos, etc. - `attic/`: old stuff and experimental code that we want to keep around for reference. - `controller/`: the reference network controller implementation, which is built and included by default on desktop and server build targets. - `debian/`: files for building Debian packages on Linux. - `doc/`: manual pages and other documentation. + - `docker/`: Dockerfile to build as a container for containerized Linux systems and Kubernetes clusters. - `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files. - `include/`: include files for the ZeroTier core. - `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.) - `macui/`: a Macintosh menu-bar app for controlling ZeroTier One, written in Objective C. - `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere. - `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets. + - `rule-compiler/`: JavaScript rules language compiler for defining network-level rules. - `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers. - - `tcp-proxy/`: TCP proxy code run by ZeroTier, Inc. to provide TCP fallback (this will die soon!). - `windows/`: Visual Studio solution files, Windows service code for ZeroTier One, and the Windows task bar app UI. -The base path contains the ZeroTier One service main entry point (`one.cpp`), self test code, makefiles, etc. - ### Build and Platform Notes To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/'. - **Mac** - - Xcode command line tools for OSX 10.7 or newer are required. - - Tap device driver kext source is in `ext/tap-mac` and a signed pre-built binary can be found in `ext/bin/tap-mac`. You should not need to build it yourself. It's a fork of [tuntaposx](http://tuntaposx.sourceforge.net) with device names changed to `zt#`, support for a larger MTU, and tun functionality removed. + - Xcode command line tools for OSX 10.8 or newer are required. - **Linux** - - The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. + - The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. (Install `clang` on CentOS 7 as G++ is too old.) - Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line. - - CentOS 7 ships with a version of GCC/G++ that is too old, but a new enough version of CLANG can be found in the *epel* repositories. Type `yum install epel-release` and then `yum install clang` to build there. - **Windows** - - Windows 7 or newer (and equivalent server versions) are supported. This *may* work on Vista but you're on your own there. Windows XP is not supported since it lacks many important network API functions. - - We build with Visual Studio 2015. Older versions may not work with the solution file and project files we ship and may not have new enough C++11 support. - - Pre-built signed Windows drivers are included in `ext/bin/tap-windows-ndis6`. The MSI files found there will install them on 32-bit and 64-bit systems. (These are included in our multi-architecture installer as chained MSIs.) - - Windows builds are more painful in general than other platforms and are for the adventurous. + - Windows 7 or newer is supported. This *may* work on Vista but isn't officially supported there. It will not work on Windows XP. + - We build with Visual Studio 2017. Older versions may not work. Clang or MinGW will also probably work but may require some makefile hacking. - **FreeBSD** - - Tested most recently on FreeBSD-11. Older versions may work but we're not sure. - - GCC/G++ 4.9 and gmake are required. These can be installed from packages or ports. Type `gmake` to build. + - GNU make is required. Type `gmake` to build. - **OpenBSD** - - There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). We're not sure if this can be increased. - - OpenBSD lacks `getifmaddrs` (or any equivalent method) to get interface multicast memberships. As a result multicast will only work on OpenBSD for ARP and NDP (IP/MAC lookup) and not for other purposes. - - Only tested on OpenBSD 6.0. Older versions may not work. - - GCC/G++ 4.9 and gmake are required and can be installed using `pkg_add` or from ports. They get installed in `/usr/local/bin` as `egcc` and `eg++` and our makefile is pre-configured to use them on OpenBSD. + - There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). + - GNU make is required. Type `gmake` to build. Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures. @@ -112,7 +96,7 @@ ZeroTier One peers will automatically locate each other and communicate directly Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours. -If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport. +If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226?pk_campaign=github_ZeroTierOne). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport. If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity. diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 195e888..a781392 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,86 @@ ZeroTier Release Notes ====== +# 2019-08-12 -- Version 1.4.2 + + * Fix high CPU use bug on some platforms + * Fix issues with PostgreSQL controller DB (only affects Central) + * Restore backward compatibility with MacOS versions prior to 10.13 + +# 2019-07-29 -- Version 1.4.0 + +### Major Changes + + * Mac version no longer requires a kernel extension, instead making use of the [feth interfaces](https://apple.stackexchange.com/questions/337715/fake-ethernet-interfaces-feth-if-fake-anyone-ever-seen-this). + * Added support for concurrent multipath (multiple paths at once) with traffic weighting by link quality and faster recovery from lost links. + * Added under-the-hood support for QoS (not yet exposed) that will eventually be configurable via our rules engine. + +### Minor Changes and Bug Fixes + + * Experimental controller DB driver for [LF](https://github.com/zerotier/lf) to store network controller data (LFDB.cpp / LFDB.hpp). + * Modified credential push and direct path push timings and algorithms to somewhat reduce "chattiness" of the protocol when idle. More radical background overhead reductions will have to wait for the 2.x line. + * Removed our beta/half-baked integration of Central with the Windows UI. We're going to do a whole new UI of some kind in the future at least for Windows and Mac. + * Fixed stack overflow issues on Linux versions using musl libc. + * Fixed some alignment problems reported on ARM and ARM64, but some reports we could not reproduce so please report any issues with exact chip, OS/distro, and ZeroTier version in use. + * Fixed numerous other small issues and bugs such as ARM alignment issues causing crashes on some devices. + * Windows now sets the adapter name such that it is consistent in both the Windows UI and command line utilities. + +# 2018-07-27 -- Version 1.2.12 + + * Fixed a bug that caused exits to take a long time on Mac due to huge numbers of redundant attempts to delete managed routes. + * Fixed a socket limit problem on Windows that caused the ZeroTier service to run out of sockets, causing the UI and CLI to be unable to access the API. + * Fixed a threading bug in the ZeroTier Core, albeit one that never manifested on the regular ZeroTier One service/client. + * Fixed a bug that could cause the service to crash if an authorized local client accessed an invalid URL via the control API. (Not exploitable since you needed admin access anyway.) + +# 2018-05-08 -- Version 1.2.10 + + * Fix bug loading `moons.d/` files for federated root operation. + * Fix compile problem with ZT_DEBUG on some versions of `clang` + * Fix slow network startup bug related to loading of `networks.d/` cache files + +# 2018-04-27 -- Version 1.2.8 + + * Linux version once again builds with PIE (position independent executable) flags + * Fixed bug in zerotier-idtool file sign and verify + * Fixed minor OSX app typo + * Merged alpha NetBSD support (mostly untested, so YMMV) + * Merged several minor typo and one-liner bug fixes + +# 2018-04-17 -- Version 1.2.6 + + * Features and Core Improvements + * Path selection has been overhauled to improve path stability, simplify code, and prepare for multi-path and trunking in the next major release. + * This version introduces remote tracing for remote diagnostics. Network controllers can set a node (usually the controller itself) to receive remote tracing events from all members of the network or from select members. Events are only sent if they pertain to a given network for security reasons. + * Multicast replication can now be done by designated multicast replicators on a network (flagged as such at the controller) rather than by the sender. Most users won't want this, but it's useful for specialized use cases on hub-and-spoke networks and for low-power devices. + * Cryptographic performance improvements on several platforms. + * Multithreaded performance improvements throughout the code base, including the use of an inline lightweight spinlock for low-contention resources. + * Bugs fixed + * Disappearing routes on Mac (GitHub issue #600) + * Route flapping and path instability in some dual-stack V4/V6 networks + * Blacklist (in local.conf) doesn't work reliably (GitHub issue #656) + * Connection instabilities due to unsigned integer overflows in timing comparisons (use int64_t instead of uint64_t) + * Binaries don't run on some older or lower-end 32-bit ARM chips (build problem) + * ARM NEON crypto code crashes (build problem) + * Fixed some lock ordering issues revealed by "valgrind" tool + * The "zerotier-idtool" command could not be accessed from "zerotier-one" via command line switch + * Leaking sockets on some platforms when uPnP/NAT-PMP is enabled + * Fixed two very rare multithreading issues that were only observed on certain systems + * Platform-Specific Changes + * MacOS + * Installer now loads the kernel extension right away so that High Sierra users will see the prompt to authorize it. This is done in the "Security & Privacy" preference pane and must be done directly on the console (not via remote desktop). On High Sierra and newer kexts must be authorized at the console via security settings system preferences pane. + * Windows + * The Windows installer should now install the driver without requiring a special prompt in most cases. This should make it easier for our packages to be accepted into and updated in the Chocolatey repository and should make it easier to perform remote installs across groups of machines using IT management and provisioning tools. + * The Windows official packages are now signed with an EV certificate (with hardware key). + * The Windows UI can now log into ZeroTier Central and join networks via the Central API. + * The `zerotier-idtool` command should now work on Windows without ugly hacks. + * Upgraded the installer version. + * Made a few changes to hopefully fix sporadic "will not uninstall" problems, though we cannot duplicate these issues ourselves. + * Linux + * Device names are now generated deterministically based on network IDs for all newly joined networks. + * Android + * Multicast now works on Android in most cases! Android apps can send and receive multicast and subscribe to multicast group IPs. Note that in some cases the app must bind to the specific correct interface for this to work. + * IPv6 can be disabled in UI for cases where it causes problems. + # 2017-04-20 -- Version 1.2.4 * Managed routes are now only bifurcated for the default route. This is a change in behavior, though few people will probably notice. Bifurcating all managed routes was causing more trouble than it was worth for most users. @@ -29,7 +109,7 @@ The largest new feature in 1.2.0, and the product of many months of work, is our Rules allow you to filter packets on your network and vector traffic to security observers. Security observation can be performed in-band using REDIRECT or out of band using TEE. -Tags and capabilites provide advanced methods for implementing fine grained permission structures and micro-segmentation schemes without bloating the size and complexity of your rules table. +Tags and capabilities provide advanced methods for implementing fine grained permission structures and micro-segmentation schemes without bloating the size and complexity of your rules table. See the [rules engine announcement blog post](https://www.zerotier.com/blog/?p=927) for an in-depth discussion of theory and implementation. The [manual](https://www.zerotier.com/manual.shtml) contains detailed information on rule, tag, and capability use, and the `rule-compiler/` subfolder of the ZeroTier source tree contains a JavaScript function to compile rules in our human-readable rule definition language into rules suitable for import into a network controller. (ZeroTier Central uses this same script to compile rules on [my.zerotier.com](https://my.zerotier.com/).) @@ -112,7 +192,7 @@ A special kind of public network called an ad-hoc network may be accessed by joi | Start of port range (hex) Reserved ZeroTier address prefix indicating a controller-less network -Ad-hoc networks are public (no access control) networks that have no network controller. Instead their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6 UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6 addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN (connection open) packets are only allowed to desintation ports within the encoded range. +Ad-hoc networks are public (no access control) networks that have no network controller. Instead their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6 UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6 addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN (connection open) packets are only allowed to destination ports within the encoded range. For example `ff00160016000000` is an ad-hoc network allowing only SSH, while `ff0000ffff000000` is an ad-hoc network allowing any UDP or TCP port. @@ -127,7 +207,7 @@ If you have data in an old SQLite3 controller we've included a NodeJS script in ## Major Bug Fixes in 1.2.0 * **The Windows HyperV 100% CPU bug is FINALLY DEAD**: This long-running problem turns out to have been an issue with Windows itself, but one we were triggering by placing invalid data into the Windows registry. Microsoft is aware of the issue but we've also fixed the triggering problem on our side. ZeroTier should now co-exist quite well with HyperV and should now be able to be bridged with a HyperV virtual switch. - * **Segmenation faults on musl-libc based Linux systems**: Alpine Linux and some embedded Linux systems that use musl libc (a minimal libc) experienced segmentation faults. These were due to a smaller default stack size. A work-around that sets the stack size for new threads has been added. + * **Segmentation faults on musl-libc based Linux systems**: Alpine Linux and some embedded Linux systems that use musl libc (a minimal libc) experienced segmentation faults. These were due to a smaller default stack size. A work-around that sets the stack size for new threads has been added. * **Windows firewall blocks local JSON API**: On some Windows systems the firewall likes to block 127.0.0.1:9993 for mysterious reasons. This is now fixed in the installer via the addition of another firewall exemption rule. * **UI crash on embedded Windows due to missing fonts**: The MSI installer now ships fonts and will install them if they are not present, so this should be fixed. diff --git a/artwork/AppIcon_1024x1024.png b/artwork/AppIcon_1024x1024.png new file mode 100644 index 0000000..c423c4f Binary files /dev/null and b/artwork/AppIcon_1024x1024.png differ diff --git a/artwork/AppIcon_20x20.png b/artwork/AppIcon_20x20.png new file mode 100644 index 0000000..bb10b47 Binary files /dev/null and b/artwork/AppIcon_20x20.png differ diff --git a/artwork/AppIcon_60x60.png b/artwork/AppIcon_60x60.png new file mode 100644 index 0000000..bb46ae7 Binary files /dev/null and b/artwork/AppIcon_60x60.png differ diff --git a/artwork/AppIcon_90x90.png b/artwork/AppIcon_90x90.png new file mode 100644 index 0000000..0a618bb Binary files /dev/null and b/artwork/AppIcon_90x90.png differ diff --git a/artwork/ZeroTierIcon32x32.png b/artwork/ZeroTierIcon32x32.png new file mode 100644 index 0000000..24ff0a1 Binary files /dev/null and b/artwork/ZeroTierIcon32x32.png differ diff --git a/attic/OSXEthernetTap.cpp.pcap-with-bridge-test b/attic/OSXEthernetTap.cpp.pcap-with-bridge-test deleted file mode 100644 index baae0a4..0000000 --- a/attic/OSXEthernetTap.cpp.pcap-with-bridge-test +++ /dev/null @@ -1,650 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? -struct prf_ra { - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; -} prf_ra; - -#include -#include - -// These are KERNEL_PRIVATE... why? -#ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ -#endif -#ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ -#endif - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- -// This source is from: -// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt -// It's here because OSX 10.6 does not have this convenience function. - -#define SALIGN (sizeof(uint32_t) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ -(SALIGN + 1)) -#define MAX_SYSCTL_TRY 5 -#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) - -/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from */ -/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ -//#define DARWIN_COMPAT - -//#ifdef DARWIN_COMPAT -#define GIM_SYSCTL_MIB NET_RT_IFLIST2 -#define GIM_RTM_ADDR RTM_NEWMADDR2 -//#else -//#define GIM_SYSCTL_MIB NET_RT_IFMALIST -//#define GIM_RTM_ADDR RTM_NEWMADDR -//#endif - -// Not in 10.6 includes so use our own -struct _intl_ifmaddrs { - struct _intl_ifmaddrs *ifma_next; - struct sockaddr *ifma_name; - struct sockaddr *ifma_addr; - struct sockaddr *ifma_lladdr; -}; - -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) -{ - int icnt = 1; - int dcnt = 0; - int ntry = 0; - size_t len; - size_t needed; - int mib[6]; - int i; - char *buf; - char *data; - char *next; - char *p; - struct ifma_msghdr2 *ifmam; - struct _intl_ifmaddrs *ifa, *ift; - struct rt_msghdr *rtm; - struct sockaddr *sa; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = GIM_SYSCTL_MIB; - mib[5] = 0; /* no flags */ - do { - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return (-1); - if ((buf = (char *)malloc(needed)) == NULL) - return (-1); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { - free(buf); - return (-1); - } - free(buf); - buf = NULL; - } - } while (buf == NULL); - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - icnt++; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - dcnt += len; - p += len; - } - break; - } - } - - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); - } - - ifa = (struct _intl_ifmaddrs *)(void *)data; - data += sizeof(struct _intl_ifmaddrs) * icnt; - - memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); - ift = ifa; - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - switch (i) { - case RTAX_GATEWAY: - ift->ifma_lladdr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFP: - ift->ifma_name = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFA: - ift->ifma_addr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - default: - data += len; - break; - } - p += len; - } - ift->ifma_next = ift + 1; - ift = ift->ifma_next; - break; - } - } - - free(buf); - - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); -} - -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) -{ - free(ifmp); -} - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "../node/Dictionary.hpp" -#include "OSUtils.hpp" -#include "OSXEthernetTap.hpp" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) -{ - struct in6_ndireq nd; - struct in6_ifreq ifr; - - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return false; - - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); - - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return false; - } - - unsigned long oldFlags = (unsigned long)nd.ndi.flags; - - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return false; - } - } - - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return false; - } - - close(s); - return true; -} - -namespace ZeroTier { - -static std::set globalDeviceNames; -static Mutex globalTapCreateLock; - -OSXEthernetTap::OSXEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _pcap((void *)0), - _nwid(nwid), - _mac(mac), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _enabled(true) -{ - char errbuf[PCAP_ERRBUF_SIZE]; - char devname[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; - - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); - - Mutex::Lock _gl(globalTapCreateLock); - - std::string desiredDevice; - Dictionary devmap; - { - std::string devmapbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { - devmap.fromString(devmapbuf); - desiredDevice = devmap.get(nwids,""); - } - } - - if ((desiredDevice.length() >= 9)&&(desiredDevice.substr(0,6) == "bridge")) { - // length() >= 9 matches bridge### or bridge#### - _dev = desiredDevice; - } else { - if (globalDeviceNames.size() >= (10000 - 128)) // sanity check... this would be nuts - throw std::runtime_error("too many devices!"); - unsigned int pseudoBridgeNo = (unsigned int)((nwid ^ (nwid >> 32)) % (10000 - 128)) + 128; // range: bridge128 to bridge9999 - sprintf(devname,"bridge%u",pseudoBridgeNo); - while (globalDeviceNames.count(std::string(devname)) > 0) { - ++pseudoBridgeNo; - if (pseudoBridgeNo > 9999) - pseudoBridgeNo = 64; - sprintf(devname,"bridge%u",pseudoBridgeNo); - } - _dev = devname; - } - - // Configure MAC address and MTU, bring interface up - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"create",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode != 0) - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } else throw std::runtime_error("unable to fork()"); - Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode != 0) - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } else throw std::runtime_error("unable to fork()"); - - _setIpv6Stuff(_dev.c_str(),true,false); - - _pcap = (void *)pcap_create(_dev.c_str(),errbuf); - if (!_pcap) { - cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } - throw std::runtime_error((std::string("pcap_create() on new bridge device failed: ") + errbuf).c_str()); - } - pcap_set_promisc(reinterpret_cast(_pcap),1); - pcap_set_timeout(reinterpret_cast(_pcap),120000); - pcap_set_immediate_mode(reinterpret_cast(_pcap),1); - if (pcap_set_buffer_size(reinterpret_cast(_pcap),1024 * 1024 * 16) != 0) // 16MB - fprintf(stderr,"WARNING: pcap_set_buffer_size() failed!\n"); - if (pcap_set_snaplen(reinterpret_cast(_pcap),4096) != 0) - fprintf(stderr,"WARNING: pcap_set_snaplen() failed!\n"); - if (pcap_activate(reinterpret_cast(_pcap)) != 0) { - pcap_close(reinterpret_cast(_pcap)); - cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } - throw std::runtime_error("pcap_activate() on new bridge device failed."); - } - - globalDeviceNames.insert(_dev); - - devmap[nwids] = _dev; - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmap.toString()); - - _thread = Thread::start(this); -} - -OSXEthernetTap::~OSXEthernetTap() -{ - _enabled = false; - - Mutex::Lock _gl(globalTapCreateLock); - globalDeviceNames.erase(_dev); - - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode == 0) { - // Destroying the interface nukes pcap and terminates the thread. - Thread::join(_thread); - } - } - - pcap_close(reinterpret_cast(_pcap)); -} - -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) -{ - long cpid = (long)vfork(); - if (cpid == 0) { - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value -} - -bool OSXEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - std::vector allIps(ips()); - if (std::binary_search(allIps.begin(),allIps.end(),ip)) - return true; - - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) - break; - } - } - - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } // else return false... - - return false; -} - -bool OSXEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return true; - std::vector allIps(ips()); - if (!std::binary_search(allIps.begin(),allIps.end(),ip)) { - if (___removeIp(_dev,ip)) - return true; - } - return false; -} - -std::vector OSXEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - std::unique(r.begin(),r.end()); - - return r; -} - -void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[4096]; - if ((len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - int r = pcap_inject(reinterpret_cast(_pcap),putBuf,len); - if (r <= 0) { - printf("%s: pcap_inject() failed\n",_dev.c_str()); - return; - } - printf("%s: inject %s -> %s etherType==%u len=%u r==%d\n",_dev.c_str(),from.toString().c_str(),to.toString().c_str(),etherType,len,r); - } -} - -std::string OSXEthernetTap::deviceName() const -{ - return _dev; -} - -void OSXEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void OSXEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - - struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; - if (!_intl_getifmaddrs(&ifmap)) { - struct _intl_ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -static void _pcapHandler(u_char *ptr,const struct pcap_pkthdr *hdr,const u_char *data) -{ - OSXEthernetTap *tap = reinterpret_cast(ptr); - if (hdr->caplen > 14) { - MAC to(data,6); - MAC from(data + 6,6); - if (from == tap->_mac) { - unsigned int etherType = ntohs(((const uint16_t *)data)[6]); - printf("%s: %s -> %s etherType==%u len==%u\n",tap->_dev.c_str(),from.toString().c_str(),to.toString().c_str(),etherType,(unsigned int)hdr->caplen); - // TODO: VLAN support - tap->_handler(tap->_arg,tap->_nwid,from,to,etherType,0,(const void *)(data + 14),hdr->len - 14); - } - } -} - -void OSXEthernetTap::threadMain() - throw() -{ - pcap_loop(reinterpret_cast(_pcap),-1,&_pcapHandler,reinterpret_cast(this)); -} - -} // namespace ZeroTier diff --git a/attic/OSXEthernetTap.cpp.utun-work-in-progress b/attic/OSXEthernetTap.cpp.utun-work-in-progress deleted file mode 100644 index f40483e..0000000 --- a/attic/OSXEthernetTap.cpp.utun-work-in-progress +++ /dev/null @@ -1,831 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? -struct prf_ra { - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; -} prf_ra; - -#include -#include - -// These are KERNEL_PRIVATE... why? -#ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ -#endif -#ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ -#endif - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- -// This source is from: -// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt -// It's here because OSX 10.6 does not have this convenience function. - -#define SALIGN (sizeof(uint32_t) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ -(SALIGN + 1)) -#define MAX_SYSCTL_TRY 5 -#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) - -/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from */ -/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ -//#define DARWIN_COMPAT - -//#ifdef DARWIN_COMPAT -#define GIM_SYSCTL_MIB NET_RT_IFLIST2 -#define GIM_RTM_ADDR RTM_NEWMADDR2 -//#else -//#define GIM_SYSCTL_MIB NET_RT_IFMALIST -//#define GIM_RTM_ADDR RTM_NEWMADDR -//#endif - -// Not in 10.6 includes so use our own -struct _intl_ifmaddrs { - struct _intl_ifmaddrs *ifma_next; - struct sockaddr *ifma_name; - struct sockaddr *ifma_addr; - struct sockaddr *ifma_lladdr; -}; - -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) -{ - int icnt = 1; - int dcnt = 0; - int ntry = 0; - size_t len; - size_t needed; - int mib[6]; - int i; - char *buf; - char *data; - char *next; - char *p; - struct ifma_msghdr2 *ifmam; - struct _intl_ifmaddrs *ifa, *ift; - struct rt_msghdr *rtm; - struct sockaddr *sa; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = GIM_SYSCTL_MIB; - mib[5] = 0; /* no flags */ - do { - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return (-1); - if ((buf = (char *)malloc(needed)) == NULL) - return (-1); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { - free(buf); - return (-1); - } - free(buf); - buf = NULL; - } - } while (buf == NULL); - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - icnt++; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - dcnt += len; - p += len; - } - break; - } - } - - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); - } - - ifa = (struct _intl_ifmaddrs *)(void *)data; - data += sizeof(struct _intl_ifmaddrs) * icnt; - - memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); - ift = ifa; - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - switch (i) { - case RTAX_GATEWAY: - ift->ifma_lladdr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFP: - ift->ifma_name = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFA: - ift->ifma_addr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - default: - data += len; - break; - } - p += len; - } - ift->ifma_next = ift + 1; - ift = ift->ifma_next; - break; - } - } - - free(buf); - - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); -} - -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) -{ - free(ifmp); -} - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "../node/Dictionary.hpp" -#include "Arp.hpp" -#include "OSUtils.hpp" -#include "OSXEthernetTap.hpp" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) -{ - struct in6_ndireq nd; - struct in6_ifreq ifr; - - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return false; - - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); - - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return false; - } - - unsigned long oldFlags = (unsigned long)nd.ndi.flags; - - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return false; - } - } - - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return false; - } - - close(s); - return true; -} - -// Create an OSX-native utun device (utun# where # is desiredNumber) -// Adapted from public domain utun example code by Jonathan Levin -static int _make_utun(int desiredNumber) -{ - struct sockaddr_ctl sc; - struct ctl_info ctlInfo; - struct ifreq ifr; - - memset(&ctlInfo, 0, sizeof(ctlInfo)); - if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= sizeof(ctlInfo.ctl_name)) { - return -1; - } - - int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); - if (fd == -1) - return -1; - if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) { - close(fd); - return -1; - } - - sc.sc_id = ctlInfo.ctl_id; - sc.sc_len = sizeof(sc); - sc.sc_family = AF_SYSTEM; - sc.ss_sysaddr = AF_SYS_CONTROL; - sc.sc_unit = desiredNumber + 1; - - if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) { - close(fd); - return -1; - } - - memset(&ifr,0,sizeof(ifr)); - sprintf(ifr.ifr_name,"utun%d",desiredNumber); - if (ioctl(fd,SIOCGIFFLAGS,(void *)&ifr) < 0) { - printf("SIOCGIFFLAGS failed\n"); - } - ifr.ifr_flags &= ~IFF_POINTOPOINT; - if (ioctl(fd,SIOCSIFFLAGS,(void *)&ifr) < 0) { - printf("clear IFF_POINTOPOINT failed\n"); - } - - return fd; -} - -namespace ZeroTier { - -static long globalTapsRunning = 0; -static Mutex globalTapCreateLock; - -OSXEthernetTap::OSXEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _arp((Arp *)0), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _fd(0), - _utun(false), - _enabled(true) -{ - char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; - struct stat stattmp; - - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); - - Mutex::Lock _gl(globalTapCreateLock); - - // Read remembered previous device name, if any -- we'll try to reuse - Dictionary devmap; - std::string desiredDevice; - { - std::string devmapbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmapbuf)) { - devmap.fromString(devmapbuf); - desiredDevice = devmap.get(nwids,""); - } - } - - if (::stat((_homePath + ZT_PATH_SEPARATOR_S + "tap.kext").c_str(),&stattmp) == 0) { - // Try to init kext if it's there, otherwise revert to utun mode - - if (::stat("/dev/zt0",&stattmp)) { - long kextpid = (long)vfork(); - if (kextpid == 0) { - ::chdir(homePath); - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - ::usleep(500); // give tap device driver time to start up and try again - if (::stat("/dev/zt0",&stattmp)) - _utun = true; - } - - if (!_utun) { - // See if we can re-use the last device we had. - bool recalledDevice = false; - if (desiredDevice.length() > 2) { - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",desiredDevice.c_str()); - if (stat(devpath,&stattmp) == 0) { - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - _dev = desiredDevice; - recalledDevice = true; - } - } - } - - // Open the first unused tap device if we didn't recall a previous one. - if (!recalledDevice) { - for(int i=0;i<64;++i) { - Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i); - if (stat(devpath,&stattmp)) { - _utun = true; - break; - } - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - char foo[16]; - Utils::snprintf(foo,sizeof(foo),"zt%d",i); - _dev = foo; - break; - } - } - } - if (_fd <= 0) - _utun = true; - } - } else { - _utun = true; - } - - if (_utun) { - // Use OSX built-in utun device if kext is not available or doesn't work - - int utunNo = 0; - - if ((desiredDevice.length() > 4)&&(desiredDevice.substr(0,4) == "utun")) { - utunNo = Utils::strToInt(desiredDevice.substr(4).c_str()); - if (utunNo >= 0) - _fd = _make_utun(utunNo); - } - - if (_fd <= 0) { - // Start at utun8 to leave lower utuns unused since other stuff might - // want them -- OpenVPN, cjdns, etc. I'm not sure if those are smart - // enough to scan upward like this. - for(utunNo=8;utunNo<=256;++utunNo) { - if ((_fd = _make_utun(utunNo)) > 0) - break; - } - } - - if (_fd <= 0) - throw std::runtime_error("unable to find/load ZeroTier tap driver OR use built-in utun driver in OSX; permission or system problem or too many open devices?"); - - Utils::snprintf(devpath,sizeof(devpath),"utun%d",utunNo); - _dev = devpath; - - // Configure address and bring it up - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure activating utun interface"); - } - } - - } else { - // Use our ZeroTier OSX tun/tap driver for zt# Ethernet tap device - - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } - - // Configure MAC address and MTU, bring interface up - Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } - - _setIpv6Stuff(_dev.c_str(),true,false); - } - - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); - - ::pipe(_shutdownSignalPipe); - - ++globalTapsRunning; - - devmap[nwids] = _dev; - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),devmap.toString()); - - _thread = Thread::start(this); -} - -OSXEthernetTap::~OSXEthernetTap() -{ - Mutex::Lock _gl(globalTapCreateLock); - - ::write(_shutdownSignalPipe[1],(const void *)this,1); // writing a byte causes thread to exit - Thread::join(_thread); - - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - - if (_utun) { - delete _arp; - } else { - if (--globalTapsRunning <= 0) { - globalTapsRunning = 0; // sanity check -- should not be possible - - char tmp[16384]; - sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext"); - long kextpid = (long)vfork(); - if (kextpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - } - } -} - -void OSXEthernetTap::setEnabled(bool en) -{ - _enabled = en; - // TODO: interface status change -} - -bool OSXEthernetTap::enabled() const -{ - return _enabled; -} - -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) -{ - long cpid = (long)vfork(); - if (cpid == 0) { - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value -} - -bool OSXEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - std::vector allIps(ips()); - if (std::binary_search(allIps.begin(),allIps.end(),ip)) - return true; - - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) - break; - } - } - - if (_utun) { - long cpid = (long)vfork(); - if (cpid == 0) { - if (ip.ss_family == AF_INET6) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet6",ip.toString().c_str(),"alias",(const char *)0); - } else { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.toString().c_str(),ip.toIpString().c_str(),"alias",(const char *)0); - } - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - - if (exitcode == 0) { - if (ip.ss_family == AF_INET) { - // Add route to network over tun for IPv4 -- otherwise it behaves - // as a simple point to point tunnel instead of a true route. - cpid = (long)vfork(); - if (cpid == 0) { - ::close(STDERR_FILENO); - ::close(STDOUT_FILENO); - ::execl("/sbin/route","/sbin/route","add",ip.network().toString().c_str(),ip.toIpString().c_str(),(const char *)0); - ::exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - } else return true; - } - } - } else { - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - } - - return false; -} - -bool OSXEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return true; - std::vector allIps(ips()); - if (!std::binary_search(allIps.begin(),allIps.end(),ip)) { - if (___removeIp(_dev,ip)) - return true; - } - return false; -} - -std::vector OSXEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - std::unique(r.begin(),r.end()); - - return r; -} - -void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[4096]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } -} - -std::string OSXEthernetTap::deviceName() const -{ - return _dev; -} - -void OSXEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void OSXEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - - struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; - if (!_intl_getifmaddrs(&ifmap)) { - struct _intl_ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -void OSXEthernetTap::threadMain() - throw() -{ - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; - - Thread::sleep(500); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; - - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; - - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; - - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } - - r = 0; - } - } - } - } -} - -} // namespace ZeroTier diff --git a/attic/OSXEthernetTap.hpp.pcap-with-bridge-test b/attic/OSXEthernetTap.hpp.pcap-with-bridge-test deleted file mode 100644 index 33f1948..0000000 --- a/attic/OSXEthernetTap.hpp.pcap-with-bridge-test +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_OSXETHERNETTAP_HPP -#define ZT_OSXETHERNETTAP_HPP - -#include -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/MAC.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MulticastGroup.hpp" - -#include "Thread.hpp" - -namespace ZeroTier { - -/** - * OSX Ethernet tap using ZeroTier kernel extension zt# devices - */ -class OSXEthernetTap -{ -public: - OSXEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - ~OSXEthernetTap(); - - inline void setEnabled(bool en) { _enabled = en; } - inline bool enabled() const { return _enabled; } - bool addIp(const InetAddress &ip); - bool removeIp(const InetAddress &ip); - std::vector ips() const; - void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - std::string deviceName() const; - void setFriendlyName(const char *friendlyName); - void scanMulticastGroups(std::vector &added,std::vector &removed); - - void threadMain() - throw(); - - // Private members of OSXEthernetTap have public visibility to be accessable - // from an internal bounce function; don't modify directly. - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - void *_pcap; // pcap_t * - uint64_t _nwid; - MAC _mac; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/README.md b/attic/README.md deleted file mode 100644 index 768bccd..0000000 --- a/attic/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Retired Code and Miscellaneous Junk -====== - -This directory is for old code that isn't used but we don't want to lose track of, and for anything else random like debug scripts. diff --git a/attic/big-http-test/2015-11-10_01_50000.out.xz b/attic/big-http-test/2015-11-10_01_50000.out.xz deleted file mode 100644 index d3e2a66..0000000 Binary files a/attic/big-http-test/2015-11-10_01_50000.out.xz and /dev/null differ diff --git a/attic/big-http-test/2015-11-10_02_50000.out.xz b/attic/big-http-test/2015-11-10_02_50000.out.xz deleted file mode 100644 index 0154da7..0000000 Binary files a/attic/big-http-test/2015-11-10_02_50000.out.xz and /dev/null differ diff --git a/attic/big-http-test/2015-11-10_03_12500_ec2-east-only.out.xz b/attic/big-http-test/2015-11-10_03_12500_ec2-east-only.out.xz deleted file mode 100644 index 3ae3555..0000000 Binary files a/attic/big-http-test/2015-11-10_03_12500_ec2-east-only.out.xz and /dev/null differ diff --git a/attic/big-http-test/Dockerfile b/attic/big-http-test/Dockerfile deleted file mode 100644 index e19b3fe..0000000 --- a/attic/big-http-test/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM centos:latest - -MAINTAINER https://www.zerotier.com/ - -EXPOSE 9993/udp - -ADD nodesource-el.repo /etc/yum.repos.d/nodesource-el.repo -RUN yum -y update && yum install -y nodejs && yum clean all - -RUN mkdir -p /var/lib/zerotier-one -RUN mkdir -p /var/lib/zerotier-one/networks.d -RUN touch /var/lib/zerotier-one/networks.d/ffffffffffffffff.conf - -ADD package.json / -RUN npm install - -ADD zerotier-one / -RUN chmod a+x /zerotier-one - -ADD agent.js / -ADD docker-main.sh / -RUN chmod a+x /docker-main.sh - -CMD ["./docker-main.sh"] diff --git a/attic/big-http-test/README.md b/attic/big-http-test/README.md deleted file mode 100644 index 23a9560..0000000 --- a/attic/big-http-test/README.md +++ /dev/null @@ -1,12 +0,0 @@ -HTTP one-to-all test -====== - -*This is really internal use code. You're free to test it out but expect to do some editing/tweaking to make it work. We used this to run some massive scale tests of our new geo-cluster-based root server infrastructure prior to taking it live.* - -Before using this code you will want to edit agent.js to change SERVER_HOST to the IP address of where you will run server.js. This should typically be an open Internet IP, since this makes reporting not dependent upon the thing being tested. Also note that this thing does no security of any kind. It's designed for one-off tests run over a short period of time, not to be anything that runs permanently. You will also want to edit the Dockerfile if you want to build containers and change the network ID to the network you want to run tests over. - -This code can be deployed across a large number of VMs or containers to test and benchmark HTTP traffic within a virtual network at scale. The agent acts as a server and can query other agents, while the server collects agent data and tells agents about each other. It's designed to use RFC4193-based ZeroTier IPv6 addresses within the cluster, which allows the easy provisioning of a large cluster without IP conflicts. - -The Dockerfile builds an image that launches the agent. The image must be "docker run" with "--device=/dev/net/tun --privileged" to permit it to open a tun/tap device within the container. (Unfortunately CAP_NET_ADMIN may not work due to a bug in Docker and/or Linux.) You can run a bunch with a command like: - - for ((n=0;n<10;n++)); do docker run --device=/dev/net/tun --privileged -d zerotier/http-test; done diff --git a/attic/big-http-test/agent.js b/attic/big-http-test/agent.js deleted file mode 100644 index 9ab2e01..0000000 --- a/attic/big-http-test/agent.js +++ /dev/null @@ -1,196 +0,0 @@ -// ZeroTier distributed HTTP test agent - -// --------------------------------------------------------------------------- -// Customizable parameters: - -// Time between startup and first test attempt -var TEST_STARTUP_LAG = 10000; - -// Maximum interval between test attempts (actual timing is random % this) -var TEST_INTERVAL_MAX = (60000 * 10); - -// Test timeout in ms -var TEST_TIMEOUT = 30000; - -// Where should I get other agents' IDs and POST results? -var SERVER_HOST = '52.26.196.147'; -var SERVER_PORT = 18080; - -// Which port do agents use to serve up test data to each other? -var AGENT_PORT = 18888; - -// Payload size in bytes -var PAYLOAD_SIZE = 5000; - -// --------------------------------------------------------------------------- - -var ipaddr = require('ipaddr.js'); -var os = require('os'); -var http = require('http'); -var async = require('async'); - -var express = require('express'); -var app = express(); - -// Find our ZeroTier-assigned RFC4193 IPv6 address -var thisAgentId = null; -var interfaces = os.networkInterfaces(); -if (!interfaces) { - console.error('FATAL: os.networkInterfaces() failed.'); - process.exit(1); -} -for(var ifname in interfaces) { - var ifaddrs = interfaces[ifname]; - if (Array.isArray(ifaddrs)) { - for(var i=0;i 1) { - - var target = agents[Math.floor(Math.random() * agents.length)]; - while (target === thisAgentId) - target = agents[Math.floor(Math.random() * agents.length)]; - - var testRequest = null; - var timeoutId = null; - timeoutId = setTimeout(function() { - if (testRequest !== null) - testRequest.abort(); - timeoutId = null; - },TEST_TIMEOUT); - var startTime = Date.now(); - - testRequest = http.get({ - host: agentIdToIp(target), - port: AGENT_PORT, - path: '/' - },function(res) { - var bytes = 0; - res.on('data',function(chunk) { bytes += chunk.length; }); - res.on('end',function() { - lastTestResult = { - source: thisAgentId, - target: target, - time: (Date.now() - startTime), - bytes: bytes, - timedOut: (timeoutId === null), - error: null - }; - if (timeoutId !== null) - clearTimeout(timeoutId); - return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1); - }); - }).on('error',function(e) { - lastTestResult = { - source: thisAgentId, - target: target, - time: (Date.now() - startTime), - bytes: 0, - timedOut: (timeoutId === null), - error: e.toString() - }; - if (timeoutId !== null) - clearTimeout(timeoutId); - return setTimeout(doTest,Math.round(Math.random() * TEST_INTERVAL_MAX) + 1); - }); - - } else { - return setTimeout(doTest,1000); - } - - }); - }).on('error',function(e) { - console.log('POST failed: '+e.toString()); - return setTimeout(doTest,1000); - }); - if (lastTestResult !== null) { - submit.write(JSON.stringify(lastTestResult)); - lastTestResult = null; - } - submit.end(); -}; - -// Agents just serve up a test payload -app.get('/',function(req,res) { return res.status(200).send(payload); }); - -var expressServer = app.listen(AGENT_PORT,function () { - // Start timeout-based loop - setTimeout(doTest(),TEST_STARTUP_LAG); -}); diff --git a/attic/big-http-test/big-test-kill.sh b/attic/big-http-test/big-test-kill.sh deleted file mode 100755 index fa7f3cc..0000000 --- a/attic/big-http-test/big-test-kill.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Kills all running Docker containers on all big-test-hosts - -export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin - -pssh -h big-test-hosts -x '-t -t' -i -OUserKnownHostsFile=/dev/null -OStrictHostKeyChecking=no -t 0 -p 256 "sudo docker ps -aq | xargs -r sudo docker rm -f" - -exit 0 diff --git a/attic/big-http-test/big-test-start.sh b/attic/big-http-test/big-test-start.sh deleted file mode 100755 index 2411eed..0000000 --- a/attic/big-http-test/big-test-start.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# More than 500 container seems to result in a lot of sporadic failures, probably due to Linux kernel scaling issues with virtual network ports -# 250 with a 16GB RAM VM like Amazon m4.xlarge seems good -NUM_CONTAINERS=250 -CONTAINER_IMAGE=zerotier/http-test -SCALE_UP_DELAY=10 - -export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin - -pssh -h big-test-hosts -x '-t -t' -i -OUserKnownHostsFile=/dev/null -OStrictHostKeyChecking=no -t 0 -p 256 "sudo sysctl -w net.netfilter.nf_conntrack_max=262144 ; for ((n=0;n<$NUM_CONTAINERS;n++)); do sudo docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep $SCALE_UP_DELAY; done" - -exit 0 diff --git a/attic/big-http-test/crunch-results.js b/attic/big-http-test/crunch-results.js deleted file mode 100644 index 50e5c49..0000000 --- a/attic/big-http-test/crunch-results.js +++ /dev/null @@ -1,65 +0,0 @@ -// -// Pipe the output of server.js into this to convert raw test results into bracketed statistics -// suitable for graphing. -// - -// Time duration per statistical bracket -var BRACKET_SIZE = 10000; - -// Number of bytes expected from each test -var EXPECTED_BYTES = 5000; - -var readline = require('readline'); -var rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - terminal: false -}); - -var count = 0.0; -var overallCount = 0.0; -var totalFailures = 0.0; -var totalOverallFailures = 0.0; -var totalMs = 0; -var totalData = 0; -var devices = {}; -var lastBracketTs = 0; - -rl.on('line',function(line) { - line = line.trim(); - var ls = line.split(','); - if (ls.length == 7) { - var ts = parseInt(ls[0]); - var fromId = ls[1]; - var toId = ls[2]; - var ms = parseFloat(ls[3]); - var bytes = parseInt(ls[4]); - var timedOut = (ls[5] == 'true') ? true : false; - var errMsg = ls[6]; - - count += 1.0; - overallCount += 1.0; - if ((bytes !== EXPECTED_BYTES)||(timedOut)) { - totalFailures += 1.0; - totalOverallFailures += 1.0; - } - totalMs += ms; - totalData += bytes; - - devices[fromId] = true; - devices[toId] = true; - - if (lastBracketTs === 0) - lastBracketTs = ts; - - if (((ts - lastBracketTs) >= BRACKET_SIZE)&&(count > 0.0)) { - console.log(count.toString()+','+overallCount.toString()+','+(totalMs / count)+','+(totalFailures / count)+','+(totalOverallFailures / overallCount)+','+totalData+','+Object.keys(devices).length); - - count = 0.0; - totalFailures = 0.0; - totalMs = 0; - totalData = 0; - lastBracketTs = ts; - } - } // else ignore junk -}); diff --git a/attic/big-http-test/docker-main.sh b/attic/big-http-test/docker-main.sh deleted file mode 100755 index 29cdced..0000000 --- a/attic/big-http-test/docker-main.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin - -/zerotier-one -d >>zerotier-one.out 2>&1 - -# Wait for ZeroTier to start and join the network -while [ ! -d "/proc/sys/net/ipv6/conf/zt0" ]; do - sleep 0.25 -done - -# Wait just a bit longer for stuff to settle -sleep 5 - -exec node --harmony /agent.js >>agent.out 2>&1 -#exec node --harmony /agent.js diff --git a/attic/big-http-test/nodesource-el.repo b/attic/big-http-test/nodesource-el.repo deleted file mode 100644 index b785d3d..0000000 --- a/attic/big-http-test/nodesource-el.repo +++ /dev/null @@ -1,6 +0,0 @@ -[nodesource] -name=Node.js Packages for Enterprise Linux 7 - $basearch -baseurl=https://rpm.nodesource.com/pub_4.x/el/7/$basearch -failovermethod=priority -enabled=1 -gpgcheck=0 diff --git a/attic/big-http-test/package.json b/attic/big-http-test/package.json deleted file mode 100644 index 173a6f9..0000000 --- a/attic/big-http-test/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "zerotier-test-http", - "version": "1.0.0", - "description": "ZeroTier in-network HTTP test", - "main": "agent.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "ZeroTier, Inc.", - "license": "GPL-3.0", - "dependencies": { - "async": "^1.5.0", - "express": "^4.13.3", - "ipaddr.js": "^1.0.3" - } -} diff --git a/attic/big-http-test/server.js b/attic/big-http-test/server.js deleted file mode 100644 index 629784d..0000000 --- a/attic/big-http-test/server.js +++ /dev/null @@ -1,53 +0,0 @@ -// ZeroTier distributed HTTP test coordinator and result-reporting server - -// --------------------------------------------------------------------------- -// Customizable parameters: - -var SERVER_PORT = 18080; - -// --------------------------------------------------------------------------- - -var fs = require('fs'); - -var express = require('express'); -var app = express(); - -app.use(function(req,res,next) { - req.rawBody = ''; - req.on('data', function(chunk) { req.rawBody += chunk.toString(); }); - req.on('end', function() { return next(); }); -}); - -var knownAgents = {}; - -app.post('/:agentId',function(req,res) { - var agentId = req.params.agentId; - if ((!agentId)||(agentId.length !== 32)) - return res.status(404).send(''); - - if (req.rawBody) { - var receiveTime = Date.now(); - var resultData = null; - try { - resultData = JSON.parse(req.rawBody); - console.log(Date.now().toString()+','+resultData.source+','+resultData.target+','+resultData.time+','+resultData.bytes+','+resultData.timedOut+',"'+((resultData.error) ? resultData.error : '')+'"'); - } catch (e) {} - } - - knownAgents[agentId] = true; - var thisUpdate = []; - var agents = Object.keys(knownAgents); - if (agents.length < 100) - thisUpdate = agents; - else { - for(var xx=0;xx<100;++xx) - thisUpdate.push(agents[Math.floor(Math.random() * agents.length)]); - } - - return res.status(200).send(JSON.stringify(thisUpdate)); -}); - -var expressServer = app.listen(SERVER_PORT,function () { - console.log('LISTENING ON '+SERVER_PORT); - console.log(''); -}); diff --git a/attic/cli/README.md b/attic/cli/README.md deleted file mode 100644 index 595df07..0000000 --- a/attic/cli/README.md +++ /dev/null @@ -1,57 +0,0 @@ -The new ZeroTier CLI! -==== - -With this update we've expanded upon the previous CLI's functionality, so things should seem pretty familiar. Here are some of the new features we've introduced: - - - Create and administer networks on ZeroTier Central directly from the console. - - Service configurations, allows you to control local/remote instances of ZeroTier One - - Identity generation and management is now part of the same CLI tool - -*** -## Configurations - -Configurations are a way for you to nickname and logically organize the control of ZeroTier services running locally or remotely (this includes ZeroTier Central!). They're merely groupings of service API url's and auth tokens. The CLI's settings data is contained within `.zerotierCliSettings`. - -For instance, you can control your local instance of ZeroTier One via the `@local` config. By default it is represented as follows: - -``` -"local": { - "auth": "7tyqRoFytajf21j2l2t9QPm5", - "type": "one", - "url": "http://127.0.0.1:9993/" -} -``` - -As an example, if you issue the command `zerotier ls` is it implicitly stating `zerotier @local ls`. - -With the same line of thinking, you could create a `@my.zerotier.com` which would allow for something like `zerotier @my.zerotier.com net-create` which talks to our hosted ZeroTier Central to create a new network. - - - -## Command families - -- `cli-` is for configuring the settings data for the CLI itself, such as adding/removing `@thing` configurations, variables, etc. -- `net-` is for operating on a *ZeroTier Central* service such as `https://my.zerotier.com` -- `id-` is for handling ZeroTier identities. - -And those commands with no prefix are there to allow you to operate ZeroTier One instances either local or remote. - -*** -## Useful command examples - -*Add a ZeroTier One configuration:* - - - `zerotier cli-add-zt MyLocalConfigName https://127.0.0.1:9993/ ` - -*Add a ZeroTier Central configuration:* - - - `zerotier cli-add-central MyZTCentralConfigName https://my.zerotier.com/ ` - -*Set a default ZeroTier One instance:* - - - `zerotier cli-set defaultOne MyLocalConfigName` - -*Set a default ZeroTier Central:* - - - `zerotier cli-set defaultCentral MyZTCentralConfigName` - diff --git a/attic/cli/zerotier.cpp b/attic/cli/zerotier.cpp deleted file mode 100644 index e75268d..0000000 --- a/attic/cli/zerotier.cpp +++ /dev/null @@ -1,957 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// Note: unlike the rest of ZT's code base, this requires C++11 due to -// the JSON library it uses and other things. - -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Identity.hpp" -#include "../version.h" -#include "../osdep/OSUtils.hpp" -#include "../ext/offbase/json/json.hpp" - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#else -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -using json = nlohmann::json; -using namespace ZeroTier; - -#define ZT_CLI_FLAG_VERBOSE 'v' -#define ZT_CLI_FLAG_UNSAFE_SSL 'X' - -#define REQ_GET 0 -#define REQ_POST 1 -#define REQ_DEL 2 - -#define OK_STR "[OK ]: " -#define FAIL_STR "[FAIL]: " -#define WARN_STR "[WARN]: " -#define INVALID_ARGS_STR "Invalid args. Usage: " - -struct CLIState -{ - std::string atname; - std::string command; - std::string url; - std::map reqHeaders; - std::vector args; - std::map opts; - json settings; -}; - -namespace { - -static Identity getIdFromArg(char *arg) -{ - Identity id; - if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line - if (id.fromString(arg)) - return id; - } else { // identity is to be read from a file - std::string idser; - if (OSUtils::readFile(arg,idser)) { - if (id.fromString(idser)) - return id; - } - } - return Identity(); -} - -static std::string trimString(const std::string &s) -{ - unsigned long end = (unsigned long)s.length(); - while (end) { - char c = s[end - 1]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - --end; - else break; - } - unsigned long start = 0; - while (start < end) { - char c = s[start]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - ++start; - else break; - } - return s.substr(start,end - start); -} - -static inline std::string getSettingsFilePath() -{ -#ifdef __WINDOWS__ -#else - const char *home = getenv("HOME"); - if (!home) - home = "/"; - return (std::string(home) + "/.zerotierCliSettings"); -#endif -} - -static bool saveSettingsBackup(CLIState &state) -{ - std::string sfp(getSettingsFilePath().c_str()); - if(state.settings.find("generateBackupConfig") != state.settings.end() - && state.settings["generateBackupConfig"].get() == "true") { - std::string backup_file = getSettingsFilePath() + ".bak"; - if(!OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) { - OSUtils::lockDownFile(sfp.c_str(),false); - std::cout << WARN_STR << "unable to write backup config file" << std::endl; - return false; - } - return true; - } - return false; -} - -static bool saveSettings(CLIState &state) -{ - std::string sfp(getSettingsFilePath().c_str()); - if(OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) { - OSUtils::lockDownFile(sfp.c_str(),false); - std::cout << OK_STR << "changes saved." << std::endl; - return true; - } - std::cout << FAIL_STR << "unable to write to " << sfp << std::endl; - return false; -} - -static void dumpHelp() -{ - std::cout << "ZeroTier Newer-Spiffier CLI " << ZEROTIER_ONE_VERSION_MAJOR << "." << ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << std::endl; - std::cout << "(c)2016 ZeroTier, Inc. / Licensed under the GNU GPL v3" << std::endl; - std::cout << std::endl; - std::cout << "Configuration path: " << getSettingsFilePath() << std::endl; - std::cout << std::endl; - std::cout << "Usage: zerotier [-option] [@name] []" << std::endl; - std::cout << std::endl; - std::cout << "Options:" << std::endl; - std::cout << " -verbose - Verbose JSON output" << std::endl; - std::cout << " -X - Do not check SSL certs (CAUTION!)" << std::endl; - std::cout << std::endl; - std::cout << "CLI Configuration Commands:" << std::endl; - std::cout << " cli-set - Set a CLI option ('cli-set help')" << std::endl; - std::cout << " cli-unset - Un-sets a CLI option ('cli-unset help')" << std::endl; - std::cout << " cli-ls - List configured @things" << std::endl; - std::cout << " cli-rm @name - Remove a configured @thing" << std::endl; - std::cout << " cli-add-zt @name - Add a ZeroTier service" << std::endl; - std::cout << " cli-add-central @name - Add ZeroTier Central instance" << std::endl; - std::cout << std::endl; - std::cout << "ZeroTier One Service Commands:" << std::endl; - std::cout << " -v / -version - Displays default local instance's version'" << std::endl; - std::cout << " ls - List currently joined networks" << std::endl; - std::cout << " join [opt=value ...] - Join a network" << std::endl; - std::cout << " leave - Leave a network" << std::endl; - std::cout << " peers - List ZeroTier VL1 peers" << std::endl; - std::cout << " show [] - Get info about self or object" << std::endl; - std::cout << std::endl; - std::cout << "Network Controller Commands:" << std::endl; - std::cout << " net-create - Create a new network" << std::endl; - std::cout << " net-rm - Delete a network (CAUTION!)" << std::endl; - std::cout << " net-ls - List administered networks" << std::endl; - std::cout << " net-members - List members of a network" << std::endl; - std::cout << " net-show [
] - Get network or member info" << std::endl; - std::cout << " net-auth
- Authorize a member" << std::endl; - std::cout << " net-unauth
- De-authorize a member" << std::endl; - std::cout << " net-set - See 'net-set help'" << std::endl; - std::cout << std::endl; - std::cout << "Identity Commands:" << std::endl; - std::cout << " id-generate [] - Generate a ZeroTier identity" << std::endl; - std::cout << " id-validate - Locally validate an identity" << std::endl; - std::cout << " id-sign - Sign a file" << std::endl; - std::cout << " id-verify - Verify a file's signature" << std::endl; - std::cout << " id-getpublic - Get full identity's public portion" << std::endl; - std::cout << std::endl; -} - -static size_t _curlStringAppendCallback(void *contents,size_t size,size_t nmemb,void *stdstring) -{ - size_t totalSize = size * nmemb; - reinterpret_cast(stdstring)->append((const char *)contents,totalSize); - return totalSize; -} - -static std::tuple REQUEST(int requestType, CLIState &state, const std::map &headers, const std::string &postfield, const std::string &url) -{ - std::string body; - char errbuf[CURL_ERROR_SIZE]; - char urlbuf[4096]; - - CURL *curl; - curl = curl_easy_init(); - if (!curl) { - std::cerr << "FATAL: curl_easy_init() failed" << std::endl; - exit(-1); - } - - Utils::scopy(urlbuf,sizeof(urlbuf),url.c_str()); - curl_easy_setopt(curl,CURLOPT_URL,urlbuf); - - struct curl_slist *hdrs = (struct curl_slist *)0; - for(std::map::const_iterator i(headers.begin());i!=headers.end();++i) { - std::string htmp(i->first); - htmp.append(": "); - htmp.append(i->second); - hdrs = curl_slist_append(hdrs,htmp.c_str()); - } - if (hdrs) - curl_easy_setopt(curl,CURLOPT_HTTPHEADER,hdrs); - - //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void *)&body); - curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curlStringAppendCallback); - - if(std::find(state.args.begin(), state.args.end(), "-X") == state.args.end()) - curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(state.opts.count(ZT_CLI_FLAG_UNSAFE_SSL) > 0) ? 0L : 1L); - - if(requestType == REQ_POST) { - curl_easy_setopt(curl, CURLOPT_POST, 1); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfield.c_str()); - } - if(requestType == REQ_DEL) - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - if(requestType == REQ_GET) { - curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errbuf); - curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,0L); - } - - curl_easy_setopt(curl,CURLOPT_USERAGENT,"ZeroTier-CLI"); - CURLcode res = curl_easy_perform(curl); - - errbuf[CURL_ERROR_SIZE-1] = (char)0; // sanity check - - if (res != CURLE_OK) - return std::make_tuple(-1,std::string(errbuf)); - - long response_code; - int rc = (int)curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &response_code); - - if(response_code == 401) { std::cout << FAIL_STR << response_code << "Unauthorized." << std::endl; exit(0); } - else if(response_code == 403) { std::cout << FAIL_STR << response_code << "Forbidden." << std::endl; exit(0); } - else if(response_code == 404) { std::cout << FAIL_STR << response_code << "Not found." << std::endl; exit(0); } - else if(response_code == 408) { std::cout << FAIL_STR << response_code << "Request timed out." << std::endl; exit(0); } - else if(response_code != 200) { std::cout << FAIL_STR << response_code << "Unable to process request." << std::endl; exit(0); } - - curl_easy_cleanup(curl); - if (hdrs) - curl_slist_free_all(hdrs); - return std::make_tuple(response_code,body); -} - -} // anonymous namespace - -////////////////////////////////////////////////////////////////////////////// - -// Check for user-specified @thing config -// Make sure it @thing makes sense -// Apply appropriate request headers -static void checkForThing(CLIState &state, std::string thingType, bool warnNoThingProvided) -{ - std::string configName; - if(state.atname.length()) { - configName = state.atname.erase(0,1); - // make sure specified @thing makes sense in the context of the command - if(thingType == "one" && state.settings["things"][configName]["type"].get() != "one") { - std::cout << FAIL_STR << "A ZeroTier Central config was specified for a ZeroTier One command." << std::endl; - exit(0); - } - if(thingType == "central" && state.settings["things"][configName]["type"].get() != "central") { - std::cout << FAIL_STR << "A ZeroTier One config was specified for a ZeroTier Central command." << std::endl; - exit(0); - } - } - else { // no @thing specified, check for defaults depending on type - if(thingType == "one") { - if(state.settings.find("defaultOne") != state.settings.end()) { - if(warnNoThingProvided) - std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier One command: " << state.settings["defaultOne"].get().c_str() << std::endl; - configName = state.settings["defaultOne"].get().erase(0,1); // get default - } - else { - std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl; - std::cout << "HELP: To set a default: zerotier cli-set defaultOne @my_default_thing" << std::endl; - exit(0); - } - } - if(thingType == "central") { - if(state.settings.find("defaultCentral") != state.settings.end()) { - if(warnNoThingProvided) - std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier Central command: " << state.settings["defaultCentral"].get().c_str() << std::endl; - configName = state.settings["defaultCentral"].get().erase(0,1); // get default - } - else { - std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl; - std::cout << "HELP: To set a default: zerotier cli-set defaultCentral @my_default_thing" << std::endl; - exit(0); - } - } - } - // Apply headers - if(thingType == "one") { - state.reqHeaders["X-ZT1-Auth"] = state.settings["things"][configName]["auth"]; - } - if(thingType == "central"){ - state.reqHeaders["Content-Type"] = "application/json"; - state.reqHeaders["Authorization"] = "Bearer " + state.settings["things"][configName]["auth"].get(); - state.reqHeaders["Accept"] = "application/json"; - } - state.url = state.settings["things"][configName]["url"]; -} - -static bool checkURL(std::string url) -{ - // TODO - return true; -} - -static std::string getLocalVersion(CLIState &state) -{ - json result; - std::tuple res; - checkForThing(state,"one",false); - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/status"); - if(std::get<0>(res) == 200) { - result = json::parse(std::get<1>(res)); - return result["version"].get(); - } - return "---"; -} - -#ifdef __WINDOWS__ -int _tmain(int argc, _TCHAR* argv[]) -#else -int main(int argc,char **argv) -#endif -{ -#ifdef __WINDOWS__ - { - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2),&wsaData); - } -#endif - - curl_global_init(CURL_GLOBAL_DEFAULT); - CLIState state; - std::string arg1, arg2, authToken; - - for(int i=1;i 0)&&(port < 65536))&&(authToken.length() > 0)) { - state.settings["things"]["local"]["url"] = (std::string("http://127.0.0.1:") + portStr + "/"); - state.settings["things"]["local"]["auth"] = authToken; - initSuccess = true; - } - } - - if (!saveSettings(state)) { - std::cerr << "FATAL: unable to write " << getSettingsFilePath() << std::endl; - exit(-1); - } - - if (initSuccess) { - std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << std::endl; - } else { - std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << " but could not auto-init local ZeroTier One service config from " << oneHome << " -- you will need to set local service URL and port manually if you want to control a local instance of ZeroTier One. (This happens if you are not root/administrator.)" << std::endl; - } - } - } - - // PRE-REQUEST SETUP - - json result; - std::tuple res; - std::string url = ""; - - // META - - if ((state.command.length() == 0)||(state.command == "help")) { - dumpHelp(); - return -1; - } - - // zerotier version - else if (state.command == "v" || state.command == "version") { - std::cout << getLocalVersion(state) << std::endl; - return 1; - } - - // zerotier cli-set - else if (state.command == "cli-set") { - if(argc != 4) { - std::cerr << INVALID_ARGS_STR << "zerotier cli-set " << std::endl; - return 1; - } - std::string settingName, settingValue; - if(state.atname.length()) { // User provided @thing erroneously, we will ignore it and adjust argument indices - settingName = argv[3]; - settingValue = argv[4]; - } - else { - settingName = argv[2]; - settingValue = argv[3]; - } - saveSettingsBackup(state); - state.settings[settingName] = settingValue; // changes - saveSettings(state); - } - - // zerotier cli-unset - else if (state.command == "cli-unset") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier cli-unset " << std::endl; - return 1; - } - std::string settingName; - if(state.atname.length()) // User provided @thing erroneously, we will ignore it and adjust argument indices - settingName = argv[3]; - else - settingName = argv[2]; - saveSettingsBackup(state); - state.settings.erase(settingName); // changes - saveSettings(state); - } - - // zerotier @thing_to_remove cli-rm --- removes the configuration - else if (state.command == "cli-rm") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier cli-rm <@thing>" << std::endl; - return 1; - } - if(state.settings["things"].find(state.atname) != state.settings["things"].end()) { - if(state.settings["defaultOne"] == state.atname) { - std::cout << "WARNING: The config you're trying to remove is currently set as your default. Set a new default first!" << std::endl; - std::cout << " | Usage: zerotier set defaultOne @your_other_thing" << std::endl; - } - else { - state.settings["things"].erase(state.atname.c_str()); - saveSettings(state); - } - } - } - - // zerotier cli-add-zt - // TODO: Check for malformed urls/auth - else if (state.command == "cli-add-zt") { - if(argc != 5) { - std::cerr << INVALID_ARGS_STR << "zerotier cli-add-zt " << std::endl; - return 1; - } - std::string thing_name = argv[2], url = argv[3], auth = argv[4]; - if(!checkURL(url)) { - std::cout << FAIL_STR << "Malformed URL" << std::endl; - return 1; - } - if(state.settings.find(thing_name) != state.settings.end()) { - std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str() - << " already exists. Choose another name or rename the old @thing" << std::endl; - std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl; - } - else { - result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "one" + "\", \"url\": \"" + url + "\" }"); - saveSettingsBackup(state); - // TODO: Handle cases where user may or may not prepend an @ - state.settings["things"][thing_name] = result; // changes - saveSettings(state); - } - } - - // zerotier cli-add-central - // TODO: Check for malformed urls/auth - else if (state.command == "cli-add-central") { - if(argc != 5) { - std::cerr << INVALID_ARGS_STR << "zerotier cli-add-central " << std::endl; - return 1; - } - std::string thing_name = argv[2], url = argv[3], auth = argv[4]; - if(!checkURL(url)) { - std::cout << FAIL_STR << "Malformed URL" << std::endl; - return 1; - } - if(state.settings.find(thing_name) != state.settings.end()) { - std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str() - << " already exists. Choose another name or rename the old @thing" << std::endl; - std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl; - } - else { - result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "central" + "\", \"url\": \"" + url + "\" }"); - saveSettingsBackup(state); - // TODO: Handle cases where user may or may not prepend an @ - state.settings["things"]["@" + thing_name] = result; // changes - saveSettings(state); - } - } - - // ONE SERVICE - - // zerotier ls --- display all networks currently joined - else if (state.command == "ls" || state.command == "listnetworks") { - if(argc != 2) { - std::cerr << INVALID_ARGS_STR << "zerotier ls" << std::endl; - return 1; - } - checkForThing(state,"one",true); - url = state.url + "network"; - res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url); - if(std::get<0>(res) == 200) { - std::cout << "listnetworks " << std::endl; - auto j = json::parse(std::get<1>(res).c_str()); - if (j.type() == json::value_t::array) { - for(int i=0;i(); - std::string name = j[i]["name"].get(); - std::string mac = j[i]["mac"].get(); - std::string status = j[i]["status"].get(); - std::string type = j[i]["type"].get(); - std::string addrs; - for(int m=0; m() + " "; - } - std::string dev = j[i]["portDeviceName"].get(); - std::cout << "listnetworks " << nwid << " " << name << " " << mac << " " << status << " " << type << " " << dev << " " << addrs << std::endl; - } - } - } - } - - // zerotier join --- joins a network - else if (state.command == "join") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier join " << std::endl; - return 1; - } - checkForThing(state,"one",true); - res = REQUEST(REQ_POST,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]); - if(std::get<0>(res) == 200) { - std::cout << OK_STR << "connected to " << state.args[0] << std::endl; - } - } - - // zerotier leave --- leaves a network - else if (state.command == "leave") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier leave " << std::endl; - return 1; - } - checkForThing(state,"one",true); - res = REQUEST(REQ_DEL,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]); - if(std::get<0>(res) == 200) { - std::cout << OK_STR << "disconnected from " << state.args[0] << std::endl; - } - } - - // zerotier peers --- display address and role of all peers - else if (state.command == "peers") { - if(argc != 2) { - std::cerr << INVALID_ARGS_STR << "zerotier peers" << std::endl; - return 1; - } - checkForThing(state,"one",true); - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/peer"); - if(std::get<0>(res) == 200) { - json result = json::parse(std::get<1>(res)); - for(int i=0; i(res) == 200) { - result = json::parse(std::get<1>(res)); - std::string status_str = result["online"].get() ? "ONLINE" : "OFFLINE"; - std::cout << "info " << result["address"].get() - << " " << status_str << " " << result["version"].get() << std::endl; - } - } - - // REMOTE - - // zerotier @thing net-create --- creates a new network - else if (state.command == "net-create") { - if(argc > 3 || (argc == 3 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-create" << std::endl; - return 1; - } - checkForThing(state,"central",true); - res = REQUEST(REQ_POST,state,state.reqHeaders,"",state.url + "api/network"); - if(std::get<0>(res) == 200) { - json result = json::parse(std::get<1>(res)); - std::cout << OK_STR << "created network " << result["config"]["nwid"].get() << std::endl; - } - } - - // zerotier @thing net-rm --- deletes a network - else if (state.command == "net-rm") { - if(argc > 4 || (argc == 4 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-rm " << std::endl; - return 1; - } - checkForThing(state,"central",true); - if(!state.args.size()) { - std::cout << "Argument error: No network specified." << std::endl; - std::cout << " | Usage: zerotier net-rm " << std::endl; - } - else { - std::string nwid = state.args[0]; - res = REQUEST(REQ_DEL,state,state.reqHeaders,"",state.url + "api/network/" + nwid); - if(std::get<0>(res) == 200) { - std::cout << "deleted network " << nwid << std::endl; - } - } - } - - // zerotier @thing net-ls --- lists all networks - else if (state.command == "net-ls") { - if(argc > 3 || (argc == 3 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-ls" << std::endl; - return 1; - } - checkForThing(state,"central",true); - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network"); - if(std::get<0>(res) == 200) { - json result = json::parse(std::get<1>(res)); - for(int m=0;m() << std::endl; - } - } - } - - // zerotier @thing net-members --- show all members of a network - else if (state.command == "net-members") { - if(argc > 4 || (argc == 4 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-members " << std::endl; - return 1; - } - checkForThing(state,"central",true); - if(!state.args.size()) { - std::cout << FAIL_STR << "Argument error: No network specified." << std::endl; - std::cout << " | Usage: zerotier net-members " << std::endl; - } - else { - std::string nwid = state.args[0]; - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member"); - json result = json::parse(std::get<1>(res)); - std::cout << "Members of " << nwid << ":" << std::endl; - for (json::iterator it = result.begin(); it != result.end(); ++it) { - std::cout << it.key() << std::endl; - } - } - } - - // zerotier @thing net-show --- show info about a device on a specific network - else if (state.command == "net-show") { - if(argc > 5 || (argc == 5 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-show " << std::endl; - return 1; - } - checkForThing(state,"central",true); - if(state.args.size() < 2) { - std::cout << FAIL_STR << "Argument error: Too few arguments." << std::endl; - std::cout << " | Usage: zerotier net-show " << std::endl; - } - else { - std::string nwid = state.args[0]; - std::string devid = state.args[1]; - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid); - // TODO: More info, what would we like to show exactly? - if(std::get<0>(res) == 200) { - json result = json::parse(std::get<1>(res)); - std::cout << "Assigned IP: " << std::endl; - for(int m=0; m() << std::endl; - } - } - } - } - - // zerotier @thing net-auth --- authorize a device on a network - else if (state.command == "net-auth") { - if(argc > 5 || (argc == 5 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-auth " << std::endl; - return 1; - } - checkForThing(state,"central",true); - if(state.args.size() != 2) { - std::cout << FAIL_STR << "Argument error: Network and/or device ID not specified." << std::endl; - std::cout << " | Usage: zerotier net-auth " << std::endl; - } - std::string nwid = state.args[0]; - std::string devid = state.args[1]; - url = state.url + "api/network/" + nwid + "/member/" + devid; - // Add device to network - res = REQUEST(REQ_POST,state,state.reqHeaders,"",(const std::string)url); - if(std::get<0>(res) == 200) { - result = json::parse(std::get<1>(res)); - res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url); - result = json::parse(std::get<1>(res)); - result["config"]["authorized"] = "true"; - std::string newconfig = result.dump(); - res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,(const std::string)url); - if(std::get<0>(res) == 200) - std::cout << OK_STR << devid << " authorized on " << nwid << std::endl; - else - std::cout << FAIL_STR << "There was a problem authorizing that device." << std::endl; - } - } - - // zerotier @thing net-unauth - else if (state.command == "net-unauth") { - if(argc > 5 || (argc == 5 && !state.atname.length())) { - std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-unauth " << std::endl; - return 1; - } - checkForThing(state,"central",true); - if(state.args.size() != 2) { - std::cout << FAIL_STR << "Bad argument. No network and/or device ID specified." << std::endl; - std::cout << " | Usage: zerotier net-unauth " << std::endl; - } - std::string nwid = state.args[0]; - std::string devid = state.args[1]; - // If successful, get member config - res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid); - result = json::parse(std::get<1>(res)); - // modify auth field and re-POST - result["config"]["authorized"] = "false"; - std::string newconfig = result.dump(); - res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,state.url + "api/network/" + nwid + "/member/" + devid); - if(std::get<0>(res) == 200) - std::cout << OK_STR << devid << " de-authorized from " << nwid << std::endl; - else - std::cout << FAIL_STR << "There was a problem de-authorizing that device." << std::endl; - } - - // zerotier @thing net-set - else if (state.command == "net-set") { - } - - // ID - - // zerotier id-generate [] - else if (state.command == "id-generate") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier id-generate []" << std::endl; - return 1; - } - uint64_t vanity = 0; - int vanityBits = 0; - if (argc >= 5) { - vanity = Utils::hexStrToU64(argv[4]) & 0xffffffffffULL; - vanityBits = 4 * strlen(argv[4]); - if (vanityBits > 40) - vanityBits = 40; - } - - ZeroTier::Identity id; - for(;;) { - id.generate(); - if ((id.address().toInt() >> (40 - vanityBits)) == vanity) { - if (vanityBits > 0) { - fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt()); - } - break; - } else { - fprintf(stderr,"vanity address: tried %.10llx looking for first %d bits of %.10llx\n",(unsigned long long)id.address().toInt(),vanityBits,(unsigned long long)(vanity << (40 - vanityBits))); - } - } - - std::string idser = id.toString(true); - if (argc >= 3) { - if (!OSUtils::writeFile(argv[2],idser)) { - std::cerr << "Error writing to " << argv[2] << std::endl; - return 1; - } else std::cout << argv[2] << " written" << std::endl; - if (argc >= 4) { - idser = id.toString(false); - if (!OSUtils::writeFile(argv[3],idser)) { - std::cerr << "Error writing to " << argv[3] << std::endl; - return 1; - } else std::cout << argv[3] << " written" << std::endl; - } - } else std::cout << idser << std::endl; - } - - // zerotier id-validate - else if (state.command == "id-validate") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier id-validate " << std::endl; - return 1; - } - Identity id = getIdFromArg(argv[2]); - if (!id) { - std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl; - return 1; - } - if (!id.locallyValidate()) { - std::cerr << argv[2] << " FAILED validation." << std::endl; - return 1; - } else std::cout << argv[2] << "is a valid identity" << std::endl; - } - - // zerotier id-sign - else if (state.command == "id-sign") { - if(argc != 4) { - std::cerr << INVALID_ARGS_STR << "zerotier id-sign " << std::endl; - return 1; - } - Identity id = getIdFromArg(argv[2]); - if (!id) { - std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl; - return 1; - } - if (!id.hasPrivate()) { - std::cerr << argv[2] << " does not contain a private key (must use private to sign)" << std::endl; - return 1; - } - std::string inf; - if (!OSUtils::readFile(argv[3],inf)) { - std::cerr << argv[3] << " is not readable" << std::endl; - return 1; - } - C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); - std::cout << Utils::hex(signature.data,(unsigned int)signature.size()) << std::endl; - } - - // zerotier id-verify - else if (state.command == "id-verify") { - if(argc != 4) { - std::cerr << INVALID_ARGS_STR << "zerotier id-verify " << std::endl; - return 1; - } - Identity id = getIdFromArg(argv[2]); - if (!id) { - std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl; - return 1; - } - std::string inf; - if (!OSUtils::readFile(argv[3],inf)) { - std::cerr << argv[3] << " is not readable" << std::endl; - return 1; - } - std::string signature(Utils::unhex(argv[4])); - if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) { - std::cout << argv[3] << " signature valid" << std::endl; - } else { - std::cerr << argv[3] << " signature check FAILED" << std::endl; - return 1; - } - } - - // zerotier id-getpublic - else if (state.command == "id-getpublic") { - if(argc != 3) { - std::cerr << INVALID_ARGS_STR << "zerotier id-getpublic " << std::endl; - return 1; - } - Identity id = getIdFromArg(argv[2]); - if (!id) { - std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl; - return 1; - } - std::cerr << id.toString(false) << std::endl; - } - // - else { - dumpHelp(); - return -1; - } - if(std::find(state.args.begin(), state.args.end(), "-verbose") != state.args.end()) - std::cout << "\n\nAPI response = " << std::get<1>(res) << std::endl; - curl_global_cleanup(); - return 0; -} diff --git a/attic/historic/anode/LICENSE.txt b/attic/historic/anode/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/attic/historic/anode/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/attic/historic/anode/config.mk.Darwin b/attic/historic/anode/config.mk.Darwin new file mode 100644 index 0000000..a5cbeee --- /dev/null +++ b/attic/historic/anode/config.mk.Darwin @@ -0,0 +1,17 @@ +CC=gcc +CXX=g++ + +#ARCH_FLAGS=-arch x86_64 -arch i386 -arch ppc + +DEFS=-DHAS_DEV_URANDOM +CXXDEFS=-DBOOST_DISABLE_ASSERTS -DBOOST_NO_TYPEID -DNDEBUG + +CFLAGS=-mmacosx-version-min=10.4 -std=c99 -O6 -ftree-vectorize -Wall $(DEFS) $(ARCH_FLAGS) +CXXFLAGS=-mmacosx-version-min=10.4 -Drestrict=__restrict__ -O6 -ftree-vectorize -Wall $(DEFS) $(CXXDEFS) $(ARCH_FLAGS) + +LDFLAGS=-mmacosx-version-min=10.4 $(ARCH_FLAGS) +DLLFLAGS=$(ARCH_FLAGS) -shared +DLLEXT=dylib + +LIBANODE_LIBS=-lcrypto -lpthread -lresolv +LIBSPARK_LIBS=-lz diff --git a/attic/historic/anode/config.mk.Linux b/attic/historic/anode/config.mk.Linux new file mode 100644 index 0000000..072fa4c --- /dev/null +++ b/attic/historic/anode/config.mk.Linux @@ -0,0 +1,17 @@ +CC=gcc +CXX=g++ + +DEFS=-DHAS_DEV_URANDOM + +CFLAGS=-std=c99 -O6 -fPIC -Wall $(DEFS) +CXXFLAGS=-Drestrict=__restrict__ -O6 -Wall $(DEFS) -I.. + +#CFLAGS=-g -Wall $(DEFS) +#CXXFLAGS=-g -Wall $(DEFS) + +LDFLAGS= +DLLFLAGS=-shared +DLLEXT=so + +LIBANODE_LIBS=-lcrypto -lresolv -pthread +LIBSPARK_LIBS=-lz diff --git a/attic/historic/anode/docs/anode_protocol.txt b/attic/historic/anode/docs/anode_protocol.txt new file mode 100644 index 0000000..0adb923 --- /dev/null +++ b/attic/historic/anode/docs/anode_protocol.txt @@ -0,0 +1,764 @@ +***************************************************************************** +Anode Protocol Specification Draft +Version 0.8 + +(c)2009-2010 Adam Ierymenko +***************************************************************************** + +Table of Contents + +***************************************************************************** + +1. Introduction + +Anode provides three components that work together to provide a global, +secure, and mobile addressing system for computer networks: + +1) An addressing system based on public key cryptography enabling network + devices or applications to assign themselves secure, unique, and globally + reachable network addresses in a flat address space. + +2) A system enabling network participants holding global addresses to locate + one another on local or global networks with "zero configuration." + +3) A communications protocol for communication between addressed network + participants that requires no special operating system support and no + changes to existing network infrastructure. + +Using Anode, both fixed and mobile applications and devices can communicate +directly as if they were all connected to the same VPN. Anode restores the +original vision of the Internet as a "flat" network where anything can talk +to anything, and adds the added benefits of address mobility and strong +protection against address spoofing and other protocol level attacks. + +1.1. Design Philosophy + +Anode's design philosophy is the classical "KISS" principle: "Keep It Simple +Stupid." Anode's design principles are: + +#1: Do not try to solve too many problems at once, and stay in scope. + +Anode does not attempt to solve too many problems at once. It attempts to +solve the problems of mobile addressing, address portability, and "flat" +addressing in the presence of NAT or other barriers. + +It does not attempt to duplicate the full functionality of SSL, X.509, SSH, +XMPP, an enterprise service bus, a pub/sub architecture, BitTorrent, etc. All +of those protocols and services can be used over Anode if their functionality +is desired. + +#2: Avoid state management. + +State multiplies the complexity and failure modes of network protocols. State +also tends to get in the way of the achievement of new features implicitly +(see principle #4). Avoid state whenever possible. + +#3: Avoid algorithm and dependency bloat. + +Anode uses only elliptic curve Diffie-Hellman (EC-DH) and AES-256. No other +cryptographic algorithms or hash functions are presently necessary. This +yields implementations compact enough for embedded devices. + +Anode also requires few or no dependencies, depending on whether the two +needed cryptographic algorithms are obtained through a library or included. +No other protocols or libraries are required in an implementation. + +#4: Achieve features implicitly. + +Use a simple stateless design that allows features to be achieved implicitly +rather than specified explicitly. For example, Anode can do multi-homing and +could be used to build a mesh network, but neither of these features is +explicitly specified. + +***************************************************************************** + +2. Core Concepts and Algorithms + +This section describes addresses, zones, common algorithms, and other core +concepts. + +2.1. Zones + +A zone is a 32-bit integer encoded into every Anode address. Zones serve to +assist in the location of peers by address on global IP networks. They are +not presently significant for local communications, though they could be +used to partition addresses into groups or link them with configuration +options. + +Each zone has a corresponding zone file which can be fetched in a number of +ways (see below). A zone file is a flat text format dictionary of the format +"key=value" separated by carriage returns. Line feeds are ignored, and any +character may be escaped with a backslash (\) character. Blank lines are +ignored. + +The following entries must appear in a zone file: + +n= +d= +c= +r= +ttl= + +Additional fields may appear as well, including fields specific to special +applications or protocols supported within the zone. Some of these are +defined in this document. + +Zone file fetching mechanisms are described below. Multiple mechanisms are +specified to enable fallback in the event that one mechanism is not available. + +2.1.1. Zone File Retrieval + +Zone files are retrieved via HTTP, with the HTTP address being formed in one +of two ways. + +The preferred DNS method: + +To fetch a zone file via DNS, use the zone ID to generate a host name and URI +of the form: + + http://a--XXXXXXXX.net/z + +The XXXXXXXX field is the zone ID in hexadecimal. + +The fallback IP method: + +For fallback in the absence of DNS, the zone ID can be used directly as an +IPv4 or IPv4-mapped-to-IPv6 IP address. A URI is generated of the form: + + http://ip_address/z + +Support for this method requires that a zone ID be chosen to correspond to a +permanent IPv4 (preferably mappable to IPv6 space as well) IP address. + +2.1.2. Zone ID Reservation + +By convention, a zone ID is considered reserved when a domain of the form +"a--XXXXXXXX.net" (where XXXXXXXX is the ID in hex) is registered. + +It is recommended that this be done even for zone IDs not used for global +address location in order to globally reserve them. + +2.2. Addresses + +Anode addresses are binary strings containing a 32-bit zone ID, a public key, +and possibly other fields. Only one address type is presently defined: + +|---------------------------------------------------------------------------| +| Name | Type ID | Elliptic Curve Parameters | Total Length | +|---------------------------------------------------------------------------| +| ANODE-256-40 | 1 | NIST-P-256 | 40 | +|---------------------------------------------------------------------------| + +|---------------------------------------------------------------------------| +| Name | Binary Layout | +|---------------------------------------------------------------------------| +| ANODE-256-40 | | +|---------------------------------------------------------------------------| + +The public key is a "compressed" form elliptic curve public key as described +in RFC5480. + +The unused section of the address must be zero. These bytes are reserved for +future use. + +2.2.1. ASCII Format For Addresses + +Addresses are encoded in ASCII using base-32, which provides a quotable and +printable encoding that is of manageable length and is case-insensitive. For +example, an ANODE-256-40 address is 64 characters long in base-32 encoding. + +2.3. Relaying + +An Anode peer may optionally relay packets to any other reachable peer. +Relaying is accomplished by sending a packet to a peer with the recipient set +to the final recipient. The receiving peer will, if relaying is allowed and if +it knows of or can reach the recipient, forward the packet. + +No error is returned if relaying fails, so relay paths are treated as possible +paths for communication until a return is received in the same way as direct +paths. + +Relaying can be used by peers to send messages indirectly, locate one +another, and determine network location information to facilitate the +establishment of direct communications. + +Peers may refuse to relay or may limit the transmission rate at which packets +can be relayed. + +2.3.1. Zone Relays + +If a zone's addresses are globally reachable on global IP networks, it must +have one or more zone relays. These must have globally reachable public +static IP addresses. + +Zone relays are specified in the zone file in the following format: + + zr.
=[,]::: + +The address checksum is the sum of the bytes in the Anode address modulus +the number of "zr" entries, in hexadecimal. For example, if a zone had four +global relays its zone file could contain the lines: + + zr.0=1.2.3.4:4343:4344:klj4j3... + zr.1=2.3.4.5:4343:4344:00194j... + zr.2=3.4.5.6:4343:4344:1j42zz... + zr.3=4.5.6.7:4343:4344:z94j1q... + +The relay would be chosen by taking the sum of the bytes in the address +modulo 4. For example, if the bytes of an address sum to 5081 then relay +zr.1 would be used to communicate with that address. + +If more than one IP address is listed for a given relay, the peer must choose +at random from among the addresses of the desired type (IPv4 or IPv6). + +Each relay must have one Anode address for every address type supported within +the zone. (At present there is only one address type defined.) + +Peers should prefer UDP and fall back to TCP only if UDP is not available. + +To make itself available, a peer must make itself known to its designated zone +relay. This is accomplished by sending a PING message. + +2.4. Key Agreement and Derivation + +Key agreement is performed using elliptic curve Diffie-Hellman. This yields +a raw key whose size depends on the elliptic curve parameters in use. + +The following algorithm is used to derive a key of any length from a raw +key generated through key agreement: + +1) Zero the derived key buffer. +2) Determine the largest of the original raw key or the derived key. +3) Loop from 0 to the largest length determined in step 2, XOR each byte of + the derived key buffer with the corresponding byte of the original key + buffer with each index being modulus the length of the respective buffer. + +2.5. Message Authentication + +For message authentication, CMAC-AES (with AES-256) is used. This is also +known in some literature as OMAC1-AES. The key is derived from key agreement +between the key pair of the sending peer and the address of the recipient. + +2.6. AES-DIGEST + +To maintain cryptographic algorithm frugality, a cryptographic hash function +is constructed from the AES-256 cipher. This hash function uses the common +Davis-Meyer construction with Merkle-Damgård length padding. + +It is described by the following pseudocode: + + byte previous_digest[16] + byte digest[16] = { 0,0,... } + byte block[32] = { 0,0,... } + integer block_counter = 0 + + ; digest message + for each byte b of message + block[block_counter] = b + block_counter = block_counter + 1 + if block_counter == 32 then + block_counter = 0 + save digest[] in previous_digest[] + encrypt digest[] with aes-256 using block[] as 256-bit aes-256 key + xor digest[] with previous_digest[] + end if + next + + ; append end marker, do final block + block[block_counter] = 0x80 + block_counter = block_counter + 1 + zero rest of block[] from block_counter to 15 + save digest[] in previous_digest[] + encrypt digest[] with aes-256 using block[] as 256-bit aes-256 key + xor digest[] with previous_digest[] + + ; Merkle-Damgård length padding + zero first 8 bytes of block[] + fill last 8 bytes of block[] w/64-bit length in big-endian order + save digest[] in previous_digest[] + encrypt digest[] with aes-256 using block[] as 256-bit aes-128 key + xor digest[] with previous_digest[] + + ; digest[] now contains 128-bit message digest + +2.7. Short Address Identifiers (Address IDs) + +A short 8-byte version of the Anode address is used in the protocol to reduce +transmission overhead when both sides are already aware of the other's full +address. + +The short address identifier is formed by computing the AES-DIGEST of the +full address and then XORing the first 8 bytes of the digest with the last +8 bytes to yield an 8-byte shortened digest. + +2.8. DNS Resolution of Anode Addresses + +Anode addresses can be saved in DNS TXT records in the following format: + +anode:
+ +This permits Anode addresses to be resolved from normal DNS host name. + +2.9. Packet Transmission Mechanisms + +2.9.1. UDP Transmission + +The recommended method of sending Anode packets is UDP. Each packet is simply +sent as a UDP packet. + +2.9.2. TCP Transmission + +To send packets over TCP, each packet is prefixed by its size as a 16-bit +integer. + +2.9.3. HTTP Transmission + +Anode packets may be submitted in HTTP POST transactions for transport over +networks where HTTP is the only available protocol. + +Anode packets are simply prefixed with a 16-byte packet size and concatenated +together just as they are in a TCP stream. One or more packets may be sent +with each HTTP POST transaction for improved performance. + +Since this method is intended for use in "hostile" or highly restricted +circumstances, no additional details such as special headers or MIME types +are specified to allow maximum flexibility. Peers should ignore anything +other than the payload. + +2.10. Endpoints + +An endpoint indicates a place where Anode packets may be sent. The following +endpoint types are specified: + +|---------------------------------------------------------------------------| +| Endpoint Type | Description | Address Format | +|---------------------------------------------------------------------------| +| 0x00 | Unspecified | (none) | +| 0x01 | Ethernet | | +| 0x02 | UDP/IPv4 | | +| 0x03 | TCP/IPv4 | | +| 0x04 | UDP/IPv6 | | +| 0x05 | TCP/IPv6 | | +| 0x06 | HTTP | | +|---------------------------------------------------------------------------| + +Endpoints are encoded by beginning with a single byte indicating the endpoint +type followed by the address information required for the given type. + +Note that IP ports bear no relationship to Anode protocol ports. + +2.11. Notes + +All integers in the protocol are transmitted in network (big endian) byte +order. + +***************************************************************************** + +3. Common Packet Format + +A common header is used for all Anode packets: + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Hop Count | 1 | 8-bit hop count (not included in MAC) | +| Flags | 1 | 8-bit flags | +| MAC | 8 | 8 byte shortened CMAC-AES of packet | +| Sender Address | ? | Full address or short ID of sender | +| Recipient Address | ? | Full address or short ID of recipient | +| Peer IDs | 1 | Two 4-bit peer IDs: sender, recipient | +| Message Type | 1 | 8-bit message type | +| Message | ? | Message payload | +|---------------------------------------------------------------------------| + +3.1. Hop Count + +The hop count begins at zero and must be incremented by each peer that relays +the packet to another peer. The hop count must not wrap to zero at 255. + +Because the hop count is modified in transit, it is not included in MAC +calculation or authentication. + +The hop count is used to prioritize endpoints that are direct over endpoints +that involve relaying, or to prioritize closer routes over more distant +ones. + +3.2. Flags and Flag Behavior + +|---------------------------------------------------------------------------| +| Flag | Description | +|---------------------------------------------------------------------------| +| 0x01 | Sender address fully specified | +| 0x02 | Recipient address fully specified | +| 0x04 | Authentication error response | +|---------------------------------------------------------------------------| + +If flag 0x01 is set, then the sender address will be the full address rather +than a short address identifier. The length of the address can be determined +from the first byte of the address, which always specifies the address type. +Flag 0x02 has the same meaning for the recipient address. + +A peer must send fully specified sender addresses until it receives a response +from the recipient. At this point the sender may assume that the recipient +knows its address and use short a short sender address instead. This +assumption should time out, with a recommended timeout of 60 seconds. + +There is presently no need to send fully specified recipient addresses, but +the flag is present in case it is needed and must be honored. + +Flag 0x04 indicates that this is an error response containing a failed +authentication error. Since authentication failed, this packet may not have +a valid MAC. Packets with this flag must never have any effect other than +to inform of an error. This error, since it is unauthenticated, must never +have any side effects such as terminating a connection. + +3.3. MAC + +The MAC is calculated as follows: + +1) Temporarily set the 64-bit/8-byte MAC field in the packet to the packet's + size as a 64-bit big-endian integer. +2) Calculate the MAC for the entire packet (excluding the first byte) using + the key agreed upon between the sender and the recipient, resulting in a + 16 byte full CMAC-AES MAC. +3) Derive the 8 byte packet MAC by XORing the first 8 bytes of the full 16 + byte CMAC-AES MAC with the last 8 bytes. Place this into the packet's MAC + field. + +3.4. Peer IDs + +Peer IDs provide a method for up to 15 different peers to share an address, +each with a unique ID allowing packets to be routed to them individually. + +A peer ID of zero indicates "any" or "unspecified." Real peers must have a +nonzero peer ID. In the normal single peer per address case, any peer ID may +be used. If multiple peers are to share an address, some implementation- +dependent method must be used to ensure that each peer has a unique peer ID. + +Relaying peers must follow these rules based on the recipient peer ID when +relaying messages: + + - IF the peer ID is zero or if the peer ID is not known, the message must + be forwarded to a random endpoint for the given recipient address. + - IF the peer ID is nonzero and matches one or more known endpoints for the + given recipient address and peer ID, the message must only be sent to + a matching endpoint. + +A receiving peer should process any message that it receives regardless of +whether its recipient peer ID is correct. The peer ID is primarily for relays. + +Peers should typically send messages with a nonzero recipient peer ID when +responding to or involved in a conversation with a specific peer (e.g. a +streaming connection), and send zero recipient peer IDs otherwise. + +3.5. Short Address Conflict Disambiguation + +In the unlikely event of two Anode addresses with the same short identifier, +the recipient should use MAC validation to disambiguate. The peer ID must not +be relied upon for this purpose. + +***************************************************************************** + +4. Basic Signaling and Transport Protocol + +4.1. Message Types + +|---------------------------------------------------------------------------| +| Type | ID | Description | +|---------------------------------------------------------------------------| +| ERROR | 0x00 | Error response | +| PING | 0x01 | Echo request | +| PONG | 0x02 | Echo response | +| EPC_REQ | 0x03 | Endpoint check request | +| EPC | 0x04 | Endpoint check response | +| EPI | 0x05 | Endpoint information | +| NAT_T | 0x06 | NAT traversal message | +| NETID_REQ | 0x07 | Request network address identification and/or test | +| NETID | 0x08 | Response to network address identification request | +| DGRAM | 0x09 | Simple UDP-like datagram | +|---------------------------------------------------------------------------| + +4.2. Message Details + +4.2.1. ERROR + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Error Code | 2 | 16-bit error code | +| Error Arguments | ? | Error arguments, depending on error type | +|---------------------------------------------------------------------------| + +Error arguments are empty unless otherwise stated below. + +Error codes: + +|---------------------------------------------------------------------------| +| Error Code | Description | +|---------------------------------------------------------------------------| +| 0x01 | Message not valid | +| 0x02 | Message authentication or decryption failed | +| 0x03 | Relaying and related features not authorized | +| 0x04 | Relay recipient not reachable | +|---------------------------------------------------------------------------| + +Generation of errors is optional. A peer may choose to ignore invalid +messages or to throttle the sending of errors. + +4.2.2. PING + +(Payload unspecified.) + +Request echo of payload as PONG message. + +4.2.3. PONG + +(Payload unspecified.) + +Echoed payload of received PING message. + +4.2.4. EPC_REQ + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Request ID | 4 | 32-bit request ID | +|---------------------------------------------------------------------------| + +Request echo of request ID in EPC message, used to check and learn endpoints. + +To learn a network endpoint for a peer, CHECK_REQ is sent. If CHECK is +returned with a valid request ID, the endpoint is considered valid. + +4.2.5. EPC + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Request ID | 4 | 32-bit request ID echoed back | +|---------------------------------------------------------------------------| + +Response to EPC_REQ containing request ID. + +4.2.6. EPI + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Flags | 1 | 8-bit flags | +| Endpoint | ? | Endpoint type and address | +| NAT-T mode | 1 | 8-bit NAT traversal mode | +| NAT-T options | ? | Options related to specified NAT-T mode | +|---------------------------------------------------------------------------| + +EPI stands for EndPoint Identification, and is sent to notify another peer of +a network endpoint where the sending peer is reachable. + +If the receiving peer is interested in communicating with the sending peer, +the receiving peer must send EPC_REQ to the sending peer at the specified +endpoint to check the validity of that endpoint. The endpoint is learned if a +valid EPC is returned. + +If the endpoint in EPI is unspecified, the actual source of the EPI message +is the endpoint. This allows EPI messages to be broadcast on a local LAN +segment to advertise the presence of an address on a local network. EPI +broadcasts on local IP networks must be made to UDP port 8737. + +Usually EPI is sent via relays (usually zone relays) to inform a peer of an +endpoint for direct communication. + +There are presently no flags, so flags must be zero. + +4.2.7. NAT_T + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| NAT-T mode | 1 | 8-bit NAT traversal mode | +| NAT-T options | ? | Options related to specified NAT-T mode | +|---------------------------------------------------------------------------| + +NAT_T is used to send messages specific to certain NAT traversal modes. + +4.2.8. NETID_REQ + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Request ID | 4 | 32-bit request ID | +| Endpoint | ? | Endpoint type and address information | +|---------------------------------------------------------------------------| + +When a NETID_REQ message is received, the recipient attempts to echo it back +as a NETID message to the specified endpoint address. If the endpoint is +unspecified, the recipient must fill it in with the actual origin of the +NETID_REQ message. This allows a peer to cooperate with another peer (usually +a zone relay) to empirically determine its externally visible network +address information. + +A peer may ignore NETID_REQ or respond with an error if it does not allow +relaying. + +4.2.9. NETID + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Request ID | 4 | 32-bit request ID echoed back | +| Endpoint Type | 1 | 8-bit endpoint type | +| Endpoint Address | ? | Endpoint Address (size depends on type) | +|---------------------------------------------------------------------------| + +NETID is sent in response to NETID_REQ to the specified endpoint address. It +always contains the endpoint address to which it was sent. + +4.2.10. DGRAM + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Source Port | 2 | 16-bit source port | +| Destination Port | 2 | 16-bit destination port | +| Payload | ? | Datagram packet payload | +|---------------------------------------------------------------------------| + +A datagram is a UDP-like message without flow control or delivery assurance. + +***************************************************************************** + +5. Stream Protocol + +The stream protocol is very similar to TCP, though it omits some features +that are not required since they are taken care of by the encapsulating +protocol. SCTP was also an inspiration in the design. + +5.1. Message Types + +|---------------------------------------------------------------------------| +| Type | ID | Description | +|---------------------------------------------------------------------------| +| S_OPEN | 20 | Initiate a streaming connection (like TCP SYN) | +| S_CLOSE | 21 | Terminate a streaming connection (like TCP RST/FIN) | +| S_DATA | 22 | Data packet | +| S_ACK | 23 | Acknowedge receipt of one or more data packets | +| S_DACK | 24 | Combination of DATA and ACK | +|---------------------------------------------------------------------------| + +5.2. Message Details + +5.2.1. S_OPEN + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Sender Link ID | 2 | 16-bit sender link ID | +| Destination Port | 2 | 16-bit destination port | +| Window Size | 2 | 16-bit window size in 1024-byte increments | +| Init. Seq. Number | 4 | 32-bit initial sequence number | +| Flags | 1 | 8-bit flags | +|---------------------------------------------------------------------------| + +The OPEN message corresponds to TCP SYN, and initiates a connection. It +specifies the initial window size for the sender and the sender's initial +sequence number, which should be randomly chosen to prevent replay attacks. + +If OPEN is successful, the recipient sends its own OPEN to establish the +connetion. If OPEN is unsuccessful, CLOSE is sent with its initial and current +sequence numbers equal and an appropriate reason such as "connection refused." + +The sender link ID must be unique for a given recipient. + +If flag 01 is set, the sender link ID is actually a source port where the +sender might be listening for connections as well. This exactly duplicates +the behavior of standard TCP. Otherwise, the sender link ID is simply an +arbitrary number that the sender uses to identify the connection with this +recipient and there is no port of origin. Ports of origin are optional for +Anode streaming connections to permit greater scalability. + +5.2.2. S_CLOSE + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Sender Link ID | 2 | 16-bit sender link ID | +| Destination Port | 2 | 16-bit destination port | +| Flags | 1 | 8-bit flags | +| Reason | 1 | 8-bit close reason | +| Init. Seq. Number | 4 | 32-bit initial sequence number | +| Sequence Number | 4 | 32-bit current sequence number | +|---------------------------------------------------------------------------| + +The CLOSE message serves a function similar to TCP FIN. The initial sequence +number is the original starting sequence number sent with S_OPEN, while the +current sequence number is the sequence number corresponding to the close +and must be ACKed to complete the close operation. The use of the initial +sequence number helps to serve as a key to prevent replay attacks. + +CLOSE is also used to indicate a failed OPEN attempt. In this case the current +sequence number will be equal to the initial sequence number and no ACK will +be expected. + +There are currently no flags, so flags must be zero. + +The reason field describes the reason for the close: + +|---------------------------------------------------------------------------| +| Reason Code | Description | +|---------------------------------------------------------------------------| +| 00 | Application closed connection | +| 01 | Connection refused | +| 02 | Protocol error | +| 03 | Timed out | +|---------------------------------------------------------------------------| + +Established connections will usually be closed with reason 00, while reason +01 is usually provided if an OPEN is received but the port is not bound. + +5.2.3. S_DATA + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Sender Link ID | 2 | 16-bit sender link ID | +| Destination Port | 2 | 16-bit destination port | +| Sequence Number | 4 | 32-bit sequence number | +| Payload | ? | Data payload | +|---------------------------------------------------------------------------| + +The DATA message carries a packet of data, with the sequence number +determining order. The sequence number is monotonically incremented with +each data packet, and wraps at the maximum value of an unsigned 32-bit +integer. + +5.2.4. S_ACK + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Sender Link ID | 2 | 16-bit sender link ID | +| Destination Port | 2 | 16-bit destination port | +| Window Size | 2 | 16-bit window size in 1024-byte increments | +| Acknowledgements | ? | One or more acknowledgements (see below) | +|---------------------------------------------------------------------------| + +Each acknowledgement is a 32-bit integer followed by an 8-bit integer (5 bytes +total). The 32-bit integer is the first sequence number to acknowledge, and +the 8-bit integer is the number of sequential following sequence numbers to +acknowledge. For example "1, 4" would acknowledge sequence numbers 1, 2, 3, +and 4. + +5.2.5. S_DACK + +|---------------------------------------------------------------------------| +| Field | Length | Description | +|---------------------------------------------------------------------------| +| Sender Link ID | 2 | 16-bit sender link ID | +| Destination Port | 2 | 16-bit destination port | +| Window Size | 2 | 16-bit window size in 1024-byte increments | +| Num. Acks | 1 | 8-bit number of acknowledgements | +| Acknowledgements | ? | One or more acknowledgements | +| Payload | ? | Data payload | +|---------------------------------------------------------------------------| + +The DACK message combines ACK and DATA, allowing two peers that are both +transmitting data to efficiently ACK without a separate packet. diff --git a/attic/historic/anode/libanode/Makefile b/attic/historic/anode/libanode/Makefile new file mode 100644 index 0000000..088587b --- /dev/null +++ b/attic/historic/anode/libanode/Makefile @@ -0,0 +1,33 @@ +SYSNAME:=${shell uname} +SYSNAME!=uname +include ../config.mk.${SYSNAME} + +LIBANODE_OBJS= \ + impl/aes.o \ + impl/dictionary.o \ + impl/dns_txt.o \ + impl/ec.o \ + impl/environment.o \ + impl/misc.o \ + impl/thread.o \ + address.o \ + aes_digest.o \ + errors.o \ + identity.o \ + network_address.o \ + secure_random.o \ + system_transport.o \ + uri.o +# zone.o + +all: $(LIBANODE_OBJS) + ar rcs libanode.a $(LIBANODE_OBJS) + ranlib libanode.a + $(CC) $(CFLAGS) -o utils/anode-make-identity utils/anode-make-identity.c $(LIBANODE_OBJS) $(LIBANODE_LIBS) + +clean: force + rm -f $(LIBANODE_OBJS) + rm -f libanode.$(DLLEXT) libanode.a + rm -f utils/anode-make-identity + +force: ; diff --git a/attic/historic/anode/libanode/address.c b/attic/historic/anode/libanode/address.c new file mode 100644 index 0000000..e7ab783 --- /dev/null +++ b/attic/historic/anode/libanode/address.c @@ -0,0 +1,98 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "impl/aes.h" +#include "impl/ec.h" +#include "impl/misc.h" +#include "impl/types.h" +#include "anode.h" + +int AnodeAddress_calc_short_id( + const AnodeAddress *address, + AnodeAddressId *short_address_id) +{ + unsigned char digest[16]; + + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + Anode_aes_digest(address->bits,ANODE_ADDRESS_LENGTH_ANODE_256_40,digest); + break; + default: + return ANODE_ERR_ADDRESS_INVALID; + } + + *((uint64_t *)short_address_id->bits) = ((uint64_t *)digest)[0] ^ ((uint64_t *)digest)[1]; + + return 0; +} + +int AnodeAddress_get_zone(const AnodeAddress *address,AnodeZone *zone) +{ + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + *((uint32_t *)&(zone->bits[0])) = *((uint32_t *)&(address->bits[1])); + return 0; + } + return ANODE_ERR_ADDRESS_INVALID; +} + +int AnodeAddress_to_string(const AnodeAddress *address,char *buf,int len) +{ + const unsigned char *inptr; + char *outptr; + unsigned int i; + + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + if (len < (((ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5) * 8) + 1)) + return ANODE_ERR_BUFFER_TOO_SMALL; + inptr = (const unsigned char *)address->bits; + outptr = buf; + for(i=0;i<(ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5);++i) { + Anode_base32_5_to_8(inptr,outptr); + inptr += 5; + outptr += 8; + } + *outptr = (char)0; + return ((ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5) * 8); + } + return ANODE_ERR_ADDRESS_INVALID; +} + +int AnodeAddress_from_string(const char *str,AnodeAddress *address) +{ + const char *blk_start = str; + const char *ptr = str; + unsigned int address_len = 0; + + while (*ptr) { + if ((unsigned long)(ptr - blk_start) == 8) { + if ((address_len + 5) > sizeof(address->bits)) + return ANODE_ERR_ADDRESS_INVALID; + Anode_base32_8_to_5(blk_start,(unsigned char *)&(address->bits[address_len])); + address_len += 5; + blk_start = ptr; + } + ++ptr; + } + + if (ptr != blk_start) + return ANODE_ERR_ADDRESS_INVALID; + if (AnodeAddress_get_type(address) != ANODE_ADDRESS_ANODE_256_40) + return ANODE_ERR_ADDRESS_INVALID; + + return 0; +} diff --git a/attic/historic/anode/libanode/aes_digest.c b/attic/historic/anode/libanode/aes_digest.c new file mode 100644 index 0000000..07b0fc7 --- /dev/null +++ b/attic/historic/anode/libanode/aes_digest.c @@ -0,0 +1,85 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "anode.h" +#include "impl/aes.h" +#include "impl/misc.h" +#include "impl/types.h" + +void Anode_aes_digest(const void *const message,unsigned long message_len,void *const hash) +{ + unsigned char previous_digest[16]; + unsigned char digest[16]; + unsigned char block[32]; + const unsigned char *in = (const unsigned char *)message; + const unsigned char *end = in + message_len; + unsigned long block_counter; + AnodeAesExpandedKey expkey; + + ((uint64_t *)digest)[0] = 0ULL; + ((uint64_t *)digest)[1] = 0ULL; + ((uint64_t *)block)[0] = 0ULL; + ((uint64_t *)block)[1] = 0ULL; + ((uint64_t *)block)[2] = 0ULL; + ((uint64_t *)block)[3] = 0ULL; + + /* Davis-Meyer hash function built from block cipher */ + block_counter = 0; + while (in != end) { + block[block_counter++] = *(in++); + if (block_counter == 32) { + block_counter = 0; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + } + } + + /* Davis-Meyer end marker */ + block[block_counter++] = 0x80; + while (block_counter != 32) block[block_counter++] = 0; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + + /* Merkle-Damgård length padding */ + ((uint64_t *)block)[0] = 0ULL; + if (sizeof(message_len) >= 8) { /* 32/64 bit? this will get optimized out */ + block[8] = (uint8_t)((uint64_t)message_len >> 56); + block[9] = (uint8_t)((uint64_t)message_len >> 48); + block[10] = (uint8_t)((uint64_t)message_len >> 40); + block[11] = (uint8_t)((uint64_t)message_len >> 32); + } else ((uint32_t *)block)[2] = 0; + block[12] = (uint8_t)(message_len >> 24); + block[13] = (uint8_t)(message_len >> 16); + block[14] = (uint8_t)(message_len >> 8); + block[15] = (uint8_t)message_len; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + + ((uint64_t *)hash)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)hash)[1] = ((uint64_t *)digest)[1]; +} diff --git a/attic/historic/anode/libanode/anode.h b/attic/historic/anode/libanode/anode.h new file mode 100644 index 0000000..e0c51e2 --- /dev/null +++ b/attic/historic/anode/libanode/anode.h @@ -0,0 +1,795 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_ANODE_H +#define _ANODE_ANODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define ANODE_ADDRESS_LENGTH_ANODE_256_40 40 +#define ANODE_ADDRESS_MAX_LENGTH 40 +#define ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40 32 +#define ANODE_ADDRESS_MAX_SECRET_LENGTH 32 + +#define ANODE_ADDRESS_ID_LENGTH 8 +#define ANODE_ZONE_LENGTH 4 + +#define ANODE_ERR_NONE 0 +#define ANODE_ERR_INVALID_ARGUMENT (-10000) +#define ANODE_ERR_OUT_OF_MEMORY (-10001) +#define ANODE_ERR_INVALID_URI (-10002) +#define ANODE_ERR_BUFFER_TOO_SMALL (-10003) +#define ANODE_ERR_ADDRESS_INVALID (-10010) +#define ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED (-10011) +#define ANODE_ERR_CONNECTION_CLOSED (-10012) +#define ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE (-10013) +#define ANODE_ERR_CONNECT_FAILED (-10014) +#define ANODE_ERR_UNABLE_TO_BIND (-10015) +#define ANODE_ERR_TOO_MANY_OPEN_SOCKETS (-10016) +#define ANODE_ERR_DNS_NAME_NOT_FOUND_OR_TIMED_OUT (-10017) + +/** + * Get a human-readable error description for an error code + * + * The value of 'err' can be either negative or positive. + * + * @param err Error code + * @return Human-readable description + */ +extern const char *Anode_strerror(int err); + +/* ----------------------------------------------------------------------- */ +/* Secure random source */ +/* ----------------------------------------------------------------------- */ + +/** + * Opaque secure random instance + */ +typedef void AnodeSecureRandom; + +/** + * Initialize a secure random source + * + * No cleanup/destructor is necessary. + * + * @param srng Random structure to initialize + */ +extern AnodeSecureRandom *AnodeSecureRandom_new(); + +/** + * Generate random bytes + * + * @param srng Secure random source + * @param buf Buffer to fill + * @param count Number of bytes to generate + */ +extern void AnodeSecureRandom_gen_bytes(AnodeSecureRandom *srng,void *buf,long count); + +/** + * Destroy and free a secure random instance + * + * @param srng Secure random source + */ +extern void AnodeSecureRandom_delete(AnodeSecureRandom *srng); + +/* ----------------------------------------------------------------------- */ +/* AES-256 derived Davis-Meyer hash function */ +/* ----------------------------------------------------------------------- */ + +/** + * Digest a message using AES-DIGEST to yield a 16-byte hash code + * + * @param message Message to digest + * @param message_len Length of message in bytes + * @param hash Buffer to store 16 byte hash code + */ +extern void Anode_aes_digest( + const void *const message, + unsigned long message_len, + void *const hash); + +/* ----------------------------------------------------------------------- */ +/* Address Types and Components */ +/* ----------------------------------------------------------------------- */ + +/** + * Anode address + * + * The first byte always identifies the address type, which right now can + * only be type 1 (ANODE-256-40). + */ +typedef struct +{ + char bits[ANODE_ADDRESS_MAX_LENGTH]; +} AnodeAddress; + +/** + * 8-byte short Anode address ID + */ +typedef struct +{ + char bits[ANODE_ADDRESS_ID_LENGTH]; +} AnodeAddressId; + +/** + * 4-byte Anode zone ID + */ +typedef struct +{ + char bits[ANODE_ZONE_LENGTH]; +} AnodeZone; + +/** + * Anode address types + */ +enum AnodeAddressType +{ + ANODE_ADDRESS_ANODE_256_40 = 1 +}; + +/** + * Get the type of an Anode address + * + * This is a shortcut macro for just looking at the first byte and casting + * it to the AnodeAddressType enum. + * + * @param a Pointer to address + * @return Type as enum AnodeAddressType + */ +#define AnodeAddress_get_type(a) ((enum AnodeAddressType)((a)->bits[0])) + +/** + * Calculate the short 8 byte address ID from an address + * + * @param address Binary address + * @param short_address_id Buffer to store 8-byte short address ID + * @return 0 on success or error code on failure + */ +extern int AnodeAddress_calc_short_id( + const AnodeAddress *address, + AnodeAddressId *short_address_id); + +/** + * Extract the zone from an anode address + * + * @param address Binary address + * @param zone Zone value-result parameter to fill on success + * @return 0 on success or error code on failure + */ +extern int AnodeAddress_get_zone(const AnodeAddress *address,AnodeZone *zone); + +/** + * Convert an address to an ASCII string + * + * Anode addresses are 64 characters in ASCII form, so the buffer should + * have 65 bytes of space. + * + * @param address Address to convert + * @param buf Buffer to receive address in string form (should have 65 bytes of space) + * @param len Length of buffer + * @return Length of resulting string or a negative error code on error + */ +extern int AnodeAddress_to_string(const AnodeAddress *address,char *buf,int len); + +/** + * Convert a string into an address + * + * @param str Address in string form + * @param address Address buffer to receive result + * @return Zero on sucess or error code on error + */ +extern int AnodeAddress_from_string(const char *str,AnodeAddress *address); + +/** + * Supported network address types + */ +enum AnodeNetworkAddressType +{ + ANODE_NETWORK_ADDRESS_IPV4 = 0, + ANODE_NETWORK_ADDRESS_IPV6 = 1, + ANODE_NETWORK_ADDRESS_ETHERNET = 2, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_USB = 3, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_BLUETOOTH = 4, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_IPC = 5, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_80211S = 6, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_SERIAL = 7, /* reserved but unused */ + ANODE_NETWORK_ADDRESS_ANODE_256_40 = 8 +}; + +/** + * Anode network address + * + * This can contain an address of any type: IPv4, IPv6, or Anode, and is used + * with the common transport API. + * + * The length of the address stored in bits[] is determined by the type. + */ +typedef struct +{ + enum AnodeNetworkAddressType type; + char bits[ANODE_ADDRESS_MAX_LENGTH]; +} AnodeNetworkAddress; + +/** + * An endpoint with an address and a port + */ +typedef struct +{ + AnodeNetworkAddress address; + int port; +} AnodeNetworkEndpoint; + +/* Constants for binding to any address (v4 or v6) */ +extern const AnodeNetworkAddress AnodeNetworkAddress_IP_ANY_V4; +extern const AnodeNetworkAddress AnodeNetworkAddress_IP_ANY_V6; + +/* Local host address in v4 and v6 */ +extern const AnodeNetworkAddress AnodeNetworkAddress_IP_LOCAL_V4; +extern const AnodeNetworkAddress AnodeNetworkAddress_IP_LOCAL_V6; + +/** + * Convert a network address to an ASCII string + * + * The buffer must have room for a 15 character string for IPv4, a 40 byte + * string for IPv6, and a 64 byte string for Anode addresses. This does not + * include the trailing null. + * + * @param address Address to convert + * @param buf Buffer to receive address in string form + * @param len Length of buffer + * @return Length of resulting string or a negative error code on error + */ +extern int AnodeNetworkAddress_to_string(const AnodeNetworkAddress *address,char *buf,int len); + +/** + * Convert a string into a network address of the correct type + * + * @param str Address in string form + * @param address Address buffer to receive result + * @return Zero on sucess or error code on error + */ +extern int AnodeNetworkAddress_from_string(const char *str,AnodeNetworkAddress *address); + +/** + * Fill a network endpoint from a C-API sockaddr structure + * + * The argument must be struct sockaddr_in for IPv4 or sockaddr_in6 for IPv6. + * The common sin_family field will be used to differentiate. + * + * @param sockaddr Pointer to proper sockaddr structure + * @param endpoint Endpoint structure to fill + * @return Zero on success or error on failure + */ +extern int AnodeNetworkEndpoint_from_sockaddr(const void *sockaddr,AnodeNetworkEndpoint *endpoint); + +/** + * Fill a sockaddr from a network endpoint + * + * To support either IPv4 or IPv6 addresses, there is a sockaddr_storage + * structure in most C APIs. If you supply anything other than an IP address + * such as an Anode address, this will return an error. + * + * @param endpoint Endpoint structure to convert + * @param sockaddr Sockaddr structure storage + * @param sockaddr_len Length of sockaddr structure storage in bytes + * @return Zero on success or error on failure + */ +extern int AnodeNetworkEndpoint_to_sockaddr(const AnodeNetworkEndpoint *endpoint,void *sockaddr,int sockaddr_len); + +/* ----------------------------------------------------------------------- */ +/* Identity Generation and Management */ +/* ----------------------------------------------------------------------- */ + +/** + * Anode identity structure containing address and secret key + * + * This structure is memcpy-safe, and its members are accessible. + */ +typedef struct +{ + /* The public Anode address */ + AnodeAddress address; + + /* Short address ID */ + AnodeAddressId address_id; + + /* The secret key corresponding with the public address */ + /* Secret length is determined by address type */ + char secret[ANODE_ADDRESS_MAX_SECRET_LENGTH]; +} AnodeIdentity; + +/** + * Generate a new identity + * + * This generates a public/private key pair and from that generates an + * identity containing an address and a secret key. + * + * @param identity Destination structure to store new identity + * @param zone Zone ID + * @param type Type of identity to generate + * @return Zero on success, error on failure + */ +extern int AnodeIdentity_generate( + AnodeIdentity *identity, + const AnodeZone *zone, + enum AnodeAddressType type); + +/** + * Convert an Anode identity to a string representation + * + * @param identity Identity to convert + * @param dest String buffer + * @param dest_len Length of string buffer + * @return Length of string created or negative error code on failure + */ +extern int AnodeIdentity_to_string( + const AnodeIdentity *identity, + char *dest, + int dest_len); + +/** + * Convert a string representation to an Anode identity structure + * + * @param identity Destination structure to fill + * @param str C-string containing string representation + * @return Zero on success or negative error code on failure + */ +extern int AnodeIdentity_from_string( + AnodeIdentity *identity, + const char *str); + +/* ----------------------------------------------------------------------- */ +/* Transport API */ +/* ----------------------------------------------------------------------- */ + +struct _AnodeTransport; +typedef struct _AnodeTransport AnodeTransport; +struct _AnodeEvent; +typedef struct _AnodeEvent AnodeEvent; + +/** + * Anode socket + */ +typedef struct +{ + /* Type of socket (read-only) */ + enum { + ANODE_SOCKET_DATAGRAM = 1, + ANODE_SOCKET_STREAM_LISTEN = 2, + ANODE_SOCKET_STREAM_CONNECTION = 3 + } type; + + /* Socket state */ + enum { + ANODE_SOCKET_CLOSED = 0, + ANODE_SOCKET_OPEN = 1, + ANODE_SOCKET_CONNECTING = 2, + } state; + + /* Local address or remote address for stream connections (read-only) */ + AnodeNetworkEndpoint endpoint; + + /* Name of owning class (read-only) */ + const char *class_name; + + /* Pointers for end user use (writable) */ + void *user_ptr[2]; + + /* Special handler to receive events or null for default (writable) */ + void (*event_handler)(const AnodeEvent *event); +} AnodeSocket; + +/** + * Anode transport I/O event + */ +struct _AnodeEvent +{ + enum { + ANODE_TRANSPORT_EVENT_DATAGRAM_RECEIVED = 1, + ANODE_TRANSPORT_EVENT_STREAM_INCOMING_CONNECT = 2, + ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_ESTABLISHED = 3, + ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED = 4, + ANODE_TRANSPORT_EVENT_STREAM_CLOSED = 5, + ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED = 6, + ANODE_TRANSPORT_EVENT_STREAM_AVAILABLE_FOR_WRITE = 7, + ANODE_TRANSPORT_EVENT_DNS_RESULT = 8 + } type; + + AnodeTransport *transport; + + /* Anode socket corresponding to this event */ + AnodeSocket *sock; + + /* Originating endpoint for incoming datagrams */ + AnodeNetworkEndpoint *datagram_from; + + /* DNS lookup results */ + const char *dns_name; + AnodeNetworkAddress *dns_addresses; + int dns_address_count; + + /* Error code or 0 for none */ + int error_code; + + /* Data for incoming datagrams and stream received events */ + int data_length; + char *data; +}; + +/** + * Enum used for dns_resolve method in transport to specify query rules + * + * This can be specified for ipv4, ipv6, and Anode address types to tell the + * DNS resolver when to bother querying for addresses of the given type. + * NEVER means to never query for this type, and ALWAYS means to always + * query. IF_NO_PREVIOUS means to query for this type if no addresses were + * found in previous queries. Addresses are queried in the order of ipv4, + * ipv6, then Anode, so if you specify IF_NO_PREVIOUS for all three you will + * get addresses in that order of priority. + */ +enum AnodeTransportDnsIncludeMode +{ + ANODE_TRANSPORT_DNS_QUERY_NEVER = 0, + ANODE_TRANSPORT_DNS_QUERY_ALWAYS = 1, + ANODE_TRANSPORT_DNS_QUERY_IF_NO_PREVIOUS = 2 +}; + +struct _AnodeTransport +{ + /** + * Set the default event handler + * + * @param transport Transport engine + * @param event_handler Default event handler + */ + void (*set_default_event_handler)(AnodeTransport *transport, + void (*event_handler)(const AnodeEvent *event)); + + /** + * Enqueue a function to be executed during a subsequent call to poll() + * + * This can be called from other threads, so it can be used to pass a + * message to the I/O thread in multithreaded applications. + * + * If it is called from the same thread, the function is still queued to be + * run later rather than being run instantly. + * + * The order in which invoked functions are called is undefined. + * + * @param transport Transport engine + * @param ptr Arbitrary pointer to pass to function to be called + * @param func Function to be called + */ + void (*invoke)(AnodeTransport *transport, + void *ptr, + void (*func)(void *)); + + /** + * Initiate a forward DNS query + * + * @param transport Transport instance + * @param name DNS name to query + * @param event_handler Event handler or null for default event path + * @param ipv4_include_mode Inclusion mode for IPv4 addresses + * @param ipv6_include_mode Inclusion mode for IPv6 addresses + * @param anode_include_mode Inclusion mode for Anode addresses + */ + void (*dns_resolve)(AnodeTransport *transport, + const char *name, + void (*event_handler)(const AnodeEvent *), + enum AnodeTransportDnsIncludeMode ipv4_include_mode, + enum AnodeTransportDnsIncludeMode ipv6_include_mode, + enum AnodeTransportDnsIncludeMode anode_include_mode); + + /** + * Open a datagram socket + * + * @param transport Transport instance + * @param local_address Local address to bind + * @param local_port Local port to bind + * @param error_code Value-result parameter to receive error code on error + * @return Listen socket or null if error (check error_code in error case) + */ + AnodeSocket *(*datagram_listen)(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code); + + /** + * Open a socket to listen for incoming stream connections + * + * @param transport Transport instance + * @param local_address Local address to bind + * @param local_port Local port to bind + * @param error_code Value-result parameter to receive error code on error + * @return Listen socket or null if error (check error_code in error case) + */ + AnodeSocket *(*stream_listen)(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code); + + /** + * Send a datagram to a network endpoint + * + * @param transport Transport instance + * @param socket Originating datagram socket + * @param data Data to send + * @param data_len Length of data to send + * @param to_endpoint Destination endpoint + * @return Zero on success or error code on error + */ + int (*datagram_send)(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len, + const AnodeNetworkEndpoint *to_endpoint); + + /** + * Initiate an outgoing stream connection attempt + * + * For IPv4 and IPv6 addresses, this will initiate a TCP connection. For + * Anode addresses, Anode's internal streaming protocol will be used. + * + * @param transport Transport instance + * @param to_endpoint Destination endpoint + * @param error_code Error code value-result parameter, filled on error + * @return Stream socket object or null on error (check error_code) + */ + AnodeSocket *(*stream_connect)(AnodeTransport *transport, + const AnodeNetworkEndpoint *to_endpoint, + int *error_code); + + /** + * Indicate that you are interested in writing to a stream + * + * This does nothing if the socket is not a stream connection or is not + * connected. + * + * @param transport Transport instance + * @param sock Stream connection + */ + void (*stream_start_writing)(AnodeTransport *transport, + AnodeSocket *sock); + + /** + * Indicate that you are no longer interested in writing to a stream + * + * This does nothing if the socket is not a stream connection or is not + * connected. + * + * @param transport Transport instance + * @param sock Stream connection + */ + void (*stream_stop_writing)(AnodeTransport *transport, + AnodeSocket *sock); + + /** + * Send data to a stream connection + * + * This must be called after a stream is indicated to be ready for writing. + * It returns the number of bytes actually written, or a negative error + * code on failure. + * + * A return value of zero can occur here, and simply indicates that nothing + * was sent. This may occur with certain network stacks on certain + * platforms. + * + * @param transport Transport engine + * @param sock Stream socket + * @param data Data to send + * @param data_len Maximum data to send in bytes + * @return Actual data sent or negative error code on error + */ + int (*stream_send)(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len); + + /** + * Close a socket + * + * If the socket is a stream connection in the connected state, this + * will generate a stream closed event with a zero error_code to indicate + * a normal close. + * + * @param transport Transport engine + * @param sock Socket object + */ + void (*close)(AnodeTransport *transport, + AnodeSocket *sock); + + /** + * Run main polling loop + * + * This should be called repeatedly from the I/O thread of your main + * process. It blocks until one or more events occur, and then returns + * the number of events. Error returns here are fatal and indicate + * serious problems such as build or platform issues or a lack of any + * network interface. + * + * Functions queued with invoke() are also called inside here. + * + * @param transport Transport engine + * @return Number of events handled or negative on (fatal) error + */ + int (*poll)(AnodeTransport *transport); + + /** + * Check whether transport supports an address type + * + * Inheriting classes should call their base if they do not natively + * speak the specified type. + * + * @param transport Transport engine + * @param at Address type + * @return Nonzero if true + */ + int (*supports_address_type)(const AnodeTransport *transport, + enum AnodeNetworkAddressType at); + + /** + * Get the instance of AnodeTransport under this one (if any) + * + * @param transport Transport engine + * @return Base instance or null if none + */ + AnodeTransport *(*base_instance)(const AnodeTransport *transport); + + /** + * @param transport Transport engine + * @return Class name of this instance + */ + const char *(*class_name)(AnodeTransport *transport); + + /** + * Delete this transport and its base transports + * + * The 'transport' pointer and any streams or sockets it owns are no longer + * valid after this call. + * + * @param transport Transport engine + */ + void (*delete)(AnodeTransport *transport); +}; + +/** + * Construct a new system transport + * + * This is the default base for AnodeTransport, and it is constructed + * automatically if 'base' is null in AnodeTransport_new(). However, it also + * exposed to the user so that specialized transports (such as those that use + * proxy servers) can be developed on top of it. These in turn can be supplied + * as 'base' to AnodeTransport_new() to talk Anode over these transports. + * + * The system transport supports IP protocols and possibly others. + * + * @param base Base class or null for none (usually null) + * @return Base transport engine instance + */ +extern AnodeTransport *AnodeSystemTransport_new(AnodeTransport *base); + +/** + * Construct a new Anode core transport + * + * This is the transport that talks Anode using the specified base transport. + * Requests for other address types are passed through to the base. If the + * base is null, an instance of AnodeSystemTransport is used. + * + * Since transport engines inherit their functionality, this transport + * will also do standard IP and everything else that the system transport + * supports. Most users will just want to construct this with a null base. + * + * @param base Base transport to use, or null to use SystemTransport + * @return Anode transport engine or null on error + */ +extern AnodeTransport *AnodeCoreTransport_new(AnodeTransport *base); + +/* ----------------------------------------------------------------------- */ +/* URI Parser */ +/* ----------------------------------------------------------------------- */ + +/** + * URI broken down by component + */ +typedef struct +{ + char scheme[8]; + char username[64]; + char password[64]; + char host[128]; + char path[256]; + char query[256]; + char fragment[64]; + int port; +} AnodeURI; + +/** + * URI parser + * + * A buffer too small error will occur if any field is too large for the + * AnodeURI structure. + * + * @param parsed_uri Structure to fill with parsed URI data + * @param uri_string URI in string format + * @return Zero on success or error on failure + */ +extern int AnodeURI_parse(AnodeURI *parsed_uri,const char *uri_string); + +/** + * Output a URI in string format + * + * @param uri URI to output as string + * @param buf Buffer to store URI string + * @param len Length of buffer + * @return Buffer or null on error + */ +extern char *AnodeURI_to_string(const AnodeURI *uri,char *buf,int len); + +/* ----------------------------------------------------------------------- */ +/* Zone File Lookup and Dictionary */ +/* ----------------------------------------------------------------------- */ + +/** + * Zone file dictionary + */ +typedef void AnodeZoneFile; + +/** + * Start asynchronous zone fetch + * + * When the zone is retrieved, the lookup handler is called. If zone lookup + * failed, the zone file argument to the handler will be null. + * + * @param transport Transport engine + * @param zone Zone ID + * @param user_ptr User pointer + * @param zone_lookup_handler Handler for Anode zone lookup + */ +extern void AnodeZoneFile_lookup( + AnodeTransport *transport, + const AnodeZone *zone, + void *ptr, + void (*zone_lookup_handler)(const AnodeZone *,AnodeZoneFile *,void *)); + +/** + * Look up a key in a zone file + * + * @param zone Zone file object + * @param key Key to get in zone file + */ +extern const char *AnodeZoneFile_get(const AnodeZoneFile *zone,const char *key); + +/** + * Free a zone file + * + * @param zone Zone to free + */ +extern void AnodeZoneFile_free(AnodeZoneFile *zone); + +/* ----------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/attic/historic/anode/libanode/errors.c b/attic/historic/anode/libanode/errors.c new file mode 100644 index 0000000..6836bdc --- /dev/null +++ b/attic/historic/anode/libanode/errors.c @@ -0,0 +1,52 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "anode.h" + +struct AnodeErrDesc +{ + int code; + const char *desc; +}; + +#define TOTAL_ERRORS 12 +static const struct AnodeErrDesc ANODE_ERRORS[TOTAL_ERRORS] = { + { ANODE_ERR_NONE, "No error (success)" }, + { ANODE_ERR_INVALID_ARGUMENT, "Invalid argument" }, + { ANODE_ERR_OUT_OF_MEMORY, "Out of memory" }, + { ANODE_ERR_INVALID_URI, "Invalid URI" }, + { ANODE_ERR_BUFFER_TOO_SMALL, "Supplied buffer too small" }, + { ANODE_ERR_ADDRESS_INVALID, "Address invalid" }, + { ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED, "Address type not supported"}, + { ANODE_ERR_CONNECTION_CLOSED, "Connection closed"}, + { ANODE_ERR_CONNECT_FAILED, "Connect failed"}, + { ANODE_ERR_UNABLE_TO_BIND, "Unable to bind to address"}, + { ANODE_ERR_TOO_MANY_OPEN_SOCKETS, "Too many open sockets"}, + { ANODE_ERR_DNS_NAME_NOT_FOUND_OR_TIMED_OUT, "DNS name not found or timed out"} +}; + +extern const char *Anode_strerror(int err) +{ + int i; + int negerr = -err; + + for(i=0;i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "impl/types.h" +#include "impl/ec.h" +#include "impl/misc.h" +#include "anode.h" + +int AnodeIdentity_generate(AnodeIdentity *identity,const AnodeZone *zone,enum AnodeAddressType type) +{ + struct AnodeECKeyPair kp; + + switch(type) { + case ANODE_ADDRESS_ANODE_256_40: + if (!AnodeECKeyPair_generate(&kp)) + return ANODE_ERR_OUT_OF_MEMORY; + + identity->address.bits[0] = (unsigned char)ANODE_ADDRESS_ANODE_256_40; + + identity->address.bits[1] = zone->bits[0]; + identity->address.bits[2] = zone->bits[1]; + identity->address.bits[3] = zone->bits[2]; + identity->address.bits[4] = zone->bits[3]; + + identity->address.bits[5] = 0; + identity->address.bits[6] = 0; + + Anode_memcpy((void *)&(identity->address.bits[7]),(const void *)kp.pub.key,ANODE_EC_PUBLIC_KEY_BYTES); + Anode_memcpy((void *)identity->secret,(const void *)kp.priv.key,kp.priv.bytes); + + AnodeAddress_calc_short_id(&identity->address,&identity->address_id); + + AnodeECKeyPair_destroy(&kp); + + return 0; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} + +int AnodeIdentity_to_string(const AnodeIdentity *identity,char *dest,int dest_len) +{ + char hexbuf[128]; + char strbuf[128]; + int n; + + if ((n = AnodeAddress_to_string(&identity->address,strbuf,sizeof(strbuf))) <= 0) + return n; + + switch(AnodeAddress_get_type(&identity->address)) { + case ANODE_ADDRESS_ANODE_256_40: + Anode_to_hex((const unsigned char *)identity->secret,ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40,hexbuf,sizeof(hexbuf)); + n = snprintf(dest,dest_len,"ANODE-256-40:%s:%s",strbuf,hexbuf); + if (n >= dest_len) + return ANODE_ERR_BUFFER_TOO_SMALL; + return n; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} + +int AnodeIdentity_from_string(AnodeIdentity *identity,const char *str) +{ + char buf[1024]; + char *id_name; + char *address; + char *secret; + int ec; + + Anode_str_copy(buf,str,sizeof(buf)); + + id_name = buf; + if (!id_name) return 0; + if (!*id_name) return 0; + address = (char *)Anode_strchr(id_name,':'); + if (!address) return 0; + if (!*address) return 0; + *(address++) = (char)0; + secret = (char *)Anode_strchr(address,':'); + if (!secret) return 0; + if (!*secret) return 0; + *(secret++) = (char)0; + + if (Anode_strcaseeq("ANODE-256-40",id_name)) { + if ((ec = AnodeAddress_from_string(address,&identity->address))) + return ec; + if (Anode_strlen(secret) != (ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40 * 2)) + return ANODE_ERR_INVALID_ARGUMENT; + Anode_from_hex(secret,(unsigned char *)identity->secret,sizeof(identity->secret)); + AnodeAddress_calc_short_id(&identity->address,&identity->address_id); + return 0; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} diff --git a/attic/historic/anode/libanode/impl/aes.c b/attic/historic/anode/libanode/impl/aes.c new file mode 100644 index 0000000..90e5e23 --- /dev/null +++ b/attic/historic/anode/libanode/impl/aes.c @@ -0,0 +1,72 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "aes.h" + +void Anode_cmac_aes256( + const AnodeAesExpandedKey *expkey, + const unsigned char *restrict data, + unsigned long data_len, + unsigned char *restrict mac) +{ + unsigned char cbc[16]; + unsigned char pad[16]; + const unsigned char *restrict pos = data; + unsigned long i; + unsigned long remaining = data_len; + unsigned char c; + + ((uint64_t *)((void *)cbc))[0] = 0ULL; + ((uint64_t *)((void *)cbc))[1] = 0ULL; + + while (remaining >= 16) { + ((uint64_t *)((void *)cbc))[0] ^= ((uint64_t *)((void *)pos))[0]; + ((uint64_t *)((void *)cbc))[1] ^= ((uint64_t *)((void *)pos))[1]; + pos += 16; + if (remaining > 16) + Anode_aes256_encrypt(expkey,cbc,cbc); + remaining -= 16; + } + + ((uint64_t *)((void *)pad))[0] = 0ULL; + ((uint64_t *)((void *)pad))[1] = 0ULL; + Anode_aes256_encrypt(expkey,pad,pad); + + c = pad[0] & 0x80; + for(i=0;i<15;++i) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[15] <<= 1; + if (c) + pad[15] ^= 0x87; + + if (remaining||(!data_len)) { + for(i=0;i> 7); + pad[15] <<= 1; + if (c) + pad[15] ^= 0x87; + } + + ((uint64_t *)((void *)mac))[0] = ((uint64_t *)((void *)pad))[0] ^ ((uint64_t *)((void *)cbc))[0]; + ((uint64_t *)((void *)mac))[1] = ((uint64_t *)((void *)pad))[1] ^ ((uint64_t *)((void *)cbc))[1]; + + Anode_aes256_encrypt(expkey,mac,mac); +} diff --git a/attic/historic/anode/libanode/impl/aes.h b/attic/historic/anode/libanode/impl/aes.h new file mode 100644 index 0000000..25e3393 --- /dev/null +++ b/attic/historic/anode/libanode/impl/aes.h @@ -0,0 +1,64 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_AES_H +#define _ANODE_AES_H + +#include +#include "types.h" + +/* This just glues us to OpenSSL's built-in AES-256 implementation */ + +#define ANODE_AES_BLOCK_SIZE 16 +#define ANODE_AES_KEY_SIZE 32 + +typedef AES_KEY AnodeAesExpandedKey; + +#define Anode_aes256_expand_key(k,ek) AES_set_encrypt_key((const unsigned char *)(k),256,(AES_KEY *)(ek)) + +/* Note: in and out can be the same thing */ +#define Anode_aes256_encrypt(ek,in,out) AES_encrypt((const unsigned char *)(in),(unsigned char *)(out),(const AES_KEY *)(ek)) + +/* Note: iv is modified */ +static inline void Anode_aes256_cfb_encrypt( + const AnodeAesExpandedKey *expkey, + const unsigned char *in, + unsigned char *out, + unsigned char *iv, + unsigned long len) +{ + int tmp = 0; + AES_cfb128_encrypt(in,out,len,(const AES_KEY *)expkey,iv,&tmp,AES_ENCRYPT); +} +static inline void Anode_aes256_cfb_decrypt( + const AnodeAesExpandedKey *expkey, + const unsigned char *in, + unsigned char *out, + unsigned char *iv, + unsigned long len) +{ + int tmp = 0; + AES_cfb128_encrypt(in,out,len,(const AES_KEY *)expkey,iv,&tmp,AES_DECRYPT); +} + +/* CMAC message authentication code */ +void Anode_cmac_aes256( + const AnodeAesExpandedKey *expkey, + const unsigned char *restrict data, + unsigned long data_len, + unsigned char *restrict mac); + +#endif diff --git a/attic/historic/anode/libanode/impl/dictionary.c b/attic/historic/anode/libanode/impl/dictionary.c new file mode 100644 index 0000000..060c381 --- /dev/null +++ b/attic/historic/anode/libanode/impl/dictionary.c @@ -0,0 +1,239 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "dictionary.h" + +static const char *EMPTY_STR = ""; + +void AnodeDictionary_clear(struct AnodeDictionary *d) +{ + struct AnodeDictionaryEntry *e,*ne; + int oldcs; + unsigned int i; + + oldcs = d->case_sensitive; + + for(i=0;iht[i]; + while (e) { + ne = e->next; + if ((e->key)&&(e->key != EMPTY_STR)) free((void *)e->key); + if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value); + free((void *)e); + e = ne; + } + } + + Anode_zero((void *)d,sizeof(struct AnodeDictionary)); + + d->case_sensitive = oldcs; +} + +void AnodeDictionary_put(struct AnodeDictionary *d,const char *key,const char *value) +{ + struct AnodeDictionaryEntry *e; + char *p1; + const char *p2; + unsigned int bucket = (d->case_sensitive) ? AnodeDictionary__get_bucket(key) : AnodeDictionary__get_bucket_ci(key); + unsigned int len,i; + + e = d->ht[bucket]; + while (e) { + if (((d->case_sensitive) ? Anode_streq(key,e->key) : Anode_strcaseeq(key,e->key))) { + if (!d->case_sensitive) { + p1 = e->key; + p2 = key; + while (*p2) *(p1++) = *(p2++); + } + + len = 0; + while (value[len]) ++len; + if (len) { + if ((e->value)&&(e->value != EMPTY_STR)) + e->value = (char *)realloc((void *)e->value,len + 1); + else e->value = (char *)malloc(len + 1); + for(i=0;ivalue[i] = value[i]; + e->value[i] = (char)0; + } else { + if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value); + e->value = (char *)EMPTY_STR; + } + return; + } + e = e->next; + } + + e = (struct AnodeDictionaryEntry *)malloc(sizeof(struct AnodeDictionaryEntry)); + + len = 0; + while (key[len]) ++len; + if (len) { + e->key = (char *)malloc(len + 1); + for(i=0;ikey[i] = key[i]; + e->key[i] = (char)0; + } else e->key = (char *)EMPTY_STR; + + len = 0; + while (value[len]) ++len; + if (len) { + e->value = (char *)malloc(len + 1); + for(i=0;ivalue[i] = value[i]; + e->value[i] = (char)0; + } else e->value = (char *)EMPTY_STR; + + e->next = d->ht[bucket]; + d->ht[bucket] = e; + + ++d->size; +} + +void AnodeDictionary_read( + struct AnodeDictionary *d, + char *in, + const char *line_breaks, + const char *kv_breaks, + const char *comment_chars, + char escape_char, + int trim_whitespace_from_keys, + int trim_whitespace_from_values) +{ + char *line = in; + char *key; + char *value; + char *p1,*p2,*p3; + char last = ~escape_char; + int eof_state = 0; + + for(;;) { + if ((!*in)||((Anode_strchr(line_breaks,*in))&&((last != escape_char)||(!escape_char)))) { + if (!*in) + eof_state = 1; + else *in = (char)0; + + if ((*line)&&((comment_chars)&&(!Anode_strchr(comment_chars,*line)))) { + key = line; + + while (*line) { + if ((Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char))) { + *(line++) = (char)0; + break; + } else last = *(line++); + } + while ((*line)&&(Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char))) + last = *(line++); + value = line; + + if (escape_char) { + p1 = key; + while (*p1) { + if (*p1 == escape_char) { + p2 = p1; + p3 = p1 + 1; + while (*p3) + *(p2++) = *(p3++); + *p2 = (char)0; + } + ++p1; + } + p1 = value; + while (*p1) { + if (*p1 == escape_char) { + p2 = p1; + p3 = p1 + 1; + while (*p3) + *(p2++) = *(p3++); + *p2 = (char)0; + } + ++p1; + } + } + + if (trim_whitespace_from_keys) + Anode_trim(key); + if (trim_whitespace_from_values) + Anode_trim(value); + + AnodeDictionary_put(d,key,value); + } + + if (eof_state) + break; + else line = in + 1; + } + last = *(in++); + } +} + +long AnodeDictionary_write( + struct AnodeDictionary *d, + char *out, + long out_size, + const char *line_break, + const char *kv_break) +{ + struct AnodeDictionaryEntry *e; + const char *tmp; + long ptr = 0; + unsigned int bucket; + + if (out_size <= 0) + return -1; + + for(bucket=0;bucketht[bucket]; + while (e) { + tmp = e->key; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = kv_break; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = e->value; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = line_break; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + e = e->next; + } + } + + out[ptr] = (char)0; + + return ptr; +} diff --git a/attic/historic/anode/libanode/impl/dictionary.h b/attic/historic/anode/libanode/impl/dictionary.h new file mode 100644 index 0000000..48e1642 --- /dev/null +++ b/attic/historic/anode/libanode/impl/dictionary.h @@ -0,0 +1,126 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/* This is a simple string hash table suitable for small tables such as zone + * files or HTTP header lists. */ + +#ifndef _ANODE_DICTIONARY_H +#define _ANODE_DICTIONARY_H + +#include "misc.h" + +/* This is a fixed hash table and is designed for relatively small numbers + * of keys for things like zone files. */ +#define ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE 16 +#define ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK 15 + +/* Computes a hash code for a string and returns the hash bucket */ +static inline unsigned int AnodeDictionary__get_bucket(const char *s) +{ + unsigned int hc = 3; + while (*s) + hc = ((hc << 4) + hc) + (unsigned int)*(s++); + return ((hc ^ (hc >> 4)) & ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK); +} +/* Case insensitive version of get_bucket */ +static inline unsigned int AnodeDictionary__get_bucket_ci(const char *s) +{ + unsigned int hc = 3; + while (*s) + hc = ((hc << 4) + hc) + (unsigned int)Anode_tolower(*(s++)); + return ((hc ^ (hc >> 4)) & ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK); +} + +struct AnodeDictionaryEntry +{ + char *key; + char *value; + struct AnodeDictionaryEntry *next; +}; + +struct AnodeDictionary +{ + struct AnodeDictionaryEntry *ht[ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE]; + unsigned int size; + int case_sensitive; +}; + +static inline void AnodeDictionary_init(struct AnodeDictionary *d,int case_sensitive) +{ + Anode_zero((void *)d,sizeof(struct AnodeDictionary)); + d->case_sensitive = case_sensitive; +} + +void AnodeDictionary_clear(struct AnodeDictionary *d); + +static inline void AnodeDictionary_destroy(struct AnodeDictionary *d) +{ + AnodeDictionary_clear(d); +} + +void AnodeDictionary_put(struct AnodeDictionary *d,const char *key,const char *value); + +static inline const char *AnodeDictionary_get(struct AnodeDictionary *d,const char *key) +{ + struct AnodeDictionaryEntry *e; + unsigned int bucket = (d->case_sensitive) ? AnodeDictionary__get_bucket(key) : AnodeDictionary__get_bucket_ci(key); + + e = d->ht[bucket]; + while (e) { + if ((d->case_sensitive ? Anode_streq(key,e->key) : Anode_strcaseeq(key,e->key))) + return e->value; + e = e->next; + } + + return (const char *)0; +} + +static inline void AnodeDictionary_iterate( + struct AnodeDictionary *d, + void *arg, + int (*func)(void *,const char *,const char *)) +{ + struct AnodeDictionaryEntry *e; + unsigned int bucket; + + for(bucket=0;bucketht[bucket]; + while (e) { + if (!func(arg,e->key,e->value)) + return; + e = e->next; + } + } +} + +void AnodeDictionary_read( + struct AnodeDictionary *d, + char *in, + const char *line_breaks, + const char *kv_breaks, + const char *comment_chars, + char escape_char, + int trim_whitespace_from_keys, + int trim_whitespace_from_values); + +long AnodeDictionary_write( + struct AnodeDictionary *d, + char *out, + long out_size, + const char *line_break, + const char *kv_break); + +#endif diff --git a/attic/historic/anode/libanode/impl/dns_txt.c b/attic/historic/anode/libanode/impl/dns_txt.c new file mode 100644 index 0000000..b5cf131 --- /dev/null +++ b/attic/historic/anode/libanode/impl/dns_txt.c @@ -0,0 +1,93 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dns_txt.h" + +#ifndef C_IN +#define C_IN ns_c_in +#endif +#ifndef T_TXT +#define T_TXT ns_t_txt +#endif + +static volatile int Anode_resolver_initialized = 0; + +int Anode_sync_resolve_txt(const char *host,char *txt,unsigned int txt_len) +{ + unsigned char answer[16384],*pptr,*end; + char name[16384]; + int len,explen,i; + + if (!Anode_resolver_initialized) { + Anode_resolver_initialized = 1; + res_init(); + } + + /* Do not taunt happy fun ball. */ + + len = res_search(host,C_IN,T_TXT,answer,sizeof(answer)); + if (len > 12) { + pptr = answer + 12; + end = answer + len; + + explen = dn_expand(answer,end,pptr,name,sizeof(name)); + if (explen > 0) { + pptr += explen; + + if ((pptr + 2) >= end) return 2; + if (ntohs(*((uint16_t *)pptr)) == T_TXT) { + pptr += 4; + if (pptr >= end) return 2; + + explen = dn_expand(answer,end,pptr,name,sizeof(name)); + if (explen > 0) { + pptr += explen; + + if ((pptr + 2) >= end) return 2; + if (ntohs(*((uint16_t *)pptr)) == T_TXT) { + pptr += 10; + if (pptr >= end) return 2; + + len = *(pptr++); + if (len <= 0) return 2; + if ((pptr + len) > end) return 2; + + if (txt_len < (len + 1)) + return 4; + else { + for(i=0;i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_DNS_TXT_H +#define _ANODE_DNS_TXT_H + +/** + * Synchronous TXT resolver routine + * + * Error codes: + * 1 - I/O error + * 2 - Invalid response + * 3 - TXT record not found + * 4 - Destination buffer too small for result + * + * @param host Host name + * @param txt Buffer to store TXT result + * @param txt_len Size of buffer + * @return Zero on success, special error code on failure + */ +int Anode_sync_resolve_txt(const char *host,char *txt,unsigned int txt_len); + +#endif + diff --git a/attic/historic/anode/libanode/impl/ec.c b/attic/historic/anode/libanode/impl/ec.c new file mode 100644 index 0000000..2604b4a --- /dev/null +++ b/attic/historic/anode/libanode/impl/ec.c @@ -0,0 +1,219 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "misc.h" +#include "ec.h" + +static EC_GROUP *AnodeEC_group = (EC_GROUP *)0; + +static void *AnodeEC_KDF(const void *in,size_t inlen,void *out,size_t *outlen) +{ + unsigned long i,longest_length; + + if (!*outlen) + return out; + + for(i=0;i<(unsigned long)*outlen;++i) + ((unsigned char *)out)[i] = (unsigned char)0; + + longest_length = inlen; + if (longest_length < *outlen) + longest_length = *outlen; + for(i=0;i ANODE_EC_PRIME_BYTES)||(len < 0)) { + EC_KEY_free(key); + return 0; + } + BN_bn2bin(EC_KEY_get0_private_key(key),&(pair->priv.key[ANODE_EC_PRIME_BYTES - len])); + pair->priv.bytes = ANODE_EC_PRIME_BYTES; + + len = EC_POINT_point2oct(AnodeEC_group,EC_KEY_get0_public_key(key),POINT_CONVERSION_COMPRESSED,pair->pub.key,sizeof(pair->pub.key),0); + if (len != ANODE_EC_PUBLIC_KEY_BYTES) { + EC_KEY_free(key); + return 0; + } + pair->pub.bytes = ANODE_EC_PUBLIC_KEY_BYTES; + + /* Keep a copy of OpenSSL's structure around so we don't have to re-init + * it every time we use our key pair structure. */ + pair->internal_key = key; + + return 1; +} + +int AnodeECKeyPair_init(struct AnodeECKeyPair *pair,const struct AnodeECKey *pub,const struct AnodeECKey *priv) +{ + EC_KEY *key; + EC_POINT *kxy; + BIGNUM *pn; + + if (!AnodeEC_group) { + AnodeEC_group = EC_GROUP_new_by_curve_name(ANODE_EC_GROUP); + if (!AnodeEC_group) return 0; + } + + key = EC_KEY_new(); + if (!key) + return 0; + + if (!EC_KEY_set_group(key,AnodeEC_group)) { + EC_KEY_free(key); + return 0; + } + + /* Grab the private key */ + if (priv->bytes != ANODE_EC_PRIME_BYTES) { + EC_KEY_free(key); + return 0; + } + pn = BN_new(); + if (!pn) { + EC_KEY_free(key); + return 0; + } + if (!BN_bin2bn(priv->key,ANODE_EC_PRIME_BYTES,pn)) { + BN_free(pn); + EC_KEY_free(key); + return 0; + } + if (!EC_KEY_set_private_key(key,pn)) { + BN_free(pn); + EC_KEY_free(key); + return 0; + } + BN_free(pn); + + /* Set the public key */ + if (pub->bytes != ANODE_EC_PUBLIC_KEY_BYTES) { + EC_KEY_free(key); + return 0; + } + kxy = EC_POINT_new(AnodeEC_group); + if (!kxy) { + EC_KEY_free(key); + return 0; + } + EC_POINT_oct2point(AnodeEC_group,kxy,pub->key,ANODE_EC_PUBLIC_KEY_BYTES,0); + if (!EC_KEY_set_public_key(key,kxy)) { + EC_POINT_free(kxy); + EC_KEY_free(key); + return 0; + } + EC_POINT_free(kxy); + + Anode_zero(pair,sizeof(struct AnodeECKeyPair)); + Anode_memcpy((void *)&(pair->pub),(const void *)pub,sizeof(struct AnodeECKey)); + Anode_memcpy((void *)&(pair->priv),(const void *)priv,sizeof(struct AnodeECKey)); + pair->internal_key = key; + + return 1; +} + +void AnodeECKeyPair_destroy(struct AnodeECKeyPair *pair) +{ + if (pair) { + if (pair->internal_key) + EC_KEY_free((EC_KEY *)pair->internal_key); + } +} + +int AnodeECKeyPair_agree(const struct AnodeECKeyPair *my_key_pair,const struct AnodeECKey *their_pub_key,unsigned char *key_buf,unsigned int key_len) +{ + EC_POINT *pub; + int i; + + if (!AnodeEC_group) { + AnodeEC_group = EC_GROUP_new_by_curve_name(ANODE_EC_GROUP); + if (!AnodeEC_group) return 0; + } + + if (!my_key_pair->internal_key) + return 0; + + if (their_pub_key->bytes != ANODE_EC_PUBLIC_KEY_BYTES) + return 0; + pub = EC_POINT_new(AnodeEC_group); + if (!pub) + return 0; + EC_POINT_oct2point(AnodeEC_group,pub,their_pub_key->key,ANODE_EC_PUBLIC_KEY_BYTES,0); + + i = ECDH_compute_key(key_buf,key_len,pub,(EC_KEY *)my_key_pair->internal_key,&AnodeEC_KDF); + if (i != (int)key_len) { + EC_POINT_free(pub); + return 0; + } + + EC_POINT_free(pub); + + return 1; +} + +void AnodeEC_random(unsigned char *buf,unsigned int len) +{ + RAND_pseudo_bytes(buf,len); +} diff --git a/attic/historic/anode/libanode/impl/ec.h b/attic/historic/anode/libanode/impl/ec.h new file mode 100644 index 0000000..f126266 --- /dev/null +++ b/attic/historic/anode/libanode/impl/ec.h @@ -0,0 +1,61 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/* Elliptic curve glue -- hides OpenSSL code behind this source module */ + +#ifndef _ANODE_EC_H +#define _ANODE_EC_H + +#include "misc.h" + +/* Right now, only one mode is supported: NIST-P-256. This is the only mode + * supported in the spec as well, and should be good for quite some time. + * If other modes are needed this code will need to be refactored. */ + +/* NIST-P-256 prime size in bytes */ +#define ANODE_EC_PRIME_BYTES 32 + +/* Sizes of key fields */ +#define ANODE_EC_GROUP NID_X9_62_prime256v1 +#define ANODE_EC_PUBLIC_KEY_BYTES (ANODE_EC_PRIME_BYTES + 1) +#define ANODE_EC_PRIVATE_KEY_BYTES ANODE_EC_PRIME_BYTES + +/* Larger of public or private key bytes, used for buffers */ +#define ANODE_EC_MAX_BYTES ANODE_EC_PUBLIC_KEY_BYTES + +struct AnodeECKey +{ + unsigned char key[ANODE_EC_MAX_BYTES]; + unsigned int bytes; +}; + +struct AnodeECKeyPair +{ + struct AnodeECKey pub; + struct AnodeECKey priv; + void *internal_key; +}; + +/* Key management functions */ +int AnodeECKeyPair_generate(struct AnodeECKeyPair *pair); +int AnodeECKeyPair_init(struct AnodeECKeyPair *pair,const struct AnodeECKey *pub,const struct AnodeECKey *priv); +void AnodeECKeyPair_destroy(struct AnodeECKeyPair *pair); +int AnodeECKeyPair_agree(const struct AnodeECKeyPair *my_key_pair,const struct AnodeECKey *their_pub_key,unsigned char *key_buf,unsigned int key_len); + +/* Provides access to the secure PRNG used to generate keys */ +void AnodeEC_random(unsigned char *buf,unsigned int len); + +#endif diff --git a/attic/historic/anode/libanode/impl/environment.c b/attic/historic/anode/libanode/impl/environment.c new file mode 100644 index 0000000..16e8ebe --- /dev/null +++ b/attic/historic/anode/libanode/impl/environment.c @@ -0,0 +1,118 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "environment.h" + +#ifdef WINDOWS +#include +#else +#include +#include +#endif + +static char Anode_cache_base[1024] = { 0 }; + +const char *Anode_get_cache() +{ + if (Anode_cache_base[0]) + return Anode_cache_base; + +#ifdef WINDOWS +#else + char tmp[1024]; + char home[1024]; + unsigned int i; + struct stat st; + const char *_home = getenv("HOME"); + + if (!_home) + return (const char *)0; + for(i=0;i * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,26 +12,19 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ + * along with this program. If not, see . */ -#ifndef ZT_NONCOPYABLE_HPP__ -#define ZT_NONCOPYABLE_HPP__ +#ifndef _ANODE_ENVIRONMENT_H +#define _ANODE_ENVIRONMENT_H -namespace ZeroTier { +#ifdef WINDOWS +#define ANODE_PATH_SEPARATOR '\\' +#else +#define ANODE_PATH_SEPARATOR '/' +#endif -/** - * A simple concept that belongs in the C++ language spec - */ -class NonCopyable -{ -protected: - NonCopyable() throw() {} -private: - NonCopyable(const NonCopyable&); - const NonCopyable& operator=(const NonCopyable&); -}; - -} // namespace ZeroTier +const char *Anode_get_cache(); +char *Anode_get_cache_sub(const char *cache_subdir,char *buf,unsigned int len); #endif + diff --git a/attic/historic/anode/libanode/impl/http_client.c b/attic/historic/anode/libanode/impl/http_client.c new file mode 100644 index 0000000..a398a58 --- /dev/null +++ b/attic/historic/anode/libanode/impl/http_client.c @@ -0,0 +1,558 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include "http_client.h" +#include "misc.h" +#include "types.h" + +/* How much to increment read buffer at each capacity top? */ +#define ANODE_HTTP_CAPACITY_INCREMENT 4096 + +static void AnodeHttpClient_close_and_fail(struct AnodeHttpClient *client) +{ + if (client->impl.tcp_connection) { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + } + + client->response.data_length = 0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + + if (client->handler) + client->handler(client); +} + +static void AnodeHttpClient_do_initiate_client(struct AnodeHttpClient *client) +{ + const char *method = ""; + long l,i; + + switch(client->method) { + case ANODE_HTTP_GET: method = "GET"; break; + case ANODE_HTTP_HEAD: method = "HEAD"; break; + case ANODE_HTTP_POST: method = "POST"; break; + } + client->impl.outbuf_len = snprintf((char *)client->impl.outbuf,sizeof(client->impl.outbuf), + "%s %s%s%s HTTP/1.1\r\nHost: %s:%d\r\n%s", + method, + client->uri.path, + ((client->uri.query[0]) ? "?" : ""), + client->uri.query, + client->uri.host, + ((client->uri.port > 0) ? client->uri.port : 80), + ((client->keepalive) ? "" : "Connection: close\r\n") + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + if (client->method == ANODE_HTTP_POST) { + if ((client->data)&&(client->data_length)) { + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Type: %s\r\n", + (client->data_content_type ? client->data_content_type : "application/x-www-form-urlencoded") + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Length: %u\r\n", + client->data_length + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + } else { + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Length: 0\r\n" + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + + l = AnodeDictionary_write(&(client->headers),(char *)client->impl.outbuf + client->impl.outbuf_len,(long)(sizeof(client->impl.outbuf) - client->impl.outbuf_len - 2),"\r\n",": "); + if (l < 0) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + client->impl.outbuf_len += (unsigned int)l; + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { /* sanity check */ + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + client->impl.outbuf[client->impl.outbuf_len++] = '\r'; + client->impl.outbuf[client->impl.outbuf_len++] = '\n'; + + if ((client->method == ANODE_HTTP_POST)&&(client->data)&&(client->data_length)) { + i = sizeof(client->impl.outbuf) - client->impl.outbuf_len; + if (i > client->data_length) + i = client->data_length; + Anode_memcpy((client->impl.outbuf + client->impl.outbuf_len),client->data,i); + client->impl.request_data_ptr += i; + client->impl.outbuf_len += i; + } + + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_SEND; + client->impl.transport_engine->tcp_start_writing(client->impl.transport_engine,client->impl.tcp_connection); +} + +static void AnodeHttpClient_tcp_outgoing_connect_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + int error_code) +{ + struct AnodeHttpClient *client; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + + if ((client->impl.phase == ANODE_HTTP_REQUEST_PHASE_CONNECT)&&(!client->impl.freed)) { + if (error_code) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_CONNECT_FAILED; + AnodeHttpClient_close_and_fail(client); + } else { + client->impl.tcp_connection = connection; + AnodeHttpClient_do_initiate_client(client); + } + } else transport->tcp_close(transport,connection); +} + +static void AnodeHttpClient_tcp_connection_terminated_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + int error_code) +{ + struct AnodeHttpClient *client; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) + return; + + client->response.data_length = 0; + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + if ((client->impl.phase != ANODE_HTTP_REQUEST_PHASE_KEEPALIVE)&&(client->impl.phase != ANODE_HTTP_REQUEST_PHASE_CLOSED)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + AnodeHttpClient_close_and_fail(client); + } else client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; +} + +static void AnodeHttpClient_tcp_receive_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + void *data, + unsigned int data_length) +{ + struct AnodeHttpClient *client; + char *p1,*p2; + unsigned int i; + long l; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) { + transport->tcp_close(transport,connection); + return; + } + + if (!client->response.data) + client->response.data = malloc(client->impl.response_data_capacity = ANODE_HTTP_CAPACITY_INCREMENT); + + i = 0; + while (i < data_length) { + switch(client->impl.read_mode) { + case ANODE_HTTP_READ_MODE_WAITING: + for(;iresponse.data)[client->response.data_length] = (char)0; + client->response.data_length = 0; + + p1 = (char *)Anode_strchr((char *)client->response.data,' '); + if (!p1) + p1 = (char *)Anode_strchr((char *)client->response.data,'\t'); + if (p1) { + while ((*p1 == ' ')||(*p1 == '\t')) ++p1; + if (!*p1) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + p2 = p1 + 1; + while (*p2) { + if ((*p2 == ' ')||(*p2 == '\t')||(*p2 == '\r')||(*p2 == '\n')) { + *p2 = (char)0; + break; + } else ++p2; + } + client->response.code = (int)strtol(p1,(char **)0,10); + client->impl.read_mode = ANODE_HTTP_READ_MODE_HEADERS; + ++i; break; /* Exit inner for() */ + } + } else { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + if (client->response.data_length >= client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity += ANODE_HTTP_CAPACITY_INCREMENT); + } + } + break; + case ANODE_HTTP_READ_MODE_HEADERS: + case ANODE_HTTP_READ_MODE_CHUNKED_FOOTER: + for(;iimpl.header_line_buf[client->impl.header_line_buf_ptr] = (char)0; + client->impl.header_line_buf_ptr = 0; + + if ((!client->impl.header_line_buf[0])||((client->impl.header_line_buf[0] == '\r')&&(!client->impl.header_line_buf[1]))) { + /* If the line is empty (or is empty with \r\n as the + * line terminator), we're at the end. */ + if (client->impl.read_mode == ANODE_HTTP_READ_MODE_CHUNKED_FOOTER) { + /* If this is a chunked footer, we finally end the + * chunked response. */ + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + } else { + /* Otherwise, this is a regular header block */ + if (client->response.code == 100) { + /* Ignore 100 Continue messages */ + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + ++i; break; /* Exit inner for() */ + } else if ((client->response.code == 200)&&(client->method != ANODE_HTTP_HEAD)) { + /* Other messages get their headers parsed to determine + * how to read them. */ + p1 = (char *)AnodeDictionary_get(&(client->response.headers),"transfer-encoding"); + if ((p1)&&(Anode_strcaseeq(p1,"chunked"))) { + /* Chunked encoding enters chunked mode */ + client->impl.header_line_buf_ptr = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE; + ++i; break; /* Exit inner for() */ + } else { + /* Else we must have a Content-Length header */ + p1 = (char *)AnodeDictionary_get(&(client->response.headers),"content-length"); + if (!p1) { + /* No chunked or content length is not supported */ + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } else { + /* Enter block read mode with content length */ + l = strtol(p1,(char **)0,10); + if (l <= 0) { + /* Zero length data is all done... */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + + ++i; break; /* Exit inner for() */ + } else { + /* Else start reading... */ + client->impl.expecting_response_length = (unsigned int)l; + client->impl.read_mode = ANODE_HTTP_READ_MODE_BLOCK; + ++i; break; /* Exit inner for() */ + } + } + } + } else { + /* HEAD clients or non-200 codes get headers only */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + + ++i; break; /* Exit inner for() */ + } + } + } else { + /* Otherwise this is another header, add to dictionary */ + AnodeDictionary_read( + &(client->response.headers), + client->impl.header_line_buf, + "\r\n", + ": \t", + "", + (char)0, + 1, + 1 + ); + } + } else { + client->impl.header_line_buf[client->impl.header_line_buf_ptr++] = ((const char *)data)[i]; + if (client->impl.header_line_buf_ptr >= sizeof(client->impl.header_line_buf)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + break; + case ANODE_HTTP_READ_MODE_BLOCK: + if ((client->response.data_length + client->impl.expecting_response_length) > client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity = (client->response.data_length + client->impl.expecting_response_length)); + + for(;((iimpl.expecting_response_length));++i) { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + --client->impl.expecting_response_length; + } + + if (!client->impl.expecting_response_length) { + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + } + break; + case ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE: + for(;iimpl.header_line_buf[client->impl.header_line_buf_ptr] = (char)0; + client->impl.header_line_buf_ptr = 0; + + p1 = client->impl.header_line_buf; + while (*p1) { + if ((*p1 == ';')||(*p1 == ' ')||(*p1 == '\r')||(*p1 == '\n')||(*p1 == '\t')) { + *p1 = (char)0; + break; + } else ++p1; + } + + if (client->impl.header_line_buf[0]) { + l = strtol(client->impl.header_line_buf,(char **)0,16); + if (l <= 0) { + /* Zero length ends chunked and enters footer mode */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_FOOTER; + } else { + /* Otherwise the next chunk is to be read */ + client->impl.expecting_response_length = (unsigned int)l; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_DATA; + } + ++i; break; /* Exit inner for() */ + } + } else { + client->impl.header_line_buf[client->impl.header_line_buf_ptr++] = ((const char *)data)[i]; + if (client->impl.header_line_buf_ptr >= sizeof(client->impl.header_line_buf)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + break; + case ANODE_HTTP_READ_MODE_CHUNKED_DATA: + if ((client->response.data_length + client->impl.expecting_response_length) > client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity = (client->response.data_length + client->impl.expecting_response_length)); + + for(;((iimpl.expecting_response_length));++i) { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + --client->impl.expecting_response_length; + } + + if (!client->impl.expecting_response_length) + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE; + break; + } + } +} + +static void AnodeHttpClient_tcp_available_for_write_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection) +{ + struct AnodeHttpClient *client; + unsigned int i,j; + int n; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) { + transport->tcp_close(transport,connection); + return; + } + + if (client->impl.phase == ANODE_HTTP_REQUEST_PHASE_SEND) { + n = client->impl.transport_engine->tcp_send(client->impl.transport_engine,client->impl.tcp_connection,(const void *)client->impl.outbuf,(int)client->impl.outbuf_len); + if (n < 0) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION; + AnodeHttpClient_close_and_fail(client); + } else if (n > 0) { + for(i=0,j=(client->impl.outbuf_len - (unsigned int)n);iimpl.outbuf[i] = client->impl.outbuf[i + (unsigned int)n]; + client->impl.outbuf_len -= (unsigned int)n; + + if ((client->method == ANODE_HTTP_POST)&&(client->data)&&(client->data_length)) { + i = sizeof(client->impl.outbuf) - client->impl.outbuf_len; + j = client->data_length - client->impl.request_data_ptr; + if (i > j) + i = j; + Anode_memcpy((client->impl.outbuf + client->impl.outbuf_len),client->data,i); + client->impl.request_data_ptr += i; + client->impl.outbuf_len += i; + } + + if (!client->impl.outbuf_len) { + client->impl.transport_engine->tcp_stop_writing(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_RECEIVE; + } + } + } else client->impl.transport_engine->tcp_stop_writing(client->impl.transport_engine,client->impl.tcp_connection); +} + +static void AnodeHttpClient_dns_result_handler( + AnodeTransportEngine *transport, + void *ptr, + int error_code, + const char *name, + const AnodeTransportIpAddress *ip_addresses, + unsigned int ip_address_count, + const AnodeAddress *anode_address) +{ + struct AnodeHttpClient *client; + AnodeTransportIpEndpoint to_endpoint; + + if (!(client = (struct AnodeHttpClient *)ptr)) + return; + if (client->impl.freed) + return; + + if ((error_code)||(!ip_address_count)) { + if (client->impl.phase == ANODE_HTTP_REQUEST_PHASE_RESOLVE) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_DNS_RESOLVE_FAILED; + AnodeHttpClient_close_and_fail(client); + } + } else { + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CONNECT; + Anode_memcpy(&to_endpoint.address,ip_addresses,sizeof(AnodeTransportIpAddress)); + to_endpoint.port = (client->uri.port > 0) ? client->uri.port : 80; + client->impl.transport_engine->tcp_connect( + client->impl.transport_engine, + client, + &AnodeHttpClient_tcp_outgoing_connect_handler, + &AnodeHttpClient_tcp_connection_terminated_handler, + &AnodeHttpClient_tcp_receive_handler, + &AnodeHttpClient_tcp_available_for_write_handler, + &to_endpoint); + } +} + +struct AnodeHttpClient *AnodeHttpClient_new(AnodeTransportEngine *transport_engine) +{ + struct AnodeHttpClient *req = malloc(sizeof(struct AnodeHttpClient)); + Anode_zero(req,sizeof(struct AnodeHttpClient)); + + AnodeDictionary_init(&(req->headers),0); + AnodeDictionary_init(&(req->response.headers),0); + + req->impl.transport_engine = transport_engine; + + return req; +} + +void AnodeHttpClient_send(struct AnodeHttpClient *client) +{ + client->response.code = 0; + client->response.data_length = 0; + AnodeDictionary_clear(&(client->response.headers)); + + client->impl.request_data_ptr = 0; + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + client->impl.outbuf_len = 0; + + if (!client->impl.tcp_connection) { + client->impl.transport_engine->dns_resolve( + client->impl.transport_engine, + &AnodeHttpClient_dns_result_handler, + client, + client->uri.host, + ANODE_TRANSPORT_DNS_QUERY_ALWAYS, + ANODE_TRANSPORT_DNS_QUERY_IF_NO_PREVIOUS, + ANODE_TRANSPORT_DNS_QUERY_NEVER); + } else AnodeHttpClient_do_initiate_client(client); +} + +void AnodeHttpClient_free(struct AnodeHttpClient *client) +{ + AnodeDictionary_destroy(&(client->headers)); + AnodeDictionary_destroy(&(client->response.headers)); + + if (client->impl.tcp_connection) { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + } + + if (client->response.data) + free(client->response.data); + + client->impl.freed = 1; + client->impl.transport_engine->run_later(client->impl.transport_engine,client,&free); +} diff --git a/attic/historic/anode/libanode/impl/http_client.h b/attic/historic/anode/libanode/impl/http_client.h new file mode 100644 index 0000000..f167309 --- /dev/null +++ b/attic/historic/anode/libanode/impl/http_client.h @@ -0,0 +1,200 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_HTTP_CLIENT_H +#define _ANODE_HTTP_CLIENT_H + +#include +#include +#include "dictionary.h" +#include "../anode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HTTP request type + */ +enum AnodeHttpClientRequestMethod +{ + ANODE_HTTP_GET = 0, + ANODE_HTTP_HEAD = 1, + ANODE_HTTP_POST = 2 +}; + +/* + * Special response codes to indicate I/O errors + */ +#define ANODE_HTTP_SPECIAL_RESPONSE_DNS_RESOLVE_FAILED -1 +#define ANODE_HTTP_SPECIAL_RESPONSE_CONNECT_FAILED -2 +#define ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE -3 +#define ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION -4 +#define ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE -5 + +/** + * Simple HTTP client + */ +struct AnodeHttpClient +{ + /** + * Request URI + */ + AnodeURI uri; + + /** + * Request method: GET, PUT, HEAD, or POST + */ + enum AnodeHttpClientRequestMethod method; + + /** + * Data for POST requests + * + * It is your responsibility to manage and/or free this pointer. The HTTP + * client only reads from it. + */ + const void *data; + unsigned int data_length; + + /** + * Content type for data, or null for application/x-www-form-urlencoded + */ + const char *data_content_type; + + /** + * Set to non-zero to use HTTP connection keepalive + * + * If keepalive is enabled, this request can be modified and re-used and + * its associated connection will stay open (being reopened if needed) + * until it is freed. + * + * Note that this client is too dumb to pool connections and pick them on + * the basis of host. Keepalive mode should only be set if the next request + * will be from the same host and port, otherwise you will get a '404'. + */ + int keepalive; + + /** + * Function pointer to be called when request is complete (or fails) + */ + void (*handler)(struct AnodeHttpClient *); + + /** + * Two arbitrary pointers that can be stored here for use by the handler. + * These are not accessed or modified by the client. + */ + void *ptr[2]; + + /** + * Request headers + */ + struct AnodeDictionary headers; + + struct { + /** + * Response code, set on completion or failure before handler is called + * + * Also check for the special response codes defined in http_client.h as + * these negative codes indicate network or other errors. + */ + int code; + + /** + * Response data, for GET and POST requests + */ + void *data; + + /** + * Length of response data + */ + unsigned int data_length; + + /** + * Response headers + */ + struct AnodeDictionary headers; + } response; + + /** + * Internal fields used by implementation + */ + struct { + /* Transport engine being used by request */ + AnodeTransportEngine *transport_engine; + + /* Connection to which request has been sent, or null if none */ + struct AnodeHttpConnection *connection; + + /* Buffer for reading chunked mode chunk lines (can't use data buf) */ + char header_line_buf[256]; + unsigned int header_line_buf_ptr; + + /* Where are we in sending request data? */ + unsigned int request_data_ptr; + + /* Capacity of response_data buffer */ + unsigned int response_data_capacity; + + /* How much response data are we currently expecting? */ + /* This is content-length in block mode or chunk length in chunked mode */ + unsigned int expecting_response_length; + + /* Read mode */ + enum { + ANODE_HTTP_READ_MODE_WAITING = 0, + ANODE_HTTP_READ_MODE_HEADERS = 1, + ANODE_HTTP_READ_MODE_BLOCK = 2, + ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE = 3, + ANODE_HTTP_READ_MODE_CHUNKED_DATA = 4, + ANODE_HTTP_READ_MODE_CHUNKED_FOOTER = 5 + } read_mode; + + /* Connection from transport engine */ + AnodeTransportTcpConnection *tcp_connection; + + /* Write buffer */ + unsigned char outbuf[16384]; + unsigned int outbuf_len; + + /* Phase of request state machine */ + enum { + ANODE_HTTP_REQUEST_PHASE_RESOLVE = 0, + ANODE_HTTP_REQUEST_PHASE_CONNECT = 1, + ANODE_HTTP_REQUEST_PHASE_SEND = 2, + ANODE_HTTP_REQUEST_PHASE_RECEIVE = 3, + ANODE_HTTP_REQUEST_PHASE_KEEPALIVE = 4, + ANODE_HTTP_REQUEST_PHASE_CLOSED = 5 + } phase; + + /* Has request object been freed? */ + int freed; + + /** + * Pointer used internally for putting requests into linked lists + */ + struct AnodeHttpClient *next; + } impl; +}; + +struct AnodeHttpClient *AnodeHttpClient_new(AnodeTransportEngine *transport_engine); +void AnodeHttpClient_send(struct AnodeHttpClient *client); +void AnodeHttpClient_free(struct AnodeHttpClient *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/attic/historic/anode/libanode/impl/misc.c b/attic/historic/anode/libanode/impl/misc.c new file mode 100644 index 0000000..edc7397 --- /dev/null +++ b/attic/historic/anode/libanode/impl/misc.c @@ -0,0 +1,190 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include "misc.h" +#include "types.h" + +static const char Anode_hex_chars[16] = { + '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' +}; + +static const char Anode_base32_chars[32] = { + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q', + 'r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' +}; +static const unsigned char Anode_base32_bits[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5, + 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,0,1,2, + 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +/* Table for converting ASCII chars to lower case */ +const unsigned char Anode_ascii_tolower_table[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +void Anode_trim(char *s) +{ + char *dest = s; + char *last; + while ((*s)&&((*s == ' ')||(*s == '\t')||(*s == '\r')||(*s == '\n'))) + ++s; + last = s; + while ((*dest = *s)) { + if ((*dest != ' ')&&(*dest != '\t')&&(*dest != '\r')&&(*dest != '\n')) + last = dest; + ++dest; + ++s; + } + if (*last) + *(++last) = (char)0; +} + +unsigned int Anode_rand() +{ + static volatile int need_seed = 1; + + if (need_seed) { + need_seed = 0; + srandom((unsigned long)Anode_time64()); + } + + return (unsigned int)random(); +} + +void Anode_to_hex(const unsigned char *b,unsigned int len,char *h,unsigned int hlen) +{ + unsigned int i; + + if ((len * 2) >= hlen) + len = (hlen - 1) / 2; + + for(i=0;i> 4]; + *(h++) = Anode_hex_chars[b[i] & 0xf]; + } + *h = (char)0; +} + +void Anode_from_hex(const char *h,unsigned char *b,unsigned int blen) +{ + unsigned char *end = b + blen; + unsigned char v = (unsigned char)0; + + while (b != end) { + switch(*(h++)) { + case '0': v = 0x00; break; + case '1': v = 0x10; break; + case '2': v = 0x20; break; + case '3': v = 0x30; break; + case '4': v = 0x40; break; + case '5': v = 0x50; break; + case '6': v = 0x60; break; + case '7': v = 0x70; break; + case '8': v = 0x80; break; + case '9': v = 0x90; break; + case 'a': v = 0xa0; break; + case 'b': v = 0xb0; break; + case 'c': v = 0xc0; break; + case 'd': v = 0xd0; break; + case 'e': v = 0xe0; break; + case 'f': v = 0xf0; break; + default: return; + } + + switch(*(h++)) { + case '0': v |= 0x00; break; + case '1': v |= 0x01; break; + case '2': v |= 0x02; break; + case '3': v |= 0x03; break; + case '4': v |= 0x04; break; + case '5': v |= 0x05; break; + case '6': v |= 0x06; break; + case '7': v |= 0x07; break; + case '8': v |= 0x08; break; + case '9': v |= 0x09; break; + case 'a': v |= 0x0a; break; + case 'b': v |= 0x0b; break; + case 'c': v |= 0x0c; break; + case 'd': v |= 0x0d; break; + case 'e': v |= 0x0e; break; + case 'f': v |= 0x0f; break; + default: return; + } + + *(b++) = v; + } +} + +void Anode_base32_5_to_8(const unsigned char *in,char *out) +{ + out[0] = Anode_base32_chars[(in[0]) >> 3]; + out[1] = Anode_base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; + out[2] = Anode_base32_chars[(in[1] & 0x3e) >> 1]; + out[3] = Anode_base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4]; + out[4] = Anode_base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7]; + out[5] = Anode_base32_chars[(in[3] & 0x7c) >> 2]; + out[6] = Anode_base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; + out[7] = Anode_base32_chars[(in[4] & 0x1f)]; +} + +void Anode_base32_8_to_5(const char *in,unsigned char *out) +{ + out[0] = ((Anode_base32_bits[(unsigned int)in[0]]) << 3) | (Anode_base32_bits[(unsigned int)in[1]] & 0x1C) >> 2; + out[1] = ((Anode_base32_bits[(unsigned int)in[1]] & 0x03) << 6) | (Anode_base32_bits[(unsigned int)in[2]]) << 1 | (Anode_base32_bits[(unsigned int)in[3]] & 0x10) >> 4; + out[2] = ((Anode_base32_bits[(unsigned int)in[3]] & 0x0F) << 4) | (Anode_base32_bits[(unsigned int)in[4]] & 0x1E) >> 1; + out[3] = ((Anode_base32_bits[(unsigned int)in[4]] & 0x01) << 7) | (Anode_base32_bits[(unsigned int)in[5]]) << 2 | (Anode_base32_bits[(unsigned int)in[6]] & 0x18) >> 3; + out[4] = ((Anode_base32_bits[(unsigned int)in[6]] & 0x07) << 5) | (Anode_base32_bits[(unsigned int)in[7]]); +} diff --git a/attic/historic/anode/libanode/impl/misc.h b/attic/historic/anode/libanode/impl/misc.h new file mode 100644 index 0000000..38ddea7 --- /dev/null +++ b/attic/historic/anode/libanode/impl/misc.h @@ -0,0 +1,193 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/* This contains miscellaneous functions, including some re-implementations + * of some functions from string.h. This is to help us port to some platforms + * (cough Windows Mobile cough) that lack a lot of the basic C library. */ + +#ifndef _ANODE_MISC_H +#define _ANODE_MISC_H + +#include +#include +#include "types.h" + +#ifndef ANODE_NO_STRING_H +#include +#include +#endif + +/* Table mapping ASCII characters to themselves or their lower case */ +extern const unsigned char Anode_ascii_tolower_table[256]; + +/* Get the lower case version of an ASCII char */ +#define Anode_tolower(c) ((char)Anode_ascii_tolower_table[((unsigned long)((unsigned char)(c)))]) + +/* Test strings for equality, return nonzero if equal */ +static inline unsigned int Anode_streq(const char *restrict a,const char *restrict b) +{ + if ((!a)||(!b)) + return 0; + while (*a == *(b++)) { + if (!*(a++)) + return 1; + } + return 0; +} + +/* Equality test ignoring (ASCII) case */ +static inline unsigned int Anode_strcaseeq(const char *restrict a,const char *restrict b) +{ + if ((!a)||(!b)) + return 0; + while (Anode_tolower(*a) == Anode_tolower(*(b++))) { + if (!*(a++)) + return 1; + } + return 0; +} + +/* Safe c-string copy, ensuring that dest[] always ends with zero */ +static inline void Anode_str_copy(char *restrict dest,const char *restrict src,unsigned int dest_size) +{ + char *restrict dest_end = dest + (dest_size - 1); + while ((*src)&&(dest != dest_end)) + *(dest++) = *(src++); + *dest = (char)0; +} + +/* Simple memcpy() */ +#ifdef ANODE_NO_STRING_H +static inline void Anode_memcpy(void *restrict dest,const void *restrict src,unsigned int len) +{ + unsigned int i; + for(i=0;i 8 base32 characters and vice versa */ +void Anode_base32_5_to_8(const unsigned char *in,char *out); +void Anode_base32_8_to_5(const char *in,unsigned char *out); + +#endif diff --git a/attic/historic/anode/libanode/impl/mutex.h b/attic/historic/anode/libanode/impl/mutex.h new file mode 100644 index 0000000..b20eb82 --- /dev/null +++ b/attic/historic/anode/libanode/impl/mutex.h @@ -0,0 +1,34 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_MUTEX_H +#define _ANODE_MUTEX_H + +#ifdef WINDOWS + +#else /* WINDOWS */ + +#include + +#define AnodeMutex pthread_mutex_t +#define AnodeMutex_init(m) pthread_mutex_init((m),(const pthread_mutexattr_t *)0) +#define AnodeMutex_destroy(m) pthread_mutex_destroy((m)) +#define AnodeMutex_lock(m) pthread_mutex_lock((m)) +#define AnodeMutex_unlock(m) pthread_mutex_unlock((m)) + +#endif /* WINDOWS */ + +#endif diff --git a/attic/historic/anode/libanode/impl/thread.c b/attic/historic/anode/libanode/impl/thread.c new file mode 100644 index 0000000..c207046 --- /dev/null +++ b/attic/historic/anode/libanode/impl/thread.c @@ -0,0 +1,58 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include "thread.h" +#include + +#ifdef WINDOWS + +#else /* not WINDOWS */ + +struct _AnodeThread +{ + void (*func)(void *); + void *arg; + int wait_for_join; + pthread_t thread; +}; + +static void *_AnodeThread_main(void *arg) +{ + ((struct _AnodeThread *)arg)->func(((struct _AnodeThread *)arg)->arg); + if (!((struct _AnodeThread *)arg)->wait_for_join) + free(arg); + return (void *)0; +} + +AnodeThread *AnodeThread_create(void (*func)(void *),void *arg,int wait_for_join) +{ + struct _AnodeThread *t = malloc(sizeof(struct _AnodeThread)); + t->func = func; + t->arg = arg; + t->wait_for_join = wait_for_join; + pthread_create(&t->thread,(const pthread_attr_t *)0,&_AnodeThread_main,(void *)t); + if (!wait_for_join) + pthread_detach(t->thread); + return (AnodeThread *)t; +} + +void AnodeThread_join(AnodeThread *thread) +{ + pthread_join(((struct _AnodeThread *)thread)->thread,(void **)0); + free((void *)thread); +} + +#endif /* WINDOWS / not WINDOWS */ diff --git a/attic/historic/anode/libanode/impl/thread.h b/attic/historic/anode/libanode/impl/thread.h new file mode 100644 index 0000000..accf173 --- /dev/null +++ b/attic/historic/anode/libanode/impl/thread.h @@ -0,0 +1,65 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_THREAD_H +#define _ANODE_THREAD_H + +#ifdef WINDOWS + +#include +#include +typedef DWORD AnodeThreadId; + +#else /* not WINDOWS */ + +#include +typedef pthread_t AnodeThreadId; + +#define AnodeThread_self() pthread_self() +#define AnodeThreadId_equal(a,b) pthread_equal((pthread_t)(a),(pthread_t)(b)) + +#endif + +typedef void AnodeThread; + +/** + * Create and launch a new thread + * + * If wait_for_join is true (nonzero), the thread can and must be joined. The + * thread object won't be freed until join is called and returns. If + * wait_for_join is false, the thread object frees itself automatically on + * termination. + * + * If wait_for_join is false (zero), there is really no need to keep track of + * the thread object. + * + * @param func Function to call as thread main + * @param arg Argument to pass to function + * @param wait_for_join If false, thread deletes itself when it terminates + */ +AnodeThread *AnodeThread_create(void (*func)(void *),void *arg,int wait_for_join); + +/** + * Wait for a thread to terminate and delete thread object + * + * This can only be used for threads created with wait_for_join set to true. + * The thread object is no longer valid after this call. + * + * @param thread Thread to wait for termination and delete + */ +void AnodeThread_join(AnodeThread *thread); + +#endif diff --git a/attic/historic/anode/libanode/impl/types.h b/attic/historic/anode/libanode/impl/types.h new file mode 100644 index 0000000..5f070e5 --- /dev/null +++ b/attic/historic/anode/libanode/impl/types.h @@ -0,0 +1,25 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _ANODE_TYPES_H +#define _ANODE_TYPES_H + +#ifdef WINDOWS +#else +#include +#endif + +#endif diff --git a/attic/historic/anode/libanode/network_address.c b/attic/historic/anode/libanode/network_address.c new file mode 100644 index 0000000..86ec054 --- /dev/null +++ b/attic/historic/anode/libanode/network_address.c @@ -0,0 +1,136 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "impl/misc.h" +#include "impl/types.h" +#include "anode.h" + +const AnodeNetworkAddress AnodeNetworkAddress_ANY4 = { + ANODE_NETWORK_ADDRESS_IPV4, + { 0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_ANY6 = { + ANODE_NETWORK_ADDRESS_IPV6, + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_LOCAL4 = { + ANODE_NETWORK_ADDRESS_IPV4, + { 127,0,0,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,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_LOCAL6 = { + ANODE_NETWORK_ADDRESS_IPV6, + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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 } +}; + +int AnodeNetworkAddress_to_string(const AnodeNetworkAddress *address,char *buf,int len) +{ + const char *s; + + switch(address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + s = inet_ntop(AF_INET,(const void *)address->bits,buf,len); + if (s) + return Anode_strlen(s); + else return ANODE_ERR_INVALID_ARGUMENT; + break; + case ANODE_NETWORK_ADDRESS_IPV6: + s = inet_ntop(AF_INET6,address->bits,buf,len); + if (s) + return Anode_strlen(s); + else return ANODE_ERR_INVALID_ARGUMENT; + /* + case ANODE_NETWORK_ADDRESS_ETHERNET: + break; + case ANODE_NETWORK_ADDRESS_USB: + break; + case ANODE_NETWORK_ADDRESS_BLUETOOTH: + break; + case ANODE_NETWORK_ADDRESS_IPC: + break; + case ANODE_NETWORK_ADDRESS_80211S: + break; + case ANODE_NETWORK_ADDRESS_SERIAL: + break; + */ + case ANODE_NETWORK_ADDRESS_ANODE_256_40: + return AnodeAddress_to_string((const AnodeAddress *)address->bits,buf,len); + default: + return ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + } +} + +int AnodeNetworkAddress_from_string(const char *str,AnodeNetworkAddress *address) +{ + unsigned int dots = Anode_count_char(str,'.'); + unsigned int colons = Anode_count_char(str,':'); + + if ((dots == 3)&&(!colons)) { + address->type = ANODE_NETWORK_ADDRESS_IPV4; + if (inet_pton(AF_INET,str,address->bits) > 0) + return 0; + else return ANODE_ERR_INVALID_ARGUMENT; + } else if ((colons)&&(!dots)) { + address->type = ANODE_NETWORK_ADDRESS_IPV6; + if (inet_pton(AF_INET6,str,address->bits) > 0) + return 0; + else return ANODE_ERR_INVALID_ARGUMENT; + } else { + address->type = ANODE_NETWORK_ADDRESS_ANODE_256_40; + return AnodeAddress_from_string(str,(AnodeAddress *)address->bits); + } +} + +int AnodeNetworkEndpoint_from_sockaddr(const void *sockaddr,AnodeNetworkEndpoint *endpoint) +{ + switch(((struct sockaddr_storage *)sockaddr)->ss_family) { + case AF_INET: + *((uint32_t *)endpoint->address.bits) = (uint32_t)(((struct sockaddr_in *)sockaddr)->sin_addr.s_addr); + endpoint->port = (int)ntohs(((struct sockaddr_in *)sockaddr)->sin_port); + return 0; + case AF_INET6: + Anode_memcpy(endpoint->address.bits,((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr,16); + endpoint->port = (int)ntohs(((struct sockaddr_in6 *)sockaddr)->sin6_port); + return 0; + default: + return ANODE_ERR_INVALID_ARGUMENT; + } +} + +int AnodeNetworkEndpoint_to_sockaddr(const AnodeNetworkEndpoint *endpoint,void *sockaddr,int sockaddr_len) +{ + switch(endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + if (sockaddr_len < (int)sizeof(struct sockaddr_in)) + return ANODE_ERR_BUFFER_TOO_SMALL; + Anode_zero(sockaddr,sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)sockaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)sockaddr)->sin_port = htons((uint16_t)endpoint->port); + ((struct sockaddr_in *)sockaddr)->sin_addr.s_addr = *((uint32_t *)endpoint->address.bits); + return 0; + case ANODE_NETWORK_ADDRESS_IPV6: + if (sockaddr_len < (int)sizeof(struct sockaddr_in6)) + return ANODE_ERR_BUFFER_TOO_SMALL; + Anode_zero(sockaddr,sizeof(struct sockaddr_in6)); + ((struct sockaddr_in6 *)sockaddr)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons((uint16_t)endpoint->port); + Anode_memcpy(((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr,endpoint->address.bits,16); + return 0; + default: + return ANODE_ERR_INVALID_ARGUMENT; + } +} diff --git a/attic/historic/anode/libanode/secure_random.c b/attic/historic/anode/libanode/secure_random.c new file mode 100644 index 0000000..4322d7d --- /dev/null +++ b/attic/historic/anode/libanode/secure_random.c @@ -0,0 +1,88 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "impl/aes.h" +#include "impl/misc.h" +#include "anode.h" + +#ifdef WINDOWS +#include +#include +#endif + +struct AnodeSecureRandomImpl +{ + AnodeAesExpandedKey key; + unsigned char state[ANODE_AES_BLOCK_SIZE]; + unsigned char block[ANODE_AES_BLOCK_SIZE]; + unsigned int ptr; +}; + +AnodeSecureRandom *AnodeSecureRandom_new() +{ + unsigned char keybuf[ANODE_AES_KEY_SIZE + ANODE_AES_BLOCK_SIZE + ANODE_AES_BLOCK_SIZE]; + unsigned int i; + struct AnodeSecureRandomImpl *srng; + +#ifdef WINDOWS + HCRYPTPROV hProv; + if (CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { + CryptGenRandom(hProv,sizeof(keybuf),keybuf); + CryptReleaseContext(hProv,0); + } +#else + FILE *urandf = fopen("/dev/urandom","rb"); + if (urandf) { + fread((void *)keybuf,sizeof(keybuf),1,urandf); + fclose(urandf); + } +#endif + + for(i=0;i> 5); + + srng = malloc(sizeof(struct AnodeSecureRandomImpl)); + Anode_aes256_expand_key(keybuf,&srng->key); + for(i=0;istate[i] = keybuf[ANODE_AES_KEY_SIZE + i]; + for(i=0;iblock[i] = keybuf[ANODE_AES_KEY_SIZE + ANODE_AES_KEY_SIZE + i]; + srng->ptr = ANODE_AES_BLOCK_SIZE; + + return (AnodeSecureRandom *)srng; +} + +void AnodeSecureRandom_gen_bytes(AnodeSecureRandom *srng,void *buf,long count) +{ + long i,j; + + for(i=0;iptr == ANODE_AES_BLOCK_SIZE) { + Anode_aes256_encrypt(&((struct AnodeSecureRandomImpl *)srng)->key,((struct AnodeSecureRandomImpl *)srng)->state,((struct AnodeSecureRandomImpl *)srng)->state); + for(j=0;jblock[j] ^= ((struct AnodeSecureRandomImpl *)srng)->state[j]; + ((struct AnodeSecureRandomImpl *)srng)->ptr = 0; + } + ((unsigned char *)buf)[i] = ((struct AnodeSecureRandomImpl *)srng)->block[((struct AnodeSecureRandomImpl *)srng)->ptr++]; + } +} + +void AnodeSecureRandom_delete(AnodeSecureRandom *srng) +{ + free(srng); +} diff --git a/attic/historic/anode/libanode/system_transport.c b/attic/historic/anode/libanode/system_transport.c new file mode 100644 index 0000000..4bfb143 --- /dev/null +++ b/attic/historic/anode/libanode/system_transport.c @@ -0,0 +1,948 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include "anode.h" +#include "impl/mutex.h" +#include "impl/thread.h" +#include "impl/misc.h" +#include "impl/dns_txt.h" + +#ifdef WINDOWS +#include +#include +#define AnodeSystemTransport__close_socket(s) closesocket((s)) +#define ANODE_USE_SELECT 1 +#else +#include +#include +#define AnodeSystemTransport__close_socket(s) close((s)) +#endif + +static const char *AnodeSystemTransport_CLASS = "SystemTransport"; + +/* ======================================================================== */ + +struct AnodeSystemTransport; + +struct AnodeSystemTransport_AnodeSocket +{ + AnodeSocket base; /* must be first */ + unsigned int entry_idx; +}; + +#define ANODE_SYSTEM_TRANSPORT_DNS_MAX_RESULTS 16 +struct AnodeSystemTransport__dns_request +{ + struct AnodeSystemTransport__dns_request *next; + + AnodeThread *thread; + struct AnodeSystemTransport *owner; + + void (*event_handler)(const AnodeEvent *event); + + char name[256]; + enum AnodeTransportDnsIncludeMode ipv4_include_mode; + enum AnodeTransportDnsIncludeMode ipv6_include_mode; + enum AnodeTransportDnsIncludeMode anode_include_mode; + + AnodeNetworkAddress addresses[ANODE_SYSTEM_TRANSPORT_DNS_MAX_RESULTS]; + unsigned int address_count; + + int error_code; +}; + +#ifdef ANODE_USE_SELECT +typedef int AnodeSystemTransport__poll_fd; /* for select() */ +#else +typedef struct pollfd AnodeSystemTransport__poll_fd; /* for poll() */ +#endif + +struct AnodeSystemTransport +{ + AnodeTransport interface; /* must be first */ + + AnodeTransport *base; + +#ifdef ANODE_USE_SELECT + FD_SET readfds; + FD_SET writefds; +#endif + + void (*default_event_handler)(const AnodeEvent *event); + + AnodeSystemTransport__poll_fd *fds; + struct AnodeSystemTransport_AnodeSocket *sockets; + unsigned int fd_count; + unsigned int fd_capacity; + + struct AnodeSystemTransport__dns_request *pending_dns_requests; + + int invoke_pipe[2]; + AnodeMutex invoke_pipe_m; + void *invoke_pipe_buf[2]; + unsigned int invoke_pipe_buf_ptr; +}; + +/* ======================================================================== */ +/* Internal helper methods */ + +static unsigned int AnodeSystemTransport__add_entry(struct AnodeSystemTransport *transport) +{ + if ((transport->fd_count + 1) > transport->fd_capacity) { + transport->fd_capacity += 8; + transport->fds = realloc(transport->fds,sizeof(AnodeSystemTransport__poll_fd) * transport->fd_capacity); + transport->sockets = realloc(transport->sockets,sizeof(struct AnodeSystemTransport_AnodeSocket) * transport->fd_capacity); + } + return transport->fd_count++; +} + +static void AnodeSystemTransport__remove_entry(struct AnodeSystemTransport *transport,const unsigned int idx) +{ + unsigned int i; + + --transport->fd_count; + for(i=idx;ifd_count;++i) { + Anode_memcpy(&transport->fds[i],&transport->fds[i+1],sizeof(AnodeSystemTransport__poll_fd)); + Anode_memcpy(&transport->sockets[i],&transport->sockets[i+1],sizeof(struct AnodeSystemTransport_AnodeSocket)); + } + + if ((transport->fd_capacity - transport->fd_count) > 16) { + transport->fd_capacity -= 16; + transport->fds = realloc(transport->fds,sizeof(AnodeSystemTransport__poll_fd) * transport->fd_capacity); + transport->sockets = realloc(transport->sockets,sizeof(struct AnodeSystemTransport_AnodeSocket) * transport->fd_capacity); + } +} + +static void AnodeSystemTransport__dns_invoke_on_completion(void *_dreq) +{ + struct AnodeSystemTransport__dns_request *dreq = (struct AnodeSystemTransport__dns_request *)_dreq; + struct AnodeSystemTransport__dns_request *ptr,**lastnext; + + AnodeThread_join(dreq->thread); + + ptr = dreq->owner->pending_dns_requests; + lastnext = &dreq->owner->pending_dns_requests; + while (ptr) { + if (ptr == dreq) { + *lastnext = ptr->next; + break; + } else { + lastnext = &ptr->next; + ptr = ptr->next; + } + } + + free(dreq); +} + +static void AnodeSystemTransport__dns_thread_main(void *_dreq) +{ + struct AnodeSystemTransport__dns_request *dreq = (struct AnodeSystemTransport__dns_request *)_dreq; + + dreq->owner->interface.invoke((AnodeTransport *)dreq->owner,dreq,&AnodeSystemTransport__dns_invoke_on_completion); +} + +static void AnodeSystemTransport__do_close(struct AnodeSystemTransport *transport,struct AnodeSystemTransport_AnodeSocket *sock,const int error_code,const int generate_event) +{ + AnodeEvent evbuf; + int fd; + + if (sock->base.class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + fd = (int)(transport->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]); +#else + fd = transport->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd; +#endif + + if ((sock->base.type == ANODE_SOCKET_STREAM_CONNECTION)&&(sock->base.state != ANODE_SOCKET_CLOSED)) { + sock->base.state = ANODE_SOCKET_CLOSED; + + if (generate_event) { + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_CLOSED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = error_code; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } + } + + AnodeSystemTransport__close_socket(fd); + AnodeSystemTransport__remove_entry(transport,((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx); + +#ifdef ANODE_USE_SELECT + FD_CLR(sock,&THIS->readfds); + FD_CLR(sock,&THIS->writefds); +#endif + } else transport->base->close(transport->base,(AnodeSocket *)sock); +} + +static int AnodeSystemTransport__populate_network_endpoint(const struct sockaddr_storage *saddr,AnodeNetworkEndpoint *ep) +{ + switch(saddr->ss_family) { + case AF_INET: + ep->address.type = ANODE_NETWORK_ADDRESS_IPV4; + *((uint32_t *)ep->address.bits) = ((struct sockaddr_in *)saddr)->sin_addr.s_addr; + ep->port = ntohs(((struct sockaddr_in *)saddr)->sin_port); + return 1; + case AF_INET6: + ep->address.type = ANODE_NETWORK_ADDRESS_IPV6; + Anode_memcpy(ep->address.bits,((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr,16); + ep->port = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); + return 1; + } + return 0; +} + +/* ======================================================================== */ + +#ifdef THIS +#undef THIS +#endif +#define THIS ((struct AnodeSystemTransport *)transport) + +static void AnodeSystemTransport_invoke(AnodeTransport *transport, + void *ptr, + void (*func)(void *)) +{ + void *invoke_msg[2]; + + invoke_msg[0] = ptr; + invoke_msg[1] = (void *)func; + + AnodeMutex_lock(&THIS->invoke_pipe_m); + write(THIS->invoke_pipe[1],(void *)(&invoke_msg),sizeof(invoke_msg)); + AnodeMutex_unlock(&THIS->invoke_pipe_m); +} + +static void AnodeSystemTransport_dns_resolve(AnodeTransport *transport, + const char *name, + void (*event_handler)(const AnodeEvent *), + enum AnodeTransportDnsIncludeMode ipv4_include_mode, + enum AnodeTransportDnsIncludeMode ipv6_include_mode, + enum AnodeTransportDnsIncludeMode anode_include_mode) +{ + struct AnodeSystemTransport__dns_request *dreq = malloc(sizeof(struct AnodeSystemTransport__dns_request)); + + dreq->owner = THIS; + dreq->event_handler = event_handler; + Anode_str_copy(dreq->name,name,sizeof(dreq->name)); + dreq->ipv4_include_mode = ipv4_include_mode; + dreq->ipv6_include_mode = ipv6_include_mode; + dreq->anode_include_mode = anode_include_mode; + + dreq->address_count = 0; + dreq->error_code = 0; + + dreq->next = THIS->pending_dns_requests; + THIS->pending_dns_requests = dreq; + + dreq->thread = AnodeThread_create(&AnodeSystemTransport__dns_thread_main,dreq,0); +} + +static AnodeSocket *AnodeSystemTransport_datagram_listen(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + int tmp; + + switch(local_address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + fd = socket(AF_INET,SOCK_DGRAM,0); + if (fd <= 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + tmp = 1; + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&tmp,sizeof(tmp)); + fcntl(fd,F_SETFL,O_NONBLOCK); + + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(local_port); + sin4.sin_addr.s_addr = *((uint32_t *)local_address->bits); + + if (bind(fd,(const struct sockaddr *)&sin4,sizeof(sin4))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + fd = socket(AF_INET6,SOCK_DGRAM,0); + if (fd <= 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + tmp = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&tmp,sizeof(tmp)); + fcntl(fd,F_SETFL,O_NONBLOCK); +#ifdef IPV6_V6ONLY + tmp = 1; setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&tmp,sizeof(tmp)); +#endif + + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(local_port); + Anode_memcpy(sin6.sin6_addr.s6_addr,local_address->bits,16); + + if (bind(fd,(const struct sockaddr *)&sin6,sizeof(sin6))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + default: + if (THIS->base) + return THIS->base->datagram_listen(THIS->base,local_address,local_port,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_DATAGRAM; + sock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&sock->base.endpoint.address,local_address,sizeof(AnodeNetworkAddress)); + sock->base.endpoint.port = local_port; + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + *error_code = 0; + return (AnodeSocket *)sock; +} + +static AnodeSocket *AnodeSystemTransport_stream_listen(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + int tmp; + + switch(local_address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + fd = socket(AF_INET,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(local_port); + sin4.sin_addr.s_addr = *((uint32_t *)local_address->bits); + + if (bind(fd,(const struct sockaddr *)&sin4,sizeof(sin4))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + if (listen(fd,8)) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + fd = socket(AF_INET6,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); +#ifdef IPV6_V6ONLY + tmp = 1; setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&tmp,sizeof(tmp)); +#endif + + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(local_port); + Anode_memcpy(sin6.sin6_addr.s6_addr,local_address->bits,16); + + if (bind(fd,(const struct sockaddr *)&sin6,sizeof(sin6))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + if (listen(fd,8)) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + default: + if (THIS->base) + return THIS->base->stream_listen(THIS->base,local_address,local_port,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_STREAM_LISTEN; + sock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&sock->base.endpoint.address,local_address,sizeof(AnodeNetworkAddress)); + sock->base.endpoint.port = local_port; + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + *error_code = 0; + return (AnodeSocket *)sock; +} + +static int AnodeSystemTransport_datagram_send(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len, + const AnodeNetworkEndpoint *to_endpoint) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + +#ifdef ANODE_USE_SELECT + const int fd = (int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]); +#else + const int fd = THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd; +#endif + + switch(to_endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons((uint16_t)to_endpoint->port); + sin4.sin_addr.s_addr = *((uint32_t *)to_endpoint->address.bits); + sendto(fd,data,data_len,0,(struct sockaddr *)&sin4,sizeof(sin4)); + return 0; + case ANODE_NETWORK_ADDRESS_IPV6: + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons((uint16_t)to_endpoint->port); + Anode_memcpy(sin6.sin6_addr.s6_addr,to_endpoint->address.bits,16); + sendto(fd,data,data_len,0,(struct sockaddr *)&sin6,sizeof(sin6)); + return 0; + default: + if (THIS->base) + return THIS->base->datagram_send(THIS->base,sock,data,data_len,to_endpoint); + else return ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + } +} + +static AnodeSocket *AnodeSystemTransport_stream_connect(AnodeTransport *transport, + const AnodeNetworkEndpoint *to_endpoint, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + + switch(to_endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(to_endpoint->port); + sin4.sin_addr.s_addr = *((uint32_t *)to_endpoint->address.bits); + + fd = socket(AF_INET,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + if (connect(fd,(struct sockaddr *)&sin4,sizeof(sin4))) { + if (errno != EINPROGRESS) { + *error_code = ANODE_ERR_CONNECT_FAILED; + AnodeSystemTransport__close_socket(fd); + return (AnodeSocket *)0; + } + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(to_endpoint->port); + Anode_memcpy(sin6.sin6_addr.s6_addr,to_endpoint->address.bits,16); + + fd = socket(AF_INET6,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + if (connect(fd,(struct sockaddr *)&sin6,sizeof(sin6))) { + if (errno == EINPROGRESS) { + *error_code = ANODE_ERR_CONNECT_FAILED; + AnodeSystemTransport__close_socket(fd); + return (AnodeSocket *)0; + } + } + break; + default: + if (THIS->base) + return THIS->base->stream_connect(THIS->base,to_endpoint,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_STREAM_CONNECTION; + sock->base.state = ANODE_SOCKET_CONNECTING; + Anode_memcpy(&sock->base.endpoint,to_endpoint,sizeof(AnodeNetworkEndpoint)); + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN|POLLOUT; + THIS->fds[entry_idx].revents = 0; + + return (AnodeSocket *)sock; +} + +static void AnodeSystemTransport_stream_start_writing(AnodeTransport *transport, + AnodeSocket *sock) +{ + if ((sock->type == ANODE_SOCKET_STREAM_CONNECTION)&&(((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state == ANODE_SOCKET_OPEN)) { + if (sock->class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + FD_SET((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),&THIS->writefds); +#else + THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].events = (POLLIN|POLLOUT); +#endif + } else THIS->base->stream_start_writing(THIS->base,sock); + } +} + +static void AnodeSystemTransport_stream_stop_writing(AnodeTransport *transport, + AnodeSocket *sock) +{ + if ((sock->type == ANODE_SOCKET_STREAM_CONNECTION)&&(((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state == ANODE_SOCKET_OPEN)) { + if (sock->class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + FD_CLR((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),&THIS->writefds); +#else + THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].events = POLLIN; +#endif + } else THIS->base->stream_stop_writing(THIS->base,sock); + } +} + +static int AnodeSystemTransport_stream_send(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len) +{ + int result; + + if (sock->type == ANODE_SOCKET_STREAM_CONNECTION) { + if (sock->class_name == AnodeSystemTransport_CLASS) { + if (((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state != ANODE_SOCKET_OPEN) + return ANODE_ERR_CONNECTION_CLOSED; + +#ifdef ANODE_USE_SELECT + result = send((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),data,data_len,0); +#else + result = send(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd,data,data_len,0); +#endif + + if (result >= 0) + return result; + else { + AnodeSystemTransport__do_close(THIS,(struct AnodeSystemTransport_AnodeSocket *)sock,ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); + return ANODE_ERR_CONNECTION_CLOSED; + } + } else return THIS->base->stream_send(THIS->base,sock,data,data_len); + } else return ANODE_ERR_INVALID_ARGUMENT; +} + +static void AnodeSystemTransport_close(AnodeTransport *transport, + AnodeSocket *sock) +{ + AnodeSystemTransport__do_close(THIS,(struct AnodeSystemTransport_AnodeSocket *)sock,0,1); +} + +static void AnodeSystemTransport__poll_do_read_datagram(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + char buf[16384]; + struct sockaddr_storage fromaddr; + AnodeNetworkEndpoint tmp_ep; + AnodeEvent evbuf; + socklen_t addrlen; + int n; + + addrlen = sizeof(struct sockaddr_storage); + n = recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&fromaddr,&addrlen); + if ((n >= 0)&&(AnodeSystemTransport__populate_network_endpoint(&fromaddr,&tmp_ep))) { + evbuf.type = ANODE_TRANSPORT_EVENT_DATAGRAM_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = &tmp_ep; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = n; + evbuf.data = buf; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } +} + +static void AnodeSystemTransport__poll_do_accept_incoming_connection(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + struct sockaddr_storage fromaddr; + AnodeNetworkEndpoint tmp_ep; + AnodeEvent evbuf; + struct AnodeSystemTransport_AnodeSocket *newsock; + socklen_t addrlen; + int n; + unsigned int entry_idx; + + addrlen = sizeof(struct sockaddr_storage); + n = accept(fd,(struct sockaddr *)&fromaddr,&addrlen); + if ((n >= 0)&&(AnodeSystemTransport__populate_network_endpoint(&fromaddr,&tmp_ep))) { + entry_idx = AnodeSystemTransport__add_entry(transport); + newsock = &(transport->sockets[entry_idx]); + + newsock->base.type = ANODE_SOCKET_STREAM_CONNECTION; + newsock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&newsock->base.endpoint,&tmp_ep,sizeof(AnodeNetworkEndpoint)); + newsock->base.class_name = AnodeSystemTransport_CLASS; + newsock->base.user_ptr[0] = NULL; + newsock->base.user_ptr[1] = NULL; + newsock->base.event_handler = NULL; + newsock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = n; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_INCOMING_CONNECT; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)newsock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } +} + +static void AnodeSystemTransport__poll_do_read_stream(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + char buf[65536]; + AnodeEvent evbuf; + int n; + + n = recv(fd,buf,sizeof(buf),0); + if (n > 0) { + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = n; + evbuf.data = buf; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } else AnodeSystemTransport__do_close(transport,sock,ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); +} + +static void AnodeSystemTransport__poll_do_stream_available_for_write(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + AnodeEvent evbuf; + + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); +} + +static void AnodeSystemTransport__poll_do_outgoing_connect(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + AnodeEvent evbuf; + int err_code; + socklen_t optlen; + + optlen = sizeof(err_code); + if (getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err_code,&optlen)) { + /* Error getting result, so we assume a failure */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = ANODE_ERR_CONNECT_FAILED; + evbuf.data_length = 0; + evbuf.data = NULL; + + AnodeSystemTransport__do_close(transport,sock,0,0); + } else if (err_code) { + /* Error code is nonzero, so connect failed */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = ANODE_ERR_CONNECT_FAILED; + evbuf.data_length = 0; + evbuf.data = NULL; + + AnodeSystemTransport__do_close(transport,sock,0,0); + } else { + /* Connect succeeded */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_ESTABLISHED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + } + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); +} + +static int AnodeSystemTransport_poll(AnodeTransport *transport) +{ + int timeout = -1; + unsigned int fd_idx; + int event_count = 0; + int n; + + if (poll((struct pollfd *)THIS->fds,THIS->fd_count,timeout) > 0) { + for(fd_idx=0;fd_idxfd_count;++fd_idx) { + if ((THIS->fds[fd_idx].revents & (POLLERR|POLLHUP|POLLNVAL))) { + if (THIS->sockets[fd_idx].base.type == ANODE_SOCKET_STREAM_CONNECTION) { + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__do_close(THIS,&THIS->sockets[fd_idx],ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); + ++event_count; + } + } else { + if ((THIS->fds[fd_idx].revents & POLLIN)) { + if (THIS->fds[fd_idx].fd == THIS->invoke_pipe[0]) { + n = read(THIS->invoke_pipe[0],&(((unsigned char *)(&(THIS->invoke_pipe_buf)))[THIS->invoke_pipe_buf_ptr]),sizeof(THIS->invoke_pipe_buf) - THIS->invoke_pipe_buf_ptr); + if (n > 0) { + THIS->invoke_pipe_buf_ptr += (unsigned int)n; + if (THIS->invoke_pipe_buf_ptr >= sizeof(THIS->invoke_pipe_buf)) { + THIS->invoke_pipe_buf_ptr -= sizeof(THIS->invoke_pipe_buf); + ((void (*)(void *))(THIS->invoke_pipe_buf[1]))(THIS->invoke_pipe_buf[0]); + } + } + } else { + switch(THIS->sockets[fd_idx].base.type) { + case ANODE_SOCKET_DATAGRAM: + AnodeSystemTransport__poll_do_read_datagram(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + case ANODE_SOCKET_STREAM_LISTEN: + AnodeSystemTransport__poll_do_accept_incoming_connection(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + case ANODE_SOCKET_STREAM_CONNECTION: + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__poll_do_read_stream(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + } + ++event_count; + } + } + + if ((THIS->fds[fd_idx].revents & POLLOUT)) { + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__poll_do_stream_available_for_write(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + ++event_count; + } + } + } + } + + return event_count; +} + +static int AnodeSystemTransport_supports_address_type(const AnodeTransport *transport, + enum AnodeNetworkAddressType at) +{ + switch(at) { + case ANODE_NETWORK_ADDRESS_IPV4: + return 1; + case ANODE_NETWORK_ADDRESS_IPV6: + return 1; + default: + if (THIS->base) + return THIS->base->supports_address_type(THIS->base,at); + return 0; + } +} + +static AnodeTransport *AnodeSystemTransport_base_instance(const AnodeTransport *transport) +{ + return THIS->base; +} + +static const char *AnodeSystemTransport_class_name(AnodeTransport *transport) +{ + return AnodeSystemTransport_CLASS; +} + +static void AnodeSystemTransport_delete(AnodeTransport *transport) +{ + close(THIS->invoke_pipe[0]); + close(THIS->invoke_pipe[1]); + + AnodeMutex_destroy(&THIS->invoke_pipe_m); + + if (THIS->fds) free(THIS->fds); + if (THIS->sockets) free(THIS->sockets); + + if (THIS->base) THIS->base->delete(THIS->base); + + free(transport); +} + +/* ======================================================================== */ + +AnodeTransport *AnodeSystemTransport_new(AnodeTransport *base) +{ + struct AnodeSystemTransport *t; + unsigned int entry_idx; + + t = malloc(sizeof(struct AnodeSystemTransport)); + if (!t) return (AnodeTransport *)0; + Anode_zero(t,sizeof(struct AnodeSystemTransport)); + + t->interface.invoke = &AnodeSystemTransport_invoke; + t->interface.dns_resolve = &AnodeSystemTransport_dns_resolve; + t->interface.datagram_listen = &AnodeSystemTransport_datagram_listen; + t->interface.stream_listen = &AnodeSystemTransport_stream_listen; + t->interface.datagram_send = &AnodeSystemTransport_datagram_send; + t->interface.stream_connect = &AnodeSystemTransport_stream_connect; + t->interface.stream_start_writing = &AnodeSystemTransport_stream_start_writing; + t->interface.stream_stop_writing = &AnodeSystemTransport_stream_stop_writing; + t->interface.stream_send = &AnodeSystemTransport_stream_send; + t->interface.close = &AnodeSystemTransport_close; + t->interface.poll = &AnodeSystemTransport_poll; + t->interface.supports_address_type = &AnodeSystemTransport_supports_address_type; + t->interface.base_instance = &AnodeSystemTransport_base_instance; + t->interface.class_name = &AnodeSystemTransport_class_name; + t->interface.delete = &AnodeSystemTransport_delete; + + t->base = base; + + pipe(t->invoke_pipe); + fcntl(t->invoke_pipe[0],F_SETFL,O_NONBLOCK); + entry_idx = AnodeSystemTransport__add_entry(t); + t->fds[entry_idx].fd = t->invoke_pipe[0]; + t->fds[entry_idx].events = POLLIN; + t->fds[entry_idx].revents = 0; + AnodeMutex_init(&t->invoke_pipe_m); + + return (AnodeTransport *)t; +} diff --git a/attic/historic/anode/libanode/tests/Makefile b/attic/historic/anode/libanode/tests/Makefile new file mode 100644 index 0000000..a479092 --- /dev/null +++ b/attic/historic/anode/libanode/tests/Makefile @@ -0,0 +1,25 @@ +all: force clean anode-utils-test anode-zone-test aes-test ec-test + +aes-test: + gcc -Wall -O6 -ftree-vectorize -std=c99 -o aes-test aes-test.c ../aes_digest.c -lcrypto + +http_client-test: + gcc -O0 -g -std=c99 -o http_client-test http_client-test.c ../anode-utils.c ../misc.c ../http_client.c ../dictionary.c ../iptransport.c ../anode-transport.c -lcrypto + +anode-utils-test: + gcc -O0 -g -std=c99 -o anode-utils-test anode-utils-test.c ../anode-utils.c ../misc.c + +ec-test: + gcc -O0 -g -std=c99 -o ec-test ec-test.c ../impl/ec.c ../impl/misc.c -lcrypto + +anode-zone-test: + gcc -O0 -g -std=c99 -o anode-zone-test anode-zone-test.c ../anode-zone.c ../http_client.c ../dictionary.c ../misc.c ../anode-transport.c ../iptransport.c ../environment.c + +system_transport-test: + gcc -O0 -g -std=c99 -o system_transport-test system_transport-test.c ../system_transport.c ../network_address.c ../address.c ../aes_digest.c ../impl/misc.c ../impl/thread.c ../impl/dns_txt.c ../impl/aes.c -lresolv -lcrypto + +clean: force + rm -rf *.dSYM + rm -f http_client-test anode-utils-test anode-zone-test ec-test aes-test system_transport-test + +force: ; diff --git a/attic/historic/anode/libanode/tests/aes-test.c b/attic/historic/anode/libanode/tests/aes-test.c new file mode 100644 index 0000000..bca63b8 --- /dev/null +++ b/attic/historic/anode/libanode/tests/aes-test.c @@ -0,0 +1,191 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include "../impl/aes.h" +#include "../anode.h" + +static const unsigned char AES_TEST_KEY[32] = { + 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, + 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E +}; +static const unsigned char AES_TEST_IN[16] = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 +}; +static const unsigned char AES_TEST_OUT[16] = { + 0x08,0x0e,0x95,0x17,0xeb,0x16,0x77,0x71,0x9a,0xcf,0x72,0x80,0x86,0x04,0x0a,0xe3 +}; + +static const unsigned char CMAC_TEST_KEY[32] = { + 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81, + 0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4 +}; + +static const unsigned char CMAC_TEST1_OUT[16] = { + 0x02,0x89,0x62,0xf6,0x1b,0x7b,0xf8,0x9e,0xfc,0x6b,0x55,0x1f,0x46,0x67,0xd9,0x83 +}; + +static const unsigned char CMAC_TEST2_IN[16] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a +}; +static const unsigned char CMAC_TEST2_OUT[16] = { + 0x28,0xa7,0x02,0x3f,0x45,0x2e,0x8f,0x82,0xbd,0x4b,0xf2,0x8d,0x8c,0x37,0xc3,0x5c +}; + +static const unsigned char CMAC_TEST3_IN[40] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11 +}; +static const unsigned char CMAC_TEST3_OUT[16] = { + 0xaa,0xf3,0xd8,0xf1,0xde,0x56,0x40,0xc2,0x32,0xf5,0xb1,0x69,0xb9,0xc9,0x11,0xe6 +}; + +static const unsigned char CMAC_TEST4_IN[64] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10 +}; +static const unsigned char CMAC_TEST4_OUT[16] = { + 0xe1,0x99,0x21,0x90,0x54,0x9f,0x6e,0xd5,0x69,0x6a,0x2c,0x05,0x6c,0x31,0x54,0x10 +}; + +static void test_cmac(const AnodeAesExpandedKey *expkey,const unsigned char *in,unsigned int inlen,const unsigned char *expected) +{ + unsigned int i; + unsigned char out[16]; + + printf("Testing CMAC with %u byte input:\n",inlen); + printf(" IN: "); + for(i=0;i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "../anode.h" +#include "../misc.h" + +int main(int argc,char **argv) +{ + unsigned char test[10005]; + unsigned int i; + AnodeSecureRandom srng; + + AnodeSecureRandom_init(&srng); + + AnodeSecureRandom_gen_bytes(&srng,test,sizeof(test)); + + for(i=0;i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "../anode.h" +#include "../misc.h" + +static const char *testuris[22] = { + "http://www.test.com", + "http://www.test.com/", + "http://www.test.com/path/to/something", + "http://user@www.test.com", + "http://user@www.test.com/path/to/something", + "http://user:password@www.test.com/path/to/something", + "http://www.test.com/path/to/something?query=foo&bar=baz", + "http://www.test.com/path/to/something#fragment", + "http://www.test.com/path/to/something?query=foo&bar=baz#fragment", + "http://user:password@www.test.com/path/to/something#fragment", + "http://user:password@www.test.com/path/to/something?query=foo&bar=baz#fragment", + "http://@www.test.com/", + "http://:@www.test.com/", + "http://www.test.com:8080/path/to/something", + "http://user:password@www.test.com:8080/path/to/something?query=foo#fragment", + "http://", + "http://www.test.com/path/to/something?#", + "http://www.test.com/path/to/something?#fragment", + "http:", + "http", + "mailto:this_is_a_urn@somedomain.com", + "" +}; + +int main(int argc,char **argv) +{ + int i,r; + char reconstbuf[2048]; + char *reconst; + AnodeURI uri; + + for(i=0;i<22;++i) { + printf("\"%s\":\n",testuris[i]); + r = AnodeURI_parse(&uri,testuris[i]); + if (r) { + printf(" error: %d\n",r); + } else { + printf(" scheme: %s\n",uri.scheme); + printf(" username: %s\n",uri.username); + printf(" password: %s\n",uri.password); + printf(" host: %s\n",uri.host); + printf(" port: %d\n",uri.port); + printf(" path: %s\n",uri.path); + printf(" query: %s\n",uri.query); + printf(" fragment: %s\n",uri.fragment); + } + reconst = AnodeURI_to_string(&uri,reconstbuf,sizeof(reconstbuf)); + printf("Reconstituted URI: %s\n",reconst ? reconst : "(null)"); + printf("\n"); + } + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/anode-zone-test.c b/attic/historic/anode/libanode/tests/anode-zone-test.c new file mode 100644 index 0000000..0839671 --- /dev/null +++ b/attic/historic/anode/libanode/tests/anode-zone-test.c @@ -0,0 +1,47 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include "../anode.h" +#include "../dictionary.h" + +static int got_it = 0; + +static void zone_lookup_handler(void *ptr,long zone_id,AnodeZone *zone) +{ + if (zone) + printf("got %.8lx: %d entries\n",(unsigned long)zone_id & 0xffffffff,((struct AnodeDictionary *)zone)->size); + else printf("failed.\n"); + got_it = 1; +} + +int main(int argc,char **argv) +{ + AnodeTransportEngine transport; + + Anode_init_ip_transport_engine(&transport); + + AnodeZone_lookup(&transport,0,0,&zone_lookup_handler); + + while (!got_it) + transport.poll(&transport); + + transport.destroy(&transport); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/dictionary-test.c b/attic/historic/anode/libanode/tests/dictionary-test.c new file mode 100644 index 0000000..12a5fb2 --- /dev/null +++ b/attic/historic/anode/libanode/tests/dictionary-test.c @@ -0,0 +1,149 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include "../dictionary.h" + +static const char *HASH_TESTS[16] = { + "test", + "testt", + "", + "foo", + "fooo", + "1", + "2", + "3", + "4", + "11", + "22", + "33", + "44", + "adklfjklejrer", + "erngnetbekjrq", + "erklerqqqqre" +}; + +int diterate(void *arg,const char *key,const char *value) +{ + printf(" %s: %s\n",key ? key : "(null)",value ? value : "(null)"); + return 1; +} + +int main(int argc,char **argv) +{ + char tmp[1024]; + char fuzzparam1[16],fuzzparam2[16],fuzzparam3[16]; + struct AnodeDictionary d; + unsigned int i,j,k,cs; + + srandom(time(0)); + + printf("Trying out hash function a little...\n"); + for(i=0;i<16;++i) + printf(" %s: %u\n",HASH_TESTS[i],(unsigned int)AnodeDictionary__get_bucket(HASH_TESTS[i])); + + for(cs=0;cs<2;++cs) { + printf("\nTesting with case sensitivity = %d\n",cs); + AnodeDictionary_init(&d,cs); + + printf("\nTesting dictionary by adding and retrieving some keys...\n"); + AnodeDictionary_put(&d,"test1","This is the first test"); + AnodeDictionary_put(&d,"test2","This is the second test"); + AnodeDictionary_put(&d,"test3","This is the third test (lower case)"); + AnodeDictionary_put(&d,"TEST3","This is the third test (UPPER CASE)"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + if (d.size != (cs ? 4 : 3)) { + printf("Failed (size).\n"); + return 1; + } + + AnodeDictionary_clear(&d); + if (d.size||(AnodeDictionary_get(&d,"test1"))) { + printf("Failed (clear).\n"); + return 1; + } + + printf("\nTesting read, trial 1: simple key=value with unterminated line\n"); + strcpy(tmp,"foo=bar\nbar=baz\ntest1=Happy happy joyjoy!\ntest2=foobarbaz\nlinewithnocr=thisworked"); + AnodeDictionary_read(&d,tmp,"\r\n","=","",'\\',0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 2: key=value with escape chars, escaped CRs\n"); + strcpy(tmp,"foo=bar\r\nbar==baz\nte\\=st1=\\=Happy happy joyjoy!\ntest2=foobarbaz\\\nfoobarbaz on next line\r\n"); + AnodeDictionary_read(&d,tmp,"\r\n","=","",'\\',0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 3: HTTP header-like dictionary\n"); + strcpy(tmp,"Host: some.host.net\r\nX-Some-Header: foo bar\r\nX-Some-Other-Header: y0y0y0y0y0\r\n"); + AnodeDictionary_read(&d,tmp,"\r\n",": ","",0,0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 4: single line key/value\n"); + strcpy(tmp,"Header: one line only"); + AnodeDictionary_read(&d,tmp,"\r\n",": ","",0,0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nFuzzing dictionary reader...\n"); fflush(stdout); + for(i=0;i<200000;++i) { + j = random() % (sizeof(tmp) - 1); + for(k=0;k> 3); + if (!tmp[k]) tmp[k] = 1; + } + tmp[j] = (char)0; + + j = random() % (sizeof(fuzzparam1) - 1); + for(k=0;k> 3); + if (!fuzzparam1[k]) fuzzparam1[k] = 1; + } + fuzzparam1[j] = (char)0; + + j = random() % (sizeof(fuzzparam2) - 1); + for(k=0;k> 3); + if (!fuzzparam2[k]) fuzzparam2[k] = 1; + } + fuzzparam2[j] = (char)0; + + j = random() % (sizeof(fuzzparam3) - 1); + for(k=0;k> 3); + if (!fuzzparam3[k]) fuzzparam3[k] = 1; + } + fuzzparam3[j] = (char)0; + + AnodeDictionary_read(&d,tmp,fuzzparam1,fuzzparam2,fuzzparam3,random() & 3,random() & 1,random() & 1); + AnodeDictionary_clear(&d); + } + + AnodeDictionary_destroy(&d); + } + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/ec-test.c b/attic/historic/anode/libanode/tests/ec-test.c new file mode 100644 index 0000000..49f0426 --- /dev/null +++ b/attic/historic/anode/libanode/tests/ec-test.c @@ -0,0 +1,97 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include "../impl/ec.h" +#include "../impl/misc.h" + +#define TEST_KEY_LEN 128 +#define AnodeEC_key_to_hex(k,b,l) Anode_to_hex((k)->key,(k)->bytes,(b),l) + +int main(int argc,char **argv) +{ + struct AnodeECKeyPair pair1; + struct AnodeECKeyPair pair2; + struct AnodeECKeyPair pair3; + unsigned char key[TEST_KEY_LEN]; + char str[16384]; + + printf("Creating key pair #1...\n"); + if (!AnodeECKeyPair_generate(&pair1)) { + printf("Could not create key pair.\n"); + return 1; + } + AnodeEC_key_to_hex(&pair1.pub,str,sizeof(str)); + printf("Public: %s\n",str); + AnodeEC_key_to_hex(&pair1.priv,str,sizeof(str)); + printf("Private: %s\n\n",str); + + printf("Creating key pair #2...\n"); + if (!AnodeECKeyPair_generate(&pair2)) { + printf("Could not create key pair.\n"); + return 1; + } + AnodeEC_key_to_hex(&pair2.pub,str,sizeof(str)); + printf("Public: %s\n",str); + AnodeEC_key_to_hex(&pair2.priv,str,sizeof(str)); + printf("Private: %s\n\n",str); + + printf("Key agreement between public #2 and private #1...\n"); + if (!AnodeECKeyPair_agree(&pair1,&pair2.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Key agreement between public #1 and private #2...\n"); + if (!AnodeECKeyPair_agree(&pair2,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Testing key pair init function (init #3 from #2's parts)...\n"); + if (!AnodeECKeyPair_init(&pair3,&(pair2.pub),&(pair2.priv))) { + printf("Init failed.\n"); + return 1; + } + + printf("Key agreement between public #1 and private #3...\n"); + if (!AnodeECKeyPair_agree(&pair3,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Key agreement between public #1 and private #1...\n"); + if (!AnodeECKeyPair_agree(&pair1,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret (should not match): %s\n\n",str); + + AnodeECKeyPair_destroy(&pair1); + AnodeECKeyPair_destroy(&pair2); + AnodeECKeyPair_destroy(&pair3); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/environment-test.c b/attic/historic/anode/libanode/tests/environment-test.c new file mode 100644 index 0000000..c481a12 --- /dev/null +++ b/attic/historic/anode/libanode/tests/environment-test.c @@ -0,0 +1,28 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "../environment.h" + +int main(int argc,char **argv) +{ + const char *cache = Anode_get_cache(); + + printf("Cache folder: %s\n",cache ? cache : "(null)"); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/http_client-test.c b/attic/historic/anode/libanode/tests/http_client-test.c new file mode 100644 index 0000000..e1f9396 --- /dev/null +++ b/attic/historic/anode/libanode/tests/http_client-test.c @@ -0,0 +1,233 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include "../anode.h" +#include "../misc.h" +#include "../http_client.h" +#include "../dictionary.h" + +struct TestCase +{ + int method; + AnodeURI uri; + const void *client_data; + unsigned int client_data_len; + const char *expected_sha1; + char actual_sha1[64]; + int got_it; + int keepalive; + struct TestCase *next; +}; + +#define NUM_TEST_CASES 7 +static struct TestCase test_cases[NUM_TEST_CASES]; + +static void init_test_cases(int keepalive) +{ + AnodeURI_parse(&(test_cases[0].uri),"http://zerotier.com/for_unit_tests/test1.txt"); + test_cases[0].method = ANODE_HTTP_GET; + test_cases[0].client_data_len = 0; + test_cases[0].expected_sha1 = "0828324174b10cc867b7255a84a8155cf89e1b8b"; + test_cases[0].actual_sha1[0] = (char)0; + test_cases[0].got_it = 0; + test_cases[0].keepalive = keepalive; + test_cases[0].next = &(test_cases[1]); + + AnodeURI_parse(&(test_cases[1].uri),"http://zerotier.com/for_unit_tests/test2.bin"); + test_cases[1].method = ANODE_HTTP_GET; + test_cases[1].client_data_len = 0; + test_cases[1].expected_sha1 = "6b67c635786ab52666211d02412c0d0f0372980d"; + test_cases[1].actual_sha1[0] = (char)0; + test_cases[1].got_it = 0; + test_cases[1].keepalive = keepalive; + test_cases[1].next = &(test_cases[2]); + + AnodeURI_parse(&(test_cases[2].uri),"http://zerotier.com/for_unit_tests/test3.bin"); + test_cases[2].method = ANODE_HTTP_GET; + test_cases[2].client_data_len = 0; + test_cases[2].expected_sha1 = "efa7722029fdbb6abd0e3ed32a0b44bfb982cff0"; + test_cases[2].actual_sha1[0] = (char)0; + test_cases[2].got_it = 0; + test_cases[2].keepalive = keepalive; + test_cases[2].next = &(test_cases[3]); + + AnodeURI_parse(&(test_cases[3].uri),"http://zerotier.com/for_unit_tests/test4.bin"); + test_cases[3].method = ANODE_HTTP_GET; + test_cases[3].client_data_len = 0; + test_cases[3].expected_sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + test_cases[3].actual_sha1[0] = (char)0; + test_cases[3].got_it = 0; + test_cases[3].keepalive = keepalive; + test_cases[3].next = &(test_cases[4]); + + AnodeURI_parse(&(test_cases[4].uri),"http://zerotier.com/for_unit_tests/echo.php?echo=foobar"); + test_cases[4].method = ANODE_HTTP_GET; + test_cases[4].client_data_len = 0; + test_cases[4].expected_sha1 = "8843d7f92416211de9ebb963ff4ce28125932878"; + test_cases[4].actual_sha1[0] = (char)0; + test_cases[4].got_it = 0; + test_cases[4].keepalive = keepalive; + test_cases[4].next = &(test_cases[5]); + + AnodeURI_parse(&(test_cases[5].uri),"http://zerotier.com/for_unit_tests/echo.php"); + test_cases[5].method = ANODE_HTTP_POST; + test_cases[5].client_data = "echo=foobar"; + test_cases[5].client_data_len = strlen((char *)test_cases[5].client_data); + test_cases[5].expected_sha1 = "8843d7f92416211de9ebb963ff4ce28125932878"; + test_cases[5].actual_sha1[0] = (char)0; + test_cases[5].got_it = 0; + test_cases[5].keepalive = keepalive; + test_cases[5].next = &(test_cases[6]); + + AnodeURI_parse(&(test_cases[6].uri),"http://zerotier.com/for_unit_tests/test3.bin"); + test_cases[6].method = ANODE_HTTP_HEAD; + test_cases[6].client_data_len = 0; + test_cases[6].expected_sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + test_cases[6].actual_sha1[0] = (char)0; + test_cases[6].got_it = 0; + test_cases[6].keepalive = keepalive; + test_cases[6].next = 0; +} + +static int http_handler_dump_headers(void *arg,const char *key,const char *value) +{ + printf(" H %s: %s\n",key,value); + return 1; +} + +static void http_handler(struct AnodeHttpClient *client) +{ + const char *method = "???"; + char buf[1024]; + unsigned char sha[20]; + struct TestCase *test = (struct TestCase *)client->ptr[0]; + + switch(client->method) { + case ANODE_HTTP_GET: + method = "GET"; + break; + case ANODE_HTTP_HEAD: + method = "HEAD"; + break; + case ANODE_HTTP_POST: + method = "POST"; + break; + } + + if (client->response.code == 200) { + SHA1((unsigned char *)client->response.data,client->response.data_length,sha); + Anode_to_hex(sha,20,test->actual_sha1,sizeof(test->actual_sha1)); + printf("%s %s\n * SHA1: %s exp: %s\n",method,AnodeURI_to_string(&(test->uri),buf,sizeof(buf)),test->actual_sha1,test->expected_sha1); + if (strcmp(test->actual_sha1,test->expected_sha1)) + printf(" ! SHA1 MISMATCH!\n"); + AnodeDictionary_iterate(&(client->response.headers),0,&http_handler_dump_headers); + } else printf("%s %s: ERROR: %d\n",method,AnodeURI_to_string(&(test->uri),buf,sizeof(buf)),client->response.code); + + test->got_it = 1; + + if (!test->keepalive) + AnodeHttpClient_free(client); + else { + test = test->next; + if (test) { + memcpy((void *)&(client->uri),(const void *)&(test->uri),sizeof(AnodeURI)); + + client->data = test->client_data; + client->data_length = test->client_data_len; + client->ptr[0] = test; + client->keepalive = test->keepalive; + client->method = test->method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + } else { + AnodeHttpClient_free(client); + } + } +} + +int main(int argc,char **argv) +{ + struct AnodeHttpClient *client; + AnodeTransportEngine transport_engine; + int i; + + if (Anode_init_ip_transport_engine(&transport_engine)) { + printf("Failed (transport engine init)\n"); + return 1; + } + + printf("Testing without keepalive...\n\n"); + init_test_cases(0); + for(i=0;iuri),(const void *)&(test_cases[i].uri),sizeof(AnodeURI)); + client->data = test_cases[i].client_data; + client->data_length = test_cases[i].client_data_len; + client->ptr[0] = &test_cases[i]; + client->keepalive = test_cases[i].keepalive; + client->method = test_cases[i].method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + } + + for(;;) { + for(i=0;iuri),(const void *)&(test_cases[i].uri),sizeof(AnodeURI)); + client->data = test_cases[i].client_data; + client->data_length = test_cases[i].client_data_len; + client->ptr[0] = &test_cases[i]; + client->keepalive = test_cases[i].keepalive; + client->method = test_cases[i].method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + + for(;;) { + for(i=0;i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include "../misc.h" + +int main(int argc,char **argv) +{ + const char *base32TestStr = "asdf"; + char *fields[16]; + char buf[1024]; + char buf2[1024]; + char buf3[4096]; + unsigned int i; + unsigned long tmpl,tmpl2; + unsigned long long tmp64; + + srand(time(0)); + + Anode_base32_5_to_8((const unsigned char *)base32TestStr,buf); + printf("Base32 from test string: %s\n",buf); + Anode_base32_8_to_5("MFZWIZQA",(unsigned char *)buf2); + printf("Test string from Base32 (upper case): %s\n",buf2); + Anode_base32_8_to_5("mfzwizqa",(unsigned char *)buf2); + printf("Test string from Base32 (lower case): %s\n",buf2); + printf("Testing variable length encoding/decoded with pad5 functions...\n"); + for(i=0;i<1024;++i) { + tmpl = rand() % (sizeof(buf) - 8); + if (!tmpl) + tmpl = 1; + for(tmpl2=0;tmpl2> 3)); + if (!Anode_base32_encode_pad5(buf2,tmpl,buf3,sizeof(buf3))) { + printf("Failed (encode failed).\n"); + return 1; + } + memset(buf2,0,sizeof(buf2)); + if (!Anode_base32_decode_pad5(buf3,buf2,sizeof(buf2))) { + printf("Failed (decode failed).\n"); + return 1; + } + if (memcmp(buf,buf2,tmpl)) { + printf("Failed (compare failed).\n"); + return 1; + } + } + + printf("Anode_htonll(0x0102030405060708) == 0x%.16llx\n",tmp64 = Anode_htonll(0x0102030405060708ULL)); + printf("Anode_ntohll(0x%.16llx) == 0x%.16llx\n",tmp64,Anode_ntohll(tmp64)); + if (Anode_ntohll(tmp64) != 0x0102030405060708ULL) { + printf("Failed.\n"); + return 1; + } + + strcpy(buf,"foo bar baz"); + Anode_trim(buf); + printf("Testing string trim: 'foo bar baz' -> '%s'\n",buf); + strcpy(buf,"foo bar baz "); + Anode_trim(buf); + printf("Testing string trim: 'foo bar baz ' -> '%s'\n",buf); + strcpy(buf," foo bar baz"); + Anode_trim(buf); + printf("Testing string trim: ' foo bar baz' -> '%s'\n",buf); + strcpy(buf," foo bar baz "); + Anode_trim(buf); + printf("Testing string trim: ' foo bar baz ' -> '%s'\n",buf); + strcpy(buf,""); + Anode_trim(buf); + printf("Testing string trim: '' -> '%s'\n",buf); + strcpy(buf," "); + Anode_trim(buf); + printf("Testing string trim: ' ' -> '%s'\n",buf); + + printf("Testing string split.\n"); + strcpy(buf,"66.246.138.121,5323,0"); + i = Anode_split(buf,';',fields,16); + if (i != 1) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s\n",fields[0]); + strcpy(buf,"a;b;c"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,";;"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,"a;b;"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,"a;;c"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + i = Anode_split(buf,';',fields,16); + if (i != 16) { + printf("Failed.\n"); + return 1; + } + strcpy(buf,""); + i = Anode_split(buf,';',fields,16); + if (i != 0) { + printf("Failed.\n"); + return 1; + } + printf("Passed.\n"); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/system_transport-test.c b/attic/historic/anode/libanode/tests/system_transport-test.c new file mode 100644 index 0000000..bda575e --- /dev/null +++ b/attic/historic/anode/libanode/tests/system_transport-test.c @@ -0,0 +1,70 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include "../anode.h" +#include "../impl/thread.h" + +static int do_client() +{ + AnodeTransport *st; + AnodeSocket *udp_sock; + int run = 1; + + st = AnodeSystemTransport_new(NULL); + if (!st) { + printf("FAILED: unable to construct AnodeSystemTransport.\n"); + return -1; + } + printf("Created AnodeSystemTransport.\n"); + + while (run) + st->poll(st); +} + +static int do_server() +{ + AnodeTransport *st; + AnodeSocket *udp_sock; + AnodeSocket *tcp_sock; + int run = 1; + + st = AnodeSystemTransport_new(NULL); + if (!st) { + printf("FAILED: unable to construct AnodeSystemTransport.\n"); + return -1; + } + printf("Created AnodeSystemTransport.\n"); + + while (run) + st->poll(st); +} + +int main(int argc,char **argv) +{ + if (argc == 2) { + if (!strcmp(argv[1],"client")) + return do_client(); + else if (!strcmp(argv[1],"server")) + return do_server(); + } + + printf("Usage: system_transport-test \n"); + return -1; +} diff --git a/attic/historic/anode/libanode/uri.c b/attic/historic/anode/libanode/uri.c new file mode 100644 index 0000000..ca644b6 --- /dev/null +++ b/attic/historic/anode/libanode/uri.c @@ -0,0 +1,185 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include "impl/misc.h" +#include "anode.h" + +int AnodeURI_parse(AnodeURI *parsed_uri,const char *uri_string) +{ + char buf[sizeof(AnodeURI)]; + unsigned long ptr = 0; + char c; + char *p1,*p2; + + Anode_zero((void *)parsed_uri,sizeof(AnodeURI)); + + /* Get the scheme */ + for(;;) { + c = *(uri_string++); + if (!c) { + parsed_uri->scheme[ptr] = (char)0; + return ANODE_ERR_INVALID_URI; + } else if (c == ':') { + parsed_uri->scheme[ptr] = (char)0; + break; + } else { + parsed_uri->scheme[ptr++] = c; + if (ptr == sizeof(parsed_uri->scheme)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + } + + if (*uri_string == '/') { + /* If it starts with /, it's a URL */ + + /* Skip double slash */ + if (!(*(++uri_string))) + return 0; /* Scheme with no path */ + if (*uri_string == '/') { + if (!(*(++uri_string))) + return 0; /* Scheme with no path */ + } + + /* Get the host section and put it in buf[] */ + ptr = 0; + while ((*uri_string)&&(*uri_string != '/')) { + buf[ptr++] = *(uri_string++); + if (ptr == sizeof(buf)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + buf[ptr] = (char)0; + + /* Parse host section for host, username, password, and port */ + if (buf[0]) { + p1 = (char *)Anode_strchr(buf,'@'); + if (p1) { + *(p1++) = (char)0; + if (*p1) { + p2 = (char *)Anode_strchr(buf,':'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->password,p2,sizeof(parsed_uri->password)); + } + Anode_str_copy(parsed_uri->username,buf,sizeof(parsed_uri->username)); + } else return ANODE_ERR_INVALID_URI; + } else p1 = buf; + + p2 = (char *)Anode_strchr(p1,':'); + if (p2) { + *(p2++) = (char)0; + if (*p2) + parsed_uri->port = (int)strtoul(p2,(char **)0,10); + } + Anode_str_copy(parsed_uri->host,p1,sizeof(parsed_uri->host)); + } + + /* Get the path, query, and fragment section and put it in buf[] */ + ptr = 0; + while ((buf[ptr++] = *(uri_string++))) { + if (ptr == sizeof(buf)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + + /* Parse path section for path, query, and fragment */ + if (buf[0]) { + p1 = (char *)Anode_strchr(buf,'?'); + if (p1) { + *(p1++) = (char)0; + p2 = (char *)Anode_strchr(p1,'#'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment)); + } + Anode_str_copy(parsed_uri->query,p1,sizeof(parsed_uri->query)); + } else { + p2 = (char *)Anode_strchr(buf,'#'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment)); + } + } + Anode_str_copy(parsed_uri->path,buf,sizeof(parsed_uri->path)); + } + } else { + /* Otherwise, it's a URN and what remains is all path */ + ptr = 0; + while ((parsed_uri->path[ptr++] = *(uri_string++))) { + if (ptr == sizeof(parsed_uri->path)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + } + + return 0; +} + +char *AnodeURI_to_string(const AnodeURI *uri,char *buf,int len) +{ + int i = 0; + char portbuf[16]; + const char *p; + + p = uri->scheme; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + buf[i++] = ':'; if (i >= len) return (char *)0; + + if (uri->host[0]) { + buf[i++] = '/'; if (i >= len) return (char *)0; + buf[i++] = '/'; if (i >= len) return (char *)0; + + if (uri->username[0]) { + p = uri->username; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + if (uri->password[0]) { + buf[i++] = ':'; if (i >= len) return (char *)0; + p = uri->password; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + buf[i++] = '@'; if (i >= len) return (char *)0; + } + + p = uri->host; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + if ((uri->port > 0)&&(uri->port <= 0xffff)) { + buf[i++] = ':'; if (i >= len) return (char *)0; + snprintf(portbuf,sizeof(portbuf),"%d",uri->port); + p = portbuf; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + } + + p = uri->path; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + if (uri->query[0]) { + buf[i++] = '?'; if (i >= len) return (char *)0; + p = uri->query; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + + if (uri->fragment[0]) { + buf[i++] = '#'; if (i >= len) return (char *)0; + p = uri->fragment; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + + buf[i] = (char)0; + + return buf; +} diff --git a/attic/historic/anode/libanode/utils/anode-make-identity.c b/attic/historic/anode/libanode/utils/anode-make-identity.c new file mode 100644 index 0000000..99a3897 --- /dev/null +++ b/attic/historic/anode/libanode/utils/anode-make-identity.c @@ -0,0 +1,50 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include "../anode.h" +#include "../impl/misc.h" +#include "../impl/types.h" + +int main(int argc,char **argv) +{ + char str[1024]; + AnodeZone zone; + AnodeIdentity identity; + + if (argc < 2) { + printf("Usage: anode-make-identity <32-bit zone ID hex>\n"); + return 0; + } + + *((uint32_t *)zone.bits) = htonl((uint32_t)strtoul(argv[1],(char **)0,16)); + + if (AnodeIdentity_generate(&identity,&zone,ANODE_ADDRESS_ANODE_256_40)) { + fprintf(stderr,"Error: identity key pair generation failed (check build settings).\n"); + return 1; + } + if (AnodeIdentity_to_string(&identity,str,sizeof(str)) <= 0) { + fprintf(stderr,"Error: internal error converting identity to string.\n"); + return -1; + } + + printf("%s\n",str); + + return 0; +} diff --git a/attic/historic/anode/libanode/zone.c b/attic/historic/anode/libanode/zone.c new file mode 100644 index 0000000..a6e397a --- /dev/null +++ b/attic/historic/anode/libanode/zone.c @@ -0,0 +1,184 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009-2010 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include "impl/types.h" +#include "impl/misc.h" +#include "impl/dictionary.h" +#include "impl/environment.h" +#include "impl/http_client.h" +#include "anode.h" + +static const char *_MONTHS[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; +static const char *_DAYS_OF_WEEK[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" }; +static inline unsigned long get_file_time_for_http(const char *path,char *buf,unsigned int len) +{ + struct stat st; + struct tm *gmt; + + if (!stat(path,(struct stat *)&st)) { + gmt = gmtime(&st.st_mtime); + if (gmt) { + snprintf(buf,len,"%s, %d %s %d %d:%d:%d GMT", + _DAYS_OF_WEEK[gmt->tm_wday], + gmt->tm_mday, + _MONTHS[gmt->tm_mon], + (1900 + gmt->tm_year), + gmt->tm_hour, + gmt->tm_min, + gmt->tm_sec); + buf[len - 1] = (char)0; + return (unsigned long)st.st_size; + } + } + + return 0; +} + +struct AnodeZoneLookupJob +{ + char cached_zone_file[2048]; + struct AnodeDictionary *zone_dict; + AnodeZone zone; + void *ptr; + void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZoneFile *); + int had_cached_zone; +}; + +static void AnodeZone_lookup_http_handler(struct AnodeHttpClient *client) +{ + char *data_tmp; + struct AnodeZoneLookupJob *job = (struct AnodeZoneLookupJob *)client->ptr[0]; + FILE *zf; + + if ((client->response.code == 200)&&(client->response.data_length > 0)) { + zf = fopen(job->cached_zone_file,"w"); + if (zf) { + fwrite(client->response.data,1,client->response.data_length,zf); + fclose(zf); + } + + data_tmp = (char *)malloc(client->response.data_length + 1); + Anode_memcpy((void *)data_tmp,client->response.data,client->response.data_length); + data_tmp[client->response.data_length] = (char)0; + + AnodeDictionary_clear(job->zone_dict); + AnodeDictionary_read( + job->zone_dict, + data_tmp, + "\r\n", + "=", + ";", + '\\', + 1,1); + + free((void *)data_tmp); + + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); + } else if (job->had_cached_zone) + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); + else { + AnodeDictionary_destroy(job->zone_dict); + free((void *)job->zone_dict); + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)0); + } + + free((void *)job); + AnodeHttpClient_free(client); +} + +void AnodeZone_lookup( + AnodeTransportEngine *transport, + const AnodeZone *zone, + void *ptr, + void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZone *)) +{ + char cached_zones_folder[2048]; + char cached_zone_file[2048]; + char if_modified_since[256]; + unsigned long file_size; + struct AnodeZoneLookupJob *job; + struct AnodeHttpClient *client; + char *file_data; + FILE *zf; + + if (Anode_get_cache_sub("zones",cached_zones_folder,sizeof(cached_zones_folder))) { + snprintf(cached_zone_file,sizeof(cached_zone_file),"%s%c%.2x%.2x%.2x%.2x.z",cached_zones_folder,ANODE_PATH_SEPARATOR,(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); + cached_zone_file[sizeof(cached_zone_file)-1] = (char)0; + + job = (struct AnodeZoneLookupJob *)malloc(sizeof(struct AnodeZoneLookupJob)); + Anode_str_copy(job->cached_zone_file,cached_zone_file,sizeof(job->cached_zone_file)); + job->zone_dict = (struct AnodeDictionary *)malloc(sizeof(struct AnodeDictionary)); + AnodeDictionary_init(job->zone_dict,0); + job->zone.bits[0] = zone->bits[0]; + job->zone.bits[1] = zone->bits[1]; + job->zone.bits[2] = zone->bits[2]; + job->zone.bits[3] = zone->bits[3]; + job->ptr = ptr; + job->zone_lookup_handler = zone_lookup_handler; + job->had_cached_zone = 0; + + client = AnodeHttpClient_new(transport); + + Anode_str_copy(client->uri.scheme,"http",sizeof(client->uri.scheme)); + snprintf(client->uri.host,sizeof(client->uri.host),"a--%.2x%.2x%.2x%.2x.net",(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); + client->uri.host[sizeof(client->uri.host)-1] = (char)0; + Anode_str_copy(client->uri.path,"/z",sizeof(client->uri.path)); + + client->handler = &AnodeZone_lookup_http_handler; + client->ptr[0] = job; + + if ((file_size = get_file_time_for_http(cached_zone_file,if_modified_since,sizeof(if_modified_since)))) { + zf = fopen(cached_zone_file,"r"); + if (zf) { + AnodeDictionary_put(&client->headers,"If-Modified-Since",if_modified_since); + file_data = (char *)malloc(file_size + 1); + if (fread((void *)file_data,1,file_size,zf)) { + file_data[file_size] = (char)0; + AnodeDictionary_read( + job->zone_dict, + file_data, + "\r\n", + "=", + ";", + '\\', + 1,1); + job->had_cached_zone = 1; + } + free((void *)file_data); + fclose(zf); + } + } + + AnodeHttpClient_send(client); + } else zone_lookup_handler(ptr,zone,(AnodeZone *)0); +} + +const char *AnodeZoneFile_get(AnodeZoneFile *zone,const char *key) +{ + return AnodeDictionary_get((struct AnodeDictionary *)zone,key); +} + +void AnodeZoneFile_free(AnodeZoneFile *zone) +{ + AnodeDictionary_destroy((struct AnodeDictionary *)zone); + free((void *)zone); +} diff --git a/attic/historic/anode/libspark/Makefile b/attic/historic/anode/libspark/Makefile new file mode 100644 index 0000000..0d3fedd --- /dev/null +++ b/attic/historic/anode/libspark/Makefile @@ -0,0 +1,16 @@ +SYSNAME:=${shell uname} +SYSNAME!=uname +include ../config.mk.${SYSNAME} + +LIBSPARK_OBJS= + +all: libspark + +libspark: $(LIBSPARK_OBJS) + ar rcs libspark.a $(LIBSPARK_OBJS) + ranlib libspark.a + +clean: force + rm -f *.a *.so *.dylib *.dll *.lib *.exe *.o + +force: ; diff --git a/attic/historic/anode/libspark/experiments/FindGoodSegmentDelimiters.cpp b/attic/historic/anode/libspark/experiments/FindGoodSegmentDelimiters.cpp new file mode 100644 index 0000000..9b1ecaa --- /dev/null +++ b/attic/historic/anode/libspark/experiments/FindGoodSegmentDelimiters.cpp @@ -0,0 +1,161 @@ +// Searches for good delimiters to cut streams into relatively well sized +// segments. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Desired size range +#define MIN_DESIRED_SIZE 4096 +#define MAX_DESIRED_SIZE 131072 + +#define DELIMITER_SET_SIZE 1 +typedef boost::array DelimArray; + +struct BestEntry +{ + DelimArray best; + double bestScore; + std::vector data; +}; + +boost::mutex bestLock; +boost::mutex outLock; +std::map best; + +static void runThread(const std::string &fileName) +{ + char tmp[4096]; + + boost::mt19937 prng; + { + boost::uint32_t seed; + FILE *ur = fopen("/dev/urandom","r"); + fread((void *)&seed,1,sizeof(seed),ur); + fclose(ur); + prng.seed(seed); + } + + BestEntry *myEntry; + { + boost::mutex::scoped_lock l(bestLock); + myEntry = &(best[fileName]); + myEntry->bestScore = 99999999.0; + } + + { + boost::mutex::scoped_lock l(outLock); + + std::cout << "*** Reading test data from: " << fileName << std::endl; + FILE *f = fopen(fileName.c_str(),"r"); + if (f) { + int n; + while ((n = fread((void *)tmp,1,sizeof(tmp),f)) > 0) { + for(int i=0;idata.push_back((unsigned char)tmp[i]); + } + fclose(f); + } + + if (myEntry->data.size() <= 0) { + std::cout << "Error: no data read." << std::endl; + exit(1); + } else std::cout << "*** Read " << myEntry->data.size() << " bytes of test data." << std::endl; + + std::cout.flush(); + } + + DelimArray current; + for(unsigned int i=0;i::iterator i=myEntry->data.begin();i!=myEntry->data.end();++i) { + shiftRegister <<= 1; + shiftRegister |= (((boost::uint32_t)*i) & 1); + + ++segSize; + + boost::uint16_t transformedShiftRegister = (boost::uint16_t)(shiftRegister); + + for(DelimArray::iterator d=current.begin();d!=current.end();++d) { + if (transformedShiftRegister == *d) { + if (segSize < MIN_DESIRED_SIZE) + ++numTooShort; + else if (segSize > MAX_DESIRED_SIZE) + ++numTooLong; + else ++numGood; + segSize = 0; + break; + } + } + } + if (segSize) { + if (segSize < MIN_DESIRED_SIZE) + ++numTooShort; + else if (segSize > MAX_DESIRED_SIZE) + ++numTooLong; + else ++numGood; + } + + if (numGood) { + double score = ((double)(numTooShort + numTooLong)) / ((double)numGood); + + if (score < myEntry->bestScore) { + myEntry->best = current; + myEntry->bestScore = score; + + boost::mutex::scoped_lock l(outLock); + + std::cout << fileName << ": "; + + for(DelimArray::iterator d=current.begin();d!=current.end();++d) { + sprintf(tmp,"0x%.4x",(unsigned int)*d); + if (d != current.begin()) + std::cout << ','; + std::cout << tmp; + } + + std::cout << ": " << numTooShort << " / " << numGood << " / " << numTooLong << " (" << score << ")" << std::endl; + std::cout.flush(); + + if ((numTooShort == 0)&&(numTooLong == 0)) + break; + } + } + + for(DelimArray::iterator i=current.begin();i!=current.end();++i) + *i = (boost::uint16_t)prng(); + } +} + +int main(int argc,char **argv) +{ + std::vector< boost::shared_ptr > threads; + + for(int i=1;i t(new boost::thread(boost::bind(&runThread,std::string(argv[i])))); + threads.push_back(t); + } + + for(std::vector< boost::shared_ptr >::iterator i=threads.begin();i!=threads.end();++i) + (*i)->join(); + + return 0; +} diff --git a/attic/historic/anode/libspark/experiments/Makefile b/attic/historic/anode/libspark/experiments/Makefile new file mode 100644 index 0000000..83aa4f6 --- /dev/null +++ b/attic/historic/anode/libspark/experiments/Makefile @@ -0,0 +1,5 @@ +all: + g++ -O6 -ftree-vectorize -o FindGoodSegmentDelimiters FindGoodSegmentDelimiters.cpp -lboost_thread -lpthread + +clean: + rm FindGoodSegmentDelimiters diff --git a/attic/historic/anode/libspark/streamencoder.h b/attic/historic/anode/libspark/streamencoder.h new file mode 100644 index 0000000..b487ca4 --- /dev/null +++ b/attic/historic/anode/libspark/streamencoder.h @@ -0,0 +1,108 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _SPARK_STREAMENCODER_H +#define _SPARK_STREAMENCODER_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + unsigned char *input_buf; + unsigned long input_buf_capacity; + unsigned long input_length; + + unsigned char *stream_out_buf; + unsigned long stream_out_buf_capacity; + unsigned long stream_out_length; + + void (*data_segment_add_func)(const void *data,unsigned long len,const void *global_hash,unsigned long global_hash_len); +} SparkStreamEncoder; + +/** + * Initialize a spark stream encoder + * + * @param enc Encoder structure to initialize + * @param data_segment_add_func Function to call to store or cache data + */ +void SparkStreamEncoder_init( + SparkStreamEncoder *enc, + void (*data_segment_add_func)( + const void *data, + unsigned long len, + const void *global_hash, + unsigned long global_hash_len)); + +/** + * Clean up a spark stream encoder structure + * + * @param enc Structure to clear + */ +void SparkStreamEncoder_destroy(SparkStreamEncoder *enc); + +/** + * Add data to encode + * + * @param enc Encoder structure + * @param data Data to encode + * @param len Length of data in bytes + * @return Number of bytes of result stream now available + */ +unsigned long SparkStreamEncoder_put( + SparkStreamEncoder *enc, + const void *data, + unsigned long len); + +/** + * Flush all data currently in input buffer + * + * @param enc Encoder structure to flush + */ +void SparkStreamEncoder_flush(SparkStreamEncoder *enc); + +/** + * @return Number of bytes of output stream available + */ +static inline unsigned long SparkStreamEncoder_available(SparkStreamEncoder *enc) +{ + return enc->stream_out_length; +} + +/** + * @return Pointer to result stream bytes (may return null if none available) + */ +static inline const void *SparkStreamEncoder_get(SparkStreamEncoder *enc) +{ + return (const void *)(enc->stream_out_buf); +} + +/** + * @return "Consume" result stream bytes after they're read or sent + */ +static inline void SparkStreamEncoder_consume(SparkStreamEncoder *enc,unsigned long len) +{ + unsigned long i; + for(i=len;istream_out_length;++i) + enc->stream_out_buf[i - len] = enc->stream_out_buf[i]; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/attic/historic/anode/libspark/wrapper.h b/attic/historic/anode/libspark/wrapper.h new file mode 100644 index 0000000..eb8c593 --- /dev/null +++ b/attic/historic/anode/libspark/wrapper.h @@ -0,0 +1,66 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 Adam Ierymenko + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#ifndef _SPARK_WRAPPER_H +#define _SPARK_WRAPPER_H + +#include +#include "../libanode/aes128.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Spark uses SHA-256 with hash length 32 */ +#define SPARK_HASH_LENGTH 32 + +// Wrap a segment for forward propagation +static inline void Spark_wrap(void *data,unsigned long len,void *plaintext_hash_buf,void *global_hash_buf) +{ + unsigned char expkey[ANODE_AES128_EXP_KEY_SIZE]; + + SHA256((const unsigned char *)data,len,(unsigned char *)plaintext_hash_buf); + + Anode_aes128_expand_key(expkey,(const unsigned char *)plaintext_hash_buf); + Anode_aes128_cfb_encrypt(expkey,((const unsigned char *)plaintext_hash_buf) + 16,(unsigned char *)data,len); + + SHA256((const unsigned char *)data,len,(unsigned char *)global_hash_buf); +} + +// Unwrap a segment and check its integrity +static inline int Spark_unwrap(void *data,unsigned long len,const void *plaintext_hash) +{ + unsigned char expkey[ANODE_AES128_EXP_KEY_SIZE]; + unsigned char check_hash[32]; + unsigned long i; + + Anode_aes128_expand_key(expkey,(const unsigned char *)plaintext_hash); + Anode_aes128_cfb_decrypt(expkey,((const unsigned char *)plaintext_hash) + 16,(unsigned char *)data,len); + + SHA256((const unsigned char *)data,len,check_hash); + + for(i=0;i<32;++i) { + if (check_hash[i] != ((const unsigned char *)plaintext_hash)[i]) + return 0; + } + return 1; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/attic/linux-build-farm/README.md b/attic/linux-build-farm/README.md deleted file mode 100644 index 8055eb0..0000000 --- a/attic/linux-build-farm/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Dockerized Linux Build Farm -====== - -This subfolder contains Dockerfiles and a script to build Linux packages for a variety of Linux distributions. It's also an excellent way to test your CPU fans and stress test your disk. - -Running `build.sh` with no arguments builds everything. You can run `build.sh` with the name of a distro (e.g. centos-7) to only build that. Both 32 and 64 bit packages are built except where no 32-bit version of the distribution exists. - -The `make-apt-repos.sh` and `make-rpm-repos.sh` scripts build repositories. They may require some editing for outside-of-ZeroTier use, and be careful with the apt one if you have an existing *aptly* configuration. diff --git a/attic/linux-build-farm/amazon-2016.03/x64/Dockerfile b/attic/linux-build-farm/amazon-2016.03/x64/Dockerfile deleted file mode 100644 index bd1a246..0000000 --- a/attic/linux-build-farm/amazon-2016.03/x64/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -#FROM ambakshi/amazon-linux:2016.03 -#MAINTAINER Adam Ierymenko - -#RUN yum update -y -#RUN yum install -y epel-release -#RUN yum install -y make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel - -#RUN gem install ronn - -FROM zerotier/zt1-build-amazon-2016.03-x64-base -MAINTAINER Adam Ierymenko - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/build.sh b/attic/linux-build-farm/build.sh deleted file mode 100755 index 0eb7c5d..0000000 --- a/attic/linux-build-farm/build.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin - -subdirs=$* -if [ ! -n "$subdirs" ]; then - subdirs=`find . -type d -name '*-*' -printf '%f '` -fi - -if [ ! -d ./ubuntu-trusty ]; then - echo 'Must run from linux-build-farm subfolder.' - exit 1 -fi - -rm -f zt1-src.tar.gz -cd .. -git archive --format=tar.gz --prefix=ZeroTierOne/ -o linux-build-farm/zt1-src.tar.gz HEAD -cd linux-build-farm - -# Note that --privileged is used so we can bind mount VM shares when building in a VM. -# It has no other impact or purpose, but probably doesn't matter here in any case. - -for distro in $subdirs; do - echo - echo "--- BUILDING FOR $distro ---" - echo - - cd $distro - - if [ -d x64 ]; then - cd x64 - mv ../../zt1-src.tar.gz . - docker build -t zt1-build-${distro}-x64 . - mv zt1-src.tar.gz ../.. - cd .. - fi - - if [ -d x86 ]; then - cd x86 - mv ../../zt1-src.tar.gz . - docker build -t zt1-build-${distro}-x86 . - mv zt1-src.tar.gz ../.. - cd .. - fi - - rm -f *.deb *.rpm - -# exit 0 - - if [ ! -n "`echo $distro | grep -F debian`" -a ! -n "`echo $distro | grep -F ubuntu`" ]; then - if [ -d x64 ]; then - docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x64 /bin/bash -c 'cd /ZeroTierOne ; make redhat ; cd .. ; cp `find /root/rpmbuild -type f -name *.rpm` /artifacts ; ls -l /artifacts' - fi - if [ -d x86 ]; then - docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x86 /bin/bash -c 'cd /ZeroTierOne ; make redhat ; cd .. ; cp `find /root/rpmbuild -type f -name *.rpm` /artifacts ; ls -l /artifacts' - fi - else - if [ -d x64 ]; then - docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x64 /bin/bash -c 'cd /ZeroTierOne ; make debian ; cd .. ; cp *.deb /artifacts ; ls -l /artifacts' - fi - if [ -d x86 ]; then - docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x86 /bin/bash -c 'cd /ZeroTierOne ; make debian ; cd .. ; cp *.deb /artifacts ; ls -l /artifacts' - fi - fi - - cd .. -done - -rm -f zt1-src.tar.gz diff --git a/attic/linux-build-farm/centos-6/x64/Dockerfile b/attic/linux-build-farm/centos-6/x64/Dockerfile deleted file mode 100644 index 2796e42..0000000 --- a/attic/linux-build-farm/centos-6/x64/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM centos:6 -MAINTAINER Adam Ierymenko - -RUN yum update -y -RUN yum install -y epel-release -RUN yum install -y make development-tools rpmdevtools clang gcc-c++ tar - -RUN yum install -y nodejs npm - -# Stop use of http-parser-devel which is installed by nodejs/npm -RUN rm -f /usr/include/http_parser.h - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/centos-6/x86/Dockerfile b/attic/linux-build-farm/centos-6/x86/Dockerfile deleted file mode 100644 index 8192d13..0000000 --- a/attic/linux-build-farm/centos-6/x86/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM toopher/centos-i386:centos6 -MAINTAINER Adam Ierymenko - -RUN yum update -y -RUN yum install -y epel-release -RUN yum install -y make development-tools rpmdevtools clang gcc-c++ tar - -RUN yum install -y nodejs npm - -# Stop use of http-parser-devel which is installed by nodejs/npm -RUN rm -f /usr/include/http_parser.h - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/centos-7/x64/Dockerfile b/attic/linux-build-farm/centos-7/x64/Dockerfile deleted file mode 100644 index 10b5840..0000000 --- a/attic/linux-build-farm/centos-7/x64/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM centos:7 -MAINTAINER Adam Ierymenko - -RUN yum update -y -RUN yum install -y epel-release -RUN yum install -y make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel - -RUN gem install ronn - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/centos-7/x86/Dockerfile b/attic/linux-build-farm/centos-7/x86/Dockerfile deleted file mode 100644 index a637a8d..0000000 --- a/attic/linux-build-farm/centos-7/x86/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -#FROM zerotier/centos7-32bit -#MAINTAINER Adam Ierymenko - -#RUN echo 'i686-redhat-linux' >/etc/rpm/platform - -#RUN yum update -y -#RUN yum install -y make development-tools rpmdevtools http-parser-devel lz4-devel libnatpmp-devel - -#RUN yum install -y gcc-c++ -#RUN rpm --install --force https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm -#RUN rpm --install --force ftp://rpmfind.net/linux/centos/6.8/os/i386/Packages/libffi-3.0.5-3.2.el6.i686.rpm -#RUN yum install -y clang - -FROM zerotier/zt1-build-centos-7-x86-base -MAINTAINER Adam Ierymenko - -RUN yum install -y ruby ruby-devel -RUN gem install ronn - -#RUN rpm --erase http-parser-devel lz4-devel libnatpmp-devel - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/debian-jessie/x64/Dockerfile b/attic/linux-build-farm/debian-jessie/x64/Dockerfile deleted file mode 100644 index 316c1d8..0000000 --- a/attic/linux-build-farm/debian-jessie/x64/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM debian:jessie -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.5 - -RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/debian-jessie/x86/Dockerfile b/attic/linux-build-farm/debian-jessie/x86/Dockerfile deleted file mode 100644 index 3ad8332..0000000 --- a/attic/linux-build-farm/debian-jessie/x86/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM 32bit/debian:jessie -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.5 - -RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/debian-stretch/x64/Dockerfile b/attic/linux-build-farm/debian-stretch/x64/Dockerfile deleted file mode 100644 index c973c2b..0000000 --- a/attic/linux-build-farm/debian-stretch/x64/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM debian:stretch -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang - -#RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++ -#RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/debian-stretch/x86/Dockerfile b/attic/linux-build-farm/debian-stretch/x86/Dockerfile deleted file mode 100644 index bfc7a86..0000000 --- a/attic/linux-build-farm/debian-stretch/x86/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM mcandre/docker-debian-32bit:stretch -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang - -#RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++ -#RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/debian-wheezy/x64/Dockerfile b/attic/linux-build-farm/debian-wheezy/x64/Dockerfile deleted file mode 100644 index 77e1c32..0000000 --- a/attic/linux-build-farm/debian-wheezy/x64/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM debian:wheezy -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / - -RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control -RUN mv -f /ZeroTierOne/debian/rules.wheezy /ZeroTierOne/debian/rules diff --git a/attic/linux-build-farm/debian-wheezy/x86/Dockerfile b/attic/linux-build-farm/debian-wheezy/x86/Dockerfile deleted file mode 100644 index 1f0117d..0000000 --- a/attic/linux-build-farm/debian-wheezy/x86/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -#FROM tubia/debian:wheezy -#MAINTAINER Adam Ierymenko - -#RUN apt-get update -#RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts - -FROM zerotier/zt1-build-debian-wheezy-x86-base -MAINTAINER Adam Ierymenko - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / - -RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control -RUN mv -f /ZeroTierOne/debian/rules.wheezy /ZeroTierOne/debian/rules diff --git a/attic/linux-build-farm/fedora-22/x64/Dockerfile b/attic/linux-build-farm/fedora-22/x64/Dockerfile deleted file mode 100644 index 6da0a92..0000000 --- a/attic/linux-build-farm/fedora-22/x64/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM fedora:22 -MAINTAINER Adam Ierymenko - -RUN yum update -y -RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel - -RUN rpm --erase http-parser-devel -RUN yum install -y rubygem-ronn ruby - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/fedora-22/x86/Dockerfile b/attic/linux-build-farm/fedora-22/x86/Dockerfile deleted file mode 100644 index 3c24b84..0000000 --- a/attic/linux-build-farm/fedora-22/x86/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -#FROM nickcis/fedora-32:22 -#MAINTAINER Adam Ierymenko - -#RUN mkdir -p /etc/dnf/vars -#RUN echo 'i386' >/etc/dnf/vars/basearch -#RUN echo 'i386' >/etc/dnf/vars/arch - -#RUN yum update -y -#RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel - -FROM zerotier/zt1-build-fedora-22-x86-base -MAINTAINER Adam Ierymenko - -RUN echo 'i686-redhat-linux' >/etc/rpm/platform - -RUN rpm --erase http-parser-devel -RUN yum install -y rubygem-ronn ruby - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/make-apt-repos.sh b/attic/linux-build-farm/make-apt-repos.sh deleted file mode 100755 index 7a81cc5..0000000 --- a/attic/linux-build-farm/make-apt-repos.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# This builds a series of Debian repositories for each distribution. - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin - -for distro in debian-* ubuntu-*; do - if [ -n "`find ${distro} -name '*.deb' -type f`" ]; then - arches=`ls ${distro}/*.deb | cut -d _ -f 3 | cut -d . -f 1 | xargs | sed 's/ /,/g'` - distro_name=`echo $distro | cut -d '-' -f 2` - echo '---' $distro / $distro_name / $arches - aptly repo create -architectures=${arches} -comment="ZeroTier, Inc. Debian Packages" -component="main" -distribution=${distro_name} zt-release-${distro_name} - aptly repo add zt-release-${distro_name} ${distro}/*.deb - aptly publish repo zt-release-${distro_name} $distro_name - fi -done diff --git a/attic/linux-build-farm/make-rpm-repos.sh b/attic/linux-build-farm/make-rpm-repos.sh deleted file mode 100755 index 0ed1cfe..0000000 --- a/attic/linux-build-farm/make-rpm-repos.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin - -GPG_KEY=contact@zerotier.com - -rm -rf /tmp/zt-rpm-repo -mkdir /tmp/zt-rpm-repo - -for distro in centos-* fedora-* amazon-*; do - dname=`echo $distro | cut -d '-' -f 1` - if [ "$dname" = "centos" ]; then - dname=el - fi - if [ "$dname" = "fedora" ]; then - dname=fc - fi - if [ "$dname" = "amazon" ]; then - dname=amzn1 - fi - dvers=`echo $distro | cut -d '-' -f 2` - - mkdir -p /tmp/zt-rpm-repo/$dname/$dvers - - cp -v $distro/*.rpm /tmp/zt-rpm-repo/$dname/$dvers -done - -rpmsign --resign --key-id=$GPG_KEY --digest-algo=sha256 `find /tmp/zt-rpm-repo -type f -name '*.rpm'` - -for db in `find /tmp/zt-rpm-repo -mindepth 2 -maxdepth 2 -type d`; do - createrepo --database $db -done - -# Stupid RHEL stuff -cd /tmp/zt-rpm-repo/el -ln -sf 6 6Client -ln -sf 6 6Workstation -ln -sf 6 6Server -ln -sf 6 6.0 -ln -sf 6 6.1 -ln -sf 6 6.2 -ln -sf 6 6.3 -ln -sf 6 6.4 -ln -sf 6 6.5 -ln -sf 6 6.6 -ln -sf 6 6.7 -ln -sf 6 6.8 -ln -sf 6 6.9 -ln -sf 7 7Client -ln -sf 7 7Workstation -ln -sf 7 7Server -ln -sf 7 7.0 -ln -sf 7 7.1 -ln -sf 7 7.2 -ln -sf 7 7.3 -ln -sf 7 7.4 -ln -sf 7 7.5 -ln -sf 7 7.6 -ln -sf 7 7.7 -ln -sf 7 7.8 -ln -sf 7 7.9 - -echo -echo Repo created in /tmp/zt-rpm-repo diff --git a/attic/linux-build-farm/ubuntu-trusty/x64/Dockerfile b/attic/linux-build-farm/ubuntu-trusty/x64/Dockerfile deleted file mode 100644 index f84cc6e..0000000 --- a/attic/linux-build-farm/ubuntu-trusty/x64/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM ubuntu:14.04 -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.6 - -RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/ubuntu-trusty/x86/Dockerfile b/attic/linux-build-farm/ubuntu-trusty/x86/Dockerfile deleted file mode 100644 index 6be3ae8..0000000 --- a/attic/linux-build-farm/ubuntu-trusty/x86/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM 32bit/ubuntu:14.04 -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.6 - -RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/ubuntu-wily/x64/Dockerfile b/attic/linux-build-farm/ubuntu-wily/x64/Dockerfile deleted file mode 100644 index 99b8d34..0000000 --- a/attic/linux-build-farm/ubuntu-wily/x64/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM ubuntu:wily -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.7 - -RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/ubuntu-wily/x86/Dockerfile b/attic/linux-build-farm/ubuntu-wily/x86/Dockerfile deleted file mode 100644 index 86ad14f..0000000 --- a/attic/linux-build-farm/ubuntu-wily/x86/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM daald/ubuntu32:wily -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.7 - -RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++ -RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/ubuntu-xenial/x64/Dockerfile b/attic/linux-build-farm/ubuntu-xenial/x64/Dockerfile deleted file mode 100644 index fa665a0..0000000 --- a/attic/linux-build-farm/ubuntu-xenial/x64/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:xenial -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.8 - -#RUN ln -sf /usr/bin/clang++-3.8 /usr/bin/clang++ -#RUN ln -sf /usr/bin/clang-3.8 /usr/bin/clang - -RUN rm -f /usr/bin/clang++ /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/linux-build-farm/ubuntu-xenial/x86/Dockerfile b/attic/linux-build-farm/ubuntu-xenial/x86/Dockerfile deleted file mode 100644 index d01eec9..0000000 --- a/attic/linux-build-farm/ubuntu-xenial/x86/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM f69m/ubuntu32:xenial -MAINTAINER Adam Ierymenko - -RUN apt-get update -RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.8 - -#RUN ln -sf /usr/bin/clang++-3.8 /usr/bin/clang++ -#RUN ln -sf /usr/bin/clang-3.8 /usr/bin/clang - -RUN rm -f /usr/bin/clang++ /usr/bin/clang - -RUN dpkg --purge libhttp-parser-dev - -ADD zt1-src.tar.gz / diff --git a/attic/old-controller-schema.sql b/attic/old-controller-schema.sql deleted file mode 100644 index d1daf8d..0000000 --- a/attic/old-controller-schema.sql +++ /dev/null @@ -1,112 +0,0 @@ -CREATE TABLE Config ( - k varchar(16) PRIMARY KEY NOT NULL, - v varchar(1024) NOT NULL -); - -CREATE TABLE Network ( - id char(16) PRIMARY KEY NOT NULL, - name varchar(128) NOT NULL, - private integer NOT NULL DEFAULT(1), - enableBroadcast integer NOT NULL DEFAULT(1), - allowPassiveBridging integer NOT NULL DEFAULT(0), - multicastLimit integer NOT NULL DEFAULT(32), - creationTime integer NOT NULL DEFAULT(0), - revision integer NOT NULL DEFAULT(1), - memberRevisionCounter integer NOT NULL DEFAULT(1), - flags integer NOT NULL DEFAULT(0) -); - -CREATE TABLE AuthToken ( - id integer PRIMARY KEY NOT NULL, - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - authMode integer NOT NULL DEFAULT(1), - useCount integer NOT NULL DEFAULT(0), - maxUses integer NOT NULL DEFAULT(0), - expiresAt integer NOT NULL DEFAULT(0), - token varchar(256) NOT NULL -); - -CREATE INDEX AuthToken_networkId_token ON AuthToken(networkId,token); - -CREATE TABLE Node ( - id char(10) PRIMARY KEY NOT NULL, - identity varchar(4096) NOT NULL -); - -CREATE TABLE IpAssignment ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - nodeId char(10) REFERENCES Node(id) ON DELETE CASCADE, - type integer NOT NULL DEFAULT(0), - ip blob(16) NOT NULL, - ipNetmaskBits integer NOT NULL DEFAULT(0), - ipVersion integer NOT NULL DEFAULT(4) -); - -CREATE UNIQUE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip); - -CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId); - -CREATE TABLE IpAssignmentPool ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - ipRangeStart blob(16) NOT NULL, - ipRangeEnd blob(16) NOT NULL, - ipVersion integer NOT NULL DEFAULT(4) -); - -CREATE UNIQUE INDEX IpAssignmentPool_networkId_ipRangeStart ON IpAssignmentPool (networkId,ipRangeStart); - -CREATE TABLE Member ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE, - authorized integer NOT NULL DEFAULT(0), - activeBridge integer NOT NULL DEFAULT(0), - memberRevision integer NOT NULL DEFAULT(0), - flags integer NOT NULL DEFAULT(0), - lastRequestTime integer NOT NULL DEFAULT(0), - lastPowDifficulty integer NOT NULL DEFAULT(0), - lastPowTime integer NOT NULL DEFAULT(0), - recentHistory blob, - PRIMARY KEY (networkId, nodeId) -); - -CREATE INDEX Member_networkId_nodeId ON Member(networkId,nodeId); -CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge); -CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision); -CREATE INDEX Member_networkId_lastRequestTime ON Member(networkId, lastRequestTime); - -CREATE TABLE Route ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - target blob(16) NOT NULL, - via blob(16), - targetNetmaskBits integer NOT NULL, - ipVersion integer NOT NULL, - flags integer NOT NULL, - metric integer NOT NULL -); - -CREATE INDEX Route_networkId ON Route (networkId); - -CREATE TABLE Rule ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - capId integer, - ruleNo integer NOT NULL, - ruleType integer NOT NULL DEFAULT(0), - "addr" blob(16), - "int1" integer, - "int2" integer, - "int3" integer, - "int4" integer -); - -CREATE INDEX Rule_networkId_capId ON Rule (networkId,capId); - -CREATE TABLE MemberTC ( - networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, - nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE, - tagId integer, - tagValue integer, - capId integer, - capMaxCustodyChainLength integer NOT NULL DEFAULT(1) -); - -CREATE INDEX MemberTC_networkId_nodeId ON MemberTC (networkId,nodeId); diff --git a/attic/old-linux-installer/buildinstaller.sh b/attic/old-linux-installer/buildinstaller.sh deleted file mode 100755 index 21f2f73..0000000 --- a/attic/old-linux-installer/buildinstaller.sh +++ /dev/null @@ -1,134 +0,0 @@ -#!/bin/bash - -# This script builds the installer for *nix systems. Windows must do everything -# completely differently, as usual. - -export PATH=/bin:/usr/bin:/sbin:/usr/sbin - -if [ ! -f zerotier-one ]; then - echo "Could not find 'zerotier-one' binary, please build before running this script." - exit 2 -fi - -machine=`uname -m` -system=`uname -s` - -vmajor=`cat version.h | grep -F ZEROTIER_ONE_VERSION_MAJOR | cut -d ' ' -f 3` -vminor=`cat version.h | grep -F ZEROTIER_ONE_VERSION_MINOR | cut -d ' ' -f 3` -revision=`cat version.h | grep -F ZEROTIER_ONE_VERSION_REVISION | cut -d ' ' -f 3` - -if [ -z "$vmajor" -o -z "$vminor" -o -z "$revision" ]; then - echo "Unable to extract version info from version.h, aborting installer build." - exit 2 -fi - -rm -rf build-installer -mkdir build-installer - -case "$system" in - - Linux) - # Canonicalize $machine for some architectures... we use x86 - # and x64 for Intel stuff. ARM and others should be fine if - # we ever ship officially for those. - debian_arch=$machine - case "$machine" in - i386|i486|i586|i686) - machine="x86" - debian_arch="i386" - ;; - x86_64|amd64|x64) - machine="x64" - debian_arch="amd64" - ;; - armv6l|arm|armhf|arm7l|armv7l) - machine="armv6l" - debian_arch="armhf" - ;; - esac - - echo "Assembling Linux installer for $machine and version $vmajor.$vminor.$revision" - - mkdir -p 'build-installer/var/lib/zerotier-one/ui' - cp -fp 'ext/installfiles/linux/uninstall.sh' 'build-installer/var/lib/zerotier-one' - cp -fp 'zerotier-one' 'build-installer/var/lib/zerotier-one' - for f in ui/*.html ui/*.js ui/*.css ui/*.jsx ; do - cp -fp "$f" 'build-installer/var/lib/zerotier-one/ui' - done - mkdir -p 'build-installer/tmp' - cp -fp 'ext/installfiles/linux/init.d/zerotier-one' 'build-installer/tmp/init.d_zerotier-one' - cp -fp 'ext/installfiles/linux/systemd/zerotier-one.service' 'build-installer/tmp/systemd_zerotier-one.service' - - targ="ZeroTierOneInstaller-linux-${machine}-${vmajor}_${vminor}_${revision}" - # Use gzip in Linux since some minimal Linux systems do not have bunzip2 - rm -f build-installer-tmp.tar.gz - cd build-installer - tar -cf - * | gzip -9 >../build-installer-tmp.tar.gz - cd .. - rm -f $targ - cat ext/installfiles/linux/install.tmpl.sh build-installer-tmp.tar.gz >$targ - chmod 0755 $targ - rm -f build-installer-tmp.tar.gz - ls -l $targ - - if [ -f /usr/bin/dpkg-deb -a "$UID" -eq 0 ]; then - echo - echo Found dpkg-deb and you are root, trying to build Debian package. - - rm -rf build-installer-deb - - debbase="build-installer-deb/zerotier-one_${vmajor}.${vminor}.${revision}_$debian_arch" - debfolder="${debbase}/DEBIAN" - mkdir -p $debfolder - - cat 'ext/installfiles/linux/DEBIAN/control.in' | sed "s/__VERSION__/${vmajor}.${vminor}.${revision}/" | sed "s/__ARCH__/${debian_arch}/" >$debfolder/control - cat $debfolder/control - cp -f 'ext/installfiles/linux/DEBIAN/conffiles' "${debfolder}/conffiles" - - mkdir -p "${debbase}/var/lib/zerotier-one/updates.d" - cp -f $targ "${debbase}/var/lib/zerotier-one/updates.d" - - rm -f "${debfolder}/postinst" "${debfolder}/prerm" - - echo '#!/bin/bash' >${debfolder}/postinst - echo "/var/lib/zerotier-one/updates.d/${targ} >>/dev/null 2>&1" >>${debfolder}/postinst - echo "/bin/rm -f /var/lib/zerotier-one/updates.d/*" >>${debfolder}/postinst - chmod a+x ${debfolder}/postinst - - echo '#!/bin/bash' >${debfolder}/prerm - echo 'export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin' >>${debfolder}/prerm - echo 'if [ "$1" != "upgrade" ]; then' >>${debfolder}/prerm - echo ' /var/lib/zerotier-one/uninstall.sh >>/dev/null 2>&1' >>${debfolder}/prerm - echo 'fi' >>${debfolder}/prerm - chmod a+x ${debfolder}/prerm - - dpkg-deb --build $debbase - - mv -f build-installer-deb/*.deb . - rm -rf build-installer-deb - fi - - if [ -f /usr/bin/rpmbuild ]; then - echo - echo Found rpmbuild, trying to build RedHat/CentOS package. - - rm -f /tmp/zerotier-one.spec - curr_dir=`pwd` - cat ext/installfiles/linux/RPM/zerotier-one.spec.in | sed "s/__VERSION__/${vmajor}.${vminor}.${revision}/g" | sed "s/__INSTALLER__/${targ}/g" >/tmp/zerotier-one.spec - - rpmbuild -ba /tmp/zerotier-one.spec - - rm -f /tmp/zerotier-one.spec - fi - - ;; - - *) - echo "Unsupported platform: $system" - exit 2 - -esac - -rm -rf build-installer - -exit 0 diff --git a/attic/old-linux-installer/install.tmpl.sh b/attic/old-linux-installer/install.tmpl.sh deleted file mode 100644 index 2d18d24..0000000 --- a/attic/old-linux-installer/install.tmpl.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin -shopt -s expand_aliases - -dryRun=0 - -echo "*** ZeroTier One install/update ***" -echo - -if [ "$UID" -ne 0 ]; then - echo "Not running as root so doing dry run (no modifications to system)..." - dryRun=1 -fi - -if [ $dryRun -gt 0 ]; then - alias ln="echo '>> ln'" - alias rm="echo '>> rm'" - alias mv="echo '>> mv'" - alias cp="echo '>> cp'" - alias chown="echo '>> chown'" - alias chgrp="echo '>> chgrp'" - alias chmod="echo '>> chmod'" - alias chkconfig="echo '>> chkconfig'" - alias zerotier-cli="echo '>> zerotier-cli'" - alias service="echo '>> service'" - alias systemctl="echo '>> systemctl'" -fi - -scriptPath="`dirname "$0"`/`basename "$0"`" -if [ ! -r "$scriptPath" ]; then - scriptPath="$0" - if [ ! -r "$scriptPath" ]; then - echo "Installer cannot determine its own path; $scriptPath is not readable." - exit 2 - fi -fi - -# Check for systemd vs. old school SysV init -SYSTEMDUNITDIR= -if [ -e /bin/systemctl -o -e /usr/bin/systemctl -o -e /usr/local/bin/systemctl -o -e /sbin/systemctl -o -e /usr/sbin/systemctl ]; then - # Second check: test if systemd appears to actually be running. Apparently Ubuntu - # thought it was a good idea to ship with systemd installed but not used. Issue #133 - if [ -d /var/run/systemd/system -o -d /run/systemd/system ]; then - if [ -e /usr/bin/pkg-config ]; then - SYSTEMDUNITDIR=`/usr/bin/pkg-config systemd --variable=systemdsystemunitdir` - fi - if [ -z "$SYSTEMDUNITDIR" -o ! -d "$SYSTEMDUNITDIR" ]; then - if [ -d /usr/lib/systemd/system ]; then - SYSTEMDUNITDIR=/usr/lib/systemd/system - fi - if [ -d /etc/systemd/system ]; then - SYSTEMDUNITDIR=/etc/systemd/system - fi - fi - fi -fi - -# Find the end of this script, which is where we have appended binary data. -endMarkerIndex=`grep -a -b -E '^################' "$scriptPath" | head -c 16 | cut -d : -f 1` -if [ "$endMarkerIndex" -le 100 ]; then - echo 'Internal error: unable to find end of script / start of binary data marker.' - exit 2 -fi -blobStart=`expr $endMarkerIndex + 17` -if [ "$blobStart" -le "$endMarkerIndex" ]; then - echo 'Internal error: unable to find end of script / start of binary data marker.' - exit 2 -fi - -echo -n 'Getting version of existing install... ' -origVersion=NONE -if [ -x /var/lib/zerotier-one/zerotier-one ]; then - origVersion=`/var/lib/zerotier-one/zerotier-one -v` -fi -echo $origVersion - -echo 'Extracting files...' -if [ $dryRun -gt 0 ]; then - echo ">> tail -c +$blobStart \"$scriptPath\" | gunzip -c | tar -xvop -C / -f -" - tail -c +$blobStart "$scriptPath" | gunzip -c | tar -t -f - | sed 's/^/>> /' -else - tail -c +$blobStart "$scriptPath" | gunzip -c | tar -xvop --no-overwrite-dir -C / -f - -fi - -if [ $dryRun -eq 0 -a ! -x "/var/lib/zerotier-one/zerotier-one" ]; then - echo 'Archive extraction failed, cannot find zerotier-one binary in "/var/lib/zerotier-one".' - exit 2 -fi - -echo -n 'Getting version of new install... ' -newVersion=`/var/lib/zerotier-one/zerotier-one -v` -echo $newVersion - -echo 'Creating symlinks...' - -rm -f /usr/bin/zerotier-cli /usr/bin/zerotier-idtool -ln -sf /var/lib/zerotier-one/zerotier-one /usr/bin/zerotier-cli -ln -sf /var/lib/zerotier-one/zerotier-one /usr/bin/zerotier-idtool - -echo 'Installing zerotier-one service...' - -if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" ]; then - # SYSTEMD - - # If this was updated or upgraded from an init.d based system, clean up the old - # init.d stuff before installing directly via systemd. - if [ -f /etc/init.d/zerotier-one ]; then - if [ -e /sbin/chkconfig -o -e /usr/sbin/chkconfig -o -e /bin/chkconfig -o -e /usr/bin/chkconfig ]; then - chkconfig zerotier-one off - fi - rm -f /etc/init.d/zerotier-one - fi - - cp -f /tmp/systemd_zerotier-one.service "$SYSTEMDUNITDIR/zerotier-one.service" - chown 0 "$SYSTEMDUNITDIR/zerotier-one.service" - chgrp 0 "$SYSTEMDUNITDIR/zerotier-one.service" - chmod 0644 "$SYSTEMDUNITDIR/zerotier-one.service" - rm -f /tmp/systemd_zerotier-one.service /tmp/init.d_zerotier-one - - systemctl enable zerotier-one.service - - echo - echo 'Done! Installed and service configured to start at system boot.' - echo - echo "To start now or restart the service if it's already running:" - echo ' sudo systemctl restart zerotier-one.service' -else - # SYSV INIT -- also covers upstart which supports SysVinit backward compatibility - - cp -f /tmp/init.d_zerotier-one /etc/init.d/zerotier-one - chmod 0755 /etc/init.d/zerotier-one - rm -f /tmp/systemd_zerotier-one.service /tmp/init.d_zerotier-one - - if [ -f /sbin/chkconfig -o -f /usr/sbin/chkconfig -o -f /usr/bin/chkconfig -o -f /bin/chkconfig ]; then - chkconfig zerotier-one on - else - # Yes Virginia, some systems lack chkconfig. - if [ -d /etc/rc0.d ]; then - rm -f /etc/rc0.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc0.d/K89zerotier-one - fi - if [ -d /etc/rc1.d ]; then - rm -f /etc/rc1.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc1.d/K89zerotier-one - fi - if [ -d /etc/rc2.d ]; then - rm -f /etc/rc2.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc2.d/S11zerotier-one - fi - if [ -d /etc/rc3.d ]; then - rm -f /etc/rc3.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc3.d/S11zerotier-one - fi - if [ -d /etc/rc4.d ]; then - rm -f /etc/rc4.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc4.d/S11zerotier-one - fi - if [ -d /etc/rc5.d ]; then - rm -f /etc/rc5.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc5.d/S11zerotier-one - fi - if [ -d /etc/rc6.d ]; then - rm -f /etc/rc6.d/???zerotier-one - ln -sf /etc/init.d/zerotier-one /etc/rc6.d/K89zerotier-one - fi - fi - - echo - echo 'Done! Installed and service configured to start at system boot.' - echo - echo "To start now or restart the service if it's already running:" - echo ' sudo service zerotier-one restart' -fi - -exit 0 - -# Do not remove the last line or add a carriage return to it! The installer -# looks for an unterminated line beginning with 16 #'s in itself to find -# the binary blob data, which is appended after it. - -################ \ No newline at end of file diff --git a/attic/old-linux-installer/uninstall.sh b/attic/old-linux-installer/uninstall.sh deleted file mode 100755 index d9495a1..0000000 --- a/attic/old-linux-installer/uninstall.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin - -if [ "$UID" -ne 0 ]; then - echo "Must be run as root; try: sudo $0" - exit 1 -fi - -# Detect systemd vs. regular init -SYSTEMDUNITDIR= -if [ -e /bin/systemctl -o -e /usr/bin/systemctl -o -e /usr/local/bin/systemctl -o -e /sbin/systemctl -o -e /usr/sbin/systemctl ]; then - if [ -e /usr/bin/pkg-config ]; then - SYSTEMDUNITDIR=`/usr/bin/pkg-config systemd --variable=systemdsystemunitdir` - fi - if [ -z "$SYSTEMDUNITDIR" -o ! -d "$SYSTEMDUNITDIR" ]; then - if [ -d /usr/lib/systemd/system ]; then - SYSTEMDUNITDIR=/usr/lib/systemd/system - fi - if [ -d /etc/systemd/system ]; then - SYSTEMDUNITDIR=/etc/systemd/system - fi - fi -fi - -echo "Killing any running zerotier-one service..." -if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" ]; then - systemctl stop zerotier-one.service - systemctl disable zerotier-one.service -else - if [ -f /sbin/service -o -f /usr/sbin/service -o -f /bin/service -o -f /usr/bin/service ]; then - service zerotier-one stop - fi -fi - -sleep 1 -if [ -f /var/lib/zerotier-one/zerotier-one.pid ]; then - kill -TERM `cat /var/lib/zerotier-one/zerotier-one.pid` - sleep 1 -fi -if [ -f /var/lib/zerotier-one/zerotier-one.pid ]; then - kill -KILL `cat /var/lib/zerotier-one/zerotier-one.pid` -fi - -if [ -f /etc/init.d/zerotier-one ]; then - echo "Removing SysV init items..." - if [ -f /sbin/chkconfig -o -f /usr/sbin/chkconfig -o -f /bin/chkconfig -o -f /usr/bin/chkconfig ]; then - chkconfig zerotier-one off - fi - rm -f /etc/init.d/zerotier-one - find /etc/rc*.d -type f -name '???zerotier-one' -print0 | xargs -0 rm -f -fi - -if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" -a -f "$SYSTEMDUNITDIR/zerotier-one.service" ]; then - echo "Removing systemd service..." - rm -f "$SYSTEMDUNITDIR/zerotier-one.service" -fi - -echo "Erasing binary and support files..." -if [ -d /var/lib/zerotier-one ]; then - cd /var/lib/zerotier-one - rm -rf zerotier-one *.persist identity.public *.log *.pid *.sh updates.d networks.d iddb.d root-topology ui -fi - -echo "Erasing anything installed into system bin directories..." -rm -f /usr/local/bin/zerotier-cli /usr/bin/zerotier-cli /usr/local/bin/zerotier-idtool /usr/bin/zerotier-idtool - -echo "Done." -echo -echo "Your ZeroTier One identity is still preserved in /var/lib/zerotier-one" -echo "as identity.secret and can be manually deleted if you wish. Save it if" -echo "you wish to re-use the address of this node, as it cannot be regenerated." - -echo - -exit 0 diff --git a/attic/world/build.sh b/attic/world/build.sh index b783702..aeb3b87 100755 --- a/attic/world/build.sh +++ b/attic/world/build.sh @@ -1 +1,3 @@ -c++ -I.. -o mkworld ../node/C25519.cpp ../node/Salsa20.cpp ../node/SHA512.cpp ../node/Identity.cpp ../node/Utils.cpp ../node/InetAddress.cpp ../osdep/OSUtils.cpp mkworld.cpp +#!/bin/bash + +c++ -std=c++11 -I../.. -I.. -O -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm diff --git a/attic/world/earth-2016-01-13.bin b/attic/world/earth-2016-01-13.bin deleted file mode 100644 index 5dea4d2..0000000 Binary files a/attic/world/earth-2016-01-13.bin and /dev/null differ diff --git a/attic/world/mkworld.cpp b/attic/world/mkworld.cpp index e0f477b..b8cb027 100644 --- a/attic/world/mkworld.cpp +++ b/attic/world/mkworld.cpp @@ -61,11 +61,11 @@ int main(int argc,char **argv) current = previous; OSUtils::writeFile("previous.c25519",previous); OSUtils::writeFile("current.c25519",current); - fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)"ZT_EOL_S); + fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S); } if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { - fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid"ZT_EOL_S); + fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S); return 1; } C25519::Pair previousKP; @@ -81,7 +81,12 @@ int main(int argc,char **argv) std::vector roots; const uint64_t id = ZT_WORLD_ID_EARTH; - const uint64_t ts = 1452708876314ULL; // January 13th, 2016 + const uint64_t ts = 1562631342273ULL; // July 8th, 2019 + + roots.push_back(World::Root()); + roots.back().identity = Identity("3a46f1bf30:0:76e66fab33e28549a62ee2064d1843273c2c300ba45c3f20bef02dbad225723bb59a9bb4b13535730961aeecf5a163ace477cceb0727025b99ac14a5166a09a3"); + roots.back().stableEndpoints.push_back(InetAddress("185.180.13.82/9993")); + roots.back().stableEndpoints.push_back(InetAddress("2a02:6ea0:c815::/9993")); // Alice roots.push_back(World::Root()); @@ -92,8 +97,8 @@ int main(int argc,char **argv) roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York - roots.back().stableEndpoints.push_back(InetAddress("169.57.143.104/9993")); // Sao Paolo - roots.back().stableEndpoints.push_back(InetAddress("2607:f0d0:1d01:57::2/9993")); // Sao Paolo + roots.back().stableEndpoints.push_back(InetAddress("131.255.6.16/9993")); // Buenos Aires + roots.back().stableEndpoints.push_back(InetAddress("2803:eb80:0:e::2/9993")); // Buenos Aires roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore @@ -118,7 +123,7 @@ int main(int argc,char **argv) // END WORLD DEFINITION // ========================================================================= - fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); + fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP); @@ -127,15 +132,15 @@ int main(int argc,char **argv) World testw; testw.deserialize(outtmp,0); if (testw != nw) { - fprintf(stderr,"FATAL: serialization test failed!"ZT_EOL_S); + fprintf(stderr,"FATAL: serialization test failed!" ZT_EOL_S); return 1; } OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size())); - fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data."ZT_EOL_S,outtmp.size()); + fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S,outtmp.size()); fprintf(stdout,ZT_EOL_S); - fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); + fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S,outtmp.size()); fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); for(unsigned int i=0;i. + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "DB.hpp" +#include "EmbeddedNetworkController.hpp" + +#include +#include +#include + +using json = nlohmann::json; + +namespace ZeroTier { + +void DB::initNetwork(nlohmann::json &network) +{ + if (!network.count("private")) network["private"] = true; + if (!network.count("creationTime")) network["creationTime"] = OSUtils::now(); + if (!network.count("name")) network["name"] = ""; + if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32; + if (!network.count("enableBroadcast")) network["enableBroadcast"] = true; + if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}}; + if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}}; + if (!network.count("authTokens")) network["authTokens"] = {{}}; + if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array(); + if (!network.count("tags")) network["tags"] = nlohmann::json::array(); + if (!network.count("routes")) network["routes"] = nlohmann::json::array(); + if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array(); + if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU; + if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json(); + if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0; + if (!network.count("rulesSource")) network["rulesSource"] = ""; + if (!network.count("rules")) { + // If unspecified, rules are set to allow anything and behave like a flat L2 segment + network["rules"] = {{ + { "not",false }, + { "or", false }, + { "type","ACTION_ACCEPT" } + }}; + } + network["objtype"] = "network"; +} + +void DB::initMember(nlohmann::json &member) +{ + if (!member.count("authorized")) member["authorized"] = false; + if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array(); + if (!member.count("activeBridge")) member["activeBridge"] = false; + if (!member.count("tags")) member["tags"] = nlohmann::json::array(); + if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array(); + if (!member.count("creationTime")) member["creationTime"] = OSUtils::now(); + if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false; + if (!member.count("revision")) member["revision"] = 0ULL; + if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL; + if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL; + if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json(); + if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json(); + if (!member.count("vMajor")) member["vMajor"] = -1; + if (!member.count("vMinor")) member["vMinor"] = -1; + if (!member.count("vRev")) member["vRev"] = -1; + if (!member.count("vProto")) member["vProto"] = -1; + if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json(); + if (!member.count("removeTraceLevel")) member["remoteTraceLevel"] = 0; + member["objtype"] = "member"; +} + +void DB::cleanNetwork(nlohmann::json &network) +{ + network.erase("clock"); + network.erase("authorizedMemberCount"); + network.erase("activeMemberCount"); + network.erase("totalMemberCount"); + network.erase("lastModified"); +} + +void DB::cleanMember(nlohmann::json &member) +{ + member.erase("clock"); + member.erase("physicalAddr"); + member.erase("recentLog"); + member.erase("lastModified"); + member.erase("lastRequestMetaData"); +} + +DB::DB() {} +DB::~DB() {} + +bool DB::get(const uint64_t networkId,nlohmann::json &network) +{ + waitForReady(); + std::shared_ptr<_Network> nw; + { + std::lock_guard l(_networks_l); + auto nwi = _networks.find(networkId); + if (nwi == _networks.end()) + return false; + nw = nwi->second; + } + { + std::lock_guard l2(nw->lock); + network = nw->config; + } + return true; +} + +bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member) +{ + waitForReady(); + std::shared_ptr<_Network> nw; + { + std::lock_guard l(_networks_l); + auto nwi = _networks.find(networkId); + if (nwi == _networks.end()) + return false; + nw = nwi->second; + } + { + std::lock_guard l2(nw->lock); + network = nw->config; + auto m = nw->members.find(memberId); + if (m == nw->members.end()) + return false; + member = m->second; + } + return true; +} + +bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info) +{ + waitForReady(); + std::shared_ptr<_Network> nw; + { + std::lock_guard l(_networks_l); + auto nwi = _networks.find(networkId); + if (nwi == _networks.end()) + return false; + nw = nwi->second; + } + { + std::lock_guard l2(nw->lock); + network = nw->config; + _fillSummaryInfo(nw,info); + auto m = nw->members.find(memberId); + if (m == nw->members.end()) + return false; + member = m->second; + } + return true; +} + +bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector &members) +{ + waitForReady(); + std::shared_ptr<_Network> nw; + { + std::lock_guard l(_networks_l); + auto nwi = _networks.find(networkId); + if (nwi == _networks.end()) + return false; + nw = nwi->second; + } + { + std::lock_guard l2(nw->lock); + network = nw->config; + for(auto m=nw->members.begin();m!=nw->members.end();++m) + members.push_back(m->second); + } + return true; +} + +void DB::networks(std::set &networks) +{ + waitForReady(); + std::lock_guard l(_networks_l); + for(auto n=_networks.begin();n!=_networks.end();++n) + networks.insert(n->first); +} + +void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) +{ + uint64_t memberId = 0; + uint64_t networkId = 0; + bool isAuth = false; + bool wasAuth = false; + std::shared_ptr<_Network> nw; + + if (old.is_object()) { + memberId = OSUtils::jsonIntHex(old["id"],0ULL); + networkId = OSUtils::jsonIntHex(old["nwid"],0ULL); + if ((memberId)&&(networkId)) { + { + std::lock_guard l(_networks_l); + auto nw2 = _networks.find(networkId); + if (nw2 != _networks.end()) + nw = nw2->second; + } + if (nw) { + std::lock_guard l(nw->lock); + if (OSUtils::jsonBool(old["activeBridge"],false)) + nw->activeBridgeMembers.erase(memberId); + wasAuth = OSUtils::jsonBool(old["authorized"],false); + if (wasAuth) + nw->authorizedMembers.erase(memberId); + json &ips = old["ipAssignments"]; + if (ips.is_array()) { + for(unsigned long i=0;iallocatedIps.erase(ipa); + } + } + } + } + } + } + + if (memberConfig.is_object()) { + if (!nw) { + memberId = OSUtils::jsonIntHex(memberConfig["id"],0ULL); + networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL); + if ((!memberId)||(!networkId)) + return; + std::lock_guard l(_networks_l); + std::shared_ptr<_Network> &nw2 = _networks[networkId]; + if (!nw2) + nw2.reset(new _Network); + nw = nw2; + } + + { + std::lock_guard l(nw->lock); + + nw->members[memberId] = memberConfig; + + if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) + nw->activeBridgeMembers.insert(memberId); + isAuth = OSUtils::jsonBool(memberConfig["authorized"],false); + if (isAuth) + nw->authorizedMembers.insert(memberId); + json &ips = memberConfig["ipAssignments"]; + if (ips.is_array()) { + for(unsigned long i=0;iallocatedIps.insert(ipa); + } + } + } + + if (!isAuth) { + const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"],0ULL); + if (ldt > nw->mostRecentDeauthTime) + nw->mostRecentDeauthTime = ldt; + } + } + + if (notifyListeners) { + std::lock_guard ll(_changeListeners_l); + for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { + (*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig); + } + } + } else if (memberId) { + if (nw) { + std::lock_guard l(nw->lock); + nw->members.erase(memberId); + } + if (networkId) { + std::lock_guard l(_networks_l); + auto er = _networkByMember.equal_range(memberId); + for(auto i=er.first;i!=er.second;++i) { + if (i->second == networkId) { + _networkByMember.erase(i); + break; + } + } + } + } + + if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) { + std::lock_guard ll(_changeListeners_l); + for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { + (*i)->onNetworkMemberDeauthorize(this,networkId,memberId); + } + } +} + +void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) +{ + if (networkConfig.is_object()) { + const std::string ids = networkConfig["id"]; + const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); + if (networkId) { + std::shared_ptr<_Network> nw; + { + std::lock_guard l(_networks_l); + std::shared_ptr<_Network> &nw2 = _networks[networkId]; + if (!nw2) + nw2.reset(new _Network); + nw = nw2; + } + { + std::lock_guard l2(nw->lock); + nw->config = networkConfig; + } + if (notifyListeners) { + std::lock_guard ll(_changeListeners_l); + for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { + (*i)->onNetworkUpdate(this,networkId,networkConfig); + } + } + } + } else if (old.is_object()) { + const std::string ids = old["id"]; + const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); + if (networkId) { + std::lock_guard l(_networks_l); + _networks.erase(networkId); + } + } +} + +void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info) +{ + for(auto ab=nw->activeBridgeMembers.begin();ab!=nw->activeBridgeMembers.end();++ab) + info.activeBridges.push_back(Address(*ab)); + std::sort(info.activeBridges.begin(),info.activeBridges.end()); + for(auto ip=nw->allocatedIps.begin();ip!=nw->allocatedIps.end();++ip) + info.allocatedIps.push_back(*ip); + std::sort(info.allocatedIps.begin(),info.allocatedIps.end()); + info.authorizedMemberCount = (unsigned long)nw->authorizedMembers.size(); + info.totalMemberCount = (unsigned long)nw->members.size(); + info.mostRecentDeauthTime = nw->mostRecentDeauthTime; +} + +} // namespace ZeroTier diff --git a/controller/DB.hpp b/controller/DB.hpp new file mode 100644 index 0000000..6c51842 --- /dev/null +++ b/controller/DB.hpp @@ -0,0 +1,177 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_CONTROLLER_DB_HPP +#define ZT_CONTROLLER_DB_HPP + +//#define ZT_CONTROLLER_USE_LIBPQ + +#include "../node/Constants.hpp" +#include "../node/Identity.hpp" +#include "../node/InetAddress.hpp" +#include "../osdep/OSUtils.hpp" +#include "../osdep/BlockingQueue.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ext/json/json.hpp" + +namespace ZeroTier +{ + +/** + * Base class with common infrastructure for all controller DB implementations + */ +class DB +{ +public: + class ChangeListener + { + public: + ChangeListener() {} + virtual ~ChangeListener() {} + virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) {} + virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) {} + virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) {} + }; + + struct NetworkSummaryInfo + { + NetworkSummaryInfo() : authorizedMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {} + std::vector
activeBridges; + std::vector allocatedIps; + unsigned long authorizedMemberCount; + unsigned long totalMemberCount; + int64_t mostRecentDeauthTime; + }; + + static void initNetwork(nlohmann::json &network); + static void initMember(nlohmann::json &member); + static void cleanNetwork(nlohmann::json &network); + static void cleanMember(nlohmann::json &member); + + DB(); + virtual ~DB(); + + virtual bool waitForReady() = 0; + virtual bool isReady() = 0; + + inline bool hasNetwork(const uint64_t networkId) const + { + std::lock_guard l(_networks_l); + return (_networks.find(networkId) != _networks.end()); + } + + bool get(const uint64_t networkId,nlohmann::json &network); + bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member); + bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info); + bool get(const uint64_t networkId,nlohmann::json &network,std::vector &members); + + void networks(std::set &networks); + + template + inline void each(F f) + { + nlohmann::json nullJson; + std::lock_guard lck(_networks_l); + for(auto nw=_networks.begin();nw!=_networks.end();++nw) { + f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID + for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) { + f(nw->first,nw->second->config,m->first,m->second); + } + } + } + + virtual bool save(nlohmann::json &record,bool notifyListeners) = 0; + + virtual void eraseNetwork(const uint64_t networkId) = 0; + virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0; + + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0; + + inline void addListener(DB::ChangeListener *const listener) + { + std::lock_guard l(_changeListeners_l); + _changeListeners.push_back(listener); + } + +protected: + static inline bool _compareRecords(const nlohmann::json &a,const nlohmann::json &b) + { + if (a.is_object() == b.is_object()) { + if (a.is_object()) { + if (a.size() != b.size()) + return false; + auto amap = a.get(); + auto bmap = b.get(); + for(auto ai=amap.begin();ai!=amap.end();++ai) { + if (ai->first != "revision") { // ignore revision, compare only non-revision-counter fields + auto bi = bmap.find(ai->first); + if ((bi == bmap.end())||(bi->second != ai->second)) + return false; + } + } + return true; + } + return (a == b); + } + return false; + } + + struct _Network + { + _Network() : mostRecentDeauthTime(0) {} + nlohmann::json config; + std::unordered_map members; + std::unordered_set activeBridgeMembers; + std::unordered_set authorizedMembers; + std::unordered_set allocatedIps; + int64_t mostRecentDeauthTime; + std::mutex lock; + }; + + void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners); + void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners); + void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info); + + std::vector _changeListeners; + std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks; + std::unordered_multimap< uint64_t,uint64_t > _networkByMember; + mutable std::mutex _changeListeners_l; + mutable std::mutex _networks_l; +}; + +} // namespace ZeroTier + +#endif diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp new file mode 100644 index 0000000..c3cd784 --- /dev/null +++ b/controller/DBMirrorSet.cpp @@ -0,0 +1,244 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "DBMirrorSet.hpp" + +namespace ZeroTier { + +DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) : + _listener(listener), + _running(true) +{ + _syncCheckerThread = std::thread([this]() { + for(;;) { + for(int i=0;i<120;++i) { // 1 minute delay between checks + if (!_running) + return; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + std::vector< std::shared_ptr > dbs; + { + std::lock_guard l(_dbs_l); + if (_dbs.size() <= 1) + continue; // no need to do this if there's only one DB, so skip the iteration + dbs = _dbs; + } + + for(auto db=dbs.begin();db!=dbs.end();++db) { + (*db)->each([this,&dbs,&db](uint64_t networkId,const nlohmann::json &network,uint64_t memberId,const nlohmann::json &member) { + try { + if (network.is_object()) { + if (memberId == 0) { + for(auto db2=dbs.begin();db2!=dbs.end();++db2) { + if (db->get() != db2->get()) { + nlohmann::json nw2; + if ((!(*db2)->get(networkId,nw2))||((nw2.is_object())&&(OSUtils::jsonInt(nw2["revision"],0) < OSUtils::jsonInt(network["revision"],0)))) { + nw2 = network; + (*db2)->save(nw2,false); + } + } + } + } else if (member.is_object()) { + for(auto db2=dbs.begin();db2!=dbs.end();++db2) { + if (db->get() != db2->get()) { + nlohmann::json nw2,m2; + if ((!(*db2)->get(networkId,nw2,memberId,m2))||((m2.is_object())&&(OSUtils::jsonInt(m2["revision"],0) < OSUtils::jsonInt(member["revision"],0)))) { + m2 = member; + (*db2)->save(m2,false); + } + } + } + } + } + } catch ( ... ) {} // skip entries that generate JSON errors + }); + } + } + }); +} + +DBMirrorSet::~DBMirrorSet() +{ + _running = false; + _syncCheckerThread.join(); +} + +bool DBMirrorSet::hasNetwork(const uint64_t networkId) const +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if ((*d)->hasNetwork(networkId)) + return true; + } + return false; +} + +bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if ((*d)->get(networkId,network)) { + return true; + } + } + return false; +} + +bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if ((*d)->get(networkId,network,memberId,member)) + return true; + } + return false; +} + +bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if ((*d)->get(networkId,network,memberId,member,info)) + return true; + } + return false; +} + +bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector &members) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if ((*d)->get(networkId,network,members)) + return true; + } + return false; +} + +void DBMirrorSet::networks(std::set &networks) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->networks(networks); + } +} + +bool DBMirrorSet::waitForReady() +{ + bool r = false; + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + r |= (*d)->waitForReady(); + } + return r; +} + +bool DBMirrorSet::isReady() +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if (!(*d)->isReady()) + return false; + } + return true; +} + +bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners) +{ + std::vector< std::shared_ptr > dbs; + { + std::lock_guard l(_dbs_l); + dbs = _dbs; + } + if (notifyListeners) { + for(auto d=dbs.begin();d!=dbs.end();++d) { + if ((*d)->save(record,true)) + return true; + } + return false; + } else { + bool modified = false; + for(auto d=dbs.begin();d!=dbs.end();++d) { + modified |= (*d)->save(record,false); + } + return modified; + } +} + +void DBMirrorSet::eraseNetwork(const uint64_t networkId) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->eraseNetwork(networkId); + } +} + +void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->eraseMember(networkId,memberId); + } +} + +void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + (*d)->nodeIsOnline(networkId,memberId,physicalAddress); + } +} + +void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) +{ + nlohmann::json record(network); + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if (d->get() != db) { + (*d)->save(record,false); + } + } + _listener->onNetworkUpdate(this,networkId,network); +} + +void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) +{ + nlohmann::json record(member); + std::lock_guard l(_dbs_l); + for(auto d=_dbs.begin();d!=_dbs.end();++d) { + if (d->get() != db) { + (*d)->save(record,false); + } + } + _listener->onNetworkMemberUpdate(this,networkId,memberId,member); +} + +void DBMirrorSet::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) +{ + _listener->onNetworkMemberDeauthorize(this,networkId,memberId); +} + +} // namespace ZeroTier diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp new file mode 100644 index 0000000..23cb25e --- /dev/null +++ b/controller/DBMirrorSet.hpp @@ -0,0 +1,84 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_DBMIRRORSET_HPP +#define ZT_DBMIRRORSET_HPP + +#include "DB.hpp" + +#include +#include +#include +#include +#include + +namespace ZeroTier { + +class DBMirrorSet : public DB::ChangeListener +{ +public: + DBMirrorSet(DB::ChangeListener *listener); + virtual ~DBMirrorSet(); + + bool hasNetwork(const uint64_t networkId) const; + + bool get(const uint64_t networkId,nlohmann::json &network); + bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member); + bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info); + bool get(const uint64_t networkId,nlohmann::json &network,std::vector &members); + + void networks(std::set &networks); + + bool waitForReady(); + bool isReady(); + bool save(nlohmann::json &record,bool notifyListeners); + void eraseNetwork(const uint64_t networkId); + void eraseMember(const uint64_t networkId,const uint64_t memberId); + void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + + // These are called by various DB instances when changes occur. + virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network); + virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member); + virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId); + + inline void addDB(const std::shared_ptr &db) + { + db->addListener(this); + std::lock_guard l(_dbs_l); + _dbs.push_back(db); + } + +private: + DB::ChangeListener *const _listener; + std::atomic_bool _running; + std::thread _syncCheckerThread; + std::vector< std::shared_ptr< DB > > _dbs; + mutable std::mutex _dbs_l; +}; + +} // namespace ZeroTier + +#endif diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 597bc9c..08d31be 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,7 +13,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include @@ -30,39 +38,41 @@ #include #include #include -#include #include +#include +#include #include "../include/ZeroTierOne.h" -#include "../node/Constants.hpp" +#include "../version.h" #include "EmbeddedNetworkController.hpp" +#include "LFDB.hpp" +#include "FileDB.hpp" +#ifdef ZT_CONTROLLER_USE_LIBPQ +#include "PostgreSQL.hpp" +#endif #include "../node/Node.hpp" -#include "../node/Utils.hpp" #include "../node/CertificateOfMembership.hpp" #include "../node/NetworkConfig.hpp" #include "../node/Dictionary.hpp" -#include "../node/InetAddress.hpp" #include "../node/MAC.hpp" -#include "../node/Address.hpp" using json = nlohmann::json; // API version reported via JSON control plane -#define ZT_NETCONF_CONTROLLER_API_VERSION 3 - -// Number of requests to remember in member history -#define ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH 2 +#define ZT_NETCONF_CONTROLLER_API_VERSION 4 // Min duration between requests for an address/nwid combo to prevent floods #define ZT_NETCONF_MIN_REQUEST_PERIOD 1000 -// Nodes are considered active if they've queried in less than this long -#define ZT_NETCONF_NODE_ACTIVE_THRESHOLD (ZT_NETWORK_AUTOCONF_DELAY * 2) +// Global maximum size of arrays in JSON objects +#define ZT_CONTROLLER_MAX_ARRAY_SIZE 16384 namespace ZeroTier { +namespace { + static json _renderRule(ZT_VirtualNetworkRule &rule) { char tmp[128]; @@ -78,19 +88,19 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) break; case ZT_NETWORK_RULE_ACTION_TEE: r["type"] = "ACTION_TEE"; - r["address"] = Address(rule.v.fwd.address).toString(); + r["address"] = Address(rule.v.fwd.address).toString(tmp); r["flags"] = (unsigned int)rule.v.fwd.flags; r["length"] = (unsigned int)rule.v.fwd.length; break; case ZT_NETWORK_RULE_ACTION_WATCH: r["type"] = "ACTION_WATCH"; - r["address"] = Address(rule.v.fwd.address).toString(); + r["address"] = Address(rule.v.fwd.address).toString(tmp); r["flags"] = (unsigned int)rule.v.fwd.flags; r["length"] = (unsigned int)rule.v.fwd.length; break; case ZT_NETWORK_RULE_ACTION_REDIRECT: r["type"] = "ACTION_REDIRECT"; - r["address"] = Address(rule.v.fwd.address).toString(); + r["address"] = Address(rule.v.fwd.address).toString(tmp); r["flags"] = (unsigned int)rule.v.fwd.flags; break; case ZT_NETWORK_RULE_ACTION_BREAK: @@ -104,11 +114,11 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) switch(rt) { case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: r["type"] = "MATCH_SOURCE_ZEROTIER_ADDRESS"; - r["zt"] = Address(rule.v.zt).toString(); + r["zt"] = Address(rule.v.zt).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: r["type"] = "MATCH_DEST_ZEROTIER_ADDRESS"; - r["zt"] = Address(rule.v.zt).toString(); + r["zt"] = Address(rule.v.zt).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_VLAN_ID: r["type"] = "MATCH_VLAN_ID"; @@ -124,29 +134,29 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: r["type"] = "MATCH_MAC_SOURCE"; - Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); r["mac"] = tmp; break; case ZT_NETWORK_RULE_MATCH_MAC_DEST: r["type"] = "MATCH_MAC_DEST"; - Utils::snprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)rule.v.mac[0],(unsigned int)rule.v.mac[1],(unsigned int)rule.v.mac[2],(unsigned int)rule.v.mac[3],(unsigned int)rule.v.mac[4],(unsigned int)rule.v.mac[5]); r["mac"] = tmp; break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: r["type"] = "MATCH_IPV4_SOURCE"; - r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(); + r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_IPV4_DEST: r["type"] = "MATCH_IPV4_DEST"; - r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(); + r["ip"] = InetAddress(&(rule.v.ipv4.ip),4,(unsigned int)rule.v.ipv4.mask).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: r["type"] = "MATCH_IPV6_SOURCE"; - r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(); + r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_IPV6_DEST: r["type"] = "MATCH_IPV6_DEST"; - r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(); + r["ip"] = InetAddress(rule.v.ipv6.ip,16,(unsigned int)rule.v.ipv6.mask).toString(tmp); break; case ZT_NETWORK_RULE_MATCH_IP_TOS: r["type"] = "MATCH_IP_TOS"; @@ -181,7 +191,7 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: r["type"] = "MATCH_CHARACTERISTICS"; - Utils::snprintf(tmp,sizeof(tmp),"%.16llx",rule.v.characteristics); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",rule.v.characteristics); r["mask"] = tmp; break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: @@ -228,6 +238,16 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) r["id"] = rule.v.tag.id; r["value"] = rule.v.tag.value; break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: + r["type"] = "INTEGER_RANGE"; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",rule.v.intRange.start); + r["start"] = tmp; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",rule.v.intRange.start + (uint64_t)rule.v.intRange.end); + r["end"] = tmp; + r["idx"] = rule.v.intRange.idx; + r["little"] = ((rule.v.intRange.format & 0x80) != 0); + r["bits"] = (rule.v.intRange.format & 63) + 1; + break; default: break; } @@ -314,28 +334,28 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) return true; } else if (t == "MATCH_IPV4_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_SOURCE; - InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0")); + InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0").c_str()); rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; return true; } else if (t == "MATCH_IPV4_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV4_DEST; - InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0")); + InetAddress ip(OSUtils::jsonString(r["ip"],"0.0.0.0").c_str()); rule.v.ipv4.ip = reinterpret_cast(&ip)->sin_addr.s_addr; rule.v.ipv4.mask = Utils::ntoh(reinterpret_cast(&ip)->sin_port) & 0xff; if (rule.v.ipv4.mask > 32) rule.v.ipv4.mask = 32; return true; } else if (t == "MATCH_IPV6_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_SOURCE; - InetAddress ip(OSUtils::jsonString(r["ip"],"::0")); + InetAddress ip(OSUtils::jsonString(r["ip"],"::0").c_str()); memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; return true; } else if (t == "MATCH_IPV6_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_IPV6_DEST; - InetAddress ip(OSUtils::jsonString(r["ip"],"::0")); + InetAddress ip(OSUtils::jsonString(r["ip"],"::0").c_str()); memcpy(rule.v.ipv6.ip,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); rule.v.ipv6.mask = Utils::ntoh(reinterpret_cast(&ip)->sin6_port) & 0xff; if (rule.v.ipv6.mask > 128) rule.v.ipv6.mask = 128; @@ -418,7 +438,26 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) } else if (t == "MATCH_TAG_RECEIVER") { rule.t |= ZT_NETWORK_RULE_MATCH_TAG_RECEIVER; tag = true; + } else if (t == "INTEGER_RANGE") { + json &s = r["start"]; + if (s.is_string()) { + std::string tmp = s; + rule.v.intRange.start = Utils::hexStrToU64(tmp.c_str()); + } else { + rule.v.intRange.start = OSUtils::jsonInt(s,0ULL); + } + json &e = r["end"]; + if (e.is_string()) { + std::string tmp = e; + rule.v.intRange.end = (uint32_t)(Utils::hexStrToU64(tmp.c_str()) - rule.v.intRange.start); + } else { + rule.v.intRange.end = (uint32_t)(OSUtils::jsonInt(e,0ULL) - rule.v.intRange.start); + } + rule.v.intRange.idx = (uint16_t)OSUtils::jsonInt(r["idx"],0ULL); + rule.v.intRange.format = (OSUtils::jsonBool(r["little"],false)) ? 0x80 : 0x00; + rule.v.intRange.format |= (uint8_t)((OSUtils::jsonInt(r["bits"],1ULL) - 1) & 63); } + if (tag) { rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL); rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL); @@ -428,29 +467,76 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) return false; } -EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath) : +} // anonymous namespace + +EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc) : _startTime(OSUtils::now()), - _threadsStarted(false), - _db(dbPath), - _node(node) + _listenPort(listenPort), + _node(node), + _ztPath(ztPath), + _path(dbPath), + _sender((NetworkController::Sender *)0), + _db(this), + _mqc(mqc) { } EmbeddedNetworkController::~EmbeddedNetworkController() { - Mutex::Lock _l(_threads_m); - if (_threadsStarted) { - for(int i=0;i<(ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT*2);++i) - _queue.post((_RQEntry *)0); - for(int i=0;i l(_threads_l); + _queue.stop(); + for(auto t=_threads.begin();t!=_threads.end();++t) + t->join(); } void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender) { - this->_sender = sender; - this->_signingId = signingId; + char tmp[64]; + _signingId = signingId; + _sender = sender; + _signingIdAddressString = signingId.address().toString(tmp); + +#ifdef ZT_CONTROLLER_USE_LIBPQ + if ((_path.length() > 9)&&(_path.substr(0,9) == "postgres:")) { + _db.addDB(std::shared_ptr(new PostgreSQL(_signingId,_path.substr(9).c_str(), _listenPort, _mqc))); + } else { +#endif + _db.addDB(std::shared_ptr(new FileDB(_path.c_str()))); +#ifdef ZT_CONTROLLER_USE_LIBPQ + } +#endif + + std::string lfJSON; + OSUtils::readFile((_ztPath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON); + if (lfJSON.length() > 0) { + nlohmann::json lfConfig(OSUtils::jsonParse(lfJSON)); + nlohmann::json &settings = lfConfig["settings"]; + if (settings.is_object()) { + nlohmann::json &controllerDb = settings["controllerDb"]; + if (controllerDb.is_object()) { + std::string type = controllerDb["type"]; + if (type == "lf") { + std::string lfOwner = controllerDb["owner"]; + std::string lfHost = controllerDb["host"]; + int lfPort = controllerDb["port"]; + bool storeOnlineState = controllerDb["storeOnlineState"]; + if ((lfOwner.length())&&(lfHost.length())&&(lfPort > 0)&&(lfPort < 65536)) { + std::size_t pubHdrLoc = lfOwner.find("Public: "); + if ((pubHdrLoc > 0)&&((pubHdrLoc + 8) < lfOwner.length())) { + std::string lfOwnerPublic = lfOwner.substr(pubHdrLoc + 8); + std::size_t pubHdrEnd = lfOwnerPublic.find_first_of("\n\r\t "); + if (pubHdrEnd != std::string::npos) { + lfOwnerPublic = lfOwnerPublic.substr(0,pubHdrEnd); + _db.addDB(std::shared_ptr(new LFDB(_signingId,_path.c_str(),lfOwner.c_str(),lfOwnerPublic.c_str(),lfHost.c_str(),lfPort,storeOnlineState))); + } + } + } + } + } + } + } + + _db.waitForReady(); } void EmbeddedNetworkController::request( @@ -462,22 +548,14 @@ void EmbeddedNetworkController::request( { if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; - - { - Mutex::Lock _l(_threads_m); - if (!_threadsStarted) { - for(int i=0;inwid = nwid; qe->requestPacketId = requestPacketId; qe->fromAddr = fromAddr; qe->identity = identity; qe->metaData = metaData; + qe->type = _RQEntry::RQENTRY_TYPE_REQUEST; _queue.post(qe); } @@ -493,15 +571,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( if ((path.size() >= 2)&&(path[1].length() == 16)) { const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); - json network; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - } - if (!network.size()) + if (!_db.get(nwid,network)) return 404; if (path.size() >= 3) { @@ -509,85 +580,76 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( if (path[2] == "member") { if (path.size() >= 4) { + // Get member + const uint64_t address = Utils::hexStrToU64(path[3].c_str()); - json member; - { - Mutex::Lock _l(_db_m); - member = _db.get("network",nwids,"member",Address(address).toString()); - } - if (!member.size()) + if (!_db.get(nwid,network,address,member)) return 404; - - _addMemberNonPersistedFields(member,OSUtils::now()); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; - return 200; } else { - - Mutex::Lock _l(_db_m); + // List members and their revisions responseBody = "{"; - _db.filter((std::string("network/") + nwids + "/member/"),[&responseBody](const std::string &n,const json &member) { - if ((member.is_object())&&(member.size() > 0)) { - responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); - responseBody.append(OSUtils::jsonString(member["id"],"0")); - responseBody.append("\":"); - responseBody.append(OSUtils::jsonString(member["revision"],"0")); + std::vector members; + if (_db.get(nwid,network,members)) { + responseBody.reserve((members.size() + 2) * 32); + std::string mid; + for(auto member=members.begin();member!=members.end();++member) { + mid = (*member)["id"]; + char tmp[128]; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s\"%s\":%llu",(responseBody.length() > 1) ? "," : "",mid.c_str(),(unsigned long long)OSUtils::jsonInt((*member)["revision"],0)); + responseBody.append(tmp); } - return true; // never delete - }); + } responseBody.push_back('}'); responseContentType = "application/json"; - return 200; } + return 200; } // else 404 } else { + // Get network - const uint64_t now = OSUtils::now(); - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - _addNetworkNonPersistedFields(network,now,nmi); responseBody = OSUtils::jsonDump(network); responseContentType = "application/json"; return 200; } } else if (path.size() == 1) { + // List networks - std::set networkIds; - { - Mutex::Lock _l(_db_m); - _db.filter("network/",[&networkIds](const std::string &n,const json &obj) { - if (n.length() == (16 + 8)) - networkIds.insert(n.substr(8)); - return true; // do not delete - }); - } - - responseBody.push_back('['); - for(std::set::iterator i(networkIds.begin());i!=networkIds.end();++i) { - responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); - responseBody.append(*i); - responseBody.append("\""); + std::set networkIds; + _db.networks(networkIds); + char tmp[64]; + responseBody = "["; + responseBody.reserve((networkIds.size() + 1) * 24); + for(std::set::const_iterator i(networkIds.begin());i!=networkIds.end();++i) { + if (responseBody.length() > 1) + responseBody.push_back(','); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"\"%.16llx\"",(unsigned long long)*i); + responseBody.append(tmp); } responseBody.push_back(']'); responseContentType = "application/json"; + return 200; } // else 404 } else { + // Controller status char tmp[4096]; - Utils::snprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now()); + const bool dbOk = _db.isReady(); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),dbOk ? "true" : "false"); responseBody = tmp; responseContentType = "application/json"; - return 200; + return dbOk ? 200 : 503; } @@ -618,58 +680,48 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( responseContentType = "application/json"; return 400; } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (path[0] == "network") { if ((path.size() >= 2)&&(path[1].length() == 16)) { uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); + OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); if (path.size() >= 3) { if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { uint64_t address = Utils::hexStrToU64(path[3].c_str()); char addrs[24]; - Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address); + OSUtils::ztsnprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address); - json member; - { - Mutex::Lock _l(_db_m); - member = _db.get("network",nwids,"member",Address(address).toString()); - } - json origMember(member); // for detecting changes - _initMember(member); + json member,network; + _db.get(nwid,network,address,member); + DB::initMember(member); try { if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false); if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"],false); + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + member["remoteTraceTarget"] = rtt; + } else { + member["remoteTraceTarget"] = json(); + } + } + if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); + if (b.count("authorized")) { const bool newAuth = OSUtils::jsonBool(b["authorized"],false); if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { member["authorized"] = newAuth; member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now; - - json ah; - ah["a"] = newAuth; - ah["by"] = "api"; - ah["ts"] = now; - ah["ct"] = json(); - ah["c"] = json(); - member["authHistory"].push_back(ah); - - // Member is being de-authorized, so spray Revocation objects to all online members - if (!newAuth) { - _clearNetworkMemberInfoCache(nwid); - Revocation rev((uint32_t)_node->prng(),nwid,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(address),Revocation::CREDENTIAL_TYPE_COM); - rev.sign(_signingId); - Mutex::Lock _l(_lastRequestTime_m); - for(std::map< std::pair,uint64_t >::iterator i(_lastRequestTime.begin());i!=_lastRequestTime.end();++i) { - if ((now - i->second) < ZT_NETWORK_AUTOCONF_DELAY) - _node->ncSendRevocation(Address(i->first.first),rev); - } + if (newAuth) { + member["lastAuthorizedCredentialType"] = "api"; + member["lastAuthorizedCredential"] = json(); } } } @@ -680,9 +732,12 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json mipa(json::array()); for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; } } member["ipAssignments"] = mipa; @@ -704,6 +759,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( ta.push_back(t->first); ta.push_back(t->second); mtagsa.push_back(ta); + if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; } member["tags"] = mtagsa; } @@ -715,6 +772,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json mcaps = json::array(); for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; } std::sort(mcaps.begin(),mcaps.end()); mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end()); @@ -731,115 +790,56 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( member["address"] = addrs; // legacy member["nwid"] = nwids; - if (member != origMember) { - member["lastModified"] = now; - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - { - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",Address(address).toString(),member); - } - _pushMemberUpdate(now,nwid,member); - } - - // Add non-persisted fields - member["clock"] = now; - + DB::cleanMember(member); + _db.save(member,true); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; - return 200; - } else if ((path.size() == 3)&&(path[2] == "test")) { - - Mutex::Lock _l(_tests_m); - - _tests.push_back(ZT_CircuitTest()); - ZT_CircuitTest *const test = &(_tests.back()); - memset(test,0,sizeof(ZT_CircuitTest)); - - Utils::getSecureRandom(&(test->testId),sizeof(test->testId)); - test->credentialNetworkId = nwid; - test->ptr = (void *)this; - json hops = b["hops"]; - if (hops.is_array()) { - for(unsigned long i=0;ihops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - } - ++test->hopCount; - } else if (hops2.is_string()) { - std::string s = hops2; - test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL; - ++test->hopCount; - } - } - } - test->reportAtEveryHop = (OSUtils::jsonBool(b["reportAtEveryHop"],true) ? 1 : 0); - - if (!test->hopCount) { - _tests.pop_back(); - responseBody = "{ \"message\": \"a test must contain at least one hop\" }"; - responseContentType = "application/json"; - return 400; - } - - test->timestamp = OSUtils::now(); - - if (_node) { - _node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback)); - } else { - _tests.pop_back(); - return 500; - } - - char json[512]; - Utils::snprintf(json,sizeof(json),"{\"testId\":\"%.16llx\",\"timestamp\":%llu}",test->testId,test->timestamp); - responseBody = json; - responseContentType = "application/json"; return 200; - } // else 404 } else { // POST to network ID - json network; - { - Mutex::Lock _l(_db_m); - - // Magic ID ending with ______ picks a random unused network ID - if (path[1].substr(10) == "______") { - nwid = 0; - uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL; - uint64_t nwidPostfix = 0; - for(unsigned long k=0;k<100000;++k) { // sanity limit on trials - Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); - uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); - if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)tryNwid); - if (_db.get("network",nwids).size() <= 0) { - nwid = tryNwid; - break; - } + // Magic ID ending with ______ picks a random unused network ID + if (path[1].substr(10) == "______") { + nwid = 0; + uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL; + uint64_t nwidPostfix = 0; + for(unsigned long k=0;k<100000;++k) { // sanity limit on trials + Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); + uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); + if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; + if (!_db.hasNetwork(tryNwid)) { + nwid = tryNwid; + break; } - if (!nwid) - return 503; } - - network = _db.get("network",nwids); + if (!nwid) + return 503; } - json origNetwork(network); // for detecting changes - _initNetwork(network); + OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); + + json network; + _db.get(nwid,network); + DB::initNetwork(network); try { if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); - if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false); if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); + if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); + + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + network["remoteTraceTarget"] = rtt; + } else { + network["remoteTraceTarget"] = json(); + } + } + if (b.count("remoteTraceLevel")) network["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); if (b.count("v4AssignMode")) { json nv4m; @@ -893,16 +893,19 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &target = rt["target"]; json &via = rt["via"]; if (target.is_string()) { - InetAddress t(target.get()); + InetAddress t(target.get().c_str()); InetAddress v; - if (via.is_string()) v.fromString(via.get()); + if (via.is_string()) v.fromString(via.get().c_str()); if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) { json tmp; - tmp["target"] = t.toString(); + char tmp2[64]; + tmp["target"] = t.toString(tmp2); if (v.ss_family == t.ss_family) - tmp["via"] = v.toIpString(); + tmp["via"] = v.toIpString(tmp2); else tmp["via"] = json(); nrts.push_back(tmp); + if (nrts.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; } } } @@ -918,13 +921,16 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; } } } @@ -940,8 +946,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &rule = rules[i]; if (rule.is_object()) { ZT_VirtualNetworkRule ztr; - if (_parseRule(rule,ztr)) + if (_parseRule(rule,ztr)) { nrules.push_back(_renderRule(ztr)); + if (nrules.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } } } network["rules"] = nrules; @@ -950,22 +959,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("authTokens")) { json &authTokens = b["authTokens"]; - if (authTokens.is_array()) { - json nat = json::array(); - for(unsigned long i=0;i 0) { - json t = json::object(); - t["token"] = tstr; - t["expires"] = OSUtils::jsonInt(token["expires"],0ULL); - t["maxUsesPerMember"] = OSUtils::jsonInt(token["maxUsesPerMember"],0ULL); - nat.push_back(t); - } - } + if (authTokens.is_object()) { + json nat; + for(json::iterator t(authTokens.begin());t!=authTokens.end();++t) { + if ((t.value().is_number())&&(t.value() >= 0)) + nat[t.key()] = t.value(); } network["authTokens"] = nat; + } else { + network["authTokens"] = {{}}; } } @@ -988,8 +990,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &rule = rules[i]; if (rule.is_object()) { ZT_VirtualNetworkRule ztr; - if (_parseRule(rule,ztr)) + if (_parseRule(rule,ztr)) { nrules.push_back(_renderRule(ztr)); + if (nrules.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } } } } @@ -1000,8 +1005,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } json ncapsa = json::array(); - for(std::map< uint64_t,json >::iterator c(ncaps.begin());c!=ncaps.end();++c) + for(std::map< uint64_t,json >::iterator c(ncaps.begin());c!=ncaps.end();++c) { ncapsa.push_back(c->second); + if (ncapsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } network["capabilities"] = ncapsa; } } @@ -1025,8 +1033,11 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } json ntagsa = json::array(); - for(std::map< uint64_t,json >::iterator t(ntags.begin());t!=ntags.end();++t) + for(std::map< uint64_t,json >::iterator t(ntags.begin());t!=ntags.end();++t) { ntagsa.push_back(t->second); + if (ntagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } network["tags"] = ntagsa; } } @@ -1040,25 +1051,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["id"] = nwids; network["nwid"] = nwids; // legacy - if (network != origNetwork) { - json &revj = network["revision"]; - network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - network["lastModified"] = now; - { - Mutex::Lock _l(_db_m); - _db.put("network",nwids,network); - } - - // Send an update to all members of the network - _db.filter((std::string("network/") + nwids + "/member/"),[this,&now,&nwid](const std::string &n,const json &obj) { - _pushMemberUpdate(now,nwid,obj); - return true; // do not delete - }); - } - - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - _addNetworkNonPersistedFields(network,now,nmi); + DB::cleanNetwork(network); + _db.save(network,true); responseBody = OSUtils::jsonDump(network); responseContentType = "application/json"; @@ -1067,18 +1061,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } // else 404 - } else if (path[0] == "ping") { - - json testRec; - const uint64_t now = OSUtils::now(); - testRec["clock"] = now; - testRec["uptime"] = (now - _startTime); - testRec["content"] = b; - responseBody = OSUtils::jsonDump(testRec); - _db.writeRaw("pong",responseBody); - responseContentType = "application/json"; - return 200; - } return 404; @@ -1098,25 +1080,18 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( if (path[0] == "network") { if ((path.size() >= 2)&&(path[1].length() == 16)) { const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); - - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - json network; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - } - if (!network.size()) - return 404; - if (path.size() >= 3) { if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { const uint64_t address = Utils::hexStrToU64(path[3].c_str()); - Mutex::Lock _l(_db_m); + json network,member; + _db.get(nwid,network,address,member); + _db.eraseMember(nwid, address); - json member = _db.get("network",nwids,"member",Address(address).toString()); - _db.erase("network",nwids,"member",Address(address).toString()); + { + std::lock_guard l(_memberStatus_l); + _memberStatus.erase(_MemberStatusKey(nwid,address)); + } if (!member.size()) return 404; @@ -1125,17 +1100,21 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( return 200; } } else { - Mutex::Lock _l(_db_m); + json network; + _db.get(nwid,network); + _db.eraseNetwork(nwid); - std::string pfx("network/"); - pfx.append(nwids); - _db.filter(pfx,[](const std::string &n,const json &obj) { - return false; // delete - }); - - Mutex::Lock _l2(_nmiCache_m); - _nmiCache.erase(nwid); + { + std::lock_guard l(_memberStatus_l); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();) { + if (i->first.networkId == nwid) + _memberStatus.erase(i++); + else ++i; + } + } + if (!network.size()) + return 404; responseBody = OSUtils::jsonDump(network); responseContentType = "application/json"; return 200; @@ -1147,87 +1126,90 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( return 404; } -void EmbeddedNetworkController::threadMain() - throw() +void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) { - uint64_t lastCircuitTestCheck = 0; - for(;;) { - _RQEntry *const qe = _queue.get(); // waits on next request - if (!qe) break; // enqueue a NULL to terminate threads - try { - _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); - } catch ( ... ) {} - delete qe; + static volatile unsigned long idCounter = 0; + char id[128],tmp[128]; + std::string k,v; - uint64_t now = OSUtils::now(); - if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - lastCircuitTestCheck = now; - Mutex::Lock _l(_tests_m); - for(std::list< ZT_CircuitTest >::iterator i(_tests.begin());i!=_tests.end();) { - if ((now - i->timestamp) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { - _node->circuitTestEnd(&(*i)); - _tests.erase(i++); - } else ++i; + try { + // Convert Dictionary into JSON object + json d; + char *saveptr = (char *)0; + for(char *l=Utils::stok(rt.data,"\n",&saveptr);(l);l=Utils::stok((char *)0,"\n",&saveptr)) { + char *eq = strchr(l,'='); + if (eq > l) { + k.assign(l,(unsigned long)(eq - l)); + v.clear(); + ++eq; + while (*eq) { + if (*eq == '\\') { + ++eq; + if (*eq) { + switch(*eq) { + case 'r': v.push_back('\r'); break; + case 'n': v.push_back('\n'); break; + case '0': v.push_back((char)0); break; + case 'e': v.push_back('='); break; + default: v.push_back(*eq); break; + } + ++eq; + } + } else { + v.push_back(*(eq++)); + } + } + if ((k.length() > 0)&&(v.length() > 0)) + d[k] = v; } } + + const int64_t now = OSUtils::now(); + OSUtils::ztsnprintf(id,sizeof(id),"%.10llx-%.16llx-%.10llx-%.4x",_signingId.address().toInt(),now,rt.origin,(unsigned int)(idCounter++ & 0xffff)); + d["id"] = id; + d["objtype"] = "trace"; + d["ts"] = now; + d["nodeId"] = Utils::hex10(rt.origin,tmp); + _db.save(d,true); + } catch ( ... ) { + // drop invalid trace messages if an error occurs } } -void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) +void EmbeddedNetworkController::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) { - char tmp[1024],id[128]; - EmbeddedNetworkController *const self = reinterpret_cast(test->ptr); + // Send an update to all members of the network that are online + const int64_t now = OSUtils::now(); + std::lock_guard l(_memberStatus_l); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) + request(networkId,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData); + } +} - if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check +void EmbeddedNetworkController::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) +{ + // Push update to member if online + try { + std::lock_guard l(_memberStatus_l); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(networkId,memberId)]; + if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData)) + request(networkId,InetAddress(),0,ms.identity,ms.lastRequestMetaData); + } catch ( ... ) {} +} - const uint64_t now = OSUtils::now(); - Utils::snprintf(id,sizeof(id),"network/%.16llx/test/%.16llx-%.16llx-%.10llx-%.10llx",test->credentialNetworkId,test->testId,now,report->upstream,report->current); - Utils::snprintf(tmp,sizeof(tmp), - "{\"id\": \"%s\"," - "\"timestamp\": %llu," - "\"networkId\": \"%.16llx\"," - "\"testId\": \"%.16llx\"," - "\"upstream\": \"%.10llx\"," - "\"current\": \"%.10llx\"," - "\"receivedTimestamp\": %llu," - "\"sourcePacketId\": \"%.16llx\"," - "\"flags\": %llu," - "\"sourcePacketHopCount\": %u," - "\"errorCode\": %u," - "\"vendor\": %d," - "\"protocolVersion\": %u," - "\"majorVersion\": %u," - "\"minorVersion\": %u," - "\"revision\": %u," - "\"platform\": %d," - "\"architecture\": %d," - "\"receivedOnLocalAddress\": \"%s\"," - "\"receivedFromRemoteAddress\": \"%s\"," - "\"receivedFromLinkQuality\": %f}", - id + 30, // last bit only, not leading path - (unsigned long long)test->timestamp, - (unsigned long long)test->credentialNetworkId, - (unsigned long long)test->testId, - (unsigned long long)report->upstream, - (unsigned long long)report->current, - (unsigned long long)now, - (unsigned long long)report->sourcePacketId, - (unsigned long long)report->flags, - report->sourcePacketHopCount, - report->errorCode, - (int)report->vendor, - report->protocolVersion, - report->majorVersion, - report->minorVersion, - report->revision, - (int)report->platform, - (int)report->architecture, - reinterpret_cast(&(report->receivedOnLocalAddress))->toString().c_str(), - reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str(), - ((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX)); - - Mutex::Lock _l(self->_db_m); - self->_db.writeRaw(id,std::string(tmp)); +void EmbeddedNetworkController::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) +{ + const int64_t now = OSUtils::now(); + Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); + rev.sign(_signingId); + { + std::lock_guard l(_memberStatus_l); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == networkId)&&(i->second.online(now))) + _node->ncSendRevocation(Address(i->first.nodeId),rev); + } + } } void EmbeddedNetworkController::_request( @@ -1237,41 +1219,36 @@ void EmbeddedNetworkController::_request( const Identity &identity, const Dictionary &metaData) { + char nwids[24]; + DB::NetworkSummaryInfo ns; + json network,member; + if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (requestPacketId) { - Mutex::Lock _l(_lastRequestTime_m); - uint64_t &lrt = _lastRequestTime[std::pair(identity.address().toInt(),nwid)]; - if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD) + std::lock_guard l(_memberStatus_l); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + if ((now - ms.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD) return; - lrt = now; + ms.lastRequestTime = now; } - char nwids[24]; - Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); - json network; - json member; - { - Mutex::Lock _l(_db_m); - network = _db.get("network",nwids); - member = _db.get("network",nwids,"member",identity.address().toString()); - } + _db.nodeIsOnline(nwid,identity.address().toInt(),fromAddr); - if (!network.size()) { + Utils::hex(nwid,nwids); + _db.get(nwid,network,identity.address().toInt(),member,ns); + if ((!network.is_object())||(network.size() == 0)) { _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND); return; } - - const bool newMember = (member.size() == 0); - - json origMember(member); // for detecting modification later - _initMember(member); + const bool newMember = ((!member.is_object())||(member.size() == 0)); + DB::initMember(member); { - std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); + const std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); if (haveIdStr.length() > 0) { // If we already know this member's identity perform a full compare. This prevents // a "collision" from being able to auth onto our network in place of an already @@ -1287,66 +1264,44 @@ void EmbeddedNetworkController::_request( } } else { // If we do not yet know this member's identity, learn it. - member["identity"] = identity.toString(false); + char idtmp[1024]; + member["identity"] = identity.toString(false,idtmp); } } // These are always the same, but make sure they are set - member["id"] = identity.address().toString(); - member["address"] = member["id"]; - member["nwid"] = nwids; + { + char tmpid[128]; + const std::string addrs(identity.address().toString(tmpid)); + member["id"] = addrs; + member["address"] = addrs; + member["nwid"] = nwids; + } // Determine whether and how member is authorized - const char *authorizedBy = (const char *)0; + bool authorized = false; bool autoAuthorized = false; json autoAuthCredentialType,autoAuthCredential; if (OSUtils::jsonBool(member["authorized"],false)) { - authorizedBy = "memberIsAuthorized"; + authorized = true; } else if (!OSUtils::jsonBool(network["private"],true)) { - authorizedBy = "networkIsPublic"; - json &ahist = member["authHistory"]; - if ((!ahist.is_array())||(ahist.size() == 0)) - autoAuthorized = true; + authorized = true; + autoAuthorized = true; + autoAuthCredentialType = "public"; } else { char presentedAuth[512]; if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)) > 0) { presentedAuth[511] = (char)0; // sanity check - - // Check for bearer token presented by member if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) { const char *const presentedToken = presentedAuth + 6; - - json &authTokens = network["authTokens"]; - if (authTokens.is_array()) { - for(unsigned long i=0;i now))&&(tstr == presentedToken)) { - bool usable = (maxUses == 0); - if (!usable) { - uint64_t useCount = 0; - json &ahist = member["authHistory"]; - if (ahist.is_array()) { - for(unsigned long j=0;j now)) { + authorized = true; + autoAuthorized = true; + autoAuthCredentialType = "token"; + autoAuthCredential = presentedToken; } } } @@ -1354,58 +1309,42 @@ void EmbeddedNetworkController::_request( } // If we auto-authorized, update member record - if ((autoAuthorized)&&(authorizedBy)) { + if ((autoAuthorized)&&(authorized)) { member["authorized"] = true; member["lastAuthorizedTime"] = now; - - json ah; - ah["a"] = true; - ah["by"] = authorizedBy; - ah["ts"] = now; - ah["ct"] = autoAuthCredentialType; - ah["c"] = autoAuthCredential; - member["authHistory"].push_back(ah); - - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); + member["lastAuthorizedCredentialType"] = autoAuthCredentialType; + member["lastAuthorizedCredential"] = autoAuthCredential; } - // Log this request - if (requestPacketId) { // only log if this is a request, not for generated pushes - json rlEntry = json::object(); - rlEntry["ts"] = now; - rlEntry["auth"] = (authorizedBy) ? true : false; - rlEntry["authBy"] = (authorizedBy) ? authorizedBy : ""; - rlEntry["vMajor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); - rlEntry["vMinor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); - rlEntry["vRev"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); - rlEntry["vProto"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); - if (fromAddr) - rlEntry["fromAddr"] = fromAddr.toString(); + if (authorized) { + // Update version info and meta-data if authorized and if this is a genuine request + if (requestPacketId) { + const uint64_t vMajor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); + const uint64_t vMinor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); + const uint64_t vRev = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); + const uint64_t vProto = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); - json recentLog = json::array(); - recentLog.push_back(rlEntry); - json &oldLog = member["recentLog"]; - if (oldLog.is_array()) { - for(unsigned long i=0;i= ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH) - break; + member["vMajor"] = vMajor; + member["vMinor"] = vMinor; + member["vRev"] = vRev; + member["vProto"] = vProto; + + { + std::lock_guard l(_memberStatus_l); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + + ms.vMajor = (int)vMajor; + ms.vMinor = (int)vMinor; + ms.vRev = (int)vRev; + ms.vProto = (int)vProto; + ms.lastRequestMetaData = metaData; + ms.identity = identity; } } - member["recentLog"] = recentLog; - - // Also only do this on real requests - member["lastRequestMetaData"] = metaData.data(); - } - - // If they are not authorized, STOP! - if (!authorizedBy) { - if (origMember != member) { - member["lastModified"] = now; - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",identity.address().toString(),member); - } + } else { + // If they are not authorized, STOP! + DB::cleanMember(member); + _db.save(member,true); _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } @@ -1414,16 +1353,12 @@ void EmbeddedNetworkController::_request( // If we made it this far, they are authorized. // ------------------------------------------------------------------------- - NetworkConfig nc; - _NetworkMemberInfo nmi; - _getNetworkMemberInfo(now,nwid,nmi); - - uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - if (now > nmi.mostRecentDeauthTime) { + int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + if (now > ns.mostRecentDeauthTime) { // If we recently de-authorized a member, shrink credential TTL/max delta to // be below the threshold required to exclude it. Cap this to a min/max to // prevent jitter or absurdly large values. - const uint64_t deauthWindow = now - nmi.mostRecentDeauthTime; + const uint64_t deauthWindow = now - ns.mostRecentDeauthTime; if (deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA) { credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA; } else if (deauthWindow < (ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL)) { @@ -1431,21 +1366,36 @@ void EmbeddedNetworkController::_request( } } - nc.networkId = nwid; - nc.type = OSUtils::jsonBool(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; - nc.timestamp = now; - nc.credentialTimeMaxDelta = credentialtmd; - nc.revision = OSUtils::jsonInt(network["revision"],0ULL); - nc.issuedTo = identity.address(); - if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; - Utils::scopy(nc.name,sizeof(nc.name),OSUtils::jsonString(network["name"],"").c_str()); - nc.multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); + std::unique_ptr nc(new NetworkConfig()); - for(std::set
::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab) { - nc.addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); + nc->networkId = nwid; + nc->type = OSUtils::jsonBool(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; + nc->timestamp = now; + nc->credentialTimeMaxDelta = credentialtmd; + nc->revision = OSUtils::jsonInt(network["revision"],0ULL); + nc->issuedTo = identity.address(); + if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; + Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str()); + nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); + nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); + + std::string rtt(OSUtils::jsonString(member["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); + nc->remoteTraceLevel = (Trace::Level)OSUtils::jsonInt(member["remoteTraceLevel"],0ULL); + } else { + rtt = OSUtils::jsonString(network["remoteTraceTarget"],""); + if (rtt.length() == 10) { + nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); + } else { + nc->remoteTraceTarget.zero(); + } + nc->remoteTraceLevel = (Trace::Level)OSUtils::jsonInt(network["remoteTraceLevel"],0ULL); } + for(std::vector
::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab) + nc->addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); + json &v4AssignMode = network["v4AssignMode"]; json &v6AssignMode = network["v6AssignMode"]; json &ipAssignmentPools = network["ipAssignmentPools"]; @@ -1460,15 +1410,15 @@ void EmbeddedNetworkController::_request( // Old versions with no rules engine support get an allow everything rule. // Since rules are enforced bidirectionally, newer versions *will* still // enforce rules on the inbound side. - nc.ruleCount = 1; - nc.rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; + nc->ruleCount = 1; + nc->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; } else { if (rules.is_array()) { for(unsigned long i=0;i= ZT_MAX_NETWORK_RULES) + if (nc->ruleCount >= ZT_MAX_NETWORK_RULES) break; - if (_parseRule(rules[i],nc.rules[nc.ruleCount])) - ++nc.ruleCount; + if (_parseRule(rules[i],nc->rules[nc->ruleCount])) + ++nc->ruleCount; } } @@ -1512,10 +1462,10 @@ void EmbeddedNetworkController::_request( ++caprc; } } - nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc); - if (nc.capabilities[nc.capabilityCount].sign(_signingId,identity.address())) - ++nc.capabilityCount; - if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES) + nc->capabilities[nc->capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc); + if (nc->capabilities[nc->capabilityCount].sign(_signingId,identity.address())) + ++nc->capabilityCount; + if (nc->capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES) break; } } @@ -1546,31 +1496,31 @@ void EmbeddedNetworkController::_request( } } for(std::map< uint32_t,uint32_t >::const_iterator t(memberTagsById.begin());t!=memberTagsById.end();++t) { - if (nc.tagCount >= ZT_MAX_NETWORK_TAGS) + if (nc->tagCount >= ZT_MAX_NETWORK_TAGS) break; - nc.tags[nc.tagCount] = Tag(nwid,now,identity.address(),t->first,t->second); - if (nc.tags[nc.tagCount].sign(_signingId)) - ++nc.tagCount; + nc->tags[nc->tagCount] = Tag(nwid,now,identity.address(),t->first,t->second); + if (nc->tags[nc->tagCount].sign(_signingId)) + ++nc->tagCount; } } if (routes.is_array()) { for(unsigned long i=0;i= ZT_MAX_NETWORK_ROUTES) + if (nc->routeCount >= ZT_MAX_NETWORK_ROUTES) break; json &route = routes[i]; json &target = route["target"]; json &via = route["via"]; if (target.is_string()) { - const InetAddress t(target.get()); + const InetAddress t(target.get().c_str()); InetAddress v; - if (via.is_string()) v.fromString(via.get()); + if (via.is_string()) v.fromString(via.get().c_str()); if ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) { - ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]); + ZT_VirtualNetworkRoute *r = &(nc->routes[nc->routeCount]); *(reinterpret_cast(&(r->target))) = t; if (v.ss_family == t.ss_family) *(reinterpret_cast(&(r->via))) = v; - ++nc.routeCount; + ++nc->routeCount; } } } @@ -1579,13 +1529,13 @@ void EmbeddedNetworkController::_request( const bool noAutoAssignIps = OSUtils::jsonBool(member["noAutoAssignIps"],false); if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) { - if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt()); - nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt()); + nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; } - if ((OSUtils::jsonBool(v6AssignMode["6plane"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt()); - nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + if ((OSUtils::jsonBool(v6AssignMode["6plane"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt()); + nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; } } @@ -1594,29 +1544,29 @@ void EmbeddedNetworkController::_request( json ipAssignments = member["ipAssignments"]; // we want to make a copy if (ipAssignments.is_array()) { for(unsigned long i=0;i(&(nc.routes[rk].target))->containsAddress(ip)) ) - routedNetmaskBits = reinterpret_cast(&(nc.routes[rk].target))->netmaskBits(); - } - - if (routedNetmaskBits > 0) { - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - ip.setPort(routedNetmaskBits); - nc.staticIps[nc.staticIpCount++] = ip; + int routedNetmaskBits = -1; + for(unsigned int rk=0;rkrouteCount;++rk) { + if (reinterpret_cast(&(nc->routes[rk].target))->containsAddress(ip)) { + const int nb = (int)(reinterpret_cast(&(nc->routes[rk].target))->netmaskBits()); + if (nb > routedNetmaskBits) + routedNetmaskBits = nb; + } + } + + if (routedNetmaskBits >= 0) { + if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { + ip.setPort(routedNetmaskBits); + nc->staticIps[nc->staticIpCount++] = ip; + } + if (ip.ss_family == AF_INET) + haveManagedIpv4AutoAssignment = true; + else if (ip.ss_family == AF_INET6) + haveManagedIpv6AutoAssignment = true; } - if (ip.ss_family == AF_INET) - haveManagedIpv4AutoAssignment = true; - else if (ip.ss_family == AF_INET6) - haveManagedIpv6AutoAssignment = true; } } } else { @@ -1627,8 +1577,8 @@ void EmbeddedNetworkController::_request( for(unsigned long p=0;((p(&(nc.routes[rk].target))->containsAddress(ip6)) ) - routedNetmaskBits = reinterpret_cast(&(nc.routes[rk].target))->netmaskBits(); + for(unsigned int rk=0;rkrouteCount;++rk) { + if ( (!nc->routes[rk].via.ss_family) && (nc->routes[rk].target.ss_family == AF_INET6) && (reinterpret_cast(&(nc->routes[rk].target))->containsAddress(ip6)) ) + routedNetmaskBits = reinterpret_cast(&(nc->routes[rk].target))->netmaskBits(); } // If it's routed, then try to claim and assign it and if successful end loop - if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip6))) { - ipAssignments.push_back(ip6.toIpString()); - member["ipAssignments"] = ipAssignments; - ip6.setPort((unsigned int)routedNetmaskBits); - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) - nc.staticIps[nc.staticIpCount++] = ip6; - haveManagedIpv6AutoAssignment = true; - _clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns - break; + if ( (routedNetmaskBits > 0) && (!std::binary_search(ns.allocatedIps.begin(),ns.allocatedIps.end(),ip6)) ) { + char tmpip[64]; + const std::string ipStr(ip6.toIpString(tmpip)); + if (std::find(ipAssignments.begin(),ipAssignments.end(),ipStr) == ipAssignments.end()) { + ipAssignments.push_back(ipStr); + member["ipAssignments"] = ipAssignments; + ip6.setPort((unsigned int)routedNetmaskBits); + if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) + nc->staticIps[nc->staticIpCount++] = ip6; + haveManagedIpv6AutoAssignment = true; + break; + } } } } @@ -1688,30 +1641,32 @@ void EmbeddedNetworkController::_request( for(unsigned long p=0;((p(&ipRangeStartIA)->sin_addr.s_addr)); uint32_t ipRangeEnd = Utils::ntoh((uint32_t)(reinterpret_cast(&ipRangeEndIA)->sin_addr.s_addr)); + if ((ipRangeEnd < ipRangeStart)||(ipRangeStart == 0)) continue; uint32_t ipRangeLen = ipRangeEnd - ipRangeStart; - + // Start with the LSB of the member's address uint32_t ipTrialCounter = (uint32_t)(identity.address().toInt() & 0xffffffff); for(uint32_t k=ipRangeStart,trialCount=0;((k<=ipRangeEnd)&&(trialCount < 1000));++k,++trialCount) { uint32_t ip = (ipRangeLen > 0) ? (ipRangeStart + (ipTrialCounter % ipRangeLen)) : ipRangeStart; ++ipTrialCounter; - if ((ip & 0x000000ff) == 0x000000ff) + if ((ip & 0x000000ff) == 0x000000ff) { continue; // don't allow addresses that end in .255 + } // Check if this IP is within a local-to-Ethernet routed network int routedNetmaskBits = -1; - for(unsigned int rk=0;rk(&(nc.routes[rk].target))->sin_addr.s_addr)); - int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast(&(nc.routes[rk].target))->sin_port)); + for(unsigned int rk=0;rkrouteCount;++rk) { + if (nc->routes[rk].target.ss_family == AF_INET) { + uint32_t targetIp = Utils::ntoh((uint32_t)(reinterpret_cast(&(nc->routes[rk].target))->sin_addr.s_addr)); + int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast(&(nc->routes[rk].target))->sin_port)); if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) { routedNetmaskBits = targetBits; break; @@ -1721,18 +1676,21 @@ void EmbeddedNetworkController::_request( // If it's routed, then try to claim and assign it and if successful end loop const InetAddress ip4(Utils::hton(ip),0); - if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip4))) { - ipAssignments.push_back(ip4.toIpString()); - member["ipAssignments"] = ipAssignments; - if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - struct sockaddr_in *const v4ip = reinterpret_cast(&(nc.staticIps[nc.staticIpCount++])); - v4ip->sin_family = AF_INET; - v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits); - v4ip->sin_addr.s_addr = Utils::hton(ip); + if ( (routedNetmaskBits > 0) && (!std::binary_search(ns.allocatedIps.begin(),ns.allocatedIps.end(),ip4)) ) { + char tmpip[64]; + const std::string ipStr(ip4.toIpString(tmpip)); + if (std::find(ipAssignments.begin(),ipAssignments.end(),ipStr) == ipAssignments.end()) { + ipAssignments.push_back(ipStr); + member["ipAssignments"] = ipAssignments; + if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) { + struct sockaddr_in *const v4ip = reinterpret_cast(&(nc->staticIps[nc->staticIpCount++])); + v4ip->sin_family = AF_INET; + v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits); + v4ip->sin_addr.s_addr = Utils::hton(ip); + } + haveManagedIpv4AutoAssignment = true; + break; } - haveManagedIpv4AutoAssignment = true; - _clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns - break; } } } @@ -1741,114 +1699,52 @@ void EmbeddedNetworkController::_request( } // Issue a certificate of ownership for all static IPs - if (nc.staticIpCount) { - nc.certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); - for(unsigned int i=0;istaticIpCount) { + nc->certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); + for(unsigned int i=0;istaticIpCount;++i) + nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]); + nc->certificatesOfOwnership[0].sign(_signingId); + nc->certificateOfOwnershipCount = 1; } CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); if (com.sign(_signingId)) { - nc.com = com; + nc->com = com; } else { _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR); return; } - if (member != origMember) { - member["lastModified"] = now; - Mutex::Lock _l(_db_m); - _db.put("network",nwids,"member",identity.address().toString(),member); - } - - _sender->ncSendConfig(nwid,requestPacketId,identity.address(),nc,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); + DB::cleanMember(member); + _db.save(member,true); + _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } -void EmbeddedNetworkController::_getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi) +void EmbeddedNetworkController::_startThreads() { - char pfx[256]; - Utils::snprintf(pfx,sizeof(pfx),"network/%.16llx/member",nwid); - - { - Mutex::Lock _l(_nmiCache_m); - std::map::iterator c(_nmiCache.find(nwid)); - if ((c != _nmiCache.end())&&((now - c->second.nmiTimestamp) < 1000)) { // a short duration cache but limits CPU use on big networks - nmi = c->second; - return; - } - } - - { - Mutex::Lock _l(_db_m); - _db.filter(pfx,[&nmi,&now](const std::string &n,const json &member) { - try { - if (OSUtils::jsonBool(member["authorized"],false)) { - ++nmi.authorizedMemberCount; - - if (member.count("recentLog")) { - const json &mlog = member["recentLog"]; - if ((mlog.is_array())&&(mlog.size() > 0)) { - const json &mlog1 = mlog[0]; - if (mlog1.is_object()) { - if ((now - OSUtils::jsonInt(mlog1["ts"],0ULL)) < ZT_NETCONF_NODE_ACTIVE_THRESHOLD) - ++nmi.activeMemberCount; - } - } + std::lock_guard l(_threads_l); + if (!_threads.empty()) + return; + const long hwc = std::max((long)std::thread::hardware_concurrency(),(long)1); + for(long t=0;tnwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); + delete qe; } - - if (OSUtils::jsonBool(member["activeBridge"],false)) { - nmi.activeBridges.insert(Address(Utils::hexStrToU64(OSUtils::jsonString(member["id"],"0000000000").c_str()))); - } - - if (member.count("ipAssignments")) { - const json &mips = member["ipAssignments"]; - if (mips.is_array()) { - for(unsigned long i=0;i 0)&&(mdstr.length() > 0)) { - const Identity id(idstr); - bool online; - { - Mutex::Lock _l(_lastRequestTime_m); - std::map< std::pair,uint64_t >::iterator lrt(_lastRequestTime.find(std::pair(id.address().toInt(),nwid))); - online = ( (lrt != _lastRequestTime.end()) && ((now - lrt->second) < ZT_NETWORK_AUTOCONF_DELAY) ); - } - if (online) { - Dictionary *metaData = new Dictionary(mdstr.c_str()); - try { - this->request(nwid,InetAddress(),0,id,*metaData); - } catch ( ... ) {} - delete metaData; - } - } - } catch ( ... ) {} } } // namespace ZeroTier diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 0ae2f3b..adc2a2e 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,7 +13,15 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SQLITENETWORKCONTROLLER_HPP @@ -26,11 +34,12 @@ #include #include #include +#include +#include +#include #include "../node/Constants.hpp" - #include "../node/NetworkController.hpp" -#include "../node/Mutex.hpp" #include "../node/Utils.hpp" #include "../node/Address.hpp" #include "../node/InetAddress.hpp" @@ -41,26 +50,23 @@ #include "../ext/json/json.hpp" -#include "JSONDB.hpp" - -// Number of background threads to start -- not actually started until needed -#define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 4 - -// TTL for circuit tests -#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000 +#include "DB.hpp" +#include "DBMirrorSet.hpp" namespace ZeroTier { class Node; -class EmbeddedNetworkController : public NetworkController +struct MQConfig; + +class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener { public: /** * @param node Parent node - * @param dbPath Path to store data + * @param dbPath Database path (file path or database credentials) */ - EmbeddedNetworkController(Node *node,const char *dbPath); + EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc = NULL); virtual ~EmbeddedNetworkController(); virtual void init(const Identity &signingId,Sender *sender); @@ -94,10 +100,16 @@ public: std::string &responseBody, std::string &responseContentType); - void threadMain() - throw(); + void handleRemoteTrace(const ZT_RemoteTrace &rt); + + virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network); + virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member); + virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId); private: + void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); + void _startThreads(); + struct _RQEntry { uint64_t nwid; @@ -105,104 +117,54 @@ private: InetAddress fromAddr; Identity identity; Dictionary metaData; + enum { + RQENTRY_TYPE_REQUEST = 0 + } type; }; - - // Gathers a bunch of statistics about members of a network, IP assignments, etc. that we need in various places - struct _NetworkMemberInfo + struct _MemberStatusKey { - _NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {} - std::set
activeBridges; - std::set allocatedIps; - unsigned long authorizedMemberCount; - unsigned long activeMemberCount; - unsigned long totalMemberCount; - uint64_t mostRecentDeauthTime; - uint64_t nmiTimestamp; // time this NMI structure was computed + _MemberStatusKey() : networkId(0),nodeId(0) {} + _MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {} + uint64_t networkId; + uint64_t nodeId; + inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } }; - - static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); - void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); - void _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi); - inline void _clearNetworkMemberInfoCache(const uint64_t nwid) { Mutex::Lock _l(_nmiCache_m); _nmiCache.erase(nwid); } - void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member); - - // These init objects with default and static/informational fields - inline void _initMember(nlohmann::json &member) + struct _MemberStatus { - if (!member.count("authorized")) member["authorized"] = false; - if (!member.count("authHistory")) member["authHistory"] = nlohmann::json::array(); - if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array(); - if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array(); - if (!member.count("activeBridge")) member["activeBridge"] = false; - if (!member.count("tags")) member["tags"] = nlohmann::json::array(); - if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array(); - if (!member.count("creationTime")) member["creationTime"] = OSUtils::now(); - if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false; - if (!member.count("revision")) member["revision"] = 0ULL; - if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL; - if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL; - member["objtype"] = "member"; - } - inline void _initNetwork(nlohmann::json &network) + _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} + uint64_t lastRequestTime; + int vMajor,vMinor,vRev,vProto; + Dictionary lastRequestMetaData; + Identity identity; + inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } + }; + struct _MemberStatusHash { - if (!network.count("private")) network["private"] = true; - if (!network.count("creationTime")) network["creationTime"] = OSUtils::now(); - if (!network.count("name")) network["name"] = ""; - if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32; - if (!network.count("enableBroadcast")) network["enableBroadcast"] = true; - if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}}; - if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}}; - if (!network.count("authTokens")) network["authTokens"] = nlohmann::json::array(); - if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array(); - if (!network.count("tags")) network["tags"] = nlohmann::json::array(); - if (!network.count("routes")) network["routes"] = nlohmann::json::array(); - if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array(); - if (!network.count("rules")) { - // If unspecified, rules are set to allow anything and behave like a flat L2 segment - network["rules"] = {{ - { "not",false }, - { "or", false }, - { "type","ACTION_ACCEPT" } - }}; + inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const + { + return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId); } - network["objtype"] = "network"; - } - inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const _NetworkMemberInfo &nmi) - { - network["clock"] = now; - network["authorizedMemberCount"] = nmi.authorizedMemberCount; - network["activeMemberCount"] = nmi.activeMemberCount; - network["totalMemberCount"] = nmi.totalMemberCount; - } - inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now) - { - member["clock"] = now; - } - - const uint64_t _startTime; - - BlockingQueue<_RQEntry *> _queue; - Thread _threads[ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT]; - bool _threadsStarted; - Mutex _threads_m; - - std::map _nmiCache; - Mutex _nmiCache_m; - - JSONDB _db; - Mutex _db_m; + }; + const int64_t _startTime; + int _listenPort; Node *const _node; + std::string _ztPath; std::string _path; - - NetworkController::Sender *_sender; Identity _signingId; + std::string _signingIdAddressString; + NetworkController::Sender *_sender; - std::list< ZT_CircuitTest > _tests; - Mutex _tests_m; + DBMirrorSet _db; + BlockingQueue< _RQEntry * > _queue; - std::map< std::pair,uint64_t > _lastRequestTime; // last request time by - Mutex _lastRequestTime_m; + std::vector _threads; + std::mutex _threads_l; + + std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; + std::mutex _memberStatus_l; + + MQConfig *_mqc; }; } // namespace ZeroTier diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp new file mode 100644 index 0000000..cf5847d --- /dev/null +++ b/controller/FileDB.cpp @@ -0,0 +1,175 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "FileDB.hpp" + +namespace ZeroTier +{ + +FileDB::FileDB(const char *path) : + DB(), + _path(path), + _networksPath(_path + ZT_PATH_SEPARATOR_S + "network"), + _tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"), + _running(true) +{ + OSUtils::mkdir(_path.c_str()); + OSUtils::lockDownFile(_path.c_str(),true); + OSUtils::mkdir(_networksPath.c_str()); + OSUtils::mkdir(_tracePath.c_str()); + + std::vector networks(OSUtils::listDirectory(_networksPath.c_str(),false)); + std::string buf; + for(auto n=networks.begin();n!=networks.end();++n) { + buf.clear(); + if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) { + try { + nlohmann::json network(OSUtils::jsonParse(buf)); + const std::string nwids = network["id"]; + if (nwids.length() == 16) { + nlohmann::json nullJson; + _networkChanged(nullJson,network,false); + std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member"); + std::vector members(OSUtils::listDirectory(membersPath.c_str(),false)); + for(auto m=members.begin();m!=members.end();++m) { + buf.clear(); + if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) { + try { + nlohmann::json member(OSUtils::jsonParse(buf)); + const std::string addrs = member["id"]; + if (addrs.length() == 10) { + nlohmann::json nullJson2; + _memberChanged(nullJson2,member,false); + } + } catch ( ... ) {} + } + } + } + } catch ( ... ) {} + } + } +} + +FileDB::~FileDB() +{ + try { + _online_l.lock(); + _running = false; + _online_l.unlock(); + _onlineUpdateThread.join(); + } catch ( ... ) {} +} + +bool FileDB::waitForReady() { return true; } +bool FileDB::isReady() { return true; } + +bool FileDB::save(nlohmann::json &record,bool notifyListeners) +{ + char p1[4096],p2[4096],pb[4096]; + bool modified = false; + try { + const std::string objtype = record["objtype"]; + if (objtype == "network") { + + const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL); + if (nwid) { + nlohmann::json old; + get(nwid,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid); + if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) + fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1); + _networkChanged(old,record,notifyListeners); + modified = true; + } + } + + } else if (objtype == "member") { + + const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL); + const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL); + if ((id)&&(nwid)) { + nlohmann::json network,old; + get(nwid,network,id,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + OSUtils::ztsnprintf(pb,sizeof(pb),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)nwid); + OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.10llx.json",pb,(unsigned long long)id); + if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) { + OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid); + OSUtils::mkdir(p2); + OSUtils::mkdir(pb); + if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) + fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1); + } + _memberChanged(old,record,notifyListeners); + modified = true; + } + } + + } + } catch ( ... ) {} // drop invalid records missing fields + return modified; +} + +void FileDB::eraseNetwork(const uint64_t networkId) +{ + nlohmann::json network,nullJson; + get(networkId,network); + char p[16384]; + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId); + OSUtils::rm(p); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)networkId); + OSUtils::rmDashRf(p); + _networkChanged(network,nullJson,true); + std::lock_guard l(this->_online_l); + this->_online.erase(networkId); +} + +void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId) +{ + nlohmann::json network,member,nullJson; + get(networkId,network); + get(memberId,member); + char p[4096]; + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",_networksPath.c_str(),networkId,memberId); + OSUtils::rm(p); + _memberChanged(member,nullJson,true); + std::lock_guard l(this->_online_l); + this->_online[networkId].erase(memberId); +} + +void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + char mid[32],atmp[64]; + OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId); + physicalAddress.toString(atmp); + std::lock_guard l(this->_online_l); + this->_online[networkId][memberId][OSUtils::now()] = physicalAddress; +} + +} // namespace ZeroTier diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp new file mode 100644 index 0000000..8aa2c18 --- /dev/null +++ b/controller/FileDB.hpp @@ -0,0 +1,60 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_CONTROLLER_FILEDB_HPP +#define ZT_CONTROLLER_FILEDB_HPP + +#include "DB.hpp" + +namespace ZeroTier +{ + +class FileDB : public DB +{ +public: + FileDB(const char *path); + virtual ~FileDB(); + + virtual bool waitForReady(); + virtual bool isReady(); + virtual bool save(nlohmann::json &record,bool notifyListeners); + virtual void eraseNetwork(const uint64_t networkId); + virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + +protected: + std::string _path; + std::string _networksPath; + std::string _tracePath; + std::thread _onlineUpdateThread; + std::map< uint64_t,std::map > > _online; + std::mutex _online_l; + bool _running; +}; + +} // namespace ZeroTier + +#endif diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp deleted file mode 100644 index d3e76fc..0000000 --- a/controller/JSONDB.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "JSONDB.hpp" - -#define ZT_JSONDB_HTTP_TIMEOUT 60000 - -namespace ZeroTier { - -static const nlohmann::json _EMPTY_JSON(nlohmann::json::object()); -static const std::map _ZT_JSONDB_GET_HEADERS; - -JSONDB::JSONDB(const std::string &basePath) : - _basePath(basePath), - _ready(false) -{ - if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) { - // TODO: this doesn't yet support IPv6 since bracketed address notiation isn't supported. - // Typically it's used with 127.0.0.1 anyway. - std::string hn = _basePath.substr(7); - std::size_t hnend = hn.find_first_of('/'); - if (hnend != std::string::npos) - hn = hn.substr(0,hnend); - std::size_t hnsep = hn.find_last_of(':'); - if (hnsep != std::string::npos) - hn[hnsep] = '/'; - _httpAddr.fromString(hn); - if (hnend != std::string::npos) - _basePath = _basePath.substr(7 + hnend); - if (_basePath.length() == 0) - _basePath = "/"; - if (_basePath[0] != '/') - _basePath = std::string("/") + _basePath; - } else { - OSUtils::mkdir(_basePath.c_str()); - OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions - } - _ready = _reload(_basePath,std::string()); -} - -bool JSONDB::writeRaw(const std::string &n,const std::string &obj) -{ - if (!_isValidObjectName(n)) - return false; - if (_httpAddr) { - std::map headers; - std::string body; - std::map reqHeaders; - char tmp[64]; - Utils::snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)obj.length()); - reqHeaders["Content-Length"] = tmp; - reqHeaders["Content-Type"] = "application/json"; - const unsigned int sc = Http::PUT(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),reqHeaders,obj.data(),(unsigned long)obj.length(),headers,body); - return (sc == 200); - } else { - const std::string path(_genPath(n,true)); - if (!path.length()) - return false; - return OSUtils::writeFile(path.c_str(),obj); - } -} - -bool JSONDB::put(const std::string &n,const nlohmann::json &obj) -{ - const bool r = writeRaw(n,OSUtils::jsonDump(obj)); - _db[n].obj = obj; - return r; -} - -const nlohmann::json &JSONDB::get(const std::string &n) -{ - while (!_ready) { - Thread::sleep(250); - _ready = _reload(_basePath,std::string()); - } - - if (!_isValidObjectName(n)) - return _EMPTY_JSON; - std::map::iterator e(_db.find(n)); - if (e != _db.end()) - return e->second.obj; - - std::string buf; - if (_httpAddr) { - std::map headers; - const unsigned int sc = Http::GET(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,buf); - if (sc != 200) - return _EMPTY_JSON; - } else { - const std::string path(_genPath(n,false)); - if (!path.length()) - return _EMPTY_JSON; - if (!OSUtils::readFile(path.c_str(),buf)) - return _EMPTY_JSON; - } - - try { - _E &e2 = _db[n]; - e2.obj = OSUtils::jsonParse(buf); - return e2.obj; - } catch ( ... ) { - _db.erase(n); - return _EMPTY_JSON; - } -} - -void JSONDB::erase(const std::string &n) -{ - if (!_isValidObjectName(n)) - return; - - if (_httpAddr) { - std::string body; - std::map headers; - Http::DEL(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); - } else { - std::string path(_genPath(n,true)); - if (!path.length()) - return; - OSUtils::rm(path.c_str()); - } - - _db.erase(n); -} - -bool JSONDB::_reload(const std::string &p,const std::string &b) -{ - if (_httpAddr) { - std::string body; - std::map headers; - const unsigned int sc = Http::GET(2147483647,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),_basePath.c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); - if (sc == 200) { - try { - nlohmann::json dbImg(OSUtils::jsonParse(body)); - std::string tmp; - if (dbImg.is_object()) { - for(nlohmann::json::iterator i(dbImg.begin());i!=dbImg.end();++i) { - if (i.value().is_object()) { - tmp = i.key(); - _db[tmp].obj = i.value(); - } - } - return true; - } - } catch ( ... ) {} // invalid JSON, so maybe incomplete request - } - return false; - } else { - std::vector dl(OSUtils::listDirectory(p.c_str(),true)); - for(std::vector::const_iterator di(dl.begin());di!=dl.end();++di) { - if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) { - this->get(b + di->substr(0,di->length() - 5)); - } else { - this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR)); - } - } - return true; - } -} - -bool JSONDB::_isValidObjectName(const std::string &n) -{ - if (n.length() == 0) - return false; - const char *p = n.c_str(); - char c; - // For security reasons we should not allow dots, backslashes, or other path characters or potential path characters. - while ((c = *(p++))) { - if (!( ((c >= 'a')&&(c <= 'z')) || ((c >= 'A')&&(c <= 'Z')) || ((c >= '0')&&(c <= '9')) || (c == '/') || (c == '_') || (c == '~') || (c == '-') )) - return false; - } - return true; -} - -std::string JSONDB::_genPath(const std::string &n,bool create) -{ - std::vector pt(OSUtils::split(n.c_str(),"/","","")); - if (pt.size() == 0) - return std::string(); - - char sep; - if (_httpAddr) { - sep = '/'; - create = false; - } else { - sep = ZT_PATH_SEPARATOR; - } - - std::string p(_basePath); - if (create) OSUtils::mkdir(p.c_str()); - for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i. - */ - -#ifndef ZT_JSONDB_HPP -#define ZT_JSONDB_HPP - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/InetAddress.hpp" -#include "../node/Mutex.hpp" -#include "../ext/json/json.hpp" -#include "../osdep/OSUtils.hpp" -#include "../osdep/Http.hpp" -#include "../osdep/Thread.hpp" - -namespace ZeroTier { - -/** - * Hierarchical JSON store that persists into the filesystem or via HTTP - */ -class JSONDB -{ -public: - JSONDB(const std::string &basePath); - - bool writeRaw(const std::string &n,const std::string &obj); - - bool put(const std::string &n,const nlohmann::json &obj); - - inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4),obj); } - inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),obj); } - - const nlohmann::json &get(const std::string &n); - - inline const nlohmann::json &get(const std::string &n1,const std::string &n2) { return this->get((n1 + "/" + n2)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3) { return this->get((n1 + "/" + n2 + "/" + n3)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4)); } - inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5)); } - - void erase(const std::string &n); - - inline void erase(const std::string &n1,const std::string &n2) { this->erase(n1 + "/" + n2); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3) { this->erase(n1 + "/" + n2 + "/" + n3); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4); } - inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5); } - - template - inline void filter(const std::string &prefix,F func) - { - while (!_ready) { - Thread::sleep(250); - _ready = _reload(_basePath,std::string()); - } - - for(std::map::iterator i(_db.lower_bound(prefix));i!=_db.end();) { - if ((i->first.length() >= prefix.length())&&(!memcmp(i->first.data(),prefix.data(),prefix.length()))) { - if (!func(i->first,get(i->first))) { - std::map::iterator i2(i); ++i2; - this->erase(i->first); - i = i2; - } else ++i; - } else break; - } - } - - inline bool operator==(const JSONDB &db) const { return ((_basePath == db._basePath)&&(_db == db._db)); } - inline bool operator!=(const JSONDB &db) const { return (!(*this == db)); } - -private: - bool _reload(const std::string &p,const std::string &b); - bool _isValidObjectName(const std::string &n); - std::string _genPath(const std::string &n,bool create); - - struct _E - { - nlohmann::json obj; - inline bool operator==(const _E &e) const { return (obj == e.obj); } - inline bool operator!=(const _E &e) const { return (obj != e.obj); } - }; - - InetAddress _httpAddr; - std::string _basePath; - std::map _db; - volatile bool _ready; -}; - -} // namespace ZeroTier - -#endif diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp new file mode 100644 index 0000000..b6dc665 --- /dev/null +++ b/controller/LFDB.cpp @@ -0,0 +1,419 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "LFDB.hpp" + +#include +#include +#include +#include + +#include "../osdep/OSUtils.hpp" +#include "../ext/cpp-httplib/httplib.h" + +namespace ZeroTier +{ + +LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState) : + DB(), + _myId(myId), + _lfOwnerPrivate((lfOwnerPrivate) ? lfOwnerPrivate : ""), + _lfOwnerPublic((lfOwnerPublic) ? lfOwnerPublic : ""), + _lfNodeHost((lfNodeHost) ? lfNodeHost : "127.0.0.1"), + _lfNodePort(((lfNodePort > 0)&&(lfNodePort < 65536)) ? lfNodePort : 9980), + _running(true), + _ready(false), + _storeOnlineState(storeOnlineState) +{ + _syncThread = std::thread([this]() { + char controllerAddress[24]; + const uint64_t controllerAddressInt = _myId.address().toInt(); + _myId.address().toString(controllerAddress); + std::string networksSelectorName("com.zerotier.controller.lfdb:"); networksSelectorName.append(controllerAddress); networksSelectorName.append("/network"); + + // LF record masking key is the first 32 bytes of SHA512(controller private key) in hex, + // hiding record values from anything but the controller or someone who has its key. + uint8_t sha512pk[64]; + _myId.sha512PrivateKey(sha512pk); + char maskingKey [128]; + Utils::hex(sha512pk,32,maskingKey); + + httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort,600); + int64_t timeRangeStart = 0; + while (_running.load()) { + { + std::lock_guard sl(_state_l); + for(auto ns=_state.begin();ns!=_state.end();++ns) { + if (ns->second.dirty) { + nlohmann::json network; + if (get(ns->first,network)) { + nlohmann::json newrec,selector0; + selector0["Name"] = networksSelectorName; + selector0["Ordinal"] = ns->first; + newrec["Selectors"].push_back(selector0); + newrec["Value"] = network.dump(); + newrec["OwnerPrivate"] = _lfOwnerPrivate; + newrec["MaskingKey"] = maskingKey; + newrec["PulseIfUnchanged"] = true; + try { + auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json"); + if (resp) { + if (resp->status == 200) { + ns->second.dirty = false; + //printf("SET network %.16llx %s\n",ns->first,resp->body.c_str()); + } else { + fprintf(stderr,"ERROR: LFDB: %d from node (create/update network): %s" ZT_EOL_S,resp->status,resp->body.c_str()); + } + } else { + fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): unknown exception" ZT_EOL_S); + } + } + } + + for(auto ms=ns->second.members.begin();ms!=ns->second.members.end();++ms) { + if ((_storeOnlineState)&&(ms->second.lastOnlineDirty)&&(ms->second.lastOnlineAddress)) { + nlohmann::json newrec,selector0,selector1,selectors,ip; + char tmp[1024],tmp2[128]; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"com.zerotier.controller.lfdb:%s/network/%.16llx/online",controllerAddress,(unsigned long long)ns->first); + ms->second.lastOnlineAddress.toIpString(tmp2); + selector0["Name"] = tmp; + selector0["Ordinal"] = ms->first; + selector1["Name"] = tmp2; + selector1["Ordinal"] = 0; + selectors.push_back(selector0); + selectors.push_back(selector1); + newrec["Selectors"] = selectors; + const uint8_t *const rawip = (const uint8_t *)ms->second.lastOnlineAddress.rawIpData(); + switch(ms->second.lastOnlineAddress.ss_family) { + case AF_INET: + for(int j=0;j<4;++j) + ip.push_back((unsigned int)rawip[j]); + break; + case AF_INET6: + for(int j=0;j<16;++j) + ip.push_back((unsigned int)rawip[j]); + break; + default: + ip = tmp2; // should never happen since only IP transport is currently supported + break; + } + newrec["Value"] = ip; + newrec["OwnerPrivate"] = _lfOwnerPrivate; + newrec["MaskingKey"] = maskingKey; + newrec["Timestamp"] = ms->second.lastOnlineTime; + newrec["PulseIfUnchanged"] = true; + try { + auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json"); + if (resp) { + if (resp->status == 200) { + ms->second.lastOnlineDirty = false; + //printf("SET member online %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str()); + } else { + fprintf(stderr,"ERROR: LFDB: %d from node (create/update member online status): %s" ZT_EOL_S,resp->status,resp->body.c_str()); + } + } else { + fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): unknown exception" ZT_EOL_S); + } + } + + if (ms->second.dirty) { + nlohmann::json network,member; + if (get(ns->first,network,ms->first,member)) { + nlohmann::json newrec,selector0,selector1,selectors; + selector0["Name"] = networksSelectorName; + selector0["Ordinal"] = ns->first; + selector1["Name"] = "member"; + selector1["Ordinal"] = ms->first; + selectors.push_back(selector0); + selectors.push_back(selector1); + newrec["Selectors"] = selectors; + newrec["Value"] = member.dump(); + newrec["OwnerPrivate"] = _lfOwnerPrivate; + newrec["MaskingKey"] = maskingKey; + newrec["PulseIfUnchanged"] = true; + try { + auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json"); + if (resp) { + if (resp->status == 200) { + ms->second.dirty = false; + //printf("SET member %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str()); + } else { + fprintf(stderr,"ERROR: LFDB: %d from node (create/update member): %s" ZT_EOL_S,resp->status,resp->body.c_str()); + } + } else { + fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): unknown exception" ZT_EOL_S); + } + } + } + } + } + } + + try { + std::ostringstream query; + query << + "{" + "\"Ranges\":[{" + "\"Name\":\"" << networksSelectorName << "\"," + "\"Range\":[0,18446744073709551615]" + "}]," + "\"TimeRange\":[" << timeRangeStart << ",9223372036854775807]," + "\"MaskingKey\":\"" << maskingKey << "\"," + "\"Owners\":[\"" << _lfOwnerPublic << "\"]" + "}"; + auto resp = htcli.Post("/query",query.str(),"application/json"); + if (resp) { + if (resp->status == 200) { + nlohmann::json results(OSUtils::jsonParse(resp->body)); + if ((results.is_array())&&(results.size() > 0)) { + for(std::size_t ri=0;ri 0)) { + + nlohmann::json &result = rset[0]; + if (result.is_object()) { + nlohmann::json &record = result["Record"]; + if (record.is_object()) { + const std::string recordValue = result["Value"]; + //printf("GET network %s\n",recordValue.c_str()); + nlohmann::json network(OSUtils::jsonParse(recordValue)); + if (network.is_object()) { + const std::string idstr = network["id"]; + const uint64_t id = Utils::hexStrToU64(idstr.c_str()); + if ((id >> 24) == controllerAddressInt) { // sanity check + + nlohmann::json oldNetwork; + if ((timeRangeStart > 0)&&(get(id,oldNetwork))) { + const uint64_t revision = network["revision"]; + const uint64_t prevRevision = oldNetwork["revision"]; + if (prevRevision < revision) { + _networkChanged(oldNetwork,network,timeRangeStart > 0); + } + } else { + nlohmann::json nullJson; + _networkChanged(nullJson,network,timeRangeStart > 0); + } + + } + } + } + } + + } + } + } + } else { + fprintf(stderr,"ERROR: LFDB: %d from node (check for network updates): %s" ZT_EOL_S,resp->status,resp->body.c_str()); + } + } else { + fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): unknown exception" ZT_EOL_S); + } + + try { + std::ostringstream query; + query << + "{" + "\"Ranges\":[{" + "\"Name\":\"" << networksSelectorName << "\"," + "\"Range\":[0,18446744073709551615]" + "},{" + "\"Name\":\"member\"," + "\"Range\":[0,18446744073709551615]" + "}]," + "\"TimeRange\":[" << timeRangeStart << ",9223372036854775807]," + "\"MaskingKey\":\"" << maskingKey << "\"," + "\"Owners\":[\"" << _lfOwnerPublic << "\"]" + "}"; + auto resp = htcli.Post("/query",query.str(),"application/json"); + if (resp) { + if (resp->status == 200) { + nlohmann::json results(OSUtils::jsonParse(resp->body)); + if ((results.is_array())&&(results.size() > 0)) { + for(std::size_t ri=0;ri 0)) { + + nlohmann::json &result = rset[0]; + if (result.is_object()) { + nlohmann::json &record = result["Record"]; + if (record.is_object()) { + const std::string recordValue = result["Value"]; + //printf("GET member %s\n",recordValue.c_str()); + nlohmann::json member(OSUtils::jsonParse(recordValue)); + if (member.is_object()) { + const std::string nwidstr = member["nwid"]; + const std::string idstr = member["id"]; + const uint64_t nwid = Utils::hexStrToU64(nwidstr.c_str()); + const uint64_t id = Utils::hexStrToU64(idstr.c_str()); + if ((id)&&((nwid >> 24) == controllerAddressInt)) { // sanity check + + nlohmann::json network,oldMember; + if ((timeRangeStart > 0)&&(get(nwid,network,id,oldMember))) { + const uint64_t revision = member["revision"]; + const uint64_t prevRevision = oldMember["revision"]; + if (prevRevision < revision) + _memberChanged(oldMember,member,timeRangeStart > 0); + } else if (hasNetwork(nwid)) { + nlohmann::json nullJson; + _memberChanged(nullJson,member,timeRangeStart > 0); + } + + } + } + } + } + + } + } + } + } else { + fprintf(stderr,"ERROR: LFDB: %d from node (check for member updates): %s" ZT_EOL_S,resp->status,resp->body.c_str()); + } + } else { + fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): unknown exception" ZT_EOL_S); + } + + timeRangeStart = time(nullptr) - 120; // start next query 2m before now to avoid losing updates + _ready.store(true); + + for(int k=0;k<4;++k) { // 2s delay between queries for remotely modified networks or members + if (!_running.load()) + return; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + } + }); +} + +LFDB::~LFDB() +{ + _running.store(false); + _syncThread.join(); +} + +bool LFDB::waitForReady() +{ + while (!_ready.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + return true; +} + +bool LFDB::isReady() +{ + return (_ready.load()); +} + +bool LFDB::save(nlohmann::json &record,bool notifyListeners) +{ + bool modified = false; + const std::string objtype = record["objtype"]; + if (objtype == "network") { + const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL); + if (nwid) { + nlohmann::json old; + get(nwid,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _networkChanged(old,record,notifyListeners); + { + std::lock_guard l(_state_l); + _state[nwid].dirty = true; + } + modified = true; + } + } + } else if (objtype == "member") { + const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL); + const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL); + if ((id)&&(nwid)) { + nlohmann::json network,old; + get(nwid,network,id,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _memberChanged(old,record,notifyListeners); + { + std::lock_guard l(_state_l); + _state[nwid].members[id].dirty = true; + } + modified = true; + } + } + } + return modified; +} + +void LFDB::eraseNetwork(const uint64_t networkId) +{ + // TODO +} + +void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId) +{ + // TODO +} + +void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) +{ + std::lock_guard l(_state_l); + auto nw = _state.find(networkId); + if (nw != _state.end()) { + auto m = nw->second.members.find(memberId); + if (m != nw->second.members.end()) { + m->second.lastOnlineTime = OSUtils::now(); + if (physicalAddress) + m->second.lastOnlineAddress = physicalAddress; + m->second.lastOnlineDirty = true; + } + } +} + +} // namespace ZeroTier diff --git a/controller/LFDB.hpp b/controller/LFDB.hpp new file mode 100644 index 0000000..bcd6cdd --- /dev/null +++ b/controller/LFDB.hpp @@ -0,0 +1,102 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_CONTROLLER_LFDB_HPP +#define ZT_CONTROLLER_LFDB_HPP + +#include "DB.hpp" + +#include +#include +#include +#include + +namespace ZeroTier { + +/** + * DB implementation for controller that stores data in LF + */ +class LFDB : public DB +{ +public: + /** + * @param myId This controller's identity + * @param path Base path for ZeroTier node itself + * @param lfOwnerPrivate LF owner private in PEM format + * @param lfOwnerPublic LF owner public in @base62 format + * @param lfNodeHost LF node host + * @param lfNodePort LF node http (not https) port + * @param storeOnlineState If true, store online/offline state and IP info in LF (a lot of data, only for private networks!) + */ + LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState); + virtual ~LFDB(); + + virtual bool waitForReady(); + virtual bool isReady(); + virtual bool save(nlohmann::json &record,bool notifyListeners); + virtual void eraseNetwork(const uint64_t networkId); + virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); + +protected: + const Identity _myId; + + std::string _lfOwnerPrivate,_lfOwnerPublic; + std::string _lfNodeHost; + int _lfNodePort; + + struct _MemberState + { + _MemberState() : + lastOnlineAddress(), + lastOnlineTime(0), + dirty(false), + lastOnlineDirty(false) {} + InetAddress lastOnlineAddress; + int64_t lastOnlineTime; + bool dirty; + bool lastOnlineDirty; + }; + struct _NetworkState + { + _NetworkState() : + members(), + dirty(false) {} + std::unordered_map members; + bool dirty; + }; + std::unordered_map _state; + std::mutex _state_l; + + std::atomic_bool _running; + std::atomic_bool _ready; + std::thread _syncThread; + bool _storeOnlineState; +}; + +} // namespace ZeroTier + +#endif diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp new file mode 100644 index 0000000..0c345c9 --- /dev/null +++ b/controller/PostgreSQL.cpp @@ -0,0 +1,1493 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "PostgreSQL.hpp" + +#ifdef ZT_CONTROLLER_USE_LIBPQ + +#include "../node/Constants.hpp" +#include "EmbeddedNetworkController.hpp" +#include "RabbitMQ.hpp" +#include "../version.h" + +#include +#include +#include +#include + +using json = nlohmann::json; + +namespace { + +static const int DB_MINIMUM_VERSION = 5; + +static const char *_timestr() +{ + time_t t = time(0); + char *ts = ctime(&t); + char *p = ts; + if (!p) + return ""; + while (*p) { + if (*p == '\n') { + *p = (char)0; + break; + } + ++p; + } + return ts; +} + +/* +std::string join(const std::vector &elements, const char * const separator) +{ + switch(elements.size()) { + case 0: + return ""; + case 1: + return elements[0]; + default: + std::ostringstream os; + std::copy(elements.begin(), elements.end()-1, std::ostream_iterator(os, separator)); + os << *elements.rbegin(); + return os.str(); + } +} +*/ + +} // anonymous namespace + +using namespace ZeroTier; + +PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc) + : DB() + , _myId(myId) + , _myAddress(myId.address()) + , _ready(0) + , _connected(1) + , _run(1) + , _waitNoticePrinted(false) + , _listenPort(listenPort) + , _mqc(mqc) +{ + char myAddress[64]; + _myAddressStr = myId.address().toString(myAddress); + _connString = std::string(path) + " application_name=controller_" + _myAddressStr; + + // Database Schema Version Check + PGconn *conn = getPgConn(); + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); + } + + PGresult *res = PQexec(conn, "SELECT version FROM ztc_database"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Error determining database version"); + exit(1); + } + + if (PQntuples(res) != 1) { + fprintf(stderr, "Invalid number of db version tuples returned."); + exit(1); + } + + int dbVersion = std::stoi(PQgetvalue(res, 0, 0)); + + if (dbVersion < DB_MINIMUM_VERSION) { + fprintf(stderr, "Central database schema version too low. This controller version requires a minimum schema version of %d. Please upgrade your Central instance", DB_MINIMUM_VERSION); + exit(1); + } + + PQclear(res); + res = NULL; + PQfinish(conn); + conn = NULL; + + _readyLock.lock(); + _heartbeatThread = std::thread(&PostgreSQL::heartbeat, this); + _membersDbWatcher = std::thread(&PostgreSQL::membersDbWatcher, this); + _networksDbWatcher = std::thread(&PostgreSQL::networksDbWatcher, this); + for (int i = 0; i < ZT_CENTRAL_CONTROLLER_COMMIT_THREADS; ++i) { + _commitThread[i] = std::thread(&PostgreSQL::commitThread, this); + } + _onlineNotificationThread = std::thread(&PostgreSQL::onlineNotificationThread, this); +} + +PostgreSQL::~PostgreSQL() +{ + _run = 0; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + _heartbeatThread.join(); + _membersDbWatcher.join(); + _networksDbWatcher.join(); + for (int i = 0; i < ZT_CENTRAL_CONTROLLER_COMMIT_THREADS; ++i) { + _commitThread[i].join(); + } + _onlineNotificationThread.join(); + +} + + +bool PostgreSQL::waitForReady() +{ + while (_ready < 2) { + if (!_waitNoticePrinted) { + _waitNoticePrinted = true; + fprintf(stderr, "[%s] NOTICE: %.10llx controller PostgreSQL waiting for initial data download..." ZT_EOL_S, ::_timestr(), (unsigned long long)_myAddress.toInt()); + } + _readyLock.lock(); + _readyLock.unlock(); + } + return true; +} + +bool PostgreSQL::isReady() +{ + return ((_ready == 2)&&(_connected)); +} + +bool PostgreSQL::save(nlohmann::json &record,bool notifyListeners) +{ + bool modified = false; + try { + if (!record.is_object()) + return false; + const std::string objtype = record["objtype"]; + if (objtype == "network") { + const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL); + if (nwid) { + nlohmann::json old; + get(nwid,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _commitQueue.post(std::pair(record,notifyListeners)); + modified = true; + } + } + } else if (objtype == "member") { + const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL); + const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL); + if ((id)&&(nwid)) { + nlohmann::json network,old; + get(nwid,network,id,old); + if ((!old.is_object())||(!_compareRecords(old,record))) { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; + _commitQueue.post(std::pair(record,notifyListeners)); + modified = true; + } + } + } + } catch (std::exception &e) { + fprintf(stderr, "Error on PostgreSQL::save: %s\n", e.what()); + } catch (...) { + fprintf(stderr, "Unknown error on PostgreSQL::save\n"); + } + return modified; +} + +void PostgreSQL::eraseNetwork(const uint64_t networkId) +{ + char tmp2[24]; + waitForReady(); + Utils::hex(networkId, tmp2); + std::pair tmp; + tmp.first["id"] = tmp2; + tmp.first["objtype"] = "_delete_network"; + tmp.second = true; + _commitQueue.post(tmp); +} + +void PostgreSQL::eraseMember(const uint64_t networkId, const uint64_t memberId) +{ + char tmp2[24]; + std::pair tmp; + Utils::hex(networkId, tmp2); + tmp.first["nwid"] = tmp2; + Utils::hex(memberId, tmp2); + tmp.first["id"] = tmp2; + tmp.first["objtype"] = "_delete_member"; + tmp.second = true; + _commitQueue.post(tmp); +} + +void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) +{ + std::lock_guard l(_lastOnline_l); + std::pair &i = _lastOnline[std::pair(networkId, memberId)]; + i.first = OSUtils::now(); + if (physicalAddress) { + i.second = physicalAddress; + } +} + +void PostgreSQL::initializeNetworks(PGconn *conn) +{ + try { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); + } + + const char *params[1] = { + _myAddressStr.c_str() + }; + + PGresult *res = PQexecParams(conn, "SELECT id, EXTRACT(EPOCH FROM creation_time AT TIME ZONE 'UTC')*1000, capabilities, " + "enable_broadcast, EXTRACT(EPOCH FROM last_modified AT TIME ZONE 'UTC')*1000, mtu, multicast_limit, name, private, remote_trace_level, " + "remote_trace_target, revision, rules, tags, v4_assign_mode, v6_assign_mode FROM ztc_network " + "WHERE deleted = false AND controller_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Networks Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + + int numRows = PQntuples(res); + for (int i = 0; i < numRows; ++i) { + json empty; + json config; + + const char *nwidparam[1] = { + PQgetvalue(res, i, 0) + }; + + config["id"] = PQgetvalue(res, i, 0); + config["nwid"] = PQgetvalue(res, i, 0); + try { + config["creationTime"] = std::stoull(PQgetvalue(res, i, 1)); + } catch (std::exception &e) { + config["creationTime"] = 0ULL; + //fprintf(stderr, "Error converting creation time: %s\n", PQgetvalue(res, i, 1)); + } + config["capabilities"] = json::parse(PQgetvalue(res, i, 2)); + config["enableBroadcast"] = (strcmp(PQgetvalue(res, i, 3),"t")==0); + try { + config["lastModified"] = std::stoull(PQgetvalue(res, i, 4)); + } catch (std::exception &e) { + config["lastModified"] = 0ULL; + //fprintf(stderr, "Error converting last modified: %s\n", PQgetvalue(res, i, 4)); + } + try { + config["mtu"] = std::stoi(PQgetvalue(res, i, 5)); + } catch (std::exception &e) { + config["mtu"] = 2800; + } + try { + config["multicastLimit"] = std::stoi(PQgetvalue(res, i, 6)); + } catch (std::exception &e) { + config["multicastLimit"] = 64; + } + config["name"] = PQgetvalue(res, i, 7); + config["private"] = (strcmp(PQgetvalue(res, i, 8),"t")==0); + try { + config["remoteTraceLevel"] = std::stoi(PQgetvalue(res, i, 9)); + } catch (std::exception &e) { + config["remoteTraceLevel"] = 0; + } + config["remoteTraceTarget"] = PQgetvalue(res, i, 10); + try { + config["revision"] = std::stoull(PQgetvalue(res, i, 11)); + } catch (std::exception &e) { + config["revision"] = 0ULL; + //fprintf(stderr, "Error converting revision: %s\n", PQgetvalue(res, i, 11)); + } + config["rules"] = json::parse(PQgetvalue(res, i, 12)); + config["tags"] = json::parse(PQgetvalue(res, i, 13)); + config["v4AssignMode"] = json::parse(PQgetvalue(res, i, 14)); + config["v6AssignMode"] = json::parse(PQgetvalue(res, i, 15)); + config["objtype"] = "network"; + config["ipAssignmentPools"] = json::array(); + config["routes"] = json::array(); + + PGresult *r2 = PQexecParams(conn, + "SELECT host(ip_range_start), host(ip_range_end) FROM ztc_network_assignment_pool WHERE network_id = $1", + 1, + NULL, + nwidparam, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "ERROR: Error retreiving IP pools for network: %s\n", PQresultErrorMessage(r2)); + PQclear(r2); + PQclear(res); + exit(1); + } + + int n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + json ip; + ip["ipRangeStart"] = PQgetvalue(r2, j, 0); + ip["ipRangeEnd"] = PQgetvalue(r2, j, 1); + + config["ipAssignmentPools"].push_back(ip); + } + + PQclear(r2); + + r2 = PQexecParams(conn, + "SELECT host(address), bits, host(via) FROM ztc_network_route WHERE network_id = $1", + 1, + NULL, + nwidparam, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "ERROR: Error retreiving routes for network: %s\n", PQresultErrorMessage(r2)); + PQclear(r2); + PQclear(res); + exit(1); + } + + n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + std::string addr = PQgetvalue(r2, j, 0); + std::string bits = PQgetvalue(r2, j, 1); + std::string via = PQgetvalue(r2, j, 2); + json route; + route["target"] = addr + "/" + bits; + + if (via == "NULL") { + route["via"] = nullptr; + } else { + route["via"] = via; + } + config["routes"].push_back(route); + } + + PQclear(r2); + + _networkChanged(empty, config, false); + } + + PQclear(res); + + if (++this->_ready == 2) { + if (_waitNoticePrinted) { + fprintf(stderr,"[%s] NOTICE: %.10llx controller PostgreSQL data download complete." ZT_EOL_S,_timestr(),(unsigned long long)_myAddress.toInt()); + } + _readyLock.unlock(); + } + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error initializing networks: %s", e.what()); + exit(-1); + } +} + +void PostgreSQL::initializeMembers(PGconn *conn) +{ + try { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); + } + + const char *params[1] = { + _myAddressStr.c_str() + }; + + PGresult *res = PQexecParams(conn, + "SELECT m.id, m.network_id, m.active_bridge, m.authorized, m.capabilities, EXTRACT(EPOCH FROM m.creation_time AT TIME ZONE 'UTC')*1000, m.identity, " + " EXTRACT(EPOCH FROM m.last_authorized_time AT TIME ZONE 'UTC')*1000, " + " EXTRACT(EPOCH FROM m.last_deauthorized_time AT TIME ZONE 'UTC')*1000, " + " m.remote_trace_level, m.remote_trace_target, m.tags, m.v_major, m.v_minor, m.v_rev, m.v_proto, " + " m.no_auto_assign_ips, m.revision " + "FROM ztc_member m " + "INNER JOIN ztc_network n " + " ON n.id = m.network_id " + "WHERE n.controller_id = $1 AND m.deleted = false", + 1, + NULL, + params, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + + int numRows = PQntuples(res); + for (int i = 0; i < numRows; ++i) { + json empty; + json config; + + std::string memberId(PQgetvalue(res, i, 0)); + std::string networkId(PQgetvalue(res, i, 1)); + std::string ctime = PQgetvalue(res, i, 5); + config["id"] = memberId; + config["nwid"] = networkId; + config["activeBridge"] = (strcmp(PQgetvalue(res, i, 2), "t") == 0); + config["authorized"] = (strcmp(PQgetvalue(res, i, 3), "t") == 0); + try { + config["capabilities"] = json::parse(PQgetvalue(res, i, 4)); + } catch (std::exception &e) { + config["capabilities"] = json::array(); + } + try { + config["creationTime"] = std::stoull(PQgetvalue(res, i, 5)); + } catch (std::exception &e) { + config["creationTime"] = 0ULL; + //fprintf(stderr, "Error upding creation time (member): %s\n", PQgetvalue(res, i, 5)); + } + config["identity"] = PQgetvalue(res, i, 6); + try { + config["lastAuthorizedTime"] = std::stoull(PQgetvalue(res, i, 7)); + } catch(std::exception &e) { + config["lastAuthorizedTime"] = 0ULL; + //fprintf(stderr, "Error updating last auth time (member): %s\n", PQgetvalue(res, i, 7)); + } + try { + config["lastDeauthorizedTime"] = std::stoull(PQgetvalue(res, i, 8)); + } catch( std::exception &e) { + config["lastDeauthorizedTime"] = 0ULL; + //fprintf(stderr, "Error updating last deauth time (member): %s\n", PQgetvalue(res, i, 8)); + } + try { + config["remoteTraceLevel"] = std::stoi(PQgetvalue(res, i, 9)); + } catch (std::exception &e) { + config["remoteTraceLevel"] = 0; + } + config["remoteTraceTarget"] = PQgetvalue(res, i, 10); + try { + config["tags"] = json::parse(PQgetvalue(res, i, 11)); + } catch (std::exception &e) { + config["tags"] = json::array(); + } + try { + config["vMajor"] = std::stoi(PQgetvalue(res, i, 12)); + } catch(std::exception &e) { + config["vMajor"] = -1; + } + try { + config["vMinor"] = std::stoi(PQgetvalue(res, i, 13)); + } catch (std::exception &e) { + config["vMinor"] = -1; + } + try { + config["vRev"] = std::stoi(PQgetvalue(res, i, 14)); + } catch (std::exception &e) { + config["vRev"] = -1; + } + try { + config["vProto"] = std::stoi(PQgetvalue(res, i, 15)); + } catch (std::exception &e) { + config["vProto"] = -1; + } + config["noAutoAssignIps"] = (strcmp(PQgetvalue(res, i, 16), "t") == 0); + try { + config["revision"] = std::stoull(PQgetvalue(res, i, 17)); + } catch (std::exception &e) { + config["revision"] = 0ULL; + //fprintf(stderr, "Error updating revision (member): %s\n", PQgetvalue(res, i, 17)); + } + config["objtype"] = "member"; + config["ipAssignments"] = json::array(); + const char *p2[2] = { + memberId.c_str(), + networkId.c_str() + }; + + PGresult *r2 = PQexecParams(conn, + "SELECT DISTINCT address FROM ztc_member_ip_assignment WHERE member_id = $1 AND network_id = $2", + 2, + NULL, + p2, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(r2); + PQclear(res); + exit(1); + } + + int n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + config["ipAssignments"].push_back(PQgetvalue(r2, j, 0)); + } + + _memberChanged(empty, config, false); + } + + PQclear(res); + + if (++this->_ready == 2) { + if (_waitNoticePrinted) { + fprintf(stderr,"[%s] NOTICE: %.10llx controller PostgreSQL data download complete." ZT_EOL_S,_timestr(),(unsigned long long)_myAddress.toInt()); + } + _readyLock.unlock(); + } + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error initializing members: %s\n", e.what()); + exit(-1); + } +} + +void PostgreSQL::heartbeat() +{ + char publicId[1024]; + char hostnameTmp[1024]; + _myId.toString(false,publicId); + if (gethostname(hostnameTmp, sizeof(hostnameTmp))!= 0) { + hostnameTmp[0] = (char)0; + } else { + for (int i = 0; i < (int)sizeof(hostnameTmp); ++i) { + if ((hostnameTmp[i] == '.')||(hostnameTmp[i] == 0)) { + hostnameTmp[i] = (char)0; + break; + } + } + } + const char *controllerId = _myAddressStr.c_str(); + const char *publicIdentity = publicId; + const char *hostname = hostnameTmp; + + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + while (_run == 1) { + if(PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "%s heartbeat thread lost connection to Database\n", _myAddressStr.c_str()); + PQfinish(conn); + exit(6); + } + if (conn) { + std::string major = std::to_string(ZEROTIER_ONE_VERSION_MAJOR); + std::string minor = std::to_string(ZEROTIER_ONE_VERSION_MINOR); + std::string rev = std::to_string(ZEROTIER_ONE_VERSION_REVISION); + std::string build = std::to_string(ZEROTIER_ONE_VERSION_BUILD); + std::string now = std::to_string(OSUtils::now()); + std::string host_port = std::to_string(_listenPort); + std::string use_rabbitmq = (_mqc != NULL) ? "true" : "false"; + const char *values[10] = { + controllerId, + hostname, + now.c_str(), + publicIdentity, + major.c_str(), + minor.c_str(), + rev.c_str(), + build.c_str(), + host_port.c_str(), + use_rabbitmq.c_str() + }; + + PGresult *res = PQexecParams(conn, + "INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_rabbitmq) " + "VALUES ($1, $2, TO_TIMESTAMP($3::double precision/1000), $4, $5, $6, $7, $8, $9, $10) " + "ON CONFLICT (id) DO UPDATE SET cluster_host = EXCLUDED.cluster_host, last_alive = EXCLUDED.last_alive, " + "public_identity = EXCLUDED.public_identity, v_major = EXCLUDED.v_major, v_minor = EXCLUDED.v_minor, " + "v_rev = EXCLUDED.v_rev, v_build = EXCLUDED.v_rev, host_port = EXCLUDED.host_port, " + "use_rabbitmq = EXCLUDED.use_rabbitmq", + 10, // number of parameters + NULL, // oid field. ignore + values, // values for substitution + NULL, // lengths in bytes of each value + NULL, // binary? + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "Heartbeat Update Failed: %s\n", PQresultErrorMessage(res)); + } + PQclear(res); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + + PQfinish(conn); + conn = NULL; +} + +void PostgreSQL::membersDbWatcher() +{ + PGconn *conn = getPgConn(NO_OVERRIDE); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + + initializeMembers(conn); + + if (this->_mqc != NULL) { + PQfinish(conn); + conn = NULL; + _membersWatcher_RabbitMQ(); + } else { + _membersWatcher_Postgres(conn); + PQfinish(conn); + conn = NULL; + } + + if (_run == 1) { + fprintf(stderr, "ERROR: %s membersDbWatcher should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(9); + } + fprintf(stderr, "Exited membersDbWatcher\n"); +} + +void PostgreSQL::_membersWatcher_Postgres(PGconn *conn) { + char buf[11] = {0}; + std::string cmd = "LISTEN member_" + std::string(_myAddress.toString(buf)); + PGresult *res = PQexec(conn, cmd.c_str()); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "LISTEN command failed: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQfinish(conn); + exit(1); + } + + PQclear(res); res = NULL; + + while(_run == 1) { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Member Watcher lost connection to Postgres."); + exit(-1); + } + PGnotify *notify = NULL; + PQconsumeInput(conn); + while ((notify = PQnotifies(conn)) != NULL) { + //fprintf(stderr, "ASYNC NOTIFY of '%s' id:%s received\n", notify->relname, notify->extra); + + try { + json tmp(json::parse(notify->extra)); + json &ov = tmp["old_val"]; + json &nv = tmp["new_val"]; + json oldConfig, newConfig; + if (ov.is_object()) oldConfig = ov; + if (nv.is_object()) newConfig = nv; + if (oldConfig.is_object() || newConfig.is_object()) { + _memberChanged(oldConfig,newConfig,(this->_ready>=2)); + } + } catch (...) {} // ignore bad records + + free(notify); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void PostgreSQL::_membersWatcher_RabbitMQ() { + char buf[11] = {0}; + std::string qname = "member_"+ std::string(_myAddress.toString(buf)); + RabbitMQ rmq(_mqc, qname.c_str()); + try { + rmq.init(); + } catch (std::runtime_error &e) { + fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); + exit(11); + } + while (_run == 1) { + try { + std::string msg = rmq.consume(); + // fprintf(stderr, "Got Member Update: %s\n", msg.c_str()); + if (msg.empty()) { + continue; + } + json tmp(json::parse(msg)); + json &ov = tmp["old_val"]; + json &nv = tmp["new_val"]; + json oldConfig, newConfig; + if (ov.is_object()) oldConfig = ov; + if (nv.is_object()) newConfig = nv; + if (oldConfig.is_object() || newConfig.is_object()) { + _memberChanged(oldConfig,newConfig,(this->_ready>=2)); + } + } catch (std::runtime_error &e) { + fprintf(stderr, "RABBITMQ ERROR member change: %s\n", e.what()); + break; + } catch(std::exception &e ) { + fprintf(stderr, "RABBITMQ ERROR member change: %s\n", e.what()); + } catch(...) { + fprintf(stderr, "RABBITMQ ERROR member change: unknown error\n"); + } + } +} + +void PostgreSQL::networksDbWatcher() +{ + PGconn *conn = getPgConn(NO_OVERRIDE); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + + initializeNetworks(conn); + + if (this->_mqc != NULL) { + PQfinish(conn); + conn = NULL; + _networksWatcher_RabbitMQ(); + } else { + _networksWatcher_Postgres(conn); + PQfinish(conn); + conn = NULL; + } + + if (_run == 1) { + fprintf(stderr, "ERROR: %s networksDbWatcher should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(8); + } + fprintf(stderr, "Exited membersDbWatcher\n"); +} + +void PostgreSQL::_networksWatcher_Postgres(PGconn *conn) { + char buf[11] = {0}; + std::string cmd = "LISTEN network_" + std::string(_myAddress.toString(buf)); + PGresult *res = PQexec(conn, cmd.c_str()); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "LISTEN command failed: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQfinish(conn); + exit(1); + } + + PQclear(res); res = NULL; + + while(_run == 1) { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Network Watcher lost connection to Postgres."); + exit(-1); + } + PGnotify *notify = NULL; + PQconsumeInput(conn); + while ((notify = PQnotifies(conn)) != NULL) { + //fprintf(stderr, "ASYNC NOTIFY of '%s' id:%s received\n", notify->relname, notify->extra); + try { + json tmp(json::parse(notify->extra)); + json &ov = tmp["old_val"]; + json &nv = tmp["new_val"]; + json oldConfig, newConfig; + if (ov.is_object()) oldConfig = ov; + if (nv.is_object()) newConfig = nv; + if (oldConfig.is_object()||newConfig.is_object()) { + _networkChanged(oldConfig,newConfig,(this->_ready >= 2)); + } + } catch (...) {} // ignore bad records + free(notify); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void PostgreSQL::_networksWatcher_RabbitMQ() { + char buf[11] = {0}; + std::string qname = "network_"+ std::string(_myAddress.toString(buf)); + RabbitMQ rmq(_mqc, qname.c_str()); + try { + rmq.init(); + } catch (std::runtime_error &e) { + fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); + exit(11); + } + while (_run == 1) { + try { + std::string msg = rmq.consume(); + if (msg.empty()) { + continue; + } + // fprintf(stderr, "Got network update: %s\n", msg.c_str()); + json tmp(json::parse(msg)); + json &ov = tmp["old_val"]; + json &nv = tmp["new_val"]; + json oldConfig, newConfig; + if (ov.is_object()) oldConfig = ov; + if (nv.is_object()) newConfig = nv; + if (oldConfig.is_object()||newConfig.is_object()) { + _networkChanged(oldConfig,newConfig,(this->_ready >= 2)); + } + } catch (std::runtime_error &e) { + fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); + break; + } catch (std::exception &e) { + fprintf(stderr, "RABBITMQ ERROR network watcher: %s\n", e.what()); + } catch(...) { + fprintf(stderr, "RABBITMQ ERROR network watcher: unknown error\n"); + } + } +} + +void PostgreSQL::commitThread() +{ + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "ERROR: Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + + std::pair qitem; + while(_commitQueue.get(qitem)&(_run == 1)) { + if (!qitem.first.is_object()) { + continue; + } + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "ERROR: Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + try { + nlohmann::json *config = &(qitem.first); + const std::string objtype = (*config)["objtype"]; + if (objtype == "member") { + try { + std::string memberId = (*config)["id"]; + std::string networkId = (*config)["nwid"]; + std::string identity = (*config)["identity"]; + std::string target = "NULL"; + + if (!(*config)["remoteTraceTarget"].is_null()) { + target = (*config)["remoteTraceTarget"]; + } + + std::string caps = OSUtils::jsonDump((*config)["capabilities"], -1); + std::string lastAuthTime = std::to_string((long long)(*config)["lastAuthorizedTime"]); + std::string lastDeauthTime = std::to_string((long long)(*config)["lastDeauthorizedTime"]); + std::string rtraceLevel = std::to_string((int)(*config)["remoteTraceLevel"]); + std::string rev = std::to_string((unsigned long long)(*config)["revision"]); + std::string tags = OSUtils::jsonDump((*config)["tags"], -1); + std::string vmajor = std::to_string((int)(*config)["vMajor"]); + std::string vminor = std::to_string((int)(*config)["vMinor"]); + std::string vrev = std::to_string((int)(*config)["vRev"]); + std::string vproto = std::to_string((int)(*config)["vProto"]); + const char *values[19] = { + memberId.c_str(), + networkId.c_str(), + ((*config)["activeBridge"] ? "true" : "false"), + ((*config)["authorized"] ? "true" : "false"), + caps.c_str(), + identity.c_str(), + lastAuthTime.c_str(), + lastDeauthTime.c_str(), + ((*config)["noAutoAssignIps"] ? "true" : "false"), + rtraceLevel.c_str(), + (target == "NULL") ? NULL : target.c_str(), + rev.c_str(), + tags.c_str(), + vmajor.c_str(), + vminor.c_str(), + vrev.c_str(), + vproto.c_str() + }; + + PGresult *res = PQexecParams(conn, + "INSERT INTO ztc_member (id, network_id, active_bridge, authorized, capabilities, " + "identity, last_authorized_time, last_deauthorized_time, no_auto_assign_ips, " + "remote_trace_level, remote_trace_target, revision, tags, v_major, v_minor, v_rev, v_proto) " + "VALUES ($1, $2, $3, $4, $5, $6, " + "TO_TIMESTAMP($7::double precision/1000), TO_TIMESTAMP($8::double precision/1000), " + "$9, $10, $11, $12, $13, $14, $15, $16, $17) ON CONFLICT (network_id, id) DO UPDATE SET " + "active_bridge = EXCLUDED.active_bridge, authorized = EXCLUDED.authorized, capabilities = EXCLUDED.capabilities, " + "identity = EXCLUDED.identity, last_authorized_time = EXCLUDED.last_authorized_time, " + "last_deauthorized_time = EXCLUDED.last_deauthorized_time, no_auto_assign_ips = EXCLUDED.no_auto_assign_ips, " + "remote_trace_level = EXCLUDED.remote_trace_level, remote_trace_target = EXCLUDED.remote_trace_target, " + "revision = EXCLUDED.revision+1, tags = EXCLUDED.tags, v_major = EXCLUDED.v_major, " + "v_minor = EXCLUDED.v_minor, v_rev = EXCLUDED.v_rev, v_proto = EXCLUDED.v_proto", + 17, + NULL, + values, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating member: %s\n", PQresultErrorMessage(res)); + fprintf(stderr, "%s", OSUtils::jsonDump(*config, 2).c_str()); + PQclear(res); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + res = PQexec(conn, "BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error beginning transaction: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + const char *v2[2] = { + memberId.c_str(), + networkId.c_str() + }; + + res = PQexecParams(conn, + "DELETE FROM ztc_member_ip_assignment WHERE member_id = $1 AND network_id = $2", + 2, + NULL, + v2, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating IP address assignments: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK"));; + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + std::vector assignments; + for (auto i = (*config)["ipAssignments"].begin(); i != (*config)["ipAssignments"].end(); ++i) { + std::string addr = *i; + + if (std::find(assignments.begin(), assignments.end(), addr) != assignments.end()) { + continue; + } + + const char *v3[3] = { + memberId.c_str(), + networkId.c_str(), + addr.c_str() + }; + + res = PQexecParams(conn, + "INSERT INTO ztc_member_ip_assignment (member_id, network_id, address) VALUES ($1, $2, $3)", + 3, + NULL, + v3, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error setting IP addresses for member: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + break;; + } + } + + res = PQexec(conn, "COMMIT"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error committing ip address data: %s\n", PQresultErrorMessage(res)); + } + + PQclear(res); + + const uint64_t nwidInt = OSUtils::jsonIntHex((*config)["nwid"], 0ULL); + const uint64_t memberidInt = OSUtils::jsonIntHex((*config)["id"], 0ULL); + if (nwidInt && memberidInt) { + nlohmann::json nwOrig; + nlohmann::json memOrig; + + nlohmann::json memNew(*config); + + get(nwidInt, nwOrig, memberidInt, memOrig); + + _memberChanged(memOrig, memNew, qitem.second); + } else { + fprintf(stderr, "Can't notify of change. Error parsing nwid or memberid: %llu-%llu\n", (unsigned long long)nwidInt, (unsigned long long)memberidInt); + } + + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error updating member: %s\n", e.what()); + } + } else if (objtype == "network") { + try { + std::string id = (*config)["id"]; + std::string controllerId = _myAddressStr.c_str(); + std::string name = (*config)["name"]; + std::string remoteTraceTarget("NULL"); + if (!(*config)["remoteTraceTarget"].is_null()) { + remoteTraceTarget = (*config)["remoteTraceTarget"]; + } + std::string rulesSource; + if ((*config)["rulesSource"].is_string()) { + rulesSource = (*config)["rulesSource"]; + } + std::string caps = OSUtils::jsonDump((*config)["capabilitles"], -1); + std::string now = std::to_string(OSUtils::now()); + std::string mtu = std::to_string((int)(*config)["mtu"]); + std::string mcastLimit = std::to_string((int)(*config)["multicastLimit"]); + std::string rtraceLevel = std::to_string((int)(*config)["remoteTraceLevel"]); + std::string rules = OSUtils::jsonDump((*config)["rules"], -1); + std::string tags = OSUtils::jsonDump((*config)["tags"], -1); + std::string v4mode = OSUtils::jsonDump((*config)["v4AssignMode"],-1); + std::string v6mode = OSUtils::jsonDump((*config)["v6AssignMode"], -1); + bool enableBroadcast = (*config)["enableBroadcast"]; + bool isPrivate = (*config)["private"]; + + const char *values[16] = { + id.c_str(), + controllerId.c_str(), + caps.c_str(), + enableBroadcast ? "true" : "false", + now.c_str(), + mtu.c_str(), + mcastLimit.c_str(), + name.c_str(), + isPrivate ? "true" : "false", + rtraceLevel.c_str(), + (remoteTraceTarget == "NULL" ? NULL : remoteTraceTarget.c_str()), + rules.c_str(), + rulesSource.c_str(), + tags.c_str(), + v4mode.c_str(), + v6mode.c_str(), + }; + + // This ugly query exists because when we want to mirror networks to/from + // another data store (e.g. FileDB or LFDB) it is possible to get a network + // that doesn't exist in Central's database. This does an upsert and sets + // the owner_id to the "first" global admin in the user DB if the record + // did not previously exist. If the record already exists owner_id is left + // unchanged, so owner_id should be left out of the update clause. + PGresult *res = PQexecParams(conn, + "INSERT INTO ztc_network (id, creation_time, owner_id, controller_id, capabilities, enable_broadcast, " + "last_modified, mtu, multicast_limit, name, private, " + "remote_trace_level, remote_trace_target, rules, rules_source, " + "tags, v4_assign_mode, v6_assign_mode) VALUES (" + "$1, TO_TIMESTAMP($5::double precision/1000), " + "(SELECT user_id AS owner_id FROM ztc_global_permissions WHERE authorize = true AND del = true AND modify = true AND read = true LIMIT 1)," + "$2, $3, $4, TO_TIMESTAMP($5::double precision/1000), " + "$6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) " + "ON CONFLICT (id) DO UPDATE set controller_id = EXCLUDED.controller_id, " + "capabilities = EXCLUDED.capabilities, enable_broadcast = EXCLUDED.enable_broadcast, " + "last_modified = EXCLUDED.last_modified, mtu = EXCLUDED.mtu, " + "multicast_limit = EXCLUDED.multicast_limit, name = EXCLUDED.name, " + "private = EXCLUDED.private, remote_trace_level = EXCLUDED.remote_trace_level, " + "remote_trace_target = EXCLUDED.remote_trace_target, rules = EXCLUDED.rules, " + "rules_source = EXCLUDED.rules_source, tags = EXCLUDED.tags, " + "v4_assign_mode = EXCLUDED.v4_assign_mode, v6_assign_mode = EXCLUDED.v6_assign_mode", + 16, + NULL, + values, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating network record: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + res = PQexec(conn, "BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error beginnning transaction: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + const char *params[1] = { + id.c_str() + }; + res = PQexecParams(conn, + "DELETE FROM ztc_network_assignment_pool WHERE network_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating assignment pool: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + auto pool = (*config)["ipAssignmentPools"]; + bool err = false; + for (auto i = pool.begin(); i != pool.end(); ++i) { + std::string start = (*i)["ipRangeStart"]; + std::string end = (*i)["ipRangeEnd"]; + const char *p[3] = { + id.c_str(), + start.c_str(), + end.c_str() + }; + + res = PQexecParams(conn, + "INSERT INTO ztc_network_assignment_pool (network_id, ip_range_start, ip_range_end) " + "VALUES ($1, $2, $3)", + 3, + NULL, + p, + NULL, + NULL, + 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating assignment pool: %s\n", PQresultErrorMessage(res)); + PQclear(res); + err = true; + break; + } + PQclear(res); + } + if (err) { + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + res = PQexecParams(conn, + "DELETE FROM ztc_network_route WHERE network_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating routes: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + + auto routes = (*config)["routes"]; + err = false; + for (auto i = routes.begin(); i != routes.end(); ++i) { + std::string t = (*i)["target"]; + std::vector target; + std::istringstream f(t); + std::string s; + while(std::getline(f, s, '/')) { + target.push_back(s); + } + if (target.empty() || target.size() != 2) { + continue; + } + std::string targetAddr = target[0]; + std::string targetBits = target[1]; + std::string via = "NULL"; + if (!(*i)["via"].is_null()) { + via = (*i)["via"]; + } + + const char *p[4] = { + id.c_str(), + targetAddr.c_str(), + targetBits.c_str(), + (via == "NULL" ? NULL : via.c_str()), + }; + + res = PQexecParams(conn, + "INSERT INTO ztc_network_route (network_id, address, bits, via) VALUES ($1, $2, $3, $4)", + 4, + NULL, + p, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating routes: %s\n", PQresultErrorMessage(res)); + PQclear(res); + err = true; + break; + } + PQclear(res); + } + if (err) { + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + res = PQexec(conn, "COMMIT"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error committing network update: %s\n", PQresultErrorMessage(res)); + } + PQclear(res); + + const uint64_t nwidInt = OSUtils::jsonIntHex((*config)["nwid"], 0ULL); + if (nwidInt) { + nlohmann::json nwOrig; + nlohmann::json nwNew(*config); + + get(nwidInt, nwOrig); + + _networkChanged(nwOrig, nwNew, qitem.second); + } else { + fprintf(stderr, "Can't notify network changed: %llu\n", (unsigned long long)nwidInt); + } + + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error updating member: %s\n", e.what()); + } + } else if (objtype == "_delete_network") { + try { + std::string networkId = (*config)["nwid"]; + const char *values[1] = { + networkId.c_str() + }; + PGresult * res = PQexecParams(conn, + "UPDATE ztc_network SET deleted = true WHERE id = $1", + 1, + NULL, + values, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error deleting network: %s\n", PQresultErrorMessage(res)); + } + + PQclear(res); + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error deleting network: %s\n", e.what()); + } + } else if (objtype == "_delete_member") { + try { + std::string memberId = (*config)["id"]; + std::string networkId = (*config)["nwid"]; + + const char *values[2] = { + memberId.c_str(), + networkId.c_str() + }; + + PGresult *res = PQexecParams(conn, + "UPDATE ztc_member SET hidden = true, deleted = true WHERE id = $1 AND network_id = $2", + 2, + NULL, + values, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error deleting member: %s\n", PQresultErrorMessage(res)); + } + + PQclear(res); + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error deleting member: %s\n", e.what()); + } + } else { + fprintf(stderr, "ERROR: unknown objtype"); + } + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error getting objtype: %s\n", e.what()); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + PQfinish(conn); + if (_run == 1) { + fprintf(stderr, "ERROR: %s commitThread should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(7); + } +} + +void PostgreSQL::onlineNotificationThread() +{ + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + _connected = 1; + + //int64_t lastUpdatedNetworkStatus = 0; + std::unordered_map< std::pair,int64_t,_PairHasher > lastOnlineCumulative; + + while (_run == 1) { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Online Notification thread lost connection to Postgres."); + PQfinish(conn); + exit(5); + } + + // map used to send notifications to front end + std::unordered_map> updateMap; + + std::unordered_map< std::pair,std::pair,_PairHasher > lastOnline; + { + std::lock_guard l(_lastOnline_l); + lastOnline.swap(_lastOnline); + } + + PGresult *res = NULL; + + std::stringstream memberUpdate; + memberUpdate << "INSERT INTO ztc_member_status (network_id, member_id, address, last_updated) VALUES "; + bool firstRun = true; + bool memberAdded = false; + for (auto i=lastOnline.begin(); i != lastOnline.end(); ++i) { + uint64_t nwid_i = i->first.first; + char nwidTmp[64]; + char memTmp[64]; + char ipTmp[64]; + OSUtils::ztsnprintf(nwidTmp,sizeof(nwidTmp), "%.16llx", nwid_i); + OSUtils::ztsnprintf(memTmp,sizeof(memTmp), "%.10llx", i->first.second); + + auto found = _networks.find(nwid_i); + if (found == _networks.end()) { + continue; // skip members trying to join non-existant networks + } + + std::string networkId(nwidTmp); + std::string memberId(memTmp); + + std::vector &members = updateMap[networkId]; + members.push_back(memberId); + + lastOnlineCumulative[i->first] = i->second.first; + + + const char *qvals[2] = { + networkId.c_str(), + memberId.c_str() + }; + + res = PQexecParams(conn, + "SELECT id, network_id FROM ztc_member WHERE network_id = $1 AND id = $2", + 2, + NULL, + qvals, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member count failed: %s", PQerrorMessage(conn)); + PQclear(res); + continue; + } + + int nrows = PQntuples(res); + PQclear(res); + + if (nrows == 1) { + int64_t ts = i->second.first; + std::string ipAddr = i->second.second.toIpString(ipTmp); + std::string timestamp = std::to_string(ts); + + if (firstRun) { + firstRun = false; + } else { + memberUpdate << ", "; + } + + memberUpdate << "('" << networkId << "', '" << memberId << "', "; + if (ipAddr.empty()) { + memberUpdate << "NULL, "; + } else { + memberUpdate << "'" << ipAddr << "', "; + } + memberUpdate << "TO_TIMESTAMP(" << timestamp << "::double precision/1000))"; + memberAdded = true; + } else if (nrows > 1) { + fprintf(stderr, "nrows > 1?!?"); + continue; + } else { + continue; + } + } + memberUpdate << " ON CONFLICT (network_id, member_id) DO UPDATE SET address = EXCLUDED.address, last_updated = EXCLUDED.last_updated;"; + + if (memberAdded) { + res = PQexec(conn, memberUpdate.str().c_str()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "Multiple insert failed: %s", PQerrorMessage(conn)); + } + PQclear(res); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + fprintf(stderr, "%s: Fell out of run loop in onlineNotificationThread\n", _myAddressStr.c_str()); + PQfinish(conn); + if (_run == 1) { + fprintf(stderr, "ERROR: %s onlineNotificationThread should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(6); + } +} + +PGconn *PostgreSQL::getPgConn(OverrideMode m) +{ + if (m == ALLOW_PGBOUNCER_OVERRIDE) { + char *connStr = getenv("PGBOUNCER_CONNSTR"); + if (connStr != NULL) { + fprintf(stderr, "PGBouncer Override\n"); + std::string conn(connStr); + conn += " application_name=controller-"; + conn += _myAddressStr.c_str(); + return PQconnectdb(conn.c_str()); + } + } + + return PQconnectdb(_connString.c_str()); +} + +#endif //ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp new file mode 100644 index 0000000..6b0ea99 --- /dev/null +++ b/controller/PostgreSQL.hpp @@ -0,0 +1,119 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "DB.hpp" + +#ifdef ZT_CONTROLLER_USE_LIBPQ + +#ifndef ZT_CONTROLLER_LIBPQ_HPP +#define ZT_CONTROLLER_LIBPQ_HPP + +#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4 + +extern "C" { +typedef struct pg_conn PGconn; +} + +namespace ZeroTier { + +struct MQConfig; + +/** + * A controller database driver that talks to PostgreSQL + * + * This is for use with ZeroTier Central. Others are free to build and use it + * but be aware taht we might change it at any time. + */ +class PostgreSQL : public DB +{ +public: + PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc = NULL); + virtual ~PostgreSQL(); + + virtual bool waitForReady(); + virtual bool isReady(); + virtual bool save(nlohmann::json &record,bool notifyListeners); + virtual void eraseNetwork(const uint64_t networkId); + virtual void eraseMember(const uint64_t networkId, const uint64_t memberId); + virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress); + +protected: + struct _PairHasher + { + inline std::size_t operator()(const std::pair &p) const { return (std::size_t)(p.first ^ p.second); } + }; + +private: + void initializeNetworks(PGconn *conn); + void initializeMembers(PGconn *conn); + void heartbeat(); + void membersDbWatcher(); + void _membersWatcher_Postgres(PGconn *conn); + void _membersWatcher_RabbitMQ(); + void networksDbWatcher(); + void _networksWatcher_Postgres(PGconn *conn); + void _networksWatcher_RabbitMQ(); + + void commitThread(); + void onlineNotificationThread(); + + enum OverrideMode { + ALLOW_PGBOUNCER_OVERRIDE = 0, + NO_OVERRIDE = 1 + }; + + PGconn * getPgConn( OverrideMode m = ALLOW_PGBOUNCER_OVERRIDE ); + + const Identity _myId; + const Address _myAddress; + std::string _myAddressStr; + std::string _connString; + + BlockingQueue< std::pair > _commitQueue; + + std::thread _heartbeatThread; + std::thread _membersDbWatcher; + std::thread _networksDbWatcher; + std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS]; + std::thread _onlineNotificationThread; + + std::unordered_map< std::pair,std::pair,_PairHasher > _lastOnline; + + mutable std::mutex _lastOnline_l; + mutable std::mutex _readyLock; + std::atomic _ready, _connected, _run; + mutable volatile bool _waitNoticePrinted; + + int _listenPort; + + MQConfig *_mqc; +}; + +} // namespace ZeroTier + +#endif // ZT_CONTROLLER_LIBPQ_HPP + +#endif // ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/README.md b/controller/README.md index db8d015..c93c08f 100644 --- a/controller/README.md +++ b/controller/README.md @@ -1,12 +1,28 @@ Network Controller Microservice ====== -Every ZeroTier virtual network has a *network controller*. This is our reference implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). Network controllers act as configuration servers and certificate authorities for the members of networks. Controllers are located on the network by simply parsing out the first 10 digits of a network's 16-digit network ID: these are the address of the controller. +Every ZeroTier virtual network has a *network controller* responsible for admitting members to the network, issuing certificates, and issuing default configuration information. -As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets, allowing any device to create virtual networks without having to be rebuilt from source with special flags to enable this feature. While this does offer a convenient way to create ad-hoc networks or experiment, we recommend running a dedicated controller somewhere secure and stable for any "serious" use case. +This is our reference controller implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets. Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files. +See the API section below for information about controlling the controller. + +### Scalability and Reliability + +Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend spreading large numbers of networks across many controllers for load balancing and fault tolerance reasons. Since the controller uses the filesystem as its data store we recommend fast filesystems and fast SSD drives for heavily loaded controllers. + +Since ZeroTier nodes are mobile and do not need static IPs, implementing high availability fail-over for controllers is easy. Just replicate their working directories from master to backup and have something automatically fire up the backup if the master goes down. Modern orchestration tools like Nomad and Kubernetes can be of help here. + +### Dockerizing Controllers + +ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it. + +### PostgreSQL Database Implementation + +The default controller stores its data in the filesystem in `controller.d` under ZeroTier's home folder. There's an alternative implementation that stores data in PostgreSQL that can be built with `make central-controller`. Right now this is only guaranteed to build and run on Centos 7 Linux with PostgreSQL 10 installed via the [PostgreSQL Yum Repository](https://www.postgresql.org/download/linux/redhat/) and is designed for use with [ZeroTier Central](https://my.zerotier.com/). You're welcome to use it but we don't "officially" support it for end-user use and it could change at any time. + ### Upgrading from Older (1.1.14 or earlier) Versions Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code. @@ -17,27 +33,15 @@ The migration tool is written in nodeJS and can be used like this: npm install node migrate.js -Very old versions of nodeJS may have issues. We tested it with version 7. - -### Scalability and Reliability - -Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend spreading large numbers of networks across many controllers for load balancing and fault tolerance reasons. Since the controller uses the filesystem as its data store we recommend fast filesystems and fast SSD drives for heavily loaded controllers. - -Since ZeroTier nodes are mobile and do not need static IPs, implementing high availability fail-over for controllers is easy. Just replicate their working directories from master to backup and have something automatically fire up the backup if the master goes down. Many modern orchestration tools have built-in support for this. It would also be possible in theory to run controllers on a replicated or distributed filesystem, but we haven't tested this yet. - -### Dockerizing Controllers - -ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it. - ### Network Controller API The controller API is hosted via the same JSON API endpoint that ZeroTier One uses for local control (usually at 127.0.0.1 port 9993). All controller options are routed under the `/controller` base path. -The controller microservice does not implement any fine-grained access control (authentication is via authtoken.secret just like the regular JSON API) or other complex mangement features. It just takes network and network member configurations and reponds to controller queries. We have an enterprise product called [ZeroTier Central](https://my.zerotier.com/) that we host as a service (and that companies can license to self-host) that does this. +The controller microservice itself does not implement any fine-grained access control. Access control is via the ZeroTier control interface itself and `authtoken.secret`. This can be sent as the `X-ZT1-Auth` HTTP header field or appended to the URL as `?auth=`. Take care when doing the latter that request URLs are not being logged. -All working network IDs on a controller must begin with the controller's ZeroTier address. The API will *allow* "foreign" networks to be added but the controller will have no way of doing anything with them since nobody will know to query it. (In the future we might support secondaries, which would make this relevant.) +While networks with any valid ID can be added to the controller's database, it will only actually work to control networks whose first 10 hex digits correspond with the network controller's ZeroTier ID. See [section 2.2.1 of the ZeroTier manual](https://zerotier.com/manual.shtml#2_2_1). -The JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrectly typed and unrecognized fields may result in ignored fields or a 400 (bad request) error. +The controller JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrect types may be ignored, set to default values, or set to undefined values. #### `/controller` @@ -69,37 +73,39 @@ By making queries to this path you can create, configure, and delete networks. D When POSTing new networks take care that their IDs are not in use, otherwise you may overwrite an existing one. To create a new network with a random unused ID, POST to `/controller/network/##########______`. The #'s are the controller's 10-digit ZeroTier address and they're followed by six underscores. Check the `nwid` field of the returned JSON object for your network's newly allocated ID. Subsequent POSTs to this network must refer to its actual path. +Example: + +`curl -X POST --header "X-ZT1-Auth: secret" -d '{"name":"my network"}' http://localhost:9993/controller/network/305f406058______` + +**Network object format:** + | Field | Type | Description | Writable | | --------------------- | ------------- | ------------------------------------------------- | -------- | | id | string | 16-digit network ID | no | -| nwid | string | 16-digit network ID (old, but still around) | no | -| clock | integer | Current clock, ms since epoch | no | +| nwid | string | 16-digit network ID (legacy) | no | +| objtype | string | Always "network" | no | | name | string | A short name for this network | YES | +| creationTime | integer | Time network record was created (ms since epoch) | no | | private | boolean | Is access control enabled? | YES | | enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES | -| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES | | v4AssignMode | object | IPv4 management and assign options (see below) | YES | | v6AssignMode | object | IPv6 management and assign options (see below) | YES | +| mtu | integer | Network MTU (default: 2800) | YES | | multicastLimit | integer | Maximum recipients for a multicast packet | YES | | creationTime | integer | Time network was first created | no | | revision | integer | Network config revision counter | no | -| authorizedMemberCount | integer | Number of authorized members (for private nets) | no | -| activeMemberCount | integer | Number of members that appear to be online | no | -| totalMemberCount | integer | Total known members of this network | no | | routes | array[object] | Managed IPv4 and IPv6 routes; see below | YES | | ipAssignmentPools | array[object] | IP auto-assign ranges; see below | YES | | rules | array[object] | Traffic rules; see below | YES | - -Recent changes: - - * The `ipLocalRoutes` field appeared in older versions but is no longer present. Routes will now show up in `routes`. - * The `relays` field is gone since network preferred relays are gone. This capability is replaced by VL1 level federation ("federated roots"). - -Other important points: +| capabilities | array[object] | Array of capability objects (see below) | YES | +| tags | array[object] | Array of tag objects (see below) | YES | +| remoteTraceTarget | string | 10-digit ZeroTier ID of remote trace target | YES | +| remoteTraceLevel | integer | Remote trace verbosity level | YES | * Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added. * Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members. * The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common. + * Changing the MTU can be disruptive and on some operating systems may require a leave/rejoin of the network or a restart of the ZeroTier service. **Auto-Assign Modes:** @@ -185,7 +191,7 @@ The entry types and their additional fields are: | `MATCH_TAGS_SAMENESS` | Match if both sides' tags differ by no more than value | `id`,`value` | | `MATCH_TAGS_BITWISE_AND` | Match if both sides' tags AND to value | `id`,`value` | | `MATCH_TAGS_BITWISE_OR` | Match if both sides' tags OR to value | `id`,`value` | -| `MATCH_TAGS_BITWISE_XOR` | Match if both sides` tags XOR to value | `id`,`value` | +| `MATCH_TAGS_BITWISE_XOR` | Match if both sides' tags XOR to value | `id`,`value` | Important notes about rules engine behavior: @@ -202,14 +208,6 @@ Important notes about rules engine behavior: This returns a JSON object containing all member IDs as keys and their `memberRevisionCounter` values as values. -#### `/controller/network//active` - - * Purpose: Get a set of all active members on this network - * Methods: GET - * Returns: { object } - -This returns an object containing all currently online members and the most recent `recentLog` entries for their last request. - #### `/controller/network//member/
` * Purpose: Create, authorize, or remove a network member @@ -221,28 +219,15 @@ This returns an object containing all currently online members and the most rece | id | string | Member's 10-digit ZeroTier address | no | | address | string | Member's 10-digit ZeroTier address | no | | nwid | string | 16-digit network ID | no | -| clock | integer | Current clock, ms since epoch | no | | authorized | boolean | Is member authorized? (for private networks) | YES | -| authHistory | array[object] | History of auth changes, latest at end | no | | activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES | | identity | string | Member's public ZeroTier identity (if known) | no | | ipAssignments | array[string] | Managed IP address assignments | YES | -| memberRevision | integer | Member revision counter | no | -| recentLog | array[object] | Recent member activity log; see below | no | +| revision | integer | Member revision counter | no | +| vMajor | integer | Most recently known major version | no | +| vMinor | integer | Most recently known minor version | no | +| vRev | integer | Most recently known revision | no | +| vProto | integer | Most recently known protocl version | no | Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored. -**Recent log object format:** - -| Field | Type | Description | -| --------------------- | ------------- | ------------------------------------------------- | -| ts | integer | Time of request, ms since epoch | -| auth | boolean | Was member authorized? | -| authBy | string | How was member authorized? | -| vMajor | integer | Client major version or -1 if unknown | -| vMinor | integer | Client minor version or -1 if unknown | -| vRev | integer | Client revision or -1 if unknown | -| vProto | integer | ZeroTier protocol version reported by client | -| fromAddr | string | Physical address if known | - -The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead. diff --git a/controller/RabbitMQ.cpp b/controller/RabbitMQ.cpp new file mode 100644 index 0000000..e14fbf3 --- /dev/null +++ b/controller/RabbitMQ.cpp @@ -0,0 +1,134 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + + +#include "RabbitMQ.hpp" + +#ifdef ZT_CONTROLLER_USE_LIBPQ + +#include +#include +#include +#include + +namespace ZeroTier +{ + +RabbitMQ::RabbitMQ(MQConfig *cfg, const char *queueName) + : _mqc(cfg) + , _qName(queueName) + , _socket(NULL) + , _status(0) +{ +} + +RabbitMQ::~RabbitMQ() +{ + amqp_channel_close(_conn, _channel, AMQP_REPLY_SUCCESS); + amqp_connection_close(_conn, AMQP_REPLY_SUCCESS); + amqp_destroy_connection(_conn); +} + +void RabbitMQ::init() +{ + struct timeval tval; + memset(&tval, 0, sizeof(struct timeval)); + tval.tv_sec = 5; + + fprintf(stderr, "Initializing RabbitMQ %s\n", _qName); + _conn = amqp_new_connection(); + _socket = amqp_tcp_socket_new(_conn); + if (!_socket) { + throw std::runtime_error("Can't create socket for RabbitMQ"); + } + + _status = amqp_socket_open_noblock(_socket, _mqc->host, _mqc->port, &tval); + if (_status) { + throw std::runtime_error("Can't connect to RabbitMQ"); + } + + amqp_rpc_reply_t r = amqp_login(_conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, + _mqc->username, _mqc->password); + if (r.reply_type != AMQP_RESPONSE_NORMAL) { + throw std::runtime_error("RabbitMQ Login Error"); + } + + static int chan = 0; + { + Mutex::Lock l(_chan_m); + _channel = ++chan; + } + amqp_channel_open(_conn, _channel); + r = amqp_get_rpc_reply(_conn); + if(r.reply_type != AMQP_RESPONSE_NORMAL) { + throw std::runtime_error("Error opening communication channel"); + } + + _q = amqp_queue_declare(_conn, _channel, amqp_cstring_bytes(_qName), 0, 0, 0, 0, amqp_empty_table); + r = amqp_get_rpc_reply(_conn); + if (r.reply_type != AMQP_RESPONSE_NORMAL) { + throw std::runtime_error("Error declaring queue " + std::string(_qName)); + } + + amqp_basic_consume(_conn, _channel, amqp_cstring_bytes(_qName), amqp_empty_bytes, 0, 1, 0, amqp_empty_table); + r = amqp_get_rpc_reply(_conn); + if (r.reply_type != AMQP_RESPONSE_NORMAL) { + throw std::runtime_error("Error consuming queue " + std::string(_qName)); + } + fprintf(stderr, "RabbitMQ Init OK %s\n", _qName); +} + +std::string RabbitMQ::consume() +{ + amqp_rpc_reply_t res; + amqp_envelope_t envelope; + amqp_maybe_release_buffers(_conn); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + res = amqp_consume_message(_conn, &envelope, &timeout, 0); + if (res.reply_type != AMQP_RESPONSE_NORMAL) { + if (res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION && res.library_error == AMQP_STATUS_TIMEOUT) { + // timeout waiting for message. Return empty string + return ""; + } else { + throw std::runtime_error("Error getting message"); + } + } + + std::string msg( + (const char*)envelope.message.body.bytes, + envelope.message.body.len + ); + amqp_destroy_envelope(&envelope); + return msg; +} + +} + +#endif // ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/RabbitMQ.hpp b/controller/RabbitMQ.hpp new file mode 100644 index 0000000..c8ef31c --- /dev/null +++ b/controller/RabbitMQ.hpp @@ -0,0 +1,81 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_CONTROLLER_RABBITMQ_HPP +#define ZT_CONTROLLER_RABBITMQ_HPP + +#include "DB.hpp" + +namespace ZeroTier +{ +struct MQConfig { + const char *host; + int port; + const char *username; + const char *password; +}; +} + +#ifdef ZT_CONTROLLER_USE_LIBPQ + +#include "../node/Mutex.hpp" + +#include +#include +#include + +namespace ZeroTier +{ + +class RabbitMQ { +public: + RabbitMQ(MQConfig *cfg, const char *queueName); + ~RabbitMQ(); + + void init(); + + std::string consume(); + +private: + MQConfig *_mqc; + const char *_qName; + + amqp_socket_t *_socket; + amqp_connection_state_t _conn; + amqp_queue_declare_ok_t *_q; + int _status; + + int _channel; + + Mutex _chan_m; +}; + +} + +#endif // ZT_CONTROLLER_USE_LIBPQ + +#endif // ZT_CONTROLLER_RABBITMQ_HPP + diff --git a/controller/migrate-sqlite/migrate.js b/controller/migrate-sqlite/migrate.js deleted file mode 100644 index ac9678a..0000000 --- a/controller/migrate-sqlite/migrate.js +++ /dev/null @@ -1,320 +0,0 @@ -'use strict'; - -var sqlite3 = require('sqlite3').verbose(); -var fs = require('fs'); -var async = require('async'); - -function blobToIPv4(b) -{ - if (!b) - return null; - if (b.length !== 16) - return null; - return b.readUInt8(12).toString()+'.'+b.readUInt8(13).toString()+'.'+b.readUInt8(14).toString()+'.'+b.readUInt8(15).toString(); -} -function blobToIPv6(b) -{ - if (!b) - return null; - if (b.length !== 16) - return null; - var s = ''; - for(var i=0;i<16;++i) { - var x = b.readUInt8(i).toString(16); - if (x.length === 1) - s += '0'; - s += x; - if ((((i+1) & 1) === 0)&&(i !== 15)) - s += ':'; - } - return s; -} - -if (process.argv.length !== 4) { - console.log('ZeroTier Old Sqlite3 Controller DB Migration Utility'); - console.log('(c)2017 ZeroTier, Inc. [GPL3]'); - console.log(''); - console.log('Usage: node migrate.js '); - console.log(''); - console.log('The first argument must be the path to the old Sqlite3 controller.db'); - console.log('file. The second must be the path to the EMPTY controller.d database'); - console.log('directory for a new (1.1.17 or newer) controller. If this path does'); - console.log('not exist it will be created.'); - console.log(''); - console.log('WARNING: this will ONLY work correctly on a 1.1.14 controller database.'); - console.log('If your controller is old you should first upgrade to 1.1.14 and run the'); - console.log('controller so that it will brings its Sqlite3 database up to the latest'); - console.log('version before running this migration.'); - console.log(''); - process.exit(1); -} - -var oldDbPath = process.argv[2]; -var newDbPath = process.argv[3]; - -console.log('Starting migrate of "'+oldDbPath+'" to "'+newDbPath+'"...'); -console.log(''); - -var old = new sqlite3.Database(oldDbPath); - -var networks = {}; - -var nodeIdentities = {}; -var networkCount = 0; -var memberCount = 0; -var routeCount = 0; -var ipAssignmentPoolCount = 0; -var ipAssignmentCount = 0; -var ruleCount = 0; -var oldSchemaVersion = -1; - -async.series([function(nextStep) { - - old.each('SELECT v from Config WHERE k = \'schemaVersion\'',function(err,row) { - oldSchemaVersion = parseInt(row.v)||-1; - },nextStep); - -},function(nextStep) { - - if (oldSchemaVersion !== 4) { - console.log('FATAL: this MUST be run on a 1.1.14 controller.db! Upgrade your old'); - console.log('controller to 1.1.14 first and run it once to bring its DB up to date.'); - return process.exit(1); - } - - console.log('Reading networks...'); - old.each('SELECT * FROM Network',function(err,row) { - if ((typeof row.id === 'string')&&(row.id.length === 16)) { - var flags = parseInt(row.flags)||0; - networks[row.id] = { - id: row.id, - nwid: row.id, - objtype: 'network', - authTokens: [], - capabilities: [], - creationTime: parseInt(row.creationTime)||0, - enableBroadcast: !!row.enableBroadcast, - ipAssignmentPools: [], - lastModified: Date.now(), - multicastLimit: row.multicastLimit||32, - name: row.name||'', - private: !!row.private, - revision: parseInt(row.revision)||1, - rules: [{ 'type': 'ACTION_ACCEPT' }], // populated later if there are defined rules, otherwise default is allow all - routes: [], - v4AssignMode: { - 'zt': ((flags & 1) !== 0) - }, - v6AssignMode: { - '6plane': ((flags & 4) !== 0), - 'rfc4193': ((flags & 2) !== 0), - 'zt': ((flags & 8) !== 0) - }, - _members: {} // temporary - }; - ++networkCount; - //console.log(networks[row.id]); - } - },nextStep); - -},function(nextStep) { - - console.log(' '+networkCount+' networks.'); - console.log('Reading network route definitions...'); - old.each('SELECT * from Route WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var rt = { - target: (((row.ipVersion == 4) ? blobToIPv4(row.target) : blobToIPv6(row.target))+'/'+row.targetNetmaskBits), - via: ((row.via) ? ((row.ipVersion == 4) ? blobToIPv4(row.via) : blobToIPv6(row.via)) : null) - }; - network.routes.push(rt); - ++routeCount; - } - },nextStep); - -},function(nextStep) { - - console.log(' '+routeCount+' routes in '+networkCount+' networks.'); - console.log('Reading IP assignment pools...'); - old.each('SELECT * FROM IpAssignmentPool WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var p = { - ipRangeStart: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeStart) : blobToIPv6(row.ipRangeStart)), - ipRangeEnd: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeEnd) : blobToIPv6(row.ipRangeEnd)) - }; - network.ipAssignmentPools.push(p); - ++ipAssignmentPoolCount; - } - },nextStep); - -},function(nextStep) { - - console.log(' '+ipAssignmentPoolCount+' IP assignment pools in '+networkCount+' networks.'); - console.log('Reading known node identities...'); - old.each('SELECT * FROM Node',function(err,row) { - nodeIdentities[row.id] = row.identity; - },nextStep); - -},function(nextStep) { - - console.log(' '+Object.keys(nodeIdentities).length+' known identities.'); - console.log('Reading network members...'); - old.each('SELECT * FROM Member',function(err,row) { - var network = networks[row.networkId]; - if (network) { - network._members[row.nodeId] = { - id: row.nodeId, - address: row.nodeId, - objtype: 'member', - authorized: !!row.authorized, - activeBridge: !!row.activeBridge, - authHistory: [], - capabilities: [], - creationTime: 0, - identity: nodeIdentities[row.nodeId]||null, - ipAssignments: [], - lastAuthorizedTime: (row.authorized) ? Date.now() : 0, - lastDeauthorizedTime: (row.authorized) ? 0 : Date.now(), - lastModified: Date.now(), - lastRequestMetaData: '', - noAutoAssignIps: false, - nwid: row.networkId, - revision: parseInt(row.memberRevision)||1, - tags: [], - recentLog: [] - }; - ++memberCount; - //console.log(network._members[row.nodeId]); - } - },nextStep); - -},function(nextStep) { - - console.log(' '+memberCount+' members of '+networkCount+' networks.'); - console.log('Reading static IP assignments...'); - old.each('SELECT * FROM IpAssignment WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) { - var network = networks[row.networkId]; - if (network) { - var member = network._members[row.nodeId]; - if ((member)&&((member.authorized)||(!network['private']))) { // don't mirror assignments to unauthorized members to avoid conflicts - if (row.ipVersion == 4) { - member.ipAssignments.push(blobToIPv4(row.ip)); - ++ipAssignmentCount; - } else if (row.ipVersion == 6) { - member.ipAssignments.push(blobToIPv6(row.ip)); - ++ipAssignmentCount; - } - } - } - },nextStep); - -},function(nextStep) { - - // Old versions only supported Ethertype whitelisting, so that's - // all we mirror forward. The other fields were always unused. - - console.log(' '+ipAssignmentCount+' IP assignments for '+memberCount+' authorized members of '+networkCount+' networks.'); - console.log('Reading allowed Ethernet types (old basic rules)...'); - var etherTypesByNetwork = {}; - old.each('SELECT DISTINCT networkId,ruleNo,etherType FROM Rule WHERE "action" = \'accept\'',function(err,row) { - if (row.networkId in networks) { - var et = parseInt(row.etherType)||0; - var ets = etherTypesByNetwork[row.networkId]; - if (!ets) - etherTypesByNetwork[row.networkId] = [ et ]; - else ets.push(et); - } - },function(err) { - if (err) return nextStep(err); - for(var nwid in etherTypesByNetwork) { - var ets = etherTypesByNetwork[nwid].sort(); - var network = networks[nwid]; - if (network) { - var rules = []; - if (ets.indexOf(0) >= 0) { - // If 0 is in the list, all Ethernet types are allowed so we accept all. - rules.push({ 'type': 'ACTION_ACCEPT' }); - } else { - // Otherwise we whitelist. - for(var i=0;i 0) { - try { - fs.mkdirSync(nwBase+network.id); - } catch (e) {} - var mbase = nwBase+network.id+'/member'; - try { - fs.mkdirSync(mbase,0o700); - } catch (e) {} - mbase = mbase + '/'; - - for(var mi=0;mi", - "license": "GPL-3.0", - "dependencies": { - "async": "^2.1.4", - "sqlite3": "^3.1.8" - } -} diff --git a/cycle_controllers.sh b/cycle_controllers.sh new file mode 100755 index 0000000..34acacf --- /dev/null +++ b/cycle_controllers.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +CONTROLLERS=`kubectl get pods -o=name | grep controller | sed "s/^.\{4\}//"` + +for c in ${CONTROLLERS[@]} +do + kubectl delete pod ${c} + sleep 30 +done diff --git a/debian/changelog b/debian/changelog index 6e9fd45..67b7ac9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,44 @@ +<<<<<<< HEAD zerotier-one (1.2.4-nt1) unstable; urgency=medium +======= +zerotier-one (1.4.2) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Thu, 04 Aug 2019 01:00:00 -0700 + +zerotier-one (1.4.0) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Thu, 29 Jul 2019 01:00:00 -0700 + +zerotier-one (1.2.12) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Tue, 25 Jul 2018 01:00:00 -0700 + +zerotier-one (1.2.10) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Tue, 08 May 2018 01:00:00 -0700 + +zerotier-one (1.2.8) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Tue, 27 Apr 2018 01:00:00 -0700 + +zerotier-one (1.2.6) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + + -- Adam Ierymenko Tue, 17 Apr 2018 01:00:00 -0700 + +zerotier-one (1.2.4) unstable; urgency=medium +>>>>>>> upstream/1.4.2 * Imported Upstream version 1.2.4 diff --git a/debian/compat b/debian/compat index f11c82a..301160a 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 \ No newline at end of file +8 \ No newline at end of file diff --git a/debian/control b/debian/control index 457f46b..0cd53f7 100644 --- a/debian/control +++ b/debian/control @@ -3,10 +3,17 @@ Maintainer: NAStools Section: net Priority: optional Standards-Version: 3.9.6 +<<<<<<< HEAD Build-Depends: debhelper (>= 9), liblz4-dev, libnatpmp-dev, ruby-ronn, dh-systemd Vcs-Git: git://github.com/didyouexpectthat/zerotierone Vcs-Browser: https://github.com/didyouexpectthat/zerotierone Homepage: https://www.zerotier.com +======= +Build-Depends: debhelper (>= 9) +Vcs-Git: git://github.com/zerotier/ZeroTierOne +Vcs-Browser: https://github.com/zerotier/ZeroTierOne +Homepage: https://www.zerotier.com/ +>>>>>>> upstream/1.4.2 Package: nastools-zerotier-one Architecture: any diff --git a/debian/postinst b/debian/postinst index 9556cc7..302b573 100644 --- a/debian/postinst +++ b/debian/postinst @@ -2,7 +2,9 @@ case "$1" in configure) - adduser --system --group --home /var/lib/zerotier-one --no-create-home zerotier-one + if ! id zerotier-one >>/dev/null 2>&1; then + useradd --system --user-group --home-dir /var/lib/zerotier-one --no-create-home zerotier-one + fi ;; esac diff --git a/debian/readynas/fvapp-nastools-zerotier-one.service b/debian/readynas/fvapp-nastools-zerotier-one.service index adc8d71..4a9b8a4 100644 --- a/debian/readynas/fvapp-nastools-zerotier-one.service +++ b/debian/readynas/fvapp-nastools-zerotier-one.service @@ -1,6 +1,11 @@ [Unit] Description=ZeroTier One +<<<<<<< HEAD:debian/readynas/fvapp-nastools-zerotier-one.service After=network.target apache2.service +======= +After=network-online.target +Wants=network-online.target +>>>>>>> upstream/1.4.2:debian/zerotier-one.service [Service] ExecStart=/apps/nastools-zerotier-one/sbin/zerotier-one diff --git a/debian/rules b/debian/rules index 6ce46ff..d045b0d 100755 --- a/debian/rules +++ b/debian/rules @@ -4,9 +4,13 @@ dh $@ override_dh_auto_build: +<<<<<<< HEAD make ZT_USE_MINIUPNPC=1 -j$(nproc) gcc $$(pwd)/debian/readynas/authtoken.c -o $$(pwd)/debian/readynas/authtoken chmod u+s $$(pwd)/debian/readynas/authtoken +======= + make -j 4 +>>>>>>> upstream/1.4.2 override_dh_fixperms: dh_fixperms -Xauthtoken diff --git a/debian/ufw-zerotier-one b/debian/ufw-zerotier-one new file mode 100644 index 0000000..7c29089 --- /dev/null +++ b/debian/ufw-zerotier-one @@ -0,0 +1,4 @@ +[zerotier-one] +title=ZeroTier One +description=A planetary Ethernet switch +ports=9993/udp diff --git a/doc/ext/kubernetes/.zerotierCliSettings b/doc/ext/kubernetes/.zerotierCliSettings deleted file mode 100644 index 0e7df9b..0000000 --- a/doc/ext/kubernetes/.zerotierCliSettings +++ /dev/null @@ -1,18 +0,0 @@ -{ - "configVersion": 1, - "defaultCentral": "@my.zerotier.com", - "defaultController": "@my.zerotier.com", - "defaultOne": "@local", - "things": { - "local": { - "auth": "local_service_auth_token_replaced_automatically", - "type": "one", - "url": "http://127.0.0.1:9993/" - }, - "my.zerotier.com": { - "auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "type": "central", - "url": "https://my.zerotier.com/" - } - } -} diff --git a/doc/ext/kubernetes/Dockerfile b/doc/ext/kubernetes/Dockerfile deleted file mode 100644 index 6437a2b..0000000 --- a/doc/ext/kubernetes/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:4.4 -EXPOSE 8080/tcp 9993/udp - -# Install ZT network conf files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD zerotier-one / -ADD zerotier-cli / -ADD .zerotierCliSettings / - -# Install App -ADD server.js / - -# script which will start/auth VM on ZT network -ADD entrypoint.sh / -RUN chmod -v +x /entrypoint.sh - -CMD ["./entrypoint.sh"] \ No newline at end of file diff --git a/doc/ext/kubernetes/README.md b/doc/ext/kubernetes/README.md deleted file mode 100644 index 482e77e..0000000 --- a/doc/ext/kubernetes/README.md +++ /dev/null @@ -1,150 +0,0 @@ -Kubernetes + ZeroTier -==== - -A self-authorizing Kubernetes cluster deployment over a private ZeroTier network. - -This is a quick tutorial for setting up a Kubernetes deployment which can self-authorize each new replica onto your private ZeroTier network with no additional configuration needed when you scale. The Kubernetes-specific instructions and content is based on the [hellonode](http://kubernetes.io/docs/hellonode/) tutorial. All of the files discussed below can be found [here](); - - - -## Preliminary tasks - -**Step 1: Go to [my.zerotier.com](https://my.zerotier.com) and generate a network controller API key. This key will be used by ZeroTier to automatically authorize new instances of your VMs to join your secure deployment network during replication.** - -**Step 2: Create a new `private` network. Take note of the network ID, henceforth: `nwid`** - -**Step 3: Follow the instructions from the [hellonode](ttp://kubernetes.io/docs/hellonode/) tutorial to set up your development system.** - -*** -## Construct docker image - -**Step 4: Create necessary files for inclusion into image, your resultant directory should contain:** - - - `ztkube/.conf` - - `ztkube/Dockerfile` - - `ztkube/entrypoint.sh` - - `ztkube/server.js` - - `ztkube/zerotier-cli` - - `ztkube/zerotier-one` - -Start by creating a build directory to copy all required files into `mkdir ztkube`. Then build the following: - - `make one` - - `make cli` - -Add the following files to the `ztkube` directory. These files will be compiled into the Docker image. - - - Create an empty `.conf` file to specify the private deployment network you created in *Step 2*: - - - Create a CLI tool config file `.zerotierCliSettings` which should only contain your network controller API key to authorize new devices on your network (the local service API key will be filled in automatically). In this example the default controller is hosted by us at [my.zerotier.com](https://my.zerotier.com). Alternatively, you can host your own network controller but you'll need to modify the CLI config file accordingly. - -``` -{ - "configVersion": 1, - "defaultCentral": "@my.zerotier.com", - "defaultController": "@my.zerotier.com", - "defaultOne": "@local", - "things": { - "local": { - "auth": "local_service_auth_token_replaced_automatically", - "type": "one", - "url": "http://127.0.0.1:9993/" - }, - "my.zerotier.com": { - "auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "type": "central", - "url": "https://my.zerotier.com/" - } - } -} -``` - - - - Create a `Dockerfile` which will copy the ZeroTier service as well as the ZeroTier CLI to the image: - -``` -FROM node:4.4 -EXPOSE 8080/tcp 9993/udp - -# Install ZT network conf files -RUN mkdir -p /var/lib/zerotier-one/networks.d -ADD *.conf /var/lib/zerotier-one/networks.d/ -ADD *.conf / -ADD zerotier-one / -ADD zerotier-cli / -ADD .zerotierCliSettings / - -# Install App -ADD server.js / - -# script which will start/auth VM on ZT network -ADD entrypoint.sh / -RUN chmod -v +x /entrypoint.sh - -CMD ["./entrypoint.sh"] -``` - - - Create the `entrypoint.sh` script which will start the ZeroTier service in the VM, attempt to join your deployment network and automatically authorize the new VM if your network is set to private: - -``` -#!/bin/bash - -echo '*** ZeroTier-Kubernetes self-auth test script' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -dev="" -nwconf=$(ls *.conf) -nwid="${nwconf%.*}" - -sleep 10 -dev=$(cat /var/lib/zerotier-one/identity.public| cut -d ':' -f 1) - -echo '*** Joining' -./zerotier-cli join "$nwid".conf -# Fill out local service auth token -AUTHTOKEN=$(cat /var/lib/zerotier-one/authtoken.secret) -sed "s|\local_service_auth_token_replaced_automatically|${AUTHTOKEN}|" .zerotierCliSettings > /root/.zerotierCliSettings -echo '*** Authorizing' -./zerotier-cli net-auth @my.zerotier.com "$nwid" "$dev" -echo '*** Cleaning up' # Remove controller auth token -rm -rf .zerotierCliSettings /root/.zerotierCliSettings -node server.js -``` - -**Step 5: Build the image:** - - - `docker build -t gcr.io/$PROJECT_ID/hello-node .` - - - -**Step 6: Push the docker image to your *Container Registry*** - - - `gcloud docker push gcr.io/$PROJECT_ID/hello-node:v1` - -*** -## Deploy! - -**Step 7: Create Kubernetes Cluster** - - - `gcloud config set compute/zone us-central1-a` - - - `gcloud container clusters create hello-world` - - - `gcloud container clusters get-credentials hello-world` - - - -**Step 8: Create your pod** - - - `kubectl run hello-node --image=gcr.io/$PROJECT_ID/hello-node:v1 --port=8080` - - - -**Step 9: Scale** - - - `kubectl scale deployment hello-node --replicas=4` - -*** -## Verify - -Now, after a minute or so you can use `zerotier-cli net-members ` to show all of your VM instances on your ZeroTier deployment network. If you haven't [configured your local CLI](https://github.com/zerotier/ZeroTierOne/tree/dev/cli), you can simply log into [my.zerotier.com](https://my.zerotier.com), go to *Networks -> nwid* to check that your VMs are indeed members of your private network. You should also note that the `entrypoint.sh` script will automatically delete your network controller API key once it has authorized your VM. This is merely a security measure and can be removed if needed. diff --git a/doc/ext/kubernetes/entrypoint.sh b/doc/ext/kubernetes/entrypoint.sh deleted file mode 100644 index 80cd278..0000000 --- a/doc/ext/kubernetes/entrypoint.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -echo '*** ZeroTier-Kubernetes self-auth test script' -chown -R daemon /var/lib/zerotier-one -chgrp -R daemon /var/lib/zerotier-one -su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1' -dev="" -nwconf=$(ls *.conf) -nwid="${nwconf%.*}" - -sleep 10 -dev=$(cat /var/lib/zerotier-one/identity.public| cut -d ':' -f 1) - -echo '*** Joining' -./zerotier-cli join "$nwid".conf -# Fill out local service auth token -AUTHTOKEN=$(cat /var/lib/zerotier-one/authtoken.secret) -sed "s|\local_service_auth_token_replaced_automatically|${AUTHTOKEN}|" .zerotierCliSettings > /root/.zerotierCliSettings -echo '*** Authorizing' -./zerotier-cli net-auth @my.zerotier.com "$nwid" "$dev" -echo '*** Cleaning up' # Remove controller auth token -rm -rf .zerotierCliSettings /root/.zerotierCliSettings -node server.js \ No newline at end of file diff --git a/doc/ext/kubernetes/server.js b/doc/ext/kubernetes/server.js deleted file mode 100644 index a4b08bb..0000000 --- a/doc/ext/kubernetes/server.js +++ /dev/null @@ -1,8 +0,0 @@ -var http = require('http'); -var handleRequest = function(request, response) { - console.log('Received request for URL: ' + request.url); - response.writeHead(200); - response.end('Hello World!'); -}; -var www = http.createServer(handleRequest); -www.listen(8080); diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..0f0750c --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,19 @@ +# Dockerfile for ZeroTier Central Controllers +FROM centos:7 +MAINTAINER Adam Ierymekno , Grant Limberg + +RUN yum update -y +RUN yum install -y https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm +RUN yum install -y bash postgresql10 libpqxx-devel + +RUN yum -y install epel-release && yum -y update && yum clean all +RUN yum -y install clang jemalloc jemalloc-devel + + +ADD zerotier-one /usr/local/bin/zerotier-one +RUN chmod a+x /usr/local/bin/zerotier-one + +ADD docker/main.sh / +RUN chmod a+x /main.sh + +ENTRYPOINT /main.sh diff --git a/docker/main.sh b/docker/main.sh new file mode 100644 index 0000000..b8d3b14 --- /dev/null +++ b/docker/main.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +if [ -z "$ZT_IDENTITY_PATH" ]; then + echo '*** FAILED: ZT_IDENTITY_PATH environment variable is not defined' + exit 1 +fi +if [ -z "$ZT_DB_HOST" ]; then + echo '*** FAILED: ZT_DB_HOST environment variable not defined' + exit 1 +fi +if [ -z "$ZT_DB_PORT" ]; then + echo '*** FAILED: ZT_DB_PORT environment variable not defined' + exit 1 +fi +if [ -z "$ZT_DB_NAME" ]; then + echo '*** FAILED: ZT_DB_NAME environment variable not defined' + exit 1 +fi +if [ -z "$ZT_DB_USER" ]; then + echo '*** FAILED: ZT_DB_USER environment variable not defined' + exit 1 +fi +if [ -z "$ZT_DB_PASSWORD" ]; then + echo '*** FAILED: ZT_DB_PASSWORD environment variable not defined' + exit 1 +fi + +RMQ="" +if [ "$ZT_USE_RABBITMQ" == "true" ]; then + if [ -z "$RABBITMQ_HOST" ]; then + echo '*** FAILED: RABBITMQ_HOST environment variable not defined' + exit 1 + fi + if [ -z "$RABBITMQ_PORT" ]; then + echo '*** FAILED: RABBITMQ_PORT environment variable not defined' + exit 1 + fi + if [ -z "$RABBITMQ_USERNAME" ]; then + echo '*** FAILED: RABBITMQ_USERNAME environment variable not defined' + exit 1 + fi + if [ -z "$RABBITMQ_PASSWORD" ]; then + echo '*** FAILED: RABBITMQ_PASSWORD environment variable not defined' + exit 1 + fi + RMQ=", \"rabbitmq\": { + \"host\": \"${RABBITMQ_HOST}\", + \"port\": ${RABBITMQ_PORT}, + \"username\": \"${RABBITMQ_USERNAME}\", + \"password\": \"${RABBITMQ_PASSWORD}\" + }" +fi + +mkdir -p /var/lib/zerotier-one + +pushd /var/lib/zerotier-one +ln -s $ZT_IDENTITY_PATH/identity.public identity.public +ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret +popd + +DEFAULT_PORT=9993 + +echo "{ + \"settings\": { + \"portMappingEnabled\": true, + \"softwareUpdate\": \"disable\", + \"interfacePrefixBlacklist\": [ + \"inot\", + \"nat64\" + ], + \"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\" + ${RMQ} + } +} +" > /var/lib/zerotier-one/local.conf + +export GLIBCXX_FORCE_NEW=1 +export GLIBCPP_FORCE_NEW=1 +export LD_PRELOAD="/usr/lib64/libjemalloc.so" +exec /usr/local/bin/zerotier-one -p${ZT_CONTROLLER_PORT:-$DEFAULT_PORT} /var/lib/zerotier-one diff --git a/ext/arm32-neon-salsa2012-asm/salsa2012.h b/ext/arm32-neon-salsa2012-asm/salsa2012.h index 95b247f..262c9b9 100644 --- a/ext/arm32-neon-salsa2012-asm/salsa2012.h +++ b/ext/arm32-neon-salsa2012-asm/salsa2012.h @@ -5,8 +5,10 @@ #include #include #define zt_arm_has_neon() ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0) -#else +#elif defined(__ARM_NEON__) || defined(__ARM_NEON) #define zt_arm_has_neon() (true) +#else +#define zt_arm_has_neon() (false) #endif #ifdef __cplusplus diff --git a/ext/bin/tap-windows-ndis6/certutil.exe b/ext/bin/tap-windows-ndis6/certutil.exe new file mode 100644 index 0000000..b9a0a09 Binary files /dev/null and b/ext/bin/tap-windows-ndis6/certutil.exe differ diff --git a/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi b/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi index 4cfb7d7..17fe08c 100644 Binary files a/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi and b/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi differ diff --git a/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi b/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi index 1b9aec4..415774c 100644 Binary files a/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi and b/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi differ diff --git a/ext/bin/tap-windows-ndis6/zttap300.cer b/ext/bin/tap-windows-ndis6/zttap300.cer new file mode 100644 index 0000000..ef74e04 Binary files /dev/null and b/ext/bin/tap-windows-ndis6/zttap300.cer differ diff --git a/ext/cpp-httplib/LICENSE b/ext/cpp-httplib/LICENSE new file mode 100644 index 0000000..3e5ed35 --- /dev/null +++ b/ext/cpp-httplib/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2017 yhirose + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/ext/cpp-httplib/README.md b/ext/cpp-httplib/README.md new file mode 100644 index 0000000..2bd2345 --- /dev/null +++ b/ext/cpp-httplib/README.md @@ -0,0 +1,259 @@ +cpp-httplib +=========== + +[![Build Status](https://travis-ci.org/yhirose/cpp-httplib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-httplib) +[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-httplib) + +A C++ header-only cross platform HTTP/HTTPS library. + +It's extremely easy to setup. Just include **httplib.h** file in your code! + +Inspired by [Sinatra](http://www.sinatrarb.com/) and [express](https://github.com/visionmedia/express). + +Server Example +-------------- + +```c++ +#include + +int main(void) +{ + using namespace httplib; + + Server svr; + + svr.Get("/hi", [](const Request& req, Response& res) { + res.set_content("Hello World!", "text/plain"); + }); + + svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) { + auto numbers = req.matches[1]; + res.set_content(numbers, "text/plain"); + }); + + svr.listen("localhost", 1234); +} +``` + +`Post`, `Put`, `Delete` and `Options` methods are also supported. + +### Bind a socket to multiple interfaces and any available port + +```cpp +int port = svr.bind_to_any_port("0.0.0.0"); +svr.listen_after_bind(); +``` + +### Method Chain + +```cpp +svr.Get("/get", [](const auto& req, auto& res) { + res.set_content("get", "text/plain"); + }) + .Post("/post", [](const auto& req, auto& res) { + res.set_content(req.body(), "text/plain"); + }) + .listen("localhost", 1234); +``` + +### Static File Server + +```cpp +svr.set_base_dir("./www"); +``` + +### Logging + +```cpp +svr.set_logger([](const auto& req, const auto& res) { + your_logger(req, res); +}); +``` + +### Error Handler + +```cpp +svr.set_error_handler([](const auto& req, auto& res) { + const char* fmt = "

Error Status: %d

"; + char buf[BUFSIZ]; + snprintf(buf, sizeof(buf), fmt, res.status); + res.set_content(buf, "text/html"); +}); +``` + +### 'multipart/form-data' POST data + +```cpp +svr.Post("/multipart", [&](const auto& req, auto& res) { + auto size = req.files.size(); + auto ret = req.has_file("name1")); + const auto& file = req.get_file_value("name1"); + // file.filename; + // file.content_type; + auto body = req.body.substr(file.offset, file.length)); +}) +``` + +Client Example +-------------- + +### GET + +```c++ +#include +#include + +int main(void) +{ + httplib::Client cli("localhost", 1234); + + auto res = cli.Get("/hi"); + if (res && res->status == 200) { + std::cout << res->body << std::endl; + } +} +``` + +### GET with Content Receiver + +```c++ + std::string body; + auto res = cli.Get("/large-data", [&](const char *data, size_t len) { + body.append(data, len); + }); + assert(res->body.empty()); +``` + +### POST + +```c++ +res = cli.Post("/post", "text", "text/plain"); +res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); +``` + +### POST with parameters + +```c++ +httplib::Params params; +params.emplace("name", "john"); +params.emplace("note", "coder"); + +auto res = cli.Post("/post", params); +``` + or + +```c++ +httplib::Params params{ + { "name", "john" }, + { "note", "coder" } +}; + +auto res = cli.Post("/post", params); +``` + +### PUT + +```c++ +res = cli.Put("/resource/foo", "text", "text/plain"); +``` + +### DELETE + +```c++ +res = cli.Delete("/resource/foo"); +``` + +### OPTIONS + +```c++ +res = cli.Options("*"); +res = cli.Options("/resource/foo"); +``` + +### Connection Timeout + +```c++ +httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds +``` +### With Progress Callback + +```cpp +httplib::Client client(url, port); + +// prints: 0 / 000 bytes => 50% complete +std::shared_ptr res = + cli.Get("/", [](uint64_t len, uint64_t total) { + printf("%lld / %lld bytes => %d%% complete\n", + len, total, + (int)((len/total)*100)); + return true; // return 'false' if you want to cancel the request. + } +); +``` + +![progress](https://user-images.githubusercontent.com/236374/33138910-495c4ecc-cf86-11e7-8693-2fc6d09615c4.gif) + +This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23). + +### Basic Authentication + +```cpp +httplib::Client cli("httplib.org"); + +auto res = cli.Get("/basic-auth/hello/world", { + httplib::make_basic_authentication_header("hello", "world") +}); +// res->status should be 200 +// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n". +``` + +### Range + +```cpp +httplib::Client cli("httpbin.org"); + +auto res = cli.Get("/range/32", { + httplib::make_range_header(1, 10) // 'Range: bytes=1-10' +}); +// res->status should be 206. +// res->body should be "bcdefghijk". +``` + +OpenSSL Support +--------------- + +SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked. + +```c++ +#define CPPHTTPLIB_OPENSSL_SUPPORT + +SSLServer svr("./cert.pem", "./key.pem"); + +SSLClient cli("localhost", 8080); +cli.set_ca_cert_path("./ca-bundle.crt"); +cli.enable_server_certificate_verification(true); +``` + +Zlib Support +------------ + +'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. + +The server applies gzip compression to the following MIME type contents: + + * all text types + * image/svg+xml + * application/javascript + * application/json + * application/xml + * application/xhtml+xml + +NOTE +---- + +g++ 4.8 cannot build this library since `` in g++4.8 is [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions). + +License +------- + +MIT license (© 2019 Yuji Hirose) diff --git a/ext/cpp-httplib/httplib.h b/ext/cpp-httplib/httplib.h new file mode 100644 index 0000000..5adfc2a --- /dev/null +++ b/ext/cpp-httplib/httplib.h @@ -0,0 +1,2779 @@ +// +// httplib.h +// +// Copyright (c) 2019 Yuji Hirose. All rights reserved. +// MIT License +// + +#ifndef CPPHTTPLIB_HTTPLIB_H +#define CPPHTTPLIB_HTTPLIB_H + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif //_CRT_SECURE_NO_WARNINGS + +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif //_CRT_NONSTDC_NO_DEPRECATE + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf_s +#endif // _MSC_VER + +#ifndef S_ISREG +#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG) +#endif // S_ISREG + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR) +#endif // S_ISDIR + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +#include +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif // strcasecmp + +typedef SOCKET socket_t; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef int socket_t; +#define INVALID_SOCKET (-1) +#endif //_WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) { + return M_ASN1_STRING_data(asn1); +} +#endif +#endif + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT +#include +#endif + +/* + * Configuration + */ +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0 +#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5 +#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5 +#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0 +#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 +#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits::max)() +#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u) + +namespace httplib { + +namespace detail { + +struct ci { + bool operator()(const std::string &s1, const std::string &s2) const { + return std::lexicographical_compare( + s1.begin(), s1.end(), s2.begin(), s2.end(), + [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); }); + } +}; + +} // namespace detail + +enum class HttpVersion { v1_0 = 0, v1_1 }; + +typedef std::multimap Headers; + +template +std::pair make_range_header(uint64_t value, + Args... args); + +typedef std::multimap Params; +typedef std::smatch Match; + +typedef std::function ContentProducer; +typedef std::function ContentReceiver; +typedef std::function Progress; + +struct MultipartFile { + std::string filename; + std::string content_type; + size_t offset = 0; + size_t length = 0; +}; +typedef std::multimap MultipartFiles; + +struct Request { + std::string version; + std::string method; + std::string target; + std::string path; + Headers headers; + std::string body; + Params params; + MultipartFiles files; + Match matches; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + const SSL *ssl; +#endif + + bool has_header(const char *key) const; + std::string get_header_value(const char *key, size_t id = 0) const; + size_t get_header_value_count(const char *key) const; + void set_header(const char *key, const char *val); + + bool has_param(const char *key) const; + std::string get_param_value(const char *key, size_t id = 0) const; + size_t get_param_value_count(const char *key) const; + + bool has_file(const char *key) const; + MultipartFile get_file_value(const char *key) const; +}; + +struct Response { + std::string version; + int status; + Headers headers; + std::string body; + + ContentProducer content_producer; + ContentReceiver content_receiver; + Progress progress; + + bool has_header(const char *key) const; + std::string get_header_value(const char *key, size_t id = 0) const; + size_t get_header_value_count(const char *key) const; + void set_header(const char *key, const char *val); + + void set_redirect(const char *uri); + void set_content(const char *s, size_t n, const char *content_type); + void set_content(const std::string &s, const char *content_type); + + Response() : status(-1) {} +}; + +class Stream { +public: + virtual ~Stream() {} + virtual int read(char *ptr, size_t size) = 0; + virtual int write(const char *ptr, size_t size1) = 0; + virtual int write(const char *ptr) = 0; + virtual std::string get_remote_addr() const = 0; + + template + void write_format(const char *fmt, const Args &... args); +}; + +class SocketStream : public Stream { +public: + SocketStream(socket_t sock); + virtual ~SocketStream(); + + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; + +private: + socket_t sock_; +}; + +class BufferStream : public Stream { +public: + BufferStream() {} + virtual ~BufferStream() {} + + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; + + const std::string &get_buffer() const; + +private: + std::string buffer; +}; + +class Server { +public: + typedef std::function Handler; + typedef std::function Logger; + + Server(); + + virtual ~Server(); + + virtual bool is_valid() const; + + Server &Get(const char *pattern, Handler handler); + Server &Post(const char *pattern, Handler handler); + + Server &Put(const char *pattern, Handler handler); + Server &Patch(const char *pattern, Handler handler); + Server &Delete(const char *pattern, Handler handler); + Server &Options(const char *pattern, Handler handler); + + bool set_base_dir(const char *path); + + void set_error_handler(Handler handler); + void set_logger(Logger logger); + + void set_keep_alive_max_count(size_t count); + void set_payload_max_length(uint64_t length); + + int bind_to_any_port(const char *host, int socket_flags = 0); + bool listen_after_bind(); + + bool listen(const char *host, int port, int socket_flags = 0); + + bool is_running() const; + void stop(); + +protected: + bool process_request(Stream &strm, bool last_connection, + bool &connection_close, + std::function setup_request = nullptr); + + size_t keep_alive_max_count_; + size_t payload_max_length_; + +private: + typedef std::vector> Handlers; + + socket_t create_server_socket(const char *host, int port, + int socket_flags) const; + int bind_internal(const char *host, int port, int socket_flags); + bool listen_internal(); + + bool routing(Request &req, Response &res); + bool handle_file_request(Request &req, Response &res); + bool dispatch_request(Request &req, Response &res, Handlers &handlers); + + bool parse_request_line(const char *s, Request &req); + void write_response(Stream &strm, bool last_connection, const Request &req, + Response &res); + + virtual bool read_and_close_socket(socket_t sock); + + std::atomic is_running_; + std::atomic svr_sock_; + std::string base_dir_; + Handlers get_handlers_; + Handlers post_handlers_; + Handlers put_handlers_; + Handlers patch_handlers_; + Handlers delete_handlers_; + Handlers options_handlers_; + Handler error_handler_; + Logger logger_; + + // TODO: Use thread pool... + std::mutex running_threads_mutex_; + int running_threads_; +}; + +class Client { +public: + Client(const char *host, int port = 80, time_t timeout_sec = 300); + + virtual ~Client(); + + virtual bool is_valid() const; + + std::shared_ptr Get(const char *path, Progress progress = nullptr); + std::shared_ptr Get(const char *path, const Headers &headers, + Progress progress = nullptr); + + std::shared_ptr Get(const char *path, + ContentReceiver content_receiver, + Progress progress = nullptr); + std::shared_ptr Get(const char *path, const Headers &headers, + ContentReceiver content_receiver, + Progress progress = nullptr); + + std::shared_ptr Head(const char *path); + std::shared_ptr Head(const char *path, const Headers &headers); + + std::shared_ptr Post(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Post(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); + + std::shared_ptr Post(const char *path, const Params ¶ms); + std::shared_ptr Post(const char *path, const Headers &headers, + const Params ¶ms); + + std::shared_ptr Put(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Put(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); + + std::shared_ptr Patch(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Patch(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); + + std::shared_ptr Delete(const char *path, + const std::string &body = std::string(), + const char *content_type = nullptr); + std::shared_ptr Delete(const char *path, const Headers &headers, + const std::string &body = std::string(), + const char *content_type = nullptr); + + std::shared_ptr Options(const char *path); + std::shared_ptr Options(const char *path, const Headers &headers); + + bool send(Request &req, Response &res); + +protected: + bool process_request(Stream &strm, Request &req, Response &res, + bool &connection_close); + + const std::string host_; + const int port_; + time_t timeout_sec_; + const std::string host_and_port_; + +private: + socket_t create_client_socket() const; + bool read_response_line(Stream &strm, Response &res); + void write_request(Stream &strm, Request &req); + + virtual bool read_and_close_socket(socket_t sock, Request &req, + Response &res); + virtual bool is_ssl() const; +}; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +class SSLSocketStream : public Stream { +public: + SSLSocketStream(socket_t sock, SSL *ssl); + virtual ~SSLSocketStream(); + + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; + +private: + socket_t sock_; + SSL *ssl_; +}; + +class SSLServer : public Server { +public: + SSLServer(const char *cert_path, const char *private_key_path, + const char *client_ca_cert_file_path = nullptr, + const char *client_ca_cert_dir_path = nullptr); + + virtual ~SSLServer(); + + virtual bool is_valid() const; + +private: + virtual bool read_and_close_socket(socket_t sock); + + SSL_CTX *ctx_; + std::mutex ctx_mutex_; +}; + +class SSLClient : public Client { +public: + SSLClient(const char *host, int port = 443, time_t timeout_sec = 300, + const char *client_cert_path = nullptr, + const char *client_key_path = nullptr); + + virtual ~SSLClient(); + + virtual bool is_valid() const; + + void set_ca_cert_path(const char *ca_ceert_file_path, + const char *ca_cert_dir_path = nullptr); + void enable_server_certificate_verification(bool enabled); + + long get_openssl_verify_result() const; + +private: + virtual bool read_and_close_socket(socket_t sock, Request &req, + Response &res); + virtual bool is_ssl() const; + + bool verify_host(X509 *server_cert) const; + bool verify_host_with_subject_alt_name(X509 *server_cert) const; + bool verify_host_with_common_name(X509 *server_cert) const; + bool check_host_name(const char *pattern, size_t pattern_len) const; + + SSL_CTX *ctx_; + std::mutex ctx_mutex_; + std::vector host_components_; + std::string ca_cert_file_path_; + std::string ca_cert_dir_path_; + bool server_certificate_verification_ = false; + long verify_result_ = 0; +}; +#endif + +/* + * Implementation + */ +namespace detail { + +inline bool is_hex(char c, int &v) { + if (0x20 <= c && isdigit(c)) { + v = c - '0'; + return true; + } else if ('A' <= c && c <= 'F') { + v = c - 'A' + 10; + return true; + } else if ('a' <= c && c <= 'f') { + v = c - 'a' + 10; + return true; + } + return false; +} + +inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, + int &val) { + if (i >= s.size()) { return false; } + + val = 0; + for (; cnt; i++, cnt--) { + if (!s[i]) { return false; } + int v = 0; + if (is_hex(s[i], v)) { + val = val * 16 + v; + } else { + return false; + } + } + return true; +} + +inline std::string from_i_to_hex(uint64_t n) { + const char *charset = "0123456789abcdef"; + std::string ret; + do { + ret = charset[n & 15] + ret; + n >>= 4; + } while (n > 0); + return ret; +} + +inline size_t to_utf8(int code, char *buff) { + if (code < 0x0080) { + buff[0] = (code & 0x7F); + return 1; + } else if (code < 0x0800) { + buff[0] = (0xC0 | ((code >> 6) & 0x1F)); + buff[1] = (0x80 | (code & 0x3F)); + return 2; + } else if (code < 0xD800) { + buff[0] = (0xE0 | ((code >> 12) & 0xF)); + buff[1] = (0x80 | ((code >> 6) & 0x3F)); + buff[2] = (0x80 | (code & 0x3F)); + return 3; + } else if (code < 0xE000) { // D800 - DFFF is invalid... + return 0; + } else if (code < 0x10000) { + buff[0] = (0xE0 | ((code >> 12) & 0xF)); + buff[1] = (0x80 | ((code >> 6) & 0x3F)); + buff[2] = (0x80 | (code & 0x3F)); + return 3; + } else if (code < 0x110000) { + buff[0] = (0xF0 | ((code >> 18) & 0x7)); + buff[1] = (0x80 | ((code >> 12) & 0x3F)); + buff[2] = (0x80 | ((code >> 6) & 0x3F)); + buff[3] = (0x80 | (code & 0x3F)); + return 4; + } + + // NOTREACHED + return 0; +} + +// NOTE: This code came up with the following stackoverflow post: +// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c +inline std::string base64_encode(const std::string &in) { + static const auto lookup = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string out; + out.reserve(in.size()); + + int val = 0; + int valb = -6; + + for (uint8_t c : in) { + val = (val << 8) + c; + valb += 8; + while (valb >= 0) { + out.push_back(lookup[(val >> valb) & 0x3F]); + valb -= 6; + } + } + + if (valb > -6) { + out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); + } + + while (out.size() % 4) { + out.push_back('='); + } + + return out; +} + +inline bool is_file(const std::string &path) { + struct stat st; + return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode); +} + +inline bool is_dir(const std::string &path) { + struct stat st; + return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode); +} + +inline bool is_valid_path(const std::string &path) { + size_t level = 0; + size_t i = 0; + + // Skip slash + while (i < path.size() && path[i] == '/') { + i++; + } + + while (i < path.size()) { + // Read component + auto beg = i; + while (i < path.size() && path[i] != '/') { + i++; + } + + auto len = i - beg; + assert(len > 0); + + if (!path.compare(beg, len, ".")) { + ; + } else if (!path.compare(beg, len, "..")) { + if (level == 0) { return false; } + level--; + } else { + level++; + } + + // Skip slash + while (i < path.size() && path[i] == '/') { + i++; + } + } + + return true; +} + +inline void read_file(const std::string &path, std::string &out) { + std::ifstream fs(path, std::ios_base::binary); + fs.seekg(0, std::ios_base::end); + auto size = fs.tellg(); + fs.seekg(0); + out.resize(static_cast(size)); + fs.read(&out[0], size); +} + +inline std::string file_extension(const std::string &path) { + std::smatch m; + auto pat = std::regex("\\.([a-zA-Z0-9]+)$"); + if (std::regex_search(path, m, pat)) { return m[1].str(); } + return std::string(); +} + +template void split(const char *b, const char *e, char d, Fn fn) { + int i = 0; + int beg = 0; + + while (e ? (b + i != e) : (b[i] != '\0')) { + if (b[i] == d) { + fn(&b[beg], &b[i]); + beg = i + 1; + } + i++; + } + + if (i) { fn(&b[beg], &b[i]); } +} + +// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer` +// to store data. The call can set memory on stack for performance. +class stream_line_reader { +public: + stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size) + : strm_(strm), fixed_buffer_(fixed_buffer), + fixed_buffer_size_(fixed_buffer_size) {} + + const char *ptr() const { + if (glowable_buffer_.empty()) { + return fixed_buffer_; + } else { + return glowable_buffer_.data(); + } + } + + size_t size() const { + if (glowable_buffer_.empty()) { + return fixed_buffer_used_size_; + } else { + return glowable_buffer_.size(); + } + } + + bool getline() { + fixed_buffer_used_size_ = 0; + glowable_buffer_.clear(); + + for (size_t i = 0;; i++) { + char byte; + auto n = strm_.read(&byte, 1); + + if (n < 0) { + return false; + } else if (n == 0) { + if (i == 0) { + return false; + } else { + break; + } + } + + append(byte); + + if (byte == '\n') { break; } + } + + return true; + } + +private: + void append(char c) { + if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) { + fixed_buffer_[fixed_buffer_used_size_++] = c; + fixed_buffer_[fixed_buffer_used_size_] = '\0'; + } else { + if (glowable_buffer_.empty()) { + assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); + glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); + } + glowable_buffer_ += c; + } + } + + Stream &strm_; + char *fixed_buffer_; + const size_t fixed_buffer_size_; + size_t fixed_buffer_used_size_; + std::string glowable_buffer_; +}; + +inline int close_socket(socket_t sock) { +#ifdef _WIN32 + return closesocket(sock); +#else + return close(sock); +#endif +} + +inline int select_read(socket_t sock, time_t sec, time_t usec) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); +} + +inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { + fd_set fdsr; + FD_ZERO(&fdsr); + FD_SET(sock, &fdsr); + + auto fdsw = fdsr; + auto fdse = fdsr; + + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); + + if (select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0) { + return false; + } else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) { + int error = 0; + socklen_t len = sizeof(error); + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0 || + error) { + return false; + } + } else { + return false; + } + + return true; +} + +template +inline bool read_and_close_socket(socket_t sock, size_t keep_alive_max_count, + T callback) { + bool ret = false; + + if (keep_alive_max_count > 0) { + auto count = keep_alive_max_count; + while (count > 0 && + detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, + CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { + SocketStream strm(sock); + auto last_connection = count == 1; + auto connection_close = false; + + ret = callback(strm, last_connection, connection_close); + if (!ret || connection_close) { break; } + + count--; + } + } else { + SocketStream strm(sock); + auto dummy_connection_close = false; + ret = callback(strm, true, dummy_connection_close); + } + + close_socket(sock); + return ret; +} + +inline int shutdown_socket(socket_t sock) { +#ifdef _WIN32 + return shutdown(sock, SD_BOTH); +#else + return shutdown(sock, SHUT_RDWR); +#endif +} + +template +socket_t create_socket(const char *host, int port, Fn fn, + int socket_flags = 0) { +#ifdef _WIN32 +#define SO_SYNCHRONOUS_NONALERT 0x20 +#define SO_OPENTYPE 0x7008 + + int opt = SO_SYNCHRONOUS_NONALERT; + setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, + sizeof(opt)); +#endif + + // Get address info + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = socket_flags; + hints.ai_protocol = 0; + + auto service = std::to_string(port); + + if (getaddrinfo(host, service.c_str(), &hints, &result)) { + return INVALID_SOCKET; + } + + for (auto rp = result; rp; rp = rp->ai_next) { + // Create a socket +#ifdef _WIN32 + auto sock = WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, + nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT); +#else + auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); +#endif + if (sock == INVALID_SOCKET) { continue; } + +#ifndef _WIN32 + if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { continue; } +#endif + + // Make 'reuse address' option available + int yes = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); +#ifdef SO_REUSEPORT + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof(yes)); +#endif + + // bind or connect + if (fn(sock, *rp)) { + freeaddrinfo(result); + return sock; + } + + close_socket(sock); + } + + freeaddrinfo(result); + return INVALID_SOCKET; +} + +inline void set_nonblocking(socket_t sock, bool nonblocking) { +#ifdef _WIN32 + auto flags = nonblocking ? 1UL : 0UL; + ioctlsocket(sock, FIONBIO, &flags); +#else + auto flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, + nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK))); +#endif +} + +inline bool is_connection_error() { +#ifdef _WIN32 + return WSAGetLastError() != WSAEWOULDBLOCK; +#else + return errno != EINPROGRESS; +#endif +} + +inline std::string get_remote_addr(socket_t sock) { + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + if (!getpeername(sock, (struct sockaddr *)&addr, &len)) { + char ipstr[NI_MAXHOST]; + + if (!getnameinfo((struct sockaddr *)&addr, len, ipstr, sizeof(ipstr), + nullptr, 0, NI_NUMERICHOST)) { + return ipstr; + } + } + + return std::string(); +} + +inline const char *find_content_type(const std::string &path) { + auto ext = file_extension(path); + if (ext == "txt") { + return "text/plain"; + } else if (ext == "html") { + return "text/html"; + } else if (ext == "css") { + return "text/css"; + } else if (ext == "jpeg" || ext == "jpg") { + return "image/jpg"; + } else if (ext == "png") { + return "image/png"; + } else if (ext == "gif") { + return "image/gif"; + } else if (ext == "svg") { + return "image/svg+xml"; + } else if (ext == "ico") { + return "image/x-icon"; + } else if (ext == "json") { + return "application/json"; + } else if (ext == "pdf") { + return "application/pdf"; + } else if (ext == "js") { + return "application/javascript"; + } else if (ext == "xml") { + return "application/xml"; + } else if (ext == "xhtml") { + return "application/xhtml+xml"; + } + return nullptr; +} + +inline const char *status_message(int status) { + switch (status) { + case 200: return "OK"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 400: return "Bad Request"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 413: return "Payload Too Large"; + case 414: return "Request-URI Too Long"; + case 415: return "Unsupported Media Type"; + default: + case 500: return "Internal Server Error"; + } +} + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT +inline bool can_compress(const std::string &content_type) { + return !content_type.find("text/") || content_type == "image/svg+xml" || + content_type == "application/javascript" || + content_type == "application/json" || + content_type == "application/xml" || + content_type == "application/xhtml+xml"; +} + +inline bool compress(std::string &content) { + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, + Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { return false; } + + strm.avail_in = content.size(); + strm.next_in = (Bytef *)content.data(); + + std::string compressed; + + const auto bufsiz = 16384; + char buff[bufsiz]; + do { + strm.avail_out = bufsiz; + strm.next_out = (Bytef *)buff; + ret = deflate(&strm, Z_FINISH); + assert(ret != Z_STREAM_ERROR); + compressed.append(buff, bufsiz - strm.avail_out); + } while (strm.avail_out == 0); + + assert(ret == Z_STREAM_END); + assert(strm.avail_in == 0); + + content.swap(compressed); + + deflateEnd(&strm); + return true; +} + +class decompressor { +public: + decompressor() { + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + // 15 is the value of wbits, which should be at the maximum possible value + // to ensure that any gzip stream can be decoded. The offset of 16 specifies + // that the stream to decompress will be formatted with a gzip wrapper. + is_valid_ = inflateInit2(&strm, 16 + 15) == Z_OK; + } + + ~decompressor() { inflateEnd(&strm); } + + bool is_valid() const { return is_valid_; } + + template + bool decompress(const char *data, size_t data_len, T callback) { + int ret = Z_OK; + std::string decompressed; + + // strm.avail_in = content.size(); + // strm.next_in = (Bytef *)content.data(); + strm.avail_in = data_len; + strm.next_in = (Bytef *)data; + + const auto bufsiz = 16384; + char buff[bufsiz]; + do { + strm.avail_out = bufsiz; + strm.next_out = (Bytef *)buff; + + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: inflateEnd(&strm); return false; + } + + decompressed.append(buff, bufsiz - strm.avail_out); + } while (strm.avail_out == 0); + + if (ret == Z_STREAM_END) { + callback(decompressed.data(), decompressed.size()); + return true; + } + + return false; + } + +private: + bool is_valid_; + z_stream strm; +}; +#endif + +inline bool has_header(const Headers &headers, const char *key) { + return headers.find(key) != headers.end(); +} + +inline const char *get_header_value(const Headers &headers, const char *key, + size_t id = 0, const char *def = nullptr) { + auto it = headers.find(key); + std::advance(it, id); + if (it != headers.end()) { return it->second.c_str(); } + return def; +} + +inline uint64_t get_header_value_uint64(const Headers &headers, const char *key, + int def = 0) { + auto it = headers.find(key); + if (it != headers.end()) { + return std::strtoull(it->second.data(), nullptr, 10); + } + return def; +} + +inline bool read_headers(Stream &strm, Headers &headers) { + static std::regex re(R"((.+?):\s*(.+?)\s*\r\n)"); + + const auto bufsiz = 2048; + char buf[bufsiz]; + + stream_line_reader reader(strm, buf, bufsiz); + + for (;;) { + if (!reader.getline()) { return false; } + if (!strcmp(reader.ptr(), "\r\n")) { break; } + std::cmatch m; + if (std::regex_match(reader.ptr(), m, re)) { + auto key = std::string(m[1]); + auto val = std::string(m[2]); + headers.emplace(key, val); + } + } + + return true; +} + +template +inline bool read_content_with_length(Stream &strm, size_t len, + Progress progress, T callback) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + + size_t r = 0; + while (r < len) { + auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); + if (n <= 0) { return false; } + + callback(buf, n); + + r += n; + + if (progress) { + if (!progress(r, len)) { return false; } + } + } + + return true; +} + +inline void skip_content_with_length(Stream &strm, size_t len) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + size_t r = 0; + while (r < len) { + auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); + if (n <= 0) { return; } + r += n; + } +} + +template +inline bool read_content_without_length(Stream &strm, T callback) { + char buf[CPPHTTPLIB_RECV_BUFSIZ]; + for (;;) { + auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ); + if (n < 0) { + return false; + } else if (n == 0) { + return true; + } + callback(buf, n); + } + + return true; +} + +template +inline bool read_content_chunked(Stream &strm, T callback) { + const auto bufsiz = 16; + char buf[bufsiz]; + + stream_line_reader reader(strm, buf, bufsiz); + + if (!reader.getline()) { return false; } + + auto chunk_len = std::stoi(reader.ptr(), 0, 16); + + while (chunk_len > 0) { + if (!read_content_with_length(strm, chunk_len, nullptr, callback)) { + return false; + } + + if (!reader.getline()) { return false; } + + if (strcmp(reader.ptr(), "\r\n")) { break; } + + if (!reader.getline()) { return false; } + + chunk_len = std::stoi(reader.ptr(), 0, 16); + } + + if (chunk_len == 0) { + // Reader terminator after chunks + if (!reader.getline() || strcmp(reader.ptr(), "\r\n")) return false; + } + + return true; +} + +inline bool is_chunked_transfer_encoding(const Headers &headers) { + return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""), + "chunked"); +} + +template +bool read_content(Stream &strm, T &x, uint64_t payload_max_length, int &status, + Progress progress, U callback) { + + ContentReceiver out = [&](const char *buf, size_t n) { callback(buf, n); }; + +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + detail::decompressor decompressor; + + if (!decompressor.is_valid()) { + status = 500; + return false; + } + + if (x.get_header_value("Content-Encoding") == "gzip") { + out = [&](const char *buf, size_t n) { + decompressor.decompress( + buf, n, [&](const char *buf, size_t n) { callback(buf, n); }); + }; + } +#else + if (x.get_header_value("Content-Encoding") == "gzip") { + status = 415; + return false; + } +#endif + + auto ret = true; + auto exceed_payload_max_length = false; + + if (is_chunked_transfer_encoding(x.headers)) { + ret = read_content_chunked(strm, out); + } else if (!has_header(x.headers, "Content-Length")) { + ret = read_content_without_length(strm, out); + } else { + auto len = get_header_value_uint64(x.headers, "Content-Length", 0); + if (len > 0) { + if ((len > payload_max_length) || + // For 32-bit platform + (sizeof(size_t) < sizeof(uint64_t) && + len > std::numeric_limits::max())) { + exceed_payload_max_length = true; + skip_content_with_length(strm, len); + ret = false; + } else { + ret = read_content_with_length(strm, len, progress, out); + } + } + } + + if (!ret) { status = exceed_payload_max_length ? 413 : 400; } + + return ret; +} + +template inline void write_headers(Stream &strm, const T &info) { + for (const auto &x : info.headers) { + strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str()); + } + strm.write("\r\n"); +} + +template +inline void write_content_chunked(Stream &strm, const T &x) { + auto chunked_response = !x.has_header("Content-Length"); + uint64_t offset = 0; + auto data_available = true; + while (data_available) { + auto chunk = x.content_producer(offset); + offset += chunk.size(); + data_available = !chunk.empty(); + + // Emit chunked response header and footer for each chunk + if (chunked_response) { + chunk = from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n"; + } + + if (strm.write(chunk.c_str(), chunk.size()) < 0) { + break; // Stop on error + } + } +} + +inline std::string encode_url(const std::string &s) { + std::string result; + + for (auto i = 0; s[i]; i++) { + switch (s[i]) { + case ' ': result += "%20"; break; + case '+': result += "%2B"; break; + case '\r': result += "%0D"; break; + case '\n': result += "%0A"; break; + case '\'': result += "%27"; break; + case ',': result += "%2C"; break; + case ':': result += "%3A"; break; + case ';': result += "%3B"; break; + default: + auto c = static_cast(s[i]); + if (c >= 0x80) { + result += '%'; + char hex[4]; + size_t len = snprintf(hex, sizeof(hex) - 1, "%02X", c); + assert(len == 2); + result.append(hex, len); + } else { + result += s[i]; + } + break; + } + } + + return result; +} + +inline std::string decode_url(const std::string &s) { + std::string result; + + for (size_t i = 0; i < s.size(); i++) { + if (s[i] == '%' && i + 1 < s.size()) { + if (s[i + 1] == 'u') { + int val = 0; + if (from_hex_to_i(s, i + 2, 4, val)) { + // 4 digits Unicode codes + char buff[4]; + size_t len = to_utf8(val, buff); + if (len > 0) { result.append(buff, len); } + i += 5; // 'u0000' + } else { + result += s[i]; + } + } else { + int val = 0; + if (from_hex_to_i(s, i + 1, 2, val)) { + // 2 digits hex codes + result += val; + i += 2; // '00' + } else { + result += s[i]; + } + } + } else if (s[i] == '+') { + result += ' '; + } else { + result += s[i]; + } + } + + return result; +} + +inline void parse_query_text(const std::string &s, Params ¶ms) { + split(&s[0], &s[s.size()], '&', [&](const char *b, const char *e) { + std::string key; + std::string val; + split(b, e, '=', [&](const char *b, const char *e) { + if (key.empty()) { + key.assign(b, e); + } else { + val.assign(b, e); + } + }); + params.emplace(key, decode_url(val)); + }); +} + +inline bool parse_multipart_boundary(const std::string &content_type, + std::string &boundary) { + auto pos = content_type.find("boundary="); + if (pos == std::string::npos) { return false; } + + boundary = content_type.substr(pos + 9); + return true; +} + +inline bool parse_multipart_formdata(const std::string &boundary, + const std::string &body, + MultipartFiles &files) { + static std::string dash = "--"; + static std::string crlf = "\r\n"; + + static std::regex re_content_type("Content-Type: (.*?)", + std::regex_constants::icase); + + static std::regex re_content_disposition( + "Content-Disposition: form-data; name=\"(.*?)\"(?:; filename=\"(.*?)\")?", + std::regex_constants::icase); + + auto dash_boundary = dash + boundary; + + auto pos = body.find(dash_boundary); + if (pos != 0) { return false; } + + pos += dash_boundary.size(); + + auto next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + pos = next_pos + crlf.size(); + + while (pos < body.size()) { + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + std::string name; + MultipartFile file; + + auto header = body.substr(pos, (next_pos - pos)); + + while (pos != next_pos) { + std::smatch m; + if (std::regex_match(header, m, re_content_type)) { + file.content_type = m[1]; + } else if (std::regex_match(header, m, re_content_disposition)) { + name = m[1]; + file.filename = m[2]; + } + + pos = next_pos + crlf.size(); + + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + header = body.substr(pos, (next_pos - pos)); + } + + pos = next_pos + crlf.size(); + + next_pos = body.find(crlf + dash_boundary, pos); + + if (next_pos == std::string::npos) { return false; } + + file.offset = pos; + file.length = next_pos - pos; + + pos = next_pos + crlf.size() + dash_boundary.size(); + + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + files.emplace(name, file); + + pos = next_pos + crlf.size(); + } + + return true; +} + +inline std::string to_lower(const char *beg, const char *end) { + std::string out; + auto it = beg; + while (it != end) { + out += ::tolower(*it); + it++; + } + return out; +} + +inline void make_range_header_core(std::string &) {} + +template +inline void make_range_header_core(std::string &field, uint64_t value) { + if (!field.empty()) { field += ", "; } + field += std::to_string(value) + "-"; +} + +template +inline void make_range_header_core(std::string &field, uint64_t value1, + uint64_t value2, Args... args) { + if (!field.empty()) { field += ", "; } + field += std::to_string(value1) + "-" + std::to_string(value2); + make_range_header_core(field, args...); +} + +#ifdef _WIN32 +class WSInit { +public: + WSInit() { + WSADATA wsaData; + WSAStartup(0x0002, &wsaData); + } + + ~WSInit() { WSACleanup(); } +}; + +static WSInit wsinit_; +#endif + +} // namespace detail + +// Header utilities +template +inline std::pair make_range_header(uint64_t value, + Args... args) { + std::string field; + detail::make_range_header_core(field, value, args...); + field.insert(0, "bytes="); + return std::make_pair("Range", field); +} + + +inline std::pair +make_basic_authentication_header(const std::string& username, const std::string& password) { + auto field = "Basic " + detail::base64_encode(username + ":" + password); + return std::make_pair("Authorization", field); +} +// Request implementation +inline bool Request::has_header(const char *key) const { + return detail::has_header(headers, key); +} + +inline std::string Request::get_header_value(const char *key, size_t id) const { + return detail::get_header_value(headers, key, id, ""); +} + +inline size_t Request::get_header_value_count(const char *key) const { + auto r = headers.equal_range(key); + return std::distance(r.first, r.second); +} + +inline void Request::set_header(const char *key, const char *val) { + headers.emplace(key, val); +} + +inline bool Request::has_param(const char *key) const { + return params.find(key) != params.end(); +} + +inline std::string Request::get_param_value(const char *key, size_t id) const { + auto it = params.find(key); + std::advance(it, id); + if (it != params.end()) { return it->second; } + return std::string(); +} + +inline size_t Request::get_param_value_count(const char *key) const { + auto r = params.equal_range(key); + return std::distance(r.first, r.second); +} + +inline bool Request::has_file(const char *key) const { + return files.find(key) != files.end(); +} + +inline MultipartFile Request::get_file_value(const char *key) const { + auto it = files.find(key); + if (it != files.end()) { return it->second; } + return MultipartFile(); +} + +// Response implementation +inline bool Response::has_header(const char *key) const { + return headers.find(key) != headers.end(); +} + +inline std::string Response::get_header_value(const char *key, + size_t id) const { + return detail::get_header_value(headers, key, id, ""); +} + +inline size_t Response::get_header_value_count(const char *key) const { + auto r = headers.equal_range(key); + return std::distance(r.first, r.second); +} + +inline void Response::set_header(const char *key, const char *val) { + headers.emplace(key, val); +} + +inline void Response::set_redirect(const char *url) { + set_header("Location", url); + status = 302; +} + +inline void Response::set_content(const char *s, size_t n, + const char *content_type) { + body.assign(s, n); + set_header("Content-Type", content_type); +} + +inline void Response::set_content(const std::string &s, + const char *content_type) { + body = s; + set_header("Content-Type", content_type); +} + +// Rstream implementation +template +inline void Stream::write_format(const char *fmt, const Args &... args) { + const auto bufsiz = 2048; + char buf[bufsiz]; + +#if defined(_MSC_VER) && _MSC_VER < 1900 + auto n = _snprintf_s(buf, bufsiz, bufsiz - 1, fmt, args...); +#else + auto n = snprintf(buf, bufsiz - 1, fmt, args...); +#endif + if (n > 0) { + if (n >= bufsiz - 1) { + std::vector glowable_buf(bufsiz); + + while (n >= static_cast(glowable_buf.size() - 1)) { + glowable_buf.resize(glowable_buf.size() * 2); +#if defined(_MSC_VER) && _MSC_VER < 1900 + n = _snprintf_s(&glowable_buf[0], glowable_buf.size(), + glowable_buf.size() - 1, fmt, args...); +#else + n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...); +#endif + } + write(&glowable_buf[0], n); + } else { + write(buf, n); + } + } +} + +// Socket stream implementation +inline SocketStream::SocketStream(socket_t sock) : sock_(sock) {} + +inline SocketStream::~SocketStream() {} + +inline int SocketStream::read(char *ptr, size_t size) { + if (detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, + CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { + return recv(sock_, ptr, static_cast(size), 0); + } + return -1; +} + +inline int SocketStream::write(const char *ptr, size_t size) { + return send(sock_, ptr, static_cast(size), 0); +} + +inline int SocketStream::write(const char *ptr) { + return write(ptr, strlen(ptr)); +} + +inline std::string SocketStream::get_remote_addr() const { + return detail::get_remote_addr(sock_); +} + +// Buffer stream implementation +inline int BufferStream::read(char *ptr, size_t size) { +#if defined(_MSC_VER) && _MSC_VER < 1900 + return static_cast(buffer._Copy_s(ptr, size, size)); +#else + return static_cast(buffer.copy(ptr, size)); +#endif +} + +inline int BufferStream::write(const char *ptr, size_t size) { + buffer.append(ptr, size); + return static_cast(size); +} + +inline int BufferStream::write(const char *ptr) { + size_t size = strlen(ptr); + buffer.append(ptr, size); + return static_cast(size); +} + +inline std::string BufferStream::get_remote_addr() const { return ""; } + +inline const std::string &BufferStream::get_buffer() const { return buffer; } + +// HTTP server implementation +inline Server::Server() + : keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT), + payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH), is_running_(false), + svr_sock_(INVALID_SOCKET), running_threads_(0) { +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif +} + +inline Server::~Server() {} + +inline Server &Server::Get(const char *pattern, Handler handler) { + get_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server &Server::Post(const char *pattern, Handler handler) { + post_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server &Server::Put(const char *pattern, Handler handler) { + put_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server &Server::Patch(const char *pattern, Handler handler) { + patch_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server &Server::Delete(const char *pattern, Handler handler) { + delete_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server &Server::Options(const char *pattern, Handler handler) { + options_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline bool Server::set_base_dir(const char *path) { + if (detail::is_dir(path)) { + base_dir_ = path; + return true; + } + return false; +} + +inline void Server::set_error_handler(Handler handler) { + error_handler_ = handler; +} + +inline void Server::set_logger(Logger logger) { logger_ = logger; } + +inline void Server::set_keep_alive_max_count(size_t count) { + keep_alive_max_count_ = count; +} + +inline void Server::set_payload_max_length(uint64_t length) { + payload_max_length_ = length; +} + +inline int Server::bind_to_any_port(const char *host, int socket_flags) { + return bind_internal(host, 0, socket_flags); +} + +inline bool Server::listen_after_bind() { return listen_internal(); } + +inline bool Server::listen(const char *host, int port, int socket_flags) { + if (bind_internal(host, port, socket_flags) < 0) return false; + return listen_internal(); +} + +inline bool Server::is_running() const { return is_running_; } + +inline void Server::stop() { + if (is_running_) { + assert(svr_sock_ != INVALID_SOCKET); + std::atomic sock(svr_sock_.exchange(INVALID_SOCKET)); + detail::shutdown_socket(sock); + detail::close_socket(sock); + } +} + +inline bool Server::parse_request_line(const char *s, Request &req) { + static std::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) " + "(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n"); + + std::cmatch m; + if (std::regex_match(s, m, re)) { + req.version = std::string(m[5]); + req.method = std::string(m[1]); + req.target = std::string(m[2]); + req.path = detail::decode_url(m[3]); + + // Parse query text + auto len = std::distance(m[4].first, m[4].second); + if (len > 0) { detail::parse_query_text(m[4], req.params); } + + return true; + } + + return false; +} + +inline void Server::write_response(Stream &strm, bool last_connection, + const Request &req, Response &res) { + assert(res.status != -1); + + if (400 <= res.status && error_handler_) { error_handler_(req, res); } + + // Response line + strm.write_format("HTTP/1.1 %d %s\r\n", res.status, + detail::status_message(res.status)); + + // Headers + if (last_connection || req.get_header_value("Connection") == "close") { + res.set_header("Connection", "close"); + } + + if (!last_connection && req.get_header_value("Connection") == "Keep-Alive") { + res.set_header("Connection", "Keep-Alive"); + } + + if (res.body.empty()) { + if (!res.has_header("Content-Length")) { + if (res.content_producer) { + // Streamed response + res.set_header("Transfer-Encoding", "chunked"); + } else { + res.set_header("Content-Length", "0"); + } + } + } else { +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + // TODO: 'Accpet-Encoding' has gzip, not gzip;q=0 + const auto &encodings = req.get_header_value("Accept-Encoding"); + if (encodings.find("gzip") != std::string::npos && + detail::can_compress(res.get_header_value("Content-Type"))) { + if (detail::compress(res.body)) { + res.set_header("Content-Encoding", "gzip"); + } + } +#endif + + if (!res.has_header("Content-Type")) { + res.set_header("Content-Type", "text/plain"); + } + + auto length = std::to_string(res.body.size()); + res.set_header("Content-Length", length.c_str()); + } + + detail::write_headers(strm, res); + + // Body + if (req.method != "HEAD") { + if (!res.body.empty()) { + strm.write(res.body.c_str(), res.body.size()); + } else if (res.content_producer) { + detail::write_content_chunked(strm, res); + } + } + + // Log + if (logger_) { logger_(req, res); } +} + +inline bool Server::handle_file_request(Request &req, Response &res) { + if (!base_dir_.empty() && detail::is_valid_path(req.path)) { + std::string path = base_dir_ + req.path; + + if (!path.empty() && path.back() == '/') { path += "index.html"; } + + if (detail::is_file(path)) { + detail::read_file(path, res.body); + auto type = detail::find_content_type(path); + if (type) { res.set_header("Content-Type", type); } + res.status = 200; + return true; + } + } + + return false; +} + +inline socket_t Server::create_server_socket(const char *host, int port, + int socket_flags) const { + return detail::create_socket( + host, port, + [](socket_t sock, struct addrinfo &ai) -> bool { + if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + return false; + } + if (::listen(sock, 5)) { // Listen through 5 channels + return false; + } + return true; + }, + socket_flags); +} + +inline int Server::bind_internal(const char *host, int port, int socket_flags) { + if (!is_valid()) { return -1; } + + svr_sock_ = create_server_socket(host, port, socket_flags); + if (svr_sock_ == INVALID_SOCKET) { return -1; } + + if (port == 0) { + struct sockaddr_storage address; + socklen_t len = sizeof(address); + if (getsockname(svr_sock_, reinterpret_cast(&address), + &len) == -1) { + return -1; + } + if (address.ss_family == AF_INET) { + return ntohs(reinterpret_cast(&address)->sin_port); + } else if (address.ss_family == AF_INET6) { + return ntohs( + reinterpret_cast(&address)->sin6_port); + } else { + return -1; + } + } else { + return port; + } +} + +inline bool Server::listen_internal() { + auto ret = true; + + is_running_ = true; + + for (;;) { + if (svr_sock_ == INVALID_SOCKET) { + // The server socket was closed by 'stop' method. + break; + } + + auto val = detail::select_read(svr_sock_, 0, 100000); + + if (val == 0) { // Timeout + continue; + } + + socket_t sock = accept(svr_sock_, nullptr, nullptr); + + if (sock == INVALID_SOCKET) { + if (svr_sock_ != INVALID_SOCKET) { + detail::close_socket(svr_sock_); + ret = false; + } else { + ; // The server socket was closed by user. + } + break; + } + + // TODO: Use thread pool... + std::thread([=]() { + { + std::lock_guard guard(running_threads_mutex_); + running_threads_++; + } + + read_and_close_socket(sock); + + { + std::lock_guard guard(running_threads_mutex_); + running_threads_--; + } + }).detach(); + } + + // TODO: Use thread pool... + for (;;) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::lock_guard guard(running_threads_mutex_); + if (!running_threads_) { break; } + } + + is_running_ = false; + + return ret; +} + +inline bool Server::routing(Request &req, Response &res) { + if (req.method == "GET" && handle_file_request(req, res)) { return true; } + + if (req.method == "GET" || req.method == "HEAD") { + return dispatch_request(req, res, get_handlers_); + } else if (req.method == "POST") { + return dispatch_request(req, res, post_handlers_); + } else if (req.method == "PUT") { + return dispatch_request(req, res, put_handlers_); + } else if (req.method == "PATCH") { + return dispatch_request(req, res, patch_handlers_); + } else if (req.method == "DELETE") { + return dispatch_request(req, res, delete_handlers_); + } else if (req.method == "OPTIONS") { + return dispatch_request(req, res, options_handlers_); + } + return false; +} + +inline bool Server::dispatch_request(Request &req, Response &res, + Handlers &handlers) { + for (const auto &x : handlers) { + const auto &pattern = x.first; + const auto &handler = x.second; + + if (std::regex_match(req.path, req.matches, pattern)) { + handler(req, res); + return true; + } + } + return false; +} + +inline bool +Server::process_request(Stream &strm, bool last_connection, + bool &connection_close, + std::function setup_request) { + const auto bufsiz = 2048; + char buf[bufsiz]; + + detail::stream_line_reader reader(strm, buf, bufsiz); + + // Connection has been closed on client + if (!reader.getline()) { return false; } + + Request req; + Response res; + + res.version = "HTTP/1.1"; + + // Check if the request URI doesn't exceed the limit + if (reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { + res.status = 414; + write_response(strm, last_connection, req, res); + return true; + } + + // Request line and headers + if (!parse_request_line(reader.ptr(), req) || + !detail::read_headers(strm, req.headers)) { + res.status = 400; + write_response(strm, last_connection, req, res); + return true; + } + + if (req.get_header_value("Connection") == "close") { + connection_close = true; + } + + req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str()); + + // Body + if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { + if (!detail::read_content( + strm, req, payload_max_length_, res.status, Progress(), + [&](const char *buf, size_t n) { req.body.append(buf, n); })) { + write_response(strm, last_connection, req, res); + return true; + } + + const auto &content_type = req.get_header_value("Content-Type"); + + if (!content_type.find("application/x-www-form-urlencoded")) { + detail::parse_query_text(req.body, req.params); + } else if (!content_type.find("multipart/form-data")) { + std::string boundary; + if (!detail::parse_multipart_boundary(content_type, boundary) || + !detail::parse_multipart_formdata(boundary, req.body, req.files)) { + res.status = 400; + write_response(strm, last_connection, req, res); + return true; + } + } + } + + // TODO: Add additional request info + if (setup_request) { setup_request(req); } + + if (routing(req, res)) { + if (res.status == -1) { res.status = 200; } + } else { + res.status = 404; + } + + write_response(strm, last_connection, req, res); + return true; +} + +inline bool Server::is_valid() const { return true; } + +inline bool Server::read_and_close_socket(socket_t sock) { + return detail::read_and_close_socket( + sock, keep_alive_max_count_, + [this](Stream &strm, bool last_connection, bool &connection_close) { + return process_request(strm, last_connection, connection_close); + }); +} + +// HTTP client implementation +inline Client::Client(const char *host, int port, time_t timeout_sec) + : host_(host), port_(port), timeout_sec_(timeout_sec), + host_and_port_(host_ + ":" + std::to_string(port_)) {} + +inline Client::~Client() {} + +inline bool Client::is_valid() const { return true; } + +inline socket_t Client::create_client_socket() const { + return detail::create_socket( + host_.c_str(), port_, [=](socket_t sock, struct addrinfo &ai) -> bool { + detail::set_nonblocking(sock, true); + + auto ret = connect(sock, ai.ai_addr, static_cast(ai.ai_addrlen)); + if (ret < 0) { + if (detail::is_connection_error() || + !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) { + detail::close_socket(sock); + return false; + } + } + + detail::set_nonblocking(sock, false); + return true; + }); +} + +inline bool Client::read_response_line(Stream &strm, Response &res) { + const auto bufsiz = 2048; + char buf[bufsiz]; + + detail::stream_line_reader reader(strm, buf, bufsiz); + + if (!reader.getline()) { return false; } + + const static std::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n"); + + std::cmatch m; + if (std::regex_match(reader.ptr(), m, re)) { + res.version = std::string(m[1]); + res.status = std::stoi(std::string(m[2])); + } + + return true; +} + +inline bool Client::send(Request &req, Response &res) { + if (req.path.empty()) { return false; } + + auto sock = create_client_socket(); + if (sock == INVALID_SOCKET) { return false; } + + return read_and_close_socket(sock, req, res); +} + +inline void Client::write_request(Stream &strm, Request &req) { + BufferStream bstrm; + + // Request line + auto path = detail::encode_url(req.path); + + bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str()); + + // Headers + if (!req.has_header("Host")) { + if (is_ssl()) { + if (port_ == 443) { + req.set_header("Host", host_.c_str()); + } else { + req.set_header("Host", host_and_port_.c_str()); + } + } else { + if (port_ == 80) { + req.set_header("Host", host_.c_str()); + } else { + req.set_header("Host", host_and_port_.c_str()); + } + } + } + + if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); } + + if (!req.has_header("User-Agent")) { + req.set_header("User-Agent", "cpp-httplib/0.2"); + } + + // TODO: Support KeepAlive connection + // if (!req.has_header("Connection")) { + req.set_header("Connection", "close"); + // } + + if (req.body.empty()) { + if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { + req.set_header("Content-Length", "0"); + } + } else { + if (!req.has_header("Content-Type")) { + req.set_header("Content-Type", "text/plain"); + } + + if (!req.has_header("Content-Length")) { + auto length = std::to_string(req.body.size()); + req.set_header("Content-Length", length.c_str()); + } + } + + detail::write_headers(bstrm, req); + + // Body + if (!req.body.empty()) { bstrm.write(req.body.c_str(), req.body.size()); } + + // Flush buffer + auto &data = bstrm.get_buffer(); + strm.write(data.data(), data.size()); +} + +inline bool Client::process_request(Stream &strm, Request &req, Response &res, + bool &connection_close) { + // Send request + write_request(strm, req); + + // Receive response and headers + if (!read_response_line(strm, res) || + !detail::read_headers(strm, res.headers)) { + return false; + } + + if (res.get_header_value("Connection") == "close" || + res.version == "HTTP/1.0") { + connection_close = true; + } + + // Body + if (req.method != "HEAD") { + ContentReceiver out = [&](const char *buf, size_t n) { + res.body.append(buf, n); + }; + + if (res.content_receiver) { + out = [&](const char *buf, size_t n) { res.content_receiver(buf, n); }; + } + + int dummy_status; + if (!detail::read_content(strm, res, std::numeric_limits::max(), + dummy_status, res.progress, out)) { + return false; + } + } + + return true; +} + +inline bool Client::read_and_close_socket(socket_t sock, Request &req, + Response &res) { + return detail::read_and_close_socket( + sock, 0, + [&](Stream &strm, bool /*last_connection*/, bool &connection_close) { + return process_request(strm, req, res, connection_close); + }); +} + +inline bool Client::is_ssl() const { return false; } + +inline std::shared_ptr Client::Get(const char *path, + Progress progress) { + return Get(path, Headers(), progress); +} + +inline std::shared_ptr +Client::Get(const char *path, const Headers &headers, Progress progress) { + Request req; + req.method = "GET"; + req.path = path; + req.headers = headers; + + auto res = std::make_shared(); + res->progress = progress; + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Get(const char *path, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, Headers(), content_receiver, progress); +} + +inline std::shared_ptr Client::Get(const char *path, + const Headers &headers, + ContentReceiver content_receiver, + Progress progress) { + Request req; + req.method = "GET"; + req.path = path; + req.headers = headers; + + auto res = std::make_shared(); + res->content_receiver = content_receiver; + res->progress = progress; + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Head(const char *path) { + return Head(path, Headers()); +} + +inline std::shared_ptr Client::Head(const char *path, + const Headers &headers) { + Request req; + req.method = "HEAD"; + req.headers = headers; + req.path = path; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Post(const char *path, + const std::string &body, + const char *content_type) { + return Post(path, Headers(), body, content_type); +} + +inline std::shared_ptr Client::Post(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "POST"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Post(const char *path, + const Params ¶ms) { + return Post(path, Headers(), params); +} + +inline std::shared_ptr +Client::Post(const char *path, const Headers &headers, const Params ¶ms) { + std::string query; + for (auto it = params.begin(); it != params.end(); ++it) { + if (it != params.begin()) { query += "&"; } + query += it->first; + query += "="; + query += detail::encode_url(it->second); + } + + return Post(path, headers, query, "application/x-www-form-urlencoded"); +} + +inline std::shared_ptr Client::Put(const char *path, + const std::string &body, + const char *content_type) { + return Put(path, Headers(), body, content_type); +} + +inline std::shared_ptr Client::Put(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "PUT"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Patch(const char *path, + const std::string &body, + const char *content_type) { + return Patch(path, Headers(), body, content_type); +} + +inline std::shared_ptr Client::Patch(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "PATCH"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Delete(const char *path, + const std::string &body, + const char *content_type) { + return Delete(path, Headers(), body, content_type); +} + +inline std::shared_ptr Client::Delete(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "DELETE"; + req.headers = headers; + req.path = path; + + if (content_type) { req.headers.emplace("Content-Type", content_type); } + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Options(const char *path) { + return Options(path, Headers()); +} + +inline std::shared_ptr Client::Options(const char *path, + const Headers &headers) { + Request req; + req.method = "OPTIONS"; + req.path = path; + req.headers = headers; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +/* + * SSL Implementation + */ +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +namespace detail { + +template +inline bool +read_and_close_socket_ssl(socket_t sock, size_t keep_alive_max_count, + // TODO: OpenSSL 1.0.2 occasionally crashes... + // The upcoming 1.1.0 is going to be thread safe. + SSL_CTX *ctx, std::mutex &ctx_mutex, + U SSL_connect_or_accept, V setup, T callback) { + SSL *ssl = nullptr; + { + std::lock_guard guard(ctx_mutex); + ssl = SSL_new(ctx); + } + + if (!ssl) { + close_socket(sock); + return false; + } + + auto bio = BIO_new_socket(sock, BIO_NOCLOSE); + SSL_set_bio(ssl, bio, bio); + + if (!setup(ssl)) { + SSL_shutdown(ssl); + { + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); + } + + close_socket(sock); + return false; + } + + bool ret = false; + + if (SSL_connect_or_accept(ssl) == 1) { + if (keep_alive_max_count > 0) { + auto count = keep_alive_max_count; + while (count > 0 && + detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, + CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { + SSLSocketStream strm(sock, ssl); + auto last_connection = count == 1; + auto connection_close = false; + + ret = callback(ssl, strm, last_connection, connection_close); + if (!ret || connection_close) { break; } + + count--; + } + } else { + SSLSocketStream strm(sock, ssl); + auto dummy_connection_close = false; + ret = callback(ssl, strm, true, dummy_connection_close); + } + } + + SSL_shutdown(ssl); + { + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); + } + + close_socket(sock); + + return ret; +} + +class SSLInit { +public: + SSLInit() { + SSL_load_error_strings(); + SSL_library_init(); + } + + ~SSLInit() { ERR_free_strings(); } +}; + +static SSLInit sslinit_; + +} // namespace detail + +// SSL socket stream implementation +inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl) + : sock_(sock), ssl_(ssl) {} + +inline SSLSocketStream::~SSLSocketStream() {} + +inline int SSLSocketStream::read(char *ptr, size_t size) { + if (SSL_pending(ssl_) > 0 || + detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, + CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { + return SSL_read(ssl_, ptr, size); + } + return -1; +} + +inline int SSLSocketStream::write(const char *ptr, size_t size) { + return SSL_write(ssl_, ptr, size); +} + +inline int SSLSocketStream::write(const char *ptr) { + return write(ptr, strlen(ptr)); +} + +inline std::string SSLSocketStream::get_remote_addr() const { + return detail::get_remote_addr(sock_); +} + +// SSL HTTP server implementation +inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, + const char *client_ca_cert_file_path, + const char *client_ca_cert_dir_path) { + ctx_ = SSL_CTX_new(SSLv23_server_method()); + + if (ctx_) { + SSL_CTX_set_options(ctx_, + SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION | + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + + // auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + // SSL_CTX_set_tmp_ecdh(ctx_, ecdh); + // EC_KEY_free(ecdh); + + if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || + SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != + 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } else if (client_ca_cert_file_path || client_ca_cert_dir_path) { + // if (client_ca_cert_file_path) { + // auto list = SSL_load_client_CA_file(client_ca_cert_file_path); + // SSL_CTX_set_client_CA_list(ctx_, list); + // } + + SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path, + client_ca_cert_dir_path); + + SSL_CTX_set_verify( + ctx_, + SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE, + nullptr); + } + } +} + +inline SSLServer::~SSLServer() { + if (ctx_) { SSL_CTX_free(ctx_); } +} + +inline bool SSLServer::is_valid() const { return ctx_; } + +inline bool SSLServer::read_and_close_socket(socket_t sock) { + return detail::read_and_close_socket_ssl( + sock, keep_alive_max_count_, ctx_, ctx_mutex_, SSL_accept, + [](SSL * /*ssl*/) { return true; }, + [this](SSL *ssl, Stream &strm, bool last_connection, + bool &connection_close) { + return process_request(strm, last_connection, connection_close, + [&](Request &req) { req.ssl = ssl; }); + }); +} + +// SSL HTTP client implementation +inline SSLClient::SSLClient(const char *host, int port, time_t timeout_sec, + const char *client_cert_path, + const char *client_key_path) + : Client(host, port, timeout_sec) { + ctx_ = SSL_CTX_new(SSLv23_client_method()); + + detail::split(&host_[0], &host_[host_.size()], '.', + [&](const char *b, const char *e) { + host_components_.emplace_back(std::string(b, e)); + }); + if (client_cert_path && client_key_path) { + if (SSL_CTX_use_certificate_file(ctx_, client_cert_path, + SSL_FILETYPE_PEM) != 1 || + SSL_CTX_use_PrivateKey_file(ctx_, client_key_path, SSL_FILETYPE_PEM) != + 1) { + SSL_CTX_free(ctx_); + ctx_ = nullptr; + } + } +} + +inline SSLClient::~SSLClient() { + if (ctx_) { SSL_CTX_free(ctx_); } +} + +inline bool SSLClient::is_valid() const { return ctx_; } + +inline void SSLClient::set_ca_cert_path(const char *ca_cert_file_path, + const char *ca_cert_dir_path) { + if (ca_cert_file_path) { ca_cert_file_path_ = ca_cert_file_path; } + if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; } +} + +inline void SSLClient::enable_server_certificate_verification(bool enabled) { + server_certificate_verification_ = enabled; +} + +inline long SSLClient::get_openssl_verify_result() const { + return verify_result_; +} + +inline bool SSLClient::read_and_close_socket(socket_t sock, Request &req, + Response &res) { + + return is_valid() && + detail::read_and_close_socket_ssl( + sock, 0, ctx_, ctx_mutex_, + [&](SSL *ssl) { + if (ca_cert_file_path_.empty()) { + SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr); + } else { + if (!SSL_CTX_load_verify_locations( + ctx_, ca_cert_file_path_.c_str(), nullptr)) { + return false; + } + SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr); + } + + if (SSL_connect(ssl) != 1) { return false; } + + if (server_certificate_verification_) { + verify_result_ = SSL_get_verify_result(ssl); + + if (verify_result_ != X509_V_OK) { return false; } + + auto server_cert = SSL_get_peer_certificate(ssl); + + if (server_cert == nullptr) { return false; } + + if (!verify_host(server_cert)) { + X509_free(server_cert); + return false; + } + X509_free(server_cert); + } + + return true; + }, + [&](SSL *ssl) { + SSL_set_tlsext_host_name(ssl, host_.c_str()); + return true; + }, + [&](SSL * /*ssl*/, Stream &strm, bool /*last_connection*/, + bool &connection_close) { + return process_request(strm, req, res, connection_close); + }); +} + +inline bool SSLClient::is_ssl() const { return true; } + +inline bool SSLClient::verify_host(X509 *server_cert) const { + /* Quote from RFC2818 section 3.1 "Server Identity" + + If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. Otherwise, the (most specific) Common Name + field in the Subject field of the certificate MUST be used. Although + the use of the Common Name is existing practice, it is deprecated and + Certification Authorities are encouraged to use the dNSName instead. + + Matching is performed using the matching rules specified by + [RFC2459]. If more than one identity of a given type is present in + the certificate (e.g., more than one dNSName name, a match in any one + of the set is considered acceptable.) Names may contain the wildcard + character * which is considered to match any single domain name + component or component fragment. E.g., *.a.com matches foo.a.com but + not bar.foo.a.com. f*.com matches foo.com but not bar.com. + + In some cases, the URI is specified as an IP address rather than a + hostname. In this case, the iPAddress subjectAltName must be present + in the certificate and must exactly match the IP in the URI. + + */ + return verify_host_with_subject_alt_name(server_cert) || + verify_host_with_common_name(server_cert); +} + +inline bool +SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { + auto ret = false; + + auto type = GEN_DNS; + + struct in6_addr addr6; + struct in_addr addr; + size_t addr_len = 0; + + if (inet_pton(AF_INET6, host_.c_str(), &addr6)) { + type = GEN_IPADD; + addr_len = sizeof(struct in6_addr); + } else if (inet_pton(AF_INET, host_.c_str(), &addr)) { + type = GEN_IPADD; + addr_len = sizeof(struct in_addr); + } + + auto alt_names = static_cast( + X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr)); + + if (alt_names) { + auto dsn_matched = false; + auto ip_mached = false; + + auto count = sk_GENERAL_NAME_num(alt_names); + + for (auto i = 0; i < count && !dsn_matched; i++) { + auto val = sk_GENERAL_NAME_value(alt_names, i); + if (val->type == type) { + auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5); + auto name_len = (size_t)ASN1_STRING_length(val->d.ia5); + + if (strlen(name) == name_len) { + switch (type) { + case GEN_DNS: dsn_matched = check_host_name(name, name_len); break; + + case GEN_IPADD: + if (!memcmp(&addr6, name, addr_len) || + !memcmp(&addr, name, addr_len)) { + ip_mached = true; + } + break; + } + } + } + } + + if (dsn_matched || ip_mached) { ret = true; } + } + + GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names); + + return ret; +} + +inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const { + const auto subject_name = X509_get_subject_name(server_cert); + + if (subject_name != nullptr) { + char name[BUFSIZ]; + auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName, + name, sizeof(name)); + + if (name_len != -1) { return check_host_name(name, name_len); } + } + + return false; +} + +inline bool SSLClient::check_host_name(const char *pattern, + size_t pattern_len) const { + if (host_.size() == pattern_len && host_ == pattern) { return true; } + + // Wildcard match + // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484 + std::vector pattern_components; + detail::split(&pattern[0], &pattern[pattern_len], '.', + [&](const char *b, const char *e) { + pattern_components.emplace_back(std::string(b, e)); + }); + + if (host_components_.size() != pattern_components.size()) { return false; } + + auto itr = pattern_components.begin(); + for (const auto &h : host_components_) { + auto &p = *itr; + if (p != h && p != "*") { + auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' && + !p.compare(0, p.size() - 1, h)); + if (!partial_match) { return false; } + } + ++itr; + } + + return true; +} +#endif + +} // namespace httplib + +#endif // CPPHTTPLIB_HTTPLIB_H diff --git a/ext/curl-7.58.0/Win32/include/curl/curl.h b/ext/curl-7.58.0/Win32/include/curl/curl.h new file mode 100644 index 0000000..7680acd --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/curl.h @@ -0,0 +1,2751 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "system.h" /* determine things run-time */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS, + CURLKHTYPE_ECDSA, + CURLKHTYPE_ED25519 +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of milliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + + /* The request target, instead of extracted from the URL */ + CINIT(REQUEST_TARGET, STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CINIT(SOCKS5_AUTH, LONG, 267), + + /* Enable/disable SSH compression */ + CINIT(SSH_COMPRESSION, LONG, 268), + + /* Post MIME data. */ + CINIT(MIMEPOST, OBJECTPOINT, 269), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +/* Special size_t value signaling a zero-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + release */ +CURL_EXTERN int curl_strequal(const char *s1, const char *s2); +CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); + +/* Mime/form handling support. */ +typedef struct curl_mime_s curl_mime; /* Mime context. */ +typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); + +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); + +/* Old form API. */ +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_PTR 0x400000 /* same as SLIST */ +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 49 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_FIFTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FIFTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + + /* These fields were added in CURLVERSION_FIFTH */ + + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is supported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ +#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/ext/curl-7.58.0/Win32/include/curl/curlver.h b/ext/curl-7.58.0/Win32/include/curl/curlver.h new file mode 100644 index 0000000..6d93cc1 --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.58.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 58 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x073a00 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date follows this template: + * + * "2007-11-23" + */ +#define LIBCURL_TIMESTAMP "2018-01-24" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/ext/curl-7.58.0/Win32/include/curl/easy.h b/ext/curl-7.58.0/Win32/include/curl/easy.h new file mode 100644 index 0000000..752c504 --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/curl-7.58.0/Win32/include/curl/mprintf.h b/ext/curl-7.58.0/Win32/include/curl/mprintf.h new file mode 100644 index 0000000..e20f546 --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/ext/curl-7.58.0/Win32/include/curl/multi.h b/ext/curl-7.58.0/Win32/include/curl/multi.h new file mode 100644 index 0000000..911c91d --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/multi.h @@ -0,0 +1,439 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/ext/curl-7.58.0/Win32/include/curl/stdcheaders.h b/ext/curl-7.58.0/Win32/include/curl/stdcheaders.h new file mode 100644 index 0000000..027b6f4 --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/ext/curl-7.58.0/Win32/include/curl/system.h b/ext/curl-7.58.0/Win32/include/curl/system.h new file mode 100644 index 0000000..07bbd9c --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/system.h @@ -0,0 +1,473 @@ +#ifndef __CURL_SYSTEM_H +#define __CURL_SYSTEM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Try to keep one section per platform, compiler and architecture, otherwise, + * if an existing section is reused for a different one and later on the + * original is adjusted, probably the piggybacking one can be adversely + * changed. + * + * In order to differentiate between platforms/compilers/architectures use + * only compiler built in predefined preprocessor symbols. + * + * curl_off_t + * ---------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit + * wide signed integral data type. The width of this data type must remain + * constant and independent of any possible large file support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit + * wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall + * only be violated if off_t is the only 64-bit data type available and the + * size of off_t is independent of large file support settings. Keep your + * build on the safe side avoiding an off_t gating. If you have a 64-bit + * off_t then take for sure that another 64-bit data type exists, dig deeper + * and you will find it. + * + */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SALFORDC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TURBOC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__LCC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__MWERKS__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(_WIN32_WCE) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__MINGW32__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_WS2TCPIP_H 1 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TINYC__) /* also known as tcc */ + +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || defined(__sparcv8)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +/* generic "safe guess" on old 32 bit style */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +#endif + +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + + +/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ +/* ws2tcpip.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_WS2TCPIP_H +# include +# include +# include +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* __CURL_SYSTEM_H */ diff --git a/ext/curl-7.58.0/Win32/include/curl/typecheck-gcc.h b/ext/curl-7.58.0/Win32/include/curl/typecheck-gcc.h new file mode 100644 index 0000000..10c74c7 --- /dev/null +++ b/ext/curl-7.58.0/Win32/include/curl/typecheck-gcc.h @@ -0,0 +1,683 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!_curl_is_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + if(_curl_is_tlssessioninfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ + _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + if(_curl_is_certinfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_certinfo *)) \ + _curl_easy_getinfo_err_curl_certinfo(); \ + if(_curl_is_socket_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_socket_t)) \ + _curl_easy_getinfo_err_curl_socket(); \ + if(_curl_is_off_t_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_tlssessioninfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_certinfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, + "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_CAINFO || \ + (option) == CURLOPT_PROXY_CAPATH || \ + (option) == CURLOPT_PROXY_CRLFILE || \ + (option) == CURLOPT_PROXY_KEYPASSWD || \ + (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSLCERT || \ + (option) == CURLOPT_PROXY_SSLCERTTYPE || \ + (option) == CURLOPT_PROXY_SSLKEY || \ + (option) == CURLOPT_PROXY_SSLKEYTYPE || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ + (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) + +/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ +#define _curl_is_tlssessioninfo_info(info) \ + (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) + +/* true if info expects a pointer to struct curl_certinfo * argument */ +#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) + +/* true if info expects a pointer to struct curl_socket_t argument */ +#define _curl_is_socket_info(info) \ + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define _curl_is_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (_curl_is_NULL(expr) || \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func) *, type)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), __typeof__(fread) *) || \ + _curl_callback_compatible((expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ + _curl_callback_compatible((expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_opensocket_callback) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (*_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (*_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/ext/curl-7.58.0/Win32/lib/libcurl_a.lib b/ext/curl-7.58.0/Win32/lib/libcurl_a.lib new file mode 100644 index 0000000..241a0e8 Binary files /dev/null and b/ext/curl-7.58.0/Win32/lib/libcurl_a.lib differ diff --git a/ext/curl-7.58.0/Win32/lib/libcurl_a_debug.lib b/ext/curl-7.58.0/Win32/lib/libcurl_a_debug.lib new file mode 100644 index 0000000..ee9efe5 Binary files /dev/null and b/ext/curl-7.58.0/Win32/lib/libcurl_a_debug.lib differ diff --git a/ext/curl-7.58.0/x64/include/curl/curl.h b/ext/curl-7.58.0/x64/include/curl/curl.h new file mode 100644 index 0000000..7680acd --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/curl.h @@ -0,0 +1,2751 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "system.h" /* determine things run-time */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS, + CURLKHTYPE_ECDSA, + CURLKHTYPE_ED25519 +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of milliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + + /* The request target, instead of extracted from the URL */ + CINIT(REQUEST_TARGET, STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CINIT(SOCKS5_AUTH, LONG, 267), + + /* Enable/disable SSH compression */ + CINIT(SSH_COMPRESSION, LONG, 268), + + /* Post MIME data. */ + CINIT(MIMEPOST, OBJECTPOINT, 269), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +/* Special size_t value signaling a zero-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + release */ +CURL_EXTERN int curl_strequal(const char *s1, const char *s2); +CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); + +/* Mime/form handling support. */ +typedef struct curl_mime_s curl_mime; /* Mime context. */ +typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); + +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); + +/* Old form API. */ +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_PTR 0x400000 /* same as SLIST */ +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 49 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_FIFTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FIFTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + + /* These fields were added in CURLVERSION_FIFTH */ + + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is supported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ +#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/ext/curl-7.58.0/x64/include/curl/curlver.h b/ext/curl-7.58.0/x64/include/curl/curlver.h new file mode 100644 index 0000000..6d93cc1 --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.58.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 58 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x073a00 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date follows this template: + * + * "2007-11-23" + */ +#define LIBCURL_TIMESTAMP "2018-01-24" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/ext/curl-7.58.0/x64/include/curl/easy.h b/ext/curl-7.58.0/x64/include/curl/easy.h new file mode 100644 index 0000000..752c504 --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/curl-7.58.0/x64/include/curl/mprintf.h b/ext/curl-7.58.0/x64/include/curl/mprintf.h new file mode 100644 index 0000000..e20f546 --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/ext/curl-7.58.0/x64/include/curl/multi.h b/ext/curl-7.58.0/x64/include/curl/multi.h new file mode 100644 index 0000000..911c91d --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/multi.h @@ -0,0 +1,439 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/ext/curl-7.58.0/x64/include/curl/stdcheaders.h b/ext/curl-7.58.0/x64/include/curl/stdcheaders.h new file mode 100644 index 0000000..027b6f4 --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/ext/curl-7.58.0/x64/include/curl/system.h b/ext/curl-7.58.0/x64/include/curl/system.h new file mode 100644 index 0000000..07bbd9c --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/system.h @@ -0,0 +1,473 @@ +#ifndef __CURL_SYSTEM_H +#define __CURL_SYSTEM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Try to keep one section per platform, compiler and architecture, otherwise, + * if an existing section is reused for a different one and later on the + * original is adjusted, probably the piggybacking one can be adversely + * changed. + * + * In order to differentiate between platforms/compilers/architectures use + * only compiler built in predefined preprocessor symbols. + * + * curl_off_t + * ---------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit + * wide signed integral data type. The width of this data type must remain + * constant and independent of any possible large file support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit + * wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall + * only be violated if off_t is the only 64-bit data type available and the + * size of off_t is independent of large file support settings. Keep your + * build on the safe side avoiding an off_t gating. If you have a 64-bit + * off_t then take for sure that another 64-bit data type exists, dig deeper + * and you will find it. + * + */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SALFORDC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TURBOC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__LCC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__MWERKS__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(_WIN32_WCE) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__MINGW32__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_WS2TCPIP_H 1 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TINYC__) /* also known as tcc */ + +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || defined(__sparcv8)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +/* generic "safe guess" on old 32 bit style */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +#endif + +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + + +/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ +/* ws2tcpip.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_WS2TCPIP_H +# include +# include +# include +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* __CURL_SYSTEM_H */ diff --git a/ext/curl-7.58.0/x64/include/curl/typecheck-gcc.h b/ext/curl-7.58.0/x64/include/curl/typecheck-gcc.h new file mode 100644 index 0000000..10c74c7 --- /dev/null +++ b/ext/curl-7.58.0/x64/include/curl/typecheck-gcc.h @@ -0,0 +1,683 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!_curl_is_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + if(_curl_is_tlssessioninfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ + _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + if(_curl_is_certinfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_certinfo *)) \ + _curl_easy_getinfo_err_curl_certinfo(); \ + if(_curl_is_socket_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_socket_t)) \ + _curl_easy_getinfo_err_curl_socket(); \ + if(_curl_is_off_t_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_tlssessioninfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_certinfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, + "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_CAINFO || \ + (option) == CURLOPT_PROXY_CAPATH || \ + (option) == CURLOPT_PROXY_CRLFILE || \ + (option) == CURLOPT_PROXY_KEYPASSWD || \ + (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSLCERT || \ + (option) == CURLOPT_PROXY_SSLCERTTYPE || \ + (option) == CURLOPT_PROXY_SSLKEY || \ + (option) == CURLOPT_PROXY_SSLKEYTYPE || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ + (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) + +/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ +#define _curl_is_tlssessioninfo_info(info) \ + (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) + +/* true if info expects a pointer to struct curl_certinfo * argument */ +#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) + +/* true if info expects a pointer to struct curl_socket_t argument */ +#define _curl_is_socket_info(info) \ + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define _curl_is_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (_curl_is_NULL(expr) || \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func) *, type)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), __typeof__(fread) *) || \ + _curl_callback_compatible((expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ + _curl_callback_compatible((expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_opensocket_callback) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (*_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (*_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/ext/curl-7.58.0/x64/lib/libcurl_a.lib b/ext/curl-7.58.0/x64/lib/libcurl_a.lib new file mode 100644 index 0000000..7efe65b Binary files /dev/null and b/ext/curl-7.58.0/x64/lib/libcurl_a.lib differ diff --git a/ext/curl-7.58.0/x64/lib/libcurl_a_debug.lib b/ext/curl-7.58.0/x64/lib/libcurl_a_debug.lib new file mode 100644 index 0000000..867964b Binary files /dev/null and b/ext/curl-7.58.0/x64/lib/libcurl_a_debug.lib differ diff --git a/ext/ed25519-amd64-asm/batch.c b/ext/ed25519-amd64-asm/batch.c new file mode 100644 index 0000000..955392e --- /dev/null +++ b/ext/ed25519-amd64-asm/batch.c @@ -0,0 +1,94 @@ +#include "crypto_sign.h" + +#include "crypto_verify_32.h" +#include "crypto_hash_sha512.h" +#include "randombytes.h" + +#include "ge25519.h" +#include "hram.h" + +#define MAXBATCH 64 + +int crypto_sign_open_batch( + unsigned char* const m[],unsigned long long mlen[], + unsigned char* const sm[],const unsigned long long smlen[], + unsigned char* const pk[], + unsigned long long num + ) +{ + int ret = 0; + unsigned long long i, j; + shortsc25519 r[MAXBATCH]; + sc25519 scalars[2*MAXBATCH+1]; + ge25519 points[2*MAXBATCH+1]; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned long long batchsize; + + for (i = 0;i < num;++i) mlen[i] = -1; + + while (num >= 3) { + batchsize = num; + if (batchsize > MAXBATCH) batchsize = MAXBATCH; + + for (i = 0;i < batchsize;++i) + if (smlen[i] < 64) goto fallback; + + randombytes((unsigned char*)r,sizeof(shortsc25519) * batchsize); + + /* Computing scalars[0] = ((r1s1 + r2s2 + ...)) */ + for(i=0;icaller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: tp_stack = tp +# asm 1: movq tp_stack=stack64#8 +# asm 2: movq tp_stack=56(%rsp) +movq %rdi,56(%rsp) + +# qhasm: pos *= 768 +# asm 1: imulq $768,pos=int64#1 +# asm 2: imulq $768,pos=%rdi +imulq $768,%rsi,%rdi + +# qhasm: mask = b +# asm 1: mov mask=int64#2 +# asm 2: mov mask=%rsi +mov %rdx,%rsi + +# qhasm: (int64) mask >>= 7 +# asm 1: sar $7,u=int64#5 +# asm 2: mov u=%r8 +mov %rdx,%r8 + +# qhasm: u += mask +# asm 1: add tysubx0=int64#2 +# asm 2: mov $1,>tysubx0=%rsi +mov $1,%rsi + +# qhasm: tysubx1 = 0 +# asm 1: mov $0,>tysubx1=int64#6 +# asm 2: mov $0,>tysubx1=%r9 +mov $0,%r9 + +# qhasm: tysubx2 = 0 +# asm 1: mov $0,>tysubx2=int64#7 +# asm 2: mov $0,>tysubx2=%rax +mov $0,%rax + +# qhasm: tysubx3 = 0 +# asm 1: mov $0,>tysubx3=int64#8 +# asm 2: mov $0,>tysubx3=%r10 +mov $0,%r10 + +# qhasm: txaddy0 = 1 +# asm 1: mov $1,>txaddy0=int64#9 +# asm 2: mov $1,>txaddy0=%r11 +mov $1,%r11 + +# qhasm: txaddy1 = 0 +# asm 1: mov $0,>txaddy1=int64#10 +# asm 2: mov $0,>txaddy1=%r12 +mov $0,%r12 + +# qhasm: txaddy2 = 0 +# asm 1: mov $0,>txaddy2=int64#11 +# asm 2: mov $0,>txaddy2=%r13 +mov $0,%r13 + +# qhasm: txaddy3 = 0 +# asm 1: mov $0,>txaddy3=int64#12 +# asm 2: mov $0,>txaddy3=%r14 +mov $0,%r14 + +# qhasm: =? u - 1 +# asm 1: cmp $1,t=int64#13 +# asm 2: movq 0(t=%r15 +movq 0(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 8(t=%r15 +movq 8(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 16(t=%r15 +movq 16(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 24(t=%r15 +movq 24(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 32(t=%r15 +movq 32(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 40(t=%r15 +movq 40(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 48(t=%r15 +movq 48(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 56(t=%r15 +movq 56(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 96(t=%r15 +movq 96(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 104(t=%r15 +movq 104(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 112(t=%r15 +movq 112(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 120(t=%r15 +movq 120(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 128(t=%r15 +movq 128(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 136(t=%r15 +movq 136(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 144(t=%r15 +movq 144(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 152(t=%r15 +movq 152(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 192(t=%r15 +movq 192(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 200(t=%r15 +movq 200(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 208(t=%r15 +movq 208(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 216(t=%r15 +movq 216(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 224(t=%r15 +movq 224(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 232(t=%r15 +movq 232(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 240(t=%r15 +movq 240(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 248(t=%r15 +movq 248(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 288(t=%r15 +movq 288(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 296(t=%r15 +movq 296(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 304(t=%r15 +movq 304(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 312(t=%r15 +movq 312(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 320(t=%r15 +movq 320(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 328(t=%r15 +movq 328(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 336(t=%r15 +movq 336(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 344(t=%r15 +movq 344(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 384(t=%r15 +movq 384(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 392(t=%r15 +movq 392(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 400(t=%r15 +movq 400(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 408(t=%r15 +movq 408(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 416(t=%r15 +movq 416(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 424(t=%r15 +movq 424(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 432(t=%r15 +movq 432(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 440(t=%r15 +movq 440(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 480(t=%r15 +movq 480(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 488(t=%r15 +movq 488(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 496(t=%r15 +movq 496(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 504(t=%r15 +movq 504(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 512(t=%r15 +movq 512(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 520(t=%r15 +movq 520(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 528(t=%r15 +movq 528(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 536(t=%r15 +movq 536(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 576(t=%r15 +movq 576(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 584(t=%r15 +movq 584(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 592(t=%r15 +movq 592(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 600(t=%r15 +movq 600(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 608(t=%r15 +movq 608(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 616(t=%r15 +movq 616(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 624(t=%r15 +movq 624(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 632(t=%r15 +movq 632(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 672(t=%r15 +movq 672(%rcx,%rdi),%r15 + +# qhasm: tysubx0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 680(t=%r15 +movq 680(%rcx,%rdi),%r15 + +# qhasm: tysubx1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 688(t=%r15 +movq 688(%rcx,%rdi),%r15 + +# qhasm: tysubx2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 696(t=%r15 +movq 696(%rcx,%rdi),%r15 + +# qhasm: tysubx3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 704(t=%r15 +movq 704(%rcx,%rdi),%r15 + +# qhasm: txaddy0 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 712(t=%r15 +movq 712(%rcx,%rdi),%r15 + +# qhasm: txaddy1 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 720(t=%r15 +movq 720(%rcx,%rdi),%r15 + +# qhasm: txaddy2 = t if = +# asm 1: cmove t=int64#13 +# asm 2: movq 728(t=%r15 +movq 728(%rcx,%rdi),%r15 + +# qhasm: txaddy3 = t if = +# asm 1: cmove t=int64#13 +# asm 2: mov t=%r15 +mov %rsi,%r15 + +# qhasm: tysubx0 = txaddy0 if signed< +# asm 1: cmovl t=int64#13 +# asm 2: mov t=%r15 +mov %r9,%r15 + +# qhasm: tysubx1 = txaddy1 if signed< +# asm 1: cmovl t=int64#13 +# asm 2: mov t=%r15 +mov %rax,%r15 + +# qhasm: tysubx2 = txaddy2 if signed< +# asm 1: cmovl t=int64#13 +# asm 2: mov t=%r15 +mov %r10,%r15 + +# qhasm: tysubx3 = txaddy3 if signed< +# asm 1: cmovl tp=int64#13 +# asm 2: movq tp=%r15 +movq 56(%rsp),%r15 + +# qhasm: *(uint64 *)(tp + 0) = tysubx0 +# asm 1: movq tt2d0=int64#2 +# asm 2: mov $0,>tt2d0=%rsi +mov $0,%rsi + +# qhasm: tt2d1 = 0 +# asm 1: mov $0,>tt2d1=int64#6 +# asm 2: mov $0,>tt2d1=%r9 +mov $0,%r9 + +# qhasm: tt2d2 = 0 +# asm 1: mov $0,>tt2d2=int64#7 +# asm 2: mov $0,>tt2d2=%rax +mov $0,%rax + +# qhasm: tt2d3 = 0 +# asm 1: mov $0,>tt2d3=int64#8 +# asm 2: mov $0,>tt2d3=%r10 +mov $0,%r10 + +# qhasm: =? u - 1 +# asm 1: cmp $1,t=int64#9 +# asm 2: movq 64(t=%r11 +movq 64(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 72(t=%r11 +movq 72(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 80(t=%r11 +movq 80(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 88(t=%r11 +movq 88(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 160(t=%r11 +movq 160(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 168(t=%r11 +movq 168(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 176(t=%r11 +movq 176(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 184(t=%r11 +movq 184(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 256(t=%r11 +movq 256(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 264(t=%r11 +movq 264(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 272(t=%r11 +movq 272(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 280(t=%r11 +movq 280(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 352(t=%r11 +movq 352(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 360(t=%r11 +movq 360(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 368(t=%r11 +movq 368(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 376(t=%r11 +movq 376(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 448(t=%r11 +movq 448(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 456(t=%r11 +movq 456(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 464(t=%r11 +movq 464(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 472(t=%r11 +movq 472(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 544(t=%r11 +movq 544(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 552(t=%r11 +movq 552(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 560(t=%r11 +movq 560(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 568(t=%r11 +movq 568(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 640(t=%r11 +movq 640(%rcx,%rdi),%r11 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 648(t=%r11 +movq 648(%rcx,%rdi),%r11 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 656(t=%r11 +movq 656(%rcx,%rdi),%r11 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#9 +# asm 2: movq 664(t=%r11 +movq 664(%rcx,%rdi),%r11 + +# qhasm: tt2d3 = t if = +# asm 1: cmove t=int64#5 +# asm 2: movq 736(t=%r8 +movq 736(%rcx,%rdi),%r8 + +# qhasm: tt2d0 = t if = +# asm 1: cmove t=int64#5 +# asm 2: movq 744(t=%r8 +movq 744(%rcx,%rdi),%r8 + +# qhasm: tt2d1 = t if = +# asm 1: cmove t=int64#5 +# asm 2: movq 752(t=%r8 +movq 752(%rcx,%rdi),%r8 + +# qhasm: tt2d2 = t if = +# asm 1: cmove t=int64#1 +# asm 2: movq 760(t=%rdi +movq 760(%rcx,%rdi),%rdi + +# qhasm: tt2d3 = t if = +# asm 1: cmove tt0=int64#1 +# asm 2: mov $0,>tt0=%rdi +mov $0,%rdi + +# qhasm: tt1 = 0 +# asm 1: mov $0,>tt1=int64#4 +# asm 2: mov $0,>tt1=%rcx +mov $0,%rcx + +# qhasm: tt2 = 0 +# asm 1: mov $0,>tt2=int64#5 +# asm 2: mov $0,>tt2=%r8 +mov $0,%r8 + +# qhasm: tt3 = 0 +# asm 1: mov $0,>tt3=int64#9 +# asm 2: mov $0,>tt3=%r11 +mov $0,%r11 + +# qhasm: carry? tt0 -= tt2d0 +# asm 1: sub subt0=int64#10 +# asm 2: mov $0,>subt0=%r12 +mov $0,%r12 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#11 +# asm 2: mov $38,>subt1=%r13 +mov $38,%r13 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/consts.s b/ext/ed25519-amd64-asm/consts.s new file mode 100644 index 0000000..c272383 --- /dev/null +++ b/ext/ed25519-amd64-asm/consts.s @@ -0,0 +1,39 @@ +.data + +.globl crypto_sign_ed25519_amd64_64_121666 +.globl crypto_sign_ed25519_amd64_64_MU0 +.globl crypto_sign_ed25519_amd64_64_MU1 +.globl crypto_sign_ed25519_amd64_64_MU2 +.globl crypto_sign_ed25519_amd64_64_MU3 +.globl crypto_sign_ed25519_amd64_64_MU4 +.globl crypto_sign_ed25519_amd64_64_ORDER0 +.globl crypto_sign_ed25519_amd64_64_ORDER1 +.globl crypto_sign_ed25519_amd64_64_ORDER2 +.globl crypto_sign_ed25519_amd64_64_ORDER3 +.globl crypto_sign_ed25519_amd64_64_EC2D0 +.globl crypto_sign_ed25519_amd64_64_EC2D1 +.globl crypto_sign_ed25519_amd64_64_EC2D2 +.globl crypto_sign_ed25519_amd64_64_EC2D3 +.globl crypto_sign_ed25519_amd64_64_38 + +.p2align 4 + +crypto_sign_ed25519_amd64_64_121666: .quad 121666 + +crypto_sign_ed25519_amd64_64_MU0: .quad 0xED9CE5A30A2C131B +crypto_sign_ed25519_amd64_64_MU1: .quad 0x2106215D086329A7 +crypto_sign_ed25519_amd64_64_MU2: .quad 0xFFFFFFFFFFFFFFEB +crypto_sign_ed25519_amd64_64_MU3: .quad 0xFFFFFFFFFFFFFFFF +crypto_sign_ed25519_amd64_64_MU4: .quad 0x000000000000000F + +crypto_sign_ed25519_amd64_64_ORDER0: .quad 0x5812631A5CF5D3ED +crypto_sign_ed25519_amd64_64_ORDER1: .quad 0x14DEF9DEA2F79CD6 +crypto_sign_ed25519_amd64_64_ORDER2: .quad 0x0000000000000000 +crypto_sign_ed25519_amd64_64_ORDER3: .quad 0x1000000000000000 + +crypto_sign_ed25519_amd64_64_EC2D0: .quad 0xEBD69B9426B2F146 +crypto_sign_ed25519_amd64_64_EC2D1: .quad 0x00E0149A8283B156 +crypto_sign_ed25519_amd64_64_EC2D2: .quad 0x198E80F2EEF3D130 +crypto_sign_ed25519_amd64_64_EC2D3: .quad 0xA406D9DC56DFFCE7 + +crypto_sign_ed25519_amd64_64_38: .quad 38 diff --git a/ext/ed25519-amd64-asm/fe25519.h b/ext/ed25519-amd64-asm/fe25519.h new file mode 100644 index 0000000..33ffabb --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519.h @@ -0,0 +1,64 @@ +#ifndef FE25519_H +#define FE25519_H + +#define fe25519 crypto_sign_ed25519_amd64_64_fe25519 +#define fe25519_freeze crypto_sign_ed25519_amd64_64_fe25519_freeze +#define fe25519_unpack crypto_sign_ed25519_amd64_64_fe25519_unpack +#define fe25519_pack crypto_sign_ed25519_amd64_64_fe25519_pack +#define fe25519_iszero_vartime crypto_sign_ed25519_amd64_64_fe25519_iszero_vartime +#define fe25519_iseq_vartime crypto_sign_ed25519_amd64_64_fe25519_iseq_vartime +#define fe25519_cmov crypto_sign_ed25519_amd64_64_fe25519_cmov +#define fe25519_setint crypto_sign_ed25519_amd64_64_fe25519_setint +#define fe25519_neg crypto_sign_ed25519_amd64_64_fe25519_neg +#define fe25519_getparity crypto_sign_ed25519_amd64_64_fe25519_getparity +#define fe25519_add crypto_sign_ed25519_amd64_64_fe25519_add +#define fe25519_sub crypto_sign_ed25519_amd64_64_fe25519_sub +#define fe25519_mul crypto_sign_ed25519_amd64_64_fe25519_mul +#define fe25519_mul121666 crypto_sign_ed25519_amd64_64_fe25519_mul121666 +#define fe25519_square crypto_sign_ed25519_amd64_64_fe25519_square +#define fe25519_invert crypto_sign_ed25519_amd64_64_fe25519_invert +#define fe25519_pow2523 crypto_sign_ed25519_amd64_64_fe25519_pow2523 + +typedef struct +{ + unsigned long long v[4]; +} +fe25519; + +void fe25519_freeze(fe25519 *r); + +void fe25519_unpack(fe25519 *r, const unsigned char x[32]); + +void fe25519_pack(unsigned char r[32], const fe25519 *x); + +void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b); + +void fe25519_cswap(fe25519 *r, fe25519 *x, unsigned char b); + +void fe25519_setint(fe25519 *r, unsigned int v); + +void fe25519_neg(fe25519 *r, const fe25519 *x); + +unsigned char fe25519_getparity(const fe25519 *x); + +int fe25519_iszero_vartime(const fe25519 *x); + +int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y); + +void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_mul121666(fe25519 *r, const fe25519 *x); + +void fe25519_square(fe25519 *r, const fe25519 *x); + +void fe25519_pow(fe25519 *r, const fe25519 *x, const unsigned char *e); + +void fe25519_invert(fe25519 *r, const fe25519 *x); + +void fe25519_pow2523(fe25519 *r, const fe25519 *x); + +#endif diff --git a/ext/ed25519-amd64-asm/fe25519_add.s b/ext/ed25519-amd64-asm/fe25519_add.s new file mode 100644 index 0000000..b2e5625 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_add.s @@ -0,0 +1,189 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_add +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_fe25519_add +.globl crypto_sign_ed25519_amd64_64_fe25519_add +_crypto_sign_ed25519_amd64_64_fe25519_add: +crypto_sign_ed25519_amd64_64_fe25519_add: +mov %rsp,%r11 +and $31,%r11 +add $0,%r11 +sub %r11,%rsp + +# qhasm: r0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(r0=int64#4 +# asm 2: movq 0(r0=%rcx +movq 0(%rsi),%rcx + +# qhasm: r1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(r1=int64#5 +# asm 2: movq 8(r1=%r8 +movq 8(%rsi),%r8 + +# qhasm: r2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(r2=int64#6 +# asm 2: movq 16(r2=%r9 +movq 16(%rsi),%r9 + +# qhasm: r3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(r3=int64#2 +# asm 2: movq 24(r3=%rsi +movq 24(%rsi),%rsi + +# qhasm: carry? r0 += *(uint64 *)(yp + 0) +# asm 1: addq 0(addt0=int64#3 +# asm 2: mov $0,>addt0=%rdx +mov $0,%rdx + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: r0 = *(uint64 *) (rp + 0) +# asm 1: movq 0(r0=int64#2 +# asm 2: movq 0(r0=%rsi +movq 0(%rdi),%rsi + +# qhasm: r1 = *(uint64 *) (rp + 8) +# asm 1: movq 8(r1=int64#3 +# asm 2: movq 8(r1=%rdx +movq 8(%rdi),%rdx + +# qhasm: r2 = *(uint64 *) (rp + 16) +# asm 1: movq 16(r2=int64#4 +# asm 2: movq 16(r2=%rcx +movq 16(%rdi),%rcx + +# qhasm: r3 = *(uint64 *) (rp + 24) +# asm 1: movq 24(r3=int64#5 +# asm 2: movq 24(r3=%r8 +movq 24(%rdi),%r8 + +# qhasm: t0 = r0 +# asm 1: mov t0=int64#6 +# asm 2: mov t0=%r9 +mov %rsi,%r9 + +# qhasm: t1 = r1 +# asm 1: mov t1=int64#7 +# asm 2: mov t1=%rax +mov %rdx,%rax + +# qhasm: t2 = r2 +# asm 1: mov t2=int64#8 +# asm 2: mov t2=%r10 +mov %rcx,%r10 + +# qhasm: t3 = r3 +# asm 1: mov t3=int64#9 +# asm 2: mov t3=%r11 +mov %r8,%r11 + +# qhasm: two63 = 1 +# asm 1: mov $1,>two63=int64#10 +# asm 2: mov $1,>two63=%r12 +mov $1,%r12 + +# qhasm: two63 <<= 63 +# asm 1: shl $63,t0=int64#6 +# asm 2: mov t0=%r9 +mov %rsi,%r9 + +# qhasm: t1 = r1 +# asm 1: mov t1=int64#7 +# asm 2: mov t1=%rax +mov %rdx,%rax + +# qhasm: t2 = r2 +# asm 1: mov t2=int64#8 +# asm 2: mov t2=%r10 +mov %rcx,%r10 + +# qhasm: t3 = r3 +# asm 1: mov t3=int64#9 +# asm 2: mov t3=%r11 +mov %r8,%r11 + +# qhasm: carry? t0 += 19 +# asm 1: add $19,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/fe25519_getparity.c b/ext/ed25519-amd64-asm/fe25519_getparity.c new file mode 100644 index 0000000..a003ec8 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_getparity.c @@ -0,0 +1,8 @@ +#include "fe25519.h" + +unsigned char fe25519_getparity(const fe25519 *x) +{ + fe25519 t = *x; + fe25519_freeze(&t); + return (unsigned char)t.v[0] & 1; +} diff --git a/ext/ed25519-amd64-asm/fe25519_invert.c b/ext/ed25519-amd64-asm/fe25519_invert.c new file mode 100644 index 0000000..a46d141 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_invert.c @@ -0,0 +1,60 @@ +#include "fe25519.h" + +void fe25519_invert(fe25519 *r, const fe25519 *x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t; + int i; + + /* 2 */ fe25519_square(&z2,x); + /* 4 */ fe25519_square(&t,&z2); + /* 8 */ fe25519_square(&t,&t); + /* 9 */ fe25519_mul(&z9,&t,x); + /* 11 */ fe25519_mul(&z11,&z9,&z2); + /* 22 */ fe25519_square(&t,&z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); + + /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); + /* 2^20 - 2^10 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); + /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); + /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } + /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t,&t); + /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); + /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); + /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } + /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t,&t); + /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } + /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t,&t); + /* 2^252 - 2^2 */ fe25519_square(&t,&t); + /* 2^253 - 2^3 */ fe25519_square(&t,&t); + + /* 2^254 - 2^4 */ fe25519_square(&t,&t); + + /* 2^255 - 2^5 */ fe25519_square(&t,&t); + /* 2^255 - 21 */ fe25519_mul(r,&t,&z11); +} diff --git a/ext/ed25519-amd64-asm/fe25519_iseq.c b/ext/ed25519-amd64-asm/fe25519_iseq.c new file mode 100644 index 0000000..bf72f8c --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_iseq.c @@ -0,0 +1,14 @@ +#include "fe25519.h" + +int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) +{ + fe25519 t1 = *x; + fe25519 t2 = *y; + fe25519_freeze(&t1); + fe25519_freeze(&t2); + if(t1.v[0] != t2.v[0]) return 0; + if(t1.v[1] != t2.v[1]) return 0; + if(t1.v[2] != t2.v[2]) return 0; + if(t1.v[3] != t2.v[3]) return 0; + return 1; +} diff --git a/ext/ed25519-amd64-asm/fe25519_iszero.c b/ext/ed25519-amd64-asm/fe25519_iszero.c new file mode 100644 index 0000000..99e4daf --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_iszero.c @@ -0,0 +1,12 @@ +#include "fe25519.h" + +int fe25519_iszero_vartime(const fe25519 *x) +{ + fe25519 t = *x; + fe25519_freeze(&t); + if (t.v[0]) return 0; + if (t.v[1]) return 0; + if (t.v[2]) return 0; + if (t.v[3]) return 0; + return 1; +} diff --git a/ext/ed25519-amd64-asm/fe25519_mul.s b/ext/ed25519-amd64-asm/fe25519_mul.s new file mode 100644 index 0000000..1478428 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_mul.s @@ -0,0 +1,865 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_mul +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_fe25519_mul +.globl crypto_sign_ed25519_amd64_64_fe25519_mul +_crypto_sign_ed25519_amd64_64_fe25519_mul: +crypto_sign_ed25519_amd64_64_fe25519_mul: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: yp = yp +# asm 1: mov yp=int64#4 +# asm 2: mov yp=%rcx +mov %rdx,%rcx + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(mulx0=int64#10 +# asm 2: movq 0(mulx0=%r12 +movq 0(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(yp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul r0=int64#11 +# asm 2: mov r0=%r13 +mov %rax,%r13 + +# qhasm: r1 = mulrdx +# asm 1: mov r1=int64#12 +# asm 2: mov r1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(yp + 8) +# asm 1: movq 8(mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul r2=int64#13 +# asm 2: mov $0,>r2=%r15 +mov $0,%r15 + +# qhasm: r2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul r3=int64#14 +# asm 2: mov $0,>r3=%rbx +mov $0,%rbx + +# qhasm: r3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 8(mulx1=%r12 +movq 8(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(yp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 16(mulx2=%r12 +movq 16(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(yp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#2 +# asm 2: movq 24(mulx3=%rsi +movq 24(%rsi),%rsi + +# qhasm: mulrax = *(uint64 *)(yp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? r0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: r0 += mulzero +# asm 1: add caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/fe25519_neg.c b/ext/ed25519-amd64-asm/fe25519_neg.c new file mode 100644 index 0000000..235b209 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_neg.c @@ -0,0 +1,8 @@ +#include "fe25519.h" + +void fe25519_neg(fe25519 *r, const fe25519 *x) +{ + fe25519 t; + fe25519_setint(&t,0); + fe25519_sub(r,&t,x); +} diff --git a/ext/ed25519-amd64-asm/fe25519_pack.c b/ext/ed25519-amd64-asm/fe25519_pack.c new file mode 100644 index 0000000..caf5185 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_pack.c @@ -0,0 +1,13 @@ +#include "fe25519.h" + +/* Assumes input x being reduced below 2^255 */ +void fe25519_pack(unsigned char r[32], const fe25519 *x) +{ + int i; + fe25519 t; + t = *x; + fe25519_freeze(&t); + /* assuming little-endian */ + for(i=0;i<32;i++) r[i] = i[(unsigned char *)&t.v]; +} + diff --git a/ext/ed25519-amd64-asm/fe25519_pow2523.c b/ext/ed25519-amd64-asm/fe25519_pow2523.c new file mode 100644 index 0000000..60042a0 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_pow2523.c @@ -0,0 +1,55 @@ +#include "fe25519.h" + +void fe25519_pow2523(fe25519 *r, const fe25519 *x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t; + int i; + + /* 2 */ fe25519_square(&z2,x); + /* 4 */ fe25519_square(&t,&z2); + /* 8 */ fe25519_square(&t,&t); + /* 9 */ fe25519_mul(&z9,&t,x); + /* 11 */ fe25519_mul(&z11,&z9,&z2); + /* 22 */ fe25519_square(&t,&z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); + + /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); + /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); + /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); + /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } + /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t,&t); + /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); + /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); + /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } + /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t,&t); + /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } + /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t,&t); + /* 2^252 - 2^2 */ fe25519_square(&t,&t); + /* 2^252 - 3 */ fe25519_mul(r,&t,x); +} diff --git a/ext/ed25519-amd64-asm/fe25519_setint.c b/ext/ed25519-amd64-asm/fe25519_setint.c new file mode 100644 index 0000000..585c4bd --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_setint.c @@ -0,0 +1,9 @@ +#include "fe25519.h" + +void fe25519_setint(fe25519 *r, unsigned int v) +{ + r->v[0] = v; + r->v[1] = 0; + r->v[2] = 0; + r->v[3] = 0; +} diff --git a/ext/ed25519-amd64-asm/fe25519_square.s b/ext/ed25519-amd64-asm/fe25519_square.s new file mode 100644 index 0000000..a74d9e8 --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_square.s @@ -0,0 +1,639 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 squarer4 + +# qhasm: int64 squarer5 + +# qhasm: int64 squarer6 + +# qhasm: int64 squarer7 + +# qhasm: int64 squarer8 + +# qhasm: int64 squarerax + +# qhasm: int64 squarerdx + +# qhasm: int64 squaret1 + +# qhasm: int64 squaret2 + +# qhasm: int64 squaret3 + +# qhasm: int64 squarec + +# qhasm: int64 squarezero + +# qhasm: int64 squarei38 + +# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_square +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_fe25519_square +.globl crypto_sign_ed25519_amd64_64_fe25519_square +_crypto_sign_ed25519_amd64_64_fe25519_square: +crypto_sign_ed25519_amd64_64_fe25519_square: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarerax = *(uint64 *)(xp + 8) +# asm 1: movq 8(squarerax=int64#7 +# asm 2: movq 8(squarerax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) +# asm 1: mulq 0(r1=int64#5 +# asm 2: mov r1=%r8 +mov %rax,%r8 + +# qhasm: r2 = squarerdx +# asm 1: mov r2=int64#6 +# asm 2: mov r2=%r9 +mov %rdx,%r9 + +# qhasm: squarerax = *(uint64 *)(xp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) +# asm 1: mulq 8(r3=int64#8 +# asm 2: mov r3=%r10 +mov %rax,%r10 + +# qhasm: squarer4 = squarerdx +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rdx,%r11 + +# qhasm: squarerax = *(uint64 *)(xp + 24) +# asm 1: movq 24(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 16) +# asm 1: mulq 16(squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rax,%r12 + +# qhasm: squarer6 = squarerdx +# asm 1: mov squarer6=int64#11 +# asm 2: mov squarer6=%r13 +mov %rdx,%r13 + +# qhasm: squarerax = *(uint64 *)(xp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) +# asm 1: mulq 0(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) +# asm 1: mulq 8(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) +# asm 1: mulq 0(squarerax=int64#7 +# asm 2: movq 0(squarerax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) +# asm 1: mulq 0(r0=int64#12 +# asm 2: mov r0=%r14 +mov %rax,%r14 + +# qhasm: squaret1 = squarerdx +# asm 1: mov squaret1=int64#13 +# asm 2: mov squaret1=%r15 +mov %rdx,%r15 + +# qhasm: squarerax = *(uint64 *)(xp + 8) +# asm 1: movq 8(squarerax=int64#7 +# asm 2: movq 8(squarerax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) +# asm 1: mulq 8(squaret2=int64#14 +# asm 2: mov squaret2=%rbx +mov %rax,%rbx + +# qhasm: squaret3 = squarerdx +# asm 1: mov squaret3=int64#15 +# asm 2: mov squaret3=%rbp +mov %rdx,%rbp + +# qhasm: squarerax = *(uint64 *)(xp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 16) +# asm 1: mulq 16(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 24) +# asm 1: mulq 24(squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r11,%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: squarer4 = squarerax +# asm 1: mov squarer4=int64#2 +# asm 2: mov squarer4=%rsi +mov %rax,%rsi + +# qhasm: squarerax = squarer5 +# asm 1: mov squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r12,%rax + +# qhasm: squarer5 = squarerdx +# asm 1: mov squarer5=int64#9 +# asm 2: mov squarer5=%r11 +mov %rdx,%r11 + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? squarer5 += squarerax +# asm 1: add squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r13,%rax + +# qhasm: squarer6 = 0 +# asm 1: mov $0,>squarer6=int64#10 +# asm 2: mov $0,>squarer6=%r12 +mov $0,%r12 + +# qhasm: squarer6 += squarerdx + carry +# asm 1: adc squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %rcx,%rax + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarer7 += squarerdx + carry +# asm 1: adc squarer8=int64#7 +# asm 2: mov $0,>squarer8=%rax +mov $0,%rax + +# qhasm: squarer8 += squarerdx + carry +# asm 1: adc squarezero=int64#2 +# asm 2: mov $0,>squarezero=%rsi +mov $0,%rsi + +# qhasm: squarer8 += squarezero + carry +# asm 1: adc squarer8=int64#3 +# asm 2: imulq $38,squarer8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? r0 += squarer8 +# asm 1: add squarezero=int64#2 +# asm 2: imulq $38,squarezero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: r0 += squarezero +# asm 1: add caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/fe25519_sub.s b/ext/ed25519-amd64-asm/fe25519_sub.s new file mode 100644 index 0000000..0b395bc --- /dev/null +++ b/ext/ed25519-amd64-asm/fe25519_sub.s @@ -0,0 +1,189 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_sub +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_fe25519_sub +.globl crypto_sign_ed25519_amd64_64_fe25519_sub +_crypto_sign_ed25519_amd64_64_fe25519_sub: +crypto_sign_ed25519_amd64_64_fe25519_sub: +mov %rsp,%r11 +and $31,%r11 +add $0,%r11 +sub %r11,%rsp + +# qhasm: r0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(r0=int64#4 +# asm 2: movq 0(r0=%rcx +movq 0(%rsi),%rcx + +# qhasm: r1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(r1=int64#5 +# asm 2: movq 8(r1=%r8 +movq 8(%rsi),%r8 + +# qhasm: r2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(r2=int64#6 +# asm 2: movq 16(r2=%r9 +movq 16(%rsi),%r9 + +# qhasm: r3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(r3=int64#2 +# asm 2: movq 24(r3=%rsi +movq 24(%rsi),%rsi + +# qhasm: carry? r0 -= *(uint64 *)(yp + 0) +# asm 1: subq 0(subt0=int64#3 +# asm 2: mov $0,>subt0=%rdx +mov $0,%rdx + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#7 +# asm 2: mov $38,>subt1=%rax +mov $38,%rax + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae v[0] = *(unsigned long long *)x; + r->v[1] = *(((unsigned long long *)x)+1); + r->v[2] = *(((unsigned long long *)x)+2); + r->v[3] = *(((unsigned long long *)x)+3); + r->v[3] &= 0x7fffffffffffffffULL; +} diff --git a/ext/ed25519-amd64-asm/ge25519.h b/ext/ed25519-amd64-asm/ge25519.h new file mode 100644 index 0000000..0b15136 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519.h @@ -0,0 +1,95 @@ +#ifndef GE25519_H +#define GE25519_H + +#include "fe25519.h" +#include "sc25519.h" + +#define ge25519 crypto_sign_ed25519_amd64_64_ge25519 +#define ge25519_base crypto_sign_ed25519_amd64_64_ge25519_base +#define ge25519_unpackneg_vartime crypto_sign_ed25519_amd64_64_unpackneg_vartime +#define ge25519_pack crypto_sign_ed25519_amd64_64_pack +#define ge25519_isneutral_vartime crypto_sign_ed25519_amd64_64_isneutral_vartime +#define ge25519_add crypto_sign_ed25519_amd64_64_ge25519_add +#define ge25519_double crypto_sign_ed25519_amd64_64_ge25519_double +#define ge25519_double_scalarmult_vartime crypto_sign_ed25519_amd64_64_double_scalarmult_vartime +#define ge25519_multi_scalarmult_vartime crypto_sign_ed25519_amd64_64_ge25519_multi_scalarmult_vartime +#define ge25519_scalarmult_base crypto_sign_ed25519_amd64_64_scalarmult_base +#define ge25519_p1p1_to_p2 crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 +#define ge25519_p1p1_to_p3 crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 +#define ge25519_add_p1p1 crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 +#define ge25519_dbl_p1p1 crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 +#define choose_t crypto_sign_ed25519_amd64_64_choose_t +#define ge25519_nielsadd2 crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 +#define ge25519_nielsadd_p1p1 crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 +#define ge25519_pnielsadd_p1p1 crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 + + +#define ge25519_p3 ge25519 + +typedef struct +{ + fe25519 x; + fe25519 y; + fe25519 z; + fe25519 t; +} ge25519; + +typedef struct +{ + fe25519 x; + fe25519 z; + fe25519 y; + fe25519 t; +} ge25519_p1p1; + +typedef struct +{ + fe25519 x; + fe25519 y; + fe25519 z; +} ge25519_p2; + +typedef struct +{ + fe25519 ysubx; + fe25519 xaddy; + fe25519 t2d; +} ge25519_niels; + +typedef struct +{ + fe25519 ysubx; + fe25519 xaddy; + fe25519 z; + fe25519 t2d; +} ge25519_pniels; + +extern void ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p); +extern void ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p); +extern void ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q); +extern void ge25519_dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p); +extern void choose_t(ge25519_niels *t, unsigned long long pos, signed long long b, const ge25519_niels *base_multiples); +extern void ge25519_nielsadd2(ge25519_p3 *r, const ge25519_niels *q); +extern void ge25519_nielsadd_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_niels *q); +extern void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_pniels *q); + +extern const ge25519 ge25519_base; + +extern int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]); + +extern void ge25519_pack(unsigned char r[32], const ge25519 *p); + +extern int ge25519_isneutral_vartime(const ge25519 *p); + +extern void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q); + +extern void ge25519_double(ge25519 *r, const ge25519 *p); + +/* computes [s1]p1 + [s2]ge25519_base */ +extern void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const sc25519 *s1, const sc25519 *s2); + +extern void ge25519_multi_scalarmult_vartime(ge25519 *r, ge25519 *p, sc25519 *s, const unsigned long long npoints); + +extern void ge25519_scalarmult_base(ge25519 *r, const sc25519 *s); + +#endif diff --git a/ext/ed25519-amd64-asm/ge25519_add.c b/ext/ed25519-amd64-asm/ge25519_add.c new file mode 100644 index 0000000..c4d1c68 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_add.c @@ -0,0 +1,8 @@ +#include "ge25519.h" + +void ge25519_add(ge25519_p3 *r, const ge25519_p3 *p, const ge25519_p3 *q) +{ + ge25519_p1p1 grp1p1; + ge25519_add_p1p1(&grp1p1, p, q); + ge25519_p1p1_to_p3(r, &grp1p1); +} diff --git a/ext/ed25519-amd64-asm/ge25519_add_p1p1.s b/ext/ed25519-amd64-asm/ge25519_add_p1p1.s new file mode 100644 index 0000000..0cb1389 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_add_p1p1.s @@ -0,0 +1,4554 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: int64 qp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: input qp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 a0 + +# qhasm: int64 a1 + +# qhasm: int64 a2 + +# qhasm: int64 a3 + +# qhasm: stack64 a0_stack + +# qhasm: stack64 a1_stack + +# qhasm: stack64 a2_stack + +# qhasm: stack64 a3_stack + +# qhasm: int64 b0 + +# qhasm: int64 b1 + +# qhasm: int64 b2 + +# qhasm: int64 b3 + +# qhasm: stack64 b0_stack + +# qhasm: stack64 b1_stack + +# qhasm: stack64 b2_stack + +# qhasm: stack64 b3_stack + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: stack64 c0_stack + +# qhasm: stack64 c1_stack + +# qhasm: stack64 c2_stack + +# qhasm: stack64 c3_stack + +# qhasm: int64 d0 + +# qhasm: int64 d1 + +# qhasm: int64 d2 + +# qhasm: int64 d3 + +# qhasm: stack64 d0_stack + +# qhasm: stack64 d1_stack + +# qhasm: stack64 d2_stack + +# qhasm: stack64 d3_stack + +# qhasm: int64 t10 + +# qhasm: int64 t11 + +# qhasm: int64 t12 + +# qhasm: int64 t13 + +# qhasm: stack64 t10_stack + +# qhasm: stack64 t11_stack + +# qhasm: stack64 t12_stack + +# qhasm: stack64 t13_stack + +# qhasm: int64 t20 + +# qhasm: int64 t21 + +# qhasm: int64 t22 + +# qhasm: int64 t23 + +# qhasm: stack64 t20_stack + +# qhasm: stack64 t21_stack + +# qhasm: stack64 t22_stack + +# qhasm: stack64 t23_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 x0 + +# qhasm: int64 x1 + +# qhasm: int64 x2 + +# qhasm: int64 x3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 +.globl crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 +_crypto_sign_ed25519_amd64_64_ge25519_add_p1p1: +crypto_sign_ed25519_amd64_64_ge25519_add_p1p1: +mov %rsp,%r11 +and $31,%r11 +add $192,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: qp = qp +# asm 1: mov qp=int64#4 +# asm 2: mov qp=%rcx +mov %rdx,%rcx + +# qhasm: a0 = *(uint64 *)(pp + 32) +# asm 1: movq 32(a0=int64#3 +# asm 2: movq 32(a0=%rdx +movq 32(%rsi),%rdx + +# qhasm: a1 = *(uint64 *)(pp + 40) +# asm 1: movq 40(a1=int64#5 +# asm 2: movq 40(a1=%r8 +movq 40(%rsi),%r8 + +# qhasm: a2 = *(uint64 *)(pp + 48) +# asm 1: movq 48(a2=int64#6 +# asm 2: movq 48(a2=%r9 +movq 48(%rsi),%r9 + +# qhasm: a3 = *(uint64 *)(pp + 56) +# asm 1: movq 56(a3=int64#7 +# asm 2: movq 56(a3=%rax +movq 56(%rsi),%rax + +# qhasm: b0 = a0 +# asm 1: mov b0=int64#8 +# asm 2: mov b0=%r10 +mov %rdx,%r10 + +# qhasm: b1 = a1 +# asm 1: mov b1=int64#9 +# asm 2: mov b1=%r11 +mov %r8,%r11 + +# qhasm: b2 = a2 +# asm 1: mov b2=int64#10 +# asm 2: mov b2=%r12 +mov %r9,%r12 + +# qhasm: b3 = a3 +# asm 1: mov b3=int64#11 +# asm 2: mov b3=%r13 +mov %rax,%r13 + +# qhasm: carry? a0 -= *(uint64 *)(pp + 0) +# asm 1: subq 0(subt0=int64#12 +# asm 2: mov $0,>subt0=%r14 +mov $0,%r14 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#13 +# asm 2: mov $38,>subt1=%r15 +mov $38,%r15 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#12 +# asm 2: mov $0,>addt0=%r14 +mov $0,%r14 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#13 +# asm 2: mov $38,>addt1=%r15 +mov $38,%r15 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r8,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r9,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rax,80(%rsp) + +# qhasm: b0_stack = b0 +# asm 1: movq b0_stack=stack64#12 +# asm 2: movq b0_stack=88(%rsp) +movq %r10,88(%rsp) + +# qhasm: b1_stack = b1 +# asm 1: movq b1_stack=stack64#13 +# asm 2: movq b1_stack=96(%rsp) +movq %r11,96(%rsp) + +# qhasm: b2_stack = b2 +# asm 1: movq b2_stack=stack64#14 +# asm 2: movq b2_stack=104(%rsp) +movq %r12,104(%rsp) + +# qhasm: b3_stack = b3 +# asm 1: movq b3_stack=stack64#15 +# asm 2: movq b3_stack=112(%rsp) +movq %r13,112(%rsp) + +# qhasm: t10 = *(uint64 *)(qp + 32) +# asm 1: movq 32(t10=int64#3 +# asm 2: movq 32(t10=%rdx +movq 32(%rcx),%rdx + +# qhasm: t11 = *(uint64 *)(qp + 40) +# asm 1: movq 40(t11=int64#5 +# asm 2: movq 40(t11=%r8 +movq 40(%rcx),%r8 + +# qhasm: t12 = *(uint64 *)(qp + 48) +# asm 1: movq 48(t12=int64#6 +# asm 2: movq 48(t12=%r9 +movq 48(%rcx),%r9 + +# qhasm: t13 = *(uint64 *)(qp + 56) +# asm 1: movq 56(t13=int64#7 +# asm 2: movq 56(t13=%rax +movq 56(%rcx),%rax + +# qhasm: t20 = t10 +# asm 1: mov t20=int64#8 +# asm 2: mov t20=%r10 +mov %rdx,%r10 + +# qhasm: t21 = t11 +# asm 1: mov t21=int64#9 +# asm 2: mov t21=%r11 +mov %r8,%r11 + +# qhasm: t22 = t12 +# asm 1: mov t22=int64#10 +# asm 2: mov t22=%r12 +mov %r9,%r12 + +# qhasm: t23 = t13 +# asm 1: mov t23=int64#11 +# asm 2: mov t23=%r13 +mov %rax,%r13 + +# qhasm: carry? t10 -= *(uint64 *) (qp + 0) +# asm 1: subq 0(subt0=int64#12 +# asm 2: mov $0,>subt0=%r14 +mov $0,%r14 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#13 +# asm 2: mov $38,>subt1=%r15 +mov $38,%r15 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#12 +# asm 2: mov $0,>addt0=%r14 +mov $0,%r14 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#13 +# asm 2: mov $38,>addt1=%r15 +mov $38,%r15 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae t10_stack=stack64#16 +# asm 2: movq t10_stack=120(%rsp) +movq %rdx,120(%rsp) + +# qhasm: t11_stack = t11 +# asm 1: movq t11_stack=stack64#17 +# asm 2: movq t11_stack=128(%rsp) +movq %r8,128(%rsp) + +# qhasm: t12_stack = t12 +# asm 1: movq t12_stack=stack64#18 +# asm 2: movq t12_stack=136(%rsp) +movq %r9,136(%rsp) + +# qhasm: t13_stack = t13 +# asm 1: movq t13_stack=stack64#19 +# asm 2: movq t13_stack=144(%rsp) +movq %rax,144(%rsp) + +# qhasm: t20_stack = t20 +# asm 1: movq t20_stack=stack64#20 +# asm 2: movq t20_stack=152(%rsp) +movq %r10,152(%rsp) + +# qhasm: t21_stack = t21 +# asm 1: movq t21_stack=stack64#21 +# asm 2: movq t21_stack=160(%rsp) +movq %r11,160(%rsp) + +# qhasm: t22_stack = t22 +# asm 1: movq t22_stack=stack64#22 +# asm 2: movq t22_stack=168(%rsp) +movq %r12,168(%rsp) + +# qhasm: t23_stack = t23 +# asm 1: movq t23_stack=stack64#23 +# asm 2: movq t23_stack=176(%rsp) +movq %r13,176(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = a0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 56(%rsp),%r12 + +# qhasm: mulrax = t10_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a0=int64#11 +# asm 2: mov a0=%r13 +mov %rax,%r13 + +# qhasm: a1 = mulrdx +# asm 1: mov a1=int64#12 +# asm 2: mov a1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = t11_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a2=int64#13 +# asm 2: mov $0,>a2=%r15 +mov $0,%r15 + +# qhasm: a2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a3=int64#14 +# asm 2: mov $0,>a3=%rbx +mov $0,%rbx + +# qhasm: a3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 64(%rsp),%r12 + +# qhasm: mulrax = t10_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 72(%rsp),%r12 + +# qhasm: mulrax = t10_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 80(%rsp),%r12 + +# qhasm: mulrax = t10_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? a0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: a0 += mulzero +# asm 1: add a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = b0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 88(%rsp),%r12 + +# qhasm: mulrax = t20_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx0=int64#11 +# asm 2: mov rx0=%r13 +mov %rax,%r13 + +# qhasm: rx1 = mulrdx +# asm 1: mov rx1=int64#12 +# asm 2: mov rx1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = t21_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx2=int64#13 +# asm 2: mov $0,>rx2=%r15 +mov $0,%r15 + +# qhasm: rx2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx3=int64#14 +# asm 2: mov $0,>rx3=%rbx +mov $0,%rbx + +# qhasm: rx3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 96(%rsp),%r12 + +# qhasm: mulrax = t20_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 104(%rsp),%r12 + +# qhasm: mulrax = t20_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 112(%rsp),%r12 + +# qhasm: mulrax = t20_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? rx0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: rx0 += mulzero +# asm 1: add ry0=int64#3 +# asm 2: mov ry0=%rdx +mov %r13,%rdx + +# qhasm: ry1 = rx1 +# asm 1: mov ry1=int64#5 +# asm 2: mov ry1=%r8 +mov %r14,%r8 + +# qhasm: ry2 = rx2 +# asm 1: mov ry2=int64#6 +# asm 2: mov ry2=%r9 +mov %r15,%r9 + +# qhasm: ry3 = rx3 +# asm 1: mov ry3=int64#7 +# asm 2: mov ry3=%rax +mov %rbx,%rax + +# qhasm: carry? ry0 += a0_stack +# asm 1: addq addt0=int64#8 +# asm 2: mov $0,>addt0=%r10 +mov $0,%r10 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#9 +# asm 2: mov $38,>addt1=%r11 +mov $38,%r11 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae subt0=int64#8 +# asm 2: mov $0,>subt0=%r10 +mov $0,%r10 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#9 +# asm 2: mov $38,>subt1=%r11 +mov $38,%r11 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulx0=int64#10 +# asm 2: movq 96(mulx0=%r12 +movq 96(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c0=int64#11 +# asm 2: mov c0=%r13 +mov %rax,%r13 + +# qhasm: c1 = mulrdx +# asm 1: mov c1=int64#12 +# asm 2: mov c1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c2=int64#13 +# asm 2: mov $0,>c2=%r15 +mov $0,%r15 + +# qhasm: c2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c3=int64#14 +# asm 2: mov $0,>c3=%rbx +mov $0,%rbx + +# qhasm: c3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 104(mulx1=%r12 +movq 104(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 112(mulx2=%r12 +movq 112(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq 120(mulx3=%r12 +movq 120(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? c0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: c0 += mulzero +# asm 1: add c0_stack=stack64#8 +# asm 2: movq c0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: c1_stack = c1 +# asm 1: movq c1_stack=stack64#9 +# asm 2: movq c1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: c2_stack = c2 +# asm 1: movq c2_stack=stack64#10 +# asm 2: movq c2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: c3_stack = c3 +# asm 1: movq c3_stack=stack64#11 +# asm 2: movq c3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = c0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 56(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 +# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c0=int64#11 +# asm 2: mov c0=%r13 +mov %rax,%r13 + +# qhasm: c1 = mulrdx +# asm 1: mov c1=int64#12 +# asm 2: mov c1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D1 +# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c2=int64#13 +# asm 2: mov $0,>c2=%r15 +mov $0,%r15 + +# qhasm: c2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c3=int64#14 +# asm 2: mov $0,>c3=%rbx +mov $0,%rbx + +# qhasm: c3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 64(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 +# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 72(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 +# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 80(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 +# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax +movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? c0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: c0 += mulzero +# asm 1: add c0_stack=stack64#8 +# asm 2: movq c0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: c1_stack = c1 +# asm 1: movq c1_stack=stack64#9 +# asm 2: movq c1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: c2_stack = c2 +# asm 1: movq c2_stack=stack64#10 +# asm 2: movq c2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: c3_stack = c3 +# asm 1: movq c3_stack=stack64#11 +# asm 2: movq c3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulx0=int64#10 +# asm 2: movq 64(mulx0=%r12 +movq 64(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt0=int64#11 +# asm 2: mov rt0=%r13 +mov %rax,%r13 + +# qhasm: rt1 = mulrdx +# asm 1: mov rt1=int64#12 +# asm 2: mov rt1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 72) +# asm 1: movq 72(mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt2=int64#13 +# asm 2: mov $0,>rt2=%r15 +mov $0,%r15 + +# qhasm: rt2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt3=int64#14 +# asm 2: mov $0,>rt3=%rbx +mov $0,%rbx + +# qhasm: rt3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 72(mulx1=%r12 +movq 72(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 80(mulx2=%r12 +movq 80(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#2 +# asm 2: movq 88(mulx3=%rsi +movq 88(%rsi),%rsi + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rt0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rt0 += mulzero +# asm 1: add addt0=int64#2 +# asm 2: mov $0,>addt0=%rsi +mov $0,%rsi + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#3 +# asm 2: mov $38,>addt1=%rdx +mov $38,%rdx + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae rz0=int64#2 +# asm 2: mov rz0=%rsi +mov %r13,%rsi + +# qhasm: rz1 = rt1 +# asm 1: mov rz1=int64#3 +# asm 2: mov rz1=%rdx +mov %r14,%rdx + +# qhasm: rz2 = rt2 +# asm 1: mov rz2=int64#4 +# asm 2: mov rz2=%rcx +mov %r15,%rcx + +# qhasm: rz3 = rt3 +# asm 1: mov rz3=int64#5 +# asm 2: mov rz3=%r8 +mov %rbx,%r8 + +# qhasm: carry? rz0 += c0_stack +# asm 1: addq addt0=int64#6 +# asm 2: mov $0,>addt0=%r9 +mov $0,%r9 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae subt0=int64#6 +# asm 2: mov $0,>subt0=%r9 +mov $0,%r9 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#7 +# asm 2: mov $38,>subt1=%rax +mov $38,%rax + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_base.c b/ext/ed25519-amd64-asm/ge25519_base.c new file mode 100644 index 0000000..a7ae978 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_base.c @@ -0,0 +1,7 @@ +#include "ge25519.h" + +const ge25519 ge25519_base = {{{0xC9562D608F25D51A, 0x692CC7609525A7B2, 0xC0A4E231FDD6DC5C, 0x216936D3CD6E53FE}}, + {{0x6666666666666658, 0x6666666666666666, 0x6666666666666666, 0x6666666666666666}}, + {{0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 000000000000000000}}, + {{0x6DDE8AB3A5B7DDA3, 0x20F09F80775152F5, 0x66EA4E8E64ABE37D, 0x67875F0FD78B7665}}}; + diff --git a/ext/ed25519-amd64-asm/ge25519_base_niels.data b/ext/ed25519-amd64-asm/ge25519_base_niels.data new file mode 100644 index 0000000..8e3300c --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_base_niels.data @@ -0,0 +1,1536 @@ +{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, + {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, + {{0xdbbd15674b6fbb59, 0x41e13f00eea2a5ea, 0xcdd49d1cc957c6fa, 0x4f0ebe1faf16ecca}}}, +{{{0x8a99a56042b4d5a8, 0x8f2b810c4e60acf6, 0xe09e236bb16e37aa, 0x6bb595a669c92555}}, + {{0x9224e7fc933c71d7, 0x9f469d967a0ff5b5, 0x5aa69a65e1d60702, 0x590c063fa87d2e2e}}, + {{0x6e347eaadad36802, 0xbaf3599383ee4805, 0x3bcabe10e6076826, 0x49314f0a165ed1b8}}}, +{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, + {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, + {{0x9bf211f4f1674834, 0xb84e6b17f62df895, 0xd7de6f075b722a4e, 0x549a04b963bb2a21}}}, +{{{0x95fe050a056818bf, 0x327e89715660faa9, 0xc3e8e3cd06a05073, 0x27933f4c7445a49a}}, + {{0x287351b98efc099f, 0x6765c6f47dfd2538, 0xca348d3dfb0a9265, 0x680e910321e58727}}, + {{0xbf1e45ece51426b0, 0xe32bc63d6dba0f94, 0xe42974d58cf852c0, 0x44f079b1b0e64c18}}}, +{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, + {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, + {{0xc832a179e7d003b3, 0x5f729d0a00124d7e, 0x62c1d4a10e6d8ff3, 0x68b8ac5938b27a98}}}, +{{{0x499806b67b7d8ca4, 0x575be28427d22739, 0xbb085ce7204553b9, 0x38b64c41ae417884}}, + {{0x3a0ceeeb77157131, 0x9b27158900c8af88, 0x8065b668da59a736, 0x51e57bb6a2cc38bd}}, + {{0x8f9dad91689de3a4, 0x175f2428f8fb9137, 0x050ab5329fcfb988, 0x7865dfa21354c09f}}}, +{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, + {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, + {{0x217a8aacab0fda36, 0xa528c6543d3549c8, 0x37d05b8b13ab7568, 0x233cef623a2cbc37}}}, +{{{0xe2a75dedf39234d9, 0x963d7680e1b558f9, 0x2c2741ac6e3c23fb, 0x3a9024a1320e01c3}}, + {{0x59b7596604dd3e8f, 0x6cb30377e288702c, 0xb1339c665ed9c323, 0x0915e76061bce52f}}, + {{0xdf7de835a834a37e, 0x8be19cda689857ea, 0x2c1185367167b326, 0x589eb3d9dbefd5c2}}}, +{{{0x7ec851ca553e2df3, 0xa71284cba64878b3, 0xe6b5e4193288d1e7, 0x4cf210ec5a9a8883}}, + {{0x322d04a52d9021f6, 0xb9c19f3375c6bf9c, 0x587a3a4342d20b09, 0x143b1cf8aa64fe61}}, + {{0x9f867c7d968acaab, 0x5f54258e27092729, 0xd0a7d34bea180975, 0x21b546a3374126e1}}}, +{{{0xa94ff858a2888343, 0xce0ed4565313ed3c, 0xf55c3dcfb5bf34fa, 0x0a653ca5c9eab371}}, + {{0x490a7a45d185218f, 0x9a15377846049335, 0x0060ea09cc31e1f6, 0x7e041577f86ee965}}, + {{0x66b2a496ce5b67f3, 0xff5492d8bd569796, 0x503cec294a592cd0, 0x566943650813acb2}}}, +{{{0xb818db0c26620798, 0x5d5c31d9606e354a, 0x0982fa4f00a8cdc7, 0x17e12bcd4653e2d4}}, + {{0x5672f9eb1dabb69d, 0xba70b535afe853fc, 0x47ac0f752796d66d, 0x32a5351794117275}}, + {{0xd3a644a6df648437, 0x703b6559880fbfdd, 0xcb852540ad3a1aa5, 0x0900b3f78e4c6468}}}, +{{{0x0a851b9f679d651b, 0xe108cb61033342f2, 0xd601f57fe88b30a3, 0x371f3acaed2dd714}}, + {{0xed280fbec816ad31, 0x52d9595bd8e6efe3, 0x0fe71772f6c623f5, 0x4314030b051e293c}}, + {{0xd560005efbf0bcad, 0x8eb70f2ed1870c5e, 0x201f9033d084e6a0, 0x4c3a5ae1ce7b6670}}}, +{{{0x4138a434dcb8fa95, 0x870cf67d6c96840b, 0xde388574297be82c, 0x7c814db27262a55a}}, + {{0xbaf875e4c93da0dd, 0xb93282a771b9294d, 0x80d63fb7f4c6c460, 0x6de9c73dea66c181}}, + {{0x478904d5a04df8f2, 0xfafbae4ab10142d3, 0xf6c8ac63555d0998, 0x5aac4a412f90b104}}}, +{{{0xc64f326b3ac92908, 0x5551b282e663e1e0, 0x476b35f54a1a4b83, 0x1b9da3fe189f68c2}}, + {{0x603a0d0abd7f5134, 0x8089c932e1d3ae46, 0xdf2591398798bd63, 0x1c145cd274ba0235}}, + {{0x32e8386475f3d743, 0x365b8baf6ae5d9ef, 0x825238b6385b681e, 0x234929c1167d65e1}}}, +{{{0x984decaba077ade8, 0x383f77ad19eb389d, 0xc7ec6b7e2954d794, 0x59c77b3aeb7c3a7a}}, + {{0x48145cc21d099fcf, 0x4535c192cc28d7e5, 0x80e7c1e548247e01, 0x4a5f28743b2973ee}}, + {{0xd3add725225ccf62, 0x911a3381b2152c5d, 0xd8b39fad5b08f87d, 0x6f05606b4799fe3b}}}, +{{{0x9ffe9e92177ba962, 0x98aee71d0de5cae1, 0x3ff4ae942d831044, 0x714de12e58533ac8}}, + {{0x5b433149f91b6483, 0xadb5dc655a2cbf62, 0x87fa8412632827b3, 0x60895e91ab49f8d8}}, + {{0xe9ecf2ed0cf86c18, 0xb46d06120735dfd4, 0xbc9da09804b96be7, 0x73e2e62fd96dc26b}}}, +{{{0xed5b635449aa515e, 0xa865c49f0bc6823a, 0x850c1fe95b42d1c4, 0x30d76d6f03d315b9}}, + {{0x2eccdd0e632f9c1d, 0x51d0b69676893115, 0x52dfb76ba8637a58, 0x6dd37d49a00eef39}}, + {{0x6c4444172106e4c7, 0xfb53d680928d7f69, 0xb4739ea4694d3f26, 0x10c697112e864bb0}}}, +{{{0x6493c4277dbe5fde, 0x265d4fad19ad7ea2, 0x0e00dfc846304590, 0x25e61cabed66fe09}}, + {{0x0ca62aa08358c805, 0x6a3d4ae37a204247, 0x7464d3a63b11eddc, 0x03bf9baf550806ef}}, + {{0x3f13e128cc586604, 0x6f5873ecb459747e, 0xa0b63dedcc1268f5, 0x566d78634586e22c}}}, +{{{0x1637a49f9cc10834, 0xbc8e56d5a89bc451, 0x1cb5ec0f7f7fd2db, 0x33975bca5ecc35d9}}, + {{0xa1054285c65a2fd0, 0x6c64112af31667c3, 0x680ae240731aee58, 0x14fba5f34793b22a}}, + {{0x3cd746166985f7d4, 0x593e5e84c9c80057, 0x2fc3f2b67b61131e, 0x14829cea83fc526c}}}, +{{{0xff437b8497dd95c2, 0x6c744e30aa4eb5a7, 0x9e0c5d613c85e88b, 0x2fd9c71e5f758173}}, + {{0x21e70b2f4e71ecb8, 0xe656ddb940a477e3, 0xbf6556cece1d4f80, 0x05fc3bc4535d7b7e}}, + {{0x24b8b3ae52afdedd, 0x3495638ced3b30cf, 0x33a4bc83a9be8195, 0x373767475c651f04}}}, +{{{0x2fba99fd40d1add9, 0xb307166f96f4d027, 0x4363f05215f03bae, 0x1fbea56c3b18f999}}, + {{0x634095cb14246590, 0xef12144016c15535, 0x9e38140c8910bc60, 0x6bf5905730907c8c}}, + {{0x0fa778f1e1415b8a, 0x06409ff7bac3a77e, 0x6f52d7b89aa29a50, 0x02521cf67a635a56}}}, +{{{0x513fee0b0a9d5294, 0x8f98e75c0fdf5a66, 0xd4618688bfe107ce, 0x3fa00a7e71382ced}}, + {{0xb1146720772f5ee4, 0xe8f894b196079ace, 0x4af8224d00ac824a, 0x001753d9f7cd6cc4}}, + {{0x3c69232d963ddb34, 0x1dde87dab4973858, 0xaad7d1f9a091f285, 0x12b5fe2fa048edb6}}}, +{{{0x71f0fbc496fce34d, 0x73b9826badf35bed, 0xd2047261ff28c561, 0x749b76f96fb1206f}}, + {{0xdf2b7c26ad6f1e92, 0x4b66d323504b8913, 0x8c409dc0751c8bc3, 0x6f7e93c20796c7b8}}, + {{0x1f5af604aea6ae05, 0xc12351f1bee49c99, 0x61a808b5eeff6b66, 0x0fcec10f01e02151}}}, +{{{0x644d58a649fe1e44, 0x21fcaea231ad777e, 0x02441c5a887fd0d2, 0x4901aa7183c511f3}}, + {{0x3df2d29dc4244e45, 0x2b020e7493d8de0a, 0x6cc8067e820c214d, 0x413779166feab90a}}, + {{0x08b1b7548c1af8f0, 0xce0f7a7c246299b4, 0xf760b0f91e06d939, 0x41bb887b726d1213}}}, +{{{0x9267806c567c49d8, 0x066d04ccca791e6a, 0xa69f5645e3cc394b, 0x5c95b686a0788cd2}}, + {{0x97d980e0aa39f7d2, 0x35d0384252c6b51c, 0x7d43f49307cd55aa, 0x56bd36cfb78ac362}}, + {{0x2ac519c10d14a954, 0xeaf474b494b5fa90, 0xe6af8382a9f87a5a, 0x0dea6db1879be094}}}, +{{{0xaa66bf547344e5ab, 0xda1258888f1b4309, 0x5e87d2b3fd564b2f, 0x5b2c78885483b1dd}}, + {{0x15baeb74d6a8797a, 0x7ef55cf1fac41732, 0x29001f5a3c8b05c5, 0x0ad7cc8752eaccfb}}, + {{0x52151362793408cf, 0xeb0f170319963d94, 0xa833b2fa883d9466, 0x093a7fa775003c78}}}, +{{{0xe5107de63a16d7be, 0xa377ffdc9af332cf, 0x70d5bf18440b677f, 0x6a252b19a4a31403}}, + {{0xb8e9604460a91286, 0x7f3fd8047778d3de, 0x67d01e31bf8a5e2d, 0x7b038a06c27b653e}}, + {{0x9ed919d5d36990f3, 0x5213aebbdb4eb9f2, 0xc708ea054cb99135, 0x58ded57f72260e56}}}, +{{{0x78e79dade9413d77, 0xf257f9d59729e67d, 0x59db910ee37aa7e6, 0x6aa11b5bbb9e039c}}, + {{0xda6d53265b0fd48b, 0x8960823193bfa988, 0xd78ac93261d57e28, 0x79f2942d3a5c8143}}, + {{0x97da2f25b6c88de9, 0x251ba7eaacf20169, 0x09b44f87ef4eb4e4, 0x7d90ab1bbc6a7da5}}}, +{{{0x9acca683a7016bfe, 0x90505f4df2c50b6d, 0x6b610d5fcce435aa, 0x19a10d446198ff96}}, + {{0x1a07a3f496b3c397, 0x11ceaa188f4e2532, 0x7d9498d5a7751bf0, 0x19ed161f508dd8a0}}, + {{0x560a2cd687dce6ca, 0x7f3568c48664cf4d, 0x8741e95222803a38, 0x483bdab1595653fc}}}, +{{{0xfa780f148734fa49, 0x106f0b70360534e0, 0x2210776fe3e307bd, 0x3286c109dde6a0fe}}, + {{0xd6cf4d0ab4da80f6, 0x82483e45f8307fe0, 0x05005269ae6f9da4, 0x1c7052909cf7877a}}, + {{0x32ee7de2874e98d4, 0x14c362e9b97e0c60, 0x5781dcde6a60a38a, 0x217dd5eaaa7aa840}}}, +{{{0x9db7c4d0248e1eb0, 0xe07697e14d74bf52, 0x1e6a9b173c562354, 0x7fa7c21f795a4965}}, + {{0x8bdf1fb9be8c0ec8, 0x00bae7f8e30a0282, 0x4963991dad6c4f6c, 0x07058a6e5df6f60a}}, + {{0xe9eb02c4db31f67f, 0xed25fd8910bcfb2b, 0x46c8131f5c5cddb4, 0x33b21c13a0cb9bce}}}, +{{{0x360692f8087d8e31, 0xf4dcc637d27163f7, 0x25a4e62065ea5963, 0x659bf72e5ac160d9}}, + {{0x9aafb9b05ee38c5b, 0xbf9d2d4e071a13c7, 0x8eee6e6de933290a, 0x1c3bab17ae109717}}, + {{0x1c9ab216c7cab7b0, 0x7d65d37407bbc3cc, 0x52744750504a58d5, 0x09f2606b131a2990}}}, +{{{0x40e87d44744346be, 0x1d48dad415b52b25, 0x7c3a8a18a13b603e, 0x4eb728c12fcdbdf7}}, + {{0x7e234c597c6691ae, 0x64889d3d0a85b4c8, 0xdae2c90c354afae7, 0x0a871e070c6a9e1d}}, + {{0x3301b5994bbc8989, 0x736bae3a5bdd4260, 0x0d61ade219d59e3c, 0x3ee7300f2685d464}}}, +{{{0xf5d255e49e7dd6b7, 0x8016115c610b1eac, 0x3c99975d92e187ca, 0x13815762979125c2}}, + {{0x43fa7947841e7518, 0xe5c6fa59639c46d7, 0xa1065e1de3052b74, 0x7d47c6a2cfb89030}}, + {{0x3fdad0148ef0d6e0, 0x9d3e749a91546f3c, 0x71ec621026bb8157, 0x148cf58d34c9ec80}}}, +{{{0x46a492f67934f027, 0x469984bef6840aa9, 0x5ca1bc2a89611854, 0x3ff2fa1ebd5dbbd4}}, + {{0xe2572f7d9ae4756d, 0x56c345bb88f3487f, 0x9fd10b6d6960a88d, 0x278febad4eaea1b9}}, + {{0xb1aa681f8c933966, 0x8c21949c20290c98, 0x39115291219d3c52, 0x4104dd02fe9c677b}}}, +{{{0x72b2bf5e1124422a, 0xa1fa0c3398a33ab5, 0x94cb6101fa52b666, 0x2c863b00afaf53d5}}, + {{0x81214e06db096ab8, 0x21a8b6c90ce44f35, 0x6524c12a409e2af5, 0x0165b5a48efca481}}, + {{0xf190a474a0846a76, 0x12eff984cd2f7cc0, 0x695e290658aa2b8f, 0x591b67d9bffec8b8}}}, +{{{0x312f0d1c80b49bfa, 0x5979515eabf3ec8a, 0x727033c09ef01c88, 0x3de02ec7ca8f7bcb}}, + {{0x99b9b3719f18b55d, 0xe465e5faa18c641e, 0x61081136c29f05ed, 0x489b4f867030128b}}, + {{0xd232102d3aeb92ef, 0xe16253b46116a861, 0x3d7eabe7190baa24, 0x49f5fbba496cbebf}}}, +{{{0x30949a108a5bcfd4, 0xdc40dd70bc6473eb, 0x92c294c1307c0d1c, 0x5604a86dcbfa6e74}}, + {{0x155d628c1e9c572e, 0x8a4d86acc5884741, 0x91a352f6515763eb, 0x06a1a6c28867515b}}, + {{0x7288d1d47c1764b6, 0x72541140e0418b51, 0x9f031a6018acf6d1, 0x20989e89fe2742c6}}}, +{{{0x499777fd3a2dcc7f, 0x32857c2ca54fd892, 0xa279d864d207e3a0, 0x0403ed1d0ca67e29}}, + {{0x1674278b85eaec2e, 0x5621dc077acb2bdf, 0x640a4c1661cbf45a, 0x730b9950f70595d3}}, + {{0xc94b2d35874ec552, 0xc5e6c8cf98246f8d, 0xf7cb46fa16c035ce, 0x5bd7454308303dcc}}}, +{{{0x7f9ad19528b24cc2, 0x7f6b54656335c181, 0x66b8b66e4fc07236, 0x133a78007380ad83}}, + {{0x85c4932115e7792a, 0xc64c89a2bdcdddc9, 0x9d1e3da8ada3d762, 0x5bb7db123067f82c}}, + {{0x0961f467c6ca62be, 0x04ec21d6211952ee, 0x182360779bd54770, 0x740dca6d58f0e0d2}}}, +{{{0x50b70bf5d3f0af0b, 0x4feaf48ae32e71f7, 0x60e84ed3a55bbd34, 0x00ed489b3f50d1ed}}, + {{0x3906c72aed261ae5, 0x9ab68fd988e100f7, 0xf5e9059af3360197, 0x0e53dc78bf2b6d47}}, + {{0xb90829bf7971877a, 0x5e4444636d17e631, 0x4d05c52e18276893, 0x27632d9a5a4a4af5}}}, +{{{0xd11ff05154b260ce, 0xd86dc38e72f95270, 0x601fcd0d267cc138, 0x2b67916429e90ccd}}, + {{0xa98285d187eaffdb, 0xa5b4fbbbd8d0a864, 0xb658f27f022663f7, 0x3bbc2b22d99ce282}}, + {{0xb917c952583c0a58, 0x653ff9b80fe4c6f3, 0x9b0da7d7bcdf3c0c, 0x43a0eeb6ab54d60e}}}, +{{{0x396966a46d4a5487, 0xf811a18aac2bb3ba, 0x66e4685b5628b26b, 0x70a477029d929b92}}, + {{0x3ac6322357875fe8, 0xd9d4f4ecf5fbcb8f, 0x8dee8493382bb620, 0x50c5eaa14c799fdc}}, + {{0xdd0edc8bd6f2fb3c, 0x54c63aa79cc7b7a0, 0xae0b032b2c8d9f1a, 0x6f9ce107602967fb}}}, +{{{0xad1054b1cde1c22a, 0xc4a8e90248eb32df, 0x5f3e7b33accdc0ea, 0x72364713fc79963e}}, + {{0x139693063520e0b5, 0x437fcf7c88ea03fe, 0xf7d4c40bd3c959bc, 0x699154d1f893ded9}}, + {{0x315d5c75b4b27526, 0xcccb842d0236daa5, 0x22f0c8a3345fee8e, 0x73975a617d39dbed}}}, +{{{0xe4024df96375da10, 0x78d3251a1830c870, 0x902b1948658cd91c, 0x7e18b10b29b7438a}}, + {{0x6f37f392f4433e46, 0x0e19b9a11f566b18, 0x220fb78a1fd1d662, 0x362a4258a381c94d}}, + {{0x9071d9132b6beb2f, 0x0f26e9ad28418247, 0xeab91ec9bdec925d, 0x4be65bc8f48af2de}}}, +{{{0x78487feba36e7028, 0x5f3f13001dd8ce34, 0x934fb12d4b30c489, 0x056c244d397f0a2b}}, + {{0x1d50fba257c26234, 0x7bd4823adeb0678b, 0xc2b0dc6ea6538af5, 0x5665eec6351da73e}}, + {{0xdb3ee00943bfb210, 0x4972018720800ac2, 0x26ab5d6173bd8667, 0x20b209c2ab204938}}}, +{{{0x549e342ac07fb34b, 0x02d8220821373d93, 0xbc262d70acd1f567, 0x7a92c9fdfbcac784}}, + {{0x1fcca94516bd3289, 0x448d65aa41420428, 0x59c3b7b216a55d62, 0x49992cc64e612cd8}}, + {{0x65bd1bea70f801de, 0x1befb7c0fe49e28a, 0xa86306cdb1b2ae4a, 0x3b7ac0cd265c2a09}}}, +{{{0x822bee438c01bcec, 0x530cb525c0fbc73b, 0x48519034c1953fe9, 0x265cc261e09a0f5b}}, + {{0xf0d54e4f22ed39a7, 0xa2aae91e5608150a, 0xf421b2e9eddae875, 0x31bc531d6b7de992}}, + {{0xdf3d134da980f971, 0x7a4fb8d1221a22a7, 0x3df7d42035aad6d8, 0x2a14edcc6a1a125e}}}, +{{{0xdf48ee0752cfce4e, 0xc3fffaf306ec08b7, 0x05710b2ab95459c4, 0x161d25fa963ea38d}}, + {{0x231a8c570478433c, 0xb7b5270ec281439d, 0xdbaa99eae3d9079f, 0x2c03f5256c2b03d9}}, + {{0x790f18757b53a47d, 0x307b0130cf0c5879, 0x31903d77257ef7f9, 0x699468bdbd96bbaf}}}, +{{{0xbd1f2f46f4dafecf, 0x7cef0114a47fd6f7, 0xd31ffdda4a47b37f, 0x525219a473905785}}, + {{0xd8dd3de66aa91948, 0x485064c22fc0d2cc, 0x9b48246634fdea2f, 0x293e1c4e6c4a2e3a}}, + {{0x376e134b925112e1, 0x703778b5dca15da0, 0xb04589af461c3111, 0x5b605c447f032823}}}, +{{{0xb965805920c47c89, 0xe7f0100c923b8fcc, 0x0001256502e2ef77, 0x24a76dcea8aeb3ee}}, + {{0x3be9fec6f0e7f04c, 0x866a579e75e34962, 0x5542ef161e1de61a, 0x2f12fef4cc5abdd5}}, + {{0x0a4522b2dfc0c740, 0x10d06e7f40c9a407, 0xc6cf144178cff668, 0x5e607b2518a43790}}}, +{{{0x58b31d8f6cdf1818, 0x35cfa74fc36258a2, 0xe1b3ff4f66e61d6e, 0x5067acab6ccdd5f7}}, + {{0xa02c431ca596cf14, 0xe3c42d40aed3e400, 0xd24526802e0f26db, 0x201f33139e457068}}, + {{0xfd527f6b08039d51, 0x18b14964017c0006, 0xd5220eb02e25a4a8, 0x397cba8862460375}}}, +{{{0x30c13093f05959b2, 0xe23aa18de9a97976, 0x222fd491721d5e26, 0x2339d320766e6c3a}}, + {{0x7815c3fbc81379e7, 0xa6619420dde12af1, 0xffa9c0f885a8fdd5, 0x771b4022c1e1c252}}, + {{0xd87dd986513a2fa7, 0xf5ac9b71f9d4cf08, 0xd06bc31b1ea283b3, 0x331a189219971a76}}}, +{{{0xf5166f45fb4f80c6, 0x9c36c7de61c775cf, 0xe3d4e81b9041d91c, 0x31167c6b83bdfe21}}, + {{0x26512f3a9d7572af, 0x5bcbe28868074a9e, 0x84edc1c11180f7c4, 0x1ac9619ff649a67b}}, + {{0xf22b3842524b1068, 0x5068343bee9ce987, 0xfc9d71844a6250c8, 0x612436341f08b111}}}, +{{{0xd99d41db874e898d, 0x09fea5f16c07dc20, 0x793d2c67d00f9bbc, 0x46ebe2309e5eff40}}, + {{0x8b6349e31a2d2638, 0x9ddfb7009bd3fd35, 0x7f8bf1b8a3a06ba4, 0x1522aa3178d90445}}, + {{0x2c382f5369614938, 0xdafe409ab72d6d10, 0xe8c83391b646f227, 0x45fe70f50524306c}}}, +{{{0xda4875a6960c0b8c, 0x5b68d076ef0e2f20, 0x07fb51cf3d0b8fd4, 0x428d1623a0e392d4}}, + {{0x62f24920c8951491, 0x05f007c83f630ca2, 0x6fbb45d2f5c9d4b8, 0x16619f6db57a2245}}, + {{0x084f4a4401a308fd, 0xa82219c376a5caac, 0xdeb8de4643d1bc7d, 0x1d81592d60bd38c6}}}, +{{{0xd833d7beec2a4c38, 0x2c9162830acc20ed, 0xe93a47aa92df7581, 0x702d67a3333c4a81}}, + {{0x3a4a369a2f89c8a1, 0x63137a1d7c8de80d, 0xbcac008a78eda015, 0x2cb8b3a5b483b03f}}, + {{0x36e417cbcb1b90a1, 0x33b3ddaa7f11794e, 0x3f510808885bc607, 0x24141dc0e6a8020d}}}, +{{{0x59f73c773fefee9d, 0xb3f1ef89c1cf989d, 0xe35dfb42e02e545f, 0x5766120b47a1b47c}}, + {{0x91925dccbd83157d, 0x3ca1205322cc8094, 0x28e57f183f90d6e4, 0x1a4714cede2e767b}}, + {{0xdb20ba0fb8b6b7ff, 0xb732c3b677511fa1, 0xa92b51c099f02d89, 0x4f3875ad489ca5f1}}}, +{{{0xc7fc762f4932ab22, 0x7ac0edf72f4c3c1b, 0x5f6b55aa9aa895e8, 0x3680274dad0a0081}}, + {{0x79ed13f6ee73eec0, 0xa5c6526d69110bb1, 0xe48928c38603860c, 0x722a1446fd7059f5}}, + {{0xd0959fe9a8cf8819, 0xd0a995508475a99c, 0x6eac173320b09cc5, 0x628ecf04331b1095}}}, +{{{0x98bcb118a9d0ddbc, 0xee449e3408b4802b, 0x87089226b8a6b104, 0x685f349a45c7915d}}, + {{0x9b41acf85c74ccf1, 0xb673318108265251, 0x99c92aed11adb147, 0x7a47d70d34ecb40f}}, + {{0x60a0c4cbcc43a4f5, 0x775c66ca3677bea9, 0xa17aa1752ff8f5ed, 0x11ded9020e01fdc0}}}, +{{{0x890e7809caefe704, 0x8728296de30e8c6c, 0x4c5cd2a392aeb1c9, 0x194263d15771531f}}, + {{0x471f95b03bea93b7, 0x0552d7d43313abd3, 0xbd9370e2e17e3f7b, 0x7b120f1db20e5bec}}, + {{0x17d2fb3d86502d7a, 0xb564d84450a69352, 0x7da962c8a60ed75d, 0x00d0f85b318736aa}}}, +{{{0x978b142e777c84fd, 0xf402644705a8c062, 0xa67ad51be7e612c7, 0x2f7b459698dd6a33}}, + {{0xa6753c1efd7621c1, 0x69c0b4a7445671f5, 0x971f527405b23c11, 0x387bc74851a8c7cd}}, + {{0x81894b4d4a52a9a8, 0xadd93e12f6b8832f, 0x184d8548b61bd638, 0x3f1c62dbd6c9f6cd}}}, +{{{0x2e8f1f0091910c1f, 0xa4df4fe0bff2e12c, 0x60c6560aee927438, 0x6338283facefc8fa}}, + {{0x3fad3e40148f693d, 0x052656e194eb9a72, 0x2f4dcbfd184f4e2f, 0x406f8db1c482e18b}}, + {{0x9e630d2c7f191ee4, 0x4fbf8301bc3ff670, 0x787d8e4e7afb73c4, 0x50d83d5be8f58fa5}}}, +{{{0x85683916c11a1897, 0x2d69a4efe506d008, 0x39af1378f664bd01, 0x65942131361517c6}}, + {{0xc0accf90b4d3b66d, 0xa7059de561732e60, 0x033d1f7870c6b0ba, 0x584161cd26d946e4}}, + {{0xbbf2b1a072d27ca2, 0xbf393c59fbdec704, 0xe98dbbcee262b81e, 0x02eebd0b3029b589}}}, +{{{0x61368756a60dac5f, 0x17e02f6aebabdc57, 0x7f193f2d4cce0f7d, 0x20234a7789ecdcf0}}, + {{0x8765b69f7b85c5e8, 0x6ff0678bd168bab2, 0x3a70e77c1d330f9b, 0x3a5f6d51b0af8e7c}}, + {{0x76d20db67178b252, 0x071c34f9d51ed160, 0xf62a4a20b3e41170, 0x7cd682353cffe366}}}, +{{{0x0be1a45bd887fab6, 0x2a846a32ba403b6e, 0xd9921012e96e6000, 0x2838c8863bdc0943}}, + {{0xa665cd6068acf4f3, 0x42d92d183cd7e3d3, 0x5759389d336025d9, 0x3ef0253b2b2cd8ff}}, + {{0xd16bb0cf4a465030, 0xfa496b4115c577ab, 0x82cfae8af4ab419d, 0x21dcb8a606a82812}}}, +{{{0x5c6004468c9d9fc8, 0x2540096ed42aa3cb, 0x125b4d4c12ee2f9c, 0x0bc3d08194a31dab}}, + {{0x9a8d00fabe7731ba, 0x8203607e629e1889, 0xb2cc023743f3d97f, 0x5d840dbf6c6f678b}}, + {{0x706e380d309fe18b, 0x6eb02da6b9e165c7, 0x57bbba997dae20ab, 0x3a4276232ac196dd}}}, +{{{0x4b42432c8a7084fa, 0x898a19e3dfb9e545, 0xbe9f00219c58e45d, 0x1ff177cea16debd1}}, + {{0x3bf8c172db447ecb, 0x5fcfc41fc6282dbd, 0x80acffc075aa15fe, 0x0770c9e824e1a9f9}}, + {{0xcf61d99a45b5b5fd, 0x860984e91b3a7924, 0xe7300919303e3e89, 0x39f264fd41500b1e}}}, +{{{0xa7ad3417dbe7e29c, 0xbd94376a2b9c139c, 0xa0e91b8e93597ba9, 0x1712d73468889840}}, + {{0xd19b4aabfe097be1, 0xa46dfce1dfe01929, 0xc3c908942ca6f1ff, 0x65c621272c35f14e}}, + {{0xe72b89f8ce3193dd, 0x4d103356a125c0bb, 0x0419a93d2e1cfe83, 0x22f9800ab19ce272}}}, +{{{0x605a368a3e9ef8cb, 0xe3e9c022a5504715, 0x553d48b05f24248f, 0x13f416cd647626e5}}, + {{0x42029fdd9a6efdac, 0xb912cebe34a54941, 0x640f64b987bdf37b, 0x4171a4d38598cab4}}, + {{0xfa2758aa99c94c8c, 0x23006f6fb000b807, 0xfbd291ddadda5392, 0x508214fa574bd1ab}}}, +{{{0xc20269153ed6fe4b, 0xa65a6739511d77c4, 0xcbde26462c14af94, 0x22f960ec6faba74b}}, + {{0x461a15bb53d003d6, 0xb2102888bcf3c965, 0x27c576756c683a5a, 0x3a7758a4c86cb447}}, + {{0x548111f693ae5076, 0x1dae21df1dfd54a6, 0x12248c90f3115e65, 0x5d9fd15f8de7f494}}}, +{{{0x031408d36d63727f, 0x6a379aefd7c7b533, 0xa9e18fc5ccaee24b, 0x332f35914f8fbed3}}, + {{0x3f244d2aeed7521e, 0x8e3a9028432e9615, 0xe164ba772e9c16d4, 0x3bc187fa47eb98d8}}, + {{0x6d470115ea86c20c, 0x998ab7cb6c46d125, 0xd77832b53a660188, 0x450d81ce906fba03}}}, +{{{0xf8ae4d2ad8453902, 0x7018058ee8db2d1d, 0xaab3995fc7d2c11e, 0x53b16d2324ccca79}}, + {{0x23264d66b2cae0b5, 0x7dbaed33ebca6576, 0x030ebed6f0d24ac8, 0x2a887f78f7635510}}, + {{0x2a23b9e75c012d4f, 0x0c974651cae1f2ea, 0x2fb63273675d70ca, 0x0ba7250b864403f5}}}, +{{{0xbb0d18fd029c6421, 0xbc2d142189298f02, 0x8347f8e68b250e96, 0x7b9f2fe8032d71c9}}, + {{0xdd63589386f86d9c, 0x61699176e13a85a4, 0x2e5111954eaa7d57, 0x32c21b57fb60bdfb}}, + {{0xd87823cd319e0780, 0xefc4cfc1897775c5, 0x4854fb129a0ab3f7, 0x12c49d417238c371}}}, +{{{0x0950b533ffe83769, 0x21861c1d8e1d6bd1, 0xf022d8381302e510, 0x2509200c6391cab4}}, + {{0x09b3a01783799542, 0x626dd08faad5ee3f, 0xba00bceeeb70149f, 0x1421b246a0a444c9}}, + {{0x4aa43a8e8c24a7c7, 0x04c1f540d8f05ef5, 0xadba5e0c0b3eb9dc, 0x2ab5504448a49ce3}}}, +{{{0x2ed227266f0f5dec, 0x9824ee415ed50824, 0x807bec7c9468d415, 0x7093bae1b521e23f}}, + {{0xdc07ac631c5d3afa, 0x58615171f9df8c6c, 0x72a079d89d73e2b0, 0x7301f4ceb4eae15d}}, + {{0x6409e759d6722c41, 0xa674e1cf72bf729b, 0xbc0a24eb3c21e569, 0x390167d24ebacb23}}}, +{{{0x27f58e3bba353f1c, 0x4c47764dbf6a4361, 0xafbbc4e56e562650, 0x07db2ee6aae1a45d}}, + {{0xd7bb054ba2f2120b, 0xe2b9ceaeb10589b7, 0x3fe8bac8f3c0edbe, 0x4cbd40767112cb69}}, + {{0x0b603cc029c58176, 0x5988e3825cb15d61, 0x2bb61413dcf0ad8d, 0x7b8eec6c74183287}}}, +{{{0xe4ca40782cd27cb0, 0xdaf9c323fbe967bd, 0xb29bd34a8ad41e9e, 0x72810497626ede4d}}, + {{0x32fee570fc386b73, 0xda8b0141da3a8cc7, 0x975ffd0ac8968359, 0x6ee809a1b132a855}}, + {{0x9444bb31fcfd863a, 0x2fe3690a3e4e48c5, 0xdc29c867d088fa25, 0x13bd1e38d173292e}}}, +{{{0xd32b4cd8696149b5, 0xe55937d781d8aab7, 0x0bcb2127ae122b94, 0x41e86fcfb14099b0}}, + {{0x223fb5cf1dfac521, 0x325c25316f554450, 0x030b98d7659177ac, 0x1ed018b64f88a4bd}}, + {{0x3630dfa1b802a6b0, 0x880f874742ad3bd5, 0x0af90d6ceec5a4d4, 0x746a247a37cdc5d9}}}, +{{{0xd531b8bd2b7b9af6, 0x5005093537fc5b51, 0x232fcf25c593546d, 0x20a365142bb40f49}}, + {{0x6eccd85278d941ed, 0x2254ae83d22f7843, 0xc522d02e7bbfcdb7, 0x681e3351bff0e4e2}}, + {{0x8b64b59d83034f45, 0x2f8b71f21fa20efb, 0x69249495ba6550e4, 0x539ef98e45d5472b}}}, +{{{0x6e7bb6a1a6205275, 0xaa4f21d7413c8e83, 0x6f56d155e88f5cb2, 0x2de25d4ba6345be1}}, + {{0xd074d8961cae743f, 0xf86d18f5ee1c63ed, 0x97bdc55be7f4ed29, 0x4cbad279663ab108}}, + {{0x80d19024a0d71fcd, 0xc525c20afb288af8, 0xb1a3974b5f3a6419, 0x7d7fbcefe2007233}}}, +{{{0xfaef1e6a266b2801, 0x866c68c4d5739f16, 0xf68a2fbc1b03762c, 0x5975435e87b75a8d}}, + {{0xcd7c5dc5f3c29094, 0xc781a29a2a9105ab, 0x80c61d36421c3058, 0x4f9cd196dcd8d4d7}}, + {{0x199297d86a7b3768, 0xd0d058241ad17a63, 0xba029cad5c1c0c17, 0x7ccdd084387a0307}}}, +{{{0xdca6422c6d260417, 0xae153d50948240bd, 0xa9c0c1b4fb68c677, 0x428bd0ed61d0cf53}}, + {{0x9b0c84186760cc93, 0xcdae007a1ab32a99, 0xa88dec86620bda18, 0x3593ca848190ca44}}, + {{0x9213189a5e849aa7, 0xd4d8c33565d8facd, 0x8c52545b53fdbbd1, 0x27398308da2d63e6}}}, +{{{0x42c38d28435ed413, 0xbd50f3603278ccc9, 0xbb07ab1a79da03ef, 0x269597aebe8c3355}}, + {{0xb9a10e4c0a702453, 0x0fa25866d57d1bde, 0xffb9d9b5cd27daf7, 0x572c2945492c33fd}}, + {{0xc77fc745d6cd30be, 0xe4dfe8d3e3baaefb, 0xa22c8830aa5dda0c, 0x7f985498c05bca80}}}, +{{{0x3849ce889f0be117, 0x8005ad1b7b54a288, 0x3da3c39f23fc921c, 0x76c2ec470a31f304}}, + {{0xd35615520fbf6363, 0x08045a45cf4dfba6, 0xeec24fbc873fa0c2, 0x30f2653cd69b12e7}}, + {{0x8a08c938aac10c85, 0x46179b60db276bcb, 0xa920c01e0e6fac70, 0x2f1273f1596473da}}}, +{{{0x4739fc7c8ae01e11, 0xfd5274904a6aab9f, 0x41d98a8287728f2e, 0x5d9e572ad85b69f2}}, + {{0x30488bd755a70bc0, 0x06d6b5a4f1d442e7, 0xead1a69ebc596162, 0x38ac1997edc5f784}}, + {{0x0666b517a751b13b, 0x747d06867e9b858c, 0xacacc011454dde49, 0x22dfcd9cbfe9e69c}}}, +{{{0x8ddbd2e0c30d0cd9, 0xad8e665facbb4333, 0x8f6b258c322a961f, 0x6b2916c05448c1c7}}, + {{0x56ec59b4103be0a1, 0x2ee3baecd259f969, 0x797cb29413f5cd32, 0x0fe9877824cde472}}, + {{0x7edb34d10aba913b, 0x4ea3cd822e6dac0e, 0x66083dff6578f815, 0x4c303f307ff00a17}}}, +{{{0xd30a3bd617b28c85, 0xc5d377b739773bea, 0xc6c6e78c1e6a5cbf, 0x0d61b8f78b2ab7c4}}, + {{0x29fc03580dd94500, 0xecd27aa46fbbec93, 0x130a155fc2e2a7f8, 0x416b151ab706a1d5}}, + {{0x56a8d7efe9c136b0, 0xbd07e5cd58e44b20, 0xafe62fda1b57e0ab, 0x191a2af74277e8d2}}}, +{{{0xd550095bab6f4985, 0x04f4cd5b4fbfaf1a, 0x9d8e2ed12a0c7540, 0x2bc24e04b2212286}}, + {{0x09d4b60b2fe09a14, 0xc384f0afdbb1747e, 0x58e2ea8978b5fd6e, 0x519ef577b5e09b0a}}, + {{0x1863d7d91124cca9, 0x7ac08145b88a708e, 0x2bcd7309857031f5, 0x62337a6e8ab8fae5}}}, +{{{0x4bcef17f06ffca16, 0xde06e1db692ae16a, 0x0753702d614f42b0, 0x5f6041b45b9212d0}}, + {{0xd1ab324e1b3a1273, 0x18947cf181055340, 0x3b5d9567a98c196e, 0x7fa00425802e1e68}}, + {{0x7d531574028c2705, 0x80317d69db0d75fe, 0x30fface8ef8c8ddd, 0x7e9de97bb6c3e998}}}, +{{{0x1558967b9e6585a3, 0x97c99ce098e98b92, 0x10af149b6eb3adad, 0x42181fe8f4d38cfa}}, + {{0xf004be62a24d40dd, 0xba0659910452d41f, 0x81c45ee162a44234, 0x4cb829d8a22266ef}}, + {{0x1dbcaa8407b86681, 0x081f001e8b26753b, 0x3cd7ce6a84048e81, 0x78af11633f25f22c}}}, +{{{0x8416ebd40b50babc, 0x1508722628208bee, 0xa3148fafb9c1c36d, 0x0d07daacd32d7d5d}}, + {{0x3241c00e7d65318c, 0xe6bee5dcd0e86de7, 0x118b2dc2fbc08c26, 0x680d04a7fc603dc3}}, + {{0xf9c2414a695aa3eb, 0xdaa42c4c05a68f21, 0x7c6c23987f93963e, 0x210e8cd30c3954e3}}}, +{{{0xac4201f210a71c06, 0x6a65e0aef3bfb021, 0xbc42c35c393632f7, 0x56ea8db1865f0742}}, + {{0x2b50f16137fe6c26, 0xe102bcd856e404d8, 0x12b0f1414c561f6b, 0x51b17bc8d028ec91}}, + {{0xfff5fb4bcf535119, 0xf4989d79df1108a0, 0xbdfcea659a3ba325, 0x18a11f1174d1a6f2}}}, +{{{0x407375ab3f6bba29, 0x9ec3b6d8991e482e, 0x99c80e82e55f92e9, 0x307c13b6fb0c0ae1}}, + {{0xfbd63cdad27a5f2c, 0xf00fc4bc8aa106d7, 0x53fb5c1a8e64a430, 0x04eaabe50c1a2e85}}, + {{0x24751021cb8ab5e7, 0xfc2344495c5010eb, 0x5f1e717b4e5610a1, 0x44da5f18c2710cd5}}}, +{{{0x033cc55ff1b82eb5, 0xb15ae36d411cae52, 0xba40b6198ffbacd3, 0x768edce1532e861f}}, + {{0x9156fe6b89d8eacc, 0xe6b79451e23126a1, 0xbd7463d93944eb4e, 0x726373f6767203ae}}, + {{0xe305ca72eb7ef68a, 0x662cf31f70eadb23, 0x18f026fdb4c45b68, 0x513b5384b5d2ecbd}}}, +{{{0x46d46280c729989e, 0x4b93fbd05368a5dd, 0x63df3f81d1765a89, 0x34cebd64b9a0a223}}, + {{0x5e2702878af34ceb, 0x900b0409b946d6ae, 0x6512ebf7dabd8512, 0x61d9b76988258f81}}, + {{0xa6c5a71349b7d94b, 0xa3f3d15823eb9446, 0x0416fbd277484834, 0x69d45e6f2c70812f}}}, +{{{0xce16f74bc53c1431, 0x2b9725ce2072edde, 0xb8b9c36fb5b23ee7, 0x7e2e0e450b5cc908}}, + {{0x9fe62b434f460efb, 0xded303d4a63607d6, 0xf052210eb7a0da24, 0x237e7dbe00545b93}}, + {{0x013575ed6701b430, 0x231094e69f0bfd10, 0x75320f1583e47f22, 0x71afa699b11155e3}}}, +{{{0x65ce6f9b3953b61d, 0xc65839eaafa141e6, 0x0f435ffda9f759fe, 0x021142e9c2b1c28e}}, + {{0xea423c1c473b50d6, 0x51e87a1f3b38ef10, 0x9b84bf5fb2c9be95, 0x00731fbc78f89a1c}}, + {{0xe430c71848f81880, 0xbf960c225ecec119, 0xb6dae0836bba15e3, 0x4c4d6f3347e15808}}}, +{{{0x18f7eccfc17d1fc9, 0x6c75f5a651403c14, 0xdbde712bf7ee0cdf, 0x193fddaaa7e47a22}}, + {{0x2f0cddfc988f1970, 0x6b916227b0b9f51b, 0x6ec7b6c4779176be, 0x38bf9500a88f9fa8}}, + {{0x1fd2c93c37e8876f, 0xa2f61e5a18d1462c, 0x5080f58239241276, 0x6a6fb99ebf0d4969}}}, +{{{0x6a46c1bb560855eb, 0x2416bb38f893f09d, 0xd71d11378f71acc1, 0x75f76914a31896ea}}, + {{0xeeb122b5b6e423c6, 0x939d7010f286ff8e, 0x90a92a831dcf5d8c, 0x136fda9f42c5eb10}}, + {{0xf94cdfb1a305bdd1, 0x0f364b9d9ff82c08, 0x2a87d8a5c3bb588a, 0x022183510be8dcba}}}, +{{{0x4af766385ead2d14, 0xa08ed880ca7c5830, 0x0d13a6e610211e3d, 0x6a071ce17b806c03}}, + {{0x9d5a710143307a7f, 0xb063de9ec47da45f, 0x22bbfe52be927ad3, 0x1387c441fd40426c}}, + {{0xb5d3c3d187978af8, 0x722b5a3d7f0e4413, 0x0d7b4848bb477ca0, 0x3171b26aaf1edc92}}}, +{{{0xa92f319097564ca8, 0xff7bb84c2275e119, 0x4f55fe37a4875150, 0x221fd4873cf0835a}}, + {{0xa60db7d8b28a47d1, 0xa6bf14d61770a4f1, 0xd4a1f89353ddbd58, 0x6c514a63344243e9}}, + {{0x2322204f3a156341, 0xfb73e0e9ba0a032d, 0xfce0dd4c410f030e, 0x48daa596fb924aaa}}}, +{{{0x6eca8e665ca59cc7, 0xa847254b2e38aca0, 0x31afc708d21e17ce, 0x676dd6fccad84af7}}, + {{0x14f61d5dc84c9793, 0x9941f9e3ef418206, 0xcdf5b88f346277ac, 0x58c837fa0e8a79a9}}, + {{0x0cf9688596fc9058, 0x1ddcbbf37b56a01b, 0xdcc2e77d4935d66a, 0x1c4f73f2c6a57f0a}}}, +{{{0x0e7a4fbd305fa0bb, 0x829d4ce054c663ad, 0xf421c3832fe33848, 0x795ac80d1bf64c42}}, + {{0xb36e706efc7c3484, 0x73dfc9b4c3c1cf61, 0xeb1d79c9781cc7e5, 0x70459adb7daf675c}}, + {{0x1b91db4991b42bb3, 0x572696234b02dcca, 0x9fdf9ee51f8c78dc, 0x5fe162848ce21fd3}}}, +{{{0xe2790aae4d077c41, 0x8b938270db7469a3, 0x6eb632dc8abd16a2, 0x720814ecaa064b72}}, + {{0x315c29c795115389, 0xd7e0e507862f74ce, 0x0c4a762185927432, 0x72de6c984a25a1e4}}, + {{0xae9ab553bf6aa310, 0x050a50a9806d6e1b, 0x92bb7403adff5139, 0x0394d27645be618b}}}, +{{{0x4d572251857eedf4, 0xe3724edde19e93c5, 0x8a71420e0b797035, 0x3b3c833687abe743}}, + {{0xf5396425b23545a4, 0x15a7a27e98fbb296, 0xab6c52bc636fdd86, 0x79d995a8419334ee}}, + {{0xcd8a8ea61195dd75, 0xa504d8a81dd9a82f, 0x540dca81a35879b6, 0x60dd16a379c86a8a}}}, +{{{0x35a2c8487381e559, 0x596ffea6d78082cb, 0xcb9771ebdba7b653, 0x5a08b5019b4da685}}, + {{0x3501d6f8153e47b8, 0xb7a9675414a2f60c, 0x112ee8b6455d9523, 0x4e62a3c18112ea8a}}, + {{0xc8d4ac04516ab786, 0x595af3215295b23d, 0xd6edd234db0230c1, 0x0929efe8825b41cc}}}, +{{{0x5f0601d1cbd0f2d3, 0x736e412f6132bb7f, 0x83604432238dde87, 0x1e3a5272f5c0753c}}, + {{0x8b3172b7ad56651d, 0x01581b7a3fabd717, 0x2dc94df6424df6e4, 0x30376e5d2c29284f}}, + {{0xd2918da78159a59c, 0x6bdc1cd93f0713f3, 0x565f7a934acd6590, 0x53daacec4cb4c128}}}, +{{{0x4ca73bd79cc8a7d6, 0x4d4a738f47e9a9b2, 0xf4cbf12942f5fe00, 0x01a13ff9bdbf0752}}, + {{0x99852bc3852cfdb0, 0x2cc12e9559d6ed0b, 0x70f9e2bf9b5ac27b, 0x4f3b8c117959ae99}}, + {{0x55b6c9c82ff26412, 0x1ac4a8c91fb667a8, 0xd527bfcfeb778bf2, 0x303337da7012a3be}}}, +{{{0x955422228c1c9d7c, 0x01fac1371a9b340f, 0x7e8d9177925b48d7, 0x53f8ad5661b3e31b}}, + {{0x976d3ccbfad2fdd1, 0xcb88839737a640a8, 0x2ff00c1d6734cb25, 0x269ff4dc789c2d2b}}, + {{0x0c003fbdc08d678d, 0x4d982fa37ead2b17, 0xc07e6bcdb2e582f1, 0x296c7291df412a44}}}, +{{{0x7903de2b33daf397, 0xd0ff0619c9a624b3, 0x8a1d252b555b3e18, 0x2b6d581c52e0b7c0}}, + {{0xdfb23205dab8b59e, 0x465aeaa0c8092250, 0xd133c1189a725d18, 0x2327370261f117d1}}, + {{0x3d0543d3623e7986, 0x679414c2c278a354, 0xae43f0cc726196f6, 0x7836c41f8245eaba}}}, +{{{0xe7a254db49e95a81, 0x5192d5d008b0ad73, 0x4d20e5b1d00afc07, 0x5d55f8012cf25f38}}, + {{0xca651e848011937c, 0xc6b0c46e6ef41a28, 0xb7021ba75f3f8d52, 0x119dff99ead7b9fd}}, + {{0x43eadfcbf4b31d4d, 0xc6503f7411148892, 0xfeee68c5060d3b17, 0x329293b3dd4a0ac8}}}, +{{{0x4e59214fe194961a, 0x49be7dc70d71cd4f, 0x9300cfd23b50f22d, 0x4789d446fc917232}}, + {{0x2879852d5d7cb208, 0xb8dedd70687df2e7, 0xdc0bffab21687891, 0x2b44c043677daa35}}, + {{0x1a1c87ab074eb78e, 0xfac6d18e99daf467, 0x3eacbbcd484f9067, 0x60c52eef2bb9a4e4}}}, +{{{0x0b5d89bc3bfd8bf1, 0xb06b9237c9f3551a, 0x0e4c16b0d53028f5, 0x10bc9c312ccfcaab}}, + {{0x702bc5c27cae6d11, 0x44c7699b54a48cab, 0xefbc4056ba492eb2, 0x70d77248d9b6676d}}, + {{0xaa8ae84b3ec2a05b, 0x98699ef4ed1781e0, 0x794513e4708e85d1, 0x63755bd3a976f413}}}, +{{{0xb55fa03e2ad10853, 0x356f75909ee63569, 0x9ff9f1fdbe69b890, 0x0d8cc1c48bc16f84}}, + {{0x3dc7101897f1acb7, 0x5dda7d5ec165bbd8, 0x508e5b9c0fa1020f, 0x2763751737c52a56}}, + {{0x029402d36eb419a9, 0xf0b44e7e77b460a5, 0xcfa86230d43c4956, 0x70c2dd8a7ad166e7}}}, +{{{0x656194509f6fec0e, 0xee2e7ea946c6518d, 0x9733c1f367e09b5c, 0x2e0fac6363948495}}, + {{0x91d4967db8ed7e13, 0x74252f0ad776817a, 0xe40982e00d852564, 0x32b8613816a53ce5}}, + {{0x79e7f7bee448cd64, 0x6ac83a67087886d0, 0xf89fd4d9a0e4db2e, 0x4179215c735a4f41}}}, +{{{0x8c7094e7d7dced2a, 0x97fb8ac347d39c70, 0xe13be033a906d902, 0x700344a30cd99d76}}, + {{0xe4ae33b9286bcd34, 0xb7ef7eb6559dd6dc, 0x278b141fb3d38e1f, 0x31fa85662241c286}}, + {{0xaf826c422e3622f4, 0xc12029879833502d, 0x9bc1b7e12b389123, 0x24bb2312a9952489}}}, +{{{0xb1a8ed1732de67c3, 0x3cb49418461b4948, 0x8ebd434376cfbcd2, 0x0fee3e871e188008}}, + {{0x41f80c2af5f85c6b, 0x687284c304fa6794, 0x8945df99a3ba1bad, 0x0d1d2af9ffeb5d16}}, + {{0xa9da8aa132621edf, 0x30b822a159226579, 0x4004197ba79ac193, 0x16acd79718531d76}}}, +{{{0x72df72af2d9b1d3d, 0x63462a36a432245a, 0x3ecea07916b39637, 0x123e0ef6b9302309}}, + {{0xc959c6c57887b6ad, 0x94e19ead5f90feba, 0x16e24e62a342f504, 0x164ed34b18161700}}, + {{0x487ed94c192fe69a, 0x61ae2cea3a911513, 0x877bf6d3b9a4de27, 0x78da0fc61073f3eb}}}, +{{{0x5bf15d28e52bc66a, 0x2c47e31870f01a8e, 0x2419afbc06c28bdd, 0x2d25deeb256b173a}}, + {{0xa29f80f1680c3a94, 0x71f77e151ae9e7e6, 0x1100f15848017973, 0x054aa4b316b38ddd}}, + {{0xdfc8468d19267cb8, 0x0b28789c66e54daf, 0x2aeb1d2a666eec17, 0x134610a6ab7da760}}}, +{{{0xcaf55ec27c59b23f, 0x99aeed3e154d04f2, 0x68441d72e14141f4, 0x140345133932a0a2}}, + {{0xd91430e0dc028c3c, 0x0eb955a85217c771, 0x4b09e1ed2c99a1fa, 0x42881af2bd6a743c}}, + {{0x7bfec69aab5cad3d, 0xc23e8cd34cb2cfad, 0x685dd14bfb37d6a2, 0x0ad6d64415677a18}}}, +{{{0x781a439e417becb5, 0x4ac5938cd10e0266, 0x5da385110692ac24, 0x11b065a2ade31233}}, + {{0x7914892847927e9f, 0x33dad6ef370aa877, 0x1f8f24fa11122703, 0x5265ac2f2adf9592}}, + {{0x405fdd309afcb346, 0xd9723d4428e63f54, 0x94c01df05f65aaae, 0x43e4dc3ae14c0809}}}, +{{{0xbc12c7f1a938a517, 0x473028ab3180b2e1, 0x3f78571efbcd254a, 0x74e534426ff6f90f}}, + {{0xea6f7ac3adc2c6a3, 0xd0e928f6e9717c94, 0xe2d379ead645eaf5, 0x46dd8785c51ffbbe}}, + {{0x709801be375c8898, 0x4b06dab5e3fd8348, 0x75880ced27230714, 0x2b09468fdd2f4c42}}}, +{{{0x97c749eeb701cb96, 0x83f438d4b6a369c3, 0x62962b8b9a402cd9, 0x6976c7509888df7b}}, + {{0x5b97946582ffa02a, 0xda096a51fea8f549, 0xa06351375f77af9b, 0x1bcfde61201d1e76}}, + {{0x4a4a5490246a59a2, 0xd63ebddee87fdd90, 0xd9437c670d2371fa, 0x69e87308d30f8ed6}}}, +{{{0x435a8bb15656beb0, 0xf8fac9ba4f4d5bca, 0xb9b278c41548c075, 0x3eb0ef76e892b622}}, + {{0x0f80bf028bc80303, 0x6aae16b37a18cefb, 0xdd47ea47d72cd6a3, 0x61943588f4ed39aa}}, + {{0xd26e5c3e91039f85, 0xc0e9e77df6f33aa9, 0xe8968c5570066a93, 0x3c34d1881faaaddd}}}, +{{{0x3f9d2b5ea09f9ec0, 0x1dab3b6fb623a890, 0xa09ba3ea72d926c4, 0x374193513fd8b36d}}, + {{0xbd5b0b8f2fffe0d9, 0x6aa254103ed24fb9, 0x2ac7d7bcb26821c4, 0x605b394b60dca36a}}, + {{0xb4e856e45a9d1ed2, 0xefe848766c97a9a2, 0xb104cf641e5eee7d, 0x2f50b81c88a71c8f}}}, +{{{0x31723c61fc6811bb, 0x9cb450486211800f, 0x768933d347995753, 0x3491a53502752fcd}}, + {{0x2b552ca0a7da522a, 0x3230b336449b0250, 0xf2c4c5bca4b99fb9, 0x7b2c674958074a22}}, + {{0xd55165883ed28cdf, 0x12d84fd2d362de39, 0x0a874ad3e3378e4f, 0x000d2b1f7c763e74}}}, +{{{0x3d420811d06d4a67, 0xbefc048590e0ffe3, 0xf870c6b7bd487bde, 0x6e2a7316319afa28}}, + {{0x9624778c3e94a8ab, 0x0ad6f3cee9a78bec, 0x948ac7810d743c4f, 0x76627935aaecfccc}}, + {{0x56a8ac24d6d59a9f, 0xc8db753e3096f006, 0x477f41e68f4c5299, 0x588d851cf6c86114}}}, +{{{0x51138ec78df6b0fe, 0x5397da89e575f51b, 0x09207a1d717af1b9, 0x2102fdba2b20d650}}, + {{0xcd2a65e777d1f515, 0x548991878faa60f1, 0xb1b73bbcdabc06e5, 0x654878cba97cc9fb}}, + {{0x969ee405055ce6a1, 0x36bca7681251ad29, 0x3a1af517aa7da415, 0x0ad725db29ecb2ba}}}, +{{{0xdc4267b1834e2457, 0xb67544b570ce1bc5, 0x1af07a0bf7d15ed7, 0x4aefcffb71a03650}}, + {{0xfec7bc0c9b056f85, 0x537d5268e7f5ffd7, 0x77afc6624312aefa, 0x4f675f5302399fd9}}, + {{0xc32d36360415171e, 0xcd2bef118998483b, 0x870a6eadd0945110, 0x0bccbb72a2a86561}}}, +{{{0x185e962feab1a9c8, 0x86e7e63565147dcd, 0xb092e031bb5b6df2, 0x4024f0ab59d6b73e}}, + {{0x186d5e4c50fe1296, 0xe0397b82fee89f7e, 0x3bc7f6c5507031b0, 0x6678fd69108f37c2}}, + {{0x1586fa31636863c2, 0x07f68c48572d33f2, 0x4f73cc9f789eaefc, 0x2d42e2108ead4701}}}, +{{{0x97f5131594dfd29b, 0x6155985d313f4c6a, 0xeba13f0708455010, 0x676b2608b8d2d322}}, + {{0x21717b0d0f537593, 0x914e690b131e064c, 0x1bb687ae752ae09f, 0x420bf3a79b423c6e}}, + {{0x8138ba651c5b2b47, 0x8671b6ec311b1b80, 0x7bff0cb1bc3135b0, 0x745d2ffa9c0cf1e0}}}, +{{{0xbf525a1e2bc9c8bd, 0xea5b260826479d81, 0xd511c70edf0155db, 0x1ae23ceb960cf5d0}}, + {{0x6036df5721d34e6a, 0xb1db8827997bb3d0, 0xd3c209c3c8756afa, 0x06e15be54c1dc839}}, + {{0x5b725d871932994a, 0x32351cb5ceb1dab0, 0x7dc41549dab7ca05, 0x58ded861278ec1f7}}}, +{{{0xd8173793f266c55c, 0xc8c976c5cc454e49, 0x5ce382f8bc26c3a8, 0x2ff39de85485f6f9}}, + {{0x2dfb5ba8b6c2c9a8, 0x48eeef8ef52c598c, 0x33809107f12d1573, 0x08ba696b531d5bd8}}, + {{0x77ed3eeec3efc57a, 0x04e05517d4ff4811, 0xea3d7a3ff1a671cb, 0x120633b4947cfe54}}}, +{{{0x0b94987891610042, 0x4ee7b13cecebfae8, 0x70be739594f0a4c0, 0x35d30a99b4d59185}}, + {{0x82bd31474912100a, 0xde237b6d7e6fbe06, 0xe11e761911ea79c6, 0x07433be3cb393bde}}, + {{0xff7944c05ce997f4, 0x575d3de4b05c51a3, 0x583381fd5a76847c, 0x2d873ede7af6da9f}}}, +{{{0x157a316443373409, 0xfab8b7eef4aa81d9, 0xb093fee6f5a64806, 0x2e773654707fa7b6}}, + {{0xaa6202e14e5df981, 0xa20d59175015e1f5, 0x18a275d3bae21d6c, 0x0543618a01600253}}, + {{0x0deabdf4974c23c1, 0xaa6f0a259dce4693, 0x04202cb8a29aba2c, 0x4b1443362d07960d}}}, +{{{0x47b837f753242cec, 0x256dc48cc04212f2, 0xe222fbfbe1d928c5, 0x48ea295bad8a2c07}}, + {{0x299b1c3f57c5715e, 0x96cb929e6b686d90, 0x3004806447235ab3, 0x2c435c24a44d9fe1}}, + {{0x0607c97c80f8833f, 0x0e851578ca25ec5b, 0x54f7450b161ebb6f, 0x7bcb4792a0def80e}}}, +{{{0x8487e3d02bc73659, 0x4baf8445059979df, 0xd17c975adcad6fbf, 0x57369f0bdefc96b6}}, + {{0x1cecd0a0045224c2, 0x757f1b1b69e53952, 0x775b7a925289f681, 0x1b6cc62016736148}}, + {{0xf1a9990175638698, 0x353dd1beeeaa60d3, 0x849471334c9ba488, 0x63fa6e6843ade311}}}, +{{{0xd15c20536597c168, 0x9f73740098d28789, 0x18aee7f13257ba1f, 0x3418bfda07346f14}}, + {{0x2195becdd24b5eb7, 0x5e41f18cc0cd44f9, 0xdf28074441ca9ede, 0x07073b98f35b7d67}}, + {{0xd03c676c4ce530d4, 0x0b64c0473b5df9f4, 0x065cef8b19b3a31e, 0x3084d661533102c9}}}, +{{{0xe1f6b79ebf8469ad, 0x15801004e2663135, 0x9a498330af74181b, 0x3ba2504f049b673c}}, + {{0x9a6ce876760321fd, 0x7fe2b5109eb63ad8, 0x00e7d4ae8ac80592, 0x73d86b7abb6f723a}}, + {{0x0b52b5606dba5ab6, 0xa9134f0fbbb1edab, 0x30a9520d9b04a635, 0x6813b8f37973e5db}}}, +{{{0x9854b054334127c1, 0x105d047882fbff25, 0xdb49f7f944186f4f, 0x1768e838bed0b900}}, + {{0xf194ca56f3157e29, 0x136d35705ef528a5, 0xdd4cef778b0599bc, 0x7d5472af24f833ed}}, + {{0xd0ef874daf33da47, 0x00d3be5db6e339f9, 0x3f2a8a2f9c9ceece, 0x5d1aeb792352435a}}}, +{{{0xf59e6bb319cd63ca, 0x670c159221d06839, 0xb06d565b2150cab6, 0x20fb199d104f12a3}}, + {{0x12c7bfaeb61ba775, 0xb84e621fe263bffd, 0x0b47a5c35c840dcf, 0x7e83be0bccaf8634}}, + {{0x61943dee6d99c120, 0x86101f2e460b9fe0, 0x6bb2f1518ee8598d, 0x76b76289fcc475cc}}}, +{{{0x791b4cc1756286fa, 0xdbced317d74a157c, 0x7e732421ea72bde6, 0x01fe18491131c8e9}}, + {{0x4245f1a1522ec0b3, 0x558785b22a75656d, 0x1d485a2548a1b3c0, 0x60959eccd58fe09f}}, + {{0x3ebfeb7ba8ed7a09, 0x49fdc2bbe502789c, 0x44ebce5d3c119428, 0x35e1eb55be947f4a}}}, +{{{0xdbdae701c5738dd3, 0xf9c6f635b26f1bee, 0x61e96a8042f15ef4, 0x3aa1d11faf60a4d8}}, + {{0x14fd6dfa726ccc74, 0x3b084cfe2f53b965, 0xf33ae4f552a2c8b4, 0x59aab07a0d40166a}}, + {{0x77bcec4c925eac25, 0x1848718460137738, 0x5b374337fea9f451, 0x1865e78ec8e6aa46}}}, +{{{0xccc4b7c7b66e1f7a, 0x44157e25f50c2f7e, 0x3ef06dfc713eaf1c, 0x582f446752da63f7}}, + {{0x967c54e91c529ccb, 0x30f6269264c635fb, 0x2747aff478121965, 0x17038418eaf66f5c}}, + {{0xc6317bd320324ce4, 0xa81042e8a4488bc4, 0xb21ef18b4e5a1364, 0x0c2a1c4bcda28dc9}}}, +{{{0xd24dc7d06f1f0447, 0xb2269e3edb87c059, 0xd15b0272fbb2d28f, 0x7c558bd1c6f64877}}, + {{0xedc4814869bd6945, 0x0d6d907dbe1c8d22, 0xc63bd212d55cc5ab, 0x5a6a9b30a314dc83}}, + {{0xd0ec1524d396463d, 0x12bb628ac35a24f0, 0xa50c3a791cbc5fa4, 0x0404a5ca0afbafc3}}}, +{{{0x8c1f40070aa743d6, 0xccbad0cb5b265ee8, 0x574b046b668fd2de, 0x46395bfdcadd9633}}, + {{0x62bc9e1b2a416fd1, 0xb5c6f728e350598b, 0x04343fd83d5d6967, 0x39527516e7f8ee98}}, + {{0x117fdb2d1a5d9a9c, 0x9c7745bcd1005c2a, 0xefd4bef154d56fea, 0x76579a29e822d016}}}, +{{{0x45b68e7e49c02a17, 0x23cd51a2bca9a37f, 0x3ed65f11ec224c1b, 0x43a384dc9e05bdb1}}, + {{0x333cb51352b434f2, 0xd832284993de80e1, 0xb5512887750d35ce, 0x02c514bb2a2777c1}}, + {{0x684bd5da8bf1b645, 0xfb8bd37ef6b54b53, 0x313916d7a9b0d253, 0x1160920961548059}}}, +{{{0xb44d166929dacfaa, 0xda529f4c8413598f, 0xe9ef63ca453d5559, 0x351e125bc5698e0b}}, + {{0x7a385616369b4dcd, 0x75c02ca7655c3563, 0x7dc21bf9d4f18021, 0x2f637d7491e6e042}}, + {{0xd4b49b461af67bbe, 0xd603037ac8ab8961, 0x71dee19ff9a699fb, 0x7f182d06e7ce2a9a}}}, +{{{0x7a7c8e64ab0168ec, 0xcb5a4a5515edc543, 0x095519d347cd0eda, 0x67d4ac8c343e93b0}}, + {{0x09454b728e217522, 0xaa58e8f4d484b8d8, 0xd358254d7f46903c, 0x44acc043241c5217}}, + {{0x1c7d6bbb4f7a5777, 0x8b35fed4918313e1, 0x4adca1c6c96b4684, 0x556d1c8312ad71bd}}}, +{{{0x17ef40e30c8d3982, 0x31f7073e15a3fa34, 0x4f21f3cb0773646e, 0x746c6c6d1d824eff}}, + {{0x81f06756b11be821, 0x0faff82310a3f3dd, 0xf8b2d0556a99465d, 0x097abe38cc8c7f05}}, + {{0x0c49c9877ea52da4, 0x4c4369559bdc1d43, 0x022c3809f7ccebd2, 0x577e14a34bee84bd}}}, +{{{0xf0e268ac61a73b0a, 0xf2fafa103791a5f5, 0xc1e13e826b6d00e9, 0x60fa7ee96fd78f42}}, + {{0x94fecebebd4dd72b, 0xf46a4fda060f2211, 0x124a5977c0c8d1ff, 0x705304b8fb009295}}, + {{0xb63d1d354d296ec6, 0xf3c3053e5fad31d8, 0x670b958cb4bd42ec, 0x21398e0ca16353fd}}}, +{{{0x216ab2ca8da7d2ef, 0x366ad9dd99f42827, 0xae64b9004fdd3c75, 0x403a395b53909e62}}, + {{0x86c5fc16861b7e9a, 0xf6a330476a27c451, 0x01667267a1e93597, 0x05ffb9cd6082dfeb}}, + {{0xa617fa9ff53f6139, 0x60f2b5e513e66cb6, 0xd7a8beefb3448aa4, 0x7a2932856f5ea192}}}, +{{{0x0b39d761b02de888, 0x5f550e7ed2414e1f, 0xa6bfa45822e1a940, 0x050a2f7dfd447b99}}, + {{0xb89c444879639302, 0x4ae4f19350c67f2c, 0xf0b35da8c81af9c6, 0x39d0003546871017}}, + {{0x437c3b33a650db77, 0x6bafe81dbac52bb2, 0xfe99402d2db7d318, 0x2b5b7eec372ba6ce}}}, +{{{0xb3bc4bbd83f50eef, 0x508f0c998c927866, 0x43e76587c8b7e66e, 0x0f7655a3a47f98d9}}, + {{0xa694404d613ac8f4, 0x500c3c2bfa97e72c, 0x874104d21fcec210, 0x1b205fb38604a8ee}}, + {{0x55ecad37d24b133c, 0x441e147d6038c90b, 0x656683a1d62c6fee, 0x0157d5dc87e0ecae}}}, +{{{0xf2a7af510354c13d, 0xd7a0b145aa372b60, 0x2869b96a05a3d470, 0x6528e42d82460173}}, + {{0x95265514d71eb524, 0xe603d8815df14593, 0x147cdf410d4de6b7, 0x5293b1730437c850}}, + {{0x23d0e0814bccf226, 0x92c745cd8196fb93, 0x8b61796c59541e5b, 0x40a44df0c021f978}}}, +{{{0xdaa869894f20ea6a, 0xea14a3d14c620618, 0x6001fccb090bf8be, 0x35f4e822947e9cf0}}, + {{0x86c96e514bc5d095, 0xf20d4098fca6804a, 0x27363d89c826ea5d, 0x39ca36565719cacf}}, + {{0x97506f2f6f87b75c, 0xc624aea0034ae070, 0x1ec856e3aad34dd6, 0x055b0be0e440e58f}}}, +{{{0x6469a17d89735d12, 0xdb6f27d5e662b9f1, 0x9fcba3286a395681, 0x363b8004d269af25}}, + {{0x4d12a04b6ea33da2, 0x57cf4c15e36126dd, 0x90ec9675ee44d967, 0x64ca348d2a985aac}}, + {{0x99588e19e4c4912d, 0xefcc3b4e1ca5ce6b, 0x4522ea60fa5b98d5, 0x7064bbab1de4a819}}}, +{{{0xb919e1515a770641, 0xa9a2e2c74e7f8039, 0x7527250b3df23109, 0x756a7330ac27b78b}}, + {{0xa290c06142542129, 0xf2e2c2aebe8d5b90, 0xcf2458db76abfe1b, 0x02157ade83d626bf}}, + {{0x3e46972a1b9a038b, 0x2e4ee66a7ee03fb4, 0x81a248776edbb4ca, 0x1a944ee88ecd0563}}}, +{{{0xd5a91d1151039372, 0x2ed377b799ca26de, 0xa17202acfd366b6b, 0x0730291bd6901995}}, + {{0xbb40a859182362d6, 0xb99f55778a4d1abb, 0x8d18b427758559f6, 0x26c20fe74d26235a}}, + {{0x648d1d9fe9cc22f5, 0x66bc561928dd577c, 0x47d3ed21652439d1, 0x49d271acedaf8b49}}}, +{{{0x89f5058a382b33f3, 0x5ae2ba0bad48c0b4, 0x8f93b503a53db36e, 0x5aa3ed9d95a232e6}}, + {{0x2798aaf9b4b75601, 0x5eac72135c8dad72, 0xd2ceaa6161b7a023, 0x1bbfb284e98f7d4e}}, + {{0x656777e9c7d96561, 0xcb2b125472c78036, 0x65053299d9506eee, 0x4a07e14e5e8957cc}}}, +{{{0x4ee412cb980df999, 0xa315d76f3c6ec771, 0xbba5edde925c77fd, 0x3f0bac391d313402}}, + {{0x240b58cdc477a49b, 0xfd38dade6447f017, 0x19928d32a7c86aad, 0x50af7aed84afa081}}, + {{0x6e4fde0115f65be5, 0x29982621216109b2, 0x780205810badd6d9, 0x1921a316baebd006}}}, +{{{0x89422f7edfb870fc, 0x2c296beb4f76b3bd, 0x0738f1d436c24df7, 0x6458df41e273aeb0}}, + {{0xd75aad9ad9f3c18b, 0x566a0eef60b1c19c, 0x3e9a0bac255c0ed9, 0x7b049deca062c7f5}}, + {{0xdccbe37a35444483, 0x758879330fedbe93, 0x786004c312c5dd87, 0x6093dccbc2950e64}}}, +{{{0x1ff39a8585e0706d, 0x36d0a5d8b3e73933, 0x43b9f2e1718f453b, 0x57d1ea084827a97c}}, + {{0x6bdeeebe6084034b, 0x3199c2b6780fb854, 0x973376abb62d0695, 0x6e3180c98b647d90}}, + {{0xee7ab6e7a128b071, 0xa4c1596d93a88baa, 0xf7b4de82b2216130, 0x363e999ddd97bd18}}}, +{{{0x96a843c135ee1fc4, 0x976eb35508e4c8cf, 0xb42f6801b58cd330, 0x48ee9b78693a052b}}, + {{0x2f1848dce24baec6, 0x769b7255babcaf60, 0x90cb3c6e3cefe931, 0x231f979bc6f9b355}}, + {{0x5c31de4bcc2af3c6, 0xb04bb030fe208d1f, 0xb78d7009c14fb466, 0x079bfa9b08792413}}}, +{{{0xe3903a51da300df4, 0x843964233da95ab0, 0xed3cf12d0b356480, 0x038c77f684817194}}, + {{0xf3c9ed80a2d54245, 0x0aa08b7877f63952, 0xd76dac63d1085475, 0x1ef4fb159470636b}}, + {{0x854e5ee65b167bec, 0x59590a4296d0cdc2, 0x72b2df3498102199, 0x575ee92a4a0bff56}}}, +{{{0xd4c080908a182fcf, 0x30e170c299489dbd, 0x05babd5752f733de, 0x43d4e7112cd3fd00}}, + {{0x5d46bc450aa4d801, 0xc3af1227a533b9d8, 0x389e3b262b8906c2, 0x200a1e7e382f581b}}, + {{0x518db967eaf93ac5, 0x71bc989b056652c0, 0xfe2b85d9567197f5, 0x050eca52651e4e38}}}, +{{{0xc3431ade453f0c9c, 0xe9f5045eff703b9b, 0xfcd97ac9ed847b3d, 0x4b0ee6c21c58f4c6}}, + {{0x97ac397660e668ea, 0x9b19bbfe153ab497, 0x4cb179b534eca79f, 0x6151c09fa131ae57}}, + {{0x3af55c0dfdf05d96, 0xdd262ee02ab4ee7a, 0x11b2bb8712171709, 0x1fef24fa800f030b}}}, +{{{0xb496123a6b6c6609, 0xa750fe8580ab5938, 0xf471bf39b7c27a5f, 0x507903ce77ac193c}}, + {{0xff91a66a90166220, 0xf22552ae5bf1e009, 0x7dff85d87f90df7c, 0x4f620ffe0c736fb9}}, + {{0x62f90d65dfde3e34, 0xcf28c592b9fa5fad, 0x99c86ef9c6164510, 0x25d448044a256c84}}}, +{{{0xbd68230ec7e9b16f, 0x0eb1b9c1c1c5795d, 0x7943c8c495b6b1ff, 0x2f9faf620bbacf5e}}, + {{0x2c7c4415c9022b55, 0x56a0d241812eb1fe, 0xf02ea1c9d7b65e0d, 0x4180512fd5323b26}}, + {{0xa4ff3e698a48a5db, 0xba6a3806bd95403b, 0x9f7ce1af47d5b65d, 0x15e087e55939d2fb}}}, +{{{0x12207543745c1496, 0xdaff3cfdda38610c, 0xe4e797272c71c34f, 0x39c07b1934bdede9}}, + {{0x8894186efb963f38, 0x48a00e80dc639bd5, 0xa4e8092be96c1c99, 0x5a097d54ca573661}}, + {{0x2d45892b17c9e755, 0xd033fd7289308df8, 0x6c2fe9d9525b8bd9, 0x2edbecf1c11cc079}}}, +{{{0x1616a4e3c715a0d2, 0x53623cb0f8341d4d, 0x96ef5329c7e899cb, 0x3d4e8dbba668baa6}}, + {{0xee0f0fddd087a25f, 0x9c7531555c3e34ee, 0x660c572e8fab3ab5, 0x0854fc44544cd3b2}}, + {{0x61eba0c555edad19, 0x24b533fef0a83de6, 0x3b77042883baa5f8, 0x678f82b898a47e8d}}}, +{{{0xb1491d0bd6900c54, 0x3539722c9d132636, 0x4db928920b362bc9, 0x4d7cd1fea68b69df}}, + {{0x1e09d94057775696, 0xeed1265c3cd951db, 0xfa9dac2b20bce16f, 0x0f7f76e0e8d089f4}}, + {{0x36d9ebc5d485b00c, 0xa2596492e4adb365, 0xc1659480c2119ccd, 0x45306349186e0d5f}}}, +{{{0x94ddd0c1a6cdff1d, 0x55f6f115e84213ae, 0x6c935f85992fcf6a, 0x067ee0f54a37f16f}}, + {{0x96a414ec2b072491, 0x1bb2218127a7b65b, 0x6d2849596e8a4af0, 0x65f3b08ccd27765f}}, + {{0xecb29fff199801f7, 0x9d361d1fa2a0f72f, 0x25f11d2375fd2f49, 0x124cefe80fe10fe2}}}, +{{{0x4c126cf9d18df255, 0xc1d471e9147a63b6, 0x2c6d3c73f3c93b5f, 0x6be3a6a2e3ff86a2}}, + {{0x1518e85b31b16489, 0x8faadcb7db710bfb, 0x39b0bdf4a14ae239, 0x05f4cbea503d20c1}}, + {{0xce040e9ec04145bc, 0xc71ff4e208f6834c, 0xbd546e8dab8847a3, 0x64666aa0a4d2aba5}}}, +{{{0x6841435a7c06d912, 0xca123c21bb3f830b, 0xd4b37b27b1cbe278, 0x1d753b84c76f5046}}, + {{0xb0c53bf73337e94c, 0x7cb5697e11e14f15, 0x4b84abac1930c750, 0x28dd4abfe0640468}}, + {{0x7dc0b64c44cb9f44, 0x18a3e1ace3925dbf, 0x7a3034862d0457c4, 0x4c498bf78a0c892e}}}, +{{{0x37d653fb1aa73196, 0x0f9495303fd76418, 0xad200b09fb3a17b2, 0x544d49292fc8613e}}, + {{0x22d2aff530976b86, 0x8d90b806c2d24604, 0xdca1896c4de5bae5, 0x28005fe6c8340c17}}, + {{0x6aefba9f34528688, 0x5c1bff9425107da1, 0xf75bbbcd66d94b36, 0x72e472930f316dfa}}}, +{{{0x2695208c9781084f, 0xb1502a0b23450ee1, 0xfd9daea603efde02, 0x5a9d2e8c2733a34c}}, + {{0x07f3f635d32a7627, 0x7aaa4d865f6566f0, 0x3c85e79728d04450, 0x1fee7f000fe06438}}, + {{0x765305da03dbf7e5, 0xa4daf2491434cdbd, 0x7b4ad5cdd24a88ec, 0x00f94051ee040543}}}, +{{{0x8d356b23c3d330b2, 0xf21c8b9bb0471b06, 0xb36c316c6e42b83c, 0x07d79c7e8beab10d}}, + {{0xd7ef93bb07af9753, 0x583ed0cf3db766a7, 0xce6998bf6e0b1ec5, 0x47b7ffd25dd40452}}, + {{0x87fbfb9cbc08dd12, 0x8a066b3ae1eec29b, 0x0d57242bdb1fc1bf, 0x1c3520a35ea64bb6}}}, +{{{0x80d253a6bccba34a, 0x3e61c3a13838219b, 0x90c3b6019882e396, 0x1c3d05775d0ee66f}}, + {{0xcda86f40216bc059, 0x1fbb231d12bcd87e, 0xb4956a9e17c70990, 0x38750c3b66d12e55}}, + {{0x692ef1409422e51a, 0xcbc0c73c2b5df671, 0x21014fe7744ce029, 0x0621e2c7d330487c}}}, +{{{0xaf9860cc8259838d, 0x90ea48c1c69f9adc, 0x6526483765581e30, 0x0007d6097bd3a5bc}}, + {{0xb7ae1796b0dbf0f3, 0x54dfafb9e17ce196, 0x25923071e9aaa3b4, 0x5d8e589ca1002e9d}}, + {{0xc0bf1d950842a94b, 0xb2d3c363588f2e3e, 0x0a961438bb51e2ef, 0x1583d7783c1cbf86}}}, +{{{0xeceea2ef5da27ae1, 0x597c3a1455670174, 0xc9a62a126609167a, 0x252a5f2e81ed8f70}}, + {{0x90034704cc9d28c7, 0x1d1b679ef72cc58f, 0x16e12b5fbe5b8726, 0x4958064e83c5580a}}, + {{0x0d2894265066e80d, 0xfcc3f785307c8c6b, 0x1b53da780c1112fd, 0x079c170bd843b388}}}, +{{{0x0506ece464fa6fff, 0xbee3431e6205e523, 0x3579422451b8ea42, 0x6dec05e34ac9fb00}}, + {{0xcdd6cd50c0d5d056, 0x9af7686dbb03573b, 0x3ca6723ff3c3ef48, 0x6768c0d7317b8acc}}, + {{0x94b625e5f155c1b3, 0x417bf3a7997b7b91, 0xc22cbddc6d6b2600, 0x51445e14ddcd52f4}}}, +{{{0x57502b4b3b144951, 0x8e67ff6b444bbcb3, 0xb8bd6927166385db, 0x13186f31e39295c8}}, + {{0x893147ab2bbea455, 0x8c53a24f92079129, 0x4b49f948be30f7a7, 0x12e990086e4fd43d}}, + {{0xf10c96b37fdfbb2e, 0x9f9a935e121ceaf9, 0xdf1136c43a5b983f, 0x77b2e3f05d3e99af}}}, +{{{0xfd0d75879cf12657, 0xe82fef94e53a0e29, 0xcc34a7f05bbb4be7, 0x0b251172a50c38a2}}, + {{0x9532f48fcc5cd29b, 0x2ba851bea3ce3671, 0x32dacaa051122941, 0x478d99d9350004f2}}, + {{0x1d5ad94890bb02c0, 0x50e208b10ec25115, 0xa26a22894ef21702, 0x4dc923343b524805}}}, +{{{0xe3828c400f8086b6, 0x3f77e6f7979f0dc8, 0x7ef6de304df42cb4, 0x5265797cb6abd784}}, + {{0x3ad3e3ebf36c4975, 0xd75d25a537862125, 0xe873943da025a516, 0x6bbc7cb4c411c847}}, + {{0x3c6f9cd1d4a50d56, 0xb6244077c6feab7e, 0x6ff9bf483580972e, 0x00375883b332acfb}}}, +{{{0x0001b2cd28cb0940, 0x63fb51a06f1c24c9, 0xb5ad8691dcd5ca31, 0x67238dbd8c450660}}, + {{0xc98bec856c75c99c, 0xe44184c000e33cf4, 0x0a676b9bba907634, 0x669e2cb571f379d7}}, + {{0xcb116b73a49bd308, 0x025aad6b2392729e, 0xb4793efa3f55d9b1, 0x72a1056140678bb9}}}, +{{{0xa2b6812b1cc9249d, 0x62866eee21211f58, 0x2cb5c5b85df10ece, 0x03a6b259e263ae00}}, + {{0x0d8d2909e2e505b6, 0x98ca78abc0291230, 0x77ef5569a9b12327, 0x7c77897b81439b47}}, + {{0xf1c1b5e2de331cb5, 0x5a9f5d8e15fca420, 0x9fa438f17bd932b1, 0x2a381bf01c6146e7}}}, +{{{0xac9b9879cfc811c1, 0x8b7d29813756e567, 0x50da4e607c70edfc, 0x5dbca62f884400b6}}, + {{0xf7c0be32b534166f, 0x27e6ca6419cf70d4, 0x934df7d7a957a759, 0x5701461dabdec2aa}}, + {{0x2c6747402c915c25, 0x1bdcd1a80b0d340a, 0x5e5601bd07b43f5f, 0x2555b4e05539a242}}}, +{{{0x6fc09f5266ddd216, 0xdce560a7c8e37048, 0xec65939da2df62fd, 0x7a869ae7e52ed192}}, + {{0x78409b1d87e463d4, 0xad4da95acdfb639d, 0xec28773755259b9c, 0x69c806e9c31230ab}}, + {{0x7b48f57414bb3f22, 0x68c7cee4aedccc88, 0xed2f936179ed80be, 0x25d70b885f77bc4b}}}, +{{{0x4151c3d9762bf4de, 0x083f435f2745d82b, 0x29775a2e0d23ddd5, 0x138e3a6269a5db24}}, + {{0x98459d29bb1ae4d4, 0x56b9c4c739f954ec, 0x832743f6c29b4b3e, 0x21ea8e2798b6878a}}, + {{0x87bef4b46a5a7b9c, 0xd2299d1b5fc1d062, 0x82409818dd321648, 0x5c5abeb1e5a2e03d}}}, +{{{0x14722af4b73c2ddb, 0xbc470c5f5a05060d, 0x00943eac2581b02e, 0x0e434b3b1f499c8f}}, + {{0x02cde6de1306a233, 0x7b5a52a2116f8ec7, 0xe1c681f4c1163b5b, 0x241d350660d32643}}, + {{0x6be4404d0ebc52c7, 0xae46233bb1a791f5, 0x2aec170ed25db42b, 0x1d8dfd966645d694}}}, +{{{0x296fa9c59c2ec4de, 0xbc8b61bf4f84f3cb, 0x1c7706d917a8f908, 0x63b795fc7ad3255d}}, + {{0xd598639c12ddb0a4, 0xa5d19f30c024866b, 0xd17c2f0358fce460, 0x07a195152e095e8a}}, + {{0xa8368f02389e5fc8, 0x90433b02cf8de43b, 0xafa1fd5dc5412643, 0x3e8fe83d032f0137}}}, +{{{0x2f8b15b90570a294, 0x94f2427067084549, 0xde1c5ae161bbfd84, 0x75ba3b797fac4007}}, + {{0x08704c8de8efd13c, 0xdfc51a8e33e03731, 0xa59d5da51260cde3, 0x22d60899a6258c86}}, + {{0x6239dbc070cdd196, 0x60fe8a8b6c7d8a9a, 0xb38847bceb401260, 0x0904d07b87779e5e}}}, +{{{0xb4ce1fd4ddba919c, 0xcf31db3ec74c8daa, 0x2c63cc63ad86cc51, 0x43e2143fbc1dde07}}, + {{0xf4322d6648f940b9, 0x06952f0cbd2d0c39, 0x167697ada081f931, 0x6240aacebaf72a6c}}, + {{0xf834749c5ba295a0, 0xd6947c5bca37d25a, 0x66f13ba7e7c9316a, 0x56bdaf238db40cac}}}, +{{{0x362ab9e3f53533eb, 0x338568d56eb93d40, 0x9e0e14521d5a5572, 0x1d24a86d83741318}}, + {{0x1310d36cc19d3bb2, 0x062a6bb7622386b9, 0x7c9b8591d7a14f5c, 0x03aa31507e1e5754}}, + {{0xf4ec7648ffd4ce1f, 0xe045eaf054ac8c1c, 0x88d225821d09357c, 0x43b261dc9aeb4859}}}, +{{{0xe55b1e1988bb79bb, 0xa09ed07dc17a359d, 0xb02c2ee2603dea33, 0x326055cf5b276bc2}}, + {{0x19513d8b6c951364, 0x94fe7126000bf47b, 0x028d10ddd54f9567, 0x02b4d5e242940964}}, + {{0xb4a155cb28d18df2, 0xeacc4646186ce508, 0xc49cf4936c824389, 0x27a6c809ae5d3410}}}, +{{{0x8ba6ebcd1f0db188, 0x37d3d73a675a5be8, 0xf22edfa315f5585a, 0x2cb67174ff60a17e}}, + {{0xcd2c270ac43d6954, 0xdd4a3e576a66cab2, 0x79fa592469d7036c, 0x221503603d8c2599}}, + {{0x59eecdf9390be1d0, 0xa9422044728ce3f1, 0x82891c667a94f0f4, 0x7b1df4b73890f436}}}, +{{{0xe492f2e0b3b2a224, 0x7c6c9e062b551160, 0x15eb8fe20d7f7b0e, 0x61fcef2658fc5992}}, + {{0x5f2e221807f8f58c, 0xe3555c9fd49409d4, 0xb2aaa88d1fb6a630, 0x68698245d352e03d}}, + {{0xdbb15d852a18187a, 0xf3e4aad386ddacd7, 0x44bae2810ff6c482, 0x46cf4c473daf01cf}}}, +{{{0x426525ed9ec4e5f9, 0x0e5eda0116903303, 0x72b1a7f2cbe5cadc, 0x29387bcd14eb5f40}}, + {{0x213c6ea7f1498140, 0x7c1e7ef8392b4854, 0x2488c38c5629ceba, 0x1065aae50d8cc5bb}}, + {{0x1c2c4525df200d57, 0x5c3b2dd6bfca674a, 0x0a07e7b1e1834030, 0x69a198e64f1ce716}}}, +{{{0x7afcd613efa9d697, 0x0cc45aa41c067959, 0xa56fe104c1fada96, 0x3a73b70472e40365}}, + {{0x7b26e56b9e2d4734, 0xc4c7132b81c61675, 0xef5c9525ec9cde7f, 0x39c80b16e71743ad}}, + {{0x0f196e0d1b826c68, 0xf71ff0e24960e3db, 0x6113167023b7436c, 0x0cf0ea5877da7282}}}, +{{{0x196c80a4ddd4ccbd, 0x22e6f55d95f2dd9d, 0xc75e33c740d6c71b, 0x7bb51279cb3c042f}}, + {{0xe332ced43ba6945a, 0xde0b1361e881c05d, 0x1ad40f095e67ed3b, 0x5da8acdab8c63d5d}}, + {{0xc4b6664a3a70159f, 0x76194f0f0a904e14, 0xa5614c39a4096c13, 0x6cd0ff50979feced}}}, +{{{0xc0e067e78f4428ac, 0x14835ab0a61135e3, 0xf21d14f338062935, 0x6390a4c8df04849c}}, + {{0x7fecfabdb04ba18e, 0xd0fc7bfc3bddbcf7, 0xa41d486e057a131c, 0x641a4391f2223a61}}, + {{0xc5c6b95aa606a8db, 0x914b7f9eb06825f1, 0x2a731f6b44fc9eff, 0x30ddf38562705cfc}}}, +{{{0x4e3dcbdad1bff7f9, 0xc9118e8220645717, 0xbacccebc0f189d56, 0x1b4822e9d4467668}}, + {{0x33bef2bd68bcd52c, 0xc649dbb069482ef2, 0xb5b6ee0c41cb1aee, 0x5c294d270212a7e5}}, + {{0xab360a7f25563781, 0x2512228a480f7958, 0xc75d05276114b4e3, 0x222d9625d976fe2a}}}, +{{{0x1c717f85b372ace1, 0x81930e694638bf18, 0x239cad056bc08b58, 0x0b34271c87f8fff4}}, + {{0x0f94be7e0a344f85, 0xeb2faa8c87f22c38, 0x9ce1e75e4ee16f0f, 0x43e64e5418a08dea}}, + {{0x8155e2521a35ce63, 0xbe100d4df912028e, 0xbff80bf8a57ddcec, 0x57342dc96d6bc6e4}}}, +{{{0xefeef065c8ce5998, 0xbf029510b5cbeaa2, 0x8c64a10620b7c458, 0x35134fb231c24855}}, + {{0xf3c3bcb71e707bf6, 0x351d9b8c7291a762, 0x00502e6edad69a33, 0x522f521f1ec8807f}}, + {{0x272c1f46f9a3902b, 0xc91ba3b799657bcc, 0xae614b304f8a1c0e, 0x7afcaad70b99017b}}}, +{{{0xc25ded54a4b8be41, 0x902d13e11bb0e2dd, 0x41f43233cde82ab2, 0x1085faa5c3aae7cb}}, + {{0xa88141ecef842b6b, 0x55e7b14797abe6c5, 0x8c748f9703784ffe, 0x5b50a1f7afcd00b7}}, + {{0x9b840f66f1361315, 0x18462242701003e9, 0x65ed45fae4a25080, 0x0a2862393fda7320}}}, +{{{0x46ab13c8347cbc9d, 0x3849e8d499c12383, 0x4cea314087d64ac9, 0x1f354134b1a29ee7}}, + {{0x960e737b6ecb9d17, 0xfaf24948d67ceae1, 0x37e7a9b4d55e1b89, 0x5cb7173cb46c59eb}}, + {{0x4a89e68b82b7abf0, 0xf41cd9279ba6b7b9, 0x16e6c210e18d876f, 0x7cacdb0f7f1b09c6}}}, +{{{0x9062b2e0d91a78bc, 0x47c9889cc8509667, 0x9df54a66405070b8, 0x7369e6a92493a1bf}}, + {{0xe1014434dcc5caed, 0x47ed5d963c84fb33, 0x70019576ed86a0e7, 0x25b2697bd267f9e4}}, + {{0x9d673ffb13986864, 0x3ca5fbd9415dc7b8, 0xe04ecc3bdf273b5e, 0x1420683db54e4cd2}}}, +{{{0xb478bd1e249dd197, 0x620c35005e58c102, 0xfb02d32fccbaac5c, 0x60b63bebf508a72d}}, + {{0x34eebb6fc1cc5ad0, 0x6a1b0ce99646ac8b, 0xd3b0da49a66bde53, 0x31e83b4161d081c1}}, + {{0x97e8c7129e062b4f, 0x49e48f4f29320ad8, 0x5bece14b6f18683f, 0x55cf1eb62d550317}}}, +{{{0x5879101065c23d58, 0x8b9d086d5094819c, 0xe2402fa912c55fa7, 0x669a6564570891d4}}, + {{0x3076b5e37df58c52, 0xd73ab9dde799cc36, 0xbd831ce34913ee20, 0x1a56fbaa62ba0133}}, + {{0x943e6b505c9dc9ec, 0x302557bba77c371a, 0x9873ae5641347651, 0x13c4836799c58a5c}}}, +{{{0x423a5d465ab3e1b9, 0xfc13c187c7f13f61, 0x19f83664ecb5b9b6, 0x66f80c93a637b607}}, + {{0xc4dcfb6a5d8bd080, 0xdeebc4ec571a4842, 0xd4b2e883b8e55365, 0x50bdc87dc8e5b827}}, + {{0x606d37836edfe111, 0x32353e15f011abd9, 0x64b03ac325b73b96, 0x1dd56444725fd5ae}}}, +{{{0x8fa47ff83362127d, 0xbc9f6ac471cd7c15, 0x6e71454349220c8b, 0x0e645912219f732e}}, + {{0xc297e60008bac89a, 0x7d4cea11eae1c3e0, 0xf3e38be19fe7977c, 0x3a3a450f63a305cd}}, + {{0x078f2f31d8394627, 0x389d3183de94a510, 0xd1e36c6d17996f80, 0x318c8d9393a9a87b}}}, +{{{0xf2745d032afffe19, 0x0c9f3c497f24db66, 0xbc98d3e3ba8598ef, 0x224c7c679a1d5314}}, + {{0x5d669e29ab1dd398, 0xfc921658342d9e3b, 0x55851dfdf35973cd, 0x509a41c325950af6}}, + {{0xbdc06edca6f925e9, 0x793ef3f4641b1f33, 0x82ec12809d833e89, 0x05bff02328a11389}}}, +{{{0x3632137023cae00b, 0x544acf0ad1accf59, 0x96741049d21a1c88, 0x780b8cc3fa2a44a7}}, + {{0x6881a0dd0dc512e4, 0x4fe70dc844a5fafe, 0x1f748e6b8f4a5240, 0x576277cdee01a3ea}}, + {{0x1ef38abc234f305f, 0x9a577fbd1405de08, 0x5e82a51434e62a0d, 0x5ff418726271b7a1}}}, +{{{0x398e080c1789db9d, 0xa7602025f3e778f5, 0xfa98894c06bd035d, 0x106a03dc25a966be}}, + {{0xe5db47e813b69540, 0xf35d2a3b432610e1, 0xac1f26e938781276, 0x29d4db8ca0a0cb69}}, + {{0xd9ad0aaf333353d0, 0x38669da5acd309e5, 0x3c57658ac888f7f0, 0x4ab38a51052cbefa}}}, +{{{0xdfdacbee4324c0e9, 0x054442883f955bb7, 0xdef7aaa8ea31609f, 0x68aee70642287cff}}, + {{0xf68fe2e8809de054, 0xe3bc096a9c82bad1, 0x076353d40aadbf45, 0x7b9b1fb5dea1959e}}, + {{0xf01cc8f17471cc0c, 0x95242e37579082bb, 0x27776093d3e46b5f, 0x2d13d55a28bd85fb}}}, +{{{0xfac5d2065b35b8da, 0xa8da8a9a85624bb7, 0xccd2ca913d21cd0f, 0x6b8341ee8bf90d58}}, + {{0xbf019cce7aee7a52, 0xa8ded2b6e454ead3, 0x3c619f0b87a8bb19, 0x3619b5d7560916d8}}, + {{0x3579f26b0282c4b2, 0x64d592f24fafefae, 0xb7cded7b28c8c7c0, 0x6a927b6b7173a8d7}}}, +{{{0x1f6db24f986e4656, 0x1021c02ed1e9105b, 0xf8ff3fff2cc0a375, 0x1d2a6bf8c6c82592}}, + {{0x8d7040863ece88eb, 0xf0e307a980eec08c, 0xac2250610d788fda, 0x056d92a43a0d478d}}, + {{0x1b05a196fc3da5a1, 0x77d7a8c243b59ed0, 0x06da3d6297d17918, 0x66fbb494f12353f7}}}, +{{{0x751a50b9d85c0fb8, 0xd1afdc258bcf097b, 0x2f16a6a38309a969, 0x14ddff9ee5b00659}}, + {{0xd6d70996f12309d6, 0xdbfb2385e9c3d539, 0x46d602b0f7552411, 0x270a0b0557843e0c}}, + {{0x61ff0640a7862bcc, 0x81cac09a5f11abfe, 0x9047830455d12abb, 0x19a4bde1945ae873}}}, +{{{0x9b9f26f520a6200a, 0x64804443cf13eaf8, 0x8a63673f8631edd3, 0x72bbbce11ed39dc1}}, + {{0x40c709dec076c49f, 0x657bfaf27f3e53f6, 0x40662331eca042c4, 0x14b375487eb4df04}}, + {{0xae853c94ab66dc47, 0xeb62343edf762d6e, 0xf08e0e186fb2f7d1, 0x4f0b1c02700ab37a}}}, +{{{0xe1706787d81951fa, 0xa10a2c8eb290c77b, 0xe7382fa03ed66773, 0x0a4d84710bcc4b54}}, + {{0x79fd21ccc1b2e23f, 0x4ae7c281453df52a, 0xc8172ec9d151486b, 0x68abe9443e0a7534}}, + {{0xda12c6c407831dcb, 0x0da230d74d5c510d, 0x4ab1531e6bd404e1, 0x4106b166bcf440ef}}}, +{{{0x02e57a421cd23668, 0x4ad9fb5d0eaef6fd, 0x954e6727b1244480, 0x7f792f9d2699f331}}, + {{0xa485ccd539e4ecf2, 0x5aa3f3ad0555bab5, 0x145e3439937df82d, 0x1238b51e1214283f}}, + {{0x0b886b925fd4d924, 0x60906f7a3626a80d, 0xecd367b4b98abd12, 0x2876beb1def344cf}}}, +{{{0xdc84e93563144691, 0x632fe8a0d61f23f4, 0x4caa800612a9a8d5, 0x48f9dbfa0e9918d3}}, + {{0xd594b3333a8a85f8, 0x4ea37689e78d7d58, 0x73bf9f455e8e351f, 0x5507d7d2bc41ebb4}}, + {{0x1ceb2903299572fc, 0x7c8ccaa29502d0ee, 0x91bfa43411cce67b, 0x5784481964a831e7}}}, +{{{0xda7c2b256768d593, 0x98c1c0574422ca13, 0xf1a80bd5ca0ace1d, 0x29cdd1adc088a690}}, + {{0xd6cfd1ef5fddc09c, 0xe82b3efdf7575dce, 0x25d56b5d201634c2, 0x3041c6bb04ed2b9b}}, + {{0x0ff2f2f9d956e148, 0xade797759f356b2e, 0x1a4698bb5f6c025c, 0x104bbd6814049a7b}}}, +{{{0x51f0fd3168f1ed67, 0x2c811dcdd86f3bc2, 0x44dc5c4304d2f2de, 0x5be8cc57092a7149}}, + {{0xa95d9a5fd67ff163, 0xe92be69d4cc75681, 0xb7f8024cde20f257, 0x204f2a20fb072df5}}, + {{0xc8143b3d30ebb079, 0x7589155abd652e30, 0x653c3c318f6d5c31, 0x2570fb17c279161f}}}, +{{{0x3efa367f2cb61575, 0xf5f96f761cd6026c, 0xe8c7142a65b52562, 0x3dcb65ea53030acd}}, + {{0x192ea9550bb8245a, 0xc8e6fba88f9050d1, 0x7986ea2d88a4c935, 0x241c5f91de018668}}, + {{0x28d8172940de6caa, 0x8fbf2cf022d9733a, 0x16d7fcdd235b01d1, 0x08420edd5fcdf0e5}}}, +{{{0xcdff20ab8362fa4a, 0x57e118d4e21a3e6e, 0xe3179617fc39e62b, 0x0d9a53efbc1769fd}}, + {{0x0358c34e04f410ce, 0xb6135b5a276e0685, 0x5d9670c7ebb91521, 0x04d654f321db889c}}, + {{0x5e7dc116ddbdb5d5, 0x2954deb68da5dd2d, 0x1cb608173334a292, 0x4a7a4f2618991ad7}}}, +{{{0xf4a718025fb15f95, 0x3df65f346b5c1b8f, 0xcdfcf08500e01112, 0x11b50c4cddd31848}}, + {{0x24c3b291af372a4b, 0x93da8270718147f2, 0xdd84856486899ef2, 0x4a96314223e0ee33}}, + {{0xa6e8274408a4ffd6, 0x738e177e9c1576d9, 0x773348b63d02b3f2, 0x4f4bce4dce6bcc51}}}, +{{{0xa71fce5ae2242584, 0x26ea725692f58a9e, 0xd21a09d71cea3cf4, 0x73fcdd14b71c01e6}}, + {{0x30e2616ec49d0b6f, 0xe456718fcaec2317, 0x48eb409bf26b4fa6, 0x3042cee561595f37}}, + {{0x427e7079449bac41, 0x855ae36dbce2310a, 0x4cae76215f841a7c, 0x389e740c9a9ce1d6}}}, +{{{0x64fcb3ae34dcb9ce, 0x97500323e348d0ad, 0x45b3f07d62c6381b, 0x61545379465a6788}}, + {{0xc9bd78f6570eac28, 0xe55b0b3227919ce1, 0x65fc3eaba19b91ed, 0x25c425e5d6263690}}, + {{0x3f3e06a6f1d7de6e, 0x3ef976278e062308, 0x8c14f6264e8a6c77, 0x6539a08915484759}}}, +{{{0xe9d21f74c3d2f773, 0xc150544125c46845, 0x624e5ce8f9b99e33, 0x11c5e4aac5cd186c}}, + {{0xddc4dbd414bb4a19, 0x19b2bc3c98424f8e, 0x48a89fd736ca7169, 0x0f65320ef019bd90}}, + {{0xd486d1b1cafde0c6, 0x4f3fe6e3163b5181, 0x59a8af0dfaf2939a, 0x4cabc7bdec33072a}}}, +{{{0x16faa8fb532f7428, 0xdbd42ea046a4e272, 0x5337653b8b9ea480, 0x4065947223973f03}}, + {{0xf7c0a19c1a54a044, 0x4a1c5e2477bd9fbb, 0xa6e3ca115af22972, 0x1819bb953f2e9e0d}}, + {{0x498fbb795e042e84, 0x7d0dd89a7698b714, 0x8bfb0ba427fe6295, 0x36ba82e721200524}}}, +{{{0xd60ecbb74245ec41, 0xfd9be89e34348716, 0xc9240afee42284de, 0x4472f648d0531db4}}, + {{0xc8d69d0a57274ed5, 0x45ba803260804b17, 0xdf3cda102255dfac, 0x77d221232709b339}}, + {{0x498a6d7064ad94d8, 0xa5b5c8fd9af62263, 0x8ca8ed0545c141f4, 0x2c63bec3662d358c}}}, +{{{0x7fe60d8bea787955, 0xb9dc117eb5f401b7, 0x91c7c09a19355cce, 0x22692ef59442bedf}}, + {{0x9a518b3a8586f8bf, 0x9ee71af6cbb196f0, 0xaa0625e6a2385cf2, 0x1deb2176ddd7c8d1}}, + {{0x8563d19a2066cf6c, 0x401bfd8c4dcc7cd7, 0xd976a6becd0d8f62, 0x67cfd773a278b05e}}}, +{{{0x8dec31faef3ee475, 0x99dbff8a9e22fd92, 0x512d11594e26cab1, 0x0cde561eec4310b9}}, + {{0x2d5fa9855a4e586a, 0x65f8f7a449beab7e, 0xaa074dddf21d33d3, 0x185cba721bcb9dee}}, + {{0x93869da3f4e3cb41, 0xbf0392f540f7977e, 0x026204fcd0463b83, 0x3ec91a769eec6eed}}}, +{{{0x1e9df75bf78166ad, 0x4dfda838eb0cd7af, 0xba002ed8c1eaf988, 0x13fedb3e11f33cfc}}, + {{0x0fad2fb7b0a3402f, 0x46615ecbfb69f4a8, 0xf745bcc8c5f8eaa6, 0x7a5fa8794a94e896}}, + {{0x52958faa13cd67a1, 0x965ee0818bdbb517, 0x16e58daa2e8845b3, 0x357d397d5499da8f}}}, +{{{0x1ebfa05fb0bace6c, 0xc934620c1caf9a1e, 0xcc771cc41d82b61a, 0x2d94a16aa5f74fec}}, + {{0x481dacb4194bfbf8, 0x4d77e3f1bae58299, 0x1ef4612e7d1372a0, 0x3a8d867e70ff69e1}}, + {{0x6f58cd5d55aff958, 0xba3eaa5c75567721, 0x75c123999165227d, 0x69be1343c2f2b35e}}}, +{{{0x0e091d5ee197c92a, 0x4f51019f2945119f, 0x143679b9f034e99c, 0x7d88112e4d24c696}}, + {{0x82bbbdac684b8de3, 0xa2f4c7d03fca0718, 0x337f92fbe096aaa8, 0x200d4d8c63587376}}, + {{0x208aed4b4893b32b, 0x3efbf23ebe59b964, 0xd762deb0dba5e507, 0x69607bd681bd9d94}}}, +{{{0xf6be021068de1ce1, 0xe8d518e70edcbc1f, 0xe3effdd01b5505a5, 0x35f63353d3ec3fd0}}, + {{0x3b7f3bd49323a902, 0x7c21b5566b2c6e53, 0xe5ba8ff53a7852a7, 0x28bc77a5838ece00}}, + {{0x63ba78a8e25d8036, 0x63651e0094333490, 0x48d82f20288ce532, 0x3a31abfa36b57524}}}, +{{{0x239e9624089c0a2e, 0xc748c4c03afe4738, 0x17dbed2a764fa12a, 0x639b93f0321c8582}}, + {{0xc08f788f3f78d289, 0xfe30a72ca1404d9f, 0xf2778bfccf65cc9d, 0x7ee498165acb2021}}, + {{0x7bd508e39111a1c3, 0x2b2b90d480907489, 0xe7d2aec2ae72fd19, 0x0edf493c85b602a6}}}, +{{{0xaecc8158599b5a68, 0xea574f0febade20e, 0x4fe41d7422b67f07, 0x403b92e3019d4fb4}}, + {{0x6767c4d284764113, 0xa090403ff7f5f835, 0x1c8fcffacae6bede, 0x04c00c54d1dfa369}}, + {{0x4dc22f818b465cf8, 0x71a0f35a1480eff8, 0xaee8bfad04c7d657, 0x355bb12ab26176f4}}}, +{{{0xa71e64cc7493bbf4, 0xe5bd84d9eca3b0c3, 0x0a6bc50cfa05e785, 0x0f9b8132182ec312}}, + {{0xa301dac75a8c7318, 0xed90039db3ceaa11, 0x6f077cbf3bae3f2d, 0x7518eaf8e052ad8e}}, + {{0xa48859c41b7f6c32, 0x0f2d60bcf4383298, 0x1815a929c9b1d1d9, 0x47c3871bbb1755c4}}}, +{{{0x5144539771ec4f48, 0xf805b17dc98c5d6e, 0xf762c11a47c3c66b, 0x00b89b85764699dc}}, + {{0xfbe65d50c85066b0, 0x62ecc4b0b3a299b0, 0xe53754ea441ae8e0, 0x08fea02ce8d48d5f}}, + {{0x824ddd7668deead0, 0xc86445204b685d23, 0xb514cfcd5d89d665, 0x473829a74f75d537}}}, +{{{0x82d2da754679c418, 0xe63bd7d8b2618df0, 0x355eef24ac47eb0a, 0x2078684c4833c6b4}}, + {{0x23d9533aad3902c9, 0x64c2ddceef03588f, 0x15257390cfe12fb4, 0x6c668b4d44e4d390}}, + {{0x3b48cf217a78820c, 0xf76a0ab281273e97, 0xa96c65a78c8eed7b, 0x7411a6054f8a433f}}}, +{{{0x4d659d32b99dc86d, 0x044cdc75603af115, 0xb34c712cdcc2e488, 0x7c136574fb8134ff}}, + {{0x579ae53d18b175b4, 0x68713159f392a102, 0x8455ecba1eef35f5, 0x1ec9a872458c398f}}, + {{0xb8e6a4d400a2509b, 0x9b81d7020bc882b4, 0x57e7cc9bf1957561, 0x3add88a5c7cd6460}}}, +{{{0xab895770b635dcf2, 0x02dfef6cf66c1fbc, 0x85530268beb6d187, 0x249929fccc879e74}}, + {{0x85c298d459393046, 0x8f7e35985ff659ec, 0x1d2ca22af2f66e3a, 0x61ba1131a406a720}}, + {{0xa3d0a0f116959029, 0x023b6b6cba7ebd89, 0x7bf15a3e26783307, 0x5620310cbbd8ece7}}}, +{{{0x528993434934d643, 0xb9dbf806a51222f5, 0x8f6d878fc3f41c22, 0x37676a2a4d9d9730}}, + {{0x6646b5f477e285d6, 0x40e8ff676c8f6193, 0xa6ec7311abb594dd, 0x7ec846f3658cec4d}}, + {{0x9b5e8f3f1da22ec7, 0x130f1d776c01cd13, 0x214c8fcfa2989fb8, 0x6daaf723399b9dd5}}}, +{{{0x591e4a5610628564, 0x2a4bb87ca8b4df34, 0xde2a2572e7a38e43, 0x3cbdabd9fee5046e}}, + {{0x81aebbdd2cd13070, 0x962e4325f85a0e9e, 0xde9391aacadffecb, 0x53177fda52c230e6}}, + {{0xa7bc970650b9de79, 0x3d12a7fbc301b59b, 0x02652e68d36ae38c, 0x79d739835a6199dc}}}, +{{{0xd9354df64131c1bd, 0x758094a186ec5822, 0x4464ee12e459f3c2, 0x6c11fce4cb133282}}, + {{0x21c9d9920d591737, 0x9bea41d2e9b46cd6, 0xe20e84200d89bfca, 0x79d99f946eae5ff8}}, + {{0xf17b483568673205, 0x387deae83caad96c, 0x61b471fd56ffe386, 0x31741195b745a599}}}, +{{{0xe8d10190b77a360b, 0x99b983209995e702, 0xbd4fdff8fa0247aa, 0x2772e344e0d36a87}}, + {{0x17f8ba683b02a047, 0x50212096feefb6c8, 0x70139be21556cbe2, 0x203e44a11d98915b}}, + {{0xd6863eba37b9e39f, 0x105bc169723b5a23, 0x104f6459a65c0762, 0x567951295b4d38d4}}}, +{{{0x535fd60613037524, 0xe210adf6b0fbc26a, 0xac8d0a9b23e990ae, 0x47204d08d72fdbf9}}, + {{0x07242eb30d4b497f, 0x1ef96306b9bccc87, 0x37950934d8116f45, 0x05468d6201405b04}}, + {{0x00f565a9f93267de, 0xcecfd78dc0d58e8a, 0xa215e2dcf318e28e, 0x4599ee919b633352}}}, +{{{0xd3c220ca70e0e76b, 0xb12bea58ea9f3094, 0x294ddec8c3271282, 0x0c3539e1a1d1d028}}, + {{0xac746d6b861ae579, 0x31ab0650f6aea9dc, 0x241d661140256d4c, 0x2f485e853d21a5de}}, + {{0x329744839c0833f3, 0x6fe6257fd2abc484, 0x5327d1814b358817, 0x65712585893fe9bc}}}, +{{{0x9c102fb732a61161, 0xe48e10dd34d520a8, 0x365c63546f9a9176, 0x32f6fe4c046f6006}}, + {{0x81c29f1bd708ee3f, 0xddcb5a05ae6407d0, 0x97aec1d7d2a3eba7, 0x1590521a91d50831}}, + {{0x40a3a11ec7910acc, 0x9013dff8f16d27ae, 0x1a9720d8abb195d4, 0x1bb9fe452ea98463}}}, +{{{0xe9d1d950b3d54f9e, 0x2d5f9cbee00d33c1, 0x51c2c656a04fc6ac, 0x65c091ee3c1cbcc9}}, + {{0xcf5e6c95cc36747c, 0x294201536b0bc30d, 0x453ac67cee797af0, 0x5eae6ab32a8bb3c9}}, + {{0x7083661114f118ea, 0x2b37b87b94349cad, 0x7273f51cb4e99f40, 0x78a2a95823d75698}}}, +{{{0xa2b072e95c8c2ace, 0x69cffc96651e9c4b, 0x44328ef842e7b42b, 0x5dd996c122aadeb3}}, + {{0xb4f23c425ef83207, 0xabf894d3c9a934b5, 0xd0708c1339fd87f7, 0x1876789117166130}}, + {{0x925b5ef0670c507c, 0x819bc842b93c33bf, 0x10792e9a70dd003f, 0x59ad4b7a6e28dc74}}}, +{{{0x5f3a7562eb3dbe47, 0xf7ea38548ebda0b8, 0x00c3e53145747299, 0x1304e9e71627d551}}, + {{0x583b04bfacad8ea2, 0x29b743e8148be884, 0x2b1e583b0810c5db, 0x2b5449e58eb3bbaa}}, + {{0x789814d26adc9cfe, 0x3c1bab3f8b48dd0b, 0xda0fe1fff979c60a, 0x4468de2d7c2dd693}}}, +{{{0x51bb355e9419469e, 0x33e6dc4c23ddc754, 0x93a5b6d6447f9962, 0x6cce7c6ffb44bd63}}, + {{0x4b9ad8c6f86307ce, 0x21113531435d0c28, 0xd4a866c5657a772c, 0x5da6427e63247352}}, + {{0x1a94c688deac22ca, 0xb9066ef7bbae1ff8, 0x88ad8c388d59580f, 0x58f29abfe79f2ca8}}}, +{{{0xe90ecfab8de73e68, 0x54036f9f377e76a5, 0xf0495b0bbe015982, 0x577629c4a7f41e36}}, + {{0x4b5a64bf710ecdf6, 0xb14ce538462c293c, 0x3643d056d50b3ab9, 0x6af93724185b4870}}, + {{0x3220024509c6a888, 0xd2e036134b558973, 0x83e236233c33289f, 0x701f25bb0caec18f}}}, +{{{0xc3a8b0f8e4616ced, 0xf700660e9e25a87d, 0x61e3061ff4bca59c, 0x2e0c92bfbdc40be9}}, + {{0x9d18f6d97cbec113, 0x844a06e674bfdbe4, 0x20f5b522ac4e60d6, 0x720a5bc050955e51}}, + {{0x0c3f09439b805a35, 0xe84e8b376242abfc, 0x691417f35c229346, 0x0e9b9cbb144ef0ec}}}, +{{{0xfbbad48ffb5720ad, 0xee81916bdbf90d0e, 0xd4813152635543bf, 0x221104eb3f337bd8}}, + {{0x8dee9bd55db1beee, 0xc9c3ab370a723fb9, 0x44a8f1bf1c68d791, 0x366d44191cfd3cde}}, + {{0x9e3c1743f2bc8c14, 0x2eda26fcb5856c3b, 0xccb82f0e68a7fb97, 0x4167a4e6bc593244}}}, +{{{0x643b9d2876f62700, 0x5d1d9d400e7668eb, 0x1b4b430321fc0684, 0x7938bb7e2255246a}}, + {{0xc2be2665f8ce8fee, 0xe967ff14e880d62c, 0xf12e6e7e2f364eee, 0x34b33370cb7ed2f6}}, + {{0xcdc591ee8681d6cc, 0xce02109ced85a753, 0xed7485c158808883, 0x1176fc6e2dfe65e4}}}, +{{{0xb4af6cd05b9c619b, 0x2ddfc9f4b2a58480, 0x3d4fa502ebe94dc4, 0x08fc3a4c677d5f34}}, + {{0xdb90e28949770eb8, 0x98fbcc2aacf440a3, 0x21354ffeded7879b, 0x1f6a3e54f26906b6}}, + {{0x60a4c199d30734ea, 0x40c085b631165cd6, 0xe2333e23f7598295, 0x4f2fad0116b900d1}}}, +{{{0x44beb24194ae4e54, 0x5f541c511857ef6c, 0xa61e6b2d368d0498, 0x445484a4972ef7ab}}, + {{0x962cd91db73bb638, 0xe60577aafc129c08, 0x6f619b39f3b61689, 0x3451995f2944ee81}}, + {{0x9152fcd09fea7d7c, 0x4a816c94b0935cf6, 0x258e9aaa47285c40, 0x10b89ca6042893b7}}}, +{{{0x9b2a426e3b646025, 0x32127190385ce4cf, 0xa25cffc2dd6dea45, 0x06409010bea8de75}}, + {{0xd67cded679d34aa0, 0xcc0b9ec0cc4db39f, 0xa535a456e35d190f, 0x2e05d9eaf61f6fef}}, + {{0xc447901ad61beb59, 0x661f19bce5dc880a, 0x24685482b7ca6827, 0x293c778cefe07f26}}}, +{{{0x86809e7007069096, 0xaad75b15e4e50189, 0x07f35715a21a0147, 0x0487f3f112815d5e}}, + {{0x16c795d6a11ff200, 0xcb70d0e2b15815c9, 0x89f293209b5395b5, 0x50b8c2d031e47b4f}}, + {{0x48350c08068a4962, 0x6ffdd05351092c9a, 0x17af4f4aaf6fc8dd, 0x4b0553b53cdba58b}}}, +{{{0x9c65fcbe1b32ff79, 0xeb75ea9f03b50f9b, 0xfced2a6c6c07e606, 0x35106cd551717908}}, + {{0xbf05211b27c152d4, 0x5ec26849bd1af639, 0x5e0b2caa8e6fab98, 0x054c8bdd50bd0840}}, + {{0x38a0b12f1dcf073d, 0x4b60a8a3b7f6a276, 0xfed5ac25d3404f9a, 0x72e82d5e5505c229}}}, +{{{0x6b0b697ff0d844c8, 0xbb12f85cd979cb49, 0xd2a541c6c1da0f1f, 0x7b7c242958ce7211}}, + {{0x00d9cdfd69771d02, 0x410276cd6cfbf17e, 0x4c45306c1cb12ec7, 0x2857bf1627500861}}, + {{0x9f21903f0101689e, 0xd779dfd3bf861005, 0xa122ee5f3deb0f1b, 0x510df84b485a00d4}}}, +{{{0xa54133bb9277a1fa, 0x74ec3b6263991237, 0x1a3c54dc35d2f15a, 0x2d347144e482ba3a}}, + {{0x24b3c887c70ac15e, 0xb0f3a557fb81b732, 0x9b2cde2fe578cc1b, 0x4cf7ed0703b54f8e}}, + {{0x6bd47c6598fbee0f, 0x9e4733e2ab55be2d, 0x1093f624127610c5, 0x4e05e26ad0a1eaa4}}}, +{{{0xda9b6b624b531f20, 0x429a760e77509abb, 0xdbe9f522e823cb80, 0x618f1856880c8f82}}, + {{0x1833c773e18fe6c0, 0xe3c4711ad3c87265, 0x3bfd3c4f0116b283, 0x1955875eb4cd4db8}}, + {{0x6da6de8f0e399799, 0x7ad61aa440fda178, 0xb32cd8105e3563dd, 0x15f6beae2ae340ae}}}, +{{{0x862bcb0c31ec3a62, 0x810e2b451138f3c2, 0x788ec4b839dac2a4, 0x28f76867ae2a9281}}, + {{0xba9a0f7b9245e215, 0xf368612dd98c0dbb, 0x2e84e4cbf220b020, 0x6ba92fe962d90eda}}, + {{0x3e4df9655884e2aa, 0xbd62fbdbdbd465a5, 0xd7596caa0de9e524, 0x6e8042ccb2b1b3d7}}}, +{{{0xf10d3c29ce28ca6e, 0xbad34540fcb6093d, 0xe7426ed7a2ea2d3f, 0x08af9d4e4ff298b9}}, + {{0x1530653616521f7e, 0x660d06b896203dba, 0x2d3989bc545f0879, 0x4b5303af78ebd7b0}}, + {{0x72f8a6c3bebcbde8, 0x4f0fca4adc3a8e89, 0x6fa9d4e8c7bfdf7a, 0x0dcf2d679b624eb7}}}, +{{{0x3d5947499718289c, 0x12ebf8c524533f26, 0x0262bfcb14c3ef15, 0x20b878d577b7518e}}, + {{0x753941be5a45f06e, 0xd07caeed6d9c5f65, 0x11776b9c72ff51b6, 0x17d2d1d9ef0d4da9}}, + {{0x27f2af18073f3e6a, 0xfd3fe519d7521069, 0x22e3b72c3ca60022, 0x72214f63cc65c6a7}}}, +{{{0xb4e37f405307a693, 0xaba714d72f336795, 0xd6fbd0a773761099, 0x5fdf48c58171cbc9}}, + {{0x1d9db7b9f43b29c9, 0xd605824a4f518f75, 0xf2c072bd312f9dc4, 0x1f24ac855a1545b0}}, + {{0x24d608328e9505aa, 0x4748c1d10c1420ee, 0xc7ffe45c06fb25a2, 0x00ba739e2ae395e6}}}, +{{{0x592e98de5c8790d6, 0xe5bfb7d345c2a2df, 0x115a3b60f9b49922, 0x03283a3e67ad78f3}}, + {{0xae4426f5ea88bb26, 0x360679d984973bfb, 0x5c9f030c26694e50, 0x72297de7d518d226}}, + {{0x48241dc7be0cb939, 0x32f19b4d8b633080, 0xd3dfc90d02289308, 0x05e1296846271945}}}, +{{{0xba82eeb32d9c495a, 0xceefc8fcf12bb97c, 0xb02dabae93b5d1e0, 0x39c00c9c13698d9b}}, + {{0xadbfbbc8242c4550, 0xbcc80cecd03081d9, 0x843566a6f5c8df92, 0x78cf25d38258ce4c}}, + {{0x15ae6b8e31489d68, 0xaa851cab9c2bf087, 0xc9a75a97f04efa05, 0x006b52076b3ff832}}}, +{{{0x29e0cfe19d95781c, 0xb681df18966310e2, 0x57df39d370516b39, 0x4d57e3443bc76122}}, + {{0xf5cb7e16b9ce082d, 0x3407f14c417abc29, 0xd4b36bce2bf4a7ab, 0x7de2e9561a9f75ce}}, + {{0xde70d4f4b6a55ecb, 0x4801527f5d85db99, 0xdbc9c440d3ee9a81, 0x6b2a90af1a6029ed}}}, +{{{0x6923f4fc9ae61e97, 0x5735281de03f5fd1, 0xa764ae43e6edd12d, 0x5fd8f4e9d12d3e4a}}, + {{0x77ebf3245bb2d80a, 0xd8301b472fb9079b, 0xc647e6f24cee7333, 0x465812c8276c2109}}, + {{0x4d43beb22a1062d9, 0x7065fb753831dc16, 0x180d4a7bde2968d7, 0x05b32c2b1cb16790}}}, +{{{0xc8c05eccd24da8fd, 0xa1cf1aac05dfef83, 0xdbbeeff27df9cd61, 0x3b5556a37b471e99}}, + {{0xf7fca42c7ad58195, 0x3214286e4333f3cc, 0xb6c29d0d340b979d, 0x31771a48567307e1}}, + {{0x32b0c524e14dd482, 0xedb351541a2ba4b6, 0xa3d16048282b5af3, 0x4fc079d27a7336eb}}}, +{{{0x51c938b089bf2f7f, 0x2497bd6502dfe9a7, 0xffffc09c7880e453, 0x124567cecaf98e92}}, + {{0xdc348b440c86c50d, 0x1337cbc9cc94e651, 0x6422f74d643e3cb9, 0x241170c2bae3cd08}}, + {{0x3ff9ab860ac473b4, 0xf0911dee0113e435, 0x4ae75060ebc6c4af, 0x3f8612966c87000d}}}, +{{{0x0c9c5303f7957be4, 0xa3c31a20e085c145, 0xb0721d71d0850050, 0x0aba390eab0bf2da}}, + {{0x529fdffe638c7bf3, 0xdf2b9e60388b4995, 0xe027b34f1bad0249, 0x7bc92fc9b9fa74ed}}, + {{0x9f97ef2e801ad9f9, 0x83697d5479afda3a, 0xe906b3ffbd596b50, 0x02672b37dd3fb8e0}}}, +{{{0x48b2ca8b260885e4, 0xa4286bec82b34c1c, 0x937e1a2617f58f74, 0x741d1fcbab2ca2a5}}, + {{0xee9ba729398ca7f5, 0xeb9ca6257a4849db, 0x29eb29ce7ec544e1, 0x232ca21ef736e2c8}}, + {{0xbf61423d253fcb17, 0x08803ceafa39eb14, 0xf18602df9851c7af, 0x0400f3a049e3414b}}}, +{{{0xabce0476ba61c55b, 0x36a3d6d7c4d39716, 0x6eb259d5e8d82d09, 0x0c9176e984d756fb}}, + {{0x2efba412a06e7b06, 0x146785452c8d2560, 0xdf9713ebd67a91c7, 0x32830ac7157eadf3}}, + {{0x0e782a7ab73769e8, 0x04a05d7875b18e2c, 0x29525226ebcceae1, 0x0d794f8383eba820}}}, +{{{0xff35f5cb9e1516f4, 0xee805bcf648aae45, 0xf0d73c2bb93a9ef3, 0x097b0bf22092a6c2}}, + {{0x7be44ce7a7a2e1ac, 0x411fd93efad1b8b7, 0x1734a1d70d5f7c9b, 0x0d6592233127db16}}, + {{0xc48bab1521a9d733, 0xa6c2eaead61abb25, 0x625c6c1cc6cb4305, 0x7fc90fea93eb3a67}}}, +{{{0x0408f1fe1f5c5926, 0x1a8f2f5e3b258bf4, 0x40a951a2fdc71669, 0x6598ee93c98b577e}}, + {{0xc527deb59c7cb23d, 0x955391695328404e, 0xd64392817ccf2c7a, 0x6ce97dabf7d8fa11}}, + {{0x25b5a8e50ef7c48f, 0xeb6034116f2ce532, 0xc5e75173e53de537, 0x73119fa08c12bb03}}}, +{{{0xed30129453f1a4cb, 0xbce621c9c8f53787, 0xfacb2b1338bee7b9, 0x3025798a9ea8428c}}, + {{0x7845b94d21f4774d, 0xbf62f16c7897b727, 0x671857c03c56522b, 0x3cd6a85295621212}}, + {{0x3fecde923aeca999, 0xbdaa5b0062e8c12f, 0x67b99dfc96988ade, 0x3f52c02852661036}}}, +{{{0xffeaa48e2a1351c6, 0x28624754fa7f53d7, 0x0b5ba9e57582ddf1, 0x60c0104ba696ac59}}, + {{0x9258bf99eec416c6, 0xac8a5017a9d2f671, 0x629549ab16dea4ab, 0x05d0e85c99091569}}, + {{0x051de020de9cbe97, 0xfa07fc56b50bcf74, 0x378cec9f0f11df65, 0x36853c69ab96de4d}}}, +{{{0x36d9b8de78f39b2d, 0x7f42ed71a847b9ec, 0x241cd1d679bd3fde, 0x6a704fec92fbce6b}}, + {{0x4433c0b0fac5e7be, 0x724bae854c08dcbe, 0xf1f24cc446978f9b, 0x4a0aff6d62825fc8}}, + {{0xe917fb9e61095301, 0xc102df9402a092f8, 0xbf09e2f5fa66190b, 0x681109bee0dcfe37}}}, +{{{0x559a0cc9782a0dde, 0x551dcdb2ea718385, 0x7f62865b31ef238c, 0x504aa7767973613d}}, + {{0x9c18fcfa36048d13, 0x29159db373899ddd, 0xdc9f350b9f92d0aa, 0x26f57eee878a19d4}}, + {{0x0cab2cd55687efb1, 0x5180d162247af17b, 0x85c15a344f5a2467, 0x4041943d9dba3069}}}, +{{{0xc3c0eeba43ebcc96, 0x8d749c9c26ea9caf, 0xd9fa95ee1c77ccc6, 0x1420a1d97684340f}}, + {{0x4b217743a26caadd, 0x47a6b424648ab7ce, 0xcb1d4f7a03fbc9e3, 0x12d931429800d019}}, + {{0x00c67799d337594f, 0x5e3c5140b23aa47b, 0x44182854e35ff395, 0x1b4f92314359a012}}}, +{{{0x3e5c109d89150951, 0x39cefa912de9696a, 0x20eae43f975f3020, 0x239b572a7f132dae}}, + {{0x33cf3030a49866b1, 0x251f73d2215f4859, 0xab82aa4051def4f6, 0x5ff191d56f9a23f6}}, + {{0x819ed433ac2d9068, 0x2883ab795fc98523, 0xef4572805593eb3d, 0x020c526a758f36cb}}}, +{{{0x779834f89ed8dbbc, 0xc8f2aaf9dc7ca46c, 0xa9524cdca3e1b074, 0x02aacc4615313877}}, + {{0xe931ef59f042cc89, 0x2c589c9d8e124bb6, 0xadc8e18aaec75997, 0x452cfe0a5602c50c}}, + {{0x86a0f7a0647877df, 0xbbc464270e607c9f, 0xab17ea25f1fb11c9, 0x4cfb7d7b304b877b}}}, +{{{0x72b43d6cb89b75fe, 0x54c694d99c6adc80, 0xb8c3aa373ee34c9f, 0x14b4622b39075364}}, + {{0xe28699c29789ef12, 0x2b6ecd71df57190d, 0xc343c857ecc970d0, 0x5b1d4cbc434d3ac5}}, + {{0xb6fb2615cc0a9f26, 0x3a4f0e2bb88dcce5, 0x1301498b3369a705, 0x2f98f71258592dd1}}}, +{{{0x0c94a74cb50f9e56, 0x5b1ff4a98e8e1320, 0x9a2acc2182300f67, 0x3a6ae249d806aaf9}}, + {{0x2e12ae444f54a701, 0xfcfe3ef0a9cbd7de, 0xcebf890d75835de0, 0x1d8062e9e7614554}}, + {{0x657ada85a9907c5a, 0x1a0ea8b591b90f62, 0x8d0e1dfbdf34b4e9, 0x298b8ce8aef25ff3}}}, +{{{0x2a927953eff70cb2, 0x4b89c92a79157076, 0x9418457a30a7cf6a, 0x34b8a8404d5ce485}}, + {{0x837a72ea0a2165de, 0x3fab07b40bcf79f6, 0x521636c77738ae70, 0x6ba6271803a7d7dc}}, + {{0xc26eecb583693335, 0xd5a813df63b5fefd, 0xa293aa9aa4b22573, 0x71d62bdd465e1c6a}}}, +{{{0x6533cc28d378df80, 0xf6db43790a0fa4b4, 0xe3645ff9f701da5a, 0x74d5f317f3172ba4}}, + {{0xcd2db5dab1f75ef5, 0xd77f95cf16b065f5, 0x14571fea3f49f085, 0x1c333621262b2b3d}}, + {{0xa86fe55467d9ca81, 0x398b7c752b298c37, 0xda6d0892e3ac623b, 0x4aebcc4547e9d98c}}}, +{{{0x53175a7205d21a77, 0xb0c04422d3b934d4, 0xadd9f24bdd5deadc, 0x074f46e69f10ff8c}}, + {{0x0de9b204a059a445, 0xe15cb4aa4b17ad0f, 0xe1bbec521f79c557, 0x2633f1b9d071081b}}, + {{0xc1fb4177018b9910, 0xa6ea20dc6c0fe140, 0xd661f3e74354c6ff, 0x5ecb72e6f1a3407a}}}, +{{{0xa515a31b2259fb4e, 0x0960f3972bcac52f, 0xedb52fec8d3454cb, 0x382e2720c476c019}}, + {{0xfeeae106e8e86997, 0x9863337f98d09383, 0x9470480eaa06ebef, 0x038b6898d4c5c2d0}}, + {{0xf391c51d8ace50a6, 0x3142d0b9ae2d2948, 0xdb4d5a1a7f24ca80, 0x21aeba8b59250ea8}}}, +{{{0x24f13b34cf405530, 0x3c44ea4a43088af7, 0x5dd5c5170006a482, 0x118eb8f8890b086d}}, + {{0x53853600f0087f23, 0x4c461879da7d5784, 0x6af303deb41f6860, 0x0a3c16c5c27c18ed}}, + {{0x17e49c17cc947f3d, 0xccc6eda6aac1d27b, 0xdf6092ceb0f08e56, 0x4909b3e22c67c36b}}}, +{{{0x9c9c85ea63fe2e89, 0xbe1baf910e9412ec, 0x8f7baa8a86fbfe7b, 0x0fb17f9fef968b6c}}, + {{0x59a16676706ff64e, 0x10b953dd0d86a53d, 0x5848e1e6ce5c0b96, 0x2d8b78e712780c68}}, + {{0x79d5c62eafc3902b, 0x773a215289e80728, 0xc38ae640e10120b9, 0x09ae23717b2b1a6d}}}, +{{{0xbb6a192a4e4d083c, 0x34ace0630029e192, 0x98245a59aafabaeb, 0x6d9c8a9ada97faac}}, + {{0x10ab8fa1ad32b1d0, 0xe9aced1be2778b24, 0xa8856bc0373de90f, 0x66f35ddddda53996}}, + {{0xd27d9afb24997323, 0x1bb7e07ef6f01d2e, 0x2ba7472df52ecc7f, 0x03019b4f646f9dc8}}}, +{{{0x04a186b5565345cd, 0xeee76610bcc4116a, 0x689c73b478fb2a45, 0x387dcbff65697512}}, + {{0xaf09b214e6b3dc6b, 0x3f7573b5ad7d2f65, 0xd019d988100a23b0, 0x392b63a58b5c35f7}}, + {{0x4093addc9c07c205, 0xc565be15f532c37e, 0x63dbecfd1583402a, 0x61722b4aef2e032e}}}, +{{{0x0012aafeecbd47af, 0x55a266fb1cd46309, 0xf203eb680967c72c, 0x39633944ca3c1429}}, + {{0xd6b07a5581cb0e3c, 0x290ff006d9444969, 0x08680b6a16dcda1f, 0x5568d2b75a06de59}}, + {{0x8d0cb88c1b37cfe1, 0x05b6a5a3053818f3, 0xf2e9bc04b787d959, 0x6beba1249add7f64}}}, +{{{0x1d06005ca5b1b143, 0x6d4c6bb87fd1cda2, 0x6ef5967653fcffe7, 0x097c29e8c1ce1ea5}}, + {{0x5c3cecb943f5a53b, 0x9cc9a61d06c08df2, 0xcfba639a85895447, 0x5a845ae80df09fd5}}, + {{0x4ce97dbe5deb94ca, 0x38d0a4388c709c48, 0xc43eced4a169d097, 0x0a1249fff7e587c3}}}, +{{{0x12f0071b276d01c9, 0xe7b8bac586c48c70, 0x5308129b71d6fba9, 0x5d88fbf95a3db792}}, + {{0x0b408d9e7354b610, 0x806b32535ba85b6e, 0xdbe63a034a58a207, 0x173bd9ddc9a1df2c}}, + {{0x2b500f1efe5872df, 0x58d6582ed43918c1, 0xe6ed278ec9673ae0, 0x06e1cd13b19ea319}}}, +{{{0x40d0ad516f166f23, 0x118e32931fab6abe, 0x3fe35e14a04d088e, 0x3080603526e16266}}, + {{0x472baf629e5b0353, 0x3baa0b90278d0447, 0x0c785f469643bf27, 0x7f3a6a1a8d837b13}}, + {{0xf7e644395d3d800b, 0x95a8d555c901edf6, 0x68cd7830592c6339, 0x30d0fded2e51307e}}}, +{{{0xe0594d1af21233b3, 0x1bdbe78ef0cc4d9c, 0x6965187f8f499a77, 0x0a9214202c099868}}, + {{0x9cb4971e68b84750, 0xa09572296664bbcf, 0x5c8de72672fa412b, 0x4615084351c589d9}}, + {{0xbc9019c0aeb9a02e, 0x55c7110d16034cae, 0x0e6df501659932ec, 0x3bca0d2895ca5dfe}}}, +{{{0x40f031bc3c5d62a4, 0x19fc8b3ecff07a60, 0x98183da2130fb545, 0x5631deddae8f13cd}}, + {{0x9c688eb69ecc01bf, 0xf0bc83ada644896f, 0xca2d955f5f7a9fe2, 0x4ea8b4038df28241}}, + {{0x2aed460af1cad202, 0x46305305a48cee83, 0x9121774549f11a5f, 0x24ce0930542ca463}}}, +{{{0x1fe890f5fd06c106, 0xb5c468355d8810f2, 0x827808fe6e8caf3e, 0x41d4e3c28a06d74b}}, + {{0x3fcfa155fdf30b85, 0xd2f7168e36372ea4, 0xb2e064de6492f844, 0x549928a7324f4280}}, + {{0xf26e32a763ee1a2e, 0xae91e4b7d25ffdea, 0xbc3bd33bd17f4d69, 0x491b66dec0dcff6a}}}, +{{{0x98f5b13dc7ea32a7, 0xe3d5f8cc7e16db98, 0xac0abf52cbf8d947, 0x08f338d0c85ee4ac}}, + {{0x75f04a8ed0da64a1, 0xed222caf67e2284b, 0x8234a3791f7b7ba4, 0x4cf6b8b0b7018b67}}, + {{0xc383a821991a73bd, 0xab27bc01df320c7a, 0xc13d331b84777063, 0x530d4a82eb078a99}}}, +{{{0x004c3630e1f94825, 0x7e2d78268cab535a, 0xc7482323cc84ff8b, 0x65ea753f101770b9}}, + {{0x6d6973456c9abf9e, 0x257fb2fc4900a880, 0x2bacf412c8cfb850, 0x0db3e7e00cbfbd5b}}, + {{0x3d66fc3ee2096363, 0x81d62c7f61b5cb6b, 0x0fbe044213443b1a, 0x02a4ec1921e1a1db}}}, +{{{0x5ce6259a3b24b8a2, 0xb8577acc45afa0b8, 0xcccbe6e88ba07037, 0x3d143c51127809bf}}, + {{0xf5c86162f1cf795f, 0x118c861926ee57f2, 0x172124851c063578, 0x36d12b5dec067fcf}}, + {{0x126d279179154557, 0xd5e48f5cfc783a0a, 0x36bdb6e8df179bac, 0x2ef517885ba82859}}}, +{{{0x88bd438cd11e0d4a, 0x30cb610d43ccf308, 0xe09a0e3791937bcc, 0x4559135b25b1720c}}, + {{0x1ea436837c6da1e9, 0xf9c189af1fb9bdbe, 0x303001fcce5dd155, 0x28a7c99ebc57be52}}, + {{0xb8fd9399e8d19e9d, 0x908191cb962423ff, 0xb2b948d747c742a3, 0x37f33226d7fb44c4}}}, +{{{0x0dae8767b55f6e08, 0x4a43b3b35b203a02, 0xe3725a6e80af8c79, 0x0f7a7fd1705fa7a3}}, + {{0x33912553c821b11d, 0x66ed42c241e301df, 0x066fcc11104222fd, 0x307a3b41c192168f}}, + {{0x8eeb5d076eb55ce0, 0x2fc536bfaa0d925a, 0xbe81830fdcb6c6e8, 0x556c7045827baf52}}}, +{{{0x8e2b517302e9d8b7, 0xe3e52269248714e8, 0xbd4fbd774ca960b5, 0x6f4b4199c5ecada9}}, + {{0xb94b90022bf44406, 0xabd4237eff90b534, 0x7600a960faf86d3a, 0x2f45abdac2322ee3}}, + {{0x61af4912c8ef8a6a, 0xe58fa4fe43fb6e5e, 0xb5afcc5d6fd427cf, 0x6a5393281e1e11eb}}}, +{{{0xf3da5139a5d1ee89, 0x8145457cff936988, 0x3f622fed00e188c4, 0x0f513815db8b5a3d}}, + {{0x0fff04fe149443cf, 0x53cac6d9865cddd7, 0x31385b03531ed1b7, 0x5846a27cacd1039d}}, + {{0x4ff5cdac1eb08717, 0x67e8b29590f2e9bc, 0x44093b5e237afa99, 0x0d414bed8708b8b2}}}, +{{{0xcfb68265fd0e75f6, 0xe45b3e28bb90e707, 0x7242a8de9ff92c7a, 0x685b3201933202dd}}, + {{0x81886a92294ac9e8, 0x23162b45d55547be, 0x94cfbc4403715983, 0x50eb8fdb134bc401}}, + {{0xc0b73ec6d6b330cd, 0x84e44807132faff1, 0x732b7352c4a5dee1, 0x5d7c7cf1aa7cd2d2}}}, +{{{0xaf3b46bf7a4aafa2, 0xb78705ec4d40d411, 0x114f0c6aca7c15e3, 0x3f364faaa9489d4d}}, + {{0x33d1013e9b73a562, 0x925cef5748ec26e1, 0xa7fce614dd468058, 0x78b0fad41e9aa438}}, + {{0xbf56a431ed05b488, 0xa533e66c9c495c7e, 0xe8652baf87f3651a, 0x0241800059d66c33}}}, +{{{0xceb077fea37a5be4, 0xdb642f02e5a5eeb7, 0xc2e6d0c5471270b8, 0x4771b65538e4529c}}, + {{0x28350c7dcf38ea01, 0x7c6cdbc0b2917ab6, 0xace7cfbe857082f7, 0x4d2845aba2d9a1e0}}, + {{0xbb537fe0447070de, 0xcba744436dd557df, 0xd3b5a3473600dbcb, 0x4aeabbe6f9ffd7f8}}}, +{{{0x4630119e40d8f78c, 0xa01a9bc53c710e11, 0x486d2b258910dd79, 0x1e6c47b3db0324e5}}, + {{0x6a2134bcc4a9c8f2, 0xfbf8fd1c8ace2e37, 0x000ae3049911a0ba, 0x046e3a616bc89b9e}}, + {{0x14e65442f03906be, 0x4a019d54e362be2a, 0x68ccdfec8dc230c7, 0x7cfb7e3faf6b861c}}}, +{{{0x4637974e8c58aedc, 0xb9ef22fbabf041a4, 0xe185d956e980718a, 0x2f1b78fab143a8a6}}, + {{0x96eebffb305b2f51, 0xd3f938ad889596b8, 0xf0f52dc746d5dd25, 0x57968290bb3a0095}}, + {{0xf71ab8430a20e101, 0xf393658d24f0ec47, 0xcf7509a86ee2eed1, 0x7dc43e35dc2aa3e1}}}, +{{{0x85966665887dd9c3, 0xc90f9b314bb05355, 0xc6e08df8ef2079b1, 0x7ef72016758cc12f}}, + {{0x5a782a5c273e9718, 0x3576c6995e4efd94, 0x0f2ed8051f237d3e, 0x044fb81d82d50a99}}, + {{0xc1df18c5a907e3d9, 0x57b3371dce4c6359, 0xca704534b201bb49, 0x7f79823f9c30dd2e}}}, +{{{0x8334d239a3b513e8, 0xc13670d4b91fa8d8, 0x12b54136f590bd33, 0x0a4e0373d784d9b4}}, + {{0x6a9c1ff068f587ba, 0x0827894e0050c8de, 0x3cbf99557ded5be7, 0x64a9b0431c06d6f0}}, + {{0x2eb3d6a15b7d2919, 0xb0b4f6a0d53a8235, 0x7156ce4389a45d47, 0x071a7d0ace18346c}}}, +{{{0xd3072daac887ba0b, 0x01262905bfa562ee, 0xcf543002c0ef768b, 0x2c3bcc7146ea7e9c}}, + {{0xcc0c355220e14431, 0x0d65950709b15141, 0x9af5621b209d5f36, 0x7c69bcf7617755d3}}, + {{0x07f0d7eb04e8295f, 0x10db18252f50f37d, 0xe951a9a3171798d7, 0x6f5a9a7322aca51d}}}, +{{{0x8ba1000c2f41c6c5, 0xc49f79c10cfefb9b, 0x4efa47703cc51c9f, 0x494e21a2e147afca}}, + {{0xe729d4eba3d944be, 0x8d9e09408078af9e, 0x4525567a47869c03, 0x02ab9680ee8d3b24}}, + {{0xefa48a85dde50d9a, 0x219a224e0fb9a249, 0xfa091f1dd91ef6d9, 0x6b5d76cbea46bb34}}}, +{{{0x8857556cec0cd994, 0x6472dc6f5cd01dba, 0xaf0169148f42b477, 0x0ae333f685277354}}, + {{0xe0f941171e782522, 0xf1e6ae74036936d3, 0x408b3ea2d0fcc746, 0x16fb869c03dd313e}}, + {{0x288e199733b60962, 0x24fc72b4d8abe133, 0x4811f7ed0991d03e, 0x3f81e38b8f70d075}}}, +{{{0x7f910fcc7ed9affe, 0x545cb8a12465874b, 0xa8397ed24b0c4704, 0x50510fc104f50993}}, + {{0x0adb7f355f17c824, 0x74b923c3d74299a4, 0xd57c3e8bcbf8eaf7, 0x0ad3e2d34cdedc3d}}, + {{0x6f0c0fc5336e249d, 0x745ede19c331cfd9, 0xf2d6fd0009eefe1c, 0x127c158bf0fa1ebe}}}, +{{{0xf6197c422e9879a2, 0xa44addd452ca3647, 0x9b413fc14b4eaccb, 0x354ef87d07ef4f68}}, + {{0xdea28fc4ae51b974, 0x1d9973d3744dfe96, 0x6240680b873848a8, 0x4ed82479d167df95}}, + {{0xfee3b52260c5d975, 0x50352efceb41b0b8, 0x8808ac30a9f6653c, 0x302d92d20539236d}}}, +{{{0x4c59023fcb3efb7c, 0x6c2fcb99c63c2a94, 0xba4190e2c3c7e084, 0x0e545daea51874d9}}, + {{0x957b8b8b0df53c30, 0x2a1c770a8e60f098, 0xbbc7a670345796de, 0x22a48f9a90c99bc9}}, + {{0x6b7dc0dc8d3fac58, 0x5497cd6ce6e42bfd, 0x542f7d1bf400d305, 0x4159f47f048d9136}}}, +{{{0x20ad660839e31e32, 0xf81e1bd58405be50, 0xf8064056f4dabc69, 0x14d23dd4ce71b975}}, + {{0x748515a8bbd24839, 0x77128347afb02b55, 0x50ba2ac649a2a17f, 0x060525513ad730f1}}, + {{0xf2398e098aa27f82, 0x6d7982bb89a1b024, 0xfa694084214dd24c, 0x71ab966fa32301c3}}}, +{{{0x2dcbd8e34ded02fc, 0x1151f3ec596f22aa, 0xbca255434e0328da, 0x35768fbe92411b22}}, + {{0xb1088a0702809955, 0x43b273ea0b43c391, 0xca9b67aefe0686ed, 0x605eecbf8335f4ed}}, + {{0x83200a656c340431, 0x9fcd71678ee59c2f, 0x75d4613f71300f8a, 0x7a912faf60f542f9}}}, +{{{0xb204585e5edc1a43, 0x9f0e16ee5897c73c, 0x5b82c0ae4e70483c, 0x624a170e2bddf9be}}, + {{0x253f4f8dfa2d5597, 0x25e49c405477130c, 0x00c052e5996b1102, 0x33cb966e33bb6c4a}}, + {{0x597028047f116909, 0x828ac41c1e564467, 0x70417dbde6217387, 0x721627aefbac4384}}}, +{{{0x97d03bc38736add5, 0x2f1422afc532b130, 0x3aa68a057101bbc4, 0x4c946cf7e74f9fa7}}, + {{0xfd3097bc410b2f22, 0xf1a05da7b5cfa844, 0x61289a1def57ca74, 0x245ea199bb821902}}, + {{0xaedca66978d477f8, 0x1898ba3c29117fe1, 0xcf73f983720cbd58, 0x67da12e6b8b56351}}}, +{{{0x7067e187b4bd6e07, 0x6e8f0203c7d1fe74, 0x93c6aa2f38c85a30, 0x76297d1f3d75a78a}}, + {{0x2b7ef3d38ec8308c, 0x828fd7ec71eb94ab, 0x807c3b36c5062abd, 0x0cb64cb831a94141}}, + {{0x3030fc33534c6378, 0xb9635c5ce541e861, 0x15d9a9bed9b2c728, 0x49233ea3f3775dcb}}}, +{{{0x629398fa8dbffc3a, 0xe12fe52dd54db455, 0xf3be11dfdaf25295, 0x628b140dce5e7b51}}, + {{0x7b3985fe1c9f249b, 0x4fd6b2d5a1233293, 0xceb345941adf4d62, 0x6987ff6f542de50c}}, + {{0x47e241428f83753c, 0x6317bebc866af997, 0xdabb5b433d1a9829, 0x074d8d245287fb2d}}}, +{{{0x8337d9cd440bfc31, 0x729d2ca1af318fd7, 0xa040a4a4772c2070, 0x46002ef03a7349be}}, + {{0x481875c6c0e31488, 0x219429b2e22034b4, 0x7223c98a31283b65, 0x3420d60b342277f9}}, + {{0xfaa23adeaffe65f7, 0x78261ed45be0764c, 0x441c0a1e2f164403, 0x5aea8e567a87d395}}}, +{{{0x7813c1a2bca4283d, 0xed62f091a1863dd9, 0xaec7bcb8c268fa86, 0x10e5d3b76f1cae4c}}, + {{0x2dbc6fb6e4e0f177, 0x04e1bf29a4bd6a93, 0x5e1966d4787af6e8, 0x0edc5f5eb426d060}}, + {{0x5453bfd653da8e67, 0xe9dc1eec24a9f641, 0xbf87263b03578a23, 0x45b46c51361cba72}}}, +{{{0xa9402abf314f7fa1, 0xe257f1dc8e8cf450, 0x1dbbd54b23a8be84, 0x2177bfa36dcb713b}}, + {{0xce9d4ddd8a7fe3e4, 0xab13645676620e30, 0x4b594f7bb30e9958, 0x5c1c0aef321229df}}, + {{0x37081bbcfa79db8f, 0x6048811ec25f59b3, 0x087a76659c832487, 0x4ae619387d8ab5bb}}}, +{{{0x8ddbf6aa5344a32e, 0x7d88eab4b41b4078, 0x5eb0eb974a130d60, 0x1a00d91b17bf3e03}}, + {{0x61117e44985bfb83, 0xfce0462a71963136, 0x83ac3448d425904b, 0x75685abe5ba43d64}}, + {{0x6e960933eb61f2b2, 0x543d0fa8c9ff4952, 0xdf7275107af66569, 0x135529b623b0e6aa}}}, +{{{0x18f0dbd7add1d518, 0x979f7888cfc11f11, 0x8732e1f07114759b, 0x79b5b81a65ca3a01}}, + {{0xf5c716bce22e83fe, 0xb42beb19e80985c1, 0xec9da63714254aae, 0x5972ea051590a613}}, + {{0x0fd4ac20dc8f7811, 0x9a9ad294ac4d4fa8, 0xc01b2d64b3360434, 0x4f7e9c95905f3bdb}}}, +{{{0x62674bbc5781302e, 0xd8520f3989addc0f, 0x8c2999ae53fbd9c6, 0x31993ad92e638e4c}}, + {{0x71c8443d355299fe, 0x8bcd3b1cdbebead7, 0x8092499ef1a49466, 0x1942eec4a144adc8}}, + {{0x7dac5319ae234992, 0x2c1b3d910cea3e92, 0x553ce494253c1122, 0x2a0a65314ef9ca75}}}, +{{{0x2db7937ff7f927c2, 0xdb741f0617d0a635, 0x5982f3a21155af76, 0x4cf6e218647c2ded}}, + {{0xcf361acd3c1c793a, 0x2f9ebcac5a35bc3b, 0x60e860e9a8cda6ab, 0x055dc39b6dea1a13}}, + {{0xb119227cc28d5bb6, 0x07e24ebc774dffab, 0xa83c78cee4a32c89, 0x121a307710aa24b6}}}, +{{{0xe4db5d5e9f034a97, 0xe153fc093034bc2d, 0x460546919551d3b1, 0x333fc76c7a40e52d}}, + {{0xd659713ec77483c9, 0x88bfe077b82b96af, 0x289e28231097bcd3, 0x527bb94a6ced3a9b}}, + {{0x563d992a995b482e, 0x3405d07c6e383801, 0x485035de2f64d8e5, 0x6b89069b20a7a9f7}}}, +{{{0x812aa0416270220d, 0x995a89faf9245b4e, 0xffadc4ce5072ef05, 0x23bc2103aa73eb73}}, + {{0x4082fa8cb5c7db77, 0x068686f8c734c155, 0x29e6c8d9f6e7a57e, 0x0473d308a7639bcf}}, + {{0xcaee792603589e05, 0x2b4b421246dcc492, 0x02a1ef74e601a94f, 0x102f73bfde04341a}}}, +{{{0xb5a2d50c7ec20d3e, 0xc64bdd6ea0c97263, 0x56e89052c1ff734d, 0x4929c6f72b2ffaba}}, + {{0x358ecba293a36247, 0xaf8f9862b268fd65, 0x412f7e9968a01c89, 0x5786f312cd754524}}, + {{0x337788ffca14032c, 0xf3921028447f1ee3, 0x8b14071f231bccad, 0x4c817b4bf2344783}}}, +{{{0x0ff853852871b96e, 0xe13e9fab60c3f1bb, 0xeefd595325344402, 0x0a37c37075b7744b}}, + {{0x413ba057a40b4484, 0xba4c2e1a4f5f6a43, 0x614ba0a5aee1d61c, 0x78a1531a8b05dc53}}, + {{0x6cbdf1703ad0562b, 0x8ecf4830c92521a3, 0xdaebd303fd8424e7, 0x72ad82a42e5ec56f}}}, +{{{0x3f9e8e35bafb65f6, 0x39d69ec8f27293a1, 0x6cb8cd958cf6a3d0, 0x1734778173adae6d}}, + {{0xc368939167024bc3, 0x8e69d16d49502fda, 0xfcf2ec3ce45f4b29, 0x065f669ea3b4cbc4}}, + {{0x8a00aec75532db4d, 0xb869a4e443e31bb1, 0x4a0f8552d3a7f515, 0x19adeb7c303d7c08}}}, +{{{0xc720cb6153ead9a3, 0x55b2c97f512b636e, 0xb1e35b5fd40290b1, 0x2fd9ccf13b530ee2}}, + {{0x9d05ba7d43c31794, 0x2470c8ff93322526, 0x8323dec816197438, 0x2852709881569b53}}, + {{0x07bd475b47f796b8, 0xd2c7b013542c8f54, 0x2dbd23f43b24f87e, 0x6551afd77b0901d6}}}, +{{{0x4546baaf54aac27f, 0xf6f66fecb2a45a28, 0x582d1b5b562bcfe8, 0x44b123f3920f785f}}, + {{0x68a24ce3a1d5c9ac, 0xbb77a33d10ff6461, 0x0f86ce4425d3166e, 0x56507c0950b9623b}}, + {{0x1206f0b7d1713e63, 0x353fe3d915bafc74, 0x194ceb970ad9d94d, 0x62fadd7cf9d03ad3}}}, +{{{0xc6b5967b5598a074, 0x5efe91ce8e493e25, 0xd4b72c4549280888, 0x20ef1149a26740c2}}, + {{0x3cd7bc61e7ce4594, 0xcd6b35a9b7dd267e, 0xa080abc84366ef27, 0x6ec7c46f59c79711}}, + {{0x2f07ad636f09a8a2, 0x8697e6ce24205e7d, 0xc0aefc05ee35a139, 0x15e80958b5f9d897}}}, +{{{0x25a5ef7d0c3e235b, 0x6c39c17fbe134ee7, 0xc774e1342dc5c327, 0x021354b892021f39}}, + {{0x4dd1ed355bb061c4, 0x42dc0cef941c0700, 0x61305dc1fd86340e, 0x56b2cc930e55a443}}, + {{0x1df79da6a6bfc5a2, 0x02f3a2749fde4369, 0xb323d9f2cda390a7, 0x7be0847b8774d363}}}, +{{{0x8c99cc5a8b3f55c3, 0x0611d7253fded2a0, 0xed2995ff36b70a36, 0x1f699a54d78a2619}}, + {{0x1466f5af5307fa11, 0x817fcc7ded6c0af2, 0x0a6de44ec3a4a3fb, 0x74071475bc927d0b}}, + {{0xe77292f373e7ea8a, 0x296537d2cb045a31, 0x1bd0653ed3274fde, 0x2f9a2c4476bd2966}}}, +{{{0xeb18b9ab7f5745c6, 0x023a8aee5787c690, 0xb72712da2df7afa9, 0x36597d25ea5c013d}}, + {{0xa2b4dae0b5511c9a, 0x7ac860292bffff06, 0x981f375df5504234, 0x3f6bd725da4ea12d}}, + {{0x734d8d7b106058ac, 0xd940579e6fc6905f, 0x6466f8f99202932d, 0x7b7ecc19da60d6d0}}}, +{{{0x78c2373c695c690d, 0xdd252e660642906e, 0x951d44444ae12bd2, 0x4235ad7601743956}}, + {{0x6dae4a51a77cfa9b, 0x82263654e7a38650, 0x09bbffcd8f2d82db, 0x03bedc661bf5caba}}, + {{0x6258cb0d078975f5, 0x492942549189f298, 0xa0cab423e2e36ee4, 0x0e7ce2b0cdf066a1}}}, +{{{0xc494643ac48c85a3, 0xfd361df43c6139ad, 0x09db17dd3ae94d48, 0x666e0a5d8fb4674a}}, + {{0xfea6fedfd94b70f9, 0xf130c051c1fcba2d, 0x4882d47e7f2fab89, 0x615256138aeceeb5}}, + {{0x2abbf64e4870cb0d, 0xcd65bcf0aa458b6b, 0x9abe4eba75e8985d, 0x7f0bc810d514dee4}}}, +{{{0xb9006ba426f4136f, 0x8d67369e57e03035, 0xcbc8dfd94f463c28, 0x0d1f8dbcf8eedbf5}}, + {{0x83ac9dad737213a0, 0x9ff6f8ba2ef72e98, 0x311e2edd43ec6957, 0x1d3a907ddec5ab75}}, + {{0xba1693313ed081dc, 0x29329fad851b3480, 0x0128013c030321cb, 0x00011b44a31bfde3}}}, +{{{0x3fdfa06c3fc66c0c, 0x5d40e38e4dd60dd2, 0x7ae38b38268e4d71, 0x3ac48d916e8357e1}}, + {{0x16561f696a0aa75c, 0xc1bf725c5852bd6a, 0x11a8dd7f9a7966ad, 0x63d988a2d2851026}}, + {{0x00120753afbd232e, 0xe92bceb8fdd8f683, 0xf81669b384e72b91, 0x33fad52b2368a066}}}, +{{{0x540649c6c5e41e16, 0x0af86430333f7735, 0xb2acfcd2f305e746, 0x16c0f429a256dca7}}, + {{0x8d2cc8d0c422cfe8, 0x072b4f7b05a13acb, 0xa3feb6e6ecf6a56f, 0x3cc355ccb90a71e2}}, + {{0xe9b69443903e9131, 0xb8a494cb7a5637ce, 0xc87cd1a4baba9244, 0x631eaf426bae7568}}}, +{{{0xb3e90410da66fe9f, 0x85dd4b526c16e5a6, 0xbc3d97611ef9bf83, 0x5599648b1ea919b5}}, + {{0x47d975b9a3700de8, 0x7280c5fbe2f80552, 0x53658f2732e45de1, 0x431f2c7f665f80b5}}, + {{0xd6026344858f7b19, 0x14ab352fa1ea514a, 0x8900441a2090a9d7, 0x7b04715f91253b26}}}, +{{{0x83edbd28acf6ae43, 0x86357c8b7d5c7ab4, 0xc0404769b7eb2c44, 0x59b37bf5c2f6583f}}, + {{0xb376c280c4e6bac6, 0x970ed3dd6d1d9b0b, 0xb09a9558450bf944, 0x48d0acfa57cde223}}, + {{0xb60f26e47dabe671, 0xf1d1a197622f3a37, 0x4208ce7ee9960394, 0x16234191336d3bdb}}}, +{{{0xf19aeac733a63aef, 0x2c7fba5d4442454e, 0x5da87aa04795e441, 0x413051e1a4e0b0f5}}, + {{0x852dd1fd3d578bbe, 0x2b65ce72c3286108, 0x658c07f4eace2273, 0x0933f804ec38ab40}}, + {{0xa7ab69798d496476, 0x8121aadefcb5abc8, 0xa5dc12ef7b539472, 0x07fd47065e45351a}}}, +{{{0xc8583c3d258d2bcd, 0x17029a4daf60b73f, 0xfa0fc9d6416a3781, 0x1c1e5fba38b3fb23}}, + {{0x304211559ae8e7c3, 0xf281b229944882a5, 0x8a13ac2e378250e4, 0x014afa0954ba48f4}}, + {{0xcb3197001bb3666c, 0x330060524bffecb9, 0x293711991a88233c, 0x291884363d4ed364}}}, +{{{0x033c6805dc4babfa, 0x2c15bf5e5596ecc1, 0x1bc70624b59b1d3b, 0x3ede9850a19f0ec5}}, + {{0xfb9d37c3bc1ab6eb, 0x02be14534d57a240, 0xf4d73415f8a5e1f6, 0x5964f4300ccc8188}}, + {{0xe44a23152d096800, 0x5c08c55970866996, 0xdf2db60a46affb6e, 0x579155c1f856fd89}}}, +{{{0x96324edd12e0c9ef, 0x468b878df2420297, 0x199a3776a4f573be, 0x1e7fbcf18e91e92a}}, + {{0xb5f16b630817e7a6, 0x808c69233c351026, 0x324a983b54cef201, 0x53c092084a485345}}, + {{0xd2d41481f1cbafbf, 0x231d2db6716174e5, 0x0b7d7656e2a55c98, 0x3e955cd82aa495f6}}}, +{{{0xe48f535e3ed15433, 0xd075692a0d7270a3, 0x40fbd21daade6387, 0x14264887cf4495f5}}, + {{0xab39f3ef61bb3a3f, 0x8eb400652eb9193e, 0xb5de6ecc38c11f74, 0x654d7e9626f3c49f}}, + {{0xe564cfdd5c7d2ceb, 0x82eeafded737ccb9, 0x6107db62d1f9b0ab, 0x0b6baac3b4358dbb}}}, +{{{0x7ae62bcb8622fe98, 0x47762256ceb891af, 0x1a5a92bcf2e406b4, 0x7d29401784e41501}}, + {{0x204abad63700a93b, 0xbe0023d3da779373, 0xd85f0346633ab709, 0x00496dc490820412}}, + {{0x1c74b88dc27e6360, 0x074854268d14850c, 0xa145fb7b3e0dcb30, 0x10843f1b43803b23}}}, +{{{0xc5f90455376276dd, 0xce59158dd7645cd9, 0x92f65d511d366b39, 0x11574b6e526996c4}}, + {{0xd56f672de324689b, 0xd1da8aedb394a981, 0xdd7b58fe9168cfed, 0x7ce246cd4d56c1e8}}, + {{0xb8f4308e7f80be53, 0x5f3cb8cb34a9d397, 0x18a961bd33cc2b2c, 0x710045fb3a9af671}}}, +{{{0x73f93d36101b95eb, 0xfaef33794f6f4486, 0x5651735f8f15e562, 0x7fa3f19058b40da1}}, + {{0xa03fc862059d699e, 0x2370cfa19a619e69, 0xc4fe3b122f823deb, 0x1d1b056fa7f0844e}}, + {{0x1bc64631e56bf61f, 0xd379ab106e5382a3, 0x4d58c57e0540168d, 0x566256628442d8e4}}}, +{{{0xb9e499def6267ff6, 0x7772ca7b742c0843, 0x23a0153fe9a4f2b1, 0x2cdfdfecd5d05006}}, + {{0xdd499cd61ff38640, 0x29cd9bc3063625a0, 0x51e2d8023dd73dc3, 0x4a25707a203b9231}}, + {{0x2ab7668a53f6ed6a, 0x304242581dd170a1, 0x4000144c3ae20161, 0x5721896d248e49fc}}}, +{{{0x0b6e5517fd181bae, 0x9022629f2bb963b4, 0x5509bce932064625, 0x578edd74f63c13da}}, + {{0x285d5091a1d0da4e, 0x4baa6fa7b5fe3e08, 0x63e5177ce19393b3, 0x03c935afc4b030fd}}, + {{0x997276c6492b0c3d, 0x47ccc2c4dfe205fc, 0xdcd29b84dd623a3c, 0x3ec2ab590288c7a2}}}, +{{{0xa1a0d27be4d87bb9, 0xa98b4deb61391aed, 0x99a0ddd073cb9b83, 0x2dd5c25a200fcace}}, + {{0xa7213a09ae32d1cb, 0x0f2b87df40f5c2d5, 0x0baea4c6e81eab29, 0x0e1bf66c6adbac5e}}, + {{0xe2abd5e9792c887e, 0x1a020018cb926d5d, 0xbfba69cdbaae5f1e, 0x730548b35ae88f5f}}}, +{{{0xc43551a3cba8b8ee, 0x65a26f1db2115f16, 0x760f4f52ab8c3850, 0x3043443b411db8ca}}, + {{0x805b094ba1d6e334, 0xbf3ef17709353f19, 0x423f06cb0622702b, 0x585a2277d87845dd}}, + {{0xa18a5f8233d48962, 0x6698c4b5ec78257f, 0xa78e6fa5373e41ff, 0x7656278950ef981f}}}, +{{{0x38c3cf59d51fc8c0, 0x9bedd2fd0506b6f2, 0x26bf109fab570e8f, 0x3f4160a8c1b846a6}}, + {{0xe17073a3ea86cf9d, 0x3a8cfbb707155fdc, 0x4853e7fc31838a8e, 0x28bbf484b613f616}}, + {{0xf2612f5c6f136c7c, 0xafead107f6dd11be, 0x527e9ad213de6f33, 0x1e79cb358188f75d}}}, +{{{0x013436c3eef7e3f1, 0x828b6a7ffe9e10f8, 0x7ff908e5bcf9defc, 0x65d7951b3a3b3831}}, + {{0x77e953d8f5e08181, 0x84a50c44299dded9, 0xdc6c2d0c864525e5, 0x478ab52d39d1f2f4}}, + {{0x66a6a4d39252d159, 0xe5dde1bc871ac807, 0xb82c6b40a6c1c96f, 0x16d87a411a212214}}}, +{{{0xb3bd7e5a42066215, 0x879be3cd0c5a24c1, 0x57c05db1d6f994b7, 0x28f87c8165f38ca6}}, + {{0xfba4d5e2d54e0583, 0xe21fafd72ebd99fa, 0x497ac2736ee9778f, 0x1f990b577a5a6dde}}, + {{0xa3344ead1be8f7d6, 0x7d1e50ebacea798f, 0x77c6569e520de052, 0x45882fe1534d6d3e}}}, +{{{0x6669345d757983d6, 0x62b6ed1117aa11a6, 0x7ddd1857985e128f, 0x688fe5b8f626f6dd}}, + {{0xd8ac9929943c6fe4, 0xb5f9f161a38392a2, 0x2699db13bec89af3, 0x7dcf843ce405f074}}, + {{0x6c90d6484a4732c0, 0xd52143fdca563299, 0xb3be28c3915dc6e1, 0x6739687e7327191b}}}, +{{{0x9f65c5ea200814cf, 0x840536e169a31740, 0x8b0ed13925c8b4ad, 0x0080dbafe936361d}}, + {{0x8ce5aad0c9cb971f, 0x1156aaa99fd54a29, 0x41f7247015af9b78, 0x1fe8cca8420f49aa}}, + {{0x72a1848f3c0cc82a, 0x38c560c2877c9e54, 0x5004e228ce554140, 0x042418a103429d71}}}, +{{{0x899dea51abf3ff5f, 0x9b93a8672fc2d8ba, 0x2c38cb97be6ebd5c, 0x114d578497263b5d}}, + {{0x58e84c6f20816247, 0x8db2b2b6e36fd793, 0x977182561d484d85, 0x0822024f8632abd7}}, + {{0xb301bb7c6b1beca3, 0x55393f6dc6eb1375, 0x910d281097b6e4eb, 0x1ad4548d9d479ea3}}}, +{{{0xcd5a7da0389a48fd, 0xb38fa4aa9a78371e, 0xc6d9761b2cdb8e6c, 0x35cf51dbc97e1443}}, + {{0xa06fe66d0fe9fed3, 0xa8733a401c587909, 0x30d14d800df98953, 0x41ce5876c7b30258}}, + {{0x59ac3bc5d670c022, 0xeae67c109b119406, 0x9798bdf0b3782fda, 0x651e3201fd074092}}}, +{{{0xd63d8483ef30c5cf, 0x4cd4b4962361cc0c, 0xee90e500a48426ac, 0x0af51d7d18c14eeb}}, + {{0xa57ba4a01efcae9e, 0x769f4beedc308a94, 0xd1f10eeb3603cb2e, 0x4099ce5e7e441278}}, + {{0x1ac98e4f8a5121e9, 0x7dae9544dbfa2fe0, 0x8320aa0dd6430df9, 0x667282652c4a2fb5}}}, +{{{0x874621f4d86bc9ab, 0xb54c7bbe56fe6fea, 0x077a24257fadc22c, 0x1ab53be419b90d39}}, + {{0xada8b6e02946db23, 0x1c0ce51a7b253ab7, 0x8448c85a66dd485b, 0x7f1fc025d0675adf}}, + {{0xd8ee1b18319ea6aa, 0x004d88083a21f0da, 0x3bd6aa1d883a4f4b, 0x4db9a3a6dfd9fd14}}}, +{{{0x8ce7b23bb99c0755, 0x35c5d6edc4f50f7a, 0x7e1e2ed2ed9b50c3, 0x36305f16e8934da1}}, + {{0xd95b00bbcbb77c68, 0xddbc846a91f17849, 0x7cf700aebe28d9b3, 0x5ce1285c85d31f3e}}, + {{0x31b6972d98b0bde8, 0x7d920706aca6de5b, 0xe67310f8908a659f, 0x50fac2a6efdf0235}}}, +{{{0xf3d3a9f35b880f5a, 0xedec050cdb03e7c2, 0xa896981ff9f0b1a2, 0x49a4ae2bac5e34a4}}, + {{0x295b1c86f6f449bc, 0x51b2e84a1f0ab4dd, 0xc001cb30aa8e551d, 0x6a28d35944f43662}}, + {{0x28bb12ee04a740e0, 0x14313bbd9bce8174, 0x72f5b5e4e8c10c40, 0x7cbfb19936adcd5b}}}, +{{{0xa311ddc26b89792d, 0x1b30b4c6da512664, 0x0ca77b4ccf150859, 0x1de443df1b009408}}, + {{0x8e793a7acc36e6e0, 0xf9fab7a37d586eed, 0x3a4f9692bae1f4e4, 0x1c14b03eff5f447e}}, + {{0x19647bd114a85291, 0x57b76cb21034d3af, 0x6329db440f9d6dfa, 0x5ef43e586a571493}}}, +{{{0xef782014385675a6, 0xa2649f30aafda9e8, 0x4cd1eb505cdfa8cb, 0x46115aba1d4dc0b3}}, + {{0xa66dcc9dc80c1ac0, 0x97a05cf41b38a436, 0xa7ebf3be95dbd7c6, 0x7da0b8f68d7e7dab}}, + {{0xd40f1953c3b5da76, 0x1dac6f7321119e9b, 0x03cc6021feb25960, 0x5a5f887e83674b4b}}}, +{{{0x8f6301cf70a13d11, 0xcfceb815350dd0c4, 0xf70297d4a4bca47e, 0x3669b656e44d1434}}, + {{0x9e9628d3a0a643b9, 0xb5c3cb00e6c32064, 0x9b5302897c2dec32, 0x43e37ae2d5d1c70c}}, + {{0x387e3f06eda6e133, 0x67301d5199a13ac0, 0xbd5ad8f836263811, 0x6a21e6cd4fd5e9be}}}, +{{{0xf1c6170a3046e65f, 0x58712a2a00d23524, 0x69dbbd3c8c82b755, 0x586bf9f1a195ff57}}, + {{0xef4129126699b2e3, 0x71d30847708d1301, 0x325432d01182b0bd, 0x45371b07001e8b36}}, + {{0xa6db088d5ef8790b, 0x5278f0dc610937e5, 0xac0349d261a16eb8, 0x0eafb03790e52179}}}, +{{{0x960555c13748042f, 0x219a41e6820baa11, 0x1c81f73873486d0c, 0x309acc675a02c661}}, + {{0x5140805e0f75ae1d, 0xec02fbe32662cc30, 0x2cebdf1eea92396d, 0x44ae3344c5435bb3}}, + {{0x9cf289b9bba543ee, 0xf3760e9d5ac97142, 0x1d82e5c64f9360aa, 0x62d5221b7f94678f}}}, +{{{0x524c299c18d0936d, 0xc86bb56c8a0c1a0c, 0xa375052edb4a8631, 0x5c0efde4bc754562}}, + {{0x7585d4263af77a3c, 0xdfae7b11fee9144d, 0xa506708059f7193d, 0x14f29a5383922037}}, + {{0xdf717edc25b2d7f5, 0x21f970db99b53040, 0xda9234b7c3ed4c62, 0x5e72365c7bee093e}}}, +{{{0x575bfc074571217f, 0x3779675d0694d95b, 0x9a0a37bbf4191e33, 0x77f1104c47b4eabc}}, + {{0x7d9339062f08b33e, 0x5b9659e5df9f32be, 0xacff3dad1f9ebdfd, 0x70b20555cb7349b7}}, + {{0xbe5113c555112c4c, 0x6688423a9a881fcd, 0x446677855e503b47, 0x0e34398f4a06404a}}}, +{{{0xb67d22d93ecebde8, 0x09b3e84127822f07, 0x743fa61fb05b6d8d, 0x5e5405368a362372}}, + {{0x18930b093e4b1928, 0x7de3e10e73f3f640, 0xf43217da73395d6f, 0x6f8aded6ca379c3e}}, + {{0xe340123dfdb7b29a, 0x487b97e1a21ab291, 0xf9967d02fde6949e, 0x780de72ec8d3de97}}}, +{{{0x0ae28545089ae7bc, 0x388ddecf1c7f4d06, 0x38ac15510a4811b8, 0x0eb28bf671928ce4}}, + {{0x671feaf300f42772, 0x8f72eb2a2a8c41aa, 0x29a17fd797373292, 0x1defc6ad32b587a6}}, + {{0xaf5bbe1aef5195a7, 0x148c1277917b15ed, 0x2991f7fb7ae5da2e, 0x467d201bf8dd2867}}}, +{{{0x7906ee72f7bd2e6b, 0x05d270d6109abf4e, 0x8d5cfe45b941a8a4, 0x44c218671c974287}}, + {{0x745f9d56296bc318, 0x993580d4d8152e65, 0xb0e5b13f5839e9ce, 0x51fc2b28d43921c0}}, + {{0x1b8fd11795e2a98c, 0x1c4e5ee12b6b6291, 0x5b30e7107424b572, 0x6e6b9de84c4f4ac6}}}, +{{{0xdff25fce4b1de151, 0xd841c0c7e11c4025, 0x2554b3c854749c87, 0x2d292459908e0df9}}, + {{0x6b7c5f10f80cb088, 0x736b54dc56e42151, 0xc2b620a5c6ef99c4, 0x5f4c802cc3a06f42}}, + {{0x9b65c8f17d0752da, 0x881ce338c77ee800, 0xc3b514f05b62f9e3, 0x66ed5dd5bec10d48}}}, +{{{0x7d38a1c20bb2089d, 0x808334e196ccd412, 0xc4a70b8c6c97d313, 0x2eacf8bc03007f20}}, + {{0xf0adf3c9cbca047d, 0x81c3b2cbf4552f6b, 0xcfda112d44735f93, 0x1f23a0c77e20048c}}, + {{0xf235467be5bc1570, 0x03d2d9020dbab38c, 0x27529aa2fcf9e09e, 0x0840bef29d34bc50}}}, +{{{0x796dfb35dc10b287, 0x27176bcd5c7ff29d, 0x7f3d43e8c7b24905, 0x0304f5a191c54276}}, + {{0xcd54e06b7f37e4eb, 0x8cc15f87f5e96cca, 0xb8248bb0d3597dce, 0x246affa06074400c}}, + {{0x37d88e68fbe45321, 0x86097548c0d75032, 0x4e9b13ef894a0d35, 0x25a83cac5753d325}}}, +{{{0x10222f48eed8165e, 0x623fc1234b8bcf3a, 0x1e145c09c221e8f0, 0x7ccfa59fca782630}}, + {{0x9f0f66293952b6e2, 0x33db5e0e0934267b, 0xff45252bd609fedc, 0x06be10f5c506e0c9}}, + {{0x1a9615a9b62a345f, 0x22050c564a52fecc, 0xa7a2788528bc0dfe, 0x5e82770a1a1ee71d}}}, +{{{0x35425183ad896a5c, 0xe8673afbe78d52f6, 0x2c66f25f92a35f64, 0x09d04f3b3b86b102}}, + {{0xe802e80a42339c74, 0x34175166a7fffae5, 0x34865d1f1c408cae, 0x2cca982c605bc5ee}}, + {{0xfd2d5d35197dbe6e, 0x207c2eea8be4ffa3, 0x2613d8db325ae918, 0x7a325d1727741d3e}}}, +{{{0xd036b9bbd16dfde2, 0xa2055757c497a829, 0x8e6cc966a7f12667, 0x4d3b1a791239c180}}, + {{0xecd27d017e2a076a, 0xd788689f1636495e, 0x52a61af0919233e5, 0x2a479df17bb1ae64}}, + {{0x9e5eee8e33db2710, 0x189854ded6c43ca5, 0xa41c22c592718138, 0x27ad5538a43a5e9b}}}, +{{{0x2746dd4b15350d61, 0xd03fcbc8ee9521b7, 0xe86e365a138672ca, 0x510e987f7e7d89e2}}, + {{0xcb5a7d638e47077c, 0x8db7536120a1c059, 0x549e1e4d8bedfdcc, 0x080153b7503b179d}}, + {{0xdda69d930a3ed3e3, 0x3d386ef1cd60a722, 0xc817ad58bdaa4ee6, 0x23be8d554fe7372a}}}, +{{{0x95fe919a74ef4fad, 0x3a827becf6a308a2, 0x964e01d309a47b01, 0x71c43c4f5ba3c797}}, + {{0xbc1ef4bd567ae7a9, 0x3f624cb2d64498bd, 0xe41064d22c1f4ec8, 0x2ef9c5a5ba384001}}, + {{0xb6fd6df6fa9e74cd, 0xf18278bce4af267a, 0x8255b3d0f1ef990e, 0x5a758ca390c5f293}}}, +{{{0xa2b72710d9462495, 0x3aa8c6d2d57d5003, 0xe3d400bfa0b487ca, 0x2dbae244b3eb72ec}}, + {{0x8ce0918b1d61dc94, 0x8ded36469a813066, 0xd4e6a829afe8aad3, 0x0a738027f639d43f}}, + {{0x980f4a2f57ffe1cc, 0x00670d0de1839843, 0x105c3f4a49fb15fd, 0x2698ca635126a69c}}}, +{{{0xe765318832b0ba78, 0x381831f7925cff8b, 0x08a81b91a0291fcc, 0x1fb43dcc49caeb07}}, + {{0x2e3d702f5e3dd90e, 0x9e3f0918e4d25386, 0x5e773ef6024da96a, 0x3c004b0c4afa3332}}, + {{0x9aa946ac06f4b82b, 0x1ca284a5a806c4f3, 0x3ed3265fc6cd4787, 0x6b43fd01cd1fd217}}}, +{{{0xc7a75d4b4697c544, 0x15fdf848df0fffbf, 0x2868b9ebaa46785a, 0x5a68d7105b52f714}}, + {{0xb5c742583e760ef3, 0x75dc52b9ee0ab990, 0xbf1427c2072b923f, 0x73420b2d6ff0d9f0}}, + {{0xaf2cf6cb9e851e06, 0x8f593913c62238c4, 0xda8ab89699fbf373, 0x3db5632fea34bc9e}}}, +{{{0xf46eee2bf75dd9d8, 0x0d17b1f6396759a5, 0x1bf2d131499e7273, 0x04321adf49d75f13}}, + {{0x2e4990b1829825d5, 0xedeaeb873e9a8991, 0xeef03d394c704af8, 0x59197ea495df2b0e}}, + {{0x04e16019e4e55aae, 0xe77b437a7e2f92e9, 0xc7ce2dc16f159aa4, 0x45eafdc1f4d70cc0}}}, +{{{0x698401858045d72b, 0x4c22faa2cf2f0651, 0x941a36656b222dc6, 0x5a5eebc80362dade}}, + {{0xb60e4624cfccb1ed, 0x59dbc292bd5c0395, 0x31a09d1ddc0481c9, 0x3f73ceea5d56d940}}, + {{0xb7a7bfd10a4e8dc6, 0xbe57007e44c9b339, 0x60c1207f1557aefa, 0x26058891266218db}}}, +{{{0x59f704a68360ff04, 0xc3d93fde7661e6f4, 0x831b2a7312873551, 0x54ad0c2e4e615d57}}, + {{0x4c818e3cc676e542, 0x5e422c9303ceccad, 0xec07cccab4129f08, 0x0dedfa10b24443b8}}, + {{0xee3b67d5b82b522a, 0x36f163469fa5c1eb, 0xa5b4d2f26ec19fd3, 0x62ecb2baa77a9408}}}, +{{{0xe5ed795261152b3d, 0x4962357d0eddd7d1, 0x7482c8d0b96b4c71, 0x2e59f919a966d8be}}, + {{0x92072836afb62874, 0x5fcd5e8579e104a5, 0x5aad01adc630a14a, 0x61913d5075663f98}}, + {{0x0dc62d361a3231da, 0xfa47583294200270, 0x02d801513f9594ce, 0x3ddbc2a131c05d5c}}}, +{{{0x3f50a50a4ffb81ef, 0xb1e035093bf420bf, 0x9baa8e1cc6aa2cd0, 0x32239861fa237a40}}, + {{0xfb735ac2004a35d1, 0x31de0f433a6607c3, 0x7b8591bfc528d599, 0x55be9a25f5bb050c}}, + {{0x0d005acd33db3dbf, 0x0111b37c80ac35e2, 0x4892d66c6f88ebeb, 0x770eadb16508fbcd}}}, +{{{0x8451f9e05e4e89dd, 0xc06302ffbc793937, 0x5d22749556a6495c, 0x09a6755ca05603fb}}, + {{0xf1d3b681a05071b9, 0x2207659a3592ff3a, 0x5f0169297881e40e, 0x16bedd0e86ba374e}}, + {{0x5ecccc4f2c2737b5, 0x43b79e0c2dccb703, 0x33e008bc4ec43df3, 0x06c1b840f07566c0}}}, +{{{0x7688a5c6a388f877, 0x02a96c14deb2b6ac, 0x64c9f3431b8c2af8, 0x3628435554a1eed6}}, + {{0x69ee9e7f9b02805c, 0xcbff828a547d1640, 0x3d93a869b2430968, 0x46b7b8cd3fe26972}}, + {{0xe9812086fe7eebe0, 0x4cba6be72f515437, 0x1d04168b516efae9, 0x5ea1391043982cb9}}}, +{{{0x49125c9cf4702ee1, 0x4520b71f8b25b32d, 0x33193026501fef7e, 0x656d8997c8d2eb2b}}, + {{0x6f2b3be4d5d3b002, 0xafec33d96a09c880, 0x035f73a4a8bcc4cc, 0x22c5b9284662198b}}, + {{0xcb58c8fe433d8939, 0x89a0cb2e6a8d7e50, 0x79ca955309fbbe5a, 0x0c626616cd7fc106}}}, +{{{0x1ffeb80a4879b61f, 0x6396726e4ada21ed, 0x33c7b093368025ba, 0x471aa0c6f3c31788}}, + {{0x8fdfc379fbf454b1, 0x45a5a970f1a4b771, 0xac921ef7bad35915, 0x42d088dca81c2192}}, + {{0x8fda0f37a0165199, 0x0adadb77c8a0e343, 0x20fbfdfcc875e820, 0x1cf2bea80c2206e7}}}, +{{{0xc2ddf1deb36202ac, 0x92a5fe09d2e27aa5, 0x7d1648f6fc09f1d3, 0x74c2cc0513bc4959}}, + {{0x982d6e1a02c0412f, 0x90fa4c83db58e8fe, 0x01c2f5bcdcb18bc0, 0x686e0c90216abc66}}, + {{0x1fadbadba54395a7, 0xb41a02a0ae0da66a, 0xbf19f598bba37c07, 0x6a12b8acde48430d}}}, +{{{0xf8daea1f39d495d9, 0x592c190e525f1dfc, 0xdb8cbd04c9991d1b, 0x11f7fda3d88f0cb7}}, + {{0x793bdd801aaeeb5f, 0x00a2a0aac1518871, 0xe8a373a31f2136b4, 0x48aab888fc91ef19}}, + {{0x041f7e925830f40e, 0x002d6ca979661c06, 0x86dc9ff92b046a2e, 0x760360928b0493d1}}}, +{{{0x21bb41c6120cf9c6, 0xeab2aa12decda59b, 0xc1a72d020aa48b34, 0x215d4d27e87d3b68}}, + {{0xb43108e5695a0b05, 0x6cb00ee8ad37a38b, 0x5edad6eea3537381, 0x3f2602d4b6dc3224}}, + {{0xc8b247b65bcaf19c, 0x49779dc3b1b2c652, 0x89a180bbd5ece2e2, 0x13f098a3cec8e039}}}, +{{{0x9adc0ff9ce5ec54b, 0x039c2a6b8c2f130d, 0x028007c7f0f89515, 0x78968314ac04b36b}}, + {{0xf3aa57a22796bb14, 0x883abab79b07da21, 0xe54be21831a0391c, 0x5ee7fb38d83205f9}}, + {{0x538dfdcb41446a8e, 0xa5acfda9434937f9, 0x46af908d263c8c78, 0x61d0633c9bca0d09}}}, +{{{0x63744935ffdb2566, 0xc5bd6b89780b68bb, 0x6f1b3280553eec03, 0x6e965fd847aed7f5}}, + {{0xada328bcf8fc73df, 0xee84695da6f037fc, 0x637fb4db38c2a909, 0x5b23ac2df8067bdc}}, + {{0x9ad2b953ee80527b, 0xe88f19aafade6d8d, 0x0e711704150e82cf, 0x79b9bbb9dd95dedc}}}, +{{{0xebb355406a3126c2, 0xd26383a868c8c393, 0x6c0c6429e5b97a82, 0x5065f158c9fd2147}}, + {{0xd1997dae8e9f7374, 0xa032a2f8cfbb0816, 0xcd6cba126d445f0a, 0x1ba811460accb834}}, + {{0x708169fb0c429954, 0xe14600acd76ecf67, 0x2eaab98a70e645ba, 0x3981f39e58a4faf2}}}, +{{{0x18fb8a7559230a93, 0x1d168f6960e6f45d, 0x3a85a94514a93cb5, 0x38dc083705acd0fd}}, + {{0xc845dfa56de66fde, 0xe152a5002c40483a, 0xe9d2e163c7b4f632, 0x30f4452edcbc1b65}}, + {{0x856d2782c5759740, 0xfa134569f99cbecc, 0x8844fc73c0ea4e71, 0x632d9a1a593f2469}}}, +{{{0xf6bb6b15b807cba6, 0x1823c7dfbc54f0d7, 0xbb1d97036e29670b, 0x0b24f48847ed4a57}}, + {{0xbf09fd11ed0c84a7, 0x63f071810d9f693a, 0x21908c2d57cf8779, 0x3a5a7df28af64ba2}}, + {{0xdcdad4be511beac7, 0xa4538075ed26ccf2, 0xe19cff9f005f9a65, 0x34fcf74475481f63}}}, +{{{0xc197e04c789767ca, 0xb8714dcb38d9467d, 0x55de888283f95fa8, 0x3d3bdc164dfa63f7}}, + {{0xa5bb1dab78cfaa98, 0x5ceda267190b72f2, 0x9309c9110a92608e, 0x0119a3042fb374b0}}, + {{0x67a2d89ce8c2177d, 0x669da5f66895d0c1, 0xf56598e5b282a2b0, 0x56c088f1ede20a73}}}, +{{{0x336d3d1110a86e17, 0xd7f388320b75b2fa, 0xf915337625072988, 0x09674c6b99108b87}}, + {{0x581b5fac24f38f02, 0xa90be9febae30cbd, 0x9a2169028acf92f0, 0x038b7ea48359038f}}, + {{0x9f4ef82199316ff8, 0x2f49d282eaa78d4f, 0x0971a5ab5aef3174, 0x6e5e31025969eb65}}}, +{{{0xb16c62f587e593fb, 0x4999eddeca5d3e71, 0xb491c1e014cc3e6d, 0x08f5114789a8dba8}}, + {{0x3304fb0e63066222, 0xfb35068987acba3f, 0xbd1924778c1061a3, 0x3058ad43d1838620}}, + {{0x323c0ffde57663d0, 0x05c3df38a22ea610, 0xbdc78abdac994f9a, 0x26549fa4efe3dc99}}}, +{{{0x738b38d787ce8f89, 0xb62658e24179a88d, 0x30738c9cf151316d, 0x49128c7f727275c9}}, + {{0x04dbbc17f75396b9, 0x69e6a2d7d2f86746, 0xc6409d99f53eabc6, 0x606175f6332e25d2}}, + {{0x4021370ef540e7dd, 0x0910d6f5a1f1d0a5, 0x4634aacd5b06b807, 0x6a39e6356944f235}}}, +{{{0x96cd5640df90f3e7, 0x6c3a760edbfa25ea, 0x24f3ef0959e33cc4, 0x42889e7e530d2e58}}, + {{0x1da1965774049e9d, 0xfbcd6ea198fe352b, 0xb1cbcd50cc5236a6, 0x1f5ec83d3f9846e2}}, + {{0x8efb23c3328ccb75, 0xaf42a207dd876ee9, 0x20fbdadc5dfae796, 0x241e246b06bf9f51}}}, +{{{0x29e68e57ad6e98f6, 0x4c9260c80b462065, 0x3f00862ea51ebb4b, 0x5bc2c77fb38d9097}}, + {{0x7eaafc9a6280bbb8, 0x22a70f12f403d809, 0x31ce40bb1bfc8d20, 0x2bc65635e8bd53ee}}, + {{0xe8d5dc9fa96bad93, 0xe58fb17dde1947dc, 0x681532ea65185fa3, 0x1fdd6c3b034a7830}}}, +{{{0x0a64e28c55dc18fe, 0xe3df9e993399ebdd, 0x79ac432370e2e652, 0x35ff7fc33ae4cc0e}}, + {{0x9c13a6a52dd8f7a9, 0x2dbb1f8c3efdcabf, 0x961e32405e08f7b5, 0x48c8a121bbe6c9e5}}, + {{0xfc415a7c59646445, 0xd224b2d7c128b615, 0x6035c9c905fbb912, 0x42d7a91274429fab}}}, +{{{0x4e6213e3eaf72ed3, 0x6794981a43acd4e7, 0xff547cde6eb508cb, 0x6fed19dd10fcb532}}, + {{0xa9a48947933da5bc, 0x4a58920ec2e979ec, 0x96d8800013e5ac4c, 0x453692d74b48b147}}, + {{0xdd775d99a8559c6f, 0xf42a2140df003e24, 0x5223e229da928a66, 0x063f46ba6d38f22c}}}, +{{{0xd2d242895f536694, 0xca33a2c542939b2c, 0x986fada6c7ddb95c, 0x5a152c042f712d5d}}, + {{0x39843cb737346921, 0xa747fb0738c89447, 0xcb8d8031a245307e, 0x67810f8e6d82f068}}, + {{0x3eeb8fbcd2287db4, 0x72c7d3a301a03e93, 0x5473e88cbd98265a, 0x7324aa515921b403}}}, +{{{0x857942f46c3cbe8e, 0xa1d364b14730c046, 0x1c8ed914d23c41bf, 0x0838e161eef6d5d2}}, + {{0xad23f6dae82354cb, 0x6962502ab6571a6d, 0x9b651636e38e37d1, 0x5cac5005d1a3312f}}, + {{0x8cc154cce9e39904, 0x5b3a040b84de6846, 0xc4d8a61cb1be5d6e, 0x40fb897bd8861f02}}}, +{{{0x84c5aa9062de37a1, 0x421da5000d1d96e1, 0x788286306a9242d9, 0x3c5e464a690d10da}}, + {{0xe57ed8475ab10761, 0x71435e206fd13746, 0x342f824ecd025632, 0x4b16281ea8791e7b}}, + {{0xd1c101d50b813381, 0xdee60f1176ee6828, 0x0cb68893383f6409, 0x6183c565f6ff484a}}}, +{{{0x741d5a461e6bf9d6, 0x2305b3fc7777a581, 0xd45574a26474d3d9, 0x1926e1dc6401e0ff}}, + {{0xdb468549af3f666e, 0xd77fcf04f14a0ea5, 0x3df23ff7a4ba0c47, 0x3a10dfe132ce3c85}}, + {{0xe07f4e8aea17cea0, 0x2fd515463a1fc1fd, 0x175322fd31f2c0f1, 0x1fa1d01d861e5d15}}}, +{{{0xcc8055947d599832, 0x1e4656da37f15520, 0x99f6f7744e059320, 0x773563bc6a75cf33}}, + {{0x38dcac00d1df94ab, 0x2e712bddd1080de9, 0x7f13e93efdd5e262, 0x73fced18ee9a01e5}}, + {{0x06b1e90863139cb3, 0xa493da67c5a03ecd, 0x8d77cec8ad638932, 0x1f426b701b864f44}}}, +{{{0xefc9264c41911c01, 0xf1a3b7b817a22c25, 0x5875da6bf30f1447, 0x4e1af5271d31b090}}, + {{0xf17e35c891a12552, 0xb76b8153575e9c76, 0xfa83406f0d9b723e, 0x0b76bb1b3fa7e438}}, + {{0x08b8c1f97f92939b, 0xbe6771cbd444ab6e, 0x22e5646399bb8017, 0x7b6dd61eb772a955}}}, +{{{0xb7adc1e850f33d92, 0x7998fa4f608cd5cf, 0xad962dbd8dfc5bdb, 0x703e9bceaf1d2f4f}}, + {{0x5730abf9ab01d2c7, 0x16fb76dc40143b18, 0x866cbe65a0cbb281, 0x53fa9b659bff6afe}}, + {{0x6c14c8e994885455, 0x843a5d6665aed4e5, 0x181bb73ebcd65af1, 0x398d93e5c4c61f50}}}, +{{{0x1c4bd16733e248f3, 0xbd9e128715bf0a5f, 0xd43f8cf0a10b0376, 0x53b09b5ddf191b13}}, + {{0xc3877c60d2e7e3f2, 0x3b34aaa030828bb1, 0x283e26e7739ef138, 0x699c9c9002c30577}}, + {{0xf306a7235946f1cc, 0x921718b5cce5d97d, 0x28cdd24781b4e975, 0x51caf30c6fcdd907}}}, +{{{0xa60ba7427674e00a, 0x630e8570a17a7bf3, 0x3758563dcf3324cc, 0x5504aa292383fdaa}}, + {{0x737af99a18ac54c7, 0x903378dcc51cb30f, 0x2b89bc334ce10cc7, 0x12ae29c189f8e99a}}, + {{0xa99ec0cb1f0d01cf, 0x0dd1efcc3a34f7ae, 0x55ca7521d09c4e22, 0x5fd14fe958eba5ea}}}, +{{{0xb5dc2ddf2845ab2c, 0x069491b10a7fe993, 0x4daaf3d64002e346, 0x093ff26e586474d1}}, + {{0x3c42fe5ebf93cb8e, 0xbedfa85136d4565f, 0xe0f0859e884220e8, 0x7dd73f960725d128}}, + {{0xb10d24fe68059829, 0x75730672dbaf23e5, 0x1367253ab457ac29, 0x2f59bcbc86b470a4}}}, +{{{0x83847d429917135f, 0xad1b911f567d03d7, 0x7e7748d9be77aad1, 0x5458b42e2e51af4a}}, + {{0x7041d560b691c301, 0x85201b3fadd7e71e, 0x16c2e16311335585, 0x2aa55e3d010828b1}}, + {{0xed5192e60c07444f, 0x42c54e2d74421d10, 0x352b4c82fdb5c864, 0x13e9004a8a768664}}}, +{{{0xcbb5b5556c032bff, 0xdf7191b729297a3a, 0xc1ff7326aded81bb, 0x71ade8bb68be03f5}}, + {{0x1e6284c5806b467c, 0xc5f6997be75d607b, 0x8b67d958b378d262, 0x3d88d66a81cd8b70}}, + {{0x8b767a93204ed789, 0x762fcacb9fa0ae2a, 0x771febcc6dce4887, 0x343062158ff05fb3}}}, +{{{0xe05da1a7e1f5bf49, 0x26457d6dd4736092, 0x77dcb07773cc32f6, 0x0a5d94969cdd5fcd}}, + {{0xfce219072a7b31b4, 0x4d7adc75aa578016, 0x0ec276a687479324, 0x6d6d9d5d1fda4beb}}, + {{0x22b1a58ae9b08183, 0xfd95d071c15c388b, 0xa9812376850a0517, 0x33384cbabb7f335e}}}, +{{{0x3c6fa2680ca2c7b5, 0x1b5082046fb64fda, 0xeb53349c5431d6de, 0x5278b38f6b879c89}}, + {{0x33bc627a26218b8d, 0xea80b21fc7a80c61, 0x9458b12b173e9ee6, 0x076247be0e2f3059}}, + {{0x52e105f61416375a, 0xec97af3685abeba4, 0x26e6b50623a67c36, 0x5cf0e856f3d4fb01}}}, +{{{0xf6c968731ae8cab4, 0x5e20741ecb4f92c5, 0x2da53be58ccdbc3e, 0x2dddfea269970df7}}, + {{0xbeaece313db342a8, 0xcba3635b842db7ee, 0xe88c6620817f13ef, 0x1b9438aa4e76d5c6}}, + {{0x8a50777e166f031a, 0x067b39f10fb7a328, 0x1925c9a6010fbd76, 0x6df9b575cc740905}}}, +{{{0x42c1192927f6bdcf, 0x8f91917a403d61ca, 0xdc1c5a668b9e1f61, 0x1596047804ec0f8d}}, + {{0xecdfc35b48cade41, 0x6a88471fb2328270, 0x740a4a2440a01b6a, 0x471e5796003b5f29}}, + {{0xda96bbb3aced37ac, 0x7a2423b5e9208cea, 0x24cc5c3038aebae2, 0x50c356afdc5dae2f}}}, +{{{0x09dcbf4341c30318, 0xeeba061183181dce, 0xc179c0cedc1e29a1, 0x1dbf7b89073f35b0}}, + {{0xcfed9cdf1b31b964, 0xf486a9858ca51af3, 0x14897265ea8c1f84, 0x784a53dd932acc00}}, + {{0x2d99f9df14fc4920, 0x76ccb60cc4499fe5, 0xa4132cbbe5cf0003, 0x3f93d82354f000ea}}}, +{{{0x8183e7689e04ce85, 0x678fb71e04465341, 0xad92058f6688edac, 0x5da350d3532b099a}}, + {{0xeaac12d179e14978, 0xff923ff3bbebff5e, 0x4af663e40663ce27, 0x0fd381a811a5f5ff}}, + {{0xf256aceca436df54, 0x108b6168ae69d6e8, 0x20d986cb6b5d036c, 0x655957b9fee2af50}}}, +{{{0xaea8b07fa902030f, 0xf88c766af463d143, 0x15b083663c787a60, 0x08eab1148267a4a8}}, + {{0xbdc1409bd002d0ac, 0x66660245b5ccd9a6, 0x82317dc4fade85ec, 0x02fe934b6ad7df0d}}, + {{0xef5cf100cfb7ea74, 0x22897633a1cb42ac, 0xd4ce0c54cef285e2, 0x30408c048a146a55}}}, +{{{0x739d8845832fcedb, 0xfa38d6c9ae6bf863, 0x32bc0dcab74ffef7, 0x73937e8814bce45e}}, + {{0xbb2e00c9193b877f, 0xece3a890e0dc506b, 0xecf3b7c036de649f, 0x5f46040898de9e1a}}, + {{0xb9037116297bf48d, 0xa9d13b22d4f06834, 0xe19715574696bdc6, 0x2cf8a4e891d5e835}}}, +{{{0x6d93fd8707110f67, 0xdd4c09d37c38b549, 0x7cb16a4cc2736a86, 0x2049bd6e58252a09}}, + {{0x2cb5487e17d06ba2, 0x24d2381c3950196b, 0xd7659c8185978a30, 0x7a6f7f2891d6a4f6}}, + {{0x7d09fd8d6a9aef49, 0xf0ee60be5b3db90b, 0x4c21b52c519ebfd4, 0x6011aadfc545941d}}}, +{{{0x5f67926dcf95f83c, 0x7c7e856171289071, 0xd6a1e7f3998f7a5b, 0x6fc5cc1b0b62f9e0}}, + {{0x63ded0c802cbf890, 0xfbd098ca0dff6aaa, 0x624d0afdb9b6ed99, 0x69ce18b779340b1e}}, + {{0xd1ef5528b29879cb, 0xdd1aae3cd47e9092, 0x127e0442189f2352, 0x15596b3ae57101f1}}}, +{{{0x462739d23f9179a2, 0xff83123197d6ddcf, 0x1307deb553f2148a, 0x0d2237687b5f4dda}}, + {{0x09ff31167e5124ca, 0x0be4158bd9c745df, 0x292b7d227ef556e5, 0x3aa4e241afb6d138}}, + {{0x2cc138bf2a3305f5, 0x48583f8fa2e926c3, 0x083ab1a25549d2eb, 0x32fcaa6e4687a36c}}}, +{{{0x7bc56e8dc57d9af5, 0x3e0bd2ed9df0bdf2, 0xaac014de22efe4a3, 0x4627e9cefebd6a5c}}, + {{0x3207a4732787ccdf, 0x17e31908f213e3f8, 0xd5b2ecd7f60d964e, 0x746f6336c2600be9}}, + {{0x3f4af345ab6c971c, 0xe288eb729943731f, 0x33596a8a0344186d, 0x7b4917007ed66293}}}, +{{{0x2d85fb5cab84b064, 0x497810d289f3bc14, 0x476adc447b15ce0c, 0x122ba376f844fd7b}}, + {{0x54341b28dd53a2dd, 0xaa17905bdf42fc3f, 0x0ff592d94dd2f8f4, 0x1d03620fe08cd37d}}, + {{0xc20232cda2b4e554, 0x9ed0fd42115d187f, 0x2eabb4be7dd479d9, 0x02c70bf52b68ec4c}}}, +{{{0xa287ec4b5d0b2fbb, 0x415c5790074882ca, 0xe044a61ec1d0815c, 0x26334f0a409ef5e0}}, + {{0xace532bf458d72e1, 0x5be768e07cb73cb5, 0x56cf7d94ee8bbde7, 0x6b0697e3feb43a03}}, + {{0xb6c8f04adf62a3c0, 0x3ef000ef076da45d, 0x9c9cb95849f0d2a9, 0x1cc37f43441b2fae}}}, +{{{0x508f565a5cc7324f, 0xd061c4c0e506a922, 0xfb18abdb5c45ac19, 0x6c6809c10380314a}}, + {{0xd76656f1c9ceaeb9, 0x1c5b15f818e5656a, 0x26e72832844c2334, 0x3a346f772f196838}}, + {{0xd2d55112e2da6ac8, 0xe9bd0331b1e851ed, 0x960746dd8ec67262, 0x05911b9f6ef7c5d0}}}, +{{{0xe9dcd756b637ff2d, 0xec4c348fc987f0c4, 0xced59285f3fbc7b7, 0x3305354793e1ea87}}, + {{0x01c18980c5fe9f94, 0xcd656769716fd5c8, 0x816045c3d195a086, 0x6e2b7f3266cc7982}}, + {{0xcc802468f7c3568f, 0x9de9ba8219974cb3, 0xabb7229cb5b81360, 0x44e2017a6fbeba62}}}, +{{{0xc4c2a74354dab774, 0x8e5d4c3c4eaf031a, 0xb76c23d242838f17, 0x749a098f68dce4ea}}, + {{0x87f82cf3b6ca6ecd, 0x580f893e18f4a0c2, 0x058930072604e557, 0x6cab6ac256d19c1d}}, + {{0xdcdfe0a02cc1de60, 0x032665ff51c5575b, 0x2c0c32f1073abeeb, 0x6a882014cd7b8606}}}, +{{{0xa52a92fea4747fb5, 0xdc12a4491fa5ab89, 0xd82da94bb847a4ce, 0x4d77edce9512cc4e}}, + {{0xd111d17caf4feb6e, 0x050bba42b33aa4a3, 0x17514c3ceeb46c30, 0x54bedb8b1bc27d75}}, + {{0x77c8e14577e2189c, 0xa3e46f6aff99c445, 0x3144dfc86d335343, 0x3a96559e7c4216a9}}}, +{{{0x12550d37f42ad2ee, 0x8b78e00498a1fbf5, 0x5d53078233894cb2, 0x02c84e4e3e498d0c}}, + {{0x4493896880baaa52, 0x4c98afc4f285940e, 0xef4aa79ba45448b6, 0x5278c510a57aae7f}}, + {{0xa54dd074294c0b94, 0xf55d46b8df18ffb6, 0xf06fecc58dae8366, 0x588657668190d165}}}, +{{{0xd47712311aef7117, 0x50343101229e92c7, 0x7a95e1849d159b97, 0x2449959b8b5d29c9}}, + {{0xbf5834f03de25cc3, 0xb887c8aed6815496, 0x5105221a9481e892, 0x6760ed19f7723f93}}, + {{0x669ba3b7ac35e160, 0x2eccf73fba842056, 0x1aec1f17c0804f07, 0x0d96bc031856f4e7}}}, +{{{0x3318be7775c52d82, 0x4cb764b554d0aab9, 0xabcf3d27cc773d91, 0x3bf4d1848123288a}}, + {{0xb1d534b0cc7505e1, 0x32cd003416c35288, 0xcb36a5800762c29d, 0x5bfe69b9237a0bf8}}, + {{0x183eab7e78a151ab, 0xbbe990c999093763, 0xff717d6e4ac7e335, 0x4c5cddb325f39f88}}}, +{{{0xc0f6b74d6190a6eb, 0x20ea81a42db8f4e4, 0xa8bd6f7d97315760, 0x33b1d60262ac7c21}}, + {{0x57750967e7a9f902, 0x2c37fdfc4f5b467e, 0xb261663a3177ba46, 0x3a375e78dc2d532b}}, + {{0x8141e72f2d4dddea, 0xe6eafe9862c607c8, 0x23c28458573cafd0, 0x46b9476f4ff97346}}}, +{{{0x0c1ffea44f901e5c, 0x2b0b6fb72184b782, 0xe587ff910114db88, 0x37130f364785a142}}, + {{0x1215505c0d58359f, 0x2a2013c7fc28c46b, 0x24a0a1af89ea664e, 0x4400b638a1130e1f}}, + {{0x3a01b76496ed19c3, 0x31e00ab0ed327230, 0x520a885783ca15b1, 0x06aab9875accbec7}}}, +{{{0xc1339983f5df0ebb, 0xc0f3758f512c4cac, 0x2cf1130a0bb398e1, 0x6b3cecf9aa270c62}}, + {{0x5349acf3512eeaef, 0x20c141d31cc1cb49, 0x24180c07a99a688d, 0x555ef9d1c64b2d17}}, + {{0x36a770ba3b73bd08, 0x624aef08a3afbf0c, 0x5737ff98b40946f2, 0x675f4de13381749d}}}, +{{{0x0e2c52036b1782fc, 0x64816c816cad83b4, 0xd0dcbdd96964073e, 0x13d99df70164c520}}, + {{0xa12ff6d93bdab31d, 0x0725d80f9d652dfe, 0x019c4ff39abe9487, 0x60f450b882cd3c43}}, + {{0x014b5ec321e5c0ca, 0x4fcb69c9d719bfa2, 0x4e5f1c18750023a0, 0x1c06de9e55edac80}}}, +{{{0x990f7ad6a33ec4e2, 0x6608f938be2ee08e, 0x9ca143c563284515, 0x4cf38a1fec2db60d}}, + {{0xffd52b40ff6d69aa, 0x34530b18dc4049bb, 0x5e4a5c2fa34d9897, 0x78096f8e7d32ba2d}}, + {{0xa0aaaa650dfa5ce7, 0xf9c49e2a48b5478c, 0x4f09cc7d7003725b, 0x373cad3a26091abe}}}, +{{{0xb294634d82c9f57c, 0x1fcbfde124934536, 0x9e9c4db3418cdb5a, 0x0040f3d9454419fc}}, + {{0xf1bea8fb89ddbbad, 0x3bcb2cbc61aeaecb, 0x8f58a7bb1f9b8d9d, 0x21547eda5112a686}}, + {{0xdefde939fd5986d3, 0xf4272c89510a380c, 0xb72ba407bb3119b9, 0x63550a334a254df4}}}, +{{{0x6507d6edb569cf37, 0x178429b00ca52ee1, 0xea7c0090eb6bd65d, 0x3eea62c7daf78f51}}, + {{0x9bba584572547b49, 0xf305c6fae2c408e0, 0x60e8fa69c734f18d, 0x39a92bafaa7d767a}}, + {{0x9d24c713e693274e, 0x5f63857768dbd375, 0x70525560eb8ab39a, 0x68436a0665c9c4cd}}}, +{{{0xbc0235e8202f3f27, 0xc75c00e264f975b0, 0x91a4e9d5a38c2416, 0x17b6e7f68ab789f9}}, + {{0x1e56d317e820107c, 0xc5266844840ae965, 0xc1e0a1c6320ffc7a, 0x5373669c91611472}}, + {{0x5d2814ab9a0e5257, 0x908f2084c9cab3fc, 0xafcaf5885b2d1eca, 0x1cb4b5a678f87d11}}}, +{{{0xb664c06b394afc6c, 0x0c88de2498da5fb1, 0x4f8d03164bcad834, 0x330bca78de7434a2}}, + {{0x6b74aa62a2a007e7, 0xf311e0b0f071c7b1, 0x5707e438000be223, 0x2dc0fd2d82ef6eac}}, + {{0x982eff841119744e, 0xf9695e962b074724, 0xc58ac14fbfc953fb, 0x3c31be1b369f1cf5}}}, +{{{0xb0f4864d08948aee, 0x07dc19ee91ba1c6f, 0x7975cdaea6aca158, 0x330b61134262d4bb}}, + {{0xc168bc93f9cb4272, 0xaeb8711fc7cedb98, 0x7f0e52aa34ac8d7a, 0x41cec1097e7d55bb}}, + {{0xf79619d7a26d808a, 0xbb1fd49e1d9e156d, 0x73d7c36cdba1df27, 0x26b44cd91f28777d}}}, +{{{0x300a9035393aa6d8, 0x2b501131a12bb1cd, 0x7b1ff677f093c222, 0x4309c1f8cab82bad}}, + {{0xaf44842db0285f37, 0x8753189047efc8df, 0x9574e091f820979a, 0x0e378d6069615579}}, + {{0xd9fa917183075a55, 0x4bdb5ad26b009fdc, 0x7829ad2cd63def0e, 0x078fc54975fd3877}}}, +{{{0x87dfbd1428878f2d, 0x134636dd1e9421a1, 0x4f17c951257341a3, 0x5df98d4bad296cb8}}, + {{0xe2004b5bb833a98a, 0x44775dec2d4c3330, 0x3aa244067eace913, 0x272630e3d58e00a9}}, + {{0xf3678fd0ecc90b54, 0xf001459b12043599, 0x26725fbc3758b89b, 0x4325e4aa73a719ae}}}, +{{{0x657dc6ef433c3493, 0x65375e9f80dbf8c3, 0x47fd2d465b372dae, 0x4966ab79796e7947}}, + {{0xed24629acf69f59d, 0x2a4a1ccedd5abbf4, 0x3535ca1f56b2d67b, 0x5d8c68d043b1b42d}}, + {{0xee332d4de3b42b0a, 0xd84e5a2b16a4601c, 0x78243877078ba3e4, 0x77ed1eb4184ee437}}}, +{{{0xbfd4e13f201839a0, 0xaeefffe23e3df161, 0xb65b04f06b5d1fe3, 0x52e085fb2b62fbc0}}, + {{0x185d43f89e92ed1a, 0xb04a1eeafe4719c6, 0x499fbe88a6f03f4f, 0x5d8b0d2f3c859bdd}}, + {{0x124079eaa54cf2ba, 0xd72465eb001b26e7, 0x6843bcfdc97af7fd, 0x0524b42b55eacd02}}}, +{{{0xfd0d5dbee45447b0, 0x6cec351a092005ee, 0x99a47844567579cb, 0x59d242a216e7fa45}}, + {{0xbc18dcad9b829eac, 0x23ae7d28b5f579d0, 0xc346122a69384233, 0x1a6110b2e7d4ac89}}, + {{0x4f833f6ae66997ac, 0x6849762a361839a4, 0x6985dec1970ab525, 0x53045e89dcb1f546}}}, +{{{0xcb8bb346d75353db, 0xfcfcb24bae511e22, 0xcba48d40d50ae6ef, 0x26e3bae5f4f7cb5d}}, + {{0x84da3cde8d45fe12, 0xbd42c218e444e2d2, 0xa85196781f7e3598, 0x7642c93f5616e2b2}}, + {{0x2323daa74595f8e4, 0xde688c8b857abeb4, 0x3fc48e961c59326e, 0x0b2e73ca15c9b8ba}}}, +{{{0xd6bb4428c17f5026, 0x9eb27223fb5a9ca7, 0xe37ba5031919c644, 0x21ce380db59a6602}}, + {{0x0e3fbfaf79c03a55, 0x3077af054cbb5acf, 0xd5c55245db3de39f, 0x015e68c1476a4af7}}, + {{0xc1d5285220066a38, 0x95603e523570aef3, 0x832659a7226b8a4d, 0x5dd689091f8eedc9}}}, +{{{0xcbac84debfd3c856, 0x1624c348b35ff244, 0xb7f88dca5d9cad07, 0x3b0e574da2c2ebe8}}, + {{0x1d022591a5313084, 0xca2d4aaed6270872, 0x86a12b852f0bfd20, 0x56e6c439ad7da748}}, + {{0xc704ff4942bdbae6, 0x5e21ade2b2de1f79, 0xe95db3f35652fad8, 0x0822b5378f08ebc1}}}, +{{{0x51f048478f387475, 0xb25dbcf49cbecb3c, 0x9aab1244d99f2055, 0x2c709e6c1c10a5d6}}, + {{0xe1b7f29362730383, 0x4b5279ffebca8a2c, 0xdafc778abfd41314, 0x7deb10149c72610f}}, + {{0xcb62af6a8766ee7a, 0x66cbec045553cd0e, 0x588001380f0be4b5, 0x08e68e9ff62ce2ea}}}, +{{{0x34ad500a4bc130ad, 0x8d38db493d0bd49c, 0xa25c3d98500a89be, 0x2f1f3f87eeba3b09}}, + {{0x2f2d09d50ab8f2f9, 0xacb9218dc55923df, 0x4a8f342673766cb9, 0x4cb13bd738f719f5}}, + {{0xf7848c75e515b64a, 0xa59501badb4a9038, 0xc20d313f3f751b50, 0x19a1e353c0ae2ee8}}}, +{{{0x7d1c7560bafa05c3, 0xb3e1a0a0c6e55e61, 0xe3529718c0d66473, 0x41546b11c20c3486}}, + {{0xb42172cdd596bdbd, 0x93e0454398eefc40, 0x9fb15347b44109b5, 0x736bd3990266ae34}}, + {{0x85532d509334b3b4, 0x46fd114b60816573, 0xcc5f5f30425c8375, 0x412295a2b87fab5c}}}, +{{{0x19c99b88f57ed6e9, 0x5393cb266df8c825, 0x5cee3213b30ad273, 0x14e153ebb52d2e34}}, + {{0x2e655261e293eac6, 0x845a92032133acdb, 0x460975cb7900996b, 0x0760bb8d195add80}}, + {{0x413e1a17cde6818a, 0x57156da9ed69a084, 0x2cbf268f46caccb1, 0x6b34be9bc33ac5f2}}}, +{{{0xf3df2f643a78c0b2, 0x4c3e971ef22e027c, 0xec7d1c5e49c1b5a3, 0x2012c18f0922dd2d}}, + {{0x11fc69656571f2d3, 0xc6c9e845530e737a, 0xe33ae7a2d4fe5035, 0x01b9c7b62e6dd30b}}, + {{0x880b55e55ac89d29, 0x1483241f45a0a763, 0x3d36efdfc2e76c1f, 0x08af5b784e4bade8}}}, +{{{0x283499dc881f2533, 0x9d0525da779323b6, 0x897addfb673441f4, 0x32b79d71163a168d}}, + {{0xe27314d289cc2c4b, 0x4be4bd11a287178d, 0x18d528d6fa3364ce, 0x6423c1d5afd9826e}}, + {{0xcc85f8d9edfcb36a, 0x22bcc28f3746e5f9, 0xe49de338f9e5d3cd, 0x480a5efbc13e2dcc}}}, +{{{0x0b51e70b01622071, 0x06b505cf8b1dafc5, 0x2c6bb061ef5aabcd, 0x47aa27600cb7bf31}}, + {{0xb6614ce442ce221f, 0x6e199dcc4c053928, 0x663fb4a4dc1cbe03, 0x24b31d47691c8e06}}, + {{0x2a541eedc015f8c3, 0x11a4fe7e7c693f7c, 0xf0af66134ea278d6, 0x545b585d14dda094}}}, +{{{0x67bf275ea0d43a0f, 0xade68e34089beebe, 0x4289134cd479e72e, 0x0f62f9c332ba5454}}, + {{0x6204e4d0e3b321e1, 0x3baa637a28ff1e95, 0x0b0ccffd5b99bd9e, 0x4d22dc3e64c8d071}}, + {{0xfcb46589d63b5f39, 0x5cae6a3f57cbcf61, 0xfebac2d2953afa05, 0x1c0fa01a36371436}}}, +{{{0xe7547449bc7cd692, 0x0f9abeaae6f73ddf, 0x4af01ca700837e29, 0x63ab1b5d3f1bc183}}, + {{0xc11ee5e854c53fae, 0x6a0b06c12b4f3ff4, 0x33540f80e0b67a72, 0x15f18fc3cd07e3ef}}, + {{0x32750763b028f48c, 0x06020740556a065f, 0xd53bd812c3495b58, 0x08706c9b865f508d}}}, +{{{0xf37ca2ab3d343dff, 0x1a8c6a2d80abc617, 0x8e49e035d4ccffca, 0x48b46beebaa1d1b9}}, + {{0xcc991b4138b41246, 0x243b9c526f9ac26b, 0xb9ef494db7cbabbd, 0x5fba433dd082ed00}}, + {{0x9c49e355c9941ad0, 0xb9734ade74498f84, 0x41c3fed066663e5c, 0x0ecfedf8e8e710b3}}}, +{{{0x76430f9f9cd470d9, 0xb62acc9ba42f6008, 0x1898297c59adad5e, 0x7789dd2db78c5080}}, + {{0x744f7463e9403762, 0xf79a8dee8dfcc9c9, 0x163a649655e4cde3, 0x3b61788db284f435}}, + {{0xb22228190d6ef6b2, 0xa94a66b246ce4bfa, 0x46c1a77a4f0b6cc7, 0x4236ccffeb7338cf}}}, +{{{0x8497404d0d55e274, 0x6c6663d9c4ad2b53, 0xec2fb0d9ada95734, 0x2617e120cdb8f73c}}, + {{0x3bd82dbfda777df6, 0x71b177cc0b98369e, 0x1d0e8463850c3699, 0x5a71945b48e2d1f1}}, + {{0x6f203dd5405b4b42, 0x327ec60410b24509, 0x9c347230ac2a8846, 0x77de29fc11ffeb6a}}}, +{{{0xb0ac57c983b778a8, 0x53cdcca9d7fe912c, 0x61c2b854ff1f59dc, 0x3a1a2cf0f0de7dac}}, + {{0x835e138fecced2ca, 0x8c9eaf13ea963b9a, 0xc95fbfc0b2160ea6, 0x575e66f3ad877892}}, + {{0x99803a27c88fcb3a, 0x345a6789275ec0b0, 0x459789d0ff6c2be5, 0x62f882651e70a8b2}}}, +{{{0x085ae2c759ff1be4, 0x149145c93b0e40b7, 0xc467e7fa7ff27379, 0x4eeecf0ad5c73a95}}, + {{0x6d822986698a19e0, 0xdc9821e174d78a71, 0x41a85f31f6cb1f47, 0x352721c2bcda9c51}}, + {{0x48329952213fc985, 0x1087cf0d368a1746, 0x8e5261b166c15aa5, 0x2d5b2d842ed24c21}}}, +{{{0x02cfebd9ebd3ded1, 0xd45b217739021974, 0x7576f813fe30a1b7, 0x5691b6f9a34ef6c2}}, + {{0x5eb7d13d196ac533, 0x377234ecdb80be2b, 0xe144cffc7cf5ae24, 0x5226bcf9c441acec}}, + {{0x79ee6c7223e5b547, 0x6f5f50768330d679, 0xed73e1e96d8adce9, 0x27c3da1e1d8ccc03}}}, +{{{0x7eb9efb23fe24c74, 0x3e50f49f1651be01, 0x3ea732dc21858dea, 0x17377bd75bb810f9}}, + {{0x28302e71630ef9f6, 0xc2d4a2032b64cee0, 0x090820304b6292be, 0x5fca747aa82adf18}}, + {{0x232a03c35c258ea5, 0x86f23a2c6bcb0cf1, 0x3dad8d0d2e442166, 0x04a8933cab76862b}}}, +{{{0xd2c604b622943dff, 0xbc8cbece44cfb3a0, 0x5d254ff397808678, 0x0fa3614f3b1ca6bf}}, + {{0x69082b0e8c936a50, 0xf9c9a035c1dac5b6, 0x6fb73e54c4dfb634, 0x4005419b1d2bc140}}, + {{0xa003febdb9be82f0, 0x2089c1af3a44ac90, 0xf8499f911954fa8e, 0x1fba218aef40ab42}}}, +{{{0xab549448fac8f53e, 0x81f6e89a7ba63741, 0x74fd6c7d6c2b5e01, 0x392e3acaa8c86e42}}, + {{0x4f3e57043e7b0194, 0xa81d3eee08daaf7f, 0xc839c6ab99dcdef1, 0x6c535d13ff7761d5}}, + {{0x4cbd34e93e8a35af, 0x2e0781445887e816, 0x19319c76f29ab0ab, 0x25e17fe4d50ac13b}}}, +{{{0x0a289bd71e04f676, 0x208e1c52d6420f95, 0x5186d8b034691fab, 0x255751442a9fb351}}, + {{0x915f7ff576f121a7, 0xc34a32272fcd87e3, 0xccba2fde4d1be526, 0x6bba828f8969899b}}, + {{0xe2d1bc6690fe3901, 0x4cb54a18a0997ad5, 0x971d6914af8460d4, 0x559d504f7f6b7be4}}}, +{{{0xa7738378b3eb54d5, 0x1d69d366a5553c7c, 0x0a26cf62f92800ba, 0x01ab12d5807e3217}}, + {{0x9c4891e7f6d266fd, 0x0744a19b0307781b, 0x88388f1d6061e23b, 0x123ea6a3354bd50e}}, + {{0x118d189041e32d96, 0xb9ede3c2d8315848, 0x1eab4271d83245d9, 0x4a3961e2c918a154}}}, +{{{0x71dc3be0f8e6bba0, 0xd6cef8347effe30a, 0xa992425fe13a476a, 0x2cd6bce3fb1db763}}, + {{0x0327d644f3233f1e, 0x499a260e34fcf016, 0x83b5a716f2dab979, 0x68aceead9bd4111f}}, + {{0x38b4c90ef3d7c210, 0x308e6e24b7ad040c, 0x3860d9f1b7e73e23, 0x595760d5b508f597}}}, +{{{0x6129bfe104aa6397, 0x8f960008a4a7fccb, 0x3f8bc0897d909458, 0x709fa43edcb291a9}}, + {{0x882acbebfd022790, 0x89af3305c4115760, 0x65f492e37d3473f4, 0x2cb2c5df54515a2b}}, + {{0xeb0a5d8c63fd2aca, 0xd22bc1662e694eff, 0x2723f36ef8cbb03a, 0x70f029ecf0c8131f}}}, +{{{0x461307b32eed3e33, 0xae042f33a45581e7, 0xc94449d3195f0366, 0x0b7d5d8a6c314858}}, + {{0x2a6aafaa5e10b0b9, 0x78f0a370ef041aa9, 0x773efb77aa3ad61f, 0x44eca5a2a74bd9e1}}, + {{0x25d448327b95d543, 0x70d38300a3340f1d, 0xde1c531c60e1c52b, 0x272224512c7de9e4}}}, +{{{0x1abc92af49c5342e, 0xffeed811b2e6fad0, 0xefa28c8dfcc84e29, 0x11b5df18a44cc543}}, + {{0xbf7bbb8a42a975fc, 0x8c5c397796ada358, 0xe27fc76fcdedaa48, 0x19735fd7f6bc20a6}}, + {{0xe3ab90d042c84266, 0xeb848e0f7f19547e, 0x2503a1d065a497b9, 0x0fef911191df895f}}}, +{{{0xb1507ca1ab1c6eb9, 0xbd448f3e16b687b3, 0x3455fb7f2c7a91ab, 0x7579229e2f2adec1}}, + {{0x6ab5dcb85b1c16b7, 0x94c0fce83c7b27a5, 0xa4b11c1a735517be, 0x499238d0ba0eafaa}}, + {{0xecf46e527aba8b57, 0x15a08c478bd1647b, 0x7af1c6a65f706fef, 0x6345fa78f03a30d5}}}, +{{{0xdf02f95f1015e7a1, 0x790ec41da9b40263, 0x4d3a0ea133ea1107, 0x54f70be7e33af8c9}}, + {{0x93d3cbe9bdd8f0a4, 0xdb152c1bfd177302, 0x7dbddc6d7f17a875, 0x3e1a71cc8f426efe}}, + {{0xc83ca3e390babd62, 0x80ede3670291c833, 0xc88038ccd37900c4, 0x2c5fc0231ec31fa1}}}, +{{{0xfeba911717038b4f, 0xe5123721c9deef81, 0x1c97e4e75d0d8834, 0x68afae7a23dc3bc6}}, + {{0xc422e4d102456e65, 0x87414ac1cad47b91, 0x1592e2bba2b6ffdd, 0x75d9d2bff5c2100f}}, + {{0x5bd9b4763626e81c, 0x89966936bca02edd, 0x0a41193d61f077b3, 0x3097a24200ce5471}}}, +{{{0x57427734c7f8b84c, 0xf141a13e01b270e9, 0x02d1adfeb4e564a6, 0x4bb23d92ce83bd48}}, + {{0xa162e7246695c486, 0x131d633435a89607, 0x30521561a0d12a37, 0x56704bada6afb363}}, + {{0xaf6c4aa752f912b9, 0x5e665f6cd86770c8, 0x4c35ac83a3c8cd58, 0x2b7a29c010a58a7e}}}, +{{{0xc4007f77d0c1cec3, 0x8d1020b6bac492f8, 0x32ec29d57e69daaf, 0x599408759d95fce0}}, + {{0x33810a23bf00086e, 0xafce925ee736ff7c, 0x3d60e670e24922d4, 0x11ce9e714f96061b}}, + {{0x219ef713d815bac1, 0xf141465d485be25c, 0x6d5447cc4e513c51, 0x174926be5ef44393}}}, +{{{0xb5deb2f9fc5bd5bb, 0x92daa72ae1d810e1, 0xafc4cfdcb72a1c59, 0x497d78813fc22a24}}, + {{0x3ef5d41593ea022e, 0x5cbcc1a20ed0eed6, 0x8fd24ecf07382c8c, 0x6fa42ead06d8e1ad}}, + {{0xe276824a1f73371f, 0x7f7cf01c4f5b6736, 0x7e201fe304fa46e7, 0x785a36a357808c96}}}, +{{{0x825fbdfd63014d2b, 0xc852369c6ca7578b, 0x5b2fcd285c0b5df0, 0x12ab214c58048c8f}}, + {{0x070442985d517bc3, 0x6acd56c7ae653678, 0x00a27983985a7763, 0x5167effae512662b}}, + {{0xbd4ea9e10f53c4b6, 0x1673dc5f8ac91a14, 0xa8f81a4e2acc1aba, 0x33a92a7924332a25}}}, +{{{0x9dd1f49927996c02, 0x0cb3b058e04d1752, 0x1f7e88967fd02c3e, 0x2f964268cb8b3eb1}}, + {{0x7ba95ba0218f2ada, 0xcff42287330fb9ca, 0xdada496d56c6d907, 0x5380c296f4beee54}}, + {{0x9d4f270466898d0a, 0x3d0987990aff3f7a, 0xd09ef36267daba45, 0x7761455e7b1c669c}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data b/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data new file mode 100644 index 0000000..a31f6f2 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data @@ -0,0 +1,768 @@ +{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, + {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, + {{0xdbbd15674b6fbb59, 0x41e13f00eea2a5ea, 0xcdd49d1cc957c6fa, 0x4f0ebe1faf16ecca}}}, +{{{0x8a99a56042b4d5a8, 0x8f2b810c4e60acf6, 0xe09e236bb16e37aa, 0x6bb595a669c92555}}, + {{0x9224e7fc933c71d7, 0x9f469d967a0ff5b5, 0x5aa69a65e1d60702, 0x590c063fa87d2e2e}}, + {{0x6e347eaadad36802, 0xbaf3599383ee4805, 0x3bcabe10e6076826, 0x49314f0a165ed1b8}}}, +{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, + {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, + {{0x9bf211f4f1674834, 0xb84e6b17f62df895, 0xd7de6f075b722a4e, 0x549a04b963bb2a21}}}, +{{{0x95fe050a056818bf, 0x327e89715660faa9, 0xc3e8e3cd06a05073, 0x27933f4c7445a49a}}, + {{0x287351b98efc099f, 0x6765c6f47dfd2538, 0xca348d3dfb0a9265, 0x680e910321e58727}}, + {{0xbf1e45ece51426b0, 0xe32bc63d6dba0f94, 0xe42974d58cf852c0, 0x44f079b1b0e64c18}}}, +{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, + {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, + {{0xc832a179e7d003b3, 0x5f729d0a00124d7e, 0x62c1d4a10e6d8ff3, 0x68b8ac5938b27a98}}}, +{{{0x499806b67b7d8ca4, 0x575be28427d22739, 0xbb085ce7204553b9, 0x38b64c41ae417884}}, + {{0x3a0ceeeb77157131, 0x9b27158900c8af88, 0x8065b668da59a736, 0x51e57bb6a2cc38bd}}, + {{0x8f9dad91689de3a4, 0x175f2428f8fb9137, 0x050ab5329fcfb988, 0x7865dfa21354c09f}}}, +{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, + {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, + {{0x217a8aacab0fda36, 0xa528c6543d3549c8, 0x37d05b8b13ab7568, 0x233cef623a2cbc37}}}, +{{{0xe2a75dedf39234d9, 0x963d7680e1b558f9, 0x2c2741ac6e3c23fb, 0x3a9024a1320e01c3}}, + {{0x59b7596604dd3e8f, 0x6cb30377e288702c, 0xb1339c665ed9c323, 0x0915e76061bce52f}}, + {{0xdf7de835a834a37e, 0x8be19cda689857ea, 0x2c1185367167b326, 0x589eb3d9dbefd5c2}}}, +{{{0xed5b635449aa515e, 0xa865c49f0bc6823a, 0x850c1fe95b42d1c4, 0x30d76d6f03d315b9}}, + {{0x2eccdd0e632f9c1d, 0x51d0b69676893115, 0x52dfb76ba8637a58, 0x6dd37d49a00eef39}}, + {{0x6c4444172106e4c7, 0xfb53d680928d7f69, 0xb4739ea4694d3f26, 0x10c697112e864bb0}}}, +{{{0x6493c4277dbe5fde, 0x265d4fad19ad7ea2, 0x0e00dfc846304590, 0x25e61cabed66fe09}}, + {{0x0ca62aa08358c805, 0x6a3d4ae37a204247, 0x7464d3a63b11eddc, 0x03bf9baf550806ef}}, + {{0x3f13e128cc586604, 0x6f5873ecb459747e, 0xa0b63dedcc1268f5, 0x566d78634586e22c}}}, +{{{0x1637a49f9cc10834, 0xbc8e56d5a89bc451, 0x1cb5ec0f7f7fd2db, 0x33975bca5ecc35d9}}, + {{0xa1054285c65a2fd0, 0x6c64112af31667c3, 0x680ae240731aee58, 0x14fba5f34793b22a}}, + {{0x3cd746166985f7d4, 0x593e5e84c9c80057, 0x2fc3f2b67b61131e, 0x14829cea83fc526c}}}, +{{{0xff437b8497dd95c2, 0x6c744e30aa4eb5a7, 0x9e0c5d613c85e88b, 0x2fd9c71e5f758173}}, + {{0x21e70b2f4e71ecb8, 0xe656ddb940a477e3, 0xbf6556cece1d4f80, 0x05fc3bc4535d7b7e}}, + {{0x24b8b3ae52afdedd, 0x3495638ced3b30cf, 0x33a4bc83a9be8195, 0x373767475c651f04}}}, +{{{0x2fba99fd40d1add9, 0xb307166f96f4d027, 0x4363f05215f03bae, 0x1fbea56c3b18f999}}, + {{0x634095cb14246590, 0xef12144016c15535, 0x9e38140c8910bc60, 0x6bf5905730907c8c}}, + {{0x0fa778f1e1415b8a, 0x06409ff7bac3a77e, 0x6f52d7b89aa29a50, 0x02521cf67a635a56}}}, +{{{0x513fee0b0a9d5294, 0x8f98e75c0fdf5a66, 0xd4618688bfe107ce, 0x3fa00a7e71382ced}}, + {{0xb1146720772f5ee4, 0xe8f894b196079ace, 0x4af8224d00ac824a, 0x001753d9f7cd6cc4}}, + {{0x3c69232d963ddb34, 0x1dde87dab4973858, 0xaad7d1f9a091f285, 0x12b5fe2fa048edb6}}}, +{{{0x71f0fbc496fce34d, 0x73b9826badf35bed, 0xd2047261ff28c561, 0x749b76f96fb1206f}}, + {{0xdf2b7c26ad6f1e92, 0x4b66d323504b8913, 0x8c409dc0751c8bc3, 0x6f7e93c20796c7b8}}, + {{0x1f5af604aea6ae05, 0xc12351f1bee49c99, 0x61a808b5eeff6b66, 0x0fcec10f01e02151}}}, +{{{0x644d58a649fe1e44, 0x21fcaea231ad777e, 0x02441c5a887fd0d2, 0x4901aa7183c511f3}}, + {{0x3df2d29dc4244e45, 0x2b020e7493d8de0a, 0x6cc8067e820c214d, 0x413779166feab90a}}, + {{0x08b1b7548c1af8f0, 0xce0f7a7c246299b4, 0xf760b0f91e06d939, 0x41bb887b726d1213}}}, +{{{0x40e87d44744346be, 0x1d48dad415b52b25, 0x7c3a8a18a13b603e, 0x4eb728c12fcdbdf7}}, + {{0x7e234c597c6691ae, 0x64889d3d0a85b4c8, 0xdae2c90c354afae7, 0x0a871e070c6a9e1d}}, + {{0x3301b5994bbc8989, 0x736bae3a5bdd4260, 0x0d61ade219d59e3c, 0x3ee7300f2685d464}}}, +{{{0xf5d255e49e7dd6b7, 0x8016115c610b1eac, 0x3c99975d92e187ca, 0x13815762979125c2}}, + {{0x43fa7947841e7518, 0xe5c6fa59639c46d7, 0xa1065e1de3052b74, 0x7d47c6a2cfb89030}}, + {{0x3fdad0148ef0d6e0, 0x9d3e749a91546f3c, 0x71ec621026bb8157, 0x148cf58d34c9ec80}}}, +{{{0x46a492f67934f027, 0x469984bef6840aa9, 0x5ca1bc2a89611854, 0x3ff2fa1ebd5dbbd4}}, + {{0xe2572f7d9ae4756d, 0x56c345bb88f3487f, 0x9fd10b6d6960a88d, 0x278febad4eaea1b9}}, + {{0xb1aa681f8c933966, 0x8c21949c20290c98, 0x39115291219d3c52, 0x4104dd02fe9c677b}}}, +{{{0x72b2bf5e1124422a, 0xa1fa0c3398a33ab5, 0x94cb6101fa52b666, 0x2c863b00afaf53d5}}, + {{0x81214e06db096ab8, 0x21a8b6c90ce44f35, 0x6524c12a409e2af5, 0x0165b5a48efca481}}, + {{0xf190a474a0846a76, 0x12eff984cd2f7cc0, 0x695e290658aa2b8f, 0x591b67d9bffec8b8}}}, +{{{0x312f0d1c80b49bfa, 0x5979515eabf3ec8a, 0x727033c09ef01c88, 0x3de02ec7ca8f7bcb}}, + {{0x99b9b3719f18b55d, 0xe465e5faa18c641e, 0x61081136c29f05ed, 0x489b4f867030128b}}, + {{0xd232102d3aeb92ef, 0xe16253b46116a861, 0x3d7eabe7190baa24, 0x49f5fbba496cbebf}}}, +{{{0x30949a108a5bcfd4, 0xdc40dd70bc6473eb, 0x92c294c1307c0d1c, 0x5604a86dcbfa6e74}}, + {{0x155d628c1e9c572e, 0x8a4d86acc5884741, 0x91a352f6515763eb, 0x06a1a6c28867515b}}, + {{0x7288d1d47c1764b6, 0x72541140e0418b51, 0x9f031a6018acf6d1, 0x20989e89fe2742c6}}}, +{{{0x499777fd3a2dcc7f, 0x32857c2ca54fd892, 0xa279d864d207e3a0, 0x0403ed1d0ca67e29}}, + {{0x1674278b85eaec2e, 0x5621dc077acb2bdf, 0x640a4c1661cbf45a, 0x730b9950f70595d3}}, + {{0xc94b2d35874ec552, 0xc5e6c8cf98246f8d, 0xf7cb46fa16c035ce, 0x5bd7454308303dcc}}}, +{{{0x7f9ad19528b24cc2, 0x7f6b54656335c181, 0x66b8b66e4fc07236, 0x133a78007380ad83}}, + {{0x85c4932115e7792a, 0xc64c89a2bdcdddc9, 0x9d1e3da8ada3d762, 0x5bb7db123067f82c}}, + {{0x0961f467c6ca62be, 0x04ec21d6211952ee, 0x182360779bd54770, 0x740dca6d58f0e0d2}}}, +{{{0xdf48ee0752cfce4e, 0xc3fffaf306ec08b7, 0x05710b2ab95459c4, 0x161d25fa963ea38d}}, + {{0x231a8c570478433c, 0xb7b5270ec281439d, 0xdbaa99eae3d9079f, 0x2c03f5256c2b03d9}}, + {{0x790f18757b53a47d, 0x307b0130cf0c5879, 0x31903d77257ef7f9, 0x699468bdbd96bbaf}}}, +{{{0xbd1f2f46f4dafecf, 0x7cef0114a47fd6f7, 0xd31ffdda4a47b37f, 0x525219a473905785}}, + {{0xd8dd3de66aa91948, 0x485064c22fc0d2cc, 0x9b48246634fdea2f, 0x293e1c4e6c4a2e3a}}, + {{0x376e134b925112e1, 0x703778b5dca15da0, 0xb04589af461c3111, 0x5b605c447f032823}}}, +{{{0xb965805920c47c89, 0xe7f0100c923b8fcc, 0x0001256502e2ef77, 0x24a76dcea8aeb3ee}}, + {{0x3be9fec6f0e7f04c, 0x866a579e75e34962, 0x5542ef161e1de61a, 0x2f12fef4cc5abdd5}}, + {{0x0a4522b2dfc0c740, 0x10d06e7f40c9a407, 0xc6cf144178cff668, 0x5e607b2518a43790}}}, +{{{0x58b31d8f6cdf1818, 0x35cfa74fc36258a2, 0xe1b3ff4f66e61d6e, 0x5067acab6ccdd5f7}}, + {{0xa02c431ca596cf14, 0xe3c42d40aed3e400, 0xd24526802e0f26db, 0x201f33139e457068}}, + {{0xfd527f6b08039d51, 0x18b14964017c0006, 0xd5220eb02e25a4a8, 0x397cba8862460375}}}, +{{{0x30c13093f05959b2, 0xe23aa18de9a97976, 0x222fd491721d5e26, 0x2339d320766e6c3a}}, + {{0x7815c3fbc81379e7, 0xa6619420dde12af1, 0xffa9c0f885a8fdd5, 0x771b4022c1e1c252}}, + {{0xd87dd986513a2fa7, 0xf5ac9b71f9d4cf08, 0xd06bc31b1ea283b3, 0x331a189219971a76}}}, +{{{0xf5166f45fb4f80c6, 0x9c36c7de61c775cf, 0xe3d4e81b9041d91c, 0x31167c6b83bdfe21}}, + {{0x26512f3a9d7572af, 0x5bcbe28868074a9e, 0x84edc1c11180f7c4, 0x1ac9619ff649a67b}}, + {{0xf22b3842524b1068, 0x5068343bee9ce987, 0xfc9d71844a6250c8, 0x612436341f08b111}}}, +{{{0xd99d41db874e898d, 0x09fea5f16c07dc20, 0x793d2c67d00f9bbc, 0x46ebe2309e5eff40}}, + {{0x8b6349e31a2d2638, 0x9ddfb7009bd3fd35, 0x7f8bf1b8a3a06ba4, 0x1522aa3178d90445}}, + {{0x2c382f5369614938, 0xdafe409ab72d6d10, 0xe8c83391b646f227, 0x45fe70f50524306c}}}, +{{{0xda4875a6960c0b8c, 0x5b68d076ef0e2f20, 0x07fb51cf3d0b8fd4, 0x428d1623a0e392d4}}, + {{0x62f24920c8951491, 0x05f007c83f630ca2, 0x6fbb45d2f5c9d4b8, 0x16619f6db57a2245}}, + {{0x084f4a4401a308fd, 0xa82219c376a5caac, 0xdeb8de4643d1bc7d, 0x1d81592d60bd38c6}}}, +{{{0x61368756a60dac5f, 0x17e02f6aebabdc57, 0x7f193f2d4cce0f7d, 0x20234a7789ecdcf0}}, + {{0x8765b69f7b85c5e8, 0x6ff0678bd168bab2, 0x3a70e77c1d330f9b, 0x3a5f6d51b0af8e7c}}, + {{0x76d20db67178b252, 0x071c34f9d51ed160, 0xf62a4a20b3e41170, 0x7cd682353cffe366}}}, +{{{0x0be1a45bd887fab6, 0x2a846a32ba403b6e, 0xd9921012e96e6000, 0x2838c8863bdc0943}}, + {{0xa665cd6068acf4f3, 0x42d92d183cd7e3d3, 0x5759389d336025d9, 0x3ef0253b2b2cd8ff}}, + {{0xd16bb0cf4a465030, 0xfa496b4115c577ab, 0x82cfae8af4ab419d, 0x21dcb8a606a82812}}}, +{{{0x5c6004468c9d9fc8, 0x2540096ed42aa3cb, 0x125b4d4c12ee2f9c, 0x0bc3d08194a31dab}}, + {{0x9a8d00fabe7731ba, 0x8203607e629e1889, 0xb2cc023743f3d97f, 0x5d840dbf6c6f678b}}, + {{0x706e380d309fe18b, 0x6eb02da6b9e165c7, 0x57bbba997dae20ab, 0x3a4276232ac196dd}}}, +{{{0x4b42432c8a7084fa, 0x898a19e3dfb9e545, 0xbe9f00219c58e45d, 0x1ff177cea16debd1}}, + {{0x3bf8c172db447ecb, 0x5fcfc41fc6282dbd, 0x80acffc075aa15fe, 0x0770c9e824e1a9f9}}, + {{0xcf61d99a45b5b5fd, 0x860984e91b3a7924, 0xe7300919303e3e89, 0x39f264fd41500b1e}}}, +{{{0xa7ad3417dbe7e29c, 0xbd94376a2b9c139c, 0xa0e91b8e93597ba9, 0x1712d73468889840}}, + {{0xd19b4aabfe097be1, 0xa46dfce1dfe01929, 0xc3c908942ca6f1ff, 0x65c621272c35f14e}}, + {{0xe72b89f8ce3193dd, 0x4d103356a125c0bb, 0x0419a93d2e1cfe83, 0x22f9800ab19ce272}}}, +{{{0x605a368a3e9ef8cb, 0xe3e9c022a5504715, 0x553d48b05f24248f, 0x13f416cd647626e5}}, + {{0x42029fdd9a6efdac, 0xb912cebe34a54941, 0x640f64b987bdf37b, 0x4171a4d38598cab4}}, + {{0xfa2758aa99c94c8c, 0x23006f6fb000b807, 0xfbd291ddadda5392, 0x508214fa574bd1ab}}}, +{{{0xc20269153ed6fe4b, 0xa65a6739511d77c4, 0xcbde26462c14af94, 0x22f960ec6faba74b}}, + {{0x461a15bb53d003d6, 0xb2102888bcf3c965, 0x27c576756c683a5a, 0x3a7758a4c86cb447}}, + {{0x548111f693ae5076, 0x1dae21df1dfd54a6, 0x12248c90f3115e65, 0x5d9fd15f8de7f494}}}, +{{{0x031408d36d63727f, 0x6a379aefd7c7b533, 0xa9e18fc5ccaee24b, 0x332f35914f8fbed3}}, + {{0x3f244d2aeed7521e, 0x8e3a9028432e9615, 0xe164ba772e9c16d4, 0x3bc187fa47eb98d8}}, + {{0x6d470115ea86c20c, 0x998ab7cb6c46d125, 0xd77832b53a660188, 0x450d81ce906fba03}}}, +{{{0x6e7bb6a1a6205275, 0xaa4f21d7413c8e83, 0x6f56d155e88f5cb2, 0x2de25d4ba6345be1}}, + {{0xd074d8961cae743f, 0xf86d18f5ee1c63ed, 0x97bdc55be7f4ed29, 0x4cbad279663ab108}}, + {{0x80d19024a0d71fcd, 0xc525c20afb288af8, 0xb1a3974b5f3a6419, 0x7d7fbcefe2007233}}}, +{{{0xfaef1e6a266b2801, 0x866c68c4d5739f16, 0xf68a2fbc1b03762c, 0x5975435e87b75a8d}}, + {{0xcd7c5dc5f3c29094, 0xc781a29a2a9105ab, 0x80c61d36421c3058, 0x4f9cd196dcd8d4d7}}, + {{0x199297d86a7b3768, 0xd0d058241ad17a63, 0xba029cad5c1c0c17, 0x7ccdd084387a0307}}}, +{{{0xdca6422c6d260417, 0xae153d50948240bd, 0xa9c0c1b4fb68c677, 0x428bd0ed61d0cf53}}, + {{0x9b0c84186760cc93, 0xcdae007a1ab32a99, 0xa88dec86620bda18, 0x3593ca848190ca44}}, + {{0x9213189a5e849aa7, 0xd4d8c33565d8facd, 0x8c52545b53fdbbd1, 0x27398308da2d63e6}}}, +{{{0x42c38d28435ed413, 0xbd50f3603278ccc9, 0xbb07ab1a79da03ef, 0x269597aebe8c3355}}, + {{0xb9a10e4c0a702453, 0x0fa25866d57d1bde, 0xffb9d9b5cd27daf7, 0x572c2945492c33fd}}, + {{0xc77fc745d6cd30be, 0xe4dfe8d3e3baaefb, 0xa22c8830aa5dda0c, 0x7f985498c05bca80}}}, +{{{0x3849ce889f0be117, 0x8005ad1b7b54a288, 0x3da3c39f23fc921c, 0x76c2ec470a31f304}}, + {{0xd35615520fbf6363, 0x08045a45cf4dfba6, 0xeec24fbc873fa0c2, 0x30f2653cd69b12e7}}, + {{0x8a08c938aac10c85, 0x46179b60db276bcb, 0xa920c01e0e6fac70, 0x2f1273f1596473da}}}, +{{{0x4739fc7c8ae01e11, 0xfd5274904a6aab9f, 0x41d98a8287728f2e, 0x5d9e572ad85b69f2}}, + {{0x30488bd755a70bc0, 0x06d6b5a4f1d442e7, 0xead1a69ebc596162, 0x38ac1997edc5f784}}, + {{0x0666b517a751b13b, 0x747d06867e9b858c, 0xacacc011454dde49, 0x22dfcd9cbfe9e69c}}}, +{{{0x8ddbd2e0c30d0cd9, 0xad8e665facbb4333, 0x8f6b258c322a961f, 0x6b2916c05448c1c7}}, + {{0x56ec59b4103be0a1, 0x2ee3baecd259f969, 0x797cb29413f5cd32, 0x0fe9877824cde472}}, + {{0x7edb34d10aba913b, 0x4ea3cd822e6dac0e, 0x66083dff6578f815, 0x4c303f307ff00a17}}}, +{{{0xd30a3bd617b28c85, 0xc5d377b739773bea, 0xc6c6e78c1e6a5cbf, 0x0d61b8f78b2ab7c4}}, + {{0x29fc03580dd94500, 0xecd27aa46fbbec93, 0x130a155fc2e2a7f8, 0x416b151ab706a1d5}}, + {{0x56a8d7efe9c136b0, 0xbd07e5cd58e44b20, 0xafe62fda1b57e0ab, 0x191a2af74277e8d2}}}, +{{{0xce16f74bc53c1431, 0x2b9725ce2072edde, 0xb8b9c36fb5b23ee7, 0x7e2e0e450b5cc908}}, + {{0x9fe62b434f460efb, 0xded303d4a63607d6, 0xf052210eb7a0da24, 0x237e7dbe00545b93}}, + {{0x013575ed6701b430, 0x231094e69f0bfd10, 0x75320f1583e47f22, 0x71afa699b11155e3}}}, +{{{0x65ce6f9b3953b61d, 0xc65839eaafa141e6, 0x0f435ffda9f759fe, 0x021142e9c2b1c28e}}, + {{0xea423c1c473b50d6, 0x51e87a1f3b38ef10, 0x9b84bf5fb2c9be95, 0x00731fbc78f89a1c}}, + {{0xe430c71848f81880, 0xbf960c225ecec119, 0xb6dae0836bba15e3, 0x4c4d6f3347e15808}}}, +{{{0x18f7eccfc17d1fc9, 0x6c75f5a651403c14, 0xdbde712bf7ee0cdf, 0x193fddaaa7e47a22}}, + {{0x2f0cddfc988f1970, 0x6b916227b0b9f51b, 0x6ec7b6c4779176be, 0x38bf9500a88f9fa8}}, + {{0x1fd2c93c37e8876f, 0xa2f61e5a18d1462c, 0x5080f58239241276, 0x6a6fb99ebf0d4969}}}, +{{{0x6a46c1bb560855eb, 0x2416bb38f893f09d, 0xd71d11378f71acc1, 0x75f76914a31896ea}}, + {{0xeeb122b5b6e423c6, 0x939d7010f286ff8e, 0x90a92a831dcf5d8c, 0x136fda9f42c5eb10}}, + {{0xf94cdfb1a305bdd1, 0x0f364b9d9ff82c08, 0x2a87d8a5c3bb588a, 0x022183510be8dcba}}}, +{{{0x4af766385ead2d14, 0xa08ed880ca7c5830, 0x0d13a6e610211e3d, 0x6a071ce17b806c03}}, + {{0x9d5a710143307a7f, 0xb063de9ec47da45f, 0x22bbfe52be927ad3, 0x1387c441fd40426c}}, + {{0xb5d3c3d187978af8, 0x722b5a3d7f0e4413, 0x0d7b4848bb477ca0, 0x3171b26aaf1edc92}}}, +{{{0xa92f319097564ca8, 0xff7bb84c2275e119, 0x4f55fe37a4875150, 0x221fd4873cf0835a}}, + {{0xa60db7d8b28a47d1, 0xa6bf14d61770a4f1, 0xd4a1f89353ddbd58, 0x6c514a63344243e9}}, + {{0x2322204f3a156341, 0xfb73e0e9ba0a032d, 0xfce0dd4c410f030e, 0x48daa596fb924aaa}}}, +{{{0x6eca8e665ca59cc7, 0xa847254b2e38aca0, 0x31afc708d21e17ce, 0x676dd6fccad84af7}}, + {{0x14f61d5dc84c9793, 0x9941f9e3ef418206, 0xcdf5b88f346277ac, 0x58c837fa0e8a79a9}}, + {{0x0cf9688596fc9058, 0x1ddcbbf37b56a01b, 0xdcc2e77d4935d66a, 0x1c4f73f2c6a57f0a}}}, +{{{0x0e7a4fbd305fa0bb, 0x829d4ce054c663ad, 0xf421c3832fe33848, 0x795ac80d1bf64c42}}, + {{0xb36e706efc7c3484, 0x73dfc9b4c3c1cf61, 0xeb1d79c9781cc7e5, 0x70459adb7daf675c}}, + {{0x1b91db4991b42bb3, 0x572696234b02dcca, 0x9fdf9ee51f8c78dc, 0x5fe162848ce21fd3}}}, +{{{0x4e59214fe194961a, 0x49be7dc70d71cd4f, 0x9300cfd23b50f22d, 0x4789d446fc917232}}, + {{0x2879852d5d7cb208, 0xb8dedd70687df2e7, 0xdc0bffab21687891, 0x2b44c043677daa35}}, + {{0x1a1c87ab074eb78e, 0xfac6d18e99daf467, 0x3eacbbcd484f9067, 0x60c52eef2bb9a4e4}}}, +{{{0x0b5d89bc3bfd8bf1, 0xb06b9237c9f3551a, 0x0e4c16b0d53028f5, 0x10bc9c312ccfcaab}}, + {{0x702bc5c27cae6d11, 0x44c7699b54a48cab, 0xefbc4056ba492eb2, 0x70d77248d9b6676d}}, + {{0xaa8ae84b3ec2a05b, 0x98699ef4ed1781e0, 0x794513e4708e85d1, 0x63755bd3a976f413}}}, +{{{0xb55fa03e2ad10853, 0x356f75909ee63569, 0x9ff9f1fdbe69b890, 0x0d8cc1c48bc16f84}}, + {{0x3dc7101897f1acb7, 0x5dda7d5ec165bbd8, 0x508e5b9c0fa1020f, 0x2763751737c52a56}}, + {{0x029402d36eb419a9, 0xf0b44e7e77b460a5, 0xcfa86230d43c4956, 0x70c2dd8a7ad166e7}}}, +{{{0x656194509f6fec0e, 0xee2e7ea946c6518d, 0x9733c1f367e09b5c, 0x2e0fac6363948495}}, + {{0x91d4967db8ed7e13, 0x74252f0ad776817a, 0xe40982e00d852564, 0x32b8613816a53ce5}}, + {{0x79e7f7bee448cd64, 0x6ac83a67087886d0, 0xf89fd4d9a0e4db2e, 0x4179215c735a4f41}}}, +{{{0x8c7094e7d7dced2a, 0x97fb8ac347d39c70, 0xe13be033a906d902, 0x700344a30cd99d76}}, + {{0xe4ae33b9286bcd34, 0xb7ef7eb6559dd6dc, 0x278b141fb3d38e1f, 0x31fa85662241c286}}, + {{0xaf826c422e3622f4, 0xc12029879833502d, 0x9bc1b7e12b389123, 0x24bb2312a9952489}}}, +{{{0xb1a8ed1732de67c3, 0x3cb49418461b4948, 0x8ebd434376cfbcd2, 0x0fee3e871e188008}}, + {{0x41f80c2af5f85c6b, 0x687284c304fa6794, 0x8945df99a3ba1bad, 0x0d1d2af9ffeb5d16}}, + {{0xa9da8aa132621edf, 0x30b822a159226579, 0x4004197ba79ac193, 0x16acd79718531d76}}}, +{{{0x72df72af2d9b1d3d, 0x63462a36a432245a, 0x3ecea07916b39637, 0x123e0ef6b9302309}}, + {{0xc959c6c57887b6ad, 0x94e19ead5f90feba, 0x16e24e62a342f504, 0x164ed34b18161700}}, + {{0x487ed94c192fe69a, 0x61ae2cea3a911513, 0x877bf6d3b9a4de27, 0x78da0fc61073f3eb}}}, +{{{0x5bf15d28e52bc66a, 0x2c47e31870f01a8e, 0x2419afbc06c28bdd, 0x2d25deeb256b173a}}, + {{0xa29f80f1680c3a94, 0x71f77e151ae9e7e6, 0x1100f15848017973, 0x054aa4b316b38ddd}}, + {{0xdfc8468d19267cb8, 0x0b28789c66e54daf, 0x2aeb1d2a666eec17, 0x134610a6ab7da760}}}, +{{{0x51138ec78df6b0fe, 0x5397da89e575f51b, 0x09207a1d717af1b9, 0x2102fdba2b20d650}}, + {{0xcd2a65e777d1f515, 0x548991878faa60f1, 0xb1b73bbcdabc06e5, 0x654878cba97cc9fb}}, + {{0x969ee405055ce6a1, 0x36bca7681251ad29, 0x3a1af517aa7da415, 0x0ad725db29ecb2ba}}}, +{{{0xdc4267b1834e2457, 0xb67544b570ce1bc5, 0x1af07a0bf7d15ed7, 0x4aefcffb71a03650}}, + {{0xfec7bc0c9b056f85, 0x537d5268e7f5ffd7, 0x77afc6624312aefa, 0x4f675f5302399fd9}}, + {{0xc32d36360415171e, 0xcd2bef118998483b, 0x870a6eadd0945110, 0x0bccbb72a2a86561}}}, +{{{0x185e962feab1a9c8, 0x86e7e63565147dcd, 0xb092e031bb5b6df2, 0x4024f0ab59d6b73e}}, + {{0x186d5e4c50fe1296, 0xe0397b82fee89f7e, 0x3bc7f6c5507031b0, 0x6678fd69108f37c2}}, + {{0x1586fa31636863c2, 0x07f68c48572d33f2, 0x4f73cc9f789eaefc, 0x2d42e2108ead4701}}}, +{{{0x97f5131594dfd29b, 0x6155985d313f4c6a, 0xeba13f0708455010, 0x676b2608b8d2d322}}, + {{0x21717b0d0f537593, 0x914e690b131e064c, 0x1bb687ae752ae09f, 0x420bf3a79b423c6e}}, + {{0x8138ba651c5b2b47, 0x8671b6ec311b1b80, 0x7bff0cb1bc3135b0, 0x745d2ffa9c0cf1e0}}}, +{{{0xbf525a1e2bc9c8bd, 0xea5b260826479d81, 0xd511c70edf0155db, 0x1ae23ceb960cf5d0}}, + {{0x6036df5721d34e6a, 0xb1db8827997bb3d0, 0xd3c209c3c8756afa, 0x06e15be54c1dc839}}, + {{0x5b725d871932994a, 0x32351cb5ceb1dab0, 0x7dc41549dab7ca05, 0x58ded861278ec1f7}}}, +{{{0xd8173793f266c55c, 0xc8c976c5cc454e49, 0x5ce382f8bc26c3a8, 0x2ff39de85485f6f9}}, + {{0x2dfb5ba8b6c2c9a8, 0x48eeef8ef52c598c, 0x33809107f12d1573, 0x08ba696b531d5bd8}}, + {{0x77ed3eeec3efc57a, 0x04e05517d4ff4811, 0xea3d7a3ff1a671cb, 0x120633b4947cfe54}}}, +{{{0x0b94987891610042, 0x4ee7b13cecebfae8, 0x70be739594f0a4c0, 0x35d30a99b4d59185}}, + {{0x82bd31474912100a, 0xde237b6d7e6fbe06, 0xe11e761911ea79c6, 0x07433be3cb393bde}}, + {{0xff7944c05ce997f4, 0x575d3de4b05c51a3, 0x583381fd5a76847c, 0x2d873ede7af6da9f}}}, +{{{0x157a316443373409, 0xfab8b7eef4aa81d9, 0xb093fee6f5a64806, 0x2e773654707fa7b6}}, + {{0xaa6202e14e5df981, 0xa20d59175015e1f5, 0x18a275d3bae21d6c, 0x0543618a01600253}}, + {{0x0deabdf4974c23c1, 0xaa6f0a259dce4693, 0x04202cb8a29aba2c, 0x4b1443362d07960d}}}, +{{{0xccc4b7c7b66e1f7a, 0x44157e25f50c2f7e, 0x3ef06dfc713eaf1c, 0x582f446752da63f7}}, + {{0x967c54e91c529ccb, 0x30f6269264c635fb, 0x2747aff478121965, 0x17038418eaf66f5c}}, + {{0xc6317bd320324ce4, 0xa81042e8a4488bc4, 0xb21ef18b4e5a1364, 0x0c2a1c4bcda28dc9}}}, +{{{0xd24dc7d06f1f0447, 0xb2269e3edb87c059, 0xd15b0272fbb2d28f, 0x7c558bd1c6f64877}}, + {{0xedc4814869bd6945, 0x0d6d907dbe1c8d22, 0xc63bd212d55cc5ab, 0x5a6a9b30a314dc83}}, + {{0xd0ec1524d396463d, 0x12bb628ac35a24f0, 0xa50c3a791cbc5fa4, 0x0404a5ca0afbafc3}}}, +{{{0x8c1f40070aa743d6, 0xccbad0cb5b265ee8, 0x574b046b668fd2de, 0x46395bfdcadd9633}}, + {{0x62bc9e1b2a416fd1, 0xb5c6f728e350598b, 0x04343fd83d5d6967, 0x39527516e7f8ee98}}, + {{0x117fdb2d1a5d9a9c, 0x9c7745bcd1005c2a, 0xefd4bef154d56fea, 0x76579a29e822d016}}}, +{{{0x45b68e7e49c02a17, 0x23cd51a2bca9a37f, 0x3ed65f11ec224c1b, 0x43a384dc9e05bdb1}}, + {{0x333cb51352b434f2, 0xd832284993de80e1, 0xb5512887750d35ce, 0x02c514bb2a2777c1}}, + {{0x684bd5da8bf1b645, 0xfb8bd37ef6b54b53, 0x313916d7a9b0d253, 0x1160920961548059}}}, +{{{0xb44d166929dacfaa, 0xda529f4c8413598f, 0xe9ef63ca453d5559, 0x351e125bc5698e0b}}, + {{0x7a385616369b4dcd, 0x75c02ca7655c3563, 0x7dc21bf9d4f18021, 0x2f637d7491e6e042}}, + {{0xd4b49b461af67bbe, 0xd603037ac8ab8961, 0x71dee19ff9a699fb, 0x7f182d06e7ce2a9a}}}, +{{{0x7a7c8e64ab0168ec, 0xcb5a4a5515edc543, 0x095519d347cd0eda, 0x67d4ac8c343e93b0}}, + {{0x09454b728e217522, 0xaa58e8f4d484b8d8, 0xd358254d7f46903c, 0x44acc043241c5217}}, + {{0x1c7d6bbb4f7a5777, 0x8b35fed4918313e1, 0x4adca1c6c96b4684, 0x556d1c8312ad71bd}}}, +{{{0x17ef40e30c8d3982, 0x31f7073e15a3fa34, 0x4f21f3cb0773646e, 0x746c6c6d1d824eff}}, + {{0x81f06756b11be821, 0x0faff82310a3f3dd, 0xf8b2d0556a99465d, 0x097abe38cc8c7f05}}, + {{0x0c49c9877ea52da4, 0x4c4369559bdc1d43, 0x022c3809f7ccebd2, 0x577e14a34bee84bd}}}, +{{{0xf0e268ac61a73b0a, 0xf2fafa103791a5f5, 0xc1e13e826b6d00e9, 0x60fa7ee96fd78f42}}, + {{0x94fecebebd4dd72b, 0xf46a4fda060f2211, 0x124a5977c0c8d1ff, 0x705304b8fb009295}}, + {{0xb63d1d354d296ec6, 0xf3c3053e5fad31d8, 0x670b958cb4bd42ec, 0x21398e0ca16353fd}}}, +{{{0x89f5058a382b33f3, 0x5ae2ba0bad48c0b4, 0x8f93b503a53db36e, 0x5aa3ed9d95a232e6}}, + {{0x2798aaf9b4b75601, 0x5eac72135c8dad72, 0xd2ceaa6161b7a023, 0x1bbfb284e98f7d4e}}, + {{0x656777e9c7d96561, 0xcb2b125472c78036, 0x65053299d9506eee, 0x4a07e14e5e8957cc}}}, +{{{0x4ee412cb980df999, 0xa315d76f3c6ec771, 0xbba5edde925c77fd, 0x3f0bac391d313402}}, + {{0x240b58cdc477a49b, 0xfd38dade6447f017, 0x19928d32a7c86aad, 0x50af7aed84afa081}}, + {{0x6e4fde0115f65be5, 0x29982621216109b2, 0x780205810badd6d9, 0x1921a316baebd006}}}, +{{{0x89422f7edfb870fc, 0x2c296beb4f76b3bd, 0x0738f1d436c24df7, 0x6458df41e273aeb0}}, + {{0xd75aad9ad9f3c18b, 0x566a0eef60b1c19c, 0x3e9a0bac255c0ed9, 0x7b049deca062c7f5}}, + {{0xdccbe37a35444483, 0x758879330fedbe93, 0x786004c312c5dd87, 0x6093dccbc2950e64}}}, +{{{0x1ff39a8585e0706d, 0x36d0a5d8b3e73933, 0x43b9f2e1718f453b, 0x57d1ea084827a97c}}, + {{0x6bdeeebe6084034b, 0x3199c2b6780fb854, 0x973376abb62d0695, 0x6e3180c98b647d90}}, + {{0xee7ab6e7a128b071, 0xa4c1596d93a88baa, 0xf7b4de82b2216130, 0x363e999ddd97bd18}}}, +{{{0x96a843c135ee1fc4, 0x976eb35508e4c8cf, 0xb42f6801b58cd330, 0x48ee9b78693a052b}}, + {{0x2f1848dce24baec6, 0x769b7255babcaf60, 0x90cb3c6e3cefe931, 0x231f979bc6f9b355}}, + {{0x5c31de4bcc2af3c6, 0xb04bb030fe208d1f, 0xb78d7009c14fb466, 0x079bfa9b08792413}}}, +{{{0xe3903a51da300df4, 0x843964233da95ab0, 0xed3cf12d0b356480, 0x038c77f684817194}}, + {{0xf3c9ed80a2d54245, 0x0aa08b7877f63952, 0xd76dac63d1085475, 0x1ef4fb159470636b}}, + {{0x854e5ee65b167bec, 0x59590a4296d0cdc2, 0x72b2df3498102199, 0x575ee92a4a0bff56}}}, +{{{0xd4c080908a182fcf, 0x30e170c299489dbd, 0x05babd5752f733de, 0x43d4e7112cd3fd00}}, + {{0x5d46bc450aa4d801, 0xc3af1227a533b9d8, 0x389e3b262b8906c2, 0x200a1e7e382f581b}}, + {{0x518db967eaf93ac5, 0x71bc989b056652c0, 0xfe2b85d9567197f5, 0x050eca52651e4e38}}}, +{{{0xc3431ade453f0c9c, 0xe9f5045eff703b9b, 0xfcd97ac9ed847b3d, 0x4b0ee6c21c58f4c6}}, + {{0x97ac397660e668ea, 0x9b19bbfe153ab497, 0x4cb179b534eca79f, 0x6151c09fa131ae57}}, + {{0x3af55c0dfdf05d96, 0xdd262ee02ab4ee7a, 0x11b2bb8712171709, 0x1fef24fa800f030b}}}, +{{{0x37d653fb1aa73196, 0x0f9495303fd76418, 0xad200b09fb3a17b2, 0x544d49292fc8613e}}, + {{0x22d2aff530976b86, 0x8d90b806c2d24604, 0xdca1896c4de5bae5, 0x28005fe6c8340c17}}, + {{0x6aefba9f34528688, 0x5c1bff9425107da1, 0xf75bbbcd66d94b36, 0x72e472930f316dfa}}}, +{{{0x2695208c9781084f, 0xb1502a0b23450ee1, 0xfd9daea603efde02, 0x5a9d2e8c2733a34c}}, + {{0x07f3f635d32a7627, 0x7aaa4d865f6566f0, 0x3c85e79728d04450, 0x1fee7f000fe06438}}, + {{0x765305da03dbf7e5, 0xa4daf2491434cdbd, 0x7b4ad5cdd24a88ec, 0x00f94051ee040543}}}, +{{{0x8d356b23c3d330b2, 0xf21c8b9bb0471b06, 0xb36c316c6e42b83c, 0x07d79c7e8beab10d}}, + {{0xd7ef93bb07af9753, 0x583ed0cf3db766a7, 0xce6998bf6e0b1ec5, 0x47b7ffd25dd40452}}, + {{0x87fbfb9cbc08dd12, 0x8a066b3ae1eec29b, 0x0d57242bdb1fc1bf, 0x1c3520a35ea64bb6}}}, +{{{0x80d253a6bccba34a, 0x3e61c3a13838219b, 0x90c3b6019882e396, 0x1c3d05775d0ee66f}}, + {{0xcda86f40216bc059, 0x1fbb231d12bcd87e, 0xb4956a9e17c70990, 0x38750c3b66d12e55}}, + {{0x692ef1409422e51a, 0xcbc0c73c2b5df671, 0x21014fe7744ce029, 0x0621e2c7d330487c}}}, +{{{0xaf9860cc8259838d, 0x90ea48c1c69f9adc, 0x6526483765581e30, 0x0007d6097bd3a5bc}}, + {{0xb7ae1796b0dbf0f3, 0x54dfafb9e17ce196, 0x25923071e9aaa3b4, 0x5d8e589ca1002e9d}}, + {{0xc0bf1d950842a94b, 0xb2d3c363588f2e3e, 0x0a961438bb51e2ef, 0x1583d7783c1cbf86}}}, +{{{0xeceea2ef5da27ae1, 0x597c3a1455670174, 0xc9a62a126609167a, 0x252a5f2e81ed8f70}}, + {{0x90034704cc9d28c7, 0x1d1b679ef72cc58f, 0x16e12b5fbe5b8726, 0x4958064e83c5580a}}, + {{0x0d2894265066e80d, 0xfcc3f785307c8c6b, 0x1b53da780c1112fd, 0x079c170bd843b388}}}, +{{{0x0506ece464fa6fff, 0xbee3431e6205e523, 0x3579422451b8ea42, 0x6dec05e34ac9fb00}}, + {{0xcdd6cd50c0d5d056, 0x9af7686dbb03573b, 0x3ca6723ff3c3ef48, 0x6768c0d7317b8acc}}, + {{0x94b625e5f155c1b3, 0x417bf3a7997b7b91, 0xc22cbddc6d6b2600, 0x51445e14ddcd52f4}}}, +{{{0x57502b4b3b144951, 0x8e67ff6b444bbcb3, 0xb8bd6927166385db, 0x13186f31e39295c8}}, + {{0x893147ab2bbea455, 0x8c53a24f92079129, 0x4b49f948be30f7a7, 0x12e990086e4fd43d}}, + {{0xf10c96b37fdfbb2e, 0x9f9a935e121ceaf9, 0xdf1136c43a5b983f, 0x77b2e3f05d3e99af}}}, +{{{0x296fa9c59c2ec4de, 0xbc8b61bf4f84f3cb, 0x1c7706d917a8f908, 0x63b795fc7ad3255d}}, + {{0xd598639c12ddb0a4, 0xa5d19f30c024866b, 0xd17c2f0358fce460, 0x07a195152e095e8a}}, + {{0xa8368f02389e5fc8, 0x90433b02cf8de43b, 0xafa1fd5dc5412643, 0x3e8fe83d032f0137}}}, +{{{0x2f8b15b90570a294, 0x94f2427067084549, 0xde1c5ae161bbfd84, 0x75ba3b797fac4007}}, + {{0x08704c8de8efd13c, 0xdfc51a8e33e03731, 0xa59d5da51260cde3, 0x22d60899a6258c86}}, + {{0x6239dbc070cdd196, 0x60fe8a8b6c7d8a9a, 0xb38847bceb401260, 0x0904d07b87779e5e}}}, +{{{0xb4ce1fd4ddba919c, 0xcf31db3ec74c8daa, 0x2c63cc63ad86cc51, 0x43e2143fbc1dde07}}, + {{0xf4322d6648f940b9, 0x06952f0cbd2d0c39, 0x167697ada081f931, 0x6240aacebaf72a6c}}, + {{0xf834749c5ba295a0, 0xd6947c5bca37d25a, 0x66f13ba7e7c9316a, 0x56bdaf238db40cac}}}, +{{{0x362ab9e3f53533eb, 0x338568d56eb93d40, 0x9e0e14521d5a5572, 0x1d24a86d83741318}}, + {{0x1310d36cc19d3bb2, 0x062a6bb7622386b9, 0x7c9b8591d7a14f5c, 0x03aa31507e1e5754}}, + {{0xf4ec7648ffd4ce1f, 0xe045eaf054ac8c1c, 0x88d225821d09357c, 0x43b261dc9aeb4859}}}, +{{{0xe55b1e1988bb79bb, 0xa09ed07dc17a359d, 0xb02c2ee2603dea33, 0x326055cf5b276bc2}}, + {{0x19513d8b6c951364, 0x94fe7126000bf47b, 0x028d10ddd54f9567, 0x02b4d5e242940964}}, + {{0xb4a155cb28d18df2, 0xeacc4646186ce508, 0xc49cf4936c824389, 0x27a6c809ae5d3410}}}, +{{{0x8ba6ebcd1f0db188, 0x37d3d73a675a5be8, 0xf22edfa315f5585a, 0x2cb67174ff60a17e}}, + {{0xcd2c270ac43d6954, 0xdd4a3e576a66cab2, 0x79fa592469d7036c, 0x221503603d8c2599}}, + {{0x59eecdf9390be1d0, 0xa9422044728ce3f1, 0x82891c667a94f0f4, 0x7b1df4b73890f436}}}, +{{{0xe492f2e0b3b2a224, 0x7c6c9e062b551160, 0x15eb8fe20d7f7b0e, 0x61fcef2658fc5992}}, + {{0x5f2e221807f8f58c, 0xe3555c9fd49409d4, 0xb2aaa88d1fb6a630, 0x68698245d352e03d}}, + {{0xdbb15d852a18187a, 0xf3e4aad386ddacd7, 0x44bae2810ff6c482, 0x46cf4c473daf01cf}}}, +{{{0x426525ed9ec4e5f9, 0x0e5eda0116903303, 0x72b1a7f2cbe5cadc, 0x29387bcd14eb5f40}}, + {{0x213c6ea7f1498140, 0x7c1e7ef8392b4854, 0x2488c38c5629ceba, 0x1065aae50d8cc5bb}}, + {{0x1c2c4525df200d57, 0x5c3b2dd6bfca674a, 0x0a07e7b1e1834030, 0x69a198e64f1ce716}}}, +{{{0x9062b2e0d91a78bc, 0x47c9889cc8509667, 0x9df54a66405070b8, 0x7369e6a92493a1bf}}, + {{0xe1014434dcc5caed, 0x47ed5d963c84fb33, 0x70019576ed86a0e7, 0x25b2697bd267f9e4}}, + {{0x9d673ffb13986864, 0x3ca5fbd9415dc7b8, 0xe04ecc3bdf273b5e, 0x1420683db54e4cd2}}}, +{{{0xb478bd1e249dd197, 0x620c35005e58c102, 0xfb02d32fccbaac5c, 0x60b63bebf508a72d}}, + {{0x34eebb6fc1cc5ad0, 0x6a1b0ce99646ac8b, 0xd3b0da49a66bde53, 0x31e83b4161d081c1}}, + {{0x97e8c7129e062b4f, 0x49e48f4f29320ad8, 0x5bece14b6f18683f, 0x55cf1eb62d550317}}}, +{{{0x5879101065c23d58, 0x8b9d086d5094819c, 0xe2402fa912c55fa7, 0x669a6564570891d4}}, + {{0x3076b5e37df58c52, 0xd73ab9dde799cc36, 0xbd831ce34913ee20, 0x1a56fbaa62ba0133}}, + {{0x943e6b505c9dc9ec, 0x302557bba77c371a, 0x9873ae5641347651, 0x13c4836799c58a5c}}}, +{{{0x423a5d465ab3e1b9, 0xfc13c187c7f13f61, 0x19f83664ecb5b9b6, 0x66f80c93a637b607}}, + {{0xc4dcfb6a5d8bd080, 0xdeebc4ec571a4842, 0xd4b2e883b8e55365, 0x50bdc87dc8e5b827}}, + {{0x606d37836edfe111, 0x32353e15f011abd9, 0x64b03ac325b73b96, 0x1dd56444725fd5ae}}}, +{{{0x8fa47ff83362127d, 0xbc9f6ac471cd7c15, 0x6e71454349220c8b, 0x0e645912219f732e}}, + {{0xc297e60008bac89a, 0x7d4cea11eae1c3e0, 0xf3e38be19fe7977c, 0x3a3a450f63a305cd}}, + {{0x078f2f31d8394627, 0x389d3183de94a510, 0xd1e36c6d17996f80, 0x318c8d9393a9a87b}}}, +{{{0xf2745d032afffe19, 0x0c9f3c497f24db66, 0xbc98d3e3ba8598ef, 0x224c7c679a1d5314}}, + {{0x5d669e29ab1dd398, 0xfc921658342d9e3b, 0x55851dfdf35973cd, 0x509a41c325950af6}}, + {{0xbdc06edca6f925e9, 0x793ef3f4641b1f33, 0x82ec12809d833e89, 0x05bff02328a11389}}}, +{{{0x3632137023cae00b, 0x544acf0ad1accf59, 0x96741049d21a1c88, 0x780b8cc3fa2a44a7}}, + {{0x6881a0dd0dc512e4, 0x4fe70dc844a5fafe, 0x1f748e6b8f4a5240, 0x576277cdee01a3ea}}, + {{0x1ef38abc234f305f, 0x9a577fbd1405de08, 0x5e82a51434e62a0d, 0x5ff418726271b7a1}}}, +{{{0x398e080c1789db9d, 0xa7602025f3e778f5, 0xfa98894c06bd035d, 0x106a03dc25a966be}}, + {{0xe5db47e813b69540, 0xf35d2a3b432610e1, 0xac1f26e938781276, 0x29d4db8ca0a0cb69}}, + {{0xd9ad0aaf333353d0, 0x38669da5acd309e5, 0x3c57658ac888f7f0, 0x4ab38a51052cbefa}}}, +{{{0xda7c2b256768d593, 0x98c1c0574422ca13, 0xf1a80bd5ca0ace1d, 0x29cdd1adc088a690}}, + {{0xd6cfd1ef5fddc09c, 0xe82b3efdf7575dce, 0x25d56b5d201634c2, 0x3041c6bb04ed2b9b}}, + {{0x0ff2f2f9d956e148, 0xade797759f356b2e, 0x1a4698bb5f6c025c, 0x104bbd6814049a7b}}}, +{{{0x51f0fd3168f1ed67, 0x2c811dcdd86f3bc2, 0x44dc5c4304d2f2de, 0x5be8cc57092a7149}}, + {{0xa95d9a5fd67ff163, 0xe92be69d4cc75681, 0xb7f8024cde20f257, 0x204f2a20fb072df5}}, + {{0xc8143b3d30ebb079, 0x7589155abd652e30, 0x653c3c318f6d5c31, 0x2570fb17c279161f}}}, +{{{0x3efa367f2cb61575, 0xf5f96f761cd6026c, 0xe8c7142a65b52562, 0x3dcb65ea53030acd}}, + {{0x192ea9550bb8245a, 0xc8e6fba88f9050d1, 0x7986ea2d88a4c935, 0x241c5f91de018668}}, + {{0x28d8172940de6caa, 0x8fbf2cf022d9733a, 0x16d7fcdd235b01d1, 0x08420edd5fcdf0e5}}}, +{{{0xcdff20ab8362fa4a, 0x57e118d4e21a3e6e, 0xe3179617fc39e62b, 0x0d9a53efbc1769fd}}, + {{0x0358c34e04f410ce, 0xb6135b5a276e0685, 0x5d9670c7ebb91521, 0x04d654f321db889c}}, + {{0x5e7dc116ddbdb5d5, 0x2954deb68da5dd2d, 0x1cb608173334a292, 0x4a7a4f2618991ad7}}}, +{{{0xf4a718025fb15f95, 0x3df65f346b5c1b8f, 0xcdfcf08500e01112, 0x11b50c4cddd31848}}, + {{0x24c3b291af372a4b, 0x93da8270718147f2, 0xdd84856486899ef2, 0x4a96314223e0ee33}}, + {{0xa6e8274408a4ffd6, 0x738e177e9c1576d9, 0x773348b63d02b3f2, 0x4f4bce4dce6bcc51}}}, +{{{0xa71fce5ae2242584, 0x26ea725692f58a9e, 0xd21a09d71cea3cf4, 0x73fcdd14b71c01e6}}, + {{0x30e2616ec49d0b6f, 0xe456718fcaec2317, 0x48eb409bf26b4fa6, 0x3042cee561595f37}}, + {{0x427e7079449bac41, 0x855ae36dbce2310a, 0x4cae76215f841a7c, 0x389e740c9a9ce1d6}}}, +{{{0x64fcb3ae34dcb9ce, 0x97500323e348d0ad, 0x45b3f07d62c6381b, 0x61545379465a6788}}, + {{0xc9bd78f6570eac28, 0xe55b0b3227919ce1, 0x65fc3eaba19b91ed, 0x25c425e5d6263690}}, + {{0x3f3e06a6f1d7de6e, 0x3ef976278e062308, 0x8c14f6264e8a6c77, 0x6539a08915484759}}}, +{{{0xe9d21f74c3d2f773, 0xc150544125c46845, 0x624e5ce8f9b99e33, 0x11c5e4aac5cd186c}}, + {{0xddc4dbd414bb4a19, 0x19b2bc3c98424f8e, 0x48a89fd736ca7169, 0x0f65320ef019bd90}}, + {{0xd486d1b1cafde0c6, 0x4f3fe6e3163b5181, 0x59a8af0dfaf2939a, 0x4cabc7bdec33072a}}}, +{{{0x239e9624089c0a2e, 0xc748c4c03afe4738, 0x17dbed2a764fa12a, 0x639b93f0321c8582}}, + {{0xc08f788f3f78d289, 0xfe30a72ca1404d9f, 0xf2778bfccf65cc9d, 0x7ee498165acb2021}}, + {{0x7bd508e39111a1c3, 0x2b2b90d480907489, 0xe7d2aec2ae72fd19, 0x0edf493c85b602a6}}}, +{{{0xaecc8158599b5a68, 0xea574f0febade20e, 0x4fe41d7422b67f07, 0x403b92e3019d4fb4}}, + {{0x6767c4d284764113, 0xa090403ff7f5f835, 0x1c8fcffacae6bede, 0x04c00c54d1dfa369}}, + {{0x4dc22f818b465cf8, 0x71a0f35a1480eff8, 0xaee8bfad04c7d657, 0x355bb12ab26176f4}}}, +{{{0xa71e64cc7493bbf4, 0xe5bd84d9eca3b0c3, 0x0a6bc50cfa05e785, 0x0f9b8132182ec312}}, + {{0xa301dac75a8c7318, 0xed90039db3ceaa11, 0x6f077cbf3bae3f2d, 0x7518eaf8e052ad8e}}, + {{0xa48859c41b7f6c32, 0x0f2d60bcf4383298, 0x1815a929c9b1d1d9, 0x47c3871bbb1755c4}}}, +{{{0x5144539771ec4f48, 0xf805b17dc98c5d6e, 0xf762c11a47c3c66b, 0x00b89b85764699dc}}, + {{0xfbe65d50c85066b0, 0x62ecc4b0b3a299b0, 0xe53754ea441ae8e0, 0x08fea02ce8d48d5f}}, + {{0x824ddd7668deead0, 0xc86445204b685d23, 0xb514cfcd5d89d665, 0x473829a74f75d537}}}, +{{{0x82d2da754679c418, 0xe63bd7d8b2618df0, 0x355eef24ac47eb0a, 0x2078684c4833c6b4}}, + {{0x23d9533aad3902c9, 0x64c2ddceef03588f, 0x15257390cfe12fb4, 0x6c668b4d44e4d390}}, + {{0x3b48cf217a78820c, 0xf76a0ab281273e97, 0xa96c65a78c8eed7b, 0x7411a6054f8a433f}}}, +{{{0x4d659d32b99dc86d, 0x044cdc75603af115, 0xb34c712cdcc2e488, 0x7c136574fb8134ff}}, + {{0x579ae53d18b175b4, 0x68713159f392a102, 0x8455ecba1eef35f5, 0x1ec9a872458c398f}}, + {{0xb8e6a4d400a2509b, 0x9b81d7020bc882b4, 0x57e7cc9bf1957561, 0x3add88a5c7cd6460}}}, +{{{0xab895770b635dcf2, 0x02dfef6cf66c1fbc, 0x85530268beb6d187, 0x249929fccc879e74}}, + {{0x85c298d459393046, 0x8f7e35985ff659ec, 0x1d2ca22af2f66e3a, 0x61ba1131a406a720}}, + {{0xa3d0a0f116959029, 0x023b6b6cba7ebd89, 0x7bf15a3e26783307, 0x5620310cbbd8ece7}}}, +{{{0x528993434934d643, 0xb9dbf806a51222f5, 0x8f6d878fc3f41c22, 0x37676a2a4d9d9730}}, + {{0x6646b5f477e285d6, 0x40e8ff676c8f6193, 0xa6ec7311abb594dd, 0x7ec846f3658cec4d}}, + {{0x9b5e8f3f1da22ec7, 0x130f1d776c01cd13, 0x214c8fcfa2989fb8, 0x6daaf723399b9dd5}}}, +{{{0x5f3a7562eb3dbe47, 0xf7ea38548ebda0b8, 0x00c3e53145747299, 0x1304e9e71627d551}}, + {{0x583b04bfacad8ea2, 0x29b743e8148be884, 0x2b1e583b0810c5db, 0x2b5449e58eb3bbaa}}, + {{0x789814d26adc9cfe, 0x3c1bab3f8b48dd0b, 0xda0fe1fff979c60a, 0x4468de2d7c2dd693}}}, +{{{0x51bb355e9419469e, 0x33e6dc4c23ddc754, 0x93a5b6d6447f9962, 0x6cce7c6ffb44bd63}}, + {{0x4b9ad8c6f86307ce, 0x21113531435d0c28, 0xd4a866c5657a772c, 0x5da6427e63247352}}, + {{0x1a94c688deac22ca, 0xb9066ef7bbae1ff8, 0x88ad8c388d59580f, 0x58f29abfe79f2ca8}}}, +{{{0xe90ecfab8de73e68, 0x54036f9f377e76a5, 0xf0495b0bbe015982, 0x577629c4a7f41e36}}, + {{0x4b5a64bf710ecdf6, 0xb14ce538462c293c, 0x3643d056d50b3ab9, 0x6af93724185b4870}}, + {{0x3220024509c6a888, 0xd2e036134b558973, 0x83e236233c33289f, 0x701f25bb0caec18f}}}, +{{{0xc3a8b0f8e4616ced, 0xf700660e9e25a87d, 0x61e3061ff4bca59c, 0x2e0c92bfbdc40be9}}, + {{0x9d18f6d97cbec113, 0x844a06e674bfdbe4, 0x20f5b522ac4e60d6, 0x720a5bc050955e51}}, + {{0x0c3f09439b805a35, 0xe84e8b376242abfc, 0x691417f35c229346, 0x0e9b9cbb144ef0ec}}}, +{{{0xfbbad48ffb5720ad, 0xee81916bdbf90d0e, 0xd4813152635543bf, 0x221104eb3f337bd8}}, + {{0x8dee9bd55db1beee, 0xc9c3ab370a723fb9, 0x44a8f1bf1c68d791, 0x366d44191cfd3cde}}, + {{0x9e3c1743f2bc8c14, 0x2eda26fcb5856c3b, 0xccb82f0e68a7fb97, 0x4167a4e6bc593244}}}, +{{{0x643b9d2876f62700, 0x5d1d9d400e7668eb, 0x1b4b430321fc0684, 0x7938bb7e2255246a}}, + {{0xc2be2665f8ce8fee, 0xe967ff14e880d62c, 0xf12e6e7e2f364eee, 0x34b33370cb7ed2f6}}, + {{0xcdc591ee8681d6cc, 0xce02109ced85a753, 0xed7485c158808883, 0x1176fc6e2dfe65e4}}}, +{{{0xb4af6cd05b9c619b, 0x2ddfc9f4b2a58480, 0x3d4fa502ebe94dc4, 0x08fc3a4c677d5f34}}, + {{0xdb90e28949770eb8, 0x98fbcc2aacf440a3, 0x21354ffeded7879b, 0x1f6a3e54f26906b6}}, + {{0x60a4c199d30734ea, 0x40c085b631165cd6, 0xe2333e23f7598295, 0x4f2fad0116b900d1}}}, +{{{0x44beb24194ae4e54, 0x5f541c511857ef6c, 0xa61e6b2d368d0498, 0x445484a4972ef7ab}}, + {{0x962cd91db73bb638, 0xe60577aafc129c08, 0x6f619b39f3b61689, 0x3451995f2944ee81}}, + {{0x9152fcd09fea7d7c, 0x4a816c94b0935cf6, 0x258e9aaa47285c40, 0x10b89ca6042893b7}}}, +{{{0x3d5947499718289c, 0x12ebf8c524533f26, 0x0262bfcb14c3ef15, 0x20b878d577b7518e}}, + {{0x753941be5a45f06e, 0xd07caeed6d9c5f65, 0x11776b9c72ff51b6, 0x17d2d1d9ef0d4da9}}, + {{0x27f2af18073f3e6a, 0xfd3fe519d7521069, 0x22e3b72c3ca60022, 0x72214f63cc65c6a7}}}, +{{{0xb4e37f405307a693, 0xaba714d72f336795, 0xd6fbd0a773761099, 0x5fdf48c58171cbc9}}, + {{0x1d9db7b9f43b29c9, 0xd605824a4f518f75, 0xf2c072bd312f9dc4, 0x1f24ac855a1545b0}}, + {{0x24d608328e9505aa, 0x4748c1d10c1420ee, 0xc7ffe45c06fb25a2, 0x00ba739e2ae395e6}}}, +{{{0x592e98de5c8790d6, 0xe5bfb7d345c2a2df, 0x115a3b60f9b49922, 0x03283a3e67ad78f3}}, + {{0xae4426f5ea88bb26, 0x360679d984973bfb, 0x5c9f030c26694e50, 0x72297de7d518d226}}, + {{0x48241dc7be0cb939, 0x32f19b4d8b633080, 0xd3dfc90d02289308, 0x05e1296846271945}}}, +{{{0xba82eeb32d9c495a, 0xceefc8fcf12bb97c, 0xb02dabae93b5d1e0, 0x39c00c9c13698d9b}}, + {{0xadbfbbc8242c4550, 0xbcc80cecd03081d9, 0x843566a6f5c8df92, 0x78cf25d38258ce4c}}, + {{0x15ae6b8e31489d68, 0xaa851cab9c2bf087, 0xc9a75a97f04efa05, 0x006b52076b3ff832}}}, +{{{0x29e0cfe19d95781c, 0xb681df18966310e2, 0x57df39d370516b39, 0x4d57e3443bc76122}}, + {{0xf5cb7e16b9ce082d, 0x3407f14c417abc29, 0xd4b36bce2bf4a7ab, 0x7de2e9561a9f75ce}}, + {{0xde70d4f4b6a55ecb, 0x4801527f5d85db99, 0xdbc9c440d3ee9a81, 0x6b2a90af1a6029ed}}}, +{{{0x6923f4fc9ae61e97, 0x5735281de03f5fd1, 0xa764ae43e6edd12d, 0x5fd8f4e9d12d3e4a}}, + {{0x77ebf3245bb2d80a, 0xd8301b472fb9079b, 0xc647e6f24cee7333, 0x465812c8276c2109}}, + {{0x4d43beb22a1062d9, 0x7065fb753831dc16, 0x180d4a7bde2968d7, 0x05b32c2b1cb16790}}}, +{{{0xc8c05eccd24da8fd, 0xa1cf1aac05dfef83, 0xdbbeeff27df9cd61, 0x3b5556a37b471e99}}, + {{0xf7fca42c7ad58195, 0x3214286e4333f3cc, 0xb6c29d0d340b979d, 0x31771a48567307e1}}, + {{0x32b0c524e14dd482, 0xedb351541a2ba4b6, 0xa3d16048282b5af3, 0x4fc079d27a7336eb}}}, +{{{0x51c938b089bf2f7f, 0x2497bd6502dfe9a7, 0xffffc09c7880e453, 0x124567cecaf98e92}}, + {{0xdc348b440c86c50d, 0x1337cbc9cc94e651, 0x6422f74d643e3cb9, 0x241170c2bae3cd08}}, + {{0x3ff9ab860ac473b4, 0xf0911dee0113e435, 0x4ae75060ebc6c4af, 0x3f8612966c87000d}}}, +{{{0x559a0cc9782a0dde, 0x551dcdb2ea718385, 0x7f62865b31ef238c, 0x504aa7767973613d}}, + {{0x9c18fcfa36048d13, 0x29159db373899ddd, 0xdc9f350b9f92d0aa, 0x26f57eee878a19d4}}, + {{0x0cab2cd55687efb1, 0x5180d162247af17b, 0x85c15a344f5a2467, 0x4041943d9dba3069}}}, +{{{0xc3c0eeba43ebcc96, 0x8d749c9c26ea9caf, 0xd9fa95ee1c77ccc6, 0x1420a1d97684340f}}, + {{0x4b217743a26caadd, 0x47a6b424648ab7ce, 0xcb1d4f7a03fbc9e3, 0x12d931429800d019}}, + {{0x00c67799d337594f, 0x5e3c5140b23aa47b, 0x44182854e35ff395, 0x1b4f92314359a012}}}, +{{{0x3e5c109d89150951, 0x39cefa912de9696a, 0x20eae43f975f3020, 0x239b572a7f132dae}}, + {{0x33cf3030a49866b1, 0x251f73d2215f4859, 0xab82aa4051def4f6, 0x5ff191d56f9a23f6}}, + {{0x819ed433ac2d9068, 0x2883ab795fc98523, 0xef4572805593eb3d, 0x020c526a758f36cb}}}, +{{{0x779834f89ed8dbbc, 0xc8f2aaf9dc7ca46c, 0xa9524cdca3e1b074, 0x02aacc4615313877}}, + {{0xe931ef59f042cc89, 0x2c589c9d8e124bb6, 0xadc8e18aaec75997, 0x452cfe0a5602c50c}}, + {{0x86a0f7a0647877df, 0xbbc464270e607c9f, 0xab17ea25f1fb11c9, 0x4cfb7d7b304b877b}}}, +{{{0x72b43d6cb89b75fe, 0x54c694d99c6adc80, 0xb8c3aa373ee34c9f, 0x14b4622b39075364}}, + {{0xe28699c29789ef12, 0x2b6ecd71df57190d, 0xc343c857ecc970d0, 0x5b1d4cbc434d3ac5}}, + {{0xb6fb2615cc0a9f26, 0x3a4f0e2bb88dcce5, 0x1301498b3369a705, 0x2f98f71258592dd1}}}, +{{{0x0c94a74cb50f9e56, 0x5b1ff4a98e8e1320, 0x9a2acc2182300f67, 0x3a6ae249d806aaf9}}, + {{0x2e12ae444f54a701, 0xfcfe3ef0a9cbd7de, 0xcebf890d75835de0, 0x1d8062e9e7614554}}, + {{0x657ada85a9907c5a, 0x1a0ea8b591b90f62, 0x8d0e1dfbdf34b4e9, 0x298b8ce8aef25ff3}}}, +{{{0x2a927953eff70cb2, 0x4b89c92a79157076, 0x9418457a30a7cf6a, 0x34b8a8404d5ce485}}, + {{0x837a72ea0a2165de, 0x3fab07b40bcf79f6, 0x521636c77738ae70, 0x6ba6271803a7d7dc}}, + {{0xc26eecb583693335, 0xd5a813df63b5fefd, 0xa293aa9aa4b22573, 0x71d62bdd465e1c6a}}}, +{{{0x6533cc28d378df80, 0xf6db43790a0fa4b4, 0xe3645ff9f701da5a, 0x74d5f317f3172ba4}}, + {{0xcd2db5dab1f75ef5, 0xd77f95cf16b065f5, 0x14571fea3f49f085, 0x1c333621262b2b3d}}, + {{0xa86fe55467d9ca81, 0x398b7c752b298c37, 0xda6d0892e3ac623b, 0x4aebcc4547e9d98c}}}, +{{{0x12f0071b276d01c9, 0xe7b8bac586c48c70, 0x5308129b71d6fba9, 0x5d88fbf95a3db792}}, + {{0x0b408d9e7354b610, 0x806b32535ba85b6e, 0xdbe63a034a58a207, 0x173bd9ddc9a1df2c}}, + {{0x2b500f1efe5872df, 0x58d6582ed43918c1, 0xe6ed278ec9673ae0, 0x06e1cd13b19ea319}}}, +{{{0x40d0ad516f166f23, 0x118e32931fab6abe, 0x3fe35e14a04d088e, 0x3080603526e16266}}, + {{0x472baf629e5b0353, 0x3baa0b90278d0447, 0x0c785f469643bf27, 0x7f3a6a1a8d837b13}}, + {{0xf7e644395d3d800b, 0x95a8d555c901edf6, 0x68cd7830592c6339, 0x30d0fded2e51307e}}}, +{{{0xe0594d1af21233b3, 0x1bdbe78ef0cc4d9c, 0x6965187f8f499a77, 0x0a9214202c099868}}, + {{0x9cb4971e68b84750, 0xa09572296664bbcf, 0x5c8de72672fa412b, 0x4615084351c589d9}}, + {{0xbc9019c0aeb9a02e, 0x55c7110d16034cae, 0x0e6df501659932ec, 0x3bca0d2895ca5dfe}}}, +{{{0x40f031bc3c5d62a4, 0x19fc8b3ecff07a60, 0x98183da2130fb545, 0x5631deddae8f13cd}}, + {{0x9c688eb69ecc01bf, 0xf0bc83ada644896f, 0xca2d955f5f7a9fe2, 0x4ea8b4038df28241}}, + {{0x2aed460af1cad202, 0x46305305a48cee83, 0x9121774549f11a5f, 0x24ce0930542ca463}}}, +{{{0x1fe890f5fd06c106, 0xb5c468355d8810f2, 0x827808fe6e8caf3e, 0x41d4e3c28a06d74b}}, + {{0x3fcfa155fdf30b85, 0xd2f7168e36372ea4, 0xb2e064de6492f844, 0x549928a7324f4280}}, + {{0xf26e32a763ee1a2e, 0xae91e4b7d25ffdea, 0xbc3bd33bd17f4d69, 0x491b66dec0dcff6a}}}, +{{{0x98f5b13dc7ea32a7, 0xe3d5f8cc7e16db98, 0xac0abf52cbf8d947, 0x08f338d0c85ee4ac}}, + {{0x75f04a8ed0da64a1, 0xed222caf67e2284b, 0x8234a3791f7b7ba4, 0x4cf6b8b0b7018b67}}, + {{0xc383a821991a73bd, 0xab27bc01df320c7a, 0xc13d331b84777063, 0x530d4a82eb078a99}}}, +{{{0x004c3630e1f94825, 0x7e2d78268cab535a, 0xc7482323cc84ff8b, 0x65ea753f101770b9}}, + {{0x6d6973456c9abf9e, 0x257fb2fc4900a880, 0x2bacf412c8cfb850, 0x0db3e7e00cbfbd5b}}, + {{0x3d66fc3ee2096363, 0x81d62c7f61b5cb6b, 0x0fbe044213443b1a, 0x02a4ec1921e1a1db}}}, +{{{0x5ce6259a3b24b8a2, 0xb8577acc45afa0b8, 0xcccbe6e88ba07037, 0x3d143c51127809bf}}, + {{0xf5c86162f1cf795f, 0x118c861926ee57f2, 0x172124851c063578, 0x36d12b5dec067fcf}}, + {{0x126d279179154557, 0xd5e48f5cfc783a0a, 0x36bdb6e8df179bac, 0x2ef517885ba82859}}}, +{{{0x4637974e8c58aedc, 0xb9ef22fbabf041a4, 0xe185d956e980718a, 0x2f1b78fab143a8a6}}, + {{0x96eebffb305b2f51, 0xd3f938ad889596b8, 0xf0f52dc746d5dd25, 0x57968290bb3a0095}}, + {{0xf71ab8430a20e101, 0xf393658d24f0ec47, 0xcf7509a86ee2eed1, 0x7dc43e35dc2aa3e1}}}, +{{{0x85966665887dd9c3, 0xc90f9b314bb05355, 0xc6e08df8ef2079b1, 0x7ef72016758cc12f}}, + {{0x5a782a5c273e9718, 0x3576c6995e4efd94, 0x0f2ed8051f237d3e, 0x044fb81d82d50a99}}, + {{0xc1df18c5a907e3d9, 0x57b3371dce4c6359, 0xca704534b201bb49, 0x7f79823f9c30dd2e}}}, +{{{0x8334d239a3b513e8, 0xc13670d4b91fa8d8, 0x12b54136f590bd33, 0x0a4e0373d784d9b4}}, + {{0x6a9c1ff068f587ba, 0x0827894e0050c8de, 0x3cbf99557ded5be7, 0x64a9b0431c06d6f0}}, + {{0x2eb3d6a15b7d2919, 0xb0b4f6a0d53a8235, 0x7156ce4389a45d47, 0x071a7d0ace18346c}}}, +{{{0xd3072daac887ba0b, 0x01262905bfa562ee, 0xcf543002c0ef768b, 0x2c3bcc7146ea7e9c}}, + {{0xcc0c355220e14431, 0x0d65950709b15141, 0x9af5621b209d5f36, 0x7c69bcf7617755d3}}, + {{0x07f0d7eb04e8295f, 0x10db18252f50f37d, 0xe951a9a3171798d7, 0x6f5a9a7322aca51d}}}, +{{{0x8ba1000c2f41c6c5, 0xc49f79c10cfefb9b, 0x4efa47703cc51c9f, 0x494e21a2e147afca}}, + {{0xe729d4eba3d944be, 0x8d9e09408078af9e, 0x4525567a47869c03, 0x02ab9680ee8d3b24}}, + {{0xefa48a85dde50d9a, 0x219a224e0fb9a249, 0xfa091f1dd91ef6d9, 0x6b5d76cbea46bb34}}}, +{{{0x8857556cec0cd994, 0x6472dc6f5cd01dba, 0xaf0169148f42b477, 0x0ae333f685277354}}, + {{0xe0f941171e782522, 0xf1e6ae74036936d3, 0x408b3ea2d0fcc746, 0x16fb869c03dd313e}}, + {{0x288e199733b60962, 0x24fc72b4d8abe133, 0x4811f7ed0991d03e, 0x3f81e38b8f70d075}}}, +{{{0x7f910fcc7ed9affe, 0x545cb8a12465874b, 0xa8397ed24b0c4704, 0x50510fc104f50993}}, + {{0x0adb7f355f17c824, 0x74b923c3d74299a4, 0xd57c3e8bcbf8eaf7, 0x0ad3e2d34cdedc3d}}, + {{0x6f0c0fc5336e249d, 0x745ede19c331cfd9, 0xf2d6fd0009eefe1c, 0x127c158bf0fa1ebe}}}, +{{{0xf6197c422e9879a2, 0xa44addd452ca3647, 0x9b413fc14b4eaccb, 0x354ef87d07ef4f68}}, + {{0xdea28fc4ae51b974, 0x1d9973d3744dfe96, 0x6240680b873848a8, 0x4ed82479d167df95}}, + {{0xfee3b52260c5d975, 0x50352efceb41b0b8, 0x8808ac30a9f6653c, 0x302d92d20539236d}}}, +{{{0x7813c1a2bca4283d, 0xed62f091a1863dd9, 0xaec7bcb8c268fa86, 0x10e5d3b76f1cae4c}}, + {{0x2dbc6fb6e4e0f177, 0x04e1bf29a4bd6a93, 0x5e1966d4787af6e8, 0x0edc5f5eb426d060}}, + {{0x5453bfd653da8e67, 0xe9dc1eec24a9f641, 0xbf87263b03578a23, 0x45b46c51361cba72}}}, +{{{0xa9402abf314f7fa1, 0xe257f1dc8e8cf450, 0x1dbbd54b23a8be84, 0x2177bfa36dcb713b}}, + {{0xce9d4ddd8a7fe3e4, 0xab13645676620e30, 0x4b594f7bb30e9958, 0x5c1c0aef321229df}}, + {{0x37081bbcfa79db8f, 0x6048811ec25f59b3, 0x087a76659c832487, 0x4ae619387d8ab5bb}}}, +{{{0x8ddbf6aa5344a32e, 0x7d88eab4b41b4078, 0x5eb0eb974a130d60, 0x1a00d91b17bf3e03}}, + {{0x61117e44985bfb83, 0xfce0462a71963136, 0x83ac3448d425904b, 0x75685abe5ba43d64}}, + {{0x6e960933eb61f2b2, 0x543d0fa8c9ff4952, 0xdf7275107af66569, 0x135529b623b0e6aa}}}, +{{{0x18f0dbd7add1d518, 0x979f7888cfc11f11, 0x8732e1f07114759b, 0x79b5b81a65ca3a01}}, + {{0xf5c716bce22e83fe, 0xb42beb19e80985c1, 0xec9da63714254aae, 0x5972ea051590a613}}, + {{0x0fd4ac20dc8f7811, 0x9a9ad294ac4d4fa8, 0xc01b2d64b3360434, 0x4f7e9c95905f3bdb}}}, +{{{0x62674bbc5781302e, 0xd8520f3989addc0f, 0x8c2999ae53fbd9c6, 0x31993ad92e638e4c}}, + {{0x71c8443d355299fe, 0x8bcd3b1cdbebead7, 0x8092499ef1a49466, 0x1942eec4a144adc8}}, + {{0x7dac5319ae234992, 0x2c1b3d910cea3e92, 0x553ce494253c1122, 0x2a0a65314ef9ca75}}}, +{{{0x2db7937ff7f927c2, 0xdb741f0617d0a635, 0x5982f3a21155af76, 0x4cf6e218647c2ded}}, + {{0xcf361acd3c1c793a, 0x2f9ebcac5a35bc3b, 0x60e860e9a8cda6ab, 0x055dc39b6dea1a13}}, + {{0xb119227cc28d5bb6, 0x07e24ebc774dffab, 0xa83c78cee4a32c89, 0x121a307710aa24b6}}}, +{{{0xe4db5d5e9f034a97, 0xe153fc093034bc2d, 0x460546919551d3b1, 0x333fc76c7a40e52d}}, + {{0xd659713ec77483c9, 0x88bfe077b82b96af, 0x289e28231097bcd3, 0x527bb94a6ced3a9b}}, + {{0x563d992a995b482e, 0x3405d07c6e383801, 0x485035de2f64d8e5, 0x6b89069b20a7a9f7}}}, +{{{0x812aa0416270220d, 0x995a89faf9245b4e, 0xffadc4ce5072ef05, 0x23bc2103aa73eb73}}, + {{0x4082fa8cb5c7db77, 0x068686f8c734c155, 0x29e6c8d9f6e7a57e, 0x0473d308a7639bcf}}, + {{0xcaee792603589e05, 0x2b4b421246dcc492, 0x02a1ef74e601a94f, 0x102f73bfde04341a}}}, +{{{0xeb18b9ab7f5745c6, 0x023a8aee5787c690, 0xb72712da2df7afa9, 0x36597d25ea5c013d}}, + {{0xa2b4dae0b5511c9a, 0x7ac860292bffff06, 0x981f375df5504234, 0x3f6bd725da4ea12d}}, + {{0x734d8d7b106058ac, 0xd940579e6fc6905f, 0x6466f8f99202932d, 0x7b7ecc19da60d6d0}}}, +{{{0x78c2373c695c690d, 0xdd252e660642906e, 0x951d44444ae12bd2, 0x4235ad7601743956}}, + {{0x6dae4a51a77cfa9b, 0x82263654e7a38650, 0x09bbffcd8f2d82db, 0x03bedc661bf5caba}}, + {{0x6258cb0d078975f5, 0x492942549189f298, 0xa0cab423e2e36ee4, 0x0e7ce2b0cdf066a1}}}, +{{{0xc494643ac48c85a3, 0xfd361df43c6139ad, 0x09db17dd3ae94d48, 0x666e0a5d8fb4674a}}, + {{0xfea6fedfd94b70f9, 0xf130c051c1fcba2d, 0x4882d47e7f2fab89, 0x615256138aeceeb5}}, + {{0x2abbf64e4870cb0d, 0xcd65bcf0aa458b6b, 0x9abe4eba75e8985d, 0x7f0bc810d514dee4}}}, +{{{0xb9006ba426f4136f, 0x8d67369e57e03035, 0xcbc8dfd94f463c28, 0x0d1f8dbcf8eedbf5}}, + {{0x83ac9dad737213a0, 0x9ff6f8ba2ef72e98, 0x311e2edd43ec6957, 0x1d3a907ddec5ab75}}, + {{0xba1693313ed081dc, 0x29329fad851b3480, 0x0128013c030321cb, 0x00011b44a31bfde3}}}, +{{{0x3fdfa06c3fc66c0c, 0x5d40e38e4dd60dd2, 0x7ae38b38268e4d71, 0x3ac48d916e8357e1}}, + {{0x16561f696a0aa75c, 0xc1bf725c5852bd6a, 0x11a8dd7f9a7966ad, 0x63d988a2d2851026}}, + {{0x00120753afbd232e, 0xe92bceb8fdd8f683, 0xf81669b384e72b91, 0x33fad52b2368a066}}}, +{{{0x540649c6c5e41e16, 0x0af86430333f7735, 0xb2acfcd2f305e746, 0x16c0f429a256dca7}}, + {{0x8d2cc8d0c422cfe8, 0x072b4f7b05a13acb, 0xa3feb6e6ecf6a56f, 0x3cc355ccb90a71e2}}, + {{0xe9b69443903e9131, 0xb8a494cb7a5637ce, 0xc87cd1a4baba9244, 0x631eaf426bae7568}}}, +{{{0xb3e90410da66fe9f, 0x85dd4b526c16e5a6, 0xbc3d97611ef9bf83, 0x5599648b1ea919b5}}, + {{0x47d975b9a3700de8, 0x7280c5fbe2f80552, 0x53658f2732e45de1, 0x431f2c7f665f80b5}}, + {{0xd6026344858f7b19, 0x14ab352fa1ea514a, 0x8900441a2090a9d7, 0x7b04715f91253b26}}}, +{{{0x83edbd28acf6ae43, 0x86357c8b7d5c7ab4, 0xc0404769b7eb2c44, 0x59b37bf5c2f6583f}}, + {{0xb376c280c4e6bac6, 0x970ed3dd6d1d9b0b, 0xb09a9558450bf944, 0x48d0acfa57cde223}}, + {{0xb60f26e47dabe671, 0xf1d1a197622f3a37, 0x4208ce7ee9960394, 0x16234191336d3bdb}}}, +{{{0xb9e499def6267ff6, 0x7772ca7b742c0843, 0x23a0153fe9a4f2b1, 0x2cdfdfecd5d05006}}, + {{0xdd499cd61ff38640, 0x29cd9bc3063625a0, 0x51e2d8023dd73dc3, 0x4a25707a203b9231}}, + {{0x2ab7668a53f6ed6a, 0x304242581dd170a1, 0x4000144c3ae20161, 0x5721896d248e49fc}}}, +{{{0x0b6e5517fd181bae, 0x9022629f2bb963b4, 0x5509bce932064625, 0x578edd74f63c13da}}, + {{0x285d5091a1d0da4e, 0x4baa6fa7b5fe3e08, 0x63e5177ce19393b3, 0x03c935afc4b030fd}}, + {{0x997276c6492b0c3d, 0x47ccc2c4dfe205fc, 0xdcd29b84dd623a3c, 0x3ec2ab590288c7a2}}}, +{{{0xa1a0d27be4d87bb9, 0xa98b4deb61391aed, 0x99a0ddd073cb9b83, 0x2dd5c25a200fcace}}, + {{0xa7213a09ae32d1cb, 0x0f2b87df40f5c2d5, 0x0baea4c6e81eab29, 0x0e1bf66c6adbac5e}}, + {{0xe2abd5e9792c887e, 0x1a020018cb926d5d, 0xbfba69cdbaae5f1e, 0x730548b35ae88f5f}}}, +{{{0xc43551a3cba8b8ee, 0x65a26f1db2115f16, 0x760f4f52ab8c3850, 0x3043443b411db8ca}}, + {{0x805b094ba1d6e334, 0xbf3ef17709353f19, 0x423f06cb0622702b, 0x585a2277d87845dd}}, + {{0xa18a5f8233d48962, 0x6698c4b5ec78257f, 0xa78e6fa5373e41ff, 0x7656278950ef981f}}}, +{{{0x38c3cf59d51fc8c0, 0x9bedd2fd0506b6f2, 0x26bf109fab570e8f, 0x3f4160a8c1b846a6}}, + {{0xe17073a3ea86cf9d, 0x3a8cfbb707155fdc, 0x4853e7fc31838a8e, 0x28bbf484b613f616}}, + {{0xf2612f5c6f136c7c, 0xafead107f6dd11be, 0x527e9ad213de6f33, 0x1e79cb358188f75d}}}, +{{{0x013436c3eef7e3f1, 0x828b6a7ffe9e10f8, 0x7ff908e5bcf9defc, 0x65d7951b3a3b3831}}, + {{0x77e953d8f5e08181, 0x84a50c44299dded9, 0xdc6c2d0c864525e5, 0x478ab52d39d1f2f4}}, + {{0x66a6a4d39252d159, 0xe5dde1bc871ac807, 0xb82c6b40a6c1c96f, 0x16d87a411a212214}}}, +{{{0xb3bd7e5a42066215, 0x879be3cd0c5a24c1, 0x57c05db1d6f994b7, 0x28f87c8165f38ca6}}, + {{0xfba4d5e2d54e0583, 0xe21fafd72ebd99fa, 0x497ac2736ee9778f, 0x1f990b577a5a6dde}}, + {{0xa3344ead1be8f7d6, 0x7d1e50ebacea798f, 0x77c6569e520de052, 0x45882fe1534d6d3e}}}, +{{{0x6669345d757983d6, 0x62b6ed1117aa11a6, 0x7ddd1857985e128f, 0x688fe5b8f626f6dd}}, + {{0xd8ac9929943c6fe4, 0xb5f9f161a38392a2, 0x2699db13bec89af3, 0x7dcf843ce405f074}}, + {{0x6c90d6484a4732c0, 0xd52143fdca563299, 0xb3be28c3915dc6e1, 0x6739687e7327191b}}}, +{{{0xef782014385675a6, 0xa2649f30aafda9e8, 0x4cd1eb505cdfa8cb, 0x46115aba1d4dc0b3}}, + {{0xa66dcc9dc80c1ac0, 0x97a05cf41b38a436, 0xa7ebf3be95dbd7c6, 0x7da0b8f68d7e7dab}}, + {{0xd40f1953c3b5da76, 0x1dac6f7321119e9b, 0x03cc6021feb25960, 0x5a5f887e83674b4b}}}, +{{{0x8f6301cf70a13d11, 0xcfceb815350dd0c4, 0xf70297d4a4bca47e, 0x3669b656e44d1434}}, + {{0x9e9628d3a0a643b9, 0xb5c3cb00e6c32064, 0x9b5302897c2dec32, 0x43e37ae2d5d1c70c}}, + {{0x387e3f06eda6e133, 0x67301d5199a13ac0, 0xbd5ad8f836263811, 0x6a21e6cd4fd5e9be}}}, +{{{0xf1c6170a3046e65f, 0x58712a2a00d23524, 0x69dbbd3c8c82b755, 0x586bf9f1a195ff57}}, + {{0xef4129126699b2e3, 0x71d30847708d1301, 0x325432d01182b0bd, 0x45371b07001e8b36}}, + {{0xa6db088d5ef8790b, 0x5278f0dc610937e5, 0xac0349d261a16eb8, 0x0eafb03790e52179}}}, +{{{0x960555c13748042f, 0x219a41e6820baa11, 0x1c81f73873486d0c, 0x309acc675a02c661}}, + {{0x5140805e0f75ae1d, 0xec02fbe32662cc30, 0x2cebdf1eea92396d, 0x44ae3344c5435bb3}}, + {{0x9cf289b9bba543ee, 0xf3760e9d5ac97142, 0x1d82e5c64f9360aa, 0x62d5221b7f94678f}}}, +{{{0x524c299c18d0936d, 0xc86bb56c8a0c1a0c, 0xa375052edb4a8631, 0x5c0efde4bc754562}}, + {{0x7585d4263af77a3c, 0xdfae7b11fee9144d, 0xa506708059f7193d, 0x14f29a5383922037}}, + {{0xdf717edc25b2d7f5, 0x21f970db99b53040, 0xda9234b7c3ed4c62, 0x5e72365c7bee093e}}}, +{{{0x575bfc074571217f, 0x3779675d0694d95b, 0x9a0a37bbf4191e33, 0x77f1104c47b4eabc}}, + {{0x7d9339062f08b33e, 0x5b9659e5df9f32be, 0xacff3dad1f9ebdfd, 0x70b20555cb7349b7}}, + {{0xbe5113c555112c4c, 0x6688423a9a881fcd, 0x446677855e503b47, 0x0e34398f4a06404a}}}, +{{{0xb67d22d93ecebde8, 0x09b3e84127822f07, 0x743fa61fb05b6d8d, 0x5e5405368a362372}}, + {{0x18930b093e4b1928, 0x7de3e10e73f3f640, 0xf43217da73395d6f, 0x6f8aded6ca379c3e}}, + {{0xe340123dfdb7b29a, 0x487b97e1a21ab291, 0xf9967d02fde6949e, 0x780de72ec8d3de97}}}, +{{{0x0ae28545089ae7bc, 0x388ddecf1c7f4d06, 0x38ac15510a4811b8, 0x0eb28bf671928ce4}}, + {{0x671feaf300f42772, 0x8f72eb2a2a8c41aa, 0x29a17fd797373292, 0x1defc6ad32b587a6}}, + {{0xaf5bbe1aef5195a7, 0x148c1277917b15ed, 0x2991f7fb7ae5da2e, 0x467d201bf8dd2867}}}, +{{{0x95fe919a74ef4fad, 0x3a827becf6a308a2, 0x964e01d309a47b01, 0x71c43c4f5ba3c797}}, + {{0xbc1ef4bd567ae7a9, 0x3f624cb2d64498bd, 0xe41064d22c1f4ec8, 0x2ef9c5a5ba384001}}, + {{0xb6fd6df6fa9e74cd, 0xf18278bce4af267a, 0x8255b3d0f1ef990e, 0x5a758ca390c5f293}}}, +{{{0xa2b72710d9462495, 0x3aa8c6d2d57d5003, 0xe3d400bfa0b487ca, 0x2dbae244b3eb72ec}}, + {{0x8ce0918b1d61dc94, 0x8ded36469a813066, 0xd4e6a829afe8aad3, 0x0a738027f639d43f}}, + {{0x980f4a2f57ffe1cc, 0x00670d0de1839843, 0x105c3f4a49fb15fd, 0x2698ca635126a69c}}}, +{{{0xe765318832b0ba78, 0x381831f7925cff8b, 0x08a81b91a0291fcc, 0x1fb43dcc49caeb07}}, + {{0x2e3d702f5e3dd90e, 0x9e3f0918e4d25386, 0x5e773ef6024da96a, 0x3c004b0c4afa3332}}, + {{0x9aa946ac06f4b82b, 0x1ca284a5a806c4f3, 0x3ed3265fc6cd4787, 0x6b43fd01cd1fd217}}}, +{{{0xc7a75d4b4697c544, 0x15fdf848df0fffbf, 0x2868b9ebaa46785a, 0x5a68d7105b52f714}}, + {{0xb5c742583e760ef3, 0x75dc52b9ee0ab990, 0xbf1427c2072b923f, 0x73420b2d6ff0d9f0}}, + {{0xaf2cf6cb9e851e06, 0x8f593913c62238c4, 0xda8ab89699fbf373, 0x3db5632fea34bc9e}}}, +{{{0xf46eee2bf75dd9d8, 0x0d17b1f6396759a5, 0x1bf2d131499e7273, 0x04321adf49d75f13}}, + {{0x2e4990b1829825d5, 0xedeaeb873e9a8991, 0xeef03d394c704af8, 0x59197ea495df2b0e}}, + {{0x04e16019e4e55aae, 0xe77b437a7e2f92e9, 0xc7ce2dc16f159aa4, 0x45eafdc1f4d70cc0}}}, +{{{0x698401858045d72b, 0x4c22faa2cf2f0651, 0x941a36656b222dc6, 0x5a5eebc80362dade}}, + {{0xb60e4624cfccb1ed, 0x59dbc292bd5c0395, 0x31a09d1ddc0481c9, 0x3f73ceea5d56d940}}, + {{0xb7a7bfd10a4e8dc6, 0xbe57007e44c9b339, 0x60c1207f1557aefa, 0x26058891266218db}}}, +{{{0x59f704a68360ff04, 0xc3d93fde7661e6f4, 0x831b2a7312873551, 0x54ad0c2e4e615d57}}, + {{0x4c818e3cc676e542, 0x5e422c9303ceccad, 0xec07cccab4129f08, 0x0dedfa10b24443b8}}, + {{0xee3b67d5b82b522a, 0x36f163469fa5c1eb, 0xa5b4d2f26ec19fd3, 0x62ecb2baa77a9408}}}, +{{{0xe5ed795261152b3d, 0x4962357d0eddd7d1, 0x7482c8d0b96b4c71, 0x2e59f919a966d8be}}, + {{0x92072836afb62874, 0x5fcd5e8579e104a5, 0x5aad01adc630a14a, 0x61913d5075663f98}}, + {{0x0dc62d361a3231da, 0xfa47583294200270, 0x02d801513f9594ce, 0x3ddbc2a131c05d5c}}}, +{{{0x9adc0ff9ce5ec54b, 0x039c2a6b8c2f130d, 0x028007c7f0f89515, 0x78968314ac04b36b}}, + {{0xf3aa57a22796bb14, 0x883abab79b07da21, 0xe54be21831a0391c, 0x5ee7fb38d83205f9}}, + {{0x538dfdcb41446a8e, 0xa5acfda9434937f9, 0x46af908d263c8c78, 0x61d0633c9bca0d09}}}, +{{{0x63744935ffdb2566, 0xc5bd6b89780b68bb, 0x6f1b3280553eec03, 0x6e965fd847aed7f5}}, + {{0xada328bcf8fc73df, 0xee84695da6f037fc, 0x637fb4db38c2a909, 0x5b23ac2df8067bdc}}, + {{0x9ad2b953ee80527b, 0xe88f19aafade6d8d, 0x0e711704150e82cf, 0x79b9bbb9dd95dedc}}}, +{{{0xebb355406a3126c2, 0xd26383a868c8c393, 0x6c0c6429e5b97a82, 0x5065f158c9fd2147}}, + {{0xd1997dae8e9f7374, 0xa032a2f8cfbb0816, 0xcd6cba126d445f0a, 0x1ba811460accb834}}, + {{0x708169fb0c429954, 0xe14600acd76ecf67, 0x2eaab98a70e645ba, 0x3981f39e58a4faf2}}}, +{{{0x18fb8a7559230a93, 0x1d168f6960e6f45d, 0x3a85a94514a93cb5, 0x38dc083705acd0fd}}, + {{0xc845dfa56de66fde, 0xe152a5002c40483a, 0xe9d2e163c7b4f632, 0x30f4452edcbc1b65}}, + {{0x856d2782c5759740, 0xfa134569f99cbecc, 0x8844fc73c0ea4e71, 0x632d9a1a593f2469}}}, +{{{0xf6bb6b15b807cba6, 0x1823c7dfbc54f0d7, 0xbb1d97036e29670b, 0x0b24f48847ed4a57}}, + {{0xbf09fd11ed0c84a7, 0x63f071810d9f693a, 0x21908c2d57cf8779, 0x3a5a7df28af64ba2}}, + {{0xdcdad4be511beac7, 0xa4538075ed26ccf2, 0xe19cff9f005f9a65, 0x34fcf74475481f63}}}, +{{{0xc197e04c789767ca, 0xb8714dcb38d9467d, 0x55de888283f95fa8, 0x3d3bdc164dfa63f7}}, + {{0xa5bb1dab78cfaa98, 0x5ceda267190b72f2, 0x9309c9110a92608e, 0x0119a3042fb374b0}}, + {{0x67a2d89ce8c2177d, 0x669da5f66895d0c1, 0xf56598e5b282a2b0, 0x56c088f1ede20a73}}}, +{{{0x336d3d1110a86e17, 0xd7f388320b75b2fa, 0xf915337625072988, 0x09674c6b99108b87}}, + {{0x581b5fac24f38f02, 0xa90be9febae30cbd, 0x9a2169028acf92f0, 0x038b7ea48359038f}}, + {{0x9f4ef82199316ff8, 0x2f49d282eaa78d4f, 0x0971a5ab5aef3174, 0x6e5e31025969eb65}}}, +{{{0xb16c62f587e593fb, 0x4999eddeca5d3e71, 0xb491c1e014cc3e6d, 0x08f5114789a8dba8}}, + {{0x3304fb0e63066222, 0xfb35068987acba3f, 0xbd1924778c1061a3, 0x3058ad43d1838620}}, + {{0x323c0ffde57663d0, 0x05c3df38a22ea610, 0xbdc78abdac994f9a, 0x26549fa4efe3dc99}}}, +{{{0x741d5a461e6bf9d6, 0x2305b3fc7777a581, 0xd45574a26474d3d9, 0x1926e1dc6401e0ff}}, + {{0xdb468549af3f666e, 0xd77fcf04f14a0ea5, 0x3df23ff7a4ba0c47, 0x3a10dfe132ce3c85}}, + {{0xe07f4e8aea17cea0, 0x2fd515463a1fc1fd, 0x175322fd31f2c0f1, 0x1fa1d01d861e5d15}}}, +{{{0xcc8055947d599832, 0x1e4656da37f15520, 0x99f6f7744e059320, 0x773563bc6a75cf33}}, + {{0x38dcac00d1df94ab, 0x2e712bddd1080de9, 0x7f13e93efdd5e262, 0x73fced18ee9a01e5}}, + {{0x06b1e90863139cb3, 0xa493da67c5a03ecd, 0x8d77cec8ad638932, 0x1f426b701b864f44}}}, +{{{0xefc9264c41911c01, 0xf1a3b7b817a22c25, 0x5875da6bf30f1447, 0x4e1af5271d31b090}}, + {{0xf17e35c891a12552, 0xb76b8153575e9c76, 0xfa83406f0d9b723e, 0x0b76bb1b3fa7e438}}, + {{0x08b8c1f97f92939b, 0xbe6771cbd444ab6e, 0x22e5646399bb8017, 0x7b6dd61eb772a955}}}, +{{{0xb7adc1e850f33d92, 0x7998fa4f608cd5cf, 0xad962dbd8dfc5bdb, 0x703e9bceaf1d2f4f}}, + {{0x5730abf9ab01d2c7, 0x16fb76dc40143b18, 0x866cbe65a0cbb281, 0x53fa9b659bff6afe}}, + {{0x6c14c8e994885455, 0x843a5d6665aed4e5, 0x181bb73ebcd65af1, 0x398d93e5c4c61f50}}}, +{{{0x1c4bd16733e248f3, 0xbd9e128715bf0a5f, 0xd43f8cf0a10b0376, 0x53b09b5ddf191b13}}, + {{0xc3877c60d2e7e3f2, 0x3b34aaa030828bb1, 0x283e26e7739ef138, 0x699c9c9002c30577}}, + {{0xf306a7235946f1cc, 0x921718b5cce5d97d, 0x28cdd24781b4e975, 0x51caf30c6fcdd907}}}, +{{{0xa60ba7427674e00a, 0x630e8570a17a7bf3, 0x3758563dcf3324cc, 0x5504aa292383fdaa}}, + {{0x737af99a18ac54c7, 0x903378dcc51cb30f, 0x2b89bc334ce10cc7, 0x12ae29c189f8e99a}}, + {{0xa99ec0cb1f0d01cf, 0x0dd1efcc3a34f7ae, 0x55ca7521d09c4e22, 0x5fd14fe958eba5ea}}}, +{{{0xb5dc2ddf2845ab2c, 0x069491b10a7fe993, 0x4daaf3d64002e346, 0x093ff26e586474d1}}, + {{0x3c42fe5ebf93cb8e, 0xbedfa85136d4565f, 0xe0f0859e884220e8, 0x7dd73f960725d128}}, + {{0xb10d24fe68059829, 0x75730672dbaf23e5, 0x1367253ab457ac29, 0x2f59bcbc86b470a4}}}, +{{{0x83847d429917135f, 0xad1b911f567d03d7, 0x7e7748d9be77aad1, 0x5458b42e2e51af4a}}, + {{0x7041d560b691c301, 0x85201b3fadd7e71e, 0x16c2e16311335585, 0x2aa55e3d010828b1}}, + {{0xed5192e60c07444f, 0x42c54e2d74421d10, 0x352b4c82fdb5c864, 0x13e9004a8a768664}}}, +{{{0x739d8845832fcedb, 0xfa38d6c9ae6bf863, 0x32bc0dcab74ffef7, 0x73937e8814bce45e}}, + {{0xbb2e00c9193b877f, 0xece3a890e0dc506b, 0xecf3b7c036de649f, 0x5f46040898de9e1a}}, + {{0xb9037116297bf48d, 0xa9d13b22d4f06834, 0xe19715574696bdc6, 0x2cf8a4e891d5e835}}}, +{{{0x6d93fd8707110f67, 0xdd4c09d37c38b549, 0x7cb16a4cc2736a86, 0x2049bd6e58252a09}}, + {{0x2cb5487e17d06ba2, 0x24d2381c3950196b, 0xd7659c8185978a30, 0x7a6f7f2891d6a4f6}}, + {{0x7d09fd8d6a9aef49, 0xf0ee60be5b3db90b, 0x4c21b52c519ebfd4, 0x6011aadfc545941d}}}, +{{{0x5f67926dcf95f83c, 0x7c7e856171289071, 0xd6a1e7f3998f7a5b, 0x6fc5cc1b0b62f9e0}}, + {{0x63ded0c802cbf890, 0xfbd098ca0dff6aaa, 0x624d0afdb9b6ed99, 0x69ce18b779340b1e}}, + {{0xd1ef5528b29879cb, 0xdd1aae3cd47e9092, 0x127e0442189f2352, 0x15596b3ae57101f1}}}, +{{{0x462739d23f9179a2, 0xff83123197d6ddcf, 0x1307deb553f2148a, 0x0d2237687b5f4dda}}, + {{0x09ff31167e5124ca, 0x0be4158bd9c745df, 0x292b7d227ef556e5, 0x3aa4e241afb6d138}}, + {{0x2cc138bf2a3305f5, 0x48583f8fa2e926c3, 0x083ab1a25549d2eb, 0x32fcaa6e4687a36c}}}, +{{{0x7bc56e8dc57d9af5, 0x3e0bd2ed9df0bdf2, 0xaac014de22efe4a3, 0x4627e9cefebd6a5c}}, + {{0x3207a4732787ccdf, 0x17e31908f213e3f8, 0xd5b2ecd7f60d964e, 0x746f6336c2600be9}}, + {{0x3f4af345ab6c971c, 0xe288eb729943731f, 0x33596a8a0344186d, 0x7b4917007ed66293}}}, +{{{0x2d85fb5cab84b064, 0x497810d289f3bc14, 0x476adc447b15ce0c, 0x122ba376f844fd7b}}, + {{0x54341b28dd53a2dd, 0xaa17905bdf42fc3f, 0x0ff592d94dd2f8f4, 0x1d03620fe08cd37d}}, + {{0xc20232cda2b4e554, 0x9ed0fd42115d187f, 0x2eabb4be7dd479d9, 0x02c70bf52b68ec4c}}}, +{{{0xa287ec4b5d0b2fbb, 0x415c5790074882ca, 0xe044a61ec1d0815c, 0x26334f0a409ef5e0}}, + {{0xace532bf458d72e1, 0x5be768e07cb73cb5, 0x56cf7d94ee8bbde7, 0x6b0697e3feb43a03}}, + {{0xb6c8f04adf62a3c0, 0x3ef000ef076da45d, 0x9c9cb95849f0d2a9, 0x1cc37f43441b2fae}}}, +{{{0x508f565a5cc7324f, 0xd061c4c0e506a922, 0xfb18abdb5c45ac19, 0x6c6809c10380314a}}, + {{0xd76656f1c9ceaeb9, 0x1c5b15f818e5656a, 0x26e72832844c2334, 0x3a346f772f196838}}, + {{0xd2d55112e2da6ac8, 0xe9bd0331b1e851ed, 0x960746dd8ec67262, 0x05911b9f6ef7c5d0}}}, +{{{0xc1339983f5df0ebb, 0xc0f3758f512c4cac, 0x2cf1130a0bb398e1, 0x6b3cecf9aa270c62}}, + {{0x5349acf3512eeaef, 0x20c141d31cc1cb49, 0x24180c07a99a688d, 0x555ef9d1c64b2d17}}, + {{0x36a770ba3b73bd08, 0x624aef08a3afbf0c, 0x5737ff98b40946f2, 0x675f4de13381749d}}}, +{{{0x0e2c52036b1782fc, 0x64816c816cad83b4, 0xd0dcbdd96964073e, 0x13d99df70164c520}}, + {{0xa12ff6d93bdab31d, 0x0725d80f9d652dfe, 0x019c4ff39abe9487, 0x60f450b882cd3c43}}, + {{0x014b5ec321e5c0ca, 0x4fcb69c9d719bfa2, 0x4e5f1c18750023a0, 0x1c06de9e55edac80}}}, +{{{0x990f7ad6a33ec4e2, 0x6608f938be2ee08e, 0x9ca143c563284515, 0x4cf38a1fec2db60d}}, + {{0xffd52b40ff6d69aa, 0x34530b18dc4049bb, 0x5e4a5c2fa34d9897, 0x78096f8e7d32ba2d}}, + {{0xa0aaaa650dfa5ce7, 0xf9c49e2a48b5478c, 0x4f09cc7d7003725b, 0x373cad3a26091abe}}}, +{{{0xb294634d82c9f57c, 0x1fcbfde124934536, 0x9e9c4db3418cdb5a, 0x0040f3d9454419fc}}, + {{0xf1bea8fb89ddbbad, 0x3bcb2cbc61aeaecb, 0x8f58a7bb1f9b8d9d, 0x21547eda5112a686}}, + {{0xdefde939fd5986d3, 0xf4272c89510a380c, 0xb72ba407bb3119b9, 0x63550a334a254df4}}}, +{{{0x6507d6edb569cf37, 0x178429b00ca52ee1, 0xea7c0090eb6bd65d, 0x3eea62c7daf78f51}}, + {{0x9bba584572547b49, 0xf305c6fae2c408e0, 0x60e8fa69c734f18d, 0x39a92bafaa7d767a}}, + {{0x9d24c713e693274e, 0x5f63857768dbd375, 0x70525560eb8ab39a, 0x68436a0665c9c4cd}}}, +{{{0xbc0235e8202f3f27, 0xc75c00e264f975b0, 0x91a4e9d5a38c2416, 0x17b6e7f68ab789f9}}, + {{0x1e56d317e820107c, 0xc5266844840ae965, 0xc1e0a1c6320ffc7a, 0x5373669c91611472}}, + {{0x5d2814ab9a0e5257, 0x908f2084c9cab3fc, 0xafcaf5885b2d1eca, 0x1cb4b5a678f87d11}}}, +{{{0xb664c06b394afc6c, 0x0c88de2498da5fb1, 0x4f8d03164bcad834, 0x330bca78de7434a2}}, + {{0x6b74aa62a2a007e7, 0xf311e0b0f071c7b1, 0x5707e438000be223, 0x2dc0fd2d82ef6eac}}, + {{0x982eff841119744e, 0xf9695e962b074724, 0xc58ac14fbfc953fb, 0x3c31be1b369f1cf5}}}, +{{{0xb0f4864d08948aee, 0x07dc19ee91ba1c6f, 0x7975cdaea6aca158, 0x330b61134262d4bb}}, + {{0xc168bc93f9cb4272, 0xaeb8711fc7cedb98, 0x7f0e52aa34ac8d7a, 0x41cec1097e7d55bb}}, + {{0xf79619d7a26d808a, 0xbb1fd49e1d9e156d, 0x73d7c36cdba1df27, 0x26b44cd91f28777d}}}, +{{{0x51f048478f387475, 0xb25dbcf49cbecb3c, 0x9aab1244d99f2055, 0x2c709e6c1c10a5d6}}, + {{0xe1b7f29362730383, 0x4b5279ffebca8a2c, 0xdafc778abfd41314, 0x7deb10149c72610f}}, + {{0xcb62af6a8766ee7a, 0x66cbec045553cd0e, 0x588001380f0be4b5, 0x08e68e9ff62ce2ea}}}, +{{{0x34ad500a4bc130ad, 0x8d38db493d0bd49c, 0xa25c3d98500a89be, 0x2f1f3f87eeba3b09}}, + {{0x2f2d09d50ab8f2f9, 0xacb9218dc55923df, 0x4a8f342673766cb9, 0x4cb13bd738f719f5}}, + {{0xf7848c75e515b64a, 0xa59501badb4a9038, 0xc20d313f3f751b50, 0x19a1e353c0ae2ee8}}}, +{{{0x7d1c7560bafa05c3, 0xb3e1a0a0c6e55e61, 0xe3529718c0d66473, 0x41546b11c20c3486}}, + {{0xb42172cdd596bdbd, 0x93e0454398eefc40, 0x9fb15347b44109b5, 0x736bd3990266ae34}}, + {{0x85532d509334b3b4, 0x46fd114b60816573, 0xcc5f5f30425c8375, 0x412295a2b87fab5c}}}, +{{{0x19c99b88f57ed6e9, 0x5393cb266df8c825, 0x5cee3213b30ad273, 0x14e153ebb52d2e34}}, + {{0x2e655261e293eac6, 0x845a92032133acdb, 0x460975cb7900996b, 0x0760bb8d195add80}}, + {{0x413e1a17cde6818a, 0x57156da9ed69a084, 0x2cbf268f46caccb1, 0x6b34be9bc33ac5f2}}}, +{{{0xf3df2f643a78c0b2, 0x4c3e971ef22e027c, 0xec7d1c5e49c1b5a3, 0x2012c18f0922dd2d}}, + {{0x11fc69656571f2d3, 0xc6c9e845530e737a, 0xe33ae7a2d4fe5035, 0x01b9c7b62e6dd30b}}, + {{0x880b55e55ac89d29, 0x1483241f45a0a763, 0x3d36efdfc2e76c1f, 0x08af5b784e4bade8}}}, +{{{0x283499dc881f2533, 0x9d0525da779323b6, 0x897addfb673441f4, 0x32b79d71163a168d}}, + {{0xe27314d289cc2c4b, 0x4be4bd11a287178d, 0x18d528d6fa3364ce, 0x6423c1d5afd9826e}}, + {{0xcc85f8d9edfcb36a, 0x22bcc28f3746e5f9, 0xe49de338f9e5d3cd, 0x480a5efbc13e2dcc}}}, +{{{0x0b51e70b01622071, 0x06b505cf8b1dafc5, 0x2c6bb061ef5aabcd, 0x47aa27600cb7bf31}}, + {{0xb6614ce442ce221f, 0x6e199dcc4c053928, 0x663fb4a4dc1cbe03, 0x24b31d47691c8e06}}, + {{0x2a541eedc015f8c3, 0x11a4fe7e7c693f7c, 0xf0af66134ea278d6, 0x545b585d14dda094}}}, +{{{0x67bf275ea0d43a0f, 0xade68e34089beebe, 0x4289134cd479e72e, 0x0f62f9c332ba5454}}, + {{0x6204e4d0e3b321e1, 0x3baa637a28ff1e95, 0x0b0ccffd5b99bd9e, 0x4d22dc3e64c8d071}}, + {{0xfcb46589d63b5f39, 0x5cae6a3f57cbcf61, 0xfebac2d2953afa05, 0x1c0fa01a36371436}}}, +{{{0xd2c604b622943dff, 0xbc8cbece44cfb3a0, 0x5d254ff397808678, 0x0fa3614f3b1ca6bf}}, + {{0x69082b0e8c936a50, 0xf9c9a035c1dac5b6, 0x6fb73e54c4dfb634, 0x4005419b1d2bc140}}, + {{0xa003febdb9be82f0, 0x2089c1af3a44ac90, 0xf8499f911954fa8e, 0x1fba218aef40ab42}}}, +{{{0xab549448fac8f53e, 0x81f6e89a7ba63741, 0x74fd6c7d6c2b5e01, 0x392e3acaa8c86e42}}, + {{0x4f3e57043e7b0194, 0xa81d3eee08daaf7f, 0xc839c6ab99dcdef1, 0x6c535d13ff7761d5}}, + {{0x4cbd34e93e8a35af, 0x2e0781445887e816, 0x19319c76f29ab0ab, 0x25e17fe4d50ac13b}}}, +{{{0x0a289bd71e04f676, 0x208e1c52d6420f95, 0x5186d8b034691fab, 0x255751442a9fb351}}, + {{0x915f7ff576f121a7, 0xc34a32272fcd87e3, 0xccba2fde4d1be526, 0x6bba828f8969899b}}, + {{0xe2d1bc6690fe3901, 0x4cb54a18a0997ad5, 0x971d6914af8460d4, 0x559d504f7f6b7be4}}}, +{{{0xa7738378b3eb54d5, 0x1d69d366a5553c7c, 0x0a26cf62f92800ba, 0x01ab12d5807e3217}}, + {{0x9c4891e7f6d266fd, 0x0744a19b0307781b, 0x88388f1d6061e23b, 0x123ea6a3354bd50e}}, + {{0x118d189041e32d96, 0xb9ede3c2d8315848, 0x1eab4271d83245d9, 0x4a3961e2c918a154}}}, +{{{0x71dc3be0f8e6bba0, 0xd6cef8347effe30a, 0xa992425fe13a476a, 0x2cd6bce3fb1db763}}, + {{0x0327d644f3233f1e, 0x499a260e34fcf016, 0x83b5a716f2dab979, 0x68aceead9bd4111f}}, + {{0x38b4c90ef3d7c210, 0x308e6e24b7ad040c, 0x3860d9f1b7e73e23, 0x595760d5b508f597}}}, +{{{0x6129bfe104aa6397, 0x8f960008a4a7fccb, 0x3f8bc0897d909458, 0x709fa43edcb291a9}}, + {{0x882acbebfd022790, 0x89af3305c4115760, 0x65f492e37d3473f4, 0x2cb2c5df54515a2b}}, + {{0xeb0a5d8c63fd2aca, 0xd22bc1662e694eff, 0x2723f36ef8cbb03a, 0x70f029ecf0c8131f}}}, +{{{0x461307b32eed3e33, 0xae042f33a45581e7, 0xc94449d3195f0366, 0x0b7d5d8a6c314858}}, + {{0x2a6aafaa5e10b0b9, 0x78f0a370ef041aa9, 0x773efb77aa3ad61f, 0x44eca5a2a74bd9e1}}, + {{0x25d448327b95d543, 0x70d38300a3340f1d, 0xde1c531c60e1c52b, 0x272224512c7de9e4}}}, +{{{0x1abc92af49c5342e, 0xffeed811b2e6fad0, 0xefa28c8dfcc84e29, 0x11b5df18a44cc543}}, + {{0xbf7bbb8a42a975fc, 0x8c5c397796ada358, 0xe27fc76fcdedaa48, 0x19735fd7f6bc20a6}}, + {{0xe3ab90d042c84266, 0xeb848e0f7f19547e, 0x2503a1d065a497b9, 0x0fef911191df895f}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data b/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data new file mode 100644 index 0000000..32a5d47 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data @@ -0,0 +1,96 @@ +{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, + {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, + {{0xabc91205877aaa68, 0x26d9e823ccaac49e, 0x5a1b7dcbdd43598c, 0x6f117b689f0c65a8}}}, +{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, + {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, + {{0x14ae933f0dd0d889, 0x589423221c35da62, 0xd170e5458cf2db4c, 0x5a2826af12b9b4c6}}}, +{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, + {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, + {{0xbcbbdbf1812a8285, 0x270e0807d0bdd1fc, 0xb41b670b1bbda72d, 0x43aabe696b3bb69a}}}, +{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, + {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, + {{0xf1836dc801b8b3a2, 0xb3035f47053ea49a, 0x529c41ba5877adf3, 0x7a9fbb1c6a0f90a7}}}, +{{{0xf36e217e039d8064, 0x98a081b6f520419b, 0x96cbc608e75eb044, 0x49c05a51fadc9c8f}}, + {{0x9b2e678aa6a8632f, 0xa6509e6f51bc46c5, 0xceb233c9c686f5b5, 0x34b9ed338add7f59}}, + {{0x06b4e8bf9045af1b, 0xe2ff83e8a719d22f, 0xaaf6fc2993d4cf16, 0x73c172021b008b06}}}, +{{{0x315f5b0249864348, 0x3ed6b36977088381, 0xa3a075556a8deb95, 0x18ab598029d5c77f}}, + {{0x2fbf00848a802ade, 0xe5d9fecf02302e27, 0x113e847117703406, 0x4275aae2546d8faf}}, + {{0xd82b2cc5fd6089e9, 0x031eb4a13282e4a4, 0x44311199b51a8622, 0x3dc65522b53df948}}}, +{{{0x506f013b327fbf93, 0xaefcebc99b776f6b, 0x9d12b232aaad5968, 0x0267882d176024a7}}, + {{0xbf70c222a2007f6d, 0xbf84b39ab5bcdedb, 0x537a0e12fb07ba07, 0x234fd7eec346f241}}, + {{0x5360a119732ea378, 0x2437e6b1df8dd471, 0xa2ef37f891a7e533, 0x497ba6fdaa097863}}}, +{{{0x040bcd86468ccf0b, 0xd3829ba42a9910d6, 0x7508300807b25192, 0x43b5cd4218d05ebf}}, + {{0x24cecc0313cfeaa0, 0x8648c28d189c246d, 0x2dbdbdfac1f2d4d0, 0x61e22917f12de72b}}, + {{0x5d9a762f9bd0b516, 0xeb38af4e373fdeee, 0x032e5a7d93d64270, 0x511d61210ae4d842}}}, +{{{0x081386484420de87, 0x8a1cf016b592edb4, 0x39fa4e2729942d25, 0x71a7fe6fe2482810}}, + {{0x92c676ef950e9d81, 0xa54620cdc0d7044f, 0xaa9b36646f8f1248, 0x6d325924ddb855e3}}, + {{0x6c7182b8a5c8c854, 0x33fd1479fe5f2a03, 0x72cf591883778d0c, 0x4746c4b6559eeaa9}}}, +{{{0x348546c864741147, 0x7d35aedd0efcc849, 0xff939a760672a332, 0x219663497db5e6d6}}, + {{0xd3777b3c6dc69a2b, 0xdefab2276f89f617, 0x45651cf7b53a16b5, 0x5c9a51de34fe9fb7}}, + {{0xf510f1cf79f10e67, 0xffdddaa1e658515b, 0x09c3a71710142277, 0x4804503c608223bb}}}, +{{{0x3b6821d23a36d175, 0xbbb40aa7e99b9e32, 0x5d9e5ce420838a47, 0x771e098858de4c5e}}, + {{0xc4249ed02ca37fc7, 0xa059a0e3a615acab, 0x88a96ed7c96e0e23, 0x553398a51650696d}}, + {{0x9a12f5d278451edf, 0x3ada5d7985899ccb, 0x477f4a2d9fa59508, 0x5a5ed1d68ff5a611}}}, +{{{0xbae5e0c558527359, 0x392e5c19cadb9d7e, 0x28653c1eda1cabe9, 0x019b60135fefdc44}}, + {{0x1195122afe150e83, 0xcf209a257e4b35d8, 0x7387f8291e711e20, 0x44acb897d8bf92f0}}, + {{0x1e6068145e134b83, 0xc4f5e64f24304c16, 0x506e88a8fc1a3ed7, 0x150c49fde6ad2f92}}}, +{{{0xb849863c9cdca868, 0xc83f44dbb8714ad0, 0xfe3ee3560c36168d, 0x78a6d7791e05fbc1}}, + {{0x8e7bf29509471138, 0x5d6fef394f75a651, 0x10af79c425a708ad, 0x6b2b5a075bb99922}}, + {{0x58bf704b47a0b976, 0xa601b355741748d5, 0xaa2b1fb1d542f590, 0x725c7ffc4ad55d00}}}, +{{{0x91802bf71cd098c0, 0xfe416ca4ed5e6366, 0xdf585d714902994c, 0x4cd54625f855fae7}}, + {{0xe4426715d1cf99b2, 0x7352d51102a20d34, 0x23d1157b8b12109f, 0x794cc9277cb1f3a3}}, + {{0x4af6c426c2ac5053, 0xbc9aedad32f67258, 0x2ad032f10a311021, 0x7008357b6fcc8e85}}}, +{{{0xd01b9fbb82584a34, 0x47ab6463d2b4792b, 0xb631639c48536202, 0x13a92a3669d6d428}}, + {{0x0b88672738773f01, 0xb8ccc8fa95fbccfb, 0x8d2dd5a3b9ad29b6, 0x06ef7e9851ad0f6a}}, + {{0xca93771cc0577de5, 0x7540e41e5035dc5c, 0x24680f01d802e071, 0x3c296ddf8a2af86a}}}, +{{{0xfceb4d2ebb1f2541, 0xb89510c740adb91f, 0xfc71a37dd0a1ad05, 0x0a892c700747717b}}, + {{0xaead15f9d914a713, 0xa92f7bf98c8ff912, 0xaff823179f53d730, 0x7a99d393490c77ba}}, + {{0x8f52ed2436bda3e8, 0x77a8c84157e80794, 0xa5a96563262f9ce0, 0x286762d28302f7d2}}}, +{{{0x7c558e2bce2ef5bd, 0xe4986cb46747bc63, 0x154a179f3bbb89b8, 0x7686f2a3d6f1767a}}, + {{0x4e7836093ce35b25, 0x82e1181db26baa97, 0x0cc192d3cbc7b83f, 0x32f1da046a9d9d3a}}, + {{0xaa8d12a66d597c6a, 0x8f11930304d3852b, 0x3f91dc73c209b022, 0x561305f8a9ad28a6}}}, +{{{0x6722cc28e7b0c0d5, 0x709de9bbdb075c53, 0xcaf68da7d7010a61, 0x030a1aef2c57cc6c}}, + {{0x100c978dec92aed1, 0xca43d5434d6d73e5, 0x83131b22d847ba48, 0x00aaec53e35d4d2c}}, + {{0x7bb1f773003ad2aa, 0x0b3f29802b216608, 0x7821dc86520ed23e, 0x20be9c1c24065480}}}, +{{{0x20e0e44ae2025e60, 0xb03b3b2fcbdcb938, 0x105d639cf95a0d1c, 0x69764c545067e311}}, + {{0xe15387d8249673a6, 0x5943bc2df546e493, 0x1c7f9a81c36f63b5, 0x750ab3361f0ac1de}}, + {{0x1e8a3283a2f81037, 0x6f2eda23bd7fcbf1, 0xb72fd15bac2e2563, 0x54f96b3fb7075040}}}, +{{{0x177dafc616b11ecd, 0x89764b9cfa576479, 0xb7a8a110e6ece785, 0x78e6839fbe85dbf0}}, + {{0x0fadf20429669279, 0x3adda2047d7d724a, 0x6f3d94828c5760f1, 0x3d7fe9c52bb7539e}}, + {{0x70332df737b8856b, 0x75d05d43041a178a, 0x320ff74aa0e59e22, 0x70f268f350088242}}}, +{{{0x2324112070dcf355, 0x380cc97ee7fce117, 0xb31ddeed3552b698, 0x404e56c039b8c4b9}}, + {{0x66864583b1805f47, 0xf535c5d160dd7c19, 0xe9874eb71e4cb006, 0x7c0d345cfad889d9}}, + {{0x591f1f4b8c78338a, 0xa0366ab167e0b5e1, 0x5cbc4152b45f3d44, 0x20d754762aaec777}}}, +{{{0x9d74feb135b9f543, 0x84b37df1de8c956c, 0xe9322b0757138ba9, 0x38b8ada8790b4ce1}}, + {{0x5e8fc36fc73bb758, 0xace543a5363cbb9a, 0xa9934a7d903bc922, 0x2b8f1e46f3ceec62}}, + {{0xb5c04a9cdf51f95d, 0x2b3952aecb1fdeac, 0x1d106d8b328b66da, 0x049aeb32ceba1953}}}, +{{{0xd7767d3c63dcfe7e, 0x209c594897856e40, 0xb6676861e14f7c13, 0x51c665e0c8d625fc}}, + {{0xaa507d0b75fc7931, 0x0fef924b7a6725d3, 0x1d82542b396b3930, 0x795ee17530f674fc}}, + {{0x254a5b0a52ecbd81, 0x5d411f6ee034afe7, 0xe6a24d0dcaee4a31, 0x6cd19bf49dc54477}}}, +{{{0x7e87619052179ca3, 0x571d0a060b2c9f85, 0x80a2baa88499711e, 0x7520f3db40b2e638}}, + {{0x1ffe612165afc386, 0x082a2a88b8d51b10, 0x76f6627e20990baa, 0x5e01b3a7429e43e7}}, + {{0x3db50be3d39357a1, 0x967b6cdd599e94a5, 0x1a309a64df311e6e, 0x71092c9ccef3c986}}}, +{{{0x53d8523f0364918c, 0xa2b404f43fab6b1c, 0x080b4a9e6681e5a4, 0x0ea15b03d0257ba7}}, + {{0x856bd8ac74051dcf, 0x03f6a40855b7aa1e, 0x3a4ae7cbc9743ceb, 0x4173a5bb7137abde}}, + {{0x17c56e31f0f9218a, 0x5a696e2b1afc4708, 0xf7931668f4b2f176, 0x5fc565614a4e3a67}}}, +{{{0x136e570dc46d7ae5, 0x0fd0aacc54f8dc8f, 0x59549f03310dad86, 0x62711c414c454aa1}}, + {{0x4892e1e67790988e, 0x01d5950f1c5cd722, 0xe3b0819ae5923eed, 0x3214c7409d46651b}}, + {{0x1329827406651770, 0x3ba4a0668a279436, 0xd9b6b8ec185d223c, 0x5bea94073ecb833c}}}, +{{{0x641dbf0912c89be4, 0xacf38b317d6e579c, 0xabfe9e02f697b065, 0x3aacd5c148f61eec}}, + {{0xb470ce63f343d2f8, 0x0067ba8f0543e8f1, 0x35da51a1a2117b6f, 0x4ad0785944f1bd2f}}, + {{0x858e3b34c3318301, 0xdc99c04707316826, 0x34085b2ed39da88c, 0x3aff0cb1d902853d}}}, +{{{0x87c5c7eb3a20405e, 0x8ee311efedad56c9, 0x29252e48ad29d5f9, 0x110e7e86f4cd251d}}, + {{0x9226430bf4c53505, 0x68e49c13261f2283, 0x09ef33788fd327c6, 0x2ccf9f732bd99e7f}}, + {{0x57c0d89ed603f5e4, 0x12888628f0b0200c, 0x53172709a02e3bb7, 0x05c557e0b9693a37}}}, +{{{0xd8f9ce311fc97e6f, 0x7a3f263011f9fdae, 0xe15b7ea08bed25dd, 0x6e154c178fe9875a}}, + {{0xf776bbb089c20eb0, 0x61f85bf6fa0fd85c, 0xb6b93f4e634421fb, 0x289fef0841861205}}, + {{0xcf616336fed69abf, 0x9b16e4e78335c94f, 0x13789765753a7fe7, 0x6afbf642a95ca319}}}, +{{{0x7da8de0c62f5d2c1, 0x98fc3da4b00e7b9a, 0x7deb6ada0dad70e0, 0x0db4b851b95038c4}}, + {{0x5de55070f913a8cc, 0x7d1d167b2b0cf561, 0xda2956b690ead489, 0x12c093cedb801ed9}}, + {{0xfc147f9308b8190f, 0x06969da0a11ae310, 0xcee75572dac7d7fd, 0x33aa8799c6635ce6}}}, +{{{0xaf0ff51ebd085cf2, 0x78f51a8967d33f1f, 0x6ec2bfe15060033c, 0x233c6f29e8e21a86}}, + {{0x8348f588fc156cb1, 0x6da2ba9b1a0a6d27, 0xe2262d5c87ca5ab6, 0x212cd0c1c8d589a6}}, + {{0xd2f4d5107f18c781, 0x122ecdf2527e9d28, 0xa70a862a3d3d3341, 0x1db7778911914ce3}}}, +{{{0xddf352397c6bc26f, 0x7a97e2cc53d50113, 0x7c74f43abf79a330, 0x31ad97ad26e2adfc}}, + {{0xb3394769dd701ab6, 0xe2b8ded419cf8da5, 0x15df4161fd2ac852, 0x7ae2ca8a017d24be}}, + {{0xb7e817ed0920b962, 0x1e8518cc3f19da9d, 0xe491c14f25560a64, 0x1ed1fc53a6622c83}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s b/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s new file mode 100644 index 0000000..265daf0 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s @@ -0,0 +1,2975 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: int64 a0 + +# qhasm: int64 a1 + +# qhasm: int64 a2 + +# qhasm: int64 a3 + +# qhasm: stack64 a0_stack + +# qhasm: stack64 a1_stack + +# qhasm: stack64 a2_stack + +# qhasm: stack64 a3_stack + +# qhasm: int64 b0 + +# qhasm: int64 b1 + +# qhasm: int64 b2 + +# qhasm: int64 b3 + +# qhasm: stack64 b0_stack + +# qhasm: stack64 b1_stack + +# qhasm: stack64 b2_stack + +# qhasm: stack64 b3_stack + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: stack64 c0_stack + +# qhasm: stack64 c1_stack + +# qhasm: stack64 c2_stack + +# qhasm: stack64 c3_stack + +# qhasm: int64 d0 + +# qhasm: int64 d1 + +# qhasm: int64 d2 + +# qhasm: int64 d3 + +# qhasm: stack64 d0_stack + +# qhasm: stack64 d1_stack + +# qhasm: stack64 d2_stack + +# qhasm: stack64 d3_stack + +# qhasm: int64 e0 + +# qhasm: int64 e1 + +# qhasm: int64 e2 + +# qhasm: int64 e3 + +# qhasm: stack64 e0_stack + +# qhasm: stack64 e1_stack + +# qhasm: stack64 e2_stack + +# qhasm: stack64 e3_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: stack64 rx0_stack + +# qhasm: stack64 rx1_stack + +# qhasm: stack64 rx2_stack + +# qhasm: stack64 rx3_stack + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 ry4 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: int64 squarer4 + +# qhasm: int64 squarer5 + +# qhasm: int64 squarer6 + +# qhasm: int64 squarer7 + +# qhasm: int64 squarer8 + +# qhasm: int64 squarerax + +# qhasm: int64 squarerdx + +# qhasm: int64 squaret1 + +# qhasm: int64 squaret2 + +# qhasm: int64 squaret3 + +# qhasm: int64 squarec + +# qhasm: int64 squarezero + +# qhasm: int64 squarei38 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 +.globl crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 +_crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1: +crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1: +mov %rsp,%r11 +and $31,%r11 +add $192,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarerax = *(uint64 *)(pp + 8) +# asm 1: movq 8(squarerax=int64#7 +# asm 2: movq 8(squarerax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) +# asm 1: mulq 0(a1=int64#5 +# asm 2: mov a1=%r8 +mov %rax,%r8 + +# qhasm: a2 = squarerdx +# asm 1: mov a2=int64#6 +# asm 2: mov a2=%r9 +mov %rdx,%r9 + +# qhasm: squarerax = *(uint64 *)(pp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) +# asm 1: mulq 8(a3=int64#8 +# asm 2: mov a3=%r10 +mov %rax,%r10 + +# qhasm: squarer4 = squarerdx +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rdx,%r11 + +# qhasm: squarerax = *(uint64 *)(pp + 24) +# asm 1: movq 24(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 16) +# asm 1: mulq 16(squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rax,%r12 + +# qhasm: squarer6 = squarerdx +# asm 1: mov squarer6=int64#11 +# asm 2: mov squarer6=%r13 +mov %rdx,%r13 + +# qhasm: squarerax = *(uint64 *)(pp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) +# asm 1: mulq 0(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) +# asm 1: mulq 8(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) +# asm 1: mulq 0(squarerax=int64#7 +# asm 2: movq 0(squarerax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) +# asm 1: mulq 0(a0=int64#12 +# asm 2: mov a0=%r14 +mov %rax,%r14 + +# qhasm: squaret1 = squarerdx +# asm 1: mov squaret1=int64#13 +# asm 2: mov squaret1=%r15 +mov %rdx,%r15 + +# qhasm: squarerax = *(uint64 *)(pp + 8) +# asm 1: movq 8(squarerax=int64#7 +# asm 2: movq 8(squarerax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) +# asm 1: mulq 8(squaret2=int64#14 +# asm 2: mov squaret2=%rbx +mov %rax,%rbx + +# qhasm: squaret3 = squarerdx +# asm 1: mov squaret3=int64#15 +# asm 2: mov squaret3=%rbp +mov %rdx,%rbp + +# qhasm: squarerax = *(uint64 *)(pp + 16) +# asm 1: movq 16(squarerax=int64#7 +# asm 2: movq 16(squarerax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 16) +# asm 1: mulq 16(squarerax=int64#7 +# asm 2: movq 24(squarerax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 24) +# asm 1: mulq 24(squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r11,%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: squarer4 = squarerax +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rax,%r11 + +# qhasm: squarerax = squarer5 +# asm 1: mov squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r12,%rax + +# qhasm: squarer5 = squarerdx +# asm 1: mov squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rdx,%r12 + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? squarer5 += squarerax +# asm 1: add squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r13,%rax + +# qhasm: squarer6 = 0 +# asm 1: mov $0,>squarer6=int64#11 +# asm 2: mov $0,>squarer6=%r13 +mov $0,%r13 + +# qhasm: squarer6 += squarerdx + carry +# asm 1: adc squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %rcx,%rax + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarer7 += squarerdx + carry +# asm 1: adc squarer8=int64#7 +# asm 2: mov $0,>squarer8=%rax +mov $0,%rax + +# qhasm: squarer8 += squarerdx + carry +# asm 1: adc squarezero=int64#3 +# asm 2: mov $0,>squarezero=%rdx +mov $0,%rdx + +# qhasm: squarer8 += squarezero + carry +# asm 1: adc squarer8=int64#4 +# asm 2: imulq $38,squarer8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? a0 += squarer8 +# asm 1: add squarezero=int64#3 +# asm 2: imulq $38,squarezero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: a0 += squarezero +# asm 1: add a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %r14,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r8,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r9,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %r10,80(%rsp) + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarerax = *(uint64 *)(pp + 40) +# asm 1: movq 40(squarerax=int64#7 +# asm 2: movq 40(squarerax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) +# asm 1: mulq 32(b1=int64#5 +# asm 2: mov b1=%r8 +mov %rax,%r8 + +# qhasm: b2 = squarerdx +# asm 1: mov b2=int64#6 +# asm 2: mov b2=%r9 +mov %rdx,%r9 + +# qhasm: squarerax = *(uint64 *)(pp + 48) +# asm 1: movq 48(squarerax=int64#7 +# asm 2: movq 48(squarerax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) +# asm 1: mulq 40(b3=int64#8 +# asm 2: mov b3=%r10 +mov %rax,%r10 + +# qhasm: squarer4 = squarerdx +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rdx,%r11 + +# qhasm: squarerax = *(uint64 *)(pp + 56) +# asm 1: movq 56(squarerax=int64#7 +# asm 2: movq 56(squarerax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 48) +# asm 1: mulq 48(squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rax,%r12 + +# qhasm: squarer6 = squarerdx +# asm 1: mov squarer6=int64#11 +# asm 2: mov squarer6=%r13 +mov %rdx,%r13 + +# qhasm: squarerax = *(uint64 *)(pp + 48) +# asm 1: movq 48(squarerax=int64#7 +# asm 2: movq 48(squarerax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) +# asm 1: mulq 32(squarerax=int64#7 +# asm 2: movq 56(squarerax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) +# asm 1: mulq 40(squarerax=int64#7 +# asm 2: movq 56(squarerax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) +# asm 1: mulq 32(squarerax=int64#7 +# asm 2: movq 32(squarerax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) +# asm 1: mulq 32(b0=int64#12 +# asm 2: mov b0=%r14 +mov %rax,%r14 + +# qhasm: squaret1 = squarerdx +# asm 1: mov squaret1=int64#13 +# asm 2: mov squaret1=%r15 +mov %rdx,%r15 + +# qhasm: squarerax = *(uint64 *)(pp + 40) +# asm 1: movq 40(squarerax=int64#7 +# asm 2: movq 40(squarerax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) +# asm 1: mulq 40(squaret2=int64#14 +# asm 2: mov squaret2=%rbx +mov %rax,%rbx + +# qhasm: squaret3 = squarerdx +# asm 1: mov squaret3=int64#15 +# asm 2: mov squaret3=%rbp +mov %rdx,%rbp + +# qhasm: squarerax = *(uint64 *)(pp + 48) +# asm 1: movq 48(squarerax=int64#7 +# asm 2: movq 48(squarerax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 48) +# asm 1: mulq 48(squarerax=int64#7 +# asm 2: movq 56(squarerax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 56) +# asm 1: mulq 56(squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r11,%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: squarer4 = squarerax +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rax,%r11 + +# qhasm: squarerax = squarer5 +# asm 1: mov squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r12,%rax + +# qhasm: squarer5 = squarerdx +# asm 1: mov squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rdx,%r12 + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? squarer5 += squarerax +# asm 1: add squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r13,%rax + +# qhasm: squarer6 = 0 +# asm 1: mov $0,>squarer6=int64#11 +# asm 2: mov $0,>squarer6=%r13 +mov $0,%r13 + +# qhasm: squarer6 += squarerdx + carry +# asm 1: adc squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %rcx,%rax + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarer7 += squarerdx + carry +# asm 1: adc squarer8=int64#7 +# asm 2: mov $0,>squarer8=%rax +mov $0,%rax + +# qhasm: squarer8 += squarerdx + carry +# asm 1: adc squarezero=int64#3 +# asm 2: mov $0,>squarezero=%rdx +mov $0,%rdx + +# qhasm: squarer8 += squarezero + carry +# asm 1: adc squarer8=int64#4 +# asm 2: imulq $38,squarer8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? b0 += squarer8 +# asm 1: add squarezero=int64#3 +# asm 2: imulq $38,squarezero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: b0 += squarezero +# asm 1: add b0_stack=stack64#12 +# asm 2: movq b0_stack=88(%rsp) +movq %r14,88(%rsp) + +# qhasm: b1_stack = b1 +# asm 1: movq b1_stack=stack64#13 +# asm 2: movq b1_stack=96(%rsp) +movq %r8,96(%rsp) + +# qhasm: b2_stack = b2 +# asm 1: movq b2_stack=stack64#14 +# asm 2: movq b2_stack=104(%rsp) +movq %r9,104(%rsp) + +# qhasm: b3_stack = b3 +# asm 1: movq b3_stack=stack64#15 +# asm 2: movq b3_stack=112(%rsp) +movq %r10,112(%rsp) + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarerax = *(uint64 *)(pp + 72) +# asm 1: movq 72(squarerax=int64#7 +# asm 2: movq 72(squarerax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) +# asm 1: mulq 64(c1=int64#5 +# asm 2: mov c1=%r8 +mov %rax,%r8 + +# qhasm: c2 = squarerdx +# asm 1: mov c2=int64#6 +# asm 2: mov c2=%r9 +mov %rdx,%r9 + +# qhasm: squarerax = *(uint64 *)(pp + 80) +# asm 1: movq 80(squarerax=int64#7 +# asm 2: movq 80(squarerax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) +# asm 1: mulq 72(c3=int64#8 +# asm 2: mov c3=%r10 +mov %rax,%r10 + +# qhasm: squarer4 = squarerdx +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rdx,%r11 + +# qhasm: squarerax = *(uint64 *)(pp + 88) +# asm 1: movq 88(squarerax=int64#7 +# asm 2: movq 88(squarerax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 80) +# asm 1: mulq 80(squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rax,%r12 + +# qhasm: squarer6 = squarerdx +# asm 1: mov squarer6=int64#11 +# asm 2: mov squarer6=%r13 +mov %rdx,%r13 + +# qhasm: squarerax = *(uint64 *)(pp + 80) +# asm 1: movq 80(squarerax=int64#7 +# asm 2: movq 80(squarerax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) +# asm 1: mulq 64(squarerax=int64#7 +# asm 2: movq 88(squarerax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) +# asm 1: mulq 72(squarerax=int64#7 +# asm 2: movq 88(squarerax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) +# asm 1: mulq 64(squarerax=int64#7 +# asm 2: movq 64(squarerax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) +# asm 1: mulq 64(c0=int64#12 +# asm 2: mov c0=%r14 +mov %rax,%r14 + +# qhasm: squaret1 = squarerdx +# asm 1: mov squaret1=int64#13 +# asm 2: mov squaret1=%r15 +mov %rdx,%r15 + +# qhasm: squarerax = *(uint64 *)(pp + 72) +# asm 1: movq 72(squarerax=int64#7 +# asm 2: movq 72(squarerax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) +# asm 1: mulq 72(squaret2=int64#14 +# asm 2: mov squaret2=%rbx +mov %rax,%rbx + +# qhasm: squaret3 = squarerdx +# asm 1: mov squaret3=int64#15 +# asm 2: mov squaret3=%rbp +mov %rdx,%rbp + +# qhasm: squarerax = *(uint64 *)(pp + 80) +# asm 1: movq 80(squarerax=int64#7 +# asm 2: movq 80(squarerax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 80) +# asm 1: mulq 80(squarerax=int64#7 +# asm 2: movq 88(squarerax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 88) +# asm 1: mulq 88(squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r11,%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: squarer4 = squarerax +# asm 1: mov squarer4=int64#9 +# asm 2: mov squarer4=%r11 +mov %rax,%r11 + +# qhasm: squarerax = squarer5 +# asm 1: mov squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r12,%rax + +# qhasm: squarer5 = squarerdx +# asm 1: mov squarer5=int64#10 +# asm 2: mov squarer5=%r12 +mov %rdx,%r12 + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? squarer5 += squarerax +# asm 1: add squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r13,%rax + +# qhasm: squarer6 = 0 +# asm 1: mov $0,>squarer6=int64#11 +# asm 2: mov $0,>squarer6=%r13 +mov $0,%r13 + +# qhasm: squarer6 += squarerdx + carry +# asm 1: adc squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %rcx,%rax + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#4 +# asm 2: mov $0,>squarer7=%rcx +mov $0,%rcx + +# qhasm: squarer7 += squarerdx + carry +# asm 1: adc squarer8=int64#7 +# asm 2: mov $0,>squarer8=%rax +mov $0,%rax + +# qhasm: squarer8 += squarerdx + carry +# asm 1: adc squarezero=int64#3 +# asm 2: mov $0,>squarezero=%rdx +mov $0,%rdx + +# qhasm: squarer8 += squarezero + carry +# asm 1: adc squarer8=int64#4 +# asm 2: imulq $38,squarer8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? c0 += squarer8 +# asm 1: add squarezero=int64#3 +# asm 2: imulq $38,squarezero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: c0 += squarezero +# asm 1: add addt0=int64#3 +# asm 2: mov $0,>addt0=%rdx +mov $0,%rdx + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#4 +# asm 2: mov $38,>addt1=%rcx +mov $38,%rcx + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae c0_stack=stack64#16 +# asm 2: movq c0_stack=120(%rsp) +movq %r14,120(%rsp) + +# qhasm: c1_stack = c1 +# asm 1: movq c1_stack=stack64#17 +# asm 2: movq c1_stack=128(%rsp) +movq %r8,128(%rsp) + +# qhasm: c2_stack = c2 +# asm 1: movq c2_stack=stack64#18 +# asm 2: movq c2_stack=136(%rsp) +movq %r9,136(%rsp) + +# qhasm: c3_stack = c3 +# asm 1: movq c3_stack=stack64#19 +# asm 2: movq c3_stack=144(%rsp) +movq %r10,144(%rsp) + +# qhasm: d0 = 0 +# asm 1: mov $0,>d0=int64#3 +# asm 2: mov $0,>d0=%rdx +mov $0,%rdx + +# qhasm: d1 = 0 +# asm 1: mov $0,>d1=int64#4 +# asm 2: mov $0,>d1=%rcx +mov $0,%rcx + +# qhasm: d2 = 0 +# asm 1: mov $0,>d2=int64#5 +# asm 2: mov $0,>d2=%r8 +mov $0,%r8 + +# qhasm: d3 = 0 +# asm 1: mov $0,>d3=int64#6 +# asm 2: mov $0,>d3=%r9 +mov $0,%r9 + +# qhasm: carry? d0 -= a0_stack +# asm 1: subq subt0=int64#7 +# asm 2: mov $0,>subt0=%rax +mov $0,%rax + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#8 +# asm 2: mov $38,>subt1=%r10 +mov $38,%r10 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae d0_stack=stack64#8 +# asm 2: movq d0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: d1_stack = d1 +# asm 1: movq d1_stack=stack64#9 +# asm 2: movq d1_stack=64(%rsp) +movq %rcx,64(%rsp) + +# qhasm: d2_stack = d2 +# asm 1: movq d2_stack=stack64#10 +# asm 2: movq d2_stack=72(%rsp) +movq %r8,72(%rsp) + +# qhasm: d3_stack = d3 +# asm 1: movq d3_stack=stack64#11 +# asm 2: movq d3_stack=80(%rsp) +movq %r9,80(%rsp) + +# qhasm: e0 = 0 +# asm 1: mov $0,>e0=int64#7 +# asm 2: mov $0,>e0=%rax +mov $0,%rax + +# qhasm: e1 = 0 +# asm 1: mov $0,>e1=int64#8 +# asm 2: mov $0,>e1=%r10 +mov $0,%r10 + +# qhasm: e2 = 0 +# asm 1: mov $0,>e2=int64#9 +# asm 2: mov $0,>e2=%r11 +mov $0,%r11 + +# qhasm: e3 = 0 +# asm 1: mov $0,>e3=int64#10 +# asm 2: mov $0,>e3=%r12 +mov $0,%r12 + +# qhasm: carry? e0 -= b0_stack +# asm 1: subq subt0=int64#11 +# asm 2: mov $0,>subt0=%r13 +mov $0,%r13 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#12 +# asm 2: mov $38,>subt1=%r14 +mov $38,%r14 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae e0_stack=stack64#20 +# asm 2: movq e0_stack=152(%rsp) +movq %rax,152(%rsp) + +# qhasm: e1_stack = e1 +# asm 1: movq e1_stack=stack64#21 +# asm 2: movq e1_stack=160(%rsp) +movq %r10,160(%rsp) + +# qhasm: e2_stack = e2 +# asm 1: movq e2_stack=stack64#22 +# asm 2: movq e2_stack=168(%rsp) +movq %r11,168(%rsp) + +# qhasm: e3_stack = e3 +# asm 1: movq e3_stack=stack64#23 +# asm 2: movq e3_stack=176(%rsp) +movq %r12,176(%rsp) + +# qhasm: rz0 = d0 +# asm 1: mov rz0=int64#7 +# asm 2: mov rz0=%rax +mov %rdx,%rax + +# qhasm: rz1 = d1 +# asm 1: mov rz1=int64#8 +# asm 2: mov rz1=%r10 +mov %rcx,%r10 + +# qhasm: rz2 = d2 +# asm 1: mov rz2=int64#9 +# asm 2: mov rz2=%r11 +mov %r8,%r11 + +# qhasm: rz3 = d3 +# asm 1: mov rz3=int64#10 +# asm 2: mov rz3=%r12 +mov %r9,%r12 + +# qhasm: carry? rz0 += b0_stack +# asm 1: addq addt0=int64#11 +# asm 2: mov $0,>addt0=%r13 +mov $0,%r13 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#12 +# asm 2: mov $38,>addt1=%r14 +mov $38,%r14 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae subt0=int64#11 +# asm 2: mov $0,>subt0=%r13 +mov $0,%r13 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#12 +# asm 2: mov $38,>subt1=%r14 +mov $38,%r14 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae subt0=int64#3 +# asm 2: mov $0,>subt0=%rdx +mov $0,%rdx + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#4 +# asm 2: mov $38,>subt1=%rcx +mov $38,%rcx + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae rx0=int64#3 +# asm 2: movq 0(rx0=%rdx +movq 0(%rsi),%rdx + +# qhasm: rx1 = *(uint64 *)(pp + 8) +# asm 1: movq 8(rx1=int64#4 +# asm 2: movq 8(rx1=%rcx +movq 8(%rsi),%rcx + +# qhasm: rx2 = *(uint64 *)(pp + 16) +# asm 1: movq 16(rx2=int64#5 +# asm 2: movq 16(rx2=%r8 +movq 16(%rsi),%r8 + +# qhasm: rx3 = *(uint64 *)(pp + 24) +# asm 1: movq 24(rx3=int64#6 +# asm 2: movq 24(rx3=%r9 +movq 24(%rsi),%r9 + +# qhasm: carry? rx0 += *(uint64 *)(pp + 32) +# asm 1: addq 32(addt0=int64#2 +# asm 2: mov $0,>addt0=%rsi +mov $0,%rsi + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae rx0_stack=stack64#12 +# asm 2: movq rx0_stack=88(%rsp) +movq %rdx,88(%rsp) + +# qhasm: rx1_stack = rx1 +# asm 1: movq rx1_stack=stack64#13 +# asm 2: movq rx1_stack=96(%rsp) +movq %rcx,96(%rsp) + +# qhasm: rx2_stack = rx2 +# asm 1: movq rx2_stack=stack64#14 +# asm 2: movq rx2_stack=104(%rsp) +movq %r8,104(%rsp) + +# qhasm: rx3_stack = rx3 +# asm 1: movq rx3_stack=stack64#15 +# asm 2: movq rx3_stack=112(%rsp) +movq %r9,112(%rsp) + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#2 +# asm 2: mov $0,>squarer7=%rsi +mov $0,%rsi + +# qhasm: squarerax = rx1_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 96(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack +# asm 1: mulq rx1=int64#4 +# asm 2: mov rx1=%rcx +mov %rax,%rcx + +# qhasm: rx2 = squarerdx +# asm 1: mov rx2=int64#5 +# asm 2: mov rx2=%r8 +mov %rdx,%r8 + +# qhasm: squarerax = rx2_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 104(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack +# asm 1: mulq rx3=int64#6 +# asm 2: mov rx3=%r9 +mov %rax,%r9 + +# qhasm: squarer4 = squarerdx +# asm 1: mov squarer4=int64#8 +# asm 2: mov squarer4=%r10 +mov %rdx,%r10 + +# qhasm: squarerax = rx3_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 112(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx2_stack +# asm 1: mulq squarer5=int64#9 +# asm 2: mov squarer5=%r11 +mov %rax,%r11 + +# qhasm: squarer6 = squarerdx +# asm 1: mov squarer6=int64#10 +# asm 2: mov squarer6=%r12 +mov %rdx,%r12 + +# qhasm: squarerax = rx2_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 104(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack +# asm 1: mulq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 112(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack +# asm 1: mulq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 112(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack +# asm 1: mulq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 88(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack +# asm 1: mulq rx0=int64#11 +# asm 2: mov rx0=%r13 +mov %rax,%r13 + +# qhasm: squaret1 = squarerdx +# asm 1: mov squaret1=int64#12 +# asm 2: mov squaret1=%r14 +mov %rdx,%r14 + +# qhasm: squarerax = rx1_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 96(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack +# asm 1: mulq squaret2=int64#13 +# asm 2: mov squaret2=%r15 +mov %rax,%r15 + +# qhasm: squaret3 = squarerdx +# asm 1: mov squaret3=int64#14 +# asm 2: mov squaret3=%rbx +mov %rdx,%rbx + +# qhasm: squarerax = rx2_stack +# asm 1: movq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 104(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx2_stack +# asm 1: mulq squarerax=int64#7 +# asm 2: movq squarerax=%rax +movq 112(%rsp),%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * rx3_stack +# asm 1: mulq squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r10,%rax + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: squarer4 = squarerax +# asm 1: mov squarer4=int64#8 +# asm 2: mov squarer4=%r10 +mov %rax,%r10 + +# qhasm: squarerax = squarer5 +# asm 1: mov squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r11,%rax + +# qhasm: squarer5 = squarerdx +# asm 1: mov squarer5=int64#9 +# asm 2: mov squarer5=%r11 +mov %rdx,%r11 + +# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? squarer5 += squarerax +# asm 1: add squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %r12,%rax + +# qhasm: squarer6 = 0 +# asm 1: mov $0,>squarer6=int64#10 +# asm 2: mov $0,>squarer6=%r12 +mov $0,%r12 + +# qhasm: squarer6 += squarerdx + carry +# asm 1: adc squarerax=int64#7 +# asm 2: mov squarerax=%rax +mov %rsi,%rax + +# qhasm: squarer7 = 0 +# asm 1: mov $0,>squarer7=int64#2 +# asm 2: mov $0,>squarer7=%rsi +mov $0,%rsi + +# qhasm: squarer7 += squarerdx + carry +# asm 1: adc squarer8=int64#7 +# asm 2: mov $0,>squarer8=%rax +mov $0,%rax + +# qhasm: squarer8 += squarerdx + carry +# asm 1: adc squarezero=int64#2 +# asm 2: mov $0,>squarezero=%rsi +mov $0,%rsi + +# qhasm: squarer8 += squarezero + carry +# asm 1: adc squarer8=int64#3 +# asm 2: imulq $38,squarer8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rx0 += squarer8 +# asm 1: add squarezero=int64#2 +# asm 2: imulq $38,squarezero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rx0 += squarezero +# asm 1: add addt0=int64#2 +# asm 2: mov $0,>addt0=%rsi +mov $0,%rsi + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#3 +# asm 2: mov $38,>addt1=%rdx +mov $38,%rdx + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae addt0=int64#2 +# asm 2: mov $0,>addt0=%rsi +mov $0,%rsi + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#3 +# asm 2: mov $38,>addt1=%rdx +mov $38,%rdx + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_double.c b/ext/ed25519-amd64-asm/ge25519_double.c new file mode 100644 index 0000000..d55e2b4 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_double.c @@ -0,0 +1,8 @@ +#include "ge25519.h" + +void ge25519_double(ge25519_p3 *r, const ge25519_p3 *p) +{ + ge25519_p1p1 grp1p1; + ge25519_dbl_p1p1(&grp1p1, (ge25519_p2 *)p); + ge25519_p1p1_to_p3(r, &grp1p1); +} diff --git a/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c b/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c new file mode 100644 index 0000000..30c922a --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c @@ -0,0 +1,102 @@ +#include "fe25519.h" +#include "sc25519.h" +#include "ge25519.h" + +#define S1_SWINDOWSIZE 5 +#define PRE1_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define PRE2_SIZE (1<<(S2_SWINDOWSIZE-2)) + +ge25519_niels pre2[PRE2_SIZE] = { +#include "ge25519_base_slide_multiples.data" +}; + +static const fe25519 ec2d = {{0xEBD69B9426B2F146, 0x00E0149A8283B156, 0x198E80F2EEF3D130, 0xA406D9DC56DFFCE7}}; + +static void setneutral(ge25519 *r) +{ + fe25519_setint(&r->x,0); + fe25519_setint(&r->y,1); + fe25519_setint(&r->z,1); + fe25519_setint(&r->t,0); +} + +/* computes [s1]p1 + [s2]p2 */ +void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const sc25519 *s2) +{ + signed char slide1[256], slide2[256]; + ge25519_pniels pre1[PRE1_SIZE], neg; + ge25519_p3 d1; + ge25519_p1p1 t; + ge25519_niels nneg; + fe25519 d; + int i; + + sc25519_slide(slide1, s1, S1_SWINDOWSIZE); + sc25519_slide(slide2, s2, S2_SWINDOWSIZE); + + /* precomputation */ + pre1[0] = *(ge25519_pniels *)p1; + ge25519_dbl_p1p1(&t,(ge25519_p2 *)pre1); ge25519_p1p1_to_p3(&d1, &t); + /* Convert pre[0] to projective Niels representation */ + d = pre1[0].ysubx; + fe25519_sub(&pre1[0].ysubx, &pre1[0].xaddy, &pre1[0].ysubx); + fe25519_add(&pre1[0].xaddy, &pre1[0].xaddy, &d); + fe25519_mul(&pre1[0].t2d, &pre1[0].t2d, &ec2d); + + for(i=0;i= 0;--i) { + if (slide1[i] || slide2[i]) goto firstbit; + } + + for(;i>=0;i--) + { + firstbit: + + ge25519_dbl_p1p1(&t, (ge25519_p2 *)r); + + if(slide1[i]>0) + { + ge25519_p1p1_to_p3(r, &t); + ge25519_pnielsadd_p1p1(&t, r, &pre1[slide1[i]/2]); + } + else if(slide1[i]<0) + { + ge25519_p1p1_to_p3(r, &t); + neg = pre1[-slide1[i]/2]; + d = neg.ysubx; + neg.ysubx = neg.xaddy; + neg.xaddy = d; + fe25519_neg(&neg.t2d, &neg.t2d); + ge25519_pnielsadd_p1p1(&t, r, &neg); + } + + if(slide2[i]>0) + { + ge25519_p1p1_to_p3(r, &t); + ge25519_nielsadd_p1p1(&t, r, &pre2[slide2[i]/2]); + } + else if(slide2[i]<0) + { + ge25519_p1p1_to_p3(r, &t); + nneg = pre2[-slide2[i]/2]; + d = nneg.ysubx; + nneg.ysubx = nneg.xaddy; + nneg.xaddy = d; + fe25519_neg(&nneg.t2d, &nneg.t2d); + ge25519_nielsadd_p1p1(&t, r, &nneg); + } + + ge25519_p1p1_to_p2((ge25519_p2 *)r, &t); + } +} diff --git a/ext/ed25519-amd64-asm/ge25519_isneutral.c b/ext/ed25519-amd64-asm/ge25519_isneutral.c new file mode 100644 index 0000000..cf566db --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_isneutral.c @@ -0,0 +1,9 @@ +#include "fe25519.h" +#include "ge25519.h" + +int ge25519_isneutral_vartime(const ge25519_p3 *p) +{ + if(!fe25519_iszero_vartime(&p->x)) return 0; + if(!fe25519_iseq_vartime(&p->y, &p->z)) return 0; + return 1; +} diff --git a/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c b/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c new file mode 100644 index 0000000..afc6aea --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c @@ -0,0 +1,102 @@ +#include "fe25519.h" +#include "sc25519.h" +#include "ge25519.h" +#include "index_heap.h" + +static void setneutral(ge25519 *r) +{ + fe25519_setint(&r->x,0); + fe25519_setint(&r->y,1); + fe25519_setint(&r->z,1); + fe25519_setint(&r->t,0); +} + +static void ge25519_scalarmult_vartime_2limbs(ge25519 *r, ge25519 *p, sc25519 *s) +{ + if (s->v[1] == 0 && s->v[0] == 1) /* This will happen most of the time after Bos-Coster */ + *r = *p; + else if (s->v[1] == 0 && s->v[0] == 0) /* This won't ever happen, except for all scalars == 0 in Bos-Coster */ + setneutral(r); + else + { + ge25519 d; + unsigned long long mask = (1ULL << 63); + int i = 1; + while(!(mask & s->v[1]) && mask != 0) + mask >>= 1; + if(mask == 0) + { + mask = (1ULL << 63); + i = 0; + while(!(mask & s->v[0]) && mask != 0) + mask >>= 1; + } + d = *p; + mask >>= 1; + for(;mask != 0;mask >>= 1) + { + ge25519_double(&d,&d); + if(s->v[i] & mask) + ge25519_add(&d,&d,p); + } + if(i==1) + { + mask = (1ULL << 63); + for(;mask != 0;mask >>= 1) + { + ge25519_double(&d,&d); + if(s->v[0] & mask) + ge25519_add(&d,&d,p); + } + } + *r = d; + } +} + +/* caller's responsibility to ensure npoints >= 5 */ +void ge25519_multi_scalarmult_vartime(ge25519_p3 *r, ge25519_p3 *p, sc25519 *s, const unsigned long long npoints) +{ + unsigned long long pos[npoints]; + unsigned long long hlen=((npoints+1)/2)|1; + unsigned long long max1, max2,i; + + heap_init(pos, hlen, s); + + for(i=0;;i++) + { + heap_get2max(pos, &max1, &max2, s); + if((s[max1].v[3] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; + sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); + ge25519_add(&p[max2],&p[max2],&p[max1]); + heap_rootreplaced(pos, hlen, s); + } + for(;;i++) + { + heap_get2max(pos, &max1, &max2, s); + if((s[max1].v[2] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; + sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); + ge25519_add(&p[max2],&p[max2],&p[max1]); + heap_rootreplaced_3limbs(pos, hlen, s); + } + /* We know that (npoints-1)/2 scalars are only 128-bit scalars */ + heap_extend(pos, hlen, npoints, s); + hlen = npoints; + for(;;i++) + { + heap_get2max(pos, &max1, &max2, s); + if((s[max1].v[1] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; + sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); + ge25519_add(&p[max2],&p[max2],&p[max1]); + heap_rootreplaced_2limbs(pos, hlen, s); + } + for(;;i++) + { + heap_get2max(pos, &max1, &max2, s); + if(sc25519_iszero_vartime(&s[max2])) break; + sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); + ge25519_add(&p[max2],&p[max2],&p[max1]); + heap_rootreplaced_1limb(pos, hlen, s); + } + + ge25519_scalarmult_vartime_2limbs(r, &p[max1], &s[max1]); +} diff --git a/ext/ed25519-amd64-asm/ge25519_nielsadd2.s b/ext/ed25519-amd64-asm/ge25519_nielsadd2.s new file mode 100644 index 0000000..19d71f1 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_nielsadd2.s @@ -0,0 +1,5791 @@ + +# qhasm: int64 rp + +# qhasm: int64 qp + +# qhasm: input rp + +# qhasm: input qp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 a0 + +# qhasm: int64 a1 + +# qhasm: int64 a2 + +# qhasm: int64 a3 + +# qhasm: stack64 a0_stack + +# qhasm: stack64 a1_stack + +# qhasm: stack64 a2_stack + +# qhasm: stack64 a3_stack + +# qhasm: int64 b0 + +# qhasm: int64 b1 + +# qhasm: int64 b2 + +# qhasm: int64 b3 + +# qhasm: stack64 b0_stack + +# qhasm: stack64 b1_stack + +# qhasm: stack64 b2_stack + +# qhasm: stack64 b3_stack + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: stack64 c0_stack + +# qhasm: stack64 c1_stack + +# qhasm: stack64 c2_stack + +# qhasm: stack64 c3_stack + +# qhasm: int64 d0 + +# qhasm: int64 d1 + +# qhasm: int64 d2 + +# qhasm: int64 d3 + +# qhasm: stack64 d0_stack + +# qhasm: stack64 d1_stack + +# qhasm: stack64 d2_stack + +# qhasm: stack64 d3_stack + +# qhasm: int64 e0 + +# qhasm: int64 e1 + +# qhasm: int64 e2 + +# qhasm: int64 e3 + +# qhasm: stack64 e0_stack + +# qhasm: stack64 e1_stack + +# qhasm: stack64 e2_stack + +# qhasm: stack64 e3_stack + +# qhasm: int64 f0 + +# qhasm: int64 f1 + +# qhasm: int64 f2 + +# qhasm: int64 f3 + +# qhasm: stack64 f0_stack + +# qhasm: stack64 f1_stack + +# qhasm: stack64 f2_stack + +# qhasm: stack64 f3_stack + +# qhasm: int64 g0 + +# qhasm: int64 g1 + +# qhasm: int64 g2 + +# qhasm: int64 g3 + +# qhasm: stack64 g0_stack + +# qhasm: stack64 g1_stack + +# qhasm: stack64 g2_stack + +# qhasm: stack64 g3_stack + +# qhasm: int64 h0 + +# qhasm: int64 h1 + +# qhasm: int64 h2 + +# qhasm: int64 h3 + +# qhasm: stack64 h0_stack + +# qhasm: stack64 h1_stack + +# qhasm: stack64 h2_stack + +# qhasm: stack64 h3_stack + +# qhasm: int64 qt0 + +# qhasm: int64 qt1 + +# qhasm: int64 qt2 + +# qhasm: int64 qt3 + +# qhasm: stack64 qt0_stack + +# qhasm: stack64 qt1_stack + +# qhasm: stack64 qt2_stack + +# qhasm: stack64 qt3_stack + +# qhasm: int64 t10 + +# qhasm: int64 t11 + +# qhasm: int64 t12 + +# qhasm: int64 t13 + +# qhasm: stack64 t10_stack + +# qhasm: stack64 t11_stack + +# qhasm: stack64 t12_stack + +# qhasm: stack64 t13_stack + +# qhasm: int64 t20 + +# qhasm: int64 t21 + +# qhasm: int64 t22 + +# qhasm: int64 t23 + +# qhasm: stack64 t20_stack + +# qhasm: stack64 t21_stack + +# qhasm: stack64 t22_stack + +# qhasm: stack64 t23_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 +.globl crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 +_crypto_sign_ed25519_amd64_64_ge25519_nielsadd2: +crypto_sign_ed25519_amd64_64_ge25519_nielsadd2: +mov %rsp,%r11 +and $31,%r11 +add $192,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: a0 = *(uint64 *)(rp + 32) +# asm 1: movq 32(a0=int64#3 +# asm 2: movq 32(a0=%rdx +movq 32(%rdi),%rdx + +# qhasm: a1 = *(uint64 *)(rp + 40) +# asm 1: movq 40(a1=int64#4 +# asm 2: movq 40(a1=%rcx +movq 40(%rdi),%rcx + +# qhasm: a2 = *(uint64 *)(rp + 48) +# asm 1: movq 48(a2=int64#5 +# asm 2: movq 48(a2=%r8 +movq 48(%rdi),%r8 + +# qhasm: a3 = *(uint64 *)(rp + 56) +# asm 1: movq 56(a3=int64#6 +# asm 2: movq 56(a3=%r9 +movq 56(%rdi),%r9 + +# qhasm: b0 = a0 +# asm 1: mov b0=int64#7 +# asm 2: mov b0=%rax +mov %rdx,%rax + +# qhasm: b1 = a1 +# asm 1: mov b1=int64#8 +# asm 2: mov b1=%r10 +mov %rcx,%r10 + +# qhasm: b2 = a2 +# asm 1: mov b2=int64#9 +# asm 2: mov b2=%r11 +mov %r8,%r11 + +# qhasm: b3 = a3 +# asm 1: mov b3=int64#10 +# asm 2: mov b3=%r12 +mov %r9,%r12 + +# qhasm: carry? a0 -= *(uint64 *) (rp + 0) +# asm 1: subq 0(subt0=int64#11 +# asm 2: mov $0,>subt0=%r13 +mov $0,%r13 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#12 +# asm 2: mov $38,>subt1=%r14 +mov $38,%r14 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#11 +# asm 2: mov $0,>addt0=%r13 +mov $0,%r13 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#12 +# asm 2: mov $38,>addt1=%r14 +mov $38,%r14 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %rcx,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r8,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %r9,80(%rsp) + +# qhasm: b0_stack = b0 +# asm 1: movq b0_stack=stack64#12 +# asm 2: movq b0_stack=88(%rsp) +movq %rax,88(%rsp) + +# qhasm: b1_stack = b1 +# asm 1: movq b1_stack=stack64#13 +# asm 2: movq b1_stack=96(%rsp) +movq %r10,96(%rsp) + +# qhasm: b2_stack = b2 +# asm 1: movq b2_stack=stack64#14 +# asm 2: movq b2_stack=104(%rsp) +movq %r11,104(%rsp) + +# qhasm: b3_stack = b3 +# asm 1: movq b3_stack=stack64#15 +# asm 2: movq b3_stack=112(%rsp) +movq %r12,112(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = a0_stack +# asm 1: movq mulx0=int64#9 +# asm 2: movq mulx0=%r11 +movq 56(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a0=int64#10 +# asm 2: mov a0=%r12 +mov %rax,%r12 + +# qhasm: a1 = mulrdx +# asm 1: mov a1=int64#11 +# asm 2: mov a1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(qp + 8) +# asm 1: movq 8(mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a2=int64#12 +# asm 2: mov $0,>a2=%r14 +mov $0,%r14 + +# qhasm: a2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a3=int64#13 +# asm 2: mov $0,>a3=%r15 +mov $0,%r15 + +# qhasm: a3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq mulx1=%r11 +movq 64(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq mulx2=%r11 +movq 72(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq mulx3=%r11 +movq 80(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? a0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: a0 += mulzero +# asm 1: add a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %r12,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r13,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r14,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %r15,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = b0_stack +# asm 1: movq mulx0=int64#9 +# asm 2: movq mulx0=%r11 +movq 88(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e0=int64#10 +# asm 2: mov e0=%r12 +mov %rax,%r12 + +# qhasm: e1 = mulrdx +# asm 1: mov e1=int64#11 +# asm 2: mov e1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(qp + 40) +# asm 1: movq 40(mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e2=int64#12 +# asm 2: mov $0,>e2=%r14 +mov $0,%r14 + +# qhasm: e2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e3=int64#13 +# asm 2: mov $0,>e3=%r15 +mov $0,%r15 + +# qhasm: e3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq mulx1=%r11 +movq 96(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq mulx2=%r11 +movq 104(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq mulx3=%r11 +movq 112(%rsp),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? e0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: e0 += mulzero +# asm 1: add h0=int64#3 +# asm 2: mov h0=%rdx +mov %r12,%rdx + +# qhasm: h1 = e1 +# asm 1: mov h1=int64#4 +# asm 2: mov h1=%rcx +mov %r13,%rcx + +# qhasm: h2 = e2 +# asm 1: mov h2=int64#5 +# asm 2: mov h2=%r8 +mov %r14,%r8 + +# qhasm: h3 = e3 +# asm 1: mov h3=int64#6 +# asm 2: mov h3=%r9 +mov %r15,%r9 + +# qhasm: carry? e0 -= a0_stack +# asm 1: subq subt0=int64#7 +# asm 2: mov $0,>subt0=%rax +mov $0,%rax + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#8 +# asm 2: mov $38,>subt1=%r10 +mov $38,%r10 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#7 +# asm 2: mov $0,>addt0=%rax +mov $0,%rax + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#8 +# asm 2: mov $38,>addt1=%r10 +mov $38,%r10 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae h0_stack=stack64#8 +# asm 2: movq h0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: h1_stack = h1 +# asm 1: movq h1_stack=stack64#9 +# asm 2: movq h1_stack=64(%rsp) +movq %rcx,64(%rsp) + +# qhasm: h2_stack = h2 +# asm 1: movq h2_stack=stack64#10 +# asm 2: movq h2_stack=72(%rsp) +movq %r8,72(%rsp) + +# qhasm: h3_stack = h3 +# asm 1: movq h3_stack=stack64#11 +# asm 2: movq h3_stack=80(%rsp) +movq %r9,80(%rsp) + +# qhasm: e0_stack = e0 +# asm 1: movq e0_stack=stack64#12 +# asm 2: movq e0_stack=88(%rsp) +movq %r12,88(%rsp) + +# qhasm: e1_stack = e1 +# asm 1: movq e1_stack=stack64#13 +# asm 2: movq e1_stack=96(%rsp) +movq %r13,96(%rsp) + +# qhasm: e2_stack = e2 +# asm 1: movq e2_stack=stack64#14 +# asm 2: movq e2_stack=104(%rsp) +movq %r14,104(%rsp) + +# qhasm: e3_stack = e3 +# asm 1: movq e3_stack=stack64#15 +# asm 2: movq e3_stack=112(%rsp) +movq %r15,112(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(rp + 96) +# asm 1: movq 96(mulx0=int64#9 +# asm 2: movq 96(mulx0=%r11 +movq 96(%rdi),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c0=int64#10 +# asm 2: mov c0=%r12 +mov %rax,%r12 + +# qhasm: c1 = mulrdx +# asm 1: mov c1=int64#11 +# asm 2: mov c1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(qp + 72) +# asm 1: movq 72(mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c2=int64#12 +# asm 2: mov $0,>c2=%r14 +mov $0,%r14 + +# qhasm: c2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c3=int64#13 +# asm 2: mov $0,>c3=%r15 +mov $0,%r15 + +# qhasm: c3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 104(mulx1=%r11 +movq 104(%rdi),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 112(mulx2=%r11 +movq 112(%rdi),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 120(mulx3=%r11 +movq 120(%rdi),%r11 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? c0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: c0 += mulzero +# asm 1: add f0=int64#2 +# asm 2: movq 64(f0=%rsi +movq 64(%rdi),%rsi + +# qhasm: f1 = *(uint64 *)(rp + 72) +# asm 1: movq 72(f1=int64#3 +# asm 2: movq 72(f1=%rdx +movq 72(%rdi),%rdx + +# qhasm: f2 = *(uint64 *)(rp + 80) +# asm 1: movq 80(f2=int64#4 +# asm 2: movq 80(f2=%rcx +movq 80(%rdi),%rcx + +# qhasm: f3 = *(uint64 *)(rp + 88) +# asm 1: movq 88(f3=int64#5 +# asm 2: movq 88(f3=%r8 +movq 88(%rdi),%r8 + +# qhasm: carry? f0 += f0 +# asm 1: add addt0=int64#6 +# asm 2: mov $0,>addt0=%r9 +mov $0,%r9 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae g0=int64#6 +# asm 2: mov g0=%r9 +mov %rsi,%r9 + +# qhasm: g1 = f1 +# asm 1: mov g1=int64#7 +# asm 2: mov g1=%rax +mov %rdx,%rax + +# qhasm: g2 = f2 +# asm 1: mov g2=int64#8 +# asm 2: mov g2=%r10 +mov %rcx,%r10 + +# qhasm: g3 = f3 +# asm 1: mov g3=int64#9 +# asm 2: mov g3=%r11 +mov %r8,%r11 + +# qhasm: carry? f0 -= c0 +# asm 1: sub subt0=int64#14 +# asm 2: mov $0,>subt0=%rbx +mov $0,%rbx + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#15 +# asm 2: mov $38,>subt1=%rbp +mov $38,%rbp + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#10 +# asm 2: mov $0,>addt0=%r12 +mov $0,%r12 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#11 +# asm 2: mov $38,>addt1=%r13 +mov $38,%r13 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae g0_stack=stack64#16 +# asm 2: movq g0_stack=120(%rsp) +movq %r9,120(%rsp) + +# qhasm: g1_stack = g1 +# asm 1: movq g1_stack=stack64#17 +# asm 2: movq g1_stack=128(%rsp) +movq %rax,128(%rsp) + +# qhasm: g2_stack = g2 +# asm 1: movq g2_stack=stack64#18 +# asm 2: movq g2_stack=136(%rsp) +movq %r10,136(%rsp) + +# qhasm: g3_stack = g3 +# asm 1: movq g3_stack=stack64#19 +# asm 2: movq g3_stack=144(%rsp) +movq %r11,144(%rsp) + +# qhasm: f0_stack = f0 +# asm 1: movq f0_stack=stack64#20 +# asm 2: movq f0_stack=152(%rsp) +movq %rsi,152(%rsp) + +# qhasm: f1_stack = f1 +# asm 1: movq f1_stack=stack64#21 +# asm 2: movq f1_stack=160(%rsp) +movq %rdx,160(%rsp) + +# qhasm: f2_stack = f2 +# asm 1: movq f2_stack=stack64#22 +# asm 2: movq f2_stack=168(%rsp) +movq %rcx,168(%rsp) + +# qhasm: f3_stack = f3 +# asm 1: movq f3_stack=stack64#23 +# asm 2: movq f3_stack=176(%rsp) +movq %r8,176(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#2 +# asm 2: mov $0,>mulr4=%rsi +mov $0,%rsi + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#4 +# asm 2: mov $0,>mulr5=%rcx +mov $0,%rcx + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulx0 = e0_stack +# asm 1: movq mulx0=int64#8 +# asm 2: movq mulx0=%r10 +movq 88(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx0=int64#9 +# asm 2: mov rx0=%r11 +mov %rax,%r11 + +# qhasm: rx1 = mulrdx +# asm 1: mov rx1=int64#10 +# asm 2: mov rx1=%r12 +mov %rdx,%r12 + +# qhasm: mulrax = f1_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx2=int64#11 +# asm 2: mov $0,>rx2=%r13 +mov $0,%r13 + +# qhasm: rx2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx3=int64#12 +# asm 2: mov $0,>rx3=%r14 +mov $0,%r14 + +# qhasm: rx3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#8 +# asm 2: movq mulx1=%r10 +movq 96(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#8 +# asm 2: movq mulx2=%r10 +movq 104(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#8 +# asm 2: movq mulx3=%r10 +movq 112(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rsi,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rx0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rx0 += mulzero +# asm 1: add mulr4=int64#2 +# asm 2: mov $0,>mulr4=%rsi +mov $0,%rsi + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#4 +# asm 2: mov $0,>mulr5=%rcx +mov $0,%rcx + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulx0 = h0_stack +# asm 1: movq mulx0=int64#8 +# asm 2: movq mulx0=%r10 +movq 56(%rsp),%r10 + +# qhasm: mulrax = g0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry0=int64#9 +# asm 2: mov ry0=%r11 +mov %rax,%r11 + +# qhasm: ry1 = mulrdx +# asm 1: mov ry1=int64#10 +# asm 2: mov ry1=%r12 +mov %rdx,%r12 + +# qhasm: mulrax = g1_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry2=int64#11 +# asm 2: mov $0,>ry2=%r13 +mov $0,%r13 + +# qhasm: ry2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry3=int64#12 +# asm 2: mov $0,>ry3=%r14 +mov $0,%r14 + +# qhasm: ry3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#8 +# asm 2: movq mulx1=%r10 +movq 64(%rsp),%r10 + +# qhasm: mulrax = g0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#8 +# asm 2: movq mulx2=%r10 +movq 72(%rsp),%r10 + +# qhasm: mulrax = g0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#8 +# asm 2: movq mulx3=%r10 +movq 80(%rsp),%r10 + +# qhasm: mulrax = g0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 120(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 128(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 136(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 144(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rsi,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? ry0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: ry0 += mulzero +# asm 1: add mulr4=int64#2 +# asm 2: mov $0,>mulr4=%rsi +mov $0,%rsi + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#4 +# asm 2: mov $0,>mulr5=%rcx +mov $0,%rcx + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulx0 = g0_stack +# asm 1: movq mulx0=int64#8 +# asm 2: movq mulx0=%r10 +movq 120(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz0=int64#9 +# asm 2: mov rz0=%r11 +mov %rax,%r11 + +# qhasm: rz1 = mulrdx +# asm 1: mov rz1=int64#10 +# asm 2: mov rz1=%r12 +mov %rdx,%r12 + +# qhasm: mulrax = f1_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz2=int64#11 +# asm 2: mov $0,>rz2=%r13 +mov $0,%r13 + +# qhasm: rz2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz3=int64#12 +# asm 2: mov $0,>rz3=%r14 +mov $0,%r14 + +# qhasm: rz3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#8 +# asm 2: movq mulx1=%r10 +movq 128(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#8 +# asm 2: movq mulx2=%r10 +movq 136(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#8 +# asm 2: movq mulx3=%r10 +movq 144(%rsp),%r10 + +# qhasm: mulrax = f0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 152(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 160(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 168(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 176(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rsi,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rz0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rz0 += mulzero +# asm 1: add mulr4=int64#2 +# asm 2: mov $0,>mulr4=%rsi +mov $0,%rsi + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#4 +# asm 2: mov $0,>mulr5=%rcx +mov $0,%rcx + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulx0 = e0_stack +# asm 1: movq mulx0=int64#8 +# asm 2: movq mulx0=%r10 +movq 88(%rsp),%r10 + +# qhasm: mulrax = h0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt0=int64#9 +# asm 2: mov rt0=%r11 +mov %rax,%r11 + +# qhasm: rt1 = mulrdx +# asm 1: mov rt1=int64#10 +# asm 2: mov rt1=%r12 +mov %rdx,%r12 + +# qhasm: mulrax = h1_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt2=int64#11 +# asm 2: mov $0,>rt2=%r13 +mov $0,%r13 + +# qhasm: rt2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt3=int64#12 +# asm 2: mov $0,>rt3=%r14 +mov $0,%r14 + +# qhasm: rt3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 80(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#8 +# asm 2: movq mulx1=%r10 +movq 96(%rsp),%r10 + +# qhasm: mulrax = h0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 80(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#8 +# asm 2: movq mulx2=%r10 +movq 104(%rsp),%r10 + +# qhasm: mulrax = h0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 80(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#8 +# asm 2: movq mulx3=%r10 +movq 112(%rsp),%r10 + +# qhasm: mulrax = h0_stack +# asm 1: movq mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#13 +# asm 2: mov $0,>mulc=%r15 +mov $0,%r15 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq mulrax=%rax +movq 80(%rsp),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rsi,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rt0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rt0 += mulzero +# asm 1: add caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s b/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s new file mode 100644 index 0000000..b562946 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s @@ -0,0 +1,3072 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: int64 qp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: input qp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 a0 + +# qhasm: int64 a1 + +# qhasm: int64 a2 + +# qhasm: int64 a3 + +# qhasm: stack64 a0_stack + +# qhasm: stack64 a1_stack + +# qhasm: stack64 a2_stack + +# qhasm: stack64 a3_stack + +# qhasm: int64 b0 + +# qhasm: int64 b1 + +# qhasm: int64 b2 + +# qhasm: int64 b3 + +# qhasm: stack64 b0_stack + +# qhasm: stack64 b1_stack + +# qhasm: stack64 b2_stack + +# qhasm: stack64 b3_stack + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: stack64 c0_stack + +# qhasm: stack64 c1_stack + +# qhasm: stack64 c2_stack + +# qhasm: stack64 c3_stack + +# qhasm: int64 d0 + +# qhasm: int64 d1 + +# qhasm: int64 d2 + +# qhasm: int64 d3 + +# qhasm: stack64 d0_stack + +# qhasm: stack64 d1_stack + +# qhasm: stack64 d2_stack + +# qhasm: stack64 d3_stack + +# qhasm: int64 e0 + +# qhasm: int64 e1 + +# qhasm: int64 e2 + +# qhasm: int64 e3 + +# qhasm: stack64 e0_stack + +# qhasm: stack64 e1_stack + +# qhasm: stack64 e2_stack + +# qhasm: stack64 e3_stack + +# qhasm: int64 f0 + +# qhasm: int64 f1 + +# qhasm: int64 f2 + +# qhasm: int64 f3 + +# qhasm: stack64 f0_stack + +# qhasm: stack64 f1_stack + +# qhasm: stack64 f2_stack + +# qhasm: stack64 f3_stack + +# qhasm: int64 g0 + +# qhasm: int64 g1 + +# qhasm: int64 g2 + +# qhasm: int64 g3 + +# qhasm: stack64 g0_stack + +# qhasm: stack64 g1_stack + +# qhasm: stack64 g2_stack + +# qhasm: stack64 g3_stack + +# qhasm: int64 h0 + +# qhasm: int64 h1 + +# qhasm: int64 h2 + +# qhasm: int64 h3 + +# qhasm: stack64 h0_stack + +# qhasm: stack64 h1_stack + +# qhasm: stack64 h2_stack + +# qhasm: stack64 h3_stack + +# qhasm: int64 qt0 + +# qhasm: int64 qt1 + +# qhasm: int64 qt2 + +# qhasm: int64 qt3 + +# qhasm: stack64 qt0_stack + +# qhasm: stack64 qt1_stack + +# qhasm: stack64 qt2_stack + +# qhasm: stack64 qt3_stack + +# qhasm: int64 t10 + +# qhasm: int64 t11 + +# qhasm: int64 t12 + +# qhasm: int64 t13 + +# qhasm: stack64 t10_stack + +# qhasm: stack64 t11_stack + +# qhasm: stack64 t12_stack + +# qhasm: stack64 t13_stack + +# qhasm: int64 t20 + +# qhasm: int64 t21 + +# qhasm: int64 t22 + +# qhasm: int64 t23 + +# qhasm: stack64 t20_stack + +# qhasm: stack64 t21_stack + +# qhasm: stack64 t22_stack + +# qhasm: stack64 t23_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 +.globl crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 +_crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1: +crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1: +mov %rsp,%r11 +and $31,%r11 +add $128,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: qp = qp +# asm 1: mov qp=int64#4 +# asm 2: mov qp=%rcx +mov %rdx,%rcx + +# qhasm: a0 = *(uint64 *)(pp + 32) +# asm 1: movq 32(a0=int64#3 +# asm 2: movq 32(a0=%rdx +movq 32(%rsi),%rdx + +# qhasm: a1 = *(uint64 *)(pp + 40) +# asm 1: movq 40(a1=int64#5 +# asm 2: movq 40(a1=%r8 +movq 40(%rsi),%r8 + +# qhasm: a2 = *(uint64 *)(pp + 48) +# asm 1: movq 48(a2=int64#6 +# asm 2: movq 48(a2=%r9 +movq 48(%rsi),%r9 + +# qhasm: a3 = *(uint64 *)(pp + 56) +# asm 1: movq 56(a3=int64#7 +# asm 2: movq 56(a3=%rax +movq 56(%rsi),%rax + +# qhasm: b0 = a0 +# asm 1: mov b0=int64#8 +# asm 2: mov b0=%r10 +mov %rdx,%r10 + +# qhasm: b1 = a1 +# asm 1: mov b1=int64#9 +# asm 2: mov b1=%r11 +mov %r8,%r11 + +# qhasm: b2 = a2 +# asm 1: mov b2=int64#10 +# asm 2: mov b2=%r12 +mov %r9,%r12 + +# qhasm: b3 = a3 +# asm 1: mov b3=int64#11 +# asm 2: mov b3=%r13 +mov %rax,%r13 + +# qhasm: carry? a0 -= *(uint64 *) (pp + 0) +# asm 1: subq 0(subt0=int64#12 +# asm 2: mov $0,>subt0=%r14 +mov $0,%r14 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#13 +# asm 2: mov $38,>subt1=%r15 +mov $38,%r15 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#12 +# asm 2: mov $0,>addt0=%r14 +mov $0,%r14 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#13 +# asm 2: mov $38,>addt1=%r15 +mov $38,%r15 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r8,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r9,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rax,80(%rsp) + +# qhasm: b0_stack = b0 +# asm 1: movq b0_stack=stack64#12 +# asm 2: movq b0_stack=88(%rsp) +movq %r10,88(%rsp) + +# qhasm: b1_stack = b1 +# asm 1: movq b1_stack=stack64#13 +# asm 2: movq b1_stack=96(%rsp) +movq %r11,96(%rsp) + +# qhasm: b2_stack = b2 +# asm 1: movq b2_stack=stack64#14 +# asm 2: movq b2_stack=104(%rsp) +movq %r12,104(%rsp) + +# qhasm: b3_stack = b3 +# asm 1: movq b3_stack=stack64#15 +# asm 2: movq b3_stack=112(%rsp) +movq %r13,112(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = a0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 56(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a0=int64#11 +# asm 2: mov a0=%r13 +mov %rax,%r13 + +# qhasm: a1 = mulrdx +# asm 1: mov a1=int64#12 +# asm 2: mov a1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 8) +# asm 1: movq 8(mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a2=int64#13 +# asm 2: mov $0,>a2=%r15 +mov $0,%r15 + +# qhasm: a2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a3=int64#14 +# asm 2: mov $0,>a3=%rbx +mov $0,%rbx + +# qhasm: a3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 64(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 72(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 80(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? a0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: a0 += mulzero +# asm 1: add a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = b0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 88(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e0=int64#11 +# asm 2: mov e0=%r13 +mov %rax,%r13 + +# qhasm: e1 = mulrdx +# asm 1: mov e1=int64#12 +# asm 2: mov e1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 40) +# asm 1: movq 40(mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e2=int64#13 +# asm 2: mov $0,>e2=%r15 +mov $0,%r15 + +# qhasm: e2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul e3=int64#14 +# asm 2: mov $0,>e3=%rbx +mov $0,%rbx + +# qhasm: e3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 96(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 104(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 112(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? e0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: e0 += mulzero +# asm 1: add h0=int64#3 +# asm 2: mov h0=%rdx +mov %r13,%rdx + +# qhasm: h1 = e1 +# asm 1: mov h1=int64#5 +# asm 2: mov h1=%r8 +mov %r14,%r8 + +# qhasm: h2 = e2 +# asm 1: mov h2=int64#6 +# asm 2: mov h2=%r9 +mov %r15,%r9 + +# qhasm: h3 = e3 +# asm 1: mov h3=int64#7 +# asm 2: mov h3=%rax +mov %rbx,%rax + +# qhasm: carry? e0 -= a0_stack +# asm 1: subq subt0=int64#8 +# asm 2: mov $0,>subt0=%r10 +mov $0,%r10 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#9 +# asm 2: mov $38,>subt1=%r11 +mov $38,%r11 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#8 +# asm 2: mov $0,>addt0=%r10 +mov $0,%r10 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#9 +# asm 2: mov $38,>addt1=%r11 +mov $38,%r11 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulx0=int64#10 +# asm 2: movq 96(mulx0=%r12 +movq 96(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c0=int64#11 +# asm 2: mov c0=%r13 +mov %rax,%r13 + +# qhasm: c1 = mulrdx +# asm 1: mov c1=int64#12 +# asm 2: mov c1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 72) +# asm 1: movq 72(mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c2=int64#13 +# asm 2: mov $0,>c2=%r15 +mov $0,%r15 + +# qhasm: c2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c3=int64#14 +# asm 2: mov $0,>c3=%rbx +mov $0,%rbx + +# qhasm: c3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 104(mulx1=%r12 +movq 104(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 112(mulx2=%r12 +movq 112(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq 120(mulx3=%r12 +movq 120(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? c0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: c0 += mulzero +# asm 1: add f0=int64#3 +# asm 2: movq 64(f0=%rdx +movq 64(%rsi),%rdx + +# qhasm: f1 = *(uint64 *)(pp + 72) +# asm 1: movq 72(f1=int64#4 +# asm 2: movq 72(f1=%rcx +movq 72(%rsi),%rcx + +# qhasm: f2 = *(uint64 *)(pp + 80) +# asm 1: movq 80(f2=int64#5 +# asm 2: movq 80(f2=%r8 +movq 80(%rsi),%r8 + +# qhasm: f3 = *(uint64 *)(pp + 88) +# asm 1: movq 88(f3=int64#2 +# asm 2: movq 88(f3=%rsi +movq 88(%rsi),%rsi + +# qhasm: carry? f0 += f0 +# asm 1: add addt0=int64#6 +# asm 2: mov $0,>addt0=%r9 +mov $0,%r9 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae g0=int64#6 +# asm 2: mov g0=%r9 +mov %rdx,%r9 + +# qhasm: g1 = f1 +# asm 1: mov g1=int64#7 +# asm 2: mov g1=%rax +mov %rcx,%rax + +# qhasm: g2 = f2 +# asm 1: mov g2=int64#8 +# asm 2: mov g2=%r10 +mov %r8,%r10 + +# qhasm: g3 = f3 +# asm 1: mov g3=int64#9 +# asm 2: mov g3=%r11 +mov %rsi,%r11 + +# qhasm: carry? f0 -= c0 +# asm 1: sub subt0=int64#10 +# asm 2: mov $0,>subt0=%r12 +mov $0,%r12 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#15 +# asm 2: mov $38,>subt1=%rbp +mov $38,%rbp + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#10 +# asm 2: mov $0,>addt0=%r12 +mov $0,%r12 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#11 +# asm 2: mov $38,>addt1=%r13 +mov $38,%r13 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s new file mode 100644 index 0000000..beddbc7 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s @@ -0,0 +1,2236 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 +.globl crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 +_crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2: +crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 0) +# asm 1: movq 0(mulx0=int64#9 +# asm 2: movq 0(mulx0=%r11 +movq 0(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx0=int64#10 +# asm 2: mov rx0=%r12 +mov %rax,%r12 + +# qhasm: rx1 = mulrdx +# asm 1: mov rx1=int64#11 +# asm 2: mov rx1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx2=int64#12 +# asm 2: mov $0,>rx2=%r14 +mov $0,%r14 + +# qhasm: rx2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx3=int64#13 +# asm 2: mov $0,>rx3=%r15 +mov $0,%r15 + +# qhasm: rx3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 8(mulx1=%r11 +movq 8(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 16(mulx2=%r11 +movq 16(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 24(mulx3=%r11 +movq 24(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? rx0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: rx0 += mulzero +# asm 1: add mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulx0=int64#9 +# asm 2: movq 64(mulx0=%r11 +movq 64(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry0=int64#10 +# asm 2: mov ry0=%r12 +mov %rax,%r12 + +# qhasm: ry1 = mulrdx +# asm 1: mov ry1=int64#11 +# asm 2: mov ry1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 40) +# asm 1: movq 40(mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry2=int64#12 +# asm 2: mov $0,>ry2=%r14 +mov $0,%r14 + +# qhasm: ry2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry3=int64#13 +# asm 2: mov $0,>ry3=%r15 +mov $0,%r15 + +# qhasm: ry3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 72(mulx1=%r11 +movq 72(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 80(mulx2=%r11 +movq 80(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 88(mulx3=%r11 +movq 88(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? ry0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: ry0 += mulzero +# asm 1: add mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulx0=int64#9 +# asm 2: movq 32(mulx0=%r11 +movq 32(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz0=int64#10 +# asm 2: mov rz0=%r12 +mov %rax,%r12 + +# qhasm: rz1 = mulrdx +# asm 1: mov rz1=int64#11 +# asm 2: mov rz1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz2=int64#12 +# asm 2: mov $0,>rz2=%r14 +mov $0,%r14 + +# qhasm: rz2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz3=int64#13 +# asm 2: mov $0,>rz3=%r15 +mov $0,%r15 + +# qhasm: rz3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 40(mulx1=%r11 +movq 40(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 48(mulx2=%r11 +movq 48(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 56(mulx3=%r11 +movq 56(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rz0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rz0 += mulzero +# asm 1: add caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s new file mode 100644 index 0000000..82433fb --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s @@ -0,0 +1,2926 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 +.globl crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 +_crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3: +crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 0) +# asm 1: movq 0(mulx0=int64#9 +# asm 2: movq 0(mulx0=%r11 +movq 0(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx0=int64#10 +# asm 2: mov rx0=%r12 +mov %rax,%r12 + +# qhasm: rx1 = mulrdx +# asm 1: mov rx1=int64#11 +# asm 2: mov rx1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx2=int64#12 +# asm 2: mov $0,>rx2=%r14 +mov $0,%r14 + +# qhasm: rx2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx3=int64#13 +# asm 2: mov $0,>rx3=%r15 +mov $0,%r15 + +# qhasm: rx3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 8(mulx1=%r11 +movq 8(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 16(mulx2=%r11 +movq 16(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 24(mulx3=%r11 +movq 24(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? rx0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: rx0 += mulzero +# asm 1: add mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulx0=int64#9 +# asm 2: movq 64(mulx0=%r11 +movq 64(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry0=int64#10 +# asm 2: mov ry0=%r12 +mov %rax,%r12 + +# qhasm: ry1 = mulrdx +# asm 1: mov ry1=int64#11 +# asm 2: mov ry1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 40) +# asm 1: movq 40(mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry2=int64#12 +# asm 2: mov $0,>ry2=%r14 +mov $0,%r14 + +# qhasm: ry2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul ry3=int64#13 +# asm 2: mov $0,>ry3=%r15 +mov $0,%r15 + +# qhasm: ry3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 72(mulx1=%r11 +movq 72(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 80(mulx2=%r11 +movq 80(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 88(mulx3=%r11 +movq 88(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? ry0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: ry0 += mulzero +# asm 1: add mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 32) +# asm 1: movq 32(mulx0=int64#9 +# asm 2: movq 32(mulx0=%r11 +movq 32(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz0=int64#10 +# asm 2: mov rz0=%r12 +mov %rax,%r12 + +# qhasm: rz1 = mulrdx +# asm 1: mov rz1=int64#11 +# asm 2: mov rz1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz2=int64#12 +# asm 2: mov $0,>rz2=%r14 +mov $0,%r14 + +# qhasm: rz2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rz3=int64#13 +# asm 2: mov $0,>rz3=%r15 +mov $0,%r15 + +# qhasm: rz3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 40(mulx1=%r11 +movq 40(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 48(mulx2=%r11 +movq 48(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 56(mulx3=%r11 +movq 56(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#4 +# asm 2: mov mulr4=%rcx +mov %rax,%rcx + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#5 +# asm 2: mov mulr5=%r8 +mov %rdx,%r8 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#4 +# asm 2: imulq $38,mulr8=%rcx +imulq $38,%rax,%rcx + +# qhasm: carry? rz0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: rz0 += mulzero +# asm 1: add mulr4=int64#4 +# asm 2: mov $0,>mulr4=%rcx +mov $0,%rcx + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#5 +# asm 2: mov $0,>mulr5=%r8 +mov $0,%r8 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#6 +# asm 2: mov $0,>mulr6=%r9 +mov $0,%r9 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#8 +# asm 2: mov $0,>mulr7=%r10 +mov $0,%r10 + +# qhasm: mulx0 = *(uint64 *)(pp + 0) +# asm 1: movq 0(mulx0=int64#9 +# asm 2: movq 0(mulx0=%r11 +movq 0(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt0=int64#10 +# asm 2: mov rt0=%r12 +mov %rax,%r12 + +# qhasm: rt1 = mulrdx +# asm 1: mov rt1=int64#11 +# asm 2: mov rt1=%r13 +mov %rdx,%r13 + +# qhasm: mulrax = *(uint64 *)(pp + 72) +# asm 1: movq 72(mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt2=int64#12 +# asm 2: mov $0,>rt2=%r14 +mov $0,%r14 + +# qhasm: rt2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt3=int64#13 +# asm 2: mov $0,>rt3=%r15 +mov $0,%r15 + +# qhasm: rt3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#9 +# asm 2: movq 8(mulx1=%r11 +movq 8(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#9 +# asm 2: movq 16(mulx2=%r11 +movq 16(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#9 +# asm 2: movq 24(mulx3=%r11 +movq 24(%rsi),%r11 + +# qhasm: mulrax = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#14 +# asm 2: mov $0,>mulc=%rbx +mov $0,%rbx + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rsi),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %rcx,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rt0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rt0 += mulzero +# asm 1: add caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_pack.c b/ext/ed25519-amd64-asm/ge25519_pack.c new file mode 100644 index 0000000..f289fe5 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_pack.c @@ -0,0 +1,13 @@ +#include "fe25519.h" +#include "sc25519.h" +#include "ge25519.h" + +void ge25519_pack(unsigned char r[32], const ge25519_p3 *p) +{ + fe25519 tx, ty, zi; + fe25519_invert(&zi, &p->z); + fe25519_mul(&tx, &p->x, &zi); + fe25519_mul(&ty, &p->y, &zi); + fe25519_pack(r, &ty); + r[31] ^= fe25519_getparity(&tx) << 7; +} diff --git a/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s b/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s new file mode 100644 index 0000000..aff2e75 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s @@ -0,0 +1,3662 @@ + +# qhasm: int64 rp + +# qhasm: int64 pp + +# qhasm: int64 qp + +# qhasm: input rp + +# qhasm: input pp + +# qhasm: input qp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 a0 + +# qhasm: int64 a1 + +# qhasm: int64 a2 + +# qhasm: int64 a3 + +# qhasm: stack64 a0_stack + +# qhasm: stack64 a1_stack + +# qhasm: stack64 a2_stack + +# qhasm: stack64 a3_stack + +# qhasm: int64 b0 + +# qhasm: int64 b1 + +# qhasm: int64 b2 + +# qhasm: int64 b3 + +# qhasm: stack64 b0_stack + +# qhasm: stack64 b1_stack + +# qhasm: stack64 b2_stack + +# qhasm: stack64 b3_stack + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: stack64 c0_stack + +# qhasm: stack64 c1_stack + +# qhasm: stack64 c2_stack + +# qhasm: stack64 c3_stack + +# qhasm: int64 d0 + +# qhasm: int64 d1 + +# qhasm: int64 d2 + +# qhasm: int64 d3 + +# qhasm: stack64 d0_stack + +# qhasm: stack64 d1_stack + +# qhasm: stack64 d2_stack + +# qhasm: stack64 d3_stack + +# qhasm: int64 t10 + +# qhasm: int64 t11 + +# qhasm: int64 t12 + +# qhasm: int64 t13 + +# qhasm: stack64 t10_stack + +# qhasm: stack64 t11_stack + +# qhasm: stack64 t12_stack + +# qhasm: stack64 t13_stack + +# qhasm: int64 t20 + +# qhasm: int64 t21 + +# qhasm: int64 t22 + +# qhasm: int64 t23 + +# qhasm: stack64 t20_stack + +# qhasm: stack64 t21_stack + +# qhasm: stack64 t22_stack + +# qhasm: stack64 t23_stack + +# qhasm: int64 rx0 + +# qhasm: int64 rx1 + +# qhasm: int64 rx2 + +# qhasm: int64 rx3 + +# qhasm: int64 ry0 + +# qhasm: int64 ry1 + +# qhasm: int64 ry2 + +# qhasm: int64 ry3 + +# qhasm: int64 rz0 + +# qhasm: int64 rz1 + +# qhasm: int64 rz2 + +# qhasm: int64 rz3 + +# qhasm: int64 rt0 + +# qhasm: int64 rt1 + +# qhasm: int64 rt2 + +# qhasm: int64 rt3 + +# qhasm: int64 x0 + +# qhasm: int64 x1 + +# qhasm: int64 x2 + +# qhasm: int64 x3 + +# qhasm: int64 mulr4 + +# qhasm: int64 mulr5 + +# qhasm: int64 mulr6 + +# qhasm: int64 mulr7 + +# qhasm: int64 mulr8 + +# qhasm: int64 mulrax + +# qhasm: int64 mulrdx + +# qhasm: int64 mulx0 + +# qhasm: int64 mulx1 + +# qhasm: int64 mulx2 + +# qhasm: int64 mulx3 + +# qhasm: int64 mulc + +# qhasm: int64 mulzero + +# qhasm: int64 muli38 + +# qhasm: int64 addt0 + +# qhasm: int64 addt1 + +# qhasm: int64 subt0 + +# qhasm: int64 subt1 + +# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 +.globl crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 +_crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1: +crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1: +mov %rsp,%r11 +and $31,%r11 +add $128,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: qp = qp +# asm 1: mov qp=int64#4 +# asm 2: mov qp=%rcx +mov %rdx,%rcx + +# qhasm: a0 = *(uint64 *)(pp + 32) +# asm 1: movq 32(a0=int64#3 +# asm 2: movq 32(a0=%rdx +movq 32(%rsi),%rdx + +# qhasm: a1 = *(uint64 *)(pp + 40) +# asm 1: movq 40(a1=int64#5 +# asm 2: movq 40(a1=%r8 +movq 40(%rsi),%r8 + +# qhasm: a2 = *(uint64 *)(pp + 48) +# asm 1: movq 48(a2=int64#6 +# asm 2: movq 48(a2=%r9 +movq 48(%rsi),%r9 + +# qhasm: a3 = *(uint64 *)(pp + 56) +# asm 1: movq 56(a3=int64#7 +# asm 2: movq 56(a3=%rax +movq 56(%rsi),%rax + +# qhasm: b0 = a0 +# asm 1: mov b0=int64#8 +# asm 2: mov b0=%r10 +mov %rdx,%r10 + +# qhasm: b1 = a1 +# asm 1: mov b1=int64#9 +# asm 2: mov b1=%r11 +mov %r8,%r11 + +# qhasm: b2 = a2 +# asm 1: mov b2=int64#10 +# asm 2: mov b2=%r12 +mov %r9,%r12 + +# qhasm: b3 = a3 +# asm 1: mov b3=int64#11 +# asm 2: mov b3=%r13 +mov %rax,%r13 + +# qhasm: carry? a0 -= *(uint64 *)(pp + 0) +# asm 1: subq 0(subt0=int64#12 +# asm 2: mov $0,>subt0=%r14 +mov $0,%r14 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#13 +# asm 2: mov $38,>subt1=%r15 +mov $38,%r15 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae addt0=int64#12 +# asm 2: mov $0,>addt0=%r14 +mov $0,%r14 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#13 +# asm 2: mov $38,>addt1=%r15 +mov $38,%r15 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %rdx,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r8,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r9,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rax,80(%rsp) + +# qhasm: b0_stack = b0 +# asm 1: movq b0_stack=stack64#12 +# asm 2: movq b0_stack=88(%rsp) +movq %r10,88(%rsp) + +# qhasm: b1_stack = b1 +# asm 1: movq b1_stack=stack64#13 +# asm 2: movq b1_stack=96(%rsp) +movq %r11,96(%rsp) + +# qhasm: b2_stack = b2 +# asm 1: movq b2_stack=stack64#14 +# asm 2: movq b2_stack=104(%rsp) +movq %r12,104(%rsp) + +# qhasm: b3_stack = b3 +# asm 1: movq b3_stack=stack64#15 +# asm 2: movq b3_stack=112(%rsp) +movq %r13,112(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = a0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 56(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a0=int64#11 +# asm 2: mov a0=%r13 +mov %rax,%r13 + +# qhasm: a1 = mulrdx +# asm 1: mov a1=int64#12 +# asm 2: mov a1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 8) +# asm 1: movq 8(mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a2=int64#13 +# asm 2: mov $0,>a2=%r15 +mov $0,%r15 + +# qhasm: a2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul a3=int64#14 +# asm 2: mov $0,>a3=%rbx +mov $0,%rbx + +# qhasm: a3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 64(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 72(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 80(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 0) +# asm 1: movq 0(mulrax=int64#7 +# asm 2: movq 0(mulrax=%rax +movq 0(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 8(mulrax=%rax +movq 8(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 16(mulrax=%rax +movq 16(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 24(mulrax=%rax +movq 24(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? a0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: a0 += mulzero +# asm 1: add a0_stack=stack64#8 +# asm 2: movq a0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: a1_stack = a1 +# asm 1: movq a1_stack=stack64#9 +# asm 2: movq a1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: a2_stack = a2 +# asm 1: movq a2_stack=stack64#10 +# asm 2: movq a2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: a3_stack = a3 +# asm 1: movq a3_stack=stack64#11 +# asm 2: movq a3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = b0_stack +# asm 1: movq mulx0=int64#10 +# asm 2: movq mulx0=%r12 +movq 88(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx0=int64#11 +# asm 2: mov rx0=%r13 +mov %rax,%r13 + +# qhasm: rx1 = mulrdx +# asm 1: mov rx1=int64#12 +# asm 2: mov rx1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 40) +# asm 1: movq 40(mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx2=int64#13 +# asm 2: mov $0,>rx2=%r15 +mov $0,%r15 + +# qhasm: rx2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rx3=int64#14 +# asm 2: mov $0,>rx3=%rbx +mov $0,%rbx + +# qhasm: rx3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq mulx1=%r12 +movq 96(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq mulx2=%r12 +movq 104(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq mulx3=%r12 +movq 112(%rsp),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 32) +# asm 1: movq 32(mulrax=int64#7 +# asm 2: movq 32(mulrax=%rax +movq 32(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 40(mulrax=%rax +movq 40(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 48(mulrax=%rax +movq 48(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 56(mulrax=%rax +movq 56(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? rx0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: rx0 += mulzero +# asm 1: add ry0=int64#3 +# asm 2: mov ry0=%rdx +mov %r13,%rdx + +# qhasm: ry1 = rx1 +# asm 1: mov ry1=int64#5 +# asm 2: mov ry1=%r8 +mov %r14,%r8 + +# qhasm: ry2 = rx2 +# asm 1: mov ry2=int64#6 +# asm 2: mov ry2=%r9 +mov %r15,%r9 + +# qhasm: ry3 = rx3 +# asm 1: mov ry3=int64#7 +# asm 2: mov ry3=%rax +mov %rbx,%rax + +# qhasm: carry? ry0 += a0_stack +# asm 1: addq addt0=int64#8 +# asm 2: mov $0,>addt0=%r10 +mov $0,%r10 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#9 +# asm 2: mov $38,>addt1=%r11 +mov $38,%r11 + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae subt0=int64#8 +# asm 2: mov $0,>subt0=%r10 +mov $0,%r10 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#9 +# asm 2: mov $38,>subt1=%r11 +mov $38,%r11 + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(pp + 96) +# asm 1: movq 96(mulx0=int64#10 +# asm 2: movq 96(mulx0=%r12 +movq 96(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c0=int64#11 +# asm 2: mov c0=%r13 +mov %rax,%r13 + +# qhasm: c1 = mulrdx +# asm 1: mov c1=int64#12 +# asm 2: mov c1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 104) +# asm 1: movq 104(mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c2=int64#13 +# asm 2: mov $0,>c2=%r15 +mov $0,%r15 + +# qhasm: c2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul c3=int64#14 +# asm 2: mov $0,>c3=%rbx +mov $0,%rbx + +# qhasm: c3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 104(mulx1=%r12 +movq 104(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 112(mulx2=%r12 +movq 112(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#10 +# asm 2: movq 120(mulx3=%r12 +movq 120(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 96) +# asm 1: movq 96(mulrax=int64#7 +# asm 2: movq 96(mulrax=%rax +movq 96(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 104(mulrax=%rax +movq 104(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 112(mulrax=%rax +movq 112(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 120(mulrax=%rax +movq 120(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#5 +# asm 2: mov mulr4=%r8 +mov %rax,%r8 + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#6 +# asm 2: mov mulr5=%r9 +mov %rdx,%r9 + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#3 +# asm 2: mov $0,>mulzero=%rdx +mov $0,%rdx + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#5 +# asm 2: imulq $38,mulr8=%r8 +imulq $38,%rax,%r8 + +# qhasm: carry? c0 += mulr8 +# asm 1: add mulzero=int64#3 +# asm 2: imulq $38,mulzero=%rdx +imulq $38,%rdx,%rdx + +# qhasm: c0 += mulzero +# asm 1: add c0_stack=stack64#8 +# asm 2: movq c0_stack=56(%rsp) +movq %r13,56(%rsp) + +# qhasm: c1_stack = c1 +# asm 1: movq c1_stack=stack64#9 +# asm 2: movq c1_stack=64(%rsp) +movq %r14,64(%rsp) + +# qhasm: c2_stack = c2 +# asm 1: movq c2_stack=stack64#10 +# asm 2: movq c2_stack=72(%rsp) +movq %r15,72(%rsp) + +# qhasm: c3_stack = c3 +# asm 1: movq c3_stack=stack64#11 +# asm 2: movq c3_stack=80(%rsp) +movq %rbx,80(%rsp) + +# qhasm: mulr4 = 0 +# asm 1: mov $0,>mulr4=int64#5 +# asm 2: mov $0,>mulr4=%r8 +mov $0,%r8 + +# qhasm: mulr5 = 0 +# asm 1: mov $0,>mulr5=int64#6 +# asm 2: mov $0,>mulr5=%r9 +mov $0,%r9 + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#8 +# asm 2: mov $0,>mulr6=%r10 +mov $0,%r10 + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#9 +# asm 2: mov $0,>mulr7=%r11 +mov $0,%r11 + +# qhasm: mulx0 = *(uint64 *)(pp + 64) +# asm 1: movq 64(mulx0=int64#10 +# asm 2: movq 64(mulx0=%r12 +movq 64(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt0=int64#11 +# asm 2: mov rt0=%r13 +mov %rax,%r13 + +# qhasm: rt1 = mulrdx +# asm 1: mov rt1=int64#12 +# asm 2: mov rt1=%r14 +mov %rdx,%r14 + +# qhasm: mulrax = *(uint64 *)(qp + 72) +# asm 1: movq 72(mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt2=int64#13 +# asm 2: mov $0,>rt2=%r15 +mov $0,%r15 + +# qhasm: rt2 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul rt3=int64#14 +# asm 2: mov $0,>rt3=%rbx +mov $0,%rbx + +# qhasm: rt3 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 +# asm 1: mul mulx1=int64#10 +# asm 2: movq 72(mulx1=%r12 +movq 72(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 +# asm 1: mul mulx2=int64#10 +# asm 2: movq 80(mulx2=%r12 +movq 80(%rsi),%r12 + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulc=int64#15 +# asm 2: mov $0,>mulc=%rbp +mov $0,%rbp + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 +# asm 1: mul mulx3=int64#2 +# asm 2: movq 88(mulx3=%rsi +movq 88(%rsi),%rsi + +# qhasm: mulrax = *(uint64 *)(qp + 64) +# asm 1: movq 64(mulrax=int64#7 +# asm 2: movq 64(mulrax=%rax +movq 64(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 72(mulrax=%rax +movq 72(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 80(mulrax=%rax +movq 80(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulc=int64#10 +# asm 2: mov $0,>mulc=%r12 +mov $0,%r12 + +# qhasm: mulc += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: movq 88(mulrax=%rax +movq 88(%rcx),%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 +# asm 1: mul mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r8,%rax + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: mulr4 = mulrax +# asm 1: mov mulr4=int64#2 +# asm 2: mov mulr4=%rsi +mov %rax,%rsi + +# qhasm: mulrax = mulr5 +# asm 1: mov mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r9,%rax + +# qhasm: mulr5 = mulrdx +# asm 1: mov mulr5=int64#4 +# asm 2: mov mulr5=%rcx +mov %rdx,%rcx + +# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 +mulq crypto_sign_ed25519_amd64_64_38(%rip) + +# qhasm: carry? mulr5 += mulrax +# asm 1: add mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r10,%rax + +# qhasm: mulr6 = 0 +# asm 1: mov $0,>mulr6=int64#5 +# asm 2: mov $0,>mulr6=%r8 +mov $0,%r8 + +# qhasm: mulr6 += mulrdx + carry +# asm 1: adc mulrax=int64#7 +# asm 2: mov mulrax=%rax +mov %r11,%rax + +# qhasm: mulr7 = 0 +# asm 1: mov $0,>mulr7=int64#6 +# asm 2: mov $0,>mulr7=%r9 +mov $0,%r9 + +# qhasm: mulr7 += mulrdx + carry +# asm 1: adc mulr8=int64#7 +# asm 2: mov $0,>mulr8=%rax +mov $0,%rax + +# qhasm: mulr8 += mulrdx + carry +# asm 1: adc mulzero=int64#2 +# asm 2: mov $0,>mulzero=%rsi +mov $0,%rsi + +# qhasm: mulr8 += mulzero + carry +# asm 1: adc mulr8=int64#3 +# asm 2: imulq $38,mulr8=%rdx +imulq $38,%rax,%rdx + +# qhasm: carry? rt0 += mulr8 +# asm 1: add mulzero=int64#2 +# asm 2: imulq $38,mulzero=%rsi +imulq $38,%rsi,%rsi + +# qhasm: rt0 += mulzero +# asm 1: add addt0=int64#2 +# asm 2: mov $0,>addt0=%rsi +mov $0,%rsi + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#3 +# asm 2: mov $38,>addt1=%rdx +mov $38,%rdx + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae rz0=int64#2 +# asm 2: mov rz0=%rsi +mov %r13,%rsi + +# qhasm: rz1 = rt1 +# asm 1: mov rz1=int64#3 +# asm 2: mov rz1=%rdx +mov %r14,%rdx + +# qhasm: rz2 = rt2 +# asm 1: mov rz2=int64#4 +# asm 2: mov rz2=%rcx +mov %r15,%rcx + +# qhasm: rz3 = rt3 +# asm 1: mov rz3=int64#5 +# asm 2: mov rz3=%r8 +mov %rbx,%r8 + +# qhasm: carry? rz0 += c0_stack +# asm 1: addq addt0=int64#6 +# asm 2: mov $0,>addt0=%r9 +mov $0,%r9 + +# qhasm: addt1 = 38 +# asm 1: mov $38,>addt1=int64#7 +# asm 2: mov $38,>addt1=%rax +mov $38,%rax + +# qhasm: addt1 = addt0 if !carry +# asm 1: cmovae subt0=int64#6 +# asm 2: mov $0,>subt0=%r9 +mov $0,%r9 + +# qhasm: subt1 = 38 +# asm 1: mov $38,>subt1=int64#7 +# asm 2: mov $38,>subt1=%rax +mov $38,%rax + +# qhasm: subt1 = subt0 if !carry +# asm 1: cmovae caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c b/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c new file mode 100644 index 0000000..ffa6e2f --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c @@ -0,0 +1,68 @@ +#include "fe25519.h" +#include "sc25519.h" +#include "ge25519.h" + +/* Multiples of the base point in Niels' representation */ +static const ge25519_niels ge25519_base_multiples_niels[] = { +#ifdef SMALLTABLES +#include "ge25519_base_niels_smalltables.data" +#else +#include "ge25519_base_niels.data" +#endif +}; + +/* d */ +/*static const fe25519 ecd = {{0x75EB4DCA135978A3, 0x00700A4D4141D8AB, 0x8CC740797779E898, 0x52036CEE2B6FFE73}};*/ + +void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s) +{ + signed char b[64]; + int i; + ge25519_niels t; + fe25519 d; + + sc25519_window4(b,s); + +#ifdef SMALLTABLES + ge25519_p1p1 tp1p1; + choose_t((ge25519_niels *)r, 0, (signed long long) b[1], ge25519_base_multiples_niels); + fe25519_sub(&d, &r->y, &r->x); + fe25519_add(&r->y, &r->y, &r->x); + r->x = d; + r->t = r->z; + fe25519_setint(&r->z,2); + for(i=3;i<64;i+=2) + { + choose_t(&t, (unsigned long long) i/2, (signed long long) b[i], ge25519_base_multiples_niels); + ge25519_nielsadd2(r, &t); + } + ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); + ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); + ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); + ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); + ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); + ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); + ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); + ge25519_p1p1_to_p3(r, &tp1p1); + choose_t(&t, (unsigned long long) 0, (signed long long) b[0], ge25519_base_multiples_niels); + fe25519_mul(&t.t2d, &t.t2d, &ecd); + ge25519_nielsadd2(r, &t); + for(i=2;i<64;i+=2) + { + choose_t(&t, (unsigned long long) i/2, (signed long long) b[i], ge25519_base_multiples_niels); + ge25519_nielsadd2(r, &t); + } +#else + choose_t((ge25519_niels *)r, 0, (signed long long) b[0], ge25519_base_multiples_niels); + fe25519_sub(&d, &r->y, &r->x); + fe25519_add(&r->y, &r->y, &r->x); + r->x = d; + r->t = r->z; + fe25519_setint(&r->z,2); + for(i=1;i<64;i++) + { + choose_t(&t, (unsigned long long) i, (signed long long) b[i], ge25519_base_multiples_niels); + ge25519_nielsadd2(r, &t); + } +#endif +} diff --git a/ext/ed25519-amd64-asm/ge25519_unpackneg.c b/ext/ed25519-amd64-asm/ge25519_unpackneg.c new file mode 100644 index 0000000..ff16fd2 --- /dev/null +++ b/ext/ed25519-amd64-asm/ge25519_unpackneg.c @@ -0,0 +1,60 @@ +#include "fe25519.h" +#include "ge25519.h" + +/* d */ +static const fe25519 ecd = {{0x75EB4DCA135978A3, 0x00700A4D4141D8AB, 0x8CC740797779E898, 0x52036CEE2B6FFE73}}; +/* sqrt(-1) */ +static const fe25519 sqrtm1 = {{0xC4EE1B274A0EA0B0, 0x2F431806AD2FE478, 0x2B4D00993DFBD7A7, 0x2B8324804FC1DF0B}}; + +/* return 0 on success, -1 otherwise */ +int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) +{ + fe25519 t, chk, num, den, den2, den4, den6; + unsigned char par = p[31] >> 7; + + fe25519_setint(&r->z,1); + fe25519_unpack(&r->y, p); + fe25519_square(&num, &r->y); /* x = y^2 */ + fe25519_mul(&den, &num, &ecd); /* den = dy^2 */ + fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ + fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ + + /* Computation of sqrt(num/den) + 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) + */ + fe25519_square(&den2, &den); + fe25519_square(&den4, &den2); + fe25519_mul(&den6, &den4, &den2); + fe25519_mul(&t, &den6, &num); + fe25519_mul(&t, &t, &den); + + fe25519_pow2523(&t, &t); + /* 2. computation of r->x = t * num * den^3 + */ + fe25519_mul(&t, &t, &num); + fe25519_mul(&t, &t, &den); + fe25519_mul(&t, &t, &den); + fe25519_mul(&r->x, &t, &den); + + /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: + */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (!fe25519_iseq_vartime(&chk, &num)) + fe25519_mul(&r->x, &r->x, &sqrtm1); + + /* 4. Now we have one of the two square roots, except if input was not a square + */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (!fe25519_iseq_vartime(&chk, &num)) + return -1; + + /* 5. Choose the desired square root according to parity: + */ + if(fe25519_getparity(&r->x) != (1-par)) + fe25519_neg(&r->x, &r->x); + + fe25519_mul(&r->t, &r->x, &r->y); + return 0; +} diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced.s b/ext/ed25519-amd64-asm/heap_rootreplaced.s new file mode 100644 index 0000000..8fe385b --- /dev/null +++ b/ext/ed25519-amd64-asm/heap_rootreplaced.s @@ -0,0 +1,476 @@ + +# qhasm: int64 hp + +# qhasm: int64 hlen + +# qhasm: int64 sp + +# qhasm: int64 pp + +# qhasm: input hp + +# qhasm: input hlen + +# qhasm: input sp + +# qhasm: int64 prc + +# qhasm: int64 plc + +# qhasm: int64 pc + +# qhasm: int64 d + +# qhasm: int64 spp + +# qhasm: int64 sprc + +# qhasm: int64 spc + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 p0 + +# qhasm: int64 p1 + +# qhasm: int64 p2 + +# qhasm: int64 p3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced +.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced +_crypto_sign_ed25519_amd64_64_heap_rootreplaced: +crypto_sign_ed25519_amd64_64_heap_rootreplaced: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: pp = 0 +# asm 1: mov $0,>pp=int64#4 +# asm 2: mov $0,>pp=%rcx +mov $0,%rcx + +# qhasm: siftdownloop: +._siftdownloop: + +# qhasm: prc = pp +# asm 1: mov prc=int64#5 +# asm 2: mov prc=%r8 +mov %rcx,%r8 + +# qhasm: prc *= 2 +# asm 1: imulq $2,prc=int64#5 +# asm 2: imulq $2,prc=%r8 +imulq $2,%r8,%r8 + +# qhasm: pc = prc +# asm 1: mov pc=int64#6 +# asm 2: mov pc=%r9 +mov %r8,%r9 + +# qhasm: prc += 2 +# asm 1: add $2,? hlen - prc +# asm 1: cmp +jbe ._siftuploop + +# qhasm: sprc = *(uint64 *)(hp + prc * 8) +# asm 1: movq (sprc=int64#7 +# asm 2: movq (sprc=%rax +movq (%rdi,%r8,8),%rax + +# qhasm: sprc <<= 5 +# asm 1: shl $5,spc=int64#8 +# asm 2: movq (spc=%r10 +movq (%rdi,%r9,8),%r10 + +# qhasm: spc <<= 5 +# asm 1: shl $5,c0=int64#9 +# asm 2: movq 0(c0=%r11 +movq 0(%r10),%r11 + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#10 +# asm 2: movq 8(c1=%r12 +movq 8(%r10),%r12 + +# qhasm: c2 = *(uint64 *)(spc + 16) +# asm 1: movq 16(c2=int64#11 +# asm 2: movq 16(c2=%r13 +movq 16(%r10),%r13 + +# qhasm: c3 = *(uint64 *)(spc + 24) +# asm 1: movq 24(c3=int64#12 +# asm 2: movq 24(c3=%r14 +movq 24(%r10),%r14 + +# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: *(uint64 *)(hp + pp * 8) = spc +# asm 1: movq pp=int64#4 +# asm 2: mov pp=%rcx +mov %r9,%rcx +# comment:fp stack unchanged by jump + +# qhasm: goto siftdownloop +jmp ._siftdownloop + +# qhasm: siftuploop: +._siftuploop: + +# qhasm: pc = pp +# asm 1: mov pc=int64#2 +# asm 2: mov pc=%rsi +mov %rcx,%rsi + +# qhasm: pp -= 1 +# asm 1: sub $1,>= 1 +# asm 1: shr $1,? pc - 0 +# asm 1: cmp $0, +jbe ._end + +# qhasm: spp = *(uint64 *)(hp + pp * 8) +# asm 1: movq (spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: spc = *(uint64 *)(hp + pc * 8) +# asm 1: movq (spc=int64#6 +# asm 2: movq (spc=%r9 +movq (%rdi,%rsi,8),%r9 + +# qhasm: spp <<= 5 +# asm 1: shl $5,c0=int64#7 +# asm 2: movq 0(c0=%rax +movq 0(%r9),%rax + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#8 +# asm 2: movq 8(c1=%r10 +movq 8(%r9),%r10 + +# qhasm: c2 = *(uint64 *)(spc + 16) +# asm 1: movq 16(c2=int64#9 +# asm 2: movq 16(c2=%r11 +movq 16(%r9),%r11 + +# qhasm: c3 = *(uint64 *)(spc + 24) +# asm 1: movq 24(c3=int64#10 +# asm 2: movq 24(c3=%r12 +movq 24(%r9),%r12 + +# qhasm: carry? c0 -= *(uint64 *)(spp + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,>= 5 +# asm 1: shr $5,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s b/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s new file mode 100644 index 0000000..488e9c5 --- /dev/null +++ b/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s @@ -0,0 +1,416 @@ + +# qhasm: int64 hp + +# qhasm: int64 hlen + +# qhasm: int64 sp + +# qhasm: int64 pp + +# qhasm: input hp + +# qhasm: input hlen + +# qhasm: input sp + +# qhasm: int64 prc + +# qhasm: int64 plc + +# qhasm: int64 pc + +# qhasm: int64 d + +# qhasm: int64 spp + +# qhasm: int64 sprc + +# qhasm: int64 spc + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 p0 + +# qhasm: int64 p1 + +# qhasm: int64 p2 + +# qhasm: int64 p3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb +.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb +_crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb: +crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: pp = 0 +# asm 1: mov $0,>pp=int64#4 +# asm 2: mov $0,>pp=%rcx +mov $0,%rcx + +# qhasm: siftdownloop: +._siftdownloop: + +# qhasm: prc = pp +# asm 1: mov prc=int64#5 +# asm 2: mov prc=%r8 +mov %rcx,%r8 + +# qhasm: prc *= 2 +# asm 1: imulq $2,prc=int64#5 +# asm 2: imulq $2,prc=%r8 +imulq $2,%r8,%r8 + +# qhasm: pc = prc +# asm 1: mov pc=int64#6 +# asm 2: mov pc=%r9 +mov %r8,%r9 + +# qhasm: prc += 2 +# asm 1: add $2,? hlen - prc +# asm 1: cmp +jbe ._siftuploop + +# qhasm: sprc = *(uint64 *)(hp + prc * 8) +# asm 1: movq (sprc=int64#7 +# asm 2: movq (sprc=%rax +movq (%rdi,%r8,8),%rax + +# qhasm: sprc <<= 5 +# asm 1: shl $5,spc=int64#8 +# asm 2: movq (spc=%r10 +movq (%rdi,%r9,8),%r10 + +# qhasm: spc <<= 5 +# asm 1: shl $5,c0=int64#9 +# asm 2: movq 0(c0=%r11 +movq 0(%r10),%r11 + +# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: *(uint64 *)(hp + pp * 8) = spc +# asm 1: movq pp=int64#4 +# asm 2: mov pp=%rcx +mov %r9,%rcx +# comment:fp stack unchanged by jump + +# qhasm: goto siftdownloop +jmp ._siftdownloop + +# qhasm: siftuploop: +._siftuploop: + +# qhasm: pc = pp +# asm 1: mov pc=int64#2 +# asm 2: mov pc=%rsi +mov %rcx,%rsi + +# qhasm: pp -= 1 +# asm 1: sub $1,>= 1 +# asm 1: shr $1,? pc - 0 +# asm 1: cmp $0, +jbe ._end + +# qhasm: spp = *(uint64 *)(hp + pp * 8) +# asm 1: movq (spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: spc = *(uint64 *)(hp + pc * 8) +# asm 1: movq (spc=int64#6 +# asm 2: movq (spc=%r9 +movq (%rdi,%rsi,8),%r9 + +# qhasm: spp <<= 5 +# asm 1: shl $5,c0=int64#7 +# asm 2: movq 0(c0=%rax +movq 0(%r9),%rax + +# qhasm: carry? c0 -= *(uint64 *)(spp + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,>= 5 +# asm 1: shr $5,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s b/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s new file mode 100644 index 0000000..f925918 --- /dev/null +++ b/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s @@ -0,0 +1,436 @@ + +# qhasm: int64 hp + +# qhasm: int64 hlen + +# qhasm: int64 sp + +# qhasm: int64 pp + +# qhasm: input hp + +# qhasm: input hlen + +# qhasm: input sp + +# qhasm: int64 prc + +# qhasm: int64 plc + +# qhasm: int64 pc + +# qhasm: int64 d + +# qhasm: int64 spp + +# qhasm: int64 sprc + +# qhasm: int64 spc + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 p0 + +# qhasm: int64 p1 + +# qhasm: int64 p2 + +# qhasm: int64 p3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs +.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs +_crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs: +crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: pp = 0 +# asm 1: mov $0,>pp=int64#4 +# asm 2: mov $0,>pp=%rcx +mov $0,%rcx + +# qhasm: siftdownloop: +._siftdownloop: + +# qhasm: prc = pp +# asm 1: mov prc=int64#5 +# asm 2: mov prc=%r8 +mov %rcx,%r8 + +# qhasm: prc *= 2 +# asm 1: imulq $2,prc=int64#5 +# asm 2: imulq $2,prc=%r8 +imulq $2,%r8,%r8 + +# qhasm: pc = prc +# asm 1: mov pc=int64#6 +# asm 2: mov pc=%r9 +mov %r8,%r9 + +# qhasm: prc += 2 +# asm 1: add $2,? hlen - prc +# asm 1: cmp +jbe ._siftuploop + +# qhasm: sprc = *(uint64 *)(hp + prc * 8) +# asm 1: movq (sprc=int64#7 +# asm 2: movq (sprc=%rax +movq (%rdi,%r8,8),%rax + +# qhasm: sprc <<= 5 +# asm 1: shl $5,spc=int64#8 +# asm 2: movq (spc=%r10 +movq (%rdi,%r9,8),%r10 + +# qhasm: spc <<= 5 +# asm 1: shl $5,c0=int64#9 +# asm 2: movq 0(c0=%r11 +movq 0(%r10),%r11 + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#10 +# asm 2: movq 8(c1=%r12 +movq 8(%r10),%r12 + +# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: *(uint64 *)(hp + pp * 8) = spc +# asm 1: movq pp=int64#4 +# asm 2: mov pp=%rcx +mov %r9,%rcx +# comment:fp stack unchanged by jump + +# qhasm: goto siftdownloop +jmp ._siftdownloop + +# qhasm: siftuploop: +._siftuploop: + +# qhasm: pc = pp +# asm 1: mov pc=int64#2 +# asm 2: mov pc=%rsi +mov %rcx,%rsi + +# qhasm: pp -= 1 +# asm 1: sub $1,>= 1 +# asm 1: shr $1,? pc - 0 +# asm 1: cmp $0, +jbe ._end + +# qhasm: spp = *(uint64 *)(hp + pp * 8) +# asm 1: movq (spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: spc = *(uint64 *)(hp + pc * 8) +# asm 1: movq (spc=int64#6 +# asm 2: movq (spc=%r9 +movq (%rdi,%rsi,8),%r9 + +# qhasm: spp <<= 5 +# asm 1: shl $5,c0=int64#7 +# asm 2: movq 0(c0=%rax +movq 0(%r9),%rax + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#8 +# asm 2: movq 8(c1=%r10 +movq 8(%r9),%r10 + +# qhasm: carry? c0 -= *(uint64 *)(spp + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,>= 5 +# asm 1: shr $5,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s b/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s new file mode 100644 index 0000000..dcf890e --- /dev/null +++ b/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s @@ -0,0 +1,456 @@ + +# qhasm: int64 hp + +# qhasm: int64 hlen + +# qhasm: int64 sp + +# qhasm: int64 pp + +# qhasm: input hp + +# qhasm: input hlen + +# qhasm: input sp + +# qhasm: int64 prc + +# qhasm: int64 plc + +# qhasm: int64 pc + +# qhasm: int64 d + +# qhasm: int64 spp + +# qhasm: int64 sprc + +# qhasm: int64 spc + +# qhasm: int64 c0 + +# qhasm: int64 c1 + +# qhasm: int64 c2 + +# qhasm: int64 c3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 p0 + +# qhasm: int64 p1 + +# qhasm: int64 p2 + +# qhasm: int64 p3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs +.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs +_crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs: +crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: pp = 0 +# asm 1: mov $0,>pp=int64#4 +# asm 2: mov $0,>pp=%rcx +mov $0,%rcx + +# qhasm: siftdownloop: +._siftdownloop: + +# qhasm: prc = pp +# asm 1: mov prc=int64#5 +# asm 2: mov prc=%r8 +mov %rcx,%r8 + +# qhasm: prc *= 2 +# asm 1: imulq $2,prc=int64#5 +# asm 2: imulq $2,prc=%r8 +imulq $2,%r8,%r8 + +# qhasm: pc = prc +# asm 1: mov pc=int64#6 +# asm 2: mov pc=%r9 +mov %r8,%r9 + +# qhasm: prc += 2 +# asm 1: add $2,? hlen - prc +# asm 1: cmp +jbe ._siftuploop + +# qhasm: sprc = *(uint64 *)(hp + prc * 8) +# asm 1: movq (sprc=int64#7 +# asm 2: movq (sprc=%rax +movq (%rdi,%r8,8),%rax + +# qhasm: sprc <<= 5 +# asm 1: shl $5,spc=int64#8 +# asm 2: movq (spc=%r10 +movq (%rdi,%r9,8),%r10 + +# qhasm: spc <<= 5 +# asm 1: shl $5,c0=int64#9 +# asm 2: movq 0(c0=%r11 +movq 0(%r10),%r11 + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#10 +# asm 2: movq 8(c1=%r12 +movq 8(%r10),%r12 + +# qhasm: c2 = *(uint64 *)(spc + 16) +# asm 1: movq 16(c2=int64#11 +# asm 2: movq 16(c2=%r13 +movq 16(%r10),%r13 + +# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: *(uint64 *)(hp + pp * 8) = spc +# asm 1: movq pp=int64#4 +# asm 2: mov pp=%rcx +mov %r9,%rcx +# comment:fp stack unchanged by jump + +# qhasm: goto siftdownloop +jmp ._siftdownloop + +# qhasm: siftuploop: +._siftuploop: + +# qhasm: pc = pp +# asm 1: mov pc=int64#2 +# asm 2: mov pc=%rsi +mov %rcx,%rsi + +# qhasm: pp -= 1 +# asm 1: sub $1,>= 1 +# asm 1: shr $1,? pc - 0 +# asm 1: cmp $0, +jbe ._end + +# qhasm: spp = *(uint64 *)(hp + pp * 8) +# asm 1: movq (spp=int64#5 +# asm 2: movq (spp=%r8 +movq (%rdi,%rcx,8),%r8 + +# qhasm: spc = *(uint64 *)(hp + pc * 8) +# asm 1: movq (spc=int64#6 +# asm 2: movq (spc=%r9 +movq (%rdi,%rsi,8),%r9 + +# qhasm: spp <<= 5 +# asm 1: shl $5,c0=int64#7 +# asm 2: movq 0(c0=%rax +movq 0(%r9),%rax + +# qhasm: c1 = *(uint64 *)(spc + 8) +# asm 1: movq 8(c1=int64#8 +# asm 2: movq 8(c1=%r10 +movq 8(%r9),%r10 + +# qhasm: c2 = *(uint64 *)(spc + 16) +# asm 1: movq 16(c2=int64#9 +# asm 2: movq 16(c2=%r11 +movq 16(%r9),%r11 + +# qhasm: carry? c0 -= *(uint64 *)(spp + 0) +# asm 1: subq 0(>= 5 +# asm 1: shr $5,>= 5 +# asm 1: shr $5,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/hram.c b/ext/ed25519-amd64-asm/hram.c new file mode 100644 index 0000000..6f99fc6 --- /dev/null +++ b/ext/ed25519-amd64-asm/hram.c @@ -0,0 +1,16 @@ +/*#include "crypto_hash_sha512.h"*/ +#include "hram.h" + +extern void ZT_sha512internal(void *digest,const void *data,unsigned int len); + +void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) +{ + unsigned long long i; + + for (i = 0;i < 32;++i) playground[i] = sm[i]; + for (i = 32;i < 64;++i) playground[i] = pk[i-32]; + for (i = 64;i < smlen;++i) playground[i] = sm[i]; + + /*crypto_hash_sha512(hram,playground,smlen);*/ + ZT_sha512internal(hram,playground,smlen); +} diff --git a/ext/ed25519-amd64-asm/hram.h b/ext/ed25519-amd64-asm/hram.h new file mode 100644 index 0000000..1740c78 --- /dev/null +++ b/ext/ed25519-amd64-asm/hram.h @@ -0,0 +1,8 @@ +#ifndef HRAM_H +#define HRAM_H + +#define get_hram crypto_sign_ed25519_amd64_64_get_hram + +extern void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen); + +#endif diff --git a/ext/ed25519-amd64-asm/implementors b/ext/ed25519-amd64-asm/implementors new file mode 100644 index 0000000..9b5399a --- /dev/null +++ b/ext/ed25519-amd64-asm/implementors @@ -0,0 +1,5 @@ +Daniel J. Bernstein +Niels Duif +Tanja Lange +lead: Peter Schwabe +Bo-Yin Yang diff --git a/ext/ed25519-amd64-asm/index_heap.c b/ext/ed25519-amd64-asm/index_heap.c new file mode 100644 index 0000000..f29f7a2 --- /dev/null +++ b/ext/ed25519-amd64-asm/index_heap.c @@ -0,0 +1,58 @@ +#include "sc25519.h" +#include "index_heap.h" + +/* caller's responsibility to ensure hlen>=3 */ +void heap_init(unsigned long long *h, unsigned long long hlen, sc25519 *scalars) +{ + h[0] = 0; + unsigned long long i=1; + while(i 0) + { + /* if(sc25519_lt_vartime(&scalars[h[ppos]], &scalars[h[pos]])) */ + if(sc25519_lt(&scalars[h[ppos]], &scalars[h[pos]])) + { + t = h[ppos]; + h[ppos] = h[pos]; + h[pos] = t; + pos = ppos; + ppos = (pos-1)/2; + } + else break; + } + (*hlen)++; +} + +/* Put the largest value in the heap in max1, the second largest in max2 */ +void heap_get2max(unsigned long long *h, unsigned long long *max1, unsigned long long *max2, sc25519 *scalars) +{ + *max1 = h[0]; + *max2 = h[1]; + if(sc25519_lt(&scalars[h[1]],&scalars[h[2]])) + *max2 = h[2]; +} + +/* After the root has been replaced, restore heap property */ +/* extern void heap_rootreplaced(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); +*/ +/* extern void heap_rootreplaced_shortscalars(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); +*/ diff --git a/ext/ed25519-amd64-asm/index_heap.h b/ext/ed25519-amd64-asm/index_heap.h new file mode 100644 index 0000000..7dee916 --- /dev/null +++ b/ext/ed25519-amd64-asm/index_heap.h @@ -0,0 +1,31 @@ +#ifndef INDEX_HEAP_H +#define INDEX_HEAP_H + +#include "sc25519.h" + +#define heap_init crypto_sign_ed25519_amd64_64_heap_init +#define heap_extend crypto_sign_ed25519_amd64_64_heap_extend +#define heap_pop crypto_sign_ed25519_amd64_64_heap_pop +#define heap_push crypto_sign_ed25519_amd64_64_heap_push +#define heap_get2max crypto_sign_ed25519_amd64_64_heap_get2max +#define heap_rootreplaced crypto_sign_ed25519_amd64_64_heap_rootreplaced +#define heap_rootreplaced_3limbs crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs +#define heap_rootreplaced_2limbs crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs +#define heap_rootreplaced_1limb crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb + +void heap_init(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); + +void heap_extend(unsigned long long *h, unsigned long long oldlen, unsigned long long newlen, sc25519 *scalars); + +unsigned long long heap_pop(unsigned long long *h, unsigned long long *hlen, sc25519 *scalars); + +void heap_push(unsigned long long *h, unsigned long long *hlen, unsigned long long elem, sc25519 *scalars); + +void heap_get2max(unsigned long long *h, unsigned long long *max1, unsigned long long *max2, sc25519 *scalars); + +void heap_rootreplaced(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); +void heap_rootreplaced_3limbs(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); +void heap_rootreplaced_2limbs(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); +void heap_rootreplaced_1limb(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); + +#endif diff --git a/ext/ed25519-amd64-asm/keypair.c b/ext/ed25519-amd64-asm/keypair.c new file mode 100644 index 0000000..7e09471 --- /dev/null +++ b/ext/ed25519-amd64-asm/keypair.c @@ -0,0 +1,25 @@ +#include +#include "crypto_sign.h" +#include "crypto_hash_sha512.h" +#include "randombytes.h" +#include "ge25519.h" + +int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) +{ + unsigned char az[64]; + sc25519 scsk; + ge25519 gepk; + + randombytes(sk,32); + crypto_hash_sha512(az,sk,32); + az[0] &= 248; + az[31] &= 127; + az[31] |= 64; + + sc25519_from32bytes(&scsk,az); + + ge25519_scalarmult_base(&gepk, &scsk); + ge25519_pack(pk, &gepk); + memmove(sk + 32,pk,32); + return 0; +} diff --git a/ext/ed25519-amd64-asm/open.c b/ext/ed25519-amd64-asm/open.c new file mode 100644 index 0000000..104d48d --- /dev/null +++ b/ext/ed25519-amd64-asm/open.c @@ -0,0 +1,49 @@ +#include +#include "crypto_sign.h" +#include "crypto_verify_32.h" +#include "crypto_hash_sha512.h" +#include "ge25519.h" + +int crypto_sign_open( + unsigned char *m,unsigned long long *mlen, + const unsigned char *sm,unsigned long long smlen, + const unsigned char *pk + ) +{ + unsigned char pkcopy[32]; + unsigned char rcopy[32]; + unsigned char hram[64]; + unsigned char rcheck[32]; + ge25519 get1, get2; + sc25519 schram, scs; + + if (smlen < 64) goto badsig; + if (sm[63] & 224) goto badsig; + if (ge25519_unpackneg_vartime(&get1,pk)) goto badsig; + + memmove(pkcopy,pk,32); + memmove(rcopy,sm,32); + + sc25519_from32bytes(&scs, sm+32); + + memmove(m,sm,smlen); + memmove(m + 32,pkcopy,32); + crypto_hash_sha512(hram,m,smlen); + + sc25519_from64bytes(&schram, hram); + + ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &scs); + ge25519_pack(rcheck, &get2); + + if (crypto_verify_32(rcopy,rcheck) == 0) { + memmove(m,m + 64,smlen - 64); + memset(m + smlen - 64,0,64); + *mlen = smlen - 64; + return 0; + } + +badsig: + *mlen = (unsigned long long) -1; + memset(m,0,smlen); + return -1; +} diff --git a/ext/ed25519-amd64-asm/sc25519.h b/ext/ed25519-amd64-asm/sc25519.h new file mode 100644 index 0000000..8ff1b1c --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519.h @@ -0,0 +1,66 @@ +#ifndef SC25519_H +#define SC25519_H + +#define sc25519 crypto_sign_ed25519_amd64_64_sc25519 +#define shortsc25519 crypto_sign_ed25519_amd64_64_shortsc25519 +#define sc25519_from32bytes crypto_sign_ed25519_amd64_64_sc25519_from32bytes +#define shortsc25519_from16bytes crypto_sign_ed25519_amd64_64_shortsc25519_from16bytes +#define sc25519_from64bytes crypto_sign_ed25519_amd64_64_sc25519_from64bytes +#define sc25519_from_shortsc crypto_sign_ed25519_amd64_64_sc25519_from_shortsc +#define sc25519_to32bytes crypto_sign_ed25519_amd64_64_sc25519_to32bytes +#define sc25519_iszero_vartime crypto_sign_ed25519_amd64_64_sc25519_iszero_vartime +#define sc25519_isshort_vartime crypto_sign_ed25519_amd64_64_sc25519_isshort_vartime +#define sc25519_lt crypto_sign_ed25519_amd64_64_sc25519_lt +#define sc25519_add crypto_sign_ed25519_amd64_64_sc25519_add +#define sc25519_sub_nored crypto_sign_ed25519_amd64_64_sc25519_sub_nored +#define sc25519_mul crypto_sign_ed25519_amd64_64_sc25519_mul +#define sc25519_mul_shortsc crypto_sign_ed25519_amd64_64_sc25519_mul_shortsc +#define sc25519_window4 crypto_sign_ed25519_amd64_64_sc25519_window4 +#define sc25519_slide crypto_sign_ed25519_amd64_64_sc25519_slide +#define sc25519_2interleave2 crypto_sign_ed25519_amd64_64_sc25519_2interleave2 +#define sc25519_barrett crypto_sign_ed25519_amd64_64_sc25519_barrett + +typedef struct +{ + unsigned long long v[4]; +} +sc25519; + +typedef struct +{ + unsigned long long v[2]; +} +shortsc25519; + +void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]); + +void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]); + +void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x); + +void sc25519_to32bytes(unsigned char r[32], const sc25519 *x); + +int sc25519_iszero_vartime(const sc25519 *x); + +int sc25519_lt(const sc25519 *x, const sc25519 *y); + +void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y); + +/* Convert s into a representation of the form \sum_{i=0}^{63}r[i]2^(4*i) + * with r[i] in {-8,...,7} + */ +void sc25519_window4(signed char r[85], const sc25519 *s); + +void sc25519_slide(signed char r[256], const sc25519 *s, int swindowsize); + +void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2); + +void sc25519_barrett(sc25519 *r, unsigned long long x[8]); + +#endif diff --git a/ext/ed25519-amd64-asm/sc25519_add.s b/ext/ed25519-amd64-asm/sc25519_add.s new file mode 100644 index 0000000..d5b941c --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_add.s @@ -0,0 +1,232 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_add +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_sc25519_add +.globl crypto_sign_ed25519_amd64_64_sc25519_add +_crypto_sign_ed25519_amd64_64_sc25519_add: +crypto_sign_ed25519_amd64_64_sc25519_add: +mov %rsp,%r11 +and $31,%r11 +add $32,%r11 +sub %r11,%rsp + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#1 +# asm 2: movq caller4_stack=0(%rsp) +movq %r14,0(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#2 +# asm 2: movq caller5_stack=8(%rsp) +movq %r15,8(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#3 +# asm 2: movq caller6_stack=16(%rsp) +movq %rbx,16(%rsp) + +# qhasm: r0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(r0=int64#4 +# asm 2: movq 0(r0=%rcx +movq 0(%rsi),%rcx + +# qhasm: r1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(r1=int64#5 +# asm 2: movq 8(r1=%r8 +movq 8(%rsi),%r8 + +# qhasm: r2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(r2=int64#6 +# asm 2: movq 16(r2=%r9 +movq 16(%rsi),%r9 + +# qhasm: r3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(r3=int64#2 +# asm 2: movq 24(r3=%rsi +movq 24(%rsi),%rsi + +# qhasm: carry? r0 += *(uint64 *)(yp + 0) +# asm 1: addq 0(t0=int64#3 +# asm 2: mov t0=%rdx +mov %rcx,%rdx + +# qhasm: t1 = r1 +# asm 1: mov t1=int64#7 +# asm 2: mov t1=%rax +mov %r8,%rax + +# qhasm: t2 = r2 +# asm 1: mov t2=int64#8 +# asm 2: mov t2=%r10 +mov %r9,%r10 + +# qhasm: t3 = r3 +# asm 1: mov t3=int64#12 +# asm 2: mov t3=%r14 +mov %rsi,%r14 + +# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 0(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 8(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 16(%rsp),%rbx + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/sc25519_barrett.s b/ext/ed25519-amd64-asm/sc25519_barrett.s new file mode 100644 index 0000000..7eb56fa --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_barrett.s @@ -0,0 +1,1188 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: int64 q23 + +# qhasm: int64 q24 + +# qhasm: int64 q30 + +# qhasm: int64 q31 + +# qhasm: int64 q32 + +# qhasm: int64 q33 + +# qhasm: int64 r20 + +# qhasm: int64 r21 + +# qhasm: int64 r22 + +# qhasm: int64 r23 + +# qhasm: int64 r24 + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 rax + +# qhasm: int64 rdx + +# qhasm: int64 c + +# qhasm: int64 zero + +# qhasm: int64 mask + +# qhasm: int64 nmask + +# qhasm: stack64 q30_stack + +# qhasm: stack64 q31_stack + +# qhasm: stack64 q32_stack + +# qhasm: stack64 q33_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_barrett +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_sc25519_barrett +.globl crypto_sign_ed25519_amd64_64_sc25519_barrett +_crypto_sign_ed25519_amd64_64_sc25519_barrett: +crypto_sign_ed25519_amd64_64_sc25519_barrett: +mov %rsp,%r11 +and $31,%r11 +add $96,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: zero ^= zero +# asm 1: xor rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 +mulq crypto_sign_ed25519_amd64_64_MU3(%rip) + +# qhasm: q23 = rax +# asm 1: mov q23=int64#10 +# asm 2: mov q23=%r12 +mov %rax,%r12 + +# qhasm: c = rdx +# asm 1: mov c=int64#11 +# asm 2: mov c=%r13 +mov %rdx,%r13 + +# qhasm: rax = *(uint64 *)(xp + 24) +# asm 1: movq 24(rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 +mulq crypto_sign_ed25519_amd64_64_MU4(%rip) + +# qhasm: q24 = rax +# asm 1: mov q24=int64#12 +# asm 2: mov q24=%r14 +mov %rax,%r14 + +# qhasm: carry? q24 += c +# asm 1: add rax=int64#7 +# asm 2: movq 32(rax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 +mulq crypto_sign_ed25519_amd64_64_MU2(%rip) + +# qhasm: carry? q23 += rax +# asm 1: add c=int64#11 +# asm 2: mov $0,>c=%r13 +mov $0,%r13 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 32(rax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 +mulq crypto_sign_ed25519_amd64_64_MU3(%rip) + +# qhasm: carry? q24 += rax +# asm 1: add c=int64#11 +# asm 2: mov $0,>c=%r13 +mov $0,%r13 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 32(rax=%rax +movq 32(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 +mulq crypto_sign_ed25519_amd64_64_MU4(%rip) + +# qhasm: carry? q30 += rax +# asm 1: add rax=int64#7 +# asm 2: movq 40(rax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 +mulq crypto_sign_ed25519_amd64_64_MU1(%rip) + +# qhasm: carry? q23 += rax +# asm 1: add c=int64#11 +# asm 2: mov $0,>c=%r13 +mov $0,%r13 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 40(rax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 +mulq crypto_sign_ed25519_amd64_64_MU2(%rip) + +# qhasm: carry? q24 += rax +# asm 1: add c=int64#11 +# asm 2: mov $0,>c=%r13 +mov $0,%r13 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 40(rax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 +mulq crypto_sign_ed25519_amd64_64_MU3(%rip) + +# qhasm: carry? q30 += rax +# asm 1: add c=int64#11 +# asm 2: mov $0,>c=%r13 +mov $0,%r13 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 40(rax=%rax +movq 40(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 +mulq crypto_sign_ed25519_amd64_64_MU4(%rip) + +# qhasm: carry? q31 += rax +# asm 1: add rax=int64#7 +# asm 2: movq 48(rax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU0 +mulq crypto_sign_ed25519_amd64_64_MU0(%rip) + +# qhasm: carry? q23 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 48(rax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 +mulq crypto_sign_ed25519_amd64_64_MU1(%rip) + +# qhasm: carry? q24 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 48(rax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 +mulq crypto_sign_ed25519_amd64_64_MU2(%rip) + +# qhasm: carry? q30 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 48(rax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 +mulq crypto_sign_ed25519_amd64_64_MU3(%rip) + +# qhasm: carry? q31 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 48(rax=%rax +movq 48(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 +mulq crypto_sign_ed25519_amd64_64_MU4(%rip) + +# qhasm: carry? q32 += rax +# asm 1: add rax=int64#7 +# asm 2: movq 56(rax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU0 +mulq crypto_sign_ed25519_amd64_64_MU0(%rip) + +# qhasm: carry? q24 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 56(rax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 +mulq crypto_sign_ed25519_amd64_64_MU1(%rip) + +# qhasm: carry? q30 += rax +# asm 1: add c=int64#10 +# asm 2: mov $0,>c=%r12 +mov $0,%r12 + +# qhasm: c += rdx + carry +# asm 1: adc q30_stack=stack64#8 +# asm 2: movq q30_stack=56(%rsp) +movq %r8,56(%rsp) + +# qhasm: rax = *(uint64 *)(xp + 56) +# asm 1: movq 56(rax=int64#7 +# asm 2: movq 56(rax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 +mulq crypto_sign_ed25519_amd64_64_MU2(%rip) + +# qhasm: carry? q31 += rax +# asm 1: add c=int64#5 +# asm 2: mov $0,>c=%r8 +mov $0,%r8 + +# qhasm: c += rdx + carry +# asm 1: adc q31_stack=stack64#9 +# asm 2: movq q31_stack=64(%rsp) +movq %r9,64(%rsp) + +# qhasm: rax = *(uint64 *)(xp + 56) +# asm 1: movq 56(rax=int64#7 +# asm 2: movq 56(rax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 +mulq crypto_sign_ed25519_amd64_64_MU3(%rip) + +# qhasm: carry? q32 += rax +# asm 1: add c=int64#5 +# asm 2: mov $0,>c=%r8 +mov $0,%r8 + +# qhasm: c += rdx + carry +# asm 1: adc q32_stack=stack64#10 +# asm 2: movq q32_stack=72(%rsp) +movq %r10,72(%rsp) + +# qhasm: rax = *(uint64 *)(xp + 56) +# asm 1: movq 56(rax=int64#7 +# asm 2: movq 56(rax=%rax +movq 56(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 +mulq crypto_sign_ed25519_amd64_64_MU4(%rip) + +# qhasm: carry? q33 += rax +# asm 1: add q33_stack=stack64#11 +# asm 2: movq q33_stack=80(%rsp) +movq %r11,80(%rsp) + +# qhasm: rax = q30_stack +# asm 1: movq rax=int64#7 +# asm 2: movq rax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) + +# qhasm: r20 = rax +# asm 1: mov r20=int64#5 +# asm 2: mov r20=%r8 +mov %rax,%r8 + +# qhasm: c = rdx +# asm 1: mov c=int64#6 +# asm 2: mov c=%r9 +mov %rdx,%r9 + +# qhasm: rax = q30_stack +# asm 1: movq rax=int64#7 +# asm 2: movq rax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 +mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) + +# qhasm: r21 = rax +# asm 1: mov r21=int64#8 +# asm 2: mov r21=%r10 +mov %rax,%r10 + +# qhasm: carry? r21 += c +# asm 1: add c=int64#6 +# asm 2: mov $0,>c=%r9 +mov $0,%r9 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq rax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER2 +mulq crypto_sign_ed25519_amd64_64_ORDER2(%rip) + +# qhasm: r22 = rax +# asm 1: mov r22=int64#9 +# asm 2: mov r22=%r11 +mov %rax,%r11 + +# qhasm: carry? r22 += c +# asm 1: add c=int64#6 +# asm 2: mov $0,>c=%r9 +mov $0,%r9 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq rax=%rax +movq 56(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER3 +mulq crypto_sign_ed25519_amd64_64_ORDER3(%rip) + +# qhasm: free rdx + +# qhasm: r23 = rax +# asm 1: mov r23=int64#10 +# asm 2: mov r23=%r12 +mov %rax,%r12 + +# qhasm: r23 += c +# asm 1: add rax=int64#7 +# asm 2: movq rax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) + +# qhasm: carry? r21 += rax +# asm 1: add c=int64#6 +# asm 2: mov $0,>c=%r9 +mov $0,%r9 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq rax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 +mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) + +# qhasm: carry? r22 += rax +# asm 1: add c=int64#4 +# asm 2: mov $0,>c=%rcx +mov $0,%rcx + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq rax=%rax +movq 64(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER2 +mulq crypto_sign_ed25519_amd64_64_ORDER2(%rip) + +# qhasm: free rdx + +# qhasm: r23 += rax +# asm 1: add rax=int64#7 +# asm 2: movq rax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) + +# qhasm: carry? r22 += rax +# asm 1: add c=int64#4 +# asm 2: mov $0,>c=%rcx +mov $0,%rcx + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq rax=%rax +movq 72(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 +mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) + +# qhasm: free rdx + +# qhasm: r23 += rax +# asm 1: add rax=int64#7 +# asm 2: movq rax=%rax +movq 80(%rsp),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) + +# qhasm: free rdx + +# qhasm: r23 += rax +# asm 1: add r0=int64#3 +# asm 2: movq 0(r0=%rdx +movq 0(%rsi),%rdx + +# qhasm: carry? r0 -= r20 +# asm 1: sub t0=int64#4 +# asm 2: mov t0=%rcx +mov %rdx,%rcx + +# qhasm: r1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(r1=int64#5 +# asm 2: movq 8(r1=%r8 +movq 8(%rsi),%r8 + +# qhasm: carry? r1 -= r21 - carry +# asm 1: sbb t1=int64#6 +# asm 2: mov t1=%r9 +mov %r8,%r9 + +# qhasm: r2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(r2=int64#7 +# asm 2: movq 16(r2=%rax +movq 16(%rsi),%rax + +# qhasm: carry? r2 -= r22 - carry +# asm 1: sbb t2=int64#8 +# asm 2: mov t2=%r10 +mov %rax,%r10 + +# qhasm: r3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(r3=int64#2 +# asm 2: movq 24(r3=%rsi +movq 24(%rsi),%rsi + +# qhasm: r3 -= r23 - carry +# asm 1: sbb t3=int64#9 +# asm 2: mov t3=%r11 +mov %rsi,%r11 + +# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,t0=int64#4 +# asm 2: mov t0=%rcx +mov %rdx,%rcx + +# qhasm: r1 = t1 if !unsigned< +# asm 1: cmovae t1=int64#6 +# asm 2: mov t1=%r9 +mov %r8,%r9 + +# qhasm: r2 = t2 if !unsigned< +# asm 1: cmovae t2=int64#8 +# asm 2: mov t2=%r10 +mov %rax,%r10 + +# qhasm: r3 = t3 if !unsigned< +# asm 1: cmovae t3=int64#9 +# asm 2: mov t3=%r11 +mov %rsi,%r11 + +# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 +# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/ed25519-amd64-asm/sc25519_from32bytes.c b/ext/ed25519-amd64-asm/sc25519_from32bytes.c new file mode 100644 index 0000000..7f21e68 --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_from32bytes.c @@ -0,0 +1,55 @@ +#include "sc25519.h" + +/*Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 + * = 7237005577332262213973186563042994240857116359379907606001950938285454250989 + */ + +/* Contains order, 2*order, 4*order, 8*order, each represented in 4 consecutive unsigned long long */ +static const unsigned long long order[16] = {0x5812631A5CF5D3EDULL, 0x14DEF9DEA2F79CD6ULL, + 0x0000000000000000ULL, 0x1000000000000000ULL, + 0xB024C634B9EBA7DAULL, 0x29BDF3BD45EF39ACULL, + 0x0000000000000000ULL, 0x2000000000000000ULL, + 0x60498C6973D74FB4ULL, 0x537BE77A8BDE7359ULL, + 0x0000000000000000ULL, 0x4000000000000000ULL, + 0xC09318D2E7AE9F68ULL, 0xA6F7CEF517BCE6B2ULL, + 0x0000000000000000ULL, 0x8000000000000000ULL}; + +static unsigned long long smaller(unsigned long long a,unsigned long long b) +{ + unsigned long long atop = a >> 32; + unsigned long long abot = a & 4294967295; + unsigned long long btop = b >> 32; + unsigned long long bbot = b & 4294967295; + unsigned long long atopbelowbtop = (atop - btop) >> 63; + unsigned long long atopeqbtop = ((atop ^ btop) - 1) >> 63; + unsigned long long abotbelowbbot = (abot - bbot) >> 63; + return atopbelowbtop | (atopeqbtop & abotbelowbbot); +} + +void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]) +{ + unsigned long long t[4]; + unsigned long long b; + unsigned long long mask; + int i, j; + + /* assuming little-endian */ + r->v[0] = *(unsigned long long *)x; + r->v[1] = *(((unsigned long long *)x)+1); + r->v[2] = *(((unsigned long long *)x)+2); + r->v[3] = *(((unsigned long long *)x)+3); + + for(j=3;j>=0;j--) + { + b=0; + for(i=0;i<4;i++) + { + b += order[4*j+i]; /* no overflow for this particular order */ + t[i] = r->v[i] - b; + b = smaller(r->v[i],b); + } + mask = b - 1; + for(i=0;i<4;i++) + r->v[i] ^= mask & (r->v[i] ^ t[i]); + } +} diff --git a/ext/ed25519-amd64-asm/sc25519_from64bytes.c b/ext/ed25519-amd64-asm/sc25519_from64bytes.c new file mode 100644 index 0000000..8e76a1b --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_from64bytes.c @@ -0,0 +1,7 @@ +#include "sc25519.h" + +void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]) +{ + /* assuming little-endian representation of unsigned long long */ + sc25519_barrett(r, (unsigned long long *)x); +} diff --git a/ext/ed25519-amd64-asm/sc25519_from_shortsc.c b/ext/ed25519-amd64-asm/sc25519_from_shortsc.c new file mode 100644 index 0000000..3b8ff2f --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_from_shortsc.c @@ -0,0 +1,9 @@ +#include "sc25519.h" + +void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x) +{ + r->v[0] = x->v[0]; + r->v[1] = x->v[1]; + r->v[2] = 0; + r->v[3] = 0; +} diff --git a/ext/ed25519-amd64-asm/sc25519_iszero.c b/ext/ed25519-amd64-asm/sc25519_iszero.c new file mode 100644 index 0000000..21f593d --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_iszero.c @@ -0,0 +1,10 @@ +#include "sc25519.h" + +int sc25519_iszero_vartime(const sc25519 *x) +{ + if(x->v[0] != 0) return 0; + if(x->v[1] != 0) return 0; + if(x->v[2] != 0) return 0; + if(x->v[3] != 0) return 0; + return 1; +} diff --git a/ext/ed25519-amd64-asm/sc25519_lt.s b/ext/ed25519-amd64-asm/sc25519_lt.s new file mode 100644 index 0000000..3ba4317 --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_lt.s @@ -0,0 +1,131 @@ + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: int64 ret + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: output ret + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 doof + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_lt +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_sc25519_lt +.globl crypto_sign_ed25519_amd64_64_sc25519_lt +_crypto_sign_ed25519_amd64_64_sc25519_lt: +crypto_sign_ed25519_amd64_64_sc25519_lt: +mov %rsp,%r11 +and $31,%r11 +add $0,%r11 +sub %r11,%rsp + +# qhasm: t0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(t0=int64#3 +# asm 2: movq 0(t0=%rdx +movq 0(%rdi),%rdx + +# qhasm: t1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(t1=int64#4 +# asm 2: movq 8(t1=%rcx +movq 8(%rdi),%rcx + +# qhasm: t2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(t2=int64#5 +# asm 2: movq 16(t2=%r8 +movq 16(%rdi),%r8 + +# qhasm: t3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(t3=int64#1 +# asm 2: movq 24(t3=%rdi +movq 24(%rdi),%rdi + +# qhasm: carry? t0 -= *(uint64 *)(yp + 0) +# asm 1: subq 0(ret=int64#1 +# asm 2: mov $0,>ret=%rdi +mov $0,%rdi + +# qhasm: doof = 1 +# asm 1: mov $1,>doof=int64#2 +# asm 2: mov $1,>doof=%rsi +mov $1,%rsi + +# qhasm: ret = doof if carry +# asm 1: cmovc v, y->v); + sc25519_barrett(r, t); +} diff --git a/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c b/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c new file mode 100644 index 0000000..0c67250 --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c @@ -0,0 +1,9 @@ +#include "sc25519.h" + +void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y) +{ + /* XXX: This wants to be faster */ + sc25519 t; + sc25519_from_shortsc(&t, y); + sc25519_mul(r, x, &t); +} diff --git a/ext/ed25519-amd64-asm/sc25519_slide.c b/ext/ed25519-amd64-asm/sc25519_slide.c new file mode 100644 index 0000000..4e52010 --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_slide.c @@ -0,0 +1,49 @@ +#include "sc25519.h" + +void sc25519_slide(signed char r[256], const sc25519 *s, int swindowsize) +{ + int i,j,k,b,m=(1<<(swindowsize-1))-1, soplen=256; + unsigned long long sv0 = s->v[0]; + unsigned long long sv1 = s->v[1]; + unsigned long long sv2 = s->v[2]; + unsigned long long sv3 = s->v[3]; + + /* first put the binary expansion into r */ + for(i=0;i<64;i++) { + r[i] = sv0 & 1; + r[i+64] = sv1 & 1; + r[i+128] = sv2 & 1; + r[i+192] = sv3 & 1; + sv0 >>= 1; + sv1 >>= 1; + sv2 >>= 1; + sv3 >>= 1; + } + + /* Making it sliding window */ + for (j = 0;j < soplen;++j) + { + if (r[j]) { + for (b = 1;b < soplen - j && b <= 6;++b) { + if (r[j] + (r[j + b] << b) <= m) + { + r[j] += r[j + b] << b; r[j + b] = 0; + } + else if (r[j] - (r[j + b] << b) >= -m) + { + r[j] -= r[j + b] << b; + for (k = j + b;k < soplen;++k) + { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } + else if (r[j + b]) + break; + } + } + } +} diff --git a/ext/ed25519-amd64-asm/sc25519_sub_nored.s b/ext/ed25519-amd64-asm/sc25519_sub_nored.s new file mode 100644 index 0000000..a347e7d --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_sub_nored.s @@ -0,0 +1,142 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 t0 + +# qhasm: int64 t1 + +# qhasm: int64 t2 + +# qhasm: int64 t3 + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_sub_nored +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_sc25519_sub_nored +.globl crypto_sign_ed25519_amd64_64_sc25519_sub_nored +_crypto_sign_ed25519_amd64_64_sc25519_sub_nored: +crypto_sign_ed25519_amd64_64_sc25519_sub_nored: +mov %rsp,%r11 +and $31,%r11 +add $0,%r11 +sub %r11,%rsp + +# qhasm: r0 = *(uint64 *)(xp + 0) +# asm 1: movq 0(r0=int64#4 +# asm 2: movq 0(r0=%rcx +movq 0(%rsi),%rcx + +# qhasm: r1 = *(uint64 *)(xp + 8) +# asm 1: movq 8(r1=int64#5 +# asm 2: movq 8(r1=%r8 +movq 8(%rsi),%r8 + +# qhasm: r2 = *(uint64 *)(xp + 16) +# asm 1: movq 16(r2=int64#6 +# asm 2: movq 16(r2=%r9 +movq 16(%rsi),%r9 + +# qhasm: r3 = *(uint64 *)(xp + 24) +# asm 1: movq 24(r3=int64#2 +# asm 2: movq 24(r3=%rsi +movq 24(%rsi),%rsi + +# qhasm: carry? r0 -= *(uint64 *)(yp + 0) +# asm 1: subq 0(v]; +} diff --git a/ext/ed25519-amd64-asm/sc25519_window4.c b/ext/ed25519-amd64-asm/sc25519_window4.c new file mode 100644 index 0000000..683a1d4 --- /dev/null +++ b/ext/ed25519-amd64-asm/sc25519_window4.c @@ -0,0 +1,27 @@ +#include "sc25519.h" + +void sc25519_window4(signed char r[64], const sc25519 *s) +{ + char carry; + int i; + for(i=0;i<16;i++) + r[i] = (s->v[0] >> (4*i)) & 15; + for(i=0;i<16;i++) + r[i+16] = (s->v[1] >> (4*i)) & 15; + for(i=0;i<16;i++) + r[i+32] = (s->v[2] >> (4*i)) & 15; + for(i=0;i<16;i++) + r[i+48] = (s->v[3] >> (4*i)) & 15; + + /* Making it signed */ + carry = 0; + for(i=0;i<63;i++) + { + r[i] += carry; + r[i+1] += r[i] >> 4; + r[i] &= 15; + carry = r[i] >> 3; + r[i] -= carry << 4; + } + r[63] += carry; +} diff --git a/ext/ed25519-amd64-asm/sign.c b/ext/ed25519-amd64-asm/sign.c new file mode 100644 index 0000000..882ae76 --- /dev/null +++ b/ext/ed25519-amd64-asm/sign.c @@ -0,0 +1,162 @@ +#include +#include +/*#include "crypto_sign.h" +#include "crypto_hash_sha512.h"*/ +#include "ge25519.h" + +/* Original */ +#if 0 +int crypto_sign( + unsigned char *sm,unsigned long long *smlen, + const unsigned char *m,unsigned long long mlen, + const unsigned char *sk + ) +{ + unsigned char pk[32]; + unsigned char az[64]; + unsigned char nonce[64]; + unsigned char hram[64]; + sc25519 sck, scs, scsk; + ge25519 ger; + + memmove(pk,sk + 32,32); + /* pk: 32-byte public key A */ + + crypto_hash_sha512(az,sk,32); + az[0] &= 248; + az[31] &= 127; + az[31] |= 64; + /* az: 32-byte scalar a, 32-byte randomizer z */ + + *smlen = mlen + 64; + memmove(sm + 64,m,mlen); + memmove(sm + 32,az + 32,32); + /* sm: 32-byte uninit, 32-byte z, mlen-byte m */ + + crypto_hash_sha512(nonce, sm+32, mlen+32); + /* nonce: 64-byte H(z,m) */ + + sc25519_from64bytes(&sck, nonce); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(sm, &ger); + /* sm: 32-byte R, 32-byte z, mlen-byte m */ + + memmove(sm + 32,pk,32); + /* sm: 32-byte R, 32-byte A, mlen-byte m */ + + crypto_hash_sha512(hram,sm,mlen + 64); + /* hram: 64-byte H(R,A,m) */ + + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, az); + sc25519_mul(&scs, &scs, &scsk); + sc25519_add(&scs, &scs, &sck); + /* scs: S = nonce + H(R,A,m)a */ + + sc25519_to32bytes(sm + 32,&scs); + /* sm: 32-byte R, 32-byte S, mlen-byte m */ + + return 0; +} +#endif + +#if 0 +void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature) +{ + sc25519 sck, scs, scsk; + ge25519 ger; + unsigned char r[32]; + unsigned char s[32]; + unsigned char extsk[64]; + unsigned char hmg[crypto_hash_sha512_BYTES]; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned char *sig = (unsigned char *)signature; + unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) + + SHA512::hash(digest,msg,len); + + SHA512::hash(extsk,myPrivate.data + 32,32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; + + for(unsigned int i=0;i<32;i++) + sig[32 + i] = extsk[32 + i]; + for(unsigned int i=0;i<32;i++) + sig[64 + i] = digest[i]; + + SHA512::hash(hmg,sig + 32,64); + + /* Computation of R */ + sc25519_from64bytes(&sck, hmg); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(r, &ger); + + /* Computation of s */ + for(unsigned int i=0;i<32;i++) + sig[i] = r[i]; + + get_hram(hram,sig,myPublic.data + 32,sig,96); + + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, extsk); + sc25519_mul(&scs, &scs, &scsk); + + sc25519_add(&scs, &scs, &sck); + + sc25519_to32bytes(s,&scs); /* cat s */ + for(unsigned int i=0;i<32;i++) + sig[32 + i] = s[i]; +} + +void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) +{ + unsigned long long i; + + for (i = 0;i < 32;++i) playground[i] = sm[i]; + for (i = 32;i < 64;++i) playground[i] = pk[i-32]; + for (i = 64;i < smlen;++i) playground[i] = sm[i]; + + //crypto_hash_sha512(hram,playground,smlen); + ZeroTier::SHA512::hash(hram,playground,(unsigned int)smlen); +} +#endif + +extern void ZT_sha512internal(void *digest,const void *data,unsigned int len); + +extern void ed25519_amd64_asm_sign(const unsigned char *sk,const unsigned char *pk,const unsigned char *digest,unsigned char *sig) +{ + unsigned char az[64]; + unsigned char nonce[64]; + unsigned char hram[64]; + sc25519 sck, scs, scsk; + ge25519 ger; + unsigned int i; + + ZT_sha512internal(az,sk,32); + az[0] &= 248; + az[31] &= 127; + az[31] |= 64; + + for(i=0;i<32;i++) + sig[32 + i] = az[32 + i]; + for(i=0;i<32;i++) + sig[64 + i] = digest[i]; + + ZT_sha512internal(nonce,sig + 32,64); + + sc25519_from64bytes(&sck, nonce); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(sig, &ger); + + memmove(sig + 32,pk,32); + + ZT_sha512internal(hram,sig,96); + + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, az); + sc25519_mul(&scs, &scs, &scsk); + sc25519_add(&scs, &scs, &sck); + + sc25519_to32bytes(sig + 32,&scs); +} diff --git a/ext/ed25519-amd64-asm/ull4_mul.s b/ext/ed25519-amd64-asm/ull4_mul.s new file mode 100644 index 0000000..9f7b4fa --- /dev/null +++ b/ext/ed25519-amd64-asm/ull4_mul.s @@ -0,0 +1,716 @@ + +# qhasm: int64 rp + +# qhasm: int64 xp + +# qhasm: int64 yp + +# qhasm: input rp + +# qhasm: input xp + +# qhasm: input yp + +# qhasm: int64 r0 + +# qhasm: int64 r1 + +# qhasm: int64 r2 + +# qhasm: int64 r3 + +# qhasm: int64 r4 + +# qhasm: int64 r5 + +# qhasm: int64 r6 + +# qhasm: int64 r7 + +# qhasm: int64 c + +# qhasm: int64 zero + +# qhasm: int64 rax + +# qhasm: int64 rdx + +# qhasm: int64 caller1 + +# qhasm: int64 caller2 + +# qhasm: int64 caller3 + +# qhasm: int64 caller4 + +# qhasm: int64 caller5 + +# qhasm: int64 caller6 + +# qhasm: int64 caller7 + +# qhasm: caller caller1 + +# qhasm: caller caller2 + +# qhasm: caller caller3 + +# qhasm: caller caller4 + +# qhasm: caller caller5 + +# qhasm: caller caller6 + +# qhasm: caller caller7 + +# qhasm: stack64 caller1_stack + +# qhasm: stack64 caller2_stack + +# qhasm: stack64 caller3_stack + +# qhasm: stack64 caller4_stack + +# qhasm: stack64 caller5_stack + +# qhasm: stack64 caller6_stack + +# qhasm: stack64 caller7_stack + +# qhasm: enter crypto_sign_ed25519_amd64_64_ull4_mul +.text +.p2align 5 +.globl _crypto_sign_ed25519_amd64_64_ull4_mul +.globl crypto_sign_ed25519_amd64_64_ull4_mul +_crypto_sign_ed25519_amd64_64_ull4_mul: +crypto_sign_ed25519_amd64_64_ull4_mul: +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp + +# qhasm: caller1_stack = caller1 +# asm 1: movq caller1_stack=stack64#1 +# asm 2: movq caller1_stack=0(%rsp) +movq %r11,0(%rsp) + +# qhasm: caller2_stack = caller2 +# asm 1: movq caller2_stack=stack64#2 +# asm 2: movq caller2_stack=8(%rsp) +movq %r12,8(%rsp) + +# qhasm: caller3_stack = caller3 +# asm 1: movq caller3_stack=stack64#3 +# asm 2: movq caller3_stack=16(%rsp) +movq %r13,16(%rsp) + +# qhasm: caller4_stack = caller4 +# asm 1: movq caller4_stack=stack64#4 +# asm 2: movq caller4_stack=24(%rsp) +movq %r14,24(%rsp) + +# qhasm: caller5_stack = caller5 +# asm 1: movq caller5_stack=stack64#5 +# asm 2: movq caller5_stack=32(%rsp) +movq %r15,32(%rsp) + +# qhasm: caller6_stack = caller6 +# asm 1: movq caller6_stack=stack64#6 +# asm 2: movq caller6_stack=40(%rsp) +movq %rbx,40(%rsp) + +# qhasm: caller7_stack = caller7 +# asm 1: movq caller7_stack=stack64#7 +# asm 2: movq caller7_stack=48(%rsp) +movq %rbp,48(%rsp) + +# qhasm: yp = yp +# asm 1: mov yp=int64#4 +# asm 2: mov yp=%rcx +mov %rdx,%rcx + +# qhasm: r4 = 0 +# asm 1: mov $0,>r4=int64#5 +# asm 2: mov $0,>r4=%r8 +mov $0,%r8 + +# qhasm: r5 = 0 +# asm 1: mov $0,>r5=int64#6 +# asm 2: mov $0,>r5=%r9 +mov $0,%r9 + +# qhasm: r6 = 0 +# asm 1: mov $0,>r6=int64#8 +# asm 2: mov $0,>r6=%r10 +mov $0,%r10 + +# qhasm: r7 = 0 +# asm 1: mov $0,>r7=int64#9 +# asm 2: mov $0,>r7=%r11 +mov $0,%r11 + +# qhasm: zero = 0 +# asm 1: mov $0,>zero=int64#10 +# asm 2: mov $0,>zero=%r12 +mov $0,%r12 + +# qhasm: rax = *(uint64 *)(xp + 0) +# asm 1: movq 0(rax=int64#7 +# asm 2: movq 0(rax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) +# asm 1: mulq 0(r0=int64#11 +# asm 2: mov r0=%r13 +mov %rax,%r13 + +# qhasm: c = rdx +# asm 1: mov c=int64#12 +# asm 2: mov c=%r14 +mov %rdx,%r14 + +# qhasm: rax = *(uint64 *)(xp + 0) +# asm 1: movq 0(rax=int64#7 +# asm 2: movq 0(rax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) +# asm 1: mulq 8(r1=int64#13 +# asm 2: mov r1=%r15 +mov %rax,%r15 + +# qhasm: carry? r1 += c +# asm 1: add c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 0(rax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) +# asm 1: mulq 16(r2=int64#14 +# asm 2: mov r2=%rbx +mov %rax,%rbx + +# qhasm: carry? r2 += c +# asm 1: add c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 0(rax=%rax +movq 0(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) +# asm 1: mulq 24(r3=int64#15 +# asm 2: mov r3=%rbp +mov %rax,%rbp + +# qhasm: carry? r3 += c +# asm 1: add rax=int64#7 +# asm 2: movq 8(rax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) +# asm 1: mulq 0(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 8(rax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) +# asm 1: mulq 8(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 8(rax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) +# asm 1: mulq 16(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 8(rax=%rax +movq 8(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) +# asm 1: mulq 24(rax=int64#7 +# asm 2: movq 16(rax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) +# asm 1: mulq 0(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 16(rax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) +# asm 1: mulq 8(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 16(rax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) +# asm 1: mulq 16(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 16(rax=%rax +movq 16(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) +# asm 1: mulq 24(rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) +# asm 1: mulq 0(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) +# asm 1: mulq 8(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) +# asm 1: mulq 16(c=int64#12 +# asm 2: mov $0,>c=%r14 +mov $0,%r14 + +# qhasm: c += rdx + carry +# asm 1: adc rax=int64#7 +# asm 2: movq 24(rax=%rax +movq 24(%rsi),%rax + +# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) +# asm 1: mulq 24(caller1=int64#9 +# asm 2: movq caller1=%r11 +movq 0(%rsp),%r11 + +# qhasm: caller2 = caller2_stack +# asm 1: movq caller2=int64#10 +# asm 2: movq caller2=%r12 +movq 8(%rsp),%r12 + +# qhasm: caller3 = caller3_stack +# asm 1: movq caller3=int64#11 +# asm 2: movq caller3=%r13 +movq 16(%rsp),%r13 + +# qhasm: caller4 = caller4_stack +# asm 1: movq caller4=int64#12 +# asm 2: movq caller4=%r14 +movq 24(%rsp),%r14 + +# qhasm: caller5 = caller5_stack +# asm 1: movq caller5=int64#13 +# asm 2: movq caller5=%r15 +movq 32(%rsp),%r15 + +# qhasm: caller6 = caller6_stack +# asm 1: movq caller6=int64#14 +# asm 2: movq caller6=%rbx +movq 40(%rsp),%rbx + +# qhasm: caller7 = caller7_stack +# asm 1: movq caller7=int64#15 +# asm 2: movq caller7=%rbp +movq 48(%rsp),%rbp + +# qhasm: leave +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret diff --git a/ext/installfiles/linux/zerotier-containerized/Dockerfile b/ext/installfiles/linux/zerotier-containerized/Dockerfile index 678216d..fd18eeb 100644 --- a/ext/installfiles/linux/zerotier-containerized/Dockerfile +++ b/ext/installfiles/linux/zerotier-containerized/Dockerfile @@ -1,20 +1,32 @@ -FROM alpine:latest -MAINTAINER Adam Ierymenko +## NOTE: to retain configuration; mount a Docker volume, or use a bind-mount, on /var/lib/zerotier-one -LABEL version="1.1.14" +FROM debian:buster-slim as builder + +## Supports x86_64, x86, arm, and arm64 + +RUN apt-get update && apt-get install -y curl gnupg +RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 0x1657198823e52a61 && \ + echo "deb http://download.zerotier.com/debian/buster buster main" > /etc/apt/sources.list.d/zerotier.list +RUN apt-get update && apt-get install -y zerotier-one=1.2.12 +RUN curl https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/ext/installfiles/linux/zerotier-containerized/main.sh > /var/lib/zerotier-one/main.sh + +FROM alpine:latest +LABEL version="1.2.12" LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts." # Uncomment to build in container -#RUN apk add --update alpine-sdk linux-headers - +# RUN apk add --update alpine-sdk linux-headers RUN apk add --update libgcc libstdc++ -ADD zerotier-one / -RUN chmod 0755 /zerotier-one -RUN ln -sf /zerotier-one /zerotier-cli +# ZeroTier relies on UDP port 9993 +EXPOSE 9993/udp + RUN mkdir -p /var/lib/zerotier-one +COPY --from=builder /usr/sbin/zerotier-cli /usr/sbin/zerotier-cli +COPY --from=builder /usr/sbin/zerotier-idtool /usr/sbin/zerotier-idtool +COPY --from=builder /usr/sbin/zerotier-one /usr/sbin/zerotier-one +COPY --from=builder /var/lib/zerotier-one/main.sh /main.sh -ADD main.sh / RUN chmod 0755 /main.sh - -ENTRYPOINT /main.sh +ENTRYPOINT ["/main.sh"] +CMD ["zerotier-one"] diff --git a/ext/installfiles/linux/zerotier-containerized/main.sh b/ext/installfiles/linux/zerotier-containerized/main.sh index 685a689..a338903 100755 --- a/ext/installfiles/linux/zerotier-containerized/main.sh +++ b/ext/installfiles/linux/zerotier-containerized/main.sh @@ -7,4 +7,4 @@ if [ ! -e /dev/net/tun ]; then exit 1 fi -exec /zerotier-one +exec "$@" diff --git a/ext/installfiles/mac/ZeroTier One.pkgproj b/ext/installfiles/mac/ZeroTier One.pkgproj index 96b1338..2bd1912 100755 --- a/ext/installfiles/mac/ZeroTier One.pkgproj +++ b/ext/installfiles/mac/ZeroTier One.pkgproj @@ -2,652 +2,731 @@ + PACKAGES + + + MUST-CLOSE-APPLICATION-ITEMS + + MUST-CLOSE-APPLICATIONS + + PACKAGE_FILES + + DEFAULT_INSTALL_LOCATION + / + HIERARCHY + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 80 + PATH + Utilities + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 80 + PATH + ../../../macui/build/Release/ZeroTier One.app + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + GID + 80 + PATH + Applications + PATH_TYPE + 0 + PERMISSIONS + 509 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + get-proxy-settings.sh + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + launch.sh + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 80 + PATH + ../../../MacEthernetTapAgent + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + BUNDLE_CAN_DOWNGRADE + + BUNDLE_POSTINSTALL_PATH + + PATH_TYPE + 0 + + BUNDLE_PREINSTALL_PATH + + PATH_TYPE + 0 + + CHILDREN + + GID + 0 + PATH + ../../bin/tap-mac/tap.kext + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + uninstall.sh + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + ../../../zerotier-one + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + GID + 80 + PATH + One + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 80 + PATH + ZeroTier + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 80 + PATH + Application Support + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Automator + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Documentation + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Filesystems + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Frameworks + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Input Methods + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Internet Plug-Ins + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + LaunchAgents + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + com.zerotier.one.plist + PATH_TYPE + 1 + PERMISSIONS + 420 + TYPE + 3 + UID + 0 + + + GID + 0 + PATH + LaunchDaemons + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + PreferencePanes + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Preferences + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 80 + PATH + Printers + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + PrivilegedHelperTools + PATH_TYPE + 0 + PERMISSIONS + 1005 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + QuickLook + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + QuickTime + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Screen Savers + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Scripts + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Services + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Widgets + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Extensions + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + Library + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + Extensions + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + Library + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + System + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + Shared + PATH_TYPE + 0 + PERMISSIONS + 1023 + TYPE + 1 + UID + 0 + + + GID + 80 + PATH + Users + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + / + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + PAYLOAD_TYPE + 0 + PRESERVE_EXTENDED_ATTRIBUTES + + SHOW_INVISIBLE + + SPLIT_FORKS + + TREAT_MISSING_FILES_AS_WARNING + + VERSION + 5 + + PACKAGE_SCRIPTS + + POSTINSTALL_PATH + + PATH + postinst.sh + PATH_TYPE + 1 + + PREINSTALL_PATH + + PATH + preinst.sh + PATH_TYPE + 1 + + RESOURCES + + + PACKAGE_SETTINGS + + AUTHENTICATION + 1 + CONCLUSION_ACTION + 0 + FOLLOW_SYMBOLIC_LINKS + + IDENTIFIER + com.zerotier.pkg.ZeroTierOne + LOCATION + 0 + NAME + ZeroTier One + OVERWRITE_PERMISSIONS + + PAYLOAD_SIZE + -1 + REFERENCE_PATH + + RELOCATABLE + + USE_HFS+_COMPRESSION + + VERSION + 1.4.2 + + TYPE + 0 + UUID + 1B6AFC3A-9EA5-4401-83D4-37F06CD13CD6 + + PROJECT - PACKAGE_FILES - - DEFAULT_INSTALL_LOCATION - / - HIERARCHY - - CHILDREN - - - CHILDREN - - - CHILDREN - - GID - 80 - PATH - Utilities - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 80 - PATH - ../../../macui/build/Release/ZeroTier One.app - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - GID - 80 - PATH - Applications - PATH_TYPE - 0 - PERMISSIONS - 509 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - - CHILDREN - - - CHILDREN - - - CHILDREN - - GID - 0 - PATH - get-proxy-settings.sh - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - launch.sh - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - ../../bin/tap-mac/tap.kext - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - uninstall.sh - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - ../../../zerotier-one - PATH_TYPE - 1 - PERMISSIONS - 493 - TYPE - 3 - UID - 0 - - - GID - 80 - PATH - One - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - ZeroTier - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 2 - UID - 0 - - - GID - 80 - PATH - Application Support - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Automator - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Documentation - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Filesystems - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Frameworks - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Input Methods - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Internet Plug-Ins - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - LaunchAgents - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - GID - 0 - PATH - com.zerotier.one.plist - PATH_TYPE - 1 - PERMISSIONS - 420 - TYPE - 3 - UID - 0 - - - GID - 0 - PATH - LaunchDaemons - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - PreferencePanes - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Preferences - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 80 - PATH - Printers - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - PrivilegedHelperTools - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - QuickLook - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - QuickTime - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Screen Savers - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Scripts - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Services - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - GID - 0 - PATH - Widgets - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - Library - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - - CHILDREN - - GID - 0 - PATH - Extensions - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - Library - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - System - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - CHILDREN - - - CHILDREN - - GID - 0 - PATH - Shared - PATH_TYPE - 0 - PERMISSIONS - 1023 - TYPE - 1 - UID - 0 - - - GID - 80 - PATH - Users - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - - GID - 0 - PATH - / - PATH_TYPE - 0 - PERMISSIONS - 493 - TYPE - 1 - UID - 0 - - PAYLOAD_TYPE - 0 - VERSION - 3 - - PACKAGE_SCRIPTS - - POSTINSTALL_PATH - - PATH - postinst.sh - PATH_TYPE - 1 - - PREINSTALL_PATH - - PATH - preinst.sh - PATH_TYPE - 1 - - RESOURCES - - - PACKAGE_SETTINGS - - AUTHENTICATION - 1 - CONCLUSION_ACTION - 0 - IDENTIFIER - com.zerotier.pkg.ZeroTierOne - OVERWRITE_PERMISSIONS - - VERSION - 1.2.4 - PROJECT_COMMENTS NOTES @@ -683,8 +762,139 @@ dG1sPgo= + PROJECT_PRESENTATION + + BACKGROUND + + APPAREANCES + + DARK_AQUA + + LIGHT_AQUA + + + SHARED_SETTINGS_FOR_ALL_APPAREANCES + + + INSTALLATION_STEPS + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewIntroductionController + INSTALLER_PLUGIN + Introduction + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewReadMeController + INSTALLER_PLUGIN + ReadMe + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewLicenseController + INSTALLER_PLUGIN + License + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewDestinationSelectController + INSTALLER_PLUGIN + TargetSelect + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewInstallationTypeController + INSTALLER_PLUGIN + PackageSelection + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewInstallationController + INSTALLER_PLUGIN + Install + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewSummaryController + INSTALLER_PLUGIN + Summary + LIST_TITLE_KEY + InstallerSectionTitle + + + INTRODUCTION + + LOCALIZATIONS + + + LICENSE + + LOCALIZATIONS + + MODE + 0 + + README + + LOCALIZATIONS + + + TITLE + + LOCALIZATIONS + + + + PROJECT_REQUIREMENTS + + LIST + + + BEHAVIOR + 3 + DICTIONARY + + IC_REQUIREMENT_OS_DISK_TYPE + 0 + IC_REQUIREMENT_OS_DISTRIBUTION_TYPE + 0 + IC_REQUIREMENT_OS_MINIMUM_VERSION + 101000 + + IC_REQUIREMENT_CHECK_TYPE + 1 + IDENTIFIER + fr.whitebox.Packages.requirement.os + MESSAGE + + NAME + Operating System + STATE + + + + RESOURCES + + ROOT_VOLUME_ONLY + + PROJECT_SETTINGS + BUILD_FORMAT + 0 BUILD_PATH PATH @@ -862,10 +1072,19 @@ NAME ZeroTier One + PAYLOAD_ONLY + + TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING + + SHARED_GLOBAL_DATA + + IC_REQUIREMENT_JAVASCRIPT_SHARED_SOURCE_CODE + + TYPE - 1 + 0 VERSION 2 diff --git a/ext/installfiles/mac/launch.sh b/ext/installfiles/mac/launch.sh index 41c4b9c..b02a667 100755 --- a/ext/installfiles/mac/launch.sh +++ b/ext/installfiles/mac/launch.sh @@ -1,7 +1,3 @@ #!/bin/bash - -zthome="/Library/Application Support/ZeroTier/One" -export PATH="$zthome:/bin:/usr/bin:/sbin:/usr/sbin" - -# Launch ZeroTier One (not as daemon... launchd monitors it) +export PATH="/Library/Application Support/ZeroTier/One:/bin:/usr/bin:/sbin:/usr/sbin" exec zerotier-one diff --git a/ext/installfiles/mac/postinst.sh b/ext/installfiles/mac/postinst.sh index 2e4f591..95301a4 100755 --- a/ext/installfiles/mac/postinst.sh +++ b/ext/installfiles/mac/postinst.sh @@ -3,9 +3,10 @@ export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin OSX_RELEASE=`sw_vers -productVersion | cut -d . -f 1,2` +DARWIN_MAJOR=`uname -r | cut -d . -f 1` launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 -sleep 1 +sleep 0.5 cd "/Library/Application Support/ZeroTier/One" @@ -23,24 +24,41 @@ if [ "$OSX_RELEASE" = "10.7" ]; then fi rm -rf node.log node.log.old root-topology shutdownIfUnreadable autoupdate.log updates.d ui peers.save + chown -R 0 tap.kext chgrp -R 0 tap.kext + if [ ! -f authtoken.secret ]; then - head -c 4096 /dev/urandom | md5 | head -c 24 >authtoken.secret + head -c 1024 /dev/urandom | md5 | head -c 24 >authtoken.secret chown 0 authtoken.secret chgrp 0 authtoken.secret chmod 0600 authtoken.secret fi + rm -f zerotier-cli zerotier-idtool ln -sf zerotier-one zerotier-cli ln -sf zerotier-one zerotier-idtool - mkdir -p /usr/local/bin cd /usr/local/bin rm -f zerotier-cli zerotier-idtool ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-cli ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-idtool +if [ $DARWIN_MAJOR -le 16 ]; then + cd "/Library/Application Support/ZeroTier/One" + kextload -r . tap.kext >>/dev/null 2>&1 & + disown %1 +fi + launchctl load /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 +sleep 1 + +if [ -f /tmp/zt1-gui-restart.tmp ]; then + for u in `cat /tmp/zt1-gui-restart.tmp`; do + su $u -c '/Applications/ZeroTier\ One.app/Contents/MacOS/ZeroTier\ One &' >>/dev/null 2>&1 & + done +fi +rm -f /tmp/zt1-gui-restart.tmp + exit 0 diff --git a/ext/installfiles/mac/preinst.sh b/ext/installfiles/mac/preinst.sh index c2cb494..af2a932 100755 --- a/ext/installfiles/mac/preinst.sh +++ b/ext/installfiles/mac/preinst.sh @@ -2,6 +2,19 @@ export PATH=/bin:/usr/bin:/sbin:/usr/sbin +rm -f /tmp/zt1-gui-restart.tmp +for i in `ps axuwww | tr -s ' ' ',' | grep -F '/Applications/ZeroTier,One.app' | grep -F -v grep | cut -d , -f 1,2 | xargs`; do + u=`echo $i | cut -d , -f 1` + p=`echo $i | cut -d , -f 2` + if [ ! -z "$u" -a "0$p" -gt 0 ]; then + kill $p >>/dev/null 2>&1 + sleep 0.2 + kill -9 $p >>/dev/null 2>&1 + echo "$u" >>/tmp/zt1-gui-restart.tmp + fi +done +chmod 0600 /tmp/zt1-gui-restart.tmp + if [ -f /Library/LaunchDaemons/com.zerotier.one.plist ]; then launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 fi diff --git a/ext/installfiles/mac/uninstall.sh b/ext/installfiles/mac/uninstall.sh index 9bf5d6f..52c09b6 100755 --- a/ext/installfiles/mac/uninstall.sh +++ b/ext/installfiles/mac/uninstall.sh @@ -27,7 +27,7 @@ kextunload '/Library/Application Support/ZeroTier/One/tap.kext' >>/dev/null 2>&1 echo "Removing ZeroTier One files..." rm -rf '/Applications/ZeroTier One.app' -rm -f '/usr/bin/zerotier-one' '/usr/bin/zerotier-idtool' '/usr/bin/zerotier-cli' '/Library/LaunchDaemons/com.zerotier.one.plist' +rm -f '/usr/local/bin/zerotier-one' '/usr/local/bin/zerotier-idtool' '/usr/local/bin/zerotier-cli' '/Library/LaunchDaemons/com.zerotier.one.plist' cd '/Library/Application Support/ZeroTier/One' if [ "`pwd`" = '/Library/Application Support/ZeroTier/One' ]; then diff --git a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip index db8566c..7ff1a05 100644 --- a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip +++ b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip @@ -1,7 +1,7 @@ - + - + @@ -19,39 +19,56 @@ + - + - - - + + + + + + + + + + + - + - + + + + + + + + + + - @@ -105,10 +122,13 @@ + + + @@ -116,9 +136,10 @@ + - + @@ -128,19 +149,26 @@ - + + + - - + + + + + - - + + + + - + diff --git a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip index b83b382..ef3d58c 100644 --- a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip +++ b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip @@ -1,7 +1,7 @@ - + - + @@ -20,39 +20,56 @@ + - + - - - + + + + + + + + + + + - + - + + + + + + + + + + - @@ -106,10 +123,13 @@ + + + @@ -117,9 +137,10 @@ + - + @@ -129,19 +150,26 @@ - + + + - - + + + + + - - + + + + - + diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index a63fa2b..1694f87 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -1,462 +1,484 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/installfiles/windows/chocolatey/zerotier-one/tools/LICENSE.txt b/ext/installfiles/windows/chocolatey/zerotier-one/tools/LICENSE.txt deleted file mode 100644 index ce0564a..0000000 --- a/ext/installfiles/windows/chocolatey/zerotier-one/tools/LICENSE.txt +++ /dev/null @@ -1,11 +0,0 @@ -From: https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/COPYING - -LICENSE - -ZeroTier One is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at -your option) any later version. - -See the file ‘LICENSE.GPL-3’ for the text of the GNU GPL version 3. -If that file is not present, see . diff --git a/ext/installfiles/windows/chocolatey/zerotier-one/tools/VERIFICATION.txt b/ext/installfiles/windows/chocolatey/zerotier-one/tools/VERIFICATION.txt deleted file mode 100644 index 0a5bc76..0000000 --- a/ext/installfiles/windows/chocolatey/zerotier-one/tools/VERIFICATION.txt +++ /dev/null @@ -1,5 +0,0 @@ -VERIFICATION -Verification is intended to assist the Chocolatey moderators and community -in verifying that this package's contents are trustworthy. - -Our MSI installer should be signed by ZeroTier, Inc. using a certificate from DigiCert. diff --git a/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyinstall.ps1 b/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyinstall.ps1 deleted file mode 100644 index f8a7457..0000000 --- a/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyinstall.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -$packageName = 'zerotier-one' -$installerType = 'msi' -$url = 'https://download.zerotier.com/RELEASES/1.1.14/dist/ZeroTier%20One.msi' -$url64 = 'https://download.zerotier.com/RELEASES/1.1.14/dist/ZeroTier%20One.msi' -$silentArgs = '/quiet' -$validExitCodes = @(0,3010) - -Install-ChocolateyPackage $packageName $installerType $silentArgs $url $url64 -validExitCodes $validExitCodes diff --git a/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyuninstall.ps1 b/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyuninstall.ps1 deleted file mode 100644 index 81f7a5a..0000000 --- a/ext/installfiles/windows/chocolatey/zerotier-one/tools/chocolateyuninstall.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -$ErrorActionPreference = 'Stop'; - -$packageName = 'zerotier-one' -$softwareName = 'ZeroTier One*' -$installerType = 'MSI' - -$silentArgs = '/qn /norestart' -$validExitCodes = @(0, 3010, 1605, 1614, 1641) -$uninstalled = $false - -[array]$key = Get-UninstallRegistryKey -SoftwareName $softwareName - -if ($key.Count -eq 1) { - $key | % { - $silentArgs = "$($_.PSChildName) $silentArgs" - $file = '' - Uninstall-ChocolateyPackage -PackageName $packageName ` - -FileType $installerType ` - -SilentArgs "$silentArgs" ` - -ValidExitCodes $validExitCodes ` - -File "$file" - } -} elseif ($key.Count -eq 0) { - Write-Warning "$packageName has already been uninstalled by other means." -} elseif ($key.Count -gt 1) { - Write-Warning "$key.Count matches found!" - Write-Warning "To prevent accidental data loss, no programs will be uninstalled." - Write-Warning "Please alert package maintainer the following keys were matched:" - $key | % {Write-Warning "- $_.DisplayName"} -} diff --git a/ext/installfiles/windows/chocolatey/zerotier-one/zerotier-one.nuspec b/ext/installfiles/windows/chocolatey/zerotier-one/zerotier-one.nuspec deleted file mode 100644 index 32fa5a9..0000000 --- a/ext/installfiles/windows/chocolatey/zerotier-one/zerotier-one.nuspec +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - zerotier-one - - - - 1.2.4 - - - - - - - - zerotier-one (Install) - ZeroTier, Inc. - - https://www.zerotier.com/ - - - - - - - - - zerotier-one admin - ZeroTier One Virtual Network Endpoint for Windows - ZeroTier is a smart switch for Earth with VLAN capability. See https://www.zerotier.com/ for more information. - - - - - - - - - - - - - - - - - diff --git a/ext/json/LICENSE.MIT b/ext/json/LICENSE.MIT index e2ac489..00599af 100644 --- a/ext/json/LICENSE.MIT +++ b/ext/json/LICENSE.MIT @@ -1,14 +1,13 @@ -The library is licensed under the MIT License -: +MIT License -Copyright (c) 2013-2016 Niels Lohmann +Copyright (c) 2013-2017 Niels Lohmann -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. diff --git a/ext/json/README.md b/ext/json/README.md index 4bcbe97..f3bbf84 100644 --- a/ext/json/README.md +++ b/ext/json/README.md @@ -3,50 +3,97 @@ [![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) -[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) -[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) +[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) +[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/nlohmann/json.svg)](http://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) +- [Design goals](#design-goals) +- [Integration](#integration) +- [Examples](#examples) + - [JSON as first-class data type](#json-as-first-class-data-type) + - [Serialization / Deserialization](#serialization--deserialization) + - [STL-like access](#stl-like-access) + - [Conversion from STL containers](#conversion-from-stl-containers) + - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch) + - [JSON Merge Patch](#json-merge-patch) + - [Implicit conversions](#implicit-conversions) + - [Conversions to/from arbitrary types](#arbitrary-types-conversions) + - [Binary formats (CBOR, MessagePack, and UBJSON)](#binary-formats-cbor-messagepack-and-ubjson) +- [Supported compilers](#supported-compilers) +- [License](#license) +- [Contact](#contact) +- [Thanks](#thanks) +- [Used third-party tools](#used-third-party-tools) +- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c) +- [Notes](#notes) +- [Execute unit tests](#execute-unit-tests) + ## Design goals There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: - **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. -- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/src/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. +- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). +- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests agains all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). Other aspects were not so important to us: - **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. -- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) may be even faster (but would consist of more files which makes the integration harder). +- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set. See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. ## Integration -The single required source, file `json.hpp` is in the `src` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add +[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add ```cpp -#include "json.hpp" +#include // for convenience using json = nlohmann::json; ``` -to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). +to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). + +You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. + +### Package Managers :beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. +If you are using the [Meson Build System](http://mesonbuild.com), then you can wrap this repository as a subproject. + +If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages. + +If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the `nlohmann_json` package. Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. + +If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. + +If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json). + +If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. + +If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). + +If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). ## Examples +Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). + +### JSON as first-class data type + Here are some examples to give you an idea how to use the class. Assume you want to create the JSON object @@ -68,7 +115,7 @@ Assume you want to create the JSON object } ``` -With the JSON class, you could write: +With this library, you could write: ```cpp // create an empty structure (null) @@ -112,7 +159,7 @@ json j2 = { }; ``` -Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help: +Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help: ```cpp // a way to express the empty array [] @@ -123,13 +170,14 @@ json empty_object_implicit = json({}); json empty_object_explicit = json::object(); // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] -json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; +json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); ``` - ### Serialization / Deserialization -You can create an object (deserialization) by appending `_json` to a string literal: +#### To/from strings + +You can create a JSON value (deserialization) by appending `_json` to a string literal: ```cpp // create object from string literal @@ -142,12 +190,18 @@ auto j2 = R"( "pi": 3.141 } )"_json; +``` -// or explicitly +Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. + +The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa9676414f2e36383c4b181fe856aa3c0.html#aa9676414f2e36383c4b181fe856aa3c0): + +```cpp +// parse explicitly auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); ``` -You can also get a string representation (serialize): +You can also get a string representation of a JSON value (serialize): ```cpp // explicit conversion to string @@ -162,6 +216,32 @@ std::cout << j.dump(4) << std::endl; // } ``` +Note the difference between serialization and assignment: + +```cpp +// store a string in a JSON value +json j_string = "this is a string"; + +// retrieve the string value (implicit JSON to std::string conversion) +std::string cpp_string = j_string; +// retrieve the string value (explicit JSON to std::string conversion) +auto cpp_string2 = j_string.get(); + +// retrieve the serialized value (explicit JSON serialization) +std::string serialized_string = j_string.dump(); + +// output of original string +std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get() << '\n'; +// output of serialized value +std::cout << j_string << " == " << serialized_string << std::endl; +``` + +[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) always returns the serialized value, and [`.get()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value. + +Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) may throw an exception. + +#### To/from streams (e.g. files, string streams) + You can also use streams to serialize and deserialize: ```cpp @@ -176,14 +256,84 @@ std::cout << j; std::cout << std::setw(4) << j << std::endl; ``` -These operators work for any subclasses of `std::istream` or `std::ostream`. +These operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files: + +```cpp +// read a JSON file +std::ifstream i("file.json"); +json j; +i >> j; + +// write prettified JSON to another file +std::ofstream o("pretty.json"); +o << std::setw(4) << j << std::endl; +``` Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use. +#### Read from iterator range + +You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector`: + +```cpp +std::vector v = {'t', 'r', 'u', 'e'}; +json j = json::parse(v.begin(), v.end()); +``` + +You may leave the iterators for the range [begin, end): + +```cpp +std::vector v = {'t', 'r', 'u', 'e'}; +json j = json::parse(v); +``` + +#### SAX interface + +The library uses a SAX-like interface with the following functions: + +```cpp +// called when null is parsed +bool null(); + +// called when a boolean is parsed; value is passed +bool boolean(bool val); + +// called when a signed or unsigned integer number is parsed; value is passed +bool number_integer(number_integer_t val); +bool number_unsigned(number_unsigned_t val); + +// called when a floating-point number is parsed; value and original string is passed +bool number_float(number_float_t val, const string_t& s); + +// called when a string is parsed; value is passed and can be safely moved away +bool string(string_t& val); + +// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) +bool start_object(std::size_t elements); +bool end_object(); +bool start_array(std::size_t elements); +bool end_array(); +// called when an object key is parsed; value is passed and can be safely moved away +bool key(string_t& val); + +// called when a parse error occurs; byte position, the last token, and an exception is passed +bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex); +``` + +The return value of each function determines whether parsing should proceed. + +To implement your own SAX handler, proceed as follows: + +1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax` as base class, but you can also use any class where the functions described above are implemented and public. +2. Create an object of your SAX interface class, e.g. `my_sax`. +3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface. + +Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp). + ### STL-like access -We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. +We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement. ```cpp // create an array using push_back @@ -192,6 +342,9 @@ j.push_back("foo"); j.push_back(1); j.push_back(true); +// also use emplace_back +j.emplace_back(1.78); + // iterate the array for (json::iterator it = j.begin(); it != j.end(); ++it) { std::cout << *it << '\n'; @@ -207,6 +360,9 @@ const std::string tmp = j[0]; j[1] = 42; bool foo = j.at(2); +// comparison +j == "[\"foo\", 1, true]"_json; // true + // other stuff j.size(); // 3 entries j.empty(); // false @@ -221,15 +377,15 @@ j.is_object(); j.is_array(); j.is_string(); -// comparison -j == "[\"foo\", 1, true]"_json; // true - // create an object json o; o["foo"] = 23; o["bar"] = false; o["baz"] = 3.141; +// also use emplace +o.emplace("weather", "sunny"); + // special iterator member functions for objects for (json::iterator it = o.begin(); it != o.end(); ++it) { std::cout << it.key() << " : " << it.value() << "\n"; @@ -251,7 +407,7 @@ o.erase("foo"); ### Conversion from STL containers -Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends how the elements are ordered in the respective STL container. +Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. ```cpp std::vector c_vector {1, 2, 3, 4}; @@ -291,7 +447,7 @@ json j_umset(c_umset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] ``` -Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. +Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. ```cpp std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; @@ -349,6 +505,37 @@ json::diff(j_result, j_original); // ] ``` +### JSON Merge Patch + +The library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified. + +```cpp +// a JSON value +json j_document = R"({ + "a": "b", + "c": { + "d": "e", + "f": "g" + } +})"_json; + +// a patch +json j_patch = R"({ + "a":"z", + "c": { + "f": null + } +})"_json; + +// apply the patch +j_original.merge_patch(j_patch); +// { +// "a": "z", +// "c": { +// "d": "e" +// } +// } +``` ### Implicit conversions @@ -383,14 +570,283 @@ int vi = jn.get(); // etc. ``` +Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly: + +```cpp +char ch = 'A'; // ASCII value 65 +json j_default = ch; // stores integer number 65 +json j_string = std::string(1, ch); // stores string "A" +``` + +### Arbitrary types conversions + +Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: + +```cpp +namespace ns { + // a simple struct to model a person + struct person { + std::string name; + std::string address; + int age; + }; +} + +ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; + +// convert to JSON: copy each value into the JSON object +json j; +j["name"] = p.name; +j["address"] = p.address; +j["age"] = p.age; + +// ... + +// convert from JSON: copy each value from the JSON object +ns::person p { + j["name"].get(), + j["address"].get(), + j["age"].get() +}; +``` + +It works, but that's quite a lot of boilerplate... Fortunately, there's a better way: + +```cpp +// create a person +ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; + +// conversion: person -> json +json j = p; + +std::cout << j << std::endl; +// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} + +// conversion: json -> person +ns::person p2 = j; + +// that's it +assert(p == p2); +``` + +#### Basic usage + +To make this work with one of your types, you only need to provide two functions: + +```cpp +using nlohmann::json; + +namespace ns { + void to_json(json& j, const person& p) { + j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}}; + } + + void from_json(const json& j, person& p) { + p.name = j.at("name").get(); + p.address = j.at("address").get(); + p.age = j.at("age").get(); + } +} // namespace ns +``` + +That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. +Likewise, when calling `get()`, the `from_json` method will be called. + +Some important things: + +* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). +* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. +* When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) +* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. +* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get();` instead. +* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +* Be careful with the definition order of the `from_json`/`to_json` functions: If a type `B` has a member of type `A`, you **MUST** define `to_json(A)` before `to_json(B)`. Look at [issue 561](https://github.com/nlohmann/json/issues/561) for more details. + + +#### How do I convert third-party types? + +This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: + +The library uses **JSON Serializers** to convert types to json. +The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)). + +It is implemented like this (simplified): + +```cpp +template +struct adl_serializer { + static void to_json(json& j, const T& value) { + // calls the "to_json" method in T's namespace + } + + static void from_json(const json& j, T& value) { + // same thing, but with the "from_json" method + } +}; +``` + +This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... + +To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example: + +```cpp +// partial specialization (full specialization works too) +namespace nlohmann { + template + struct adl_serializer> { + static void to_json(json& j, const boost::optional& opt) { + if (opt == boost::none) { + j = nullptr; + } else { + j = *opt; // this will call adl_serializer::to_json which will + // find the free function to_json in T's namespace! + } + } + + static void from_json(const json& j, boost::optional& opt) { + if (j.is_null()) { + opt = boost::none; + } else { + opt = j.get(); // same as above, but with + // adl_serializer::from_json + } + } + }; +} +``` + +#### How can I use `get()` for non-default constructible/non-copyable types? + +There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: + +```cpp +struct move_only_type { + move_only_type() = delete; + move_only_type(int ii): i(ii) {} + move_only_type(const move_only_type&) = delete; + move_only_type(move_only_type&&) = default; + + int i; +}; + +namespace nlohmann { + template <> + struct adl_serializer { + // note: the return type is no longer 'void', and the method only takes + // one argument + static move_only_type from_json(const json& j) { + return {j.get()}; + } + + // Here's the catch! You must provide a to_json method! Otherwise you + // will not be able to convert move_only_type to json, since you fully + // specialized adl_serializer on that type + static void to_json(json& j, move_only_type t) { + j = t.i; + } + }; +} +``` + +#### Can I write my own serializer? (Advanced use) + +Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples. + +If you write your own serializer, you'll need to do a few things: + +- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) +- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods +- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL + +Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL. + +```cpp +// You should use void as a second template argument +// if you don't need compile-time checks on T +template::type> +struct less_than_32_serializer { + template + static void to_json(BasicJsonType& j, T value) { + // we want to use ADL, and call the correct to_json overload + using nlohmann::to_json; // this method is called by adl_serializer, + // this is where the magic happens + to_json(j, value); + } + + template + static void from_json(const BasicJsonType& j, T& value) { + // same thing here + using nlohmann::from_json; + from_json(j, value); + } +}; +``` + +Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention: + +```cpp +template +struct bad_serializer +{ + template + static void to_json(BasicJsonType& j, const T& value) { + // this calls BasicJsonType::json_serializer::to_json(j, value); + // if BasicJsonType::json_serializer == bad_serializer ... oops! + j = value; + } + + template + static void to_json(const BasicJsonType& j, T& value) { + // this calls BasicJsonType::json_serializer::from_json(j, value); + // if BasicJsonType::json_serializer == bad_serializer ... oops! + value = j.template get(); // oops! + } +}; +``` + +### Binary formats (CBOR, MessagePack, and UBJSON) + +Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors. + +```cpp +// create a JSON value +json j = R"({"compact": true, "schema": 0})"_json; + +// serialize to CBOR +std::vector v_cbor = json::to_cbor(j); + +// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 + +// roundtrip +json j_from_cbor = json::from_cbor(v_cbor); + +// serialize to MessagePack +std::vector v_msgpack = json::to_msgpack(j); + +// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 + +// roundtrip +json j_from_msgpack = json::from_msgpack(v_msgpack); + +// serialize to UBJSON +std::vector v_ubjson = json::to_ubjson(j); + +// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D + +// roundtrip +json j_from_ubjson = json::from_ubjson(v_ubjson); +``` + ## Supported compilers -Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: +Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 6.0 (and possibly later) -- Clang 3.4 - 3.9 (and possibly later) +- GCC 4.9 - 8.2 (and possibly later) +- Clang 3.4 - 6.1 (and possibly later) +- Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) +- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) I would be happy to learn about other compilers/versions. @@ -398,41 +854,49 @@ Please note: - GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - + ``` APP_STL := c++_shared NDK_TOOLCHAIN_VERSION := clang3.6 APP_CPPFLAGS += -frtti -fexceptions ``` - + The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. - For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). +- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. + The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json): | Compiler | Operating System | Version String | |-----------------|------------------------------|----------------| -| GCC 4.9.3 | Ubuntu 14.04.4 LTS | g++-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 | -| GCC 5.3.0 | Ubuntu 14.04.4 LTS | g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204 | -| GCC 6.1.1 | Ubuntu 14.04.4 LTS | g++-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511 | -| Clang 3.6.0 | Ubuntu 14.04.4 LTS | clang version 3.6.0 (tags/RELEASE_360/final) | -| Clang 3.6.1 | Ubuntu 14.04.4 LTS | clang version 3.6.1 (tags/RELEASE_361/final) | -| Clang 3.6.2 | Ubuntu 14.04.4 LTS | clang version 3.6.2 (tags/RELEASE_362/final) | -| Clang 3.7.0 | Ubuntu 14.04.4 LTS | clang version 3.7.0 (tags/RELEASE_370/final) | -| Clang 3.7.1 | Ubuntu 14.04.4 LTS | clang version 3.7.1 (tags/RELEASE_371/final) | -| Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) | -| Clang 3.8.1 | Ubuntu 14.04.4 LTS | clang version 3.8.1 (tags/RELEASE_381/final) | -| Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) | -| Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) | -| Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) | -| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | -| Clang Xcode 7.1 | Darwin Kernel Version 14.5.0 (OSX 10.10.5) | Apple LLVM version 7.0.0 (clang-700.1.76) | -| Clang Xcode 7.2 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.0.2 (clang-700.1.81) | -| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) | -| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 (OSX 10.11.6) | Apple LLVM version 8.0.0 (clang-800.0.38) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25123.0 | - +| GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | +| GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | +| GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | +| GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 | +| GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 | +| GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 | +| Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) | +| Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) | +| Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) | +| Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) | +| Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) | +| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | +| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) | +| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) | +| Clang Xcode 6.4 | OSX 10.10.5 | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | +| Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) | +| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) | +| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | +| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | +| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) | +| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) | +| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | +| Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | +| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | +| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | +| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | ## License @@ -440,7 +904,7 @@ The following compilers are currently used in continuous integration at [Travis] The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): -Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me) +Copyright © 2013-2018 [Niels Lohmann](http://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -448,11 +912,28 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* * * + +The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) + +The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](http://florian.loitsch.com/) + +## Contact + +If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. + +Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). + +## Security + +[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69). ## Thanks I deeply appreciate the help of the following people. +![Contributors](https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png) + - [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. - [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. - [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. @@ -465,7 +946,7 @@ I deeply appreciate the help of the following people. - [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. - [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. - [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. -- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. +- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types. - [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. - [dariomt](https://github.com/dariomt) fixed some typos in the examples. - [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. @@ -480,7 +961,7 @@ I deeply appreciate the help of the following people. - [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. - [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. - [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. -- [msm-](https://github.com/msm-) added support for american fuzzy lop. +- [msm-](https://github.com/msm-) added support for American Fuzzy Lop. - [Annihil](https://github.com/Annihil) fixed an example in the README file. - [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. - [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. @@ -493,46 +974,150 @@ I deeply appreciate the help of the following people. - [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. - [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. - [Thomas Braun](https://github.com/t-b) fixed a warning in a test case. -- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). +- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks. - [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. - [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. - [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. -- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable. +- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. - [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. +- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. +- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. +- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. +- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. +- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. +- [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one. +- [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers. +- [Jonathan Lee](https://github.com/vjon) fixed an example in the README file. +- [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types. +- [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio. +- [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types. +- [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example. +- [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite. +- [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section. +- [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README. +- [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s. +- [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation. +- [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings. +- [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible. +- [ftillier](https://github.com/ftillier) fixed a compiler warning. +- [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped. +- [Fytch](https://github.com/Fytch) found a bug in the documentation. +- [Jay Sistar](https://github.com/Type1J) implemented a Meson build description. +- [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation. +- [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager. +- [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`. +- [Mike Tzou](https://github.com/Chocobo1) fixed some typos. +- [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats. +- [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `` with ``. +- [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library. +- [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists. +- [Greg Hurrell](https://github.com/wincent) fixed a typo. +- [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo. +- [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler. +- [Markus Werle](https://github.com/daixtrose) fixed a typo. +- [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check. +- [Alex](https://github.com/leha-bot) noted an error in a code sample. +- [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped fixing them. +- [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams. +- [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error. +- [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings. +- [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file. +- [pvleuven](https://github.com/pvleuven) helped fixing a warning in ICC. +- [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC. +- [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`. +- [Mitja](https://github.com/Itja) fixed some typos. +- [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. +- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. +- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. +- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. +- [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed. +- [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README. +- [zerodefect](https://github.com/zerodefect) fixed a compiler warning. +- [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior. +- [mark-99](https://github.com/mark-99) helped fixing an ICC error. +- [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. +- [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. +- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. +- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. +- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. +- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type. +- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake. +- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). +- [Carlos O'Ryan](https://github.com/coryan) fixed a typo. +- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. +- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines +- [Jan Schöppach](https://github.com/dns13) fixed a typo. +- [martin-mfg](https://github.com/martin-mfg) fixed a typo. +- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. +- [agrianius](https://github.com/agrianius) added code to use alternative string implementations. +- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. +- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com). +- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. +- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. +- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. +- [thyu](https://github.com/thyu) fixed a compiler warning. -Thanks a lot for helping out! +Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. + + +## Used third-party tools + +The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! + +- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file +- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing +- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows +- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation +- [**Catch**](https://github.com/philsquared/Catch) for the unit tests +- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers +- [**Cmake**](https://cmake.org) for build automation +- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) +- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) +- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) +- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis +- [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/) +- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages +- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) +- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks +- [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz +- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) +- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. +- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox) +- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS +- [**Valgrind**](http://valgrind.org) to check for correct memory management +- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) + + +## Projects using JSON for Modern C++ + +The library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices. ## Notes -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726). +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726). - As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The library supports **Unicode input** as follows: - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1). - - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors. + - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors. - [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. + - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. +- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. +- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by an `abort()` call. +- By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). ## Execute unit tests To compile and run the tests, you need to execute -```sh -$ make check - -=============================================================================== -All tests passed (8905491 assertions in 36 test cases) -``` - -Alternatively, you can use [CMake](https://cmake.org) and run - ```sh $ mkdir build $ cd build $ cmake .. -$ make -$ ctest +$ cmake --build . +$ ctest --output-on-failure ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/ext/json/json.hpp b/ext/json/json.hpp index 9d48e7a..b80386f 100644 --- a/ext/json/json.hpp +++ b/ext/json/json.hpp @@ -1,11 +1,12 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.0.10 +| | |__ | | | | | | version 3.2.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . -Copyright (c) 2013-2017 Niels Lohmann . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,43 +30,104 @@ SOFTWARE. #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP -#include // all_of, for_each, transform -#include // array +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each #include // assert -#include // isdigit #include // and, not, or -#include // isfinite, ldexp, signbit #include // nullptr_t, ptrdiff_t, size_t -#include // int64_t, uint64_t -#include // strtod, strtof, strtold, strtoul -#include // strlen -#include // function, hash, less +#include // hash, less #include // initializer_list -#include // setw -#include // istream, ostream -#include // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include // numeric_limits -#include // locale -#include // map -#include // addressof, allocator, allocator_traits, unique_ptr +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag #include // accumulate -#include // stringstream -#include // domain_error, invalid_argument, out_of_range -#include // getline, stoi, string, to_string -#include // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference -#include // declval, forward, make_pair, move, pair, swap +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string #include // vector +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + // exclude unsupported compilers -#if defined(__clang__) - #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) - #if CLANG_VERSION < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - #if GCC_VERSION < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif #endif #endif @@ -90,6 +152,11030 @@ SOFTWARE. #define JSON_DEPRECATED #endif +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl +{ + static constexpr auto value = + std::is_same::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_compatible_string_type +{ + static auto constexpr value = is_compatible_string_type_impl < + conjunction>, + has_value_type>::value, + typename BasicJsonType::string_t, CompatibleStringType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ + static constexpr bool value = + not std::is_base_of::value and + not is_basic_json::value and + not is_basic_json_nested_type::value and + has_to_json::value; +}; + +template +struct is_compatible_type + : conjunction, + is_compatible_complete_type> +{ +}; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +// #include + + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_UNLIKELY(not j.is_null())) + { + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename CompatibleStringType, + enable_if_t < + is_compatible_string_type::value and + not std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleStringType& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template < + typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type::value and + not std::is_same::value and + std::is_constructible < + BasicJsonType, typename CompatibleArrayType::value_type >::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +template ::value>> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template ::value>> +void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +// #include + + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + +// #include + +// #include + + +#include // size_t +#include // string, to_string +#include // input_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_internal; + using pointer = iteration_proxy_internal*; + using reference = iteration_proxy_internal&; + using iterator_category = std::input_iterator_tag; + + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable std::string array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + const std::string empty_str = ""; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + iteration_proxy_internal(const iteration_proxy_internal&) = default; + iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_internal& o) const noexcept + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + const std::string& key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + array_index_str = std::to_string(array_index); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +// for https://github.com/nlohmann/json/pull/1134 +template::iteration_proxy_internal>::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + j = {{b.key(), b.value()}}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +// #include + + +#include // assert +#include // size_t +#include // strlen +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson }; + +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of +exactly one non-EOF character for future input. The int_type characters +returned consist of all valid char values as positive values (typically +unsigned char), plus an EOF value outside that range, specified by the value +of the function std::char_traits::eof(). This value is typically -1, but +could be any arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l) + {} + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* const limit; +}; + +template +class wide_string_input_adapter : public input_adapter_protocol +{ + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits::int_type get_character() noexcept override + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + if (sizeof(typename WideStringType::value_type) == 2) + { + fill_buffer_utf16(); + } + else + { + fill_buffer_utf32(); + } + + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); + } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + void fill_buffer_utf16() + { + utf8_bytes_index = 0; + + if (current_wchar == str.size()) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const int wc = static_cast(str[current_wchar++]); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6)); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc or wc >= 0xE000) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12)); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else + { + if (current_wchar < str.size()) + { + const int wc2 = static_cast(str[current_wchar++]); + const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); + utf8_bytes[0] = 0xf0 | (charcode >> 18); + utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (charcode & 0x3F); + utf8_bytes_filled = 4; + } + else + { + // unknown character + ++current_wchar; + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + } + } + } + + void fill_buffer_utf32() + { + utf8_bytes_index = 0; + + if (current_wchar == str.size()) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const int wc = static_cast(str[current_wchar++]); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + } + } + + private: + /// the wstring to process + const WideStringType& str; + + /// index of the current wchar in str + std::size_t current_wchar = 0; + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + input_adapter(const std::wstring& ws) + : ia(std::make_shared>(ws)) {} + + input_adapter(const std::u16string& ws) + : ia(std::make_shared>(ws)) {} + + input_adapter(const std::u32string& ws) + : ia(std::make_shared>(ws)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +// #include + + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // snprintf +#include // initializer_list +#include // char_traits, string +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } + + explicit lexer(detail::input_adapter_t&& adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // LCOV_EXCL_START + default: + { + // all other characters are rejected outside scan_number() + assert(false); + } + // LCOV_EXCL_STOP + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia->get_character(); + } + + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read and + token_string. The next call to get() will behave as if the unget character + is read again. + */ + void unget() + { + next_unget = true; + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(int c) + { + token_buffer.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + char cs[9]; + snprintf(cs, 9, "", static_cast(c)); + result += cs; + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + if (get() == 0xBB and get() == 0xBF) + { + // we completely parsed the BOM + return true; + } + else + { + // after reading 0xEF, an unexpected character followed + return false; + } + } + else + { + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + } + + token_type scan() + { + // initially, skip the BOM + if (chars_read == 0 and not skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include + +// #include + +// #include + + +#include // size_t +#include // declval + +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +using void_t = void; +} +} + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template